register_macros/lib.rs
1use darling::{FromMeta, ast::NestedMeta};
2use syn::{ItemStruct, parse_macro_input};
3
4use crate::register::Register;
5
6mod field;
7mod register;
8mod util;
9
10const SUPPORTED_WIDTHS: [usize; 5] = [8usize, 16usize, 32usize, 64usize, 128usize];
11
12#[derive(Debug, darling::FromMeta)]
13#[darling(and_then = verify_args)]
14struct MacroArgs {
15 size: usize,
16
17 #[darling(default = || true)]
18 read: bool,
19
20 #[darling(default = || true)]
21 write: bool,
22}
23
24fn verify_args(args: MacroArgs) -> darling::Result<MacroArgs> {
25 if !SUPPORTED_WIDTHS.contains(&args.size) {
26 return Err(darling::Error::custom(format!(
27 "Invalid size: {}, expected one of: {:?}",
28 args.size, SUPPORTED_WIDTHS
29 ))
30 .with_span(&args.size));
31 }
32
33 Ok(args)
34}
35
36/// Generate register handling code for a register definition.
37///
38/// This macro may only be used on structs, and supports only registers with the widths of 8 bits,
39/// 16 bits, 32 bits, 64 bits, or 128 bits.
40///
41/// This size *must* be declared as an attribute parameter, like so:
42/// ```ignore
43/// #[register(size = 16)]
44/// struct MyRegister {}
45/// ```
46///
47/// Fields may be declared in a similar syntax to the fields of a normal struct. They must define,
48/// as attributes, the least significant bit (lsb) and most significant bit (msb). They must also
49/// specify their sign via the "type" of the field. This type must either be "u" for unsigned or
50/// "i" for signed. They may also optionally specify whether or not that field may be read or
51/// written to, defaulting to true.
52///
53/// ```ignore
54/// #[register(size = 16)]
55/// struct MyRegister {
56/// // Readable, writable, unsigned
57/// #[field(lsb = 0, msb = 7)]
58/// lower: u,
59///
60/// // Readable, signed
61/// #[field(lsb = 8, msb = 15, write = false)]
62/// upper: i,
63/// }
64///
65/// let mut reg = MyRegister::new(0x04AD);
66/// assert_eq!(reg.get_lower(), 0xAD);
67/// assert_eq!(reg.get_upper(), 4);
68/// assert!(reg.set_lower(-4).is_ok());
69/// assert_eq!(reg.get_lower(), -4);
70/// ```
71#[proc_macro_attribute]
72pub fn register(
73 _attr: proc_macro::TokenStream,
74 item: proc_macro::TokenStream,
75) -> proc_macro::TokenStream {
76 let nested_meta = match NestedMeta::parse_meta_list(_attr.into()) {
77 Ok(v) => v,
78 Err(e) => return e.to_compile_error().into(),
79 };
80 let macro_args = match MacroArgs::from_list(&nested_meta) {
81 Ok(v) => v,
82 Err(e) => return e.write_errors().into(),
83 };
84 let strct = parse_macro_input!(item as ItemStruct);
85 let reg = Register::new(strct, macro_args);
86 reg.implement().into()
87}