rp235x_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        #[cfg(target_arch = "arm")]
26        {
27            // Enable the Double-Co-Pro and the GPIO Co-Pro in the CPACR register.
28            // We have to do this early, before there's a chance we might call
29            // any accelerated functions.
30            const SCB_CPACR_PTR: *mut u32 = 0xE000_ED88 as *mut u32;
31            const SCB_CPACR_FULL_ACCESS: u32 = 0b11;
32            // Do a R-M-W, because the FPU enable is here and that's already been enabled
33            let mut temp = SCB_CPACR_PTR.read_volatile();
34            // DCP Co-Pro is 4, two-bits per entry
35            temp |= SCB_CPACR_FULL_ACCESS << (4 * 2);
36            // GPIO Co-Pro is 0, two-bits per entry
37            temp |= SCB_CPACR_FULL_ACCESS << (0 * 2);
38            SCB_CPACR_PTR.write_volatile(temp);
39            // Don't allow any DCP code to be moved before this fence.
40            core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
41        }
42    })
43    .into();
44    let clear_locks = parse_macro_input!(clear_locks as Stmt);
45
46    // statics must stay first so cortex_m_rt::entry still finds them
47    let stmts = insert_after_static(f.block.stmts, clear_locks);
48    f.block.stmts = stmts;
49
50    quote!(
51        #[rp235x_hal::arch_entry]
52        #f
53    )
54    .into()
55}
56
57/// Insert new statements after initial block of statics
58fn insert_after_static(stmts: impl IntoIterator<Item = Stmt>, insert: Stmt) -> Vec<Stmt> {
59    let mut istmts = stmts.into_iter();
60    let mut stmts = vec![];
61    for stmt in istmts.by_ref() {
62        match stmt {
63            Stmt::Item(Item::Static(var)) => {
64                stmts.push(Stmt::Item(Item::Static(var)));
65            }
66            _ => {
67                stmts.push(insert);
68                stmts.push(stmt);
69                break;
70            }
71        }
72    }
73    stmts.extend(istmts);
74
75    stmts
76}