Add an rp2040 specific #[entry] macro. (#300)

* Add an rp2040 specific #[entry] macro.

This macro extends the one from cortex-m-rt by code to unlock
all spinlocks on boot.

* Idiomatic pointer arithmetic

Apply suggestion by @9names, improving address calculations.
(This doesn't change the generated code at opt levels 2 or "z".)

Co-authored-by: 9names <60134748+9names@users.noreply.github.com>
This commit is contained in:
Jan Niehusmann 2022-03-13 02:35:59 +01:00 committed by GitHub
parent 7aefb8680d
commit f8de8755cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 0 deletions

View file

@ -2,6 +2,7 @@
resolver = "2"
members = [
"rp2040-hal",
"rp2040-hal-macros",
"boards/adafruit-feather-rp2040",
"boards/adafruit-itsy-bitsy-rp2040",
"boards/adafruit-kb2040",

View file

@ -0,0 +1,20 @@
[package]
description = "Macros used by rp2040-hal"
license = "MIT OR Apache-2.0"
name = "rp2040-hal-macros"
readme = "README.md"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0"
proc-macro2 = "1.0"
cortex-m-rt = "0.7.0"
[dependencies.syn]
features = ["extra-traits", "full"]
version = "1.0"

View file

@ -0,0 +1,27 @@
# `rp2040-hal-macros`
Macros used by rp2040-hal.
## Entry macro
Extension of the `cortex-m-rt` `#[entry]` with rp2040 specific initialization code.
Currently, it just unlocks all spinlocks before calling the entry function.
# License
Licensed under either of
- Apache License, Version 2.0 (`APACHE2.0` or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (`MIT` or http://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

View file

@ -0,0 +1,59 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse, parse_macro_input, Item, ItemFn, Stmt};
#[proc_macro_attribute]
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let mut f = parse_macro_input!(input as ItemFn);
if !args.is_empty() {
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
.to_compile_error()
.into();
}
let clear_locks: TokenStream = quote!(unsafe {
const SIO_BASE: u32 = 0xd0000000;
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
const SPINLOCK_COUNT: usize = 32;
for i in 0..SPINLOCK_COUNT {
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
}
})
.into();
let clear_locks = parse_macro_input!(clear_locks as Stmt);
// statics must stay first so cortex_m_rt::entry still finds them
let stmts = insert_after_static(f.block.stmts, clear_locks);
f.block.stmts = stmts;
quote!(
#[::cortex_m_rt::entry]
#f
)
.into()
}
/// Insert new statements after initial block of statics
fn insert_after_static(stmts: impl IntoIterator<Item = Stmt>, insert: Stmt) -> Vec<Stmt> {
let mut istmts = stmts.into_iter();
let mut stmts = vec![];
for stmt in istmts.by_ref() {
match stmt {
Stmt::Item(Item::Static(var)) => {
stmts.push(Stmt::Item(Item::Static(var)));
}
_ => {
stmts.push(insert);
stmts.push(stmt);
break;
}
}
}
stmts.extend(istmts);
stmts
}

View file

@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
cortex-m = "0.7.2"
cortex-m-rt = ">=0.6.15,<0.8"
embedded-hal = { version = "0.2.5", features = ["unproven"] }
eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true }
embedded-time = "0.12.0"
@ -19,6 +20,7 @@ nb = "1.0"
rp2040-pac = "0.3.0"
paste = "1.0"
pio = "0.2.0"
rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" }
usb-device = "0.2.8"
vcell = "0.1"
void = { version = "1.0.2", default-features = false }

View file

@ -49,6 +49,15 @@ pub mod xosc;
pub use adc::Adc;
pub use clocks::Clock;
pub use i2c::I2C;
/// Attribute to declare the entry point of the program
///
/// This is based on and can be used like the [entry attribute from
/// cortex-m-rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html).
///
/// It extends that macro with code to unlock all spinlocks at the beginning
/// of `main`. As spinlocks are not automatically unlocked on software resets,
/// this can prevent unexpected deadlocks when running from a debugger.
pub use rp2040_hal_macros::entry;
pub use sio::Sio;
pub use spi::Spi;
pub use timer::Timer;