register_interface/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4use syn::parse::{Parse, ParseStream};
5use syn::{parse_macro_input, ItemStruct, LitInt, Result, Token};
6
7struct FieldArgs {
8    name: Ident,
9    _s0: Token![,],
10    from: LitInt,
11    _s1: Token![,],
12    to: LitInt,
13}
14
15impl Parse for FieldArgs {
16    fn parse(input: ParseStream) -> Result<Self> {
17        Ok(FieldArgs {
18            name: input.parse()?,
19            _s0: input.parse()?,
20            from: input.parse()?,
21            _s1: input.parse()?,
22            to: input.parse()?,
23        })
24    }
25}
26
27#[proc_macro_attribute]
28pub fn field(args: TokenStream, input: TokenStream) -> TokenStream {
29    let args_p = parse_macro_input!(args as FieldArgs);
30    let field_name = args_p.name.clone();
31    let field_from = args_p.from.base10_digits().parse().unwrap();
32    let field_to = args_p.to.base10_digits().parse().unwrap();
33    let clonned = input.clone();
34    let input_p = parse_macro_input!(input as ItemStruct);
35    let struct_name = input_p.ident;
36    let set_field_name = Ident::new(&format!("set_{}", args_p.name), Span::call_site());
37
38    let mask = gen_mask(field_from, field_to);
39    let n_mask = !mask;
40    let extended = quote!(
41        impl #struct_name {
42            pub fn #field_name(&self) -> usize {
43                use core::ptr::read_volatile;
44                ((unsafe { read_volatile(self.addr)}) & #mask) >> #field_from
45            }
46            pub fn #set_field_name(&mut self, value: usize) {
47                use core::ptr::{read_volatile, write_volatile};
48                unsafe {
49                  let original = read_volatile(self.addr) & #n_mask;
50                  let value = value << #field_from;
51                  write_volatile(self.addr, original | value);
52                }
53            }
54        }
55    );
56
57    let mut ts = TokenStream::from(extended);
58    ts.extend(clonned);
59    ts
60}
61
62struct RegisterArgs {
63    name: Ident,
64    _s0: Token![,],
65    typ: Ident,
66    _s1: Token![,],
67    offset: LitInt,
68}
69
70impl Parse for RegisterArgs {
71    fn parse(input: ParseStream) -> Result<Self> {
72        Ok(RegisterArgs {
73            name: input.parse()?,
74            _s0: input.parse()?,
75            typ: input.parse()?,
76            _s1: input.parse()?,
77            offset: input.parse()?,
78        })
79    }
80}
81
82#[proc_macro_attribute]
83pub fn register(args: TokenStream, input: TokenStream) -> TokenStream {
84    let args_p = parse_macro_input!(args as RegisterArgs);
85    let reg_name = args_p.name.clone();
86    let reg_offset: usize = args_p.offset.base10_digits().parse().unwrap();
87    let reg_type = args_p.typ;
88    let clonned = input.clone();
89    let input_p = parse_macro_input!(input as ItemStruct);
90    let struct_name = input_p.ident;
91
92    let extended = quote!(
93        impl #struct_name {
94            pub fn #reg_name(&self) -> #reg_type {
95                use core::mem::transmute;
96                unsafe {
97                    let addr = (self.addr as usize + #reg_offset) as *mut usize;
98                    #reg_type{addr}
99                }
100            }
101        }
102    );
103
104    let mut ts = TokenStream::from(extended);
105    ts.extend(clonned);
106    ts
107}
108
109fn gen_mask(from: u32, to: u32) -> usize {
110    let mut mask = 0;
111    for i in from..=to {
112        mask |= 1 << i;
113    }
114    mask
115}