xref: /linux/rust/macros/io/register.rs (revision 631adefcac893728c278f4bd2c9634cfe3f35482)
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     offset: RegOffset,
69     bitfield: Option<(Type, Group)>,
70 }
71 
72 impl Parse for Reg {
73     fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
74         let attrs = input.call(Attribute::parse_outer)?;
75         let vis = input.parse()?;
76         let name = input.parse()?;
77 
78         let lh = input.lookahead1();
79         let (ty, bitfield_storage) = if lh.peek(Token![:]) {
80             let _: Token![:] = input.parse()?;
81             (input.parse()?, None)
82         } else if lh.peek(token::Paren) {
83             let content;
84             parenthesized!(content in input);
85             let bitfield_storage = Some(content.parse()?);
86 
87             // For bitfields, bitfield macro will generate a type with the same name as `name`.
88             (parse_quote!(#name), bitfield_storage)
89         } else {
90             Err(lh.error())?
91         };
92 
93         let array = if input.peek(token::Bracket) {
94             let content;
95             bracketed!(content in input);
96             let size = content.parse()?;
97             let stride = if content.peek(Token![,]) {
98                 let _: Token![,] = content.parse()?;
99                 let _: kw::stride = content.parse()?;
100                 let _: Token![=] = content.parse()?;
101                 Some(content.parse()?)
102             } else {
103                 None
104             };
105             Some(RegArrayDef { size, stride })
106         } else {
107             None
108         };
109 
110         // Parse offset and the base it's relative to.
111         let lh = input.lookahead1();
112         let offset = if lh.peek(Token![@]) {
113             let _: Token![@] = input.parse()?;
114 
115             RegOffset::Fixed {
116                 offset: input.parse()?,
117             }
118         } else if lh.peek(Token![=>]) {
119             let _: Token![=>] = input.parse()?;
120             let alias: Path = input.parse()?;
121 
122             if input.peek(token::Bracket) {
123                 let content;
124                 bracketed!(content in input);
125                 RegOffset::ElementAlias {
126                     alias,
127                     idx: content.parse()?,
128                 }
129             } else {
130                 RegOffset::Alias { alias }
131             }
132         } else {
133             Err(lh.error())?
134         };
135 
136         let bitfield = if let Some(storage) = bitfield_storage {
137             let lh = input.lookahead1();
138             let args = if lh.peek(token::Brace) {
139                 input.parse()?
140             } else {
141                 Err(lh.error())?
142             };
143             Some((storage, args))
144         } else {
145             let _: Token![;] = input.parse()?;
146             None
147         };
148 
149         Ok(Self {
150             attrs,
151             vis,
152             name,
153             ty,
154             array,
155             offset,
156             bitfield,
157         })
158     }
159 }
160 
161 pub(crate) struct RegDef {
162     base: Type,
163     regs: Vec<Reg>,
164 }
165 
166 impl Parse for RegDef {
167     fn parse(input: syn::parse::ParseStream<'_>) -> Result<Self> {
168         let _: kw::base = input.parse().map_err(|e| {
169             Error::new(
170                 e.span(),
171                 "a base type needs to be specified for `register!` invocation with `base: ty;`",
172             )
173         })?;
174 
175         let _: Token![:] = input.parse()?;
176         let base = input.parse()?;
177         let _: Token![;] = input.parse()?;
178 
179         let mut regs = Vec::new();
180         while !input.is_empty() {
181             regs.push(input.parse()?);
182         }
183         Ok(RegDef { base, regs })
184     }
185 }
186 
187 pub(crate) fn register(def: RegDef) -> Result<TokenStream> {
188     let mut outputs = TokenStream::new();
189 
190     let base = &def.base;
191     for reg in def.regs {
192         let Reg {
193             attrs,
194             vis,
195             name,
196             ty,
197             array,
198             offset,
199             bitfield,
200         } = reg;
201 
202         // Use register name's span for generated code, so error messages (if any) can point to it
203         // instead of the entire register allocation.
204         let span = name.span().resolved_at(Span::mixed_site());
205 
206         let offset = match offset {
207             RegOffset::Fixed { offset } => quote!(#offset),
208             RegOffset::Alias { alias } => {
209                 quote_spanned!(alias.span().resolved_at(span) =>
210                     ::kernel::io::register::alias_offset::<#base, #alias>()
211                 )
212             }
213             RegOffset::ElementAlias { alias, idx } => {
214                 quote_spanned!(alias.span().resolved_at(span) =>
215                     ::kernel::io::register::element_alias_offset::<#base, #alias>(#idx)
216                 )
217             }
218         };
219 
220         if let Some((storage, args)) = &bitfield {
221             outputs.extend(quote_spanned!(span =>
222                 ::kernel::bitfield!(
223                     // `#[allow(non_camel_case_types)]` is added since register names typically use
224                     // `SCREAMING_CASE`.
225                     #[allow(non_camel_case_types)]
226                     #(#attrs)* #vis struct #name(#storage) #args
227                 );
228 
229                 impl ::kernel::io::register::Register for #name {
230                     type Base = #base;
231                     const OFFSET: usize = #offset;
232                 }
233             ));
234         }
235 
236         match array {
237             None if bitfield.is_none() => outputs.extend(quote!(
238                 #(#attrs)* #vis const #name: ::kernel::io::register::OffsetLoc<#base, #ty> =
239                     ::kernel::io::register::OffsetLoc::new(#offset);
240             )),
241 
242             _ if bitfield.is_none() => Err(Error::new_spanned(
243                 ty,
244                 "defining without bitfield is not yet supported for this type of register",
245             ))?,
246 
247             None => outputs.extend(quote_spanned!(span =>
248                 impl ::kernel::io::register::FixedRegister for #name {}
249 
250                 #(#attrs)* #vis const #name: ::kernel::io::register::FixedRegisterLoc<#name> =
251                     ::kernel::io::register::FixedRegisterLoc::<#name>::new();
252             )),
253 
254             Some(def) => {
255                 let size = &def.size;
256                 let stride = if let Some(stride) = &def.stride {
257                     outputs.extend(quote_spanned!(stride.span().resolved_at(span) =>
258                         ::kernel::build_assert::static_assert!(
259                             ::core::mem::size_of::<#ty>() <= #stride
260                         );
261                     ));
262                     quote!(#stride)
263                 } else {
264                     quote_spanned!(span => ::core::mem::size_of::<#ty>())
265                 };
266 
267                 outputs.extend(quote_spanned!(span =>
268                     impl ::kernel::io::register::Array for #name {}
269 
270                     impl ::kernel::io::register::RegisterArray for #name {
271                         const SIZE: usize = #size;
272                         const STRIDE: usize = #stride;
273                     }
274                 ));
275             }
276         };
277     }
278 
279     Ok(outputs)
280 }
281