xref: /linux/rust/macros/io/register.rs (revision c09d3a26e1b810d43ee8a15c4f09ee752fee55a6)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Documentation and usage example of the macro can be found at `rust/kernel/io/register.rs`.
4 
5 use proc_macro2::{
6     Group,
7     Literal,
8     Span,
9     TokenStream, //
10 };
11 use quote::{
12     quote,
13     quote_spanned, //
14 };
15 use syn::{
16     bracketed,
17     parenthesized,
18     parse::Parse,
19     parse_quote,
20     spanned::Spanned,
21     token,
22     Attribute,
23     Error,
24     Expr,
25     Ident,
26     Path,
27     Result,
28     Token,
29     Type,
30     Visibility, //
31 };
32 
33 mod kw {
34     syn::custom_keyword!(base);
35     syn::custom_keyword!(stride);
36 }
37 
38 /// Definition of a register array.
39 ///
40 /// Specify a size, and optionally a stride. Syntax is of form `[EXPR $(, stride = EXPR)?]`.
41 struct RegArrayDef {
42     size: Expr,
43     stride: Option<Expr>,
44 }
45 
46 /// Offset of a register.
47 ///
48 /// Can be either of form
49 /// * `@ offset` for fixed offset
50 /// * `=> alias` for alias of register `alias`.
51 /// * `=> alias[idx]` for alias of register array `alias`'s `idx`-th element.
52 enum RegOffset {
53     /// Register is located at fixed address.
54     Fixed { offset: Literal },
55     /// Register is an alias of a fixed register.
56     Alias { alias: Path },
57     /// Register is an alias of an element of a register array.
58     ElementAlias { alias: Path, idx: Expr },
59 }
60 
61 /// Definition of a single register.
62 struct Reg {
63     attrs: Vec<Attribute>,
64     vis: Visibility,
65     name: Ident,
66     ty: Type,
67     array: Option<RegArrayDef>,
68     relative_base: Option<Path>,
69     offset: RegOffset,
70     bitfield: Option<(Type, Group)>,
71 }
72 
73 impl Parse for Reg {
74     fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
75         let attrs = input.call(Attribute::parse_outer)?;
76         let vis = input.parse()?;
77         let name = input.parse()?;
78 
79         let lh = input.lookahead1();
80         let (ty, bitfield_storage) = if lh.peek(Token![:]) {
81             let _: Token![:] = input.parse()?;
82             (input.parse()?, None)
83         } else if lh.peek(token::Paren) {
84             let content;
85             parenthesized!(content in input);
86             let bitfield_storage = Some(content.parse()?);
87 
88             // For bitfields, bitfield macro will generate a type with the same name as `name`.
89             (parse_quote!(#name), bitfield_storage)
90         } else {
91             Err(lh.error())?
92         };
93 
94         let array = if input.peek(token::Bracket) {
95             let content;
96             bracketed!(content in input);
97             let size = content.parse()?;
98             let stride = if content.peek(Token![,]) {
99                 let _: Token![,] = content.parse()?;
100                 let _: kw::stride = content.parse()?;
101                 let _: Token![=] = content.parse()?;
102                 Some(content.parse()?)
103             } else {
104                 None
105             };
106             Some(RegArrayDef { size, stride })
107         } else {
108             None
109         };
110 
111         // Parse offset and the base it's relative to.
112         let lh = input.lookahead1();
113         let mut relative_base = None;
114         let offset = if lh.peek(Token![@]) {
115             let _: Token![@] = input.parse()?;
116 
117             if input.peek(Ident) {
118                 relative_base = Some(input.parse()?);
119                 let _: Token![+] = input.parse()?;
120             }
121 
122             RegOffset::Fixed {
123                 offset: input.parse()?,
124             }
125         } else if lh.peek(Token![=>]) {
126             let _: Token![=>] = input.parse()?;
127             let mut alias: Path = input.parse()?;
128             if input.peek(Token![+]) {
129                 let _: Token![+] = input.parse()?;
130                 relative_base = Some(alias);
131                 alias = input.parse()?;
132             }
133 
134             if input.peek(token::Bracket) {
135                 let content;
136                 bracketed!(content in input);
137                 RegOffset::ElementAlias {
138                     alias,
139                     idx: content.parse()?,
140                 }
141             } else {
142                 RegOffset::Alias { alias }
143             }
144         } else {
145             Err(lh.error())?
146         };
147 
148         let bitfield = if let Some(storage) = bitfield_storage {
149             let lh = input.lookahead1();
150             let args = if lh.peek(token::Brace) {
151                 input.parse()?
152             } else {
153                 Err(lh.error())?
154             };
155             Some((storage, args))
156         } else {
157             let _: Token![;] = input.parse()?;
158             None
159         };
160 
161         Ok(Self {
162             attrs,
163             vis,
164             name,
165             ty,
166             array,
167             relative_base,
168             offset,
169             bitfield,
170         })
171     }
172 }
173 
174 pub(crate) struct RegDef {
175     base: Type,
176     regs: Vec<Reg>,
177 }
178 
179 impl Parse for RegDef {
180     fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
181         let _: kw::base = input.parse().map_err(|e| {
182             Error::new(
183                 e.span(),
184                 "a base type needs to be specified for `register!` invocation with `base: ty;`",
185             )
186         })?;
187 
188         let _: Token![:] = input.parse()?;
189         let base = input.parse()?;
190         let _: Token![;] = input.parse()?;
191 
192         let mut regs = Vec::new();
193         while !input.is_empty() {
194             regs.push(input.parse()?);
195         }
196         Ok(RegDef { base, regs })
197     }
198 }
199 
200 pub(crate) fn register(def: RegDef) -> Result<TokenStream> {
201     let mut outputs = TokenStream::new();
202 
203     let base = &def.base;
204     for reg in def.regs {
205         let Reg {
206             attrs,
207             vis,
208             name,
209             ty,
210             array,
211             relative_base,
212             offset,
213             bitfield,
214         } = reg;
215 
216         // Use register name's span for generated code, so error messages (if any) can point to it
217         // instead of the entire register allocation.
218         let span = name.span().resolved_at(Span::mixed_site());
219 
220         let offset = match offset {
221             RegOffset::Fixed { offset } => quote!(#offset),
222             RegOffset::Alias { alias } => {
223                 quote_spanned!(alias.span().resolved_at(span) =>
224                     ::kernel::io::register::alias_offset::<#base, #alias>()
225                 )
226             }
227             RegOffset::ElementAlias { alias, idx } => {
228                 quote_spanned!(alias.span().resolved_at(span) =>
229                     ::kernel::io::register::element_alias_offset::<#base, #alias>(#idx)
230                 )
231             }
232         };
233 
234         if let Some((storage, args)) = &bitfield {
235             outputs.extend(quote_spanned!(span =>
236                 ::kernel::bitfield!(
237                     // `#[allow(non_camel_case_types)]` is added since register names typically use
238                     // `SCREAMING_CASE`.
239                     #[allow(non_camel_case_types)]
240                     #(#attrs)* #vis struct #name(#storage) #args
241                 );
242 
243                 impl ::kernel::io::register::Register for #name {
244                     type Base = #base;
245                     const OFFSET: usize = #offset;
246                 }
247             ));
248         }
249 
250         match array {
251             None if bitfield.is_none() && relative_base.is_none() => outputs.extend(quote!(
252                 #(#attrs)* #vis const #name: ::kernel::io::register::OffsetLoc<#base, #ty> =
253                     ::kernel::io::register::OffsetLoc::new(#offset);
254             )),
255 
256             _ if bitfield.is_none() => Err(Error::new_spanned(
257                 ty,
258                 "defining without bitfield is not yet supported for this type of register",
259             ))?,
260 
261             None => match relative_base {
262                 None => outputs.extend(quote_spanned!(span =>
263                     impl ::kernel::io::register::FixedRegister for #name {}
264 
265                     #(#attrs)* #vis const #name: ::kernel::io::register::FixedRegisterLoc<#name> =
266                         ::kernel::io::register::FixedRegisterLoc::<#name>::new();
267                 )),
268                 Some(relative_base) => outputs.extend(quote_spanned!(span =>
269                     impl ::kernel::io::register::WithBase for #name {
270                         type BaseFamily = #relative_base;
271                     }
272 
273                     impl ::kernel::io::register::RelativeRegister for #name {}
274                 )),
275             },
276 
277             Some(def) => {
278                 let size = &def.size;
279                 let stride = if let Some(stride) = &def.stride {
280                     outputs.extend(quote_spanned!(stride.span().resolved_at(span) =>
281                         ::kernel::build_assert::static_assert!(
282                             ::core::mem::size_of::<#ty>() <= #stride
283                         );
284                     ));
285                     quote!(#stride)
286                 } else {
287                     quote_spanned!(span => ::core::mem::size_of::<#ty>())
288                 };
289 
290                 outputs.extend(quote_spanned!(span =>
291                     impl ::kernel::io::register::RegisterArray for #name {
292                         const SIZE: usize = #size;
293                         const STRIDE: usize = #stride;
294                     }
295                 ));
296 
297                 match relative_base {
298                     None => outputs.extend(quote_spanned!(span =>
299                         impl ::kernel::io::register::Array for #name {}
300                     )),
301                     Some(relative_base) => outputs.extend(quote_spanned!(span =>
302                         impl ::kernel::io::register::WithBase for #name {
303                             type BaseFamily = #relative_base;
304                         }
305 
306                         impl ::kernel::io::register::RelativeRegisterArray for #name {}
307                     )),
308                 }
309             }
310         };
311     }
312 
313     Ok(outputs)
314 }
315