rp2040_hal_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::quote;
6use syn::{parse, parse_macro_input, Item, ItemFn, Stmt};
7
8#[proc_macro_attribute]
9pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
10    let mut f = parse_macro_input!(input as ItemFn);
11
12    if !args.is_empty() {
13        return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
14            .to_compile_error()
15            .into();
16    }
17
18    let clear_locks: TokenStream = quote!(unsafe {
19        const SIO_BASE: u32 = 0xd0000000;
20        const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
21        const SPINLOCK_COUNT: usize = 32;
22        for i in 0..SPINLOCK_COUNT {
23            SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
24        }
25    })
26    .into();
27    let clear_locks = parse_macro_input!(clear_locks as Stmt);
28
29    // statics must stay first so cortex_m_rt::entry still finds them
30    let stmts = insert_after_static(f.block.stmts, clear_locks);
31    f.block.stmts = stmts;
32
33    quote!(
34        #[::cortex_m_rt::entry]
35        #f
36    )
37    .into()
38}
39
40/// Insert new statements after initial block of statics
41fn insert_after_static(stmts: impl IntoIterator<Item = Stmt>, insert: Stmt) -> Vec<Stmt> {
42    let mut istmts = stmts.into_iter();
43    let mut stmts = vec![];
44    for stmt in istmts.by_ref() {
45        match stmt {
46            Stmt::Item(Item::Static(var)) => {
47                stmts.push(Stmt::Item(Item::Static(var)));
48            }
49            _ => {
50                stmts.push(insert);
51                stmts.push(stmt);
52                break;
53            }
54        }
55    }
56    stmts.extend(istmts);
57
58    stmts
59}