diff options
35 files changed, 603 insertions, 754 deletions
diff --git a/asm/inline.rs b/asm/inline.rs new file mode 100644 index 0000000..67e4925 --- /dev/null +++ b/asm/inline.rs @@ -0,0 +1,345 @@ +//! Inline assembly implementing the routines exposed in `cortex_m::asm`. +//! +//! If the `inline-asm` feature is enabled, these functions will be directly called by the +//! `cortex-m` wrappers. Otherwise, `cortex-m` links against them via prebuilt archives. +//! +//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where +//! applicable. + +#[inline(always)] +pub unsafe fn __bkpt() { + asm!("bkpt"); +} + +#[inline(always)] +pub unsafe fn __control_r() -> u32 { + let r; + asm!("mrs {}, CONTROL", out(reg) r); + r +} + +#[inline(always)] +pub unsafe fn __control_w(w: u32) { + asm!("msr CONTROL, {}", in(reg) w); +} + +#[inline(always)] +pub unsafe fn __cpsid() { + asm!("cpsid i"); +} + +#[inline(always)] +pub unsafe fn __cpsie() { + asm!("cpsie i"); +} + +#[inline(always)] +pub unsafe fn __delay(cyc: u32) { + asm!(" + 1: + nop + subs {}, #1 + bne 1b + // Branch to 1 instead of delay does not generate R_ARM_THM_JUMP8 relocation, which breaks + // linking on the thumbv6m-none-eabi target + ", in(reg) cyc); +} + +// FIXME do we need compiler fences here or should we expect them in the caller? +#[inline(always)] +pub unsafe fn __dmb() { + asm!("dmb 0xF"); +} + +#[inline(always)] +pub unsafe fn __dsb() { + asm!("dsb 0xF"); +} + +#[inline(always)] +pub unsafe fn __isb() { + asm!("isb 0xF"); +} + +#[inline(always)] +pub unsafe fn __msp_r() -> u32 { + let r; + asm!("mrs {}, MSP", out(reg) r); + r +} + +#[inline(always)] +pub unsafe fn __msp_w(val: u32) { + asm!("msr MSP, {}", in(reg) val); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __apsr_r() -> u32 { + let r; + asm!("mrs {}, APSR", out(reg) r); + r +} + +#[inline(always)] +pub unsafe fn __nop() { + // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate + // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N + // nops when they call `nop` N times, let's not add that option. + asm!("nop"); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __pc_r() -> u32 { + let r; + asm!("mov {}, R15", out(reg) r); + r +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __pc_w(val: u32) { + asm!("mov R15, {}", in(reg) val); +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __lr_r() -> u32 { + let r; + asm!("mov {}, R14", out(reg) r); + r +} + +// NOTE: No FFI shim, this requires inline asm. +#[inline(always)] +pub unsafe fn __lr_w(val: u32) { + asm!("mov R14, {}", in(reg) val); +} + +#[inline(always)] +pub unsafe fn __primask_r() -> u32 { + let r; + asm!("mrs {}, PRIMASK", out(reg) r); + r +} + +#[inline(always)] +pub unsafe fn __psp_r() -> u32 { + let r; + asm!("mrs {}, PSP", out(reg) r); + r +} + +#[inline(always)] +pub unsafe fn __psp_w(val: u32) { + asm!("msr PSP, {}", in(reg) val); +} + +#[inline(always)] +pub unsafe fn __sev() { + asm!("sev"); +} + +#[inline(always)] +pub unsafe fn __udf() -> ! { + asm!("udf #0", options(noreturn)); +} + +#[inline(always)] +pub unsafe fn __wfe() { + asm!("wfe"); +} + +#[inline(always)] +pub unsafe fn __wfi() { + asm!("wfi"); +} + +// v7m *AND* v8m.main, but *NOT* v8m.base +#[cfg(any(armv7m, armv8m_main))] +pub use self::v7m::*; +#[cfg(any(armv7m, armv8m_main))] +mod v7m { + #[inline(always)] + pub unsafe fn __basepri_max(val: u8) { + asm!("msr BASEPRI_MAX, {}", in(reg) val); + } + + #[inline(always)] + pub unsafe fn __basepri_r() -> u8 { + let r; + asm!("mrs {}, BASEPRI", out(reg) r); + r + } + + #[inline(always)] + pub unsafe fn __basepri_w(val: u8) { + asm!("msr BASEPRI, {}", in(reg) val); + } + + #[inline(always)] + pub unsafe fn __faultmask_r() -> u32 { + let r; + asm!("mrs {}, FAULTMASK", out(reg) r); + r + } + + // FIXME: compiler_fences necessary? + #[inline(always)] + pub unsafe fn __enable_icache() { + asm!( + " + ldr r0, =0xE000ED14 @ CCR + mrs r2, PRIMASK @ save critical nesting info + cpsid i @ mask interrupts + ldr r1, [r0] @ read CCR + orr.w r1, r1, #(1 << 17) @ Set bit 17, IC + str r1, [r0] @ write it back + dsb @ ensure store completes + isb @ synchronize pipeline + msr PRIMASK, r2 @ unnest critical section + ", + out("r0") _, + out("r1") _, + out("r2") _, + ); + } + + #[inline(always)] + pub unsafe fn __enable_dcache() { + asm!( + " + ldr r0, =0xE000ED14 @ CCR + mrs r2, PRIMASK @ save critical nesting info + cpsid i @ mask interrupts + ldr r1, [r0] @ read CCR + orr.w r1, r1, #(1 << 16) @ Set bit 16, DC + str r1, [r0] @ write it back + dsb @ ensure store completes + isb @ synchronize pipeline + msr PRIMASK, r2 @ unnest critical section + ", + out("r0") _, + out("r1") _, + out("r2") _, + ); + } +} + +#[cfg(armv7em)] +pub use self::v7em::*; +#[cfg(armv7em)] +mod v7em { + #[inline(always)] + pub unsafe fn __basepri_max_cm7_r0p1(val: u8) { + asm!( + " + mrs r1, PRIMASK + cpsid i + tst.w r1, #1 + msr BASEPRI_MAX, {} + it ne + bxne lr + cpsie i + ", + in(reg) val, + out("r1") _, + ); + } + + #[inline(always)] + pub unsafe fn __basepri_w_cm7_r0p1(val: u8) { + asm!( + " + mrs r1, PRIMASK + cpsid i + tst.w r1, #1 + msr BASEPRI, {} + it ne + bxne lr + cpsie i + ", + in(reg) val, + out("r1") _, + ); + } +} + +#[cfg(armv8m)] +pub use self::v8m::*; +/// Baseline and Mainline. +#[cfg(armv8m)] +mod v8m { + #[inline(always)] + pub unsafe fn __tt(mut target: u32) -> u32 { + asm!("tt {target}, {target}", target = inout(reg) target); + target + } + + #[inline(always)] + pub unsafe fn __ttt(mut target: u32) -> u32 { + asm!("ttt {target}, {target}", target = inout(reg) target); + target + } + + #[inline(always)] + pub unsafe fn __tta(mut target: u32) -> u32 { + asm!("tta {target}, {target}", target = inout(reg) target); + target + } + + #[inline(always)] + pub unsafe fn __ttat(mut target: u32) -> u32 { + asm!("ttat {target}, {target}", target = inout(reg) target); + target + } +} + +#[cfg(armv8m_main)] +pub use self::v8m_main::*; +/// Mainline only. +#[cfg(armv8m_main)] +mod v8m_main { + #[inline(always)] + pub unsafe fn __msplim_r() -> u32 { + let r; + asm!("mrs {}, MSPLIM", out(reg) r); + r + } + + #[inline(always)] + pub unsafe fn __msplim_w(val: u32) { + asm!("msr MSPLIM, {}", in(reg) val); + } + + #[inline(always)] + pub unsafe fn __psplim_r() -> u32 { + let r; + asm!("mrs {}, PSPLIM", out(reg) r); + r + } + + #[inline(always)] + pub unsafe fn __psplim_w(val: u32) { + asm!("msr PSPLIM, {}", in(reg) val); + } +} + +#[cfg(has_fpu)] +pub use self::fpu::*; +/// All targets with FPU. +#[cfg(has_fpu)] +mod fpu { + #[inline(always)] + pub unsafe fn __fpscr_r() -> u32 { + let r; + asm!("vmrs {}, fpscr", out(reg) r); + r + } + + #[inline(always)] + pub unsafe fn __fpscr_w(val: u32) { + asm!("vmsr fpscr, {}", in(reg) val); + } +} diff --git a/asm/lib.rs b/asm/lib.rs new file mode 100644 index 0000000..95e05a2 --- /dev/null +++ b/asm/lib.rs @@ -0,0 +1,133 @@ +//! FFI shim around the inline assembly in `inline.rs`. +//! +//! We use this file to precompile some assembly stubs into the static libraries you can find in +//! `bin`. Apps using the `cortex-m` crate then link against those static libraries and don't need +//! to build this file themselves. +//! +//! Nowadays the assembly stubs are no longer actual assembly files, but actually just this small +//! Rust crate that uses unstable inline assembly, coupled with the `xtask` tool to invoke rustc +//! and build the files. +//! +//! Precompiling this to a static lib allows users to call assembly routines from stable Rust, but +//! also perform [linker plugin LTO] with the precompiled artifacts to completely inline the +//! assembly routines into their code, which brings the "outline assembly" on par with "real" inline +//! assembly. +//! +//! For developers and contributors to `cortex-m`, this setup means that they don't have to install +//! any binutils, assembler, or C compiler to hack on the crate. All they need is to run `cargo +//! xtask assemble` to rebuild the archives from this file. +//! +//! Cool, right? +//! +//! # Rust version management +//! +//! Since inline assembly is still unstable, and we want to ensure that the created blobs are +//! up-to-date in CI, we have to pin the nightly version we use for this. The nightly toolchain is +//! stored in `asm-toolchain`. +//! +//! The `cargo xtask` automation will automatically install the `asm-toolchain` as well as all +//! Cortex-M targets needed to generate the blobs. +//! +//! [linker plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html + +#![feature(asm)] +#![no_std] +#![crate_type = "staticlib"] +#![deny(warnings)] + +mod inline; + +macro_rules! shims { + ( + $( fn $name:ident( $($arg:ident: $argty:ty),* ) $(-> $ret:ty)?; )+ + ) => { + $( + #[no_mangle] + pub unsafe extern "C" fn $name( + $($arg: $argty),* + ) $(-> $ret)? { + crate::inline::$name($($arg)*) + } + )+ + }; +} + +shims! { + fn __bkpt(); + fn __control_r() -> u32; + fn __control_w(w: u32); + fn __cpsid(); + fn __cpsie(); + fn __delay(cyc: u32); + fn __dmb(); + fn __isb(); + fn __msp_r() -> u32; + fn __msp_w(val: u32); + fn __nop(); + fn __primask_r() -> u32; + fn __psp_r() -> u32; + fn __psp_w(val: u32); + fn __sev(); + fn __udf(); + fn __wfe(); + fn __wfi(); +} + +#[cfg(armv7m)] +shims! { + fn __basepri_max(val: u8); + fn __basepri_r() -> u8; + fn __basepri_w(val: u8); + fn __faultmask_r() -> u32; + fn __enable_icache(); + fn __enable_dcache(); +} + +#[cfg(armv7em)] +shims! { + fn __basepri_max_cm7_r0p1(val: u8); + fn __basepri_w_cm7_r0p1(val: u8); +} + +// Baseline and Mainline. +#[cfg(armv8m)] +shims! { + fn __tt(target: u32) -> u32; + fn __ttt(target: u32) -> u32; + fn __tta(target: u32) -> u32; + fn __ttat(target: u32) -> u32; +} + +// Mainline only. +#[cfg(armv8m_main)] +shims! { + fn __msplim_r() -> u32; + fn __msplim_w(val: u32); + fn __psplim_r() -> u32; + fn __psplim_w(val: u32); +} + +// All targets with FPU. +#[cfg(has_fpu)] +shims! { + fn __fpscr_r() -> u32; + fn __fpscr_w(val: u32); +} + +/// We *must* define a panic handler here, even though nothing here should ever be able to panic. +/// +/// We prove that nothing will ever panic by calling a function that doesn't exist. If the panic +/// handler gets linked in, this causes a linker error. We always build this file with optimizations +/// enabled, but even without them the panic handler should never be linked in. +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + extern "C" { + #[link_name = "cortex-m internal error: panic handler not optimized out, please file an \ + issue at https://github.com/rust-embedded/cortex-m"] + fn __cortex_m_should_not_panic() -> !; + } + + unsafe { + __cortex_m_should_not_panic(); + } +} diff --git a/bin/thumbv6m-none-eabi-lto.a b/bin/thumbv6m-none-eabi-lto.a Binary files differindex 4d2f02c..517c2a8 100644 --- a/bin/thumbv6m-none-eabi-lto.a +++ b/bin/thumbv6m-none-eabi-lto.a diff --git a/bin/thumbv6m-none-eabi.a b/bin/thumbv6m-none-eabi.a Binary files differindex beedd73..05a27d7 100644 --- a/bin/thumbv6m-none-eabi.a +++ b/bin/thumbv6m-none-eabi.a diff --git a/bin/thumbv7em-none-eabi-lto.a b/bin/thumbv7em-none-eabi-lto.a Binary files differindex 7b8a4f8..f4b6087 100644 --- a/bin/thumbv7em-none-eabi-lto.a +++ b/bin/thumbv7em-none-eabi-lto.a diff --git a/bin/thumbv7em-none-eabi.a b/bin/thumbv7em-none-eabi.a Binary files differindex 588e5cd..a33e9d1 100644 --- a/bin/thumbv7em-none-eabi.a +++ b/bin/thumbv7em-none-eabi.a diff --git a/bin/thumbv7em-none-eabihf-lto.a b/bin/thumbv7em-none-eabihf-lto.a Binary files differindex 4efadd8..c3bcb56 100644 --- a/bin/thumbv7em-none-eabihf-lto.a +++ b/bin/thumbv7em-none-eabihf-lto.a diff --git a/bin/thumbv7em-none-eabihf.a b/bin/thumbv7em-none-eabihf.a Binary files differindex fd08ba5..dbb5558 100644 --- a/bin/thumbv7em-none-eabihf.a +++ b/bin/thumbv7em-none-eabihf.a diff --git a/bin/thumbv7m-none-eabi-lto.a b/bin/thumbv7m-none-eabi-lto.a Binary files differindex 28e5860..cf9c68d 100644 --- a/bin/thumbv7m-none-eabi-lto.a +++ b/bin/thumbv7m-none-eabi-lto.a diff --git a/bin/thumbv7m-none-eabi.a b/bin/thumbv7m-none-eabi.a Binary files differindex 4559ad4..644a375 100644 --- a/bin/thumbv7m-none-eabi.a +++ b/bin/thumbv7m-none-eabi.a diff --git a/bin/thumbv8m.base-none-eabi-lto.a b/bin/thumbv8m.base-none-eabi-lto.a Binary files differindex ee46792..2ad27c3 100644 --- a/bin/thumbv8m.base-none-eabi-lto.a +++ b/bin/thumbv8m.base-none-eabi-lto.a diff --git a/bin/thumbv8m.base-none-eabi.a b/bin/thumbv8m.base-none-eabi.a Binary files differindex 26d25bd..42523f6 100644 --- a/bin/thumbv8m.base-none-eabi.a +++ b/bin/thumbv8m.base-none-eabi.a diff --git a/bin/thumbv8m.main-none-eabi-lto.a b/bin/thumbv8m.main-none-eabi-lto.a Binary files differindex e3aa0cf..bf17ac4 100644 --- a/bin/thumbv8m.main-none-eabi-lto.a +++ b/bin/thumbv8m.main-none-eabi-lto.a diff --git a/bin/thumbv8m.main-none-eabi.a b/bin/thumbv8m.main-none-eabi.a Binary files differindex 10bbf53..7272d7c 100644 --- a/bin/thumbv8m.main-none-eabi.a +++ b/bin/thumbv8m.main-none-eabi.a diff --git a/bin/thumbv8m.main-none-eabihf-lto.a b/bin/thumbv8m.main-none-eabihf-lto.a Binary files differindex 1c25494..9c22c5a 100644 --- a/bin/thumbv8m.main-none-eabihf-lto.a +++ b/bin/thumbv8m.main-none-eabihf-lto.a diff --git a/bin/thumbv8m.main-none-eabihf.a b/bin/thumbv8m.main-none-eabihf.a Binary files differindex 0651788..3a0a632 100644 --- a/bin/thumbv8m.main-none-eabihf.a +++ b/bin/thumbv8m.main-none-eabihf.a @@ -1,27 +1,18 @@ //! Miscellaneous assembly instructions +// When inline assembly is enabled, pull in the assembly routines here. `call_asm!` will invoke +// these routines. +#[cfg(feature = "inline-asm")] +#[path = "../asm/inline.rs"] +pub(crate) mod inline; + /// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint". /// /// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an /// exception. #[inline(always)] pub fn bkpt() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("bkpt" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __bkpt(); - } - - __bkpt(); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__bkpt()); } /// Blocks the program for *at least* `n` instruction cycles @@ -29,151 +20,47 @@ pub fn bkpt() { /// This is implemented in assembly so its execution time is independent of the optimization /// level, however it is dependent on the specific architecture and core configuration. /// -/// NOTE that the delay can take much longer if interrupts are serviced during its execution +/// NOTE that the delay can take much longer if interrupts are serviced during its execution /// and the execution time may vary with other factors. This delay is mainly useful for simple /// timer-less initialization of peripherals if and only if accurate timing is not essential. In /// any other case please use a more accurate method to produce a delay. #[inline] -pub fn delay(_n: u32) { +pub fn delay(n: u32) { // NOTE(divide by 4) is easier to compute than `/ 3` because it's just a shift (`>> 2`). - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("1: - nop - subs $0, $$1 - bne.n 1b" - : "+r"(_n / 4 + 1) - : - : "cpsr" - : "volatile"); - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __delay(n: u32); - } - - __delay(_n / 4 + 1); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let real_cyc = n / 4 + 1; + call_asm!(__delay(real_cyc: u32)); } /// A no-operation. Useful to prevent delay loops from being optimized away. #[inline] pub fn nop() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("nop" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __nop(); - } - - __nop() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__nop()); } - /// Generate an Undefined Instruction exception. /// /// Can be used as a stable alternative to `core::intrinsics::abort`. #[inline] pub fn udf() -> ! { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("udf" :::: "volatile"); - core::hint::unreachable_unchecked(); - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __udf(); - } - - __udf(); - - core::hint::unreachable_unchecked(); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__udf() -> !) } /// Wait For Event #[inline] pub fn wfe() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("wfe" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __wfe(); - } - - __wfe() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__wfe()) } /// Wait For Interrupt #[inline] pub fn wfi() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("wfi" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __wfi(); - } - - __wfi() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__wfi()) } /// Send Event #[inline] pub fn sev() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("sev" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __sev(); - } - - __sev() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__sev()) } /// Instruction Synchronization Barrier @@ -182,23 +69,7 @@ pub fn sev() { /// from cache or memory, after the instruction has been completed. #[inline] pub fn isb() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("isb 0xF" ::: "memory" : "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __isb(); - } - - __isb() - // XXX do we need a explicit compiler barrier here? - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__isb()) } /// Data Synchronization Barrier @@ -210,23 +81,7 @@ pub fn isb() { /// * all cache and branch predictor maintenance operations before this instruction complete #[inline] pub fn dsb() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("dsb 0xF" ::: "memory" : "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __dsb(); - } - - __dsb() - // XXX do we need a explicit compiler barrier here? - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__dsb()) } /// Data Memory Barrier @@ -236,23 +91,7 @@ pub fn dsb() { /// after the `DMB` instruction. #[inline] pub fn dmb() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("dmb 0xF" ::: "memory" : "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __dmb(); - } - - __dmb() - // XXX do we need a explicit compiler barrier here? - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__dmb()) } /// Test Target @@ -265,28 +104,8 @@ pub fn dmb() { // The __tt function does not dereference the pointer received. #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn tt(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("tt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __tt(_: *mut u32) -> u32; - } - - __tt(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let addr = addr as u32; + call_asm!(__tt(addr: u32) -> u32) } /// Test Target Unprivileged @@ -300,28 +119,8 @@ pub fn tt(addr: *mut u32) -> u32 { // The __ttt function does not dereference the pointer received. #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn ttt(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("ttt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __ttt(_: *mut u32) -> u32; - } - - __ttt(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let addr = addr as u32; + call_asm!(__ttt(addr: u32) -> u32) } /// Test Target Alternate Domain @@ -336,28 +135,8 @@ pub fn ttt(addr: *mut u32) -> u32 { // The __tta function does not dereference the pointer received. #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn tta(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("tta $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __tta(_: *mut u32) -> u32; - } - - __tta(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let addr = addr as u32; + call_asm!(__tta(addr: u32) -> u32) } /// Test Target Alternate Domain Unprivileged @@ -372,26 +151,6 @@ pub fn tta(addr: *mut u32) -> u32 { // The __ttat function does not dereference the pointer received. #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn ttat(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("ttat $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __ttat(_: *mut u32) -> u32; - } - - __ttat(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let addr = addr as u32; + call_asm!(__ttat(addr: u32) -> u32) } diff --git a/src/call_asm.rs b/src/call_asm.rs new file mode 100644 index 0000000..295277f --- /dev/null +++ b/src/call_asm.rs @@ -0,0 +1,24 @@ +/// An internal macro to invoke an assembly routine. +/// +/// Depending on whether the unstable `inline-asm` feature is enabled, this will either call into +/// the inline assembly implementation directly, or through the FFI shim (see `asm/lib.rs`). +macro_rules! call_asm { + ( $func:ident ( $($args:ident: $tys:ty),* ) $(-> $ret:ty)? ) => {{ + #[allow(unused_unsafe)] + unsafe { + match () { + #[cfg(feature = "inline-asm")] + () => crate::asm::inline::$func($($args),*), + + #[cfg(not(feature = "inline-asm"))] + () => { + extern "C" { + fn $func($($args: $tys),*) $(-> $ret)?; + } + + $func($($args),*) + }, + } + } + }}; +} diff --git a/src/interrupt.rs b/src/interrupt.rs index c5da48d..68719ec 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -26,25 +26,7 @@ pub unsafe trait InterruptNumber: Copy { /// Disables all interrupts #[inline] pub fn disable() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("cpsid i" ::: "memory" : "volatile"); - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __cpsid(); - } - - // XXX do we need a explicit compiler barrier here? - __cpsid(); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__cpsid()); } /// Enables all the interrupts @@ -54,23 +36,7 @@ pub fn disable() { /// - Do not call this function inside an `interrupt::free` critical section #[inline] pub unsafe fn enable() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("cpsie i" ::: "memory" : "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __cpsie(); - } - - // XXX do we need a explicit compiler barrier here? - __cpsie(); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__cpsie()); } /// Execute closure `f` in an interrupt-free context. @@ -12,7 +12,7 @@ //! ## `inline-asm` //! //! When this feature is enabled the implementation of all the functions inside the `asm` and -//! `register` modules use inline assembly (`llvm_asm!`) instead of external assembly (FFI into separate +//! `register` modules use inline assembly (`asm!`) instead of external assembly (FFI into separate //! assembly files pre-compiled using `arm-none-eabi-gcc`). The advantages of enabling `inline-asm` //! are: //! @@ -55,14 +55,13 @@ //! This crate is guaranteed to compile on stable Rust 1.31 and up. It *might* //! compile with older versions but that may change in any new patch release. -#![cfg_attr(feature = "inline-asm", feature(llvm_asm))] +#![cfg_attr(feature = "inline-asm", feature(asm))] #![deny(missing_docs)] #![no_std] #![allow(clippy::identity_op)] #![allow(clippy::missing_safety_doc)] // Prevent clippy from complaining about empty match expression that are used for cfg gating. #![allow(clippy::match_single_binding)] - // This makes clippy warn about public functions which are not #[inline]. // // Almost all functions in this crate result in trivial or even no assembly. @@ -82,6 +81,8 @@ extern crate bare_metal; extern crate volatile_register; #[macro_use] +mod call_asm; +#[macro_use] mod macros; pub mod asm; diff --git a/src/register/apsr.rs b/src/register/apsr.rs index 3db8aeb..b81d892 100644 --- a/src/register/apsr.rs +++ b/src/register/apsr.rs @@ -50,17 +50,6 @@ impl Apsr { /// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] pub fn read() -> Apsr { - match () { - #[cfg(cortex_m)] - () => { - let r: u32; - unsafe { - llvm_asm!("mrs $0, APSR" : "=r"(r) ::: "volatile"); - } - Apsr { bits: r } - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let bits: u32 = call_asm!(__apsr_r() -> u32); + Apsr { bits } } diff --git a/src/register/basepri.rs b/src/register/basepri.rs index 6caf938..07084cd 100644 --- a/src/register/basepri.rs +++ b/src/register/basepri.rs @@ -3,28 +3,7 @@ /// Reads the CPU register #[inline] pub fn read() -> u8 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r: u32; - unsafe { - llvm_asm!("mrs $0, BASEPRI" : "=r"(r) ::: "volatile"); - } - r as u8 - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __basepri_r() -> u8; - } - - __basepri_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__basepri_r() -> u8) } /// Writes to the CPU register @@ -32,39 +11,14 @@ pub fn read() -> u8 { /// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the /// `cm7-r0p1` Cargo feature or this function WILL misbehave. #[inline] -pub unsafe fn write(_basepri: u8) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => match () { - #[cfg(not(feature = "cm7-r0p1"))] - () => llvm_asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), - #[cfg(feature = "cm7-r0p1")] - () => crate::interrupt::free( - |_| llvm_asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), - ), - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => match () { - #[cfg(not(feature = "cm7-r0p1"))] - () => { - extern "C" { - fn __basepri_w(_: u8); - } - - __basepri_w(_basepri); - } - #[cfg(feature = "cm7-r0p1")] - () => { - extern "C" { - fn __basepri_w_cm7_r0p1(_: u8); - } - - __basepri_w_cm7_r0p1(_basepri); - } - }, +pub unsafe fn write(basepri: u8) { + #[cfg(feature = "cm7-r0p1")] + { + call_asm!(__basepri_w_cm7_r0p1(basepri: u8)); + } - #[cfg(not(cortex_m))] - () => unimplemented!(), + #[cfg(not(feature = "cm7-r0p1"))] + { + call_asm!(__basepri_w(basepri: u8)); } } diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs index 0e66f69..cea3838 100644 --- a/src/register/basepri_max.rs +++ b/src/register/basepri_max.rs @@ -8,43 +8,14 @@ /// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the /// `cm7-r0p1` Cargo feature or this function WILL misbehave. #[inline] -pub fn write(_basepri: u8) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - match () { - #[cfg(not(feature = "cm7-r0p1"))] - () => llvm_asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), - #[cfg(feature = "cm7-r0p1")] - () => crate::interrupt::free( - |_| llvm_asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), - ), - } - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - match () { - #[cfg(not(feature = "cm7-r0p1"))] - () => { - extern "C" { - fn __basepri_max(_: u8); - } - - __basepri_max(_basepri) - } - #[cfg(feature = "cm7-r0p1")] - () => { - extern "C" { - fn __basepri_max_cm7_r0p1(_: u8); - } - - __basepri_max_cm7_r0p1(_basepri) - } - } - }, +pub fn write(basepri: u8) { + #[cfg(feature = "cm7-r0p1")] + { + call_asm!(__basepri_max_cm7_r0p1(basepri: u8)); + } - #[cfg(not(cortex_m))] - () => unimplemented!(), + #[cfg(not(feature = "cm7-r0p1"))] + { + call_asm!(__basepri_max(basepri: u8)); } } diff --git a/src/register/control.rs b/src/register/control.rs index 211b532..938b10f 100644 --- a/src/register/control.rs +++ b/src/register/control.rs @@ -156,58 +156,13 @@ impl Fpca { /// Reads the CPU register #[inline] pub fn read() -> Control { - match () { - #[cfg(cortex_m)] - () => { - let r = match () { - #[cfg(feature = "inline-asm")] - () => { - let r: u32; - unsafe { llvm_asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(feature = "inline-asm"))] - () => unsafe { - extern "C" { - fn __control_r() -> u32; - } - - __control_r() - }, - }; - - Control { bits: r } - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let bits: u32 = call_asm!(__control_r() -> u32); + Control { bits } } /// Writes to the CPU register. #[inline] -pub unsafe fn write(_control: Control) { - match () { - #[cfg(cortex_m)] - () => match () { - #[cfg(feature = "inline-asm")] - () => { - let control = _control.bits(); - llvm_asm!("msr CONTROL, $0" :: "r"(control) : "memory" : "volatile"); - } - - #[cfg(not(feature = "inline-asm"))] - () => { - extern "C" { - fn __control_w(bits: u32); - } - - __control_w(_control.bits()); - } - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(control: Control) { + let control = control.bits(); + call_asm!(__control_w(control: u32)); } diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs index 06f60fe..1f19d97 100644 --- a/src/register/faultmask.rs +++ b/src/register/faultmask.rs @@ -27,36 +27,10 @@ impl Faultmask { /// Reads the CPU register #[inline] pub fn read() -> Faultmask { - match () { - #[cfg(cortex_m)] - () => { - let r = match () { - #[cfg(feature = "inline-asm")] - () => { - let r: u32; - unsafe { llvm_asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(feature = "inline-asm"))] - () => unsafe { - extern "C" { - fn __faultmask() -> u32; - - } - - __faultmask() - }, - }; - - if r & (1 << 0) == (1 << 0) { - Faultmask::Inactive - } else { - Faultmask::Active - } - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), + let r: u32 = call_asm!(__faultmask_r() -> u32); + if r & (1 << 0) == (1 << 0) { + Faultmask::Inactive + } else { + Faultmask::Active } } diff --git a/src/register/fpscr.rs b/src/register/fpscr.rs index 2ca00e1..dd538e9 100644 --- a/src/register/fpscr.rs +++ b/src/register/fpscr.rs @@ -295,49 +295,13 @@ impl RMode { /// Read the FPSCR register #[inline] pub fn read() -> Fpscr { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r: u32; - unsafe { - llvm_asm!("vmrs $0, fpscr" : "=r"(r) ::: "volatile"); - } - Fpscr::from_bits(r) - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __get_FPSCR() -> u32; - } - Fpscr::from_bits(__get_FPSCR()) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + let r: u32 = call_asm!(__fpscr_r() -> u32); + Fpscr::from_bits(r) } /// Set the value of the FPSCR register #[inline] -pub unsafe fn write(_fspcr: Fpscr) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let bits = _fspcr.bits(); - llvm_asm!("vmsr fpscr, $0" :: "r"(bits) :: "volatile"); - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __set_FPSCR(bits: u32); - } - - __set_FPSCR(_fspcr.bits()); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(fpscr: Fpscr) { + let fpscr = fpscr.bits(); + call_asm!(__fpscr_w(fpscr: u32)); } diff --git a/src/register/lr.rs b/src/register/lr.rs index 6919e10..1aa546c 100644 --- a/src/register/lr.rs +++ b/src/register/lr.rs @@ -5,29 +5,13 @@ /// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] pub fn read() -> u32 { - match () { - #[cfg(cortex_m)] - () => { - let r: u32; - unsafe { llvm_asm!("mov $0,R14" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__lr_r() -> u32) } /// Writes `bits` to the CPU register /// /// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(cortex_m)] - () => llvm_asm!("mov R14,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__lr_w(bits: u32)); } diff --git a/src/register/mod.rs b/src/register/mod.rs index efbe6ef..48d157a 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -58,11 +58,11 @@ pub mod psplim; // Accessing these registers requires inline assembly because their contents are tied to the current // stack frame -#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] +#[cfg(feature = "inline-asm")] pub mod apsr; -#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] +#[cfg(feature = "inline-asm")] pub mod lr; -#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] +#[cfg(feature = "inline-asm")] pub mod pc; diff --git a/src/register/msp.rs b/src/register/msp.rs index b5460ed..275023d 100644 --- a/src/register/msp.rs +++ b/src/register/msp.rs @@ -3,45 +3,11 @@ /// Reads the CPU register #[inline] pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __msp_r() -> u32; - } - - __msp_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__msp_r() -> u32) } /// Writes `bits` to the CPU register #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr MSP,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __msp_w(_: u32); - } - - __msp_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__msp_w(bits: u32)); } diff --git a/src/register/msplim.rs b/src/register/msplim.rs index 68915c4..ac6f9ed 100644 --- a/src/register/msplim.rs +++ b/src/register/msplim.rs @@ -3,45 +3,11 @@ /// Reads the CPU register #[inline] pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,MSPLIM" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __msplim_r() -> u32; - } - - __msplim_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__msplim_r() -> u32) } /// Writes `bits` to the CPU register #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr MSPLIM,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __msplim_w(_: u32); - } - - __msplim_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__msplim_w(bits: u32)) } diff --git a/src/register/pc.rs b/src/register/pc.rs index f4486c4..0b33629 100644 --- a/src/register/pc.rs +++ b/src/register/pc.rs @@ -5,29 +5,13 @@ /// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] pub fn read() -> u32 { - match () { - #[cfg(cortex_m)] - () => { - let r; - unsafe { llvm_asm!("mov $0,R15" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__pc_r() -> u32) } /// Writes `bits` to the CPU register /// /// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(cortex_m)] - () => llvm_asm!("mov R15,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__pc_w(bits: u32)); } diff --git a/src/register/primask.rs b/src/register/primask.rs index 4b6df3c..20692a2 100644 --- a/src/register/primask.rs +++ b/src/register/primask.rs @@ -27,35 +27,14 @@ impl Primask { /// Reads the CPU register #[inline] pub fn read() -> Primask { - match () { - #[cfg(cortex_m)] - () => { - let r = match () { - #[cfg(feature = "inline-asm")] - () => { - let r: u32; - unsafe { llvm_asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(feature = "inline-asm"))] - () => { - extern "C" { - fn __primask() -> u32; - } - - unsafe { __primask() } - } - }; - - if r & (1 << 0) == (1 << 0) { - Primask::Inactive - } else { - Primask::Active - } - } + fn read_raw() -> u32 { + call_asm!(__primask_r() -> u32) + } - #[cfg(not(cortex_m))] - () => unimplemented!(), + let r = read_raw(); + if r & (1 << 0) == (1 << 0) { + Primask::Inactive + } else { + Primask::Active } } diff --git a/src/register/psp.rs b/src/register/psp.rs index c020e4f..0bca22c 100644 --- a/src/register/psp.rs +++ b/src/register/psp.rs @@ -3,45 +3,11 @@ /// Reads the CPU register #[inline] pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __psp_r() -> u32; - } - - __psp_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__psp_r() -> u32) } /// Writes `bits` to the CPU register #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr PSP,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __psp_w(_: u32); - } - - __psp_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__psp_w(bits: u32)) } diff --git a/src/register/psplim.rs b/src/register/psplim.rs index 8cb8f1c..8ee1e94 100644 --- a/src/register/psplim.rs +++ b/src/register/psplim.rs @@ -3,45 +3,11 @@ /// Reads the CPU register #[inline] pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,PSPLIM" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __psplim_r() -> u32; - } - - __psplim_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } + call_asm!(__psplim_r() -> u32) } /// Writes `bits` to the CPU register #[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr PSPLIM,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __psplim_w(_: u32); - } - - __psplim_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } +pub unsafe fn write(bits: u32) { + call_asm!(__psplim_w(bits: u32)) } diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 4575f65..e6248d1 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -68,7 +68,7 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) { // Pass output and input file. cmd.arg("-o").arg(&obj_file); - cmd.arg("asm.rs"); + cmd.arg("asm/lib.rs"); println!("{:?}", cmd); let status = cmd.status().unwrap(); @@ -198,7 +198,10 @@ pub fn check_blobs() { for ((file, before), (_, after)) in files_before.iter().zip(files_after.iter()) { if before != after { - panic!("{} differs between rebuilds", file); + panic!( + "{} is not up-to-date, please run `cargo xtask assemble`", + file + ); } } |