1mod riscv;
8
9use proc_macro::TokenStream;
10use proc_macro2::TokenStream as TokenStream2;
11use quote::quote;
12use syn::parse::{Error, Parse, ParseStream, Result};
13use syn::{DeriveInput, Expr, Ident, Token, parse_macro_input};
14
15#[proc_macro_attribute]
16pub fn offset(attr: TokenStream, item: TokenStream) -> TokenStream {
17 let input = parse_macro_input!(item as DeriveInput);
18 let ty = &input.ident;
19 let OffsetAttrs { offset, access } = parse_macro_input!(attr as OffsetAttrs);
20 let marker_impls = access.marker_impls(ty);
21 quote! {
22 #input
23
24 impl ::regio::Register for #ty {
25 type Base = <Self as ::core::ops::Deref>::Target;
26 type Addr = ::regio::Offset;
27 }
28
29 impl ::regio::FixedAddr for #ty {
30 const ADDR: ::regio::Offset = ::regio::Offset(#offset);
31 }
32
33 #marker_impls
34 }
35 .into()
36}
37
38#[proc_macro_attribute]
39pub fn riscv_csr(attr: TokenStream, item: TokenStream) -> TokenStream {
40 let attrs = parse_macro_input!(attr as riscv::CsrAttrs);
41 let input = parse_macro_input!(item as DeriveInput);
42 attrs.expand(input).into()
43}
44
45struct OffsetAttrs {
46 offset: Expr,
47 access: AccessMode,
48}
49
50impl Parse for OffsetAttrs {
51 fn parse(input: ParseStream) -> Result<Self> {
52 let offset: Expr = input.parse()?;
53 let access: AccessMode = if input.is_empty() {
54 AccessMode::ReadWrite
55 } else {
56 let _: Token![,] = input.parse()?;
57 input.parse()?
58 };
59 Ok(Self { offset, access })
60 }
61}
62
63enum AccessMode {
64 ReadOnly,
65 ReadWrite,
66 WriteOnly,
67}
68impl Parse for AccessMode {
69 fn parse(input: ParseStream) -> Result<Self> {
70 let ident: Ident = input.parse()?;
71 if ident == "ro" {
72 Ok(AccessMode::ReadOnly)
73 } else if ident == "rw" {
74 Ok(AccessMode::ReadWrite)
75 } else if ident == "wo" {
76 Ok(AccessMode::WriteOnly)
77 } else {
78 Err(Error::new_spanned(
79 ident,
80 "access mode must be one of `ro`, `rw`, or `wo`, or \
81 unspecified altogether for a default of `rw`",
82 ))
83 }
84 }
85}
86
87impl AccessMode {
88 pub(crate) fn marker_impls(&self, ty: &Ident) -> TokenStream2 {
89 match self {
90 AccessMode::ReadOnly => quote! {
91 impl ::regio::Readable for #ty {}
92 },
93 AccessMode::ReadWrite => quote! {
94 impl ::regio::Readable for #ty {}
95 impl ::regio::Writable for #ty {}
96 },
97 AccessMode::WriteOnly => quote! {
98 impl ::regio::Writable for #ty {}
99 },
100 }
101 }
102}