aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm/inline.rs345
-rw-r--r--asm/lib.rs133
-rw-r--r--bin/thumbv6m-none-eabi-lto.abin12016 -> 13596 bytes
-rw-r--r--bin/thumbv6m-none-eabi.abin16188 -> 18284 bytes
-rw-r--r--bin/thumbv7em-none-eabi-lto.abin16704 -> 19224 bytes
-rw-r--r--bin/thumbv7em-none-eabi.abin20056 -> 23360 bytes
-rw-r--r--bin/thumbv7em-none-eabihf-lto.abin17504 -> 20176 bytes
-rw-r--r--bin/thumbv7em-none-eabihf.abin21112 -> 24684 bytes
-rw-r--r--bin/thumbv7m-none-eabi-lto.abin15436 -> 17628 bytes
-rw-r--r--bin/thumbv7m-none-eabi.abin19044 -> 22020 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi-lto.abin13392 -> 15496 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi.abin17976 -> 20936 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi-lto.abin18040 -> 21228 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi.abin22776 -> 27220 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf-lto.abin18776 -> 22168 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf.abin23764 -> 28488 bytes
-rw-r--r--src/asm.rs295
-rw-r--r--src/call_asm.rs24
-rw-r--r--src/interrupt.rs38
-rw-r--r--src/lib.rs7
-rw-r--r--src/register/apsr.rs15
-rw-r--r--src/register/basepri.rs64
-rw-r--r--src/register/basepri_max.rs45
-rw-r--r--src/register/control.rs55
-rw-r--r--src/register/faultmask.rs36
-rw-r--r--src/register/fpscr.rs46
-rw-r--r--src/register/lr.rs22
-rw-r--r--src/register/mod.rs6
-rw-r--r--src/register/msp.rs40
-rw-r--r--src/register/msplim.rs40
-rw-r--r--src/register/pc.rs22
-rw-r--r--src/register/primask.rs37
-rw-r--r--src/register/psp.rs40
-rw-r--r--src/register/psplim.rs40
-rw-r--r--xtask/src/lib.rs7
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
index 4d2f02c..517c2a8 100644
--- a/bin/thumbv6m-none-eabi-lto.a
+++ b/bin/thumbv6m-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv6m-none-eabi.a b/bin/thumbv6m-none-eabi.a
index beedd73..05a27d7 100644
--- a/bin/thumbv6m-none-eabi.a
+++ b/bin/thumbv6m-none-eabi.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabi-lto.a b/bin/thumbv7em-none-eabi-lto.a
index 7b8a4f8..f4b6087 100644
--- a/bin/thumbv7em-none-eabi-lto.a
+++ b/bin/thumbv7em-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabi.a b/bin/thumbv7em-none-eabi.a
index 588e5cd..a33e9d1 100644
--- a/bin/thumbv7em-none-eabi.a
+++ b/bin/thumbv7em-none-eabi.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf-lto.a b/bin/thumbv7em-none-eabihf-lto.a
index 4efadd8..c3bcb56 100644
--- a/bin/thumbv7em-none-eabihf-lto.a
+++ b/bin/thumbv7em-none-eabihf-lto.a
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf.a b/bin/thumbv7em-none-eabihf.a
index fd08ba5..dbb5558 100644
--- a/bin/thumbv7em-none-eabihf.a
+++ b/bin/thumbv7em-none-eabihf.a
Binary files differ
diff --git a/bin/thumbv7m-none-eabi-lto.a b/bin/thumbv7m-none-eabi-lto.a
index 28e5860..cf9c68d 100644
--- a/bin/thumbv7m-none-eabi-lto.a
+++ b/bin/thumbv7m-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv7m-none-eabi.a b/bin/thumbv7m-none-eabi.a
index 4559ad4..644a375 100644
--- a/bin/thumbv7m-none-eabi.a
+++ b/bin/thumbv7m-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi-lto.a b/bin/thumbv8m.base-none-eabi-lto.a
index ee46792..2ad27c3 100644
--- a/bin/thumbv8m.base-none-eabi-lto.a
+++ b/bin/thumbv8m.base-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi.a b/bin/thumbv8m.base-none-eabi.a
index 26d25bd..42523f6 100644
--- a/bin/thumbv8m.base-none-eabi.a
+++ b/bin/thumbv8m.base-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi-lto.a b/bin/thumbv8m.main-none-eabi-lto.a
index e3aa0cf..bf17ac4 100644
--- a/bin/thumbv8m.main-none-eabi-lto.a
+++ b/bin/thumbv8m.main-none-eabi-lto.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi.a b/bin/thumbv8m.main-none-eabi.a
index 10bbf53..7272d7c 100644
--- a/bin/thumbv8m.main-none-eabi.a
+++ b/bin/thumbv8m.main-none-eabi.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf-lto.a b/bin/thumbv8m.main-none-eabihf-lto.a
index 1c25494..9c22c5a 100644
--- a/bin/thumbv8m.main-none-eabihf-lto.a
+++ b/bin/thumbv8m.main-none-eabihf-lto.a
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf.a b/bin/thumbv8m.main-none-eabihf.a
index 0651788..3a0a632 100644
--- a/bin/thumbv8m.main-none-eabihf.a
+++ b/bin/thumbv8m.main-none-eabihf.a
Binary files differ
diff --git a/src/asm.rs b/src/asm.rs
index 39cd8ef..3165aca 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -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.
diff --git a/src/lib.rs b/src/lib.rs
index 723816a..f0de721 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
+ );
}
}