// SPDX-License-Identifier: GPL-2.0 //! Documentation and usage example of the macro can be found at `rust/kernel/io/register.rs`. use proc_macro2::{ Group, Literal, Span, TokenStream, // }; use quote::{ quote, quote_spanned, // }; use syn::{ bracketed, parenthesized, parse::Parse, parse_quote, spanned::Spanned, token, Attribute, Error, Expr, Ident, Path, Result, Token, Type, Visibility, // }; mod kw { syn::custom_keyword!(base); syn::custom_keyword!(stride); } /// Definition of a register array. /// /// Specify a size, and optionally a stride. Syntax is of form `[EXPR $(, stride = EXPR)?]`. struct RegArrayDef { size: Expr, stride: Option, } /// Offset of a register. /// /// Can be either of form /// * `@ offset` for fixed offset /// * `=> alias` for alias of register `alias`. /// * `=> alias[idx]` for alias of register array `alias`'s `idx`-th element. enum RegOffset { /// Register is located at fixed address. Fixed { offset: Literal }, /// Register is an alias of a fixed register. Alias { alias: Path }, /// Register is an alias of an element of a register array. ElementAlias { alias: Path, idx: Expr }, } /// Definition of a single register. struct Reg { attrs: Vec, vis: Visibility, name: Ident, unique: bool, ty: Type, array: Option, offset: RegOffset, bitfield: Option<(Type, Group)>, } impl Parse for Reg { fn parse(input: syn::parse::ParseStream<'_>) -> Result { let attrs = input.call(Attribute::parse_outer)?; let vis = input.parse()?; let name = input.parse()?; let lh = input.lookahead1(); let (unique, ty, bitfield_storage) = if lh.peek(Token![:]) { let _: Token![:] = input.parse()?; let mut attrs = input.call(Attribute::parse_outer)?; let unique = attrs .extract_if(.., |attr| attr.path().is_ident("unique")) .count() != 0; if !attrs.is_empty() { Err(Error::new_spanned(&attrs[0], "unexpected attributes"))? } (unique, input.parse()?, None) } else if lh.peek(token::Paren) { let content; parenthesized!(content in input); let bitfield_storage = Some(content.parse()?); // For bitfields, bitfield macro will generate a type with the same name as `name`. (true, parse_quote!(#name), bitfield_storage) } else { Err(lh.error())? }; let array = if input.peek(token::Bracket) { let content; bracketed!(content in input); let size = content.parse()?; let stride = if content.peek(Token![,]) { let _: Token![,] = content.parse()?; let _: kw::stride = content.parse()?; let _: Token![=] = content.parse()?; Some(content.parse()?) } else { None }; Some(RegArrayDef { size, stride }) } else { None }; // Parse offset and the base it's relative to. let lh = input.lookahead1(); let offset = if lh.peek(Token![@]) { let _: Token![@] = input.parse()?; RegOffset::Fixed { offset: input.parse()?, } } else if lh.peek(Token![=>]) { let _: Token![=>] = input.parse()?; let alias: Path = input.parse()?; if input.peek(token::Bracket) { let content; bracketed!(content in input); RegOffset::ElementAlias { alias, idx: content.parse()?, } } else { RegOffset::Alias { alias } } } else { Err(lh.error())? }; let bitfield = if let Some(storage) = bitfield_storage { let lh = input.lookahead1(); let args = if lh.peek(token::Brace) { input.parse()? } else { Err(lh.error())? }; Some((storage, args)) } else { let _: Token![;] = input.parse()?; None }; Ok(Self { attrs, vis, name, unique, ty, array, offset, bitfield, }) } } pub(crate) struct RegDef { base: Type, regs: Vec, } impl Parse for RegDef { fn parse(input: syn::parse::ParseStream<'_>) -> Result { let _: kw::base = input.parse().map_err(|e| { Error::new( e.span(), "a base type needs to be specified for `register!` invocation with `base: ty;`", ) })?; let _: Token![:] = input.parse()?; let base = input.parse()?; let _: Token![;] = input.parse()?; let mut regs = Vec::new(); while !input.is_empty() { regs.push(input.parse()?); } Ok(RegDef { base, regs }) } } pub(crate) fn register(def: RegDef) -> Result { let mut outputs = TokenStream::new(); let base = &def.base; for reg in def.regs { let Reg { attrs, vis, name, unique, ty, array, offset, bitfield, } = reg; // Use register name's span for generated code, so error messages (if any) can point to it // instead of the entire register allocation. let span = name.span().resolved_at(Span::mixed_site()); let offset = match offset { RegOffset::Fixed { offset } => quote!(#offset), RegOffset::Alias { alias } => { quote_spanned!(alias.span().resolved_at(span) => ::kernel::io::register::OffsetLoc::<#base, _>::const_offset(#alias) ) } RegOffset::ElementAlias { alias, idx } => { quote_spanned!(alias.span().resolved_at(span) => ::kernel::io::register::element_alias_offset::<#base, #alias>(#idx) ) } }; if let Some((storage, args)) = &bitfield { outputs.extend(quote_spanned!(span => ::kernel::bitfield!( // `#[allow(non_camel_case_types)]` is added since register names typically use // `SCREAMING_CASE`. #[allow(non_camel_case_types)] #(#attrs)* #vis struct #name(#storage) #args ); )); } match array { None => { if unique { outputs.extend(quote!( impl ::kernel::io::register::FixedIoLoc<#base> for #ty { type Location = ::kernel::io::register::OffsetLoc<#base, #ty>; const LOCATION: Self::Location = #name; } )) } outputs.extend(quote_spanned!(span => #(#attrs)* #vis const #name: ::kernel::io::register::OffsetLoc<#base, #ty> = ::kernel::io::register::OffsetLoc::new(#offset); )); } Some(def) => { if bitfield.is_none() { Err(Error::new_spanned( &ty, "defining without bitfield is not yet supported for this type of register", ))? } let size = &def.size; let stride = if let Some(stride) = &def.stride { outputs.extend(quote_spanned!(stride.span().resolved_at(span) => ::kernel::build_assert::static_assert!( ::core::mem::size_of::<#ty>() <= #stride ); )); quote!(#stride) } else { quote_spanned!(span => ::core::mem::size_of::<#ty>()) }; outputs.extend(quote_spanned!(span => impl ::kernel::io::register::Array for #name {} impl ::kernel::io::register::RegisterArray for #name { type Base = #base; const OFFSET: usize = #offset; const SIZE: usize = #size; const STRIDE: usize = #stride; } )); } }; } Ok(outputs) }