Skip to main content

macros/io/
register.rs

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