aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs139
-rw-r--r--src/call_asm.rs24
-rw-r--r--src/interrupt.rs19
-rw-r--r--src/lib.rs40
-rw-r--r--src/peripheral/mod.rs2
-rw-r--r--src/register/apsr.rs9
-rw-r--r--src/register/basepri.rs24
-rw-r--r--src/register/basepri_max.rs23
-rw-r--r--src/register/control.rs23
-rw-r--r--src/register/faultmask.rs7
-rw-r--r--src/register/fpscr.rs7
-rw-r--r--src/register/lr.rs15
-rw-r--r--src/register/mod.rs5
-rw-r--r--src/register/msp.rs21
-rw-r--r--src/register/msplim.rs8
-rw-r--r--src/register/pc.rs15
-rw-r--r--src/register/primask.rs7
-rw-r--r--src/register/psp.rs13
-rw-r--r--src/register/psplim.rs8
19 files changed, 276 insertions, 133 deletions
diff --git a/src/asm.rs b/src/asm.rs
index 4dc1ab0..0434b5f 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -1,18 +1,17 @@
//! 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;
+#[cfg(cortex_m)]
+use core::arch::asm;
+use core::sync::atomic::{compiler_fence, Ordering};
/// 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.
+#[cfg(cortex_m)]
#[inline(always)]
pub fn bkpt() {
- call_asm!(__bkpt());
+ unsafe { asm!("bkpt", options(nomem, nostack, preserves_flags)) };
}
/// Blocks the program for *at least* `cycles` CPU cycles.
@@ -24,41 +23,66 @@ pub fn bkpt() {
/// 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.
+#[cfg(cortex_m)]
#[inline]
pub fn delay(cycles: u32) {
- call_asm!(__delay(cycles: u32));
+ // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
+ // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
+ // for more cycles is okay.
+ // Add 1 to prevent an integer underflow which would cause a long freeze
+ let real_cycles = 1 + cycles / 2;
+ unsafe {
+ asm!(
+ // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
+ "1:",
+ "subs {}, #1",
+ "bne 1b",
+ inout(reg) real_cycles => _,
+ options(nomem, nostack),
+ )
+ };
}
/// A no-operation. Useful to prevent delay loops from being optimized away.
#[inline]
pub fn nop() {
- call_asm!(__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.
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("nop", options(nomem, nostack, preserves_flags))
+ };
}
/// Generate an Undefined Instruction exception.
///
/// Can be used as a stable alternative to `core::intrinsics::abort`.
+#[cfg(cortex_m)]
#[inline]
pub fn udf() -> ! {
- call_asm!(__udf() -> !)
+ unsafe { asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)) };
}
/// Wait For Event
+#[cfg(cortex_m)]
#[inline]
pub fn wfe() {
- call_asm!(__wfe())
+ unsafe { asm!("wfe", options(nomem, nostack, preserves_flags)) };
}
/// Wait For Interrupt
+#[cfg(cortex_m)]
#[inline]
pub fn wfi() {
- call_asm!(__wfi())
+ unsafe { asm!("wfi", options(nomem, nostack, preserves_flags)) };
}
/// Send Event
+#[cfg(cortex_m)]
#[inline]
pub fn sev() {
- call_asm!(__sev())
+ unsafe { asm!("sev", options(nomem, nostack, preserves_flags)) };
}
/// Instruction Synchronization Barrier
@@ -67,7 +91,12 @@ pub fn sev() {
/// from cache or memory, after the instruction has been completed.
#[inline]
pub fn isb() {
- call_asm!(__isb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("isb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Data Synchronization Barrier
@@ -79,7 +108,12 @@ pub fn isb() {
/// * all cache and branch predictor maintenance operations before this instruction complete
#[inline]
pub fn dsb() {
- call_asm!(__dsb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("dsb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Data Memory Barrier
@@ -89,7 +123,12 @@ pub fn dsb() {
/// after the `DMB` instruction.
#[inline]
pub fn dmb() {
- call_asm!(__dmb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("dmb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Test Target
@@ -102,8 +141,15 @@ 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 {
- let addr = addr as u32;
- call_asm!(__tt(addr: u32) -> u32)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "tt {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Unprivileged
@@ -117,8 +163,15 @@ 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 {
- let addr = addr as u32;
- call_asm!(__ttt(addr: u32) -> u32)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "ttt {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Alternate Domain
@@ -133,8 +186,15 @@ 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 {
- let addr = addr as u32;
- call_asm!(__tta(addr: u32) -> u32)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "tta {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Alternate Domain Unprivileged
@@ -149,8 +209,15 @@ 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 {
- let addr = addr as u32;
- call_asm!(__ttat(addr: u32) -> u32)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "ttat {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Branch and Exchange Non-secure
@@ -160,15 +227,17 @@ pub fn ttat(addr: *mut u32) -> u32 {
#[inline]
#[cfg(armv8m)]
pub unsafe fn bx_ns(addr: u32) {
- call_asm!(__bxns(addr: u32));
+ asm!("bxns {}", in(reg) addr, options(nomem, nostack, preserves_flags));
}
/// Semihosting syscall.
///
/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
+#[cfg(cortex_m)]
#[inline]
-pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
- call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32)
+pub unsafe fn semihosting_syscall(mut nr: u32, arg: u32) -> u32 {
+ asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
+ nr
}
/// Bootstrap.
@@ -181,12 +250,27 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
///
/// `msp` and `rv` must point to valid stack memory and executable code,
/// respectively.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
// Ensure thumb mode is set.
let rv = (rv as u32) | 1;
let msp = msp as u32;
- call_asm!(__bootstrap(msp: u32, rv: u32) -> !);
+ asm!(
+ "mrs {tmp}, CONTROL",
+ "bics {tmp}, {spsel}",
+ "msr CONTROL, {tmp}",
+ "isb",
+ "msr MSP, {msp}",
+ "bx {rv}",
+ // `out(reg) _` is not permitted in a `noreturn` asm! call,
+ // so instead use `in(reg) 0` and don't restore it afterwards.
+ tmp = in(reg) 0,
+ spsel = in(reg) 2,
+ msp = in(reg) msp,
+ rv = in(reg) rv,
+ options(noreturn, nomem, nostack),
+ );
}
/// Bootload.
@@ -201,6 +285,7 @@ pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
/// The provided `vector_table` must point to a valid vector
/// table, with a valid stack pointer as the first word and
/// a valid reset vector as the second word.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn bootload(vector_table: *const u32) -> ! {
let msp = core::ptr::read_volatile(vector_table);
diff --git a/src/call_asm.rs b/src/call_asm.rs
deleted file mode 100644
index 295277f..0000000
--- a/src/call_asm.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/// 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 68719ec..06b91f1 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -1,6 +1,10 @@
//! Interrupts
pub use bare_metal::{CriticalSection, Mutex};
+#[cfg(cortex_m)]
+use core::arch::asm;
+#[cfg(cortex_m)]
+use core::sync::atomic::{compiler_fence, Ordering};
/// Trait for enums of external interrupt numbers.
///
@@ -24,9 +28,15 @@ pub unsafe trait InterruptNumber: Copy {
}
/// Disables all interrupts
+#[cfg(cortex_m)]
#[inline]
pub fn disable() {
- call_asm!(__cpsid());
+ unsafe {
+ asm!("cpsid i", options(nomem, nostack, preserves_flags));
+ }
+
+ // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
+ compiler_fence(Ordering::SeqCst);
}
/// Enables all the interrupts
@@ -34,14 +44,19 @@ pub fn disable() {
/// # Safety
///
/// - Do not call this function inside an `interrupt::free` critical section
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn enable() {
- call_asm!(__cpsie());
+ // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
+ compiler_fence(Ordering::SeqCst);
+
+ asm!("cpsie i", options(nomem, nostack, preserves_flags));
}
/// Execute closure `f` in an interrupt-free context.
///
/// This as also known as a "critical section".
+#[cfg(cortex_m)]
#[inline]
pub fn free<F, R>(f: F) -> R
where
diff --git a/src/lib.rs b/src/lib.rs
index dd46fd7..7286f06 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,53 +9,17 @@
//!
//! # Optional features
//!
-//! ## `inline-asm`
-//!
-//! When this feature is enabled the implementation of all the functions inside the `asm` and
-//! `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:
-//!
-//! - Reduced overhead. FFI eliminates the possibility of inlining so all operations include a
-//! function call overhead when `inline-asm` is not enabled.
-//!
-//! - Some of the `register` API only becomes available only when `inline-asm` is enabled. Check the
-//! API docs for details.
-//!
-//! The disadvantage is that `inline-asm` requires a nightly toolchain.
-//!
//! ## `cm7-r0p1`
//!
//! This feature enables workarounds for errata found on Cortex-M7 chips with revision r0p1. Some
//! functions in this crate only work correctly on those chips if this Cargo feature is enabled
//! (the functions are documented accordingly).
//!
-//! ## `linker-plugin-lto`
-//!
-//! This feature links against prebuilt assembly blobs that are compatible with [Linker-Plugin LTO].
-//! This allows inlining assembly routines into the caller, even without the `inline-asm` feature,
-//! and works on stable Rust (but note the drawbacks below!).
-//!
-//! If you want to use this feature, you need to be aware of a few things:
-//!
-//! - You need to make sure that `-Clinker-plugin-lto` is passed to rustc. Please refer to the
-//! [Linker-Plugin LTO] documentation for details.
-//!
-//! - You have to use a Rust version whose LLVM version is compatible with the toolchain in
-//! `asm-toolchain`.
-//!
-//! - Due to a [Rust bug][rust-lang/rust#75940] in compiler versions **before 1.49**, this option
-//! does not work with optimization levels `s` and `z`.
-//!
-//! [Linker-Plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
-//! [rust-lang/rust#75940]: https://github.com/rust-lang/rust/issues/75940
-//!
//! # Minimum Supported Rust Version (MSRV)
//!
-//! This crate is guaranteed to compile on stable Rust 1.42 and up. It *might*
+//! This crate is guaranteed to compile on stable Rust 1.59 and up. It *might*
//! compile with older versions but that may change in any new patch release.
-#![cfg_attr(feature = "inline-asm", feature(asm))]
#![deny(missing_docs)]
#![no_std]
#![allow(clippy::identity_op)]
@@ -83,8 +47,6 @@ extern crate bare_metal;
extern crate volatile_register;
#[macro_use]
-mod call_asm;
-#[macro_use]
mod macros;
pub mod asm;
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index af922b1..d1dfb6a 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -60,6 +60,7 @@
use core::marker::PhantomData;
use core::ops;
+#[cfg(cortex_m)]
use crate::interrupt;
#[cfg(cm7)]
@@ -163,6 +164,7 @@ static mut TAKEN: bool = false;
impl Peripherals {
/// Returns all the core peripherals *once*
+ #[cfg(cortex_m)]
#[inline]
pub fn take() -> Option<Self> {
interrupt::free(|_| {
diff --git a/src/register/apsr.rs b/src/register/apsr.rs
index e83435c..edb8737 100644
--- a/src/register/apsr.rs
+++ b/src/register/apsr.rs
@@ -1,5 +1,8 @@
//! Application Program Status Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Application Program Status Register
#[derive(Clone, Copy, Debug)]
pub struct Apsr {
@@ -45,10 +48,10 @@ impl Apsr {
}
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Apsr {
- let bits: u32 = call_asm!(__apsr_r() -> u32);
+ let bits;
+ unsafe { asm!("mrs {}, APSR", out(reg) bits, options(nomem, nostack, preserves_flags)) };
Apsr { bits }
}
diff --git a/src/register/basepri.rs b/src/register/basepri.rs
index 07084cd..cffb379 100644
--- a/src/register/basepri.rs
+++ b/src/register/basepri.rs
@@ -1,24 +1,42 @@
//! Base Priority Mask Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u8 {
- call_asm!(__basepri_r() -> u8)
+ let r;
+ unsafe { asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes to the CPU register
///
/// **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.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(basepri: u8) {
#[cfg(feature = "cm7-r0p1")]
{
- call_asm!(__basepri_w_cm7_r0p1(basepri: u8));
+ asm!(
+ "mrs {1}, PRIMASK",
+ "cpsid i",
+ "tst.w {1}, #1",
+ "msr BASEPRI, {0}",
+ "it ne",
+ "bxne lr",
+ "cpsie i",
+ in(reg) basepri,
+ out(reg) _,
+ options(nomem, nostack, preserves_flags),
+ );
}
#[cfg(not(feature = "cm7-r0p1"))]
{
- call_asm!(__basepri_w(basepri: u8));
+ asm!("msr BASEPRI, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
}
}
diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs
index cea3838..2881c4f 100644
--- a/src/register/basepri_max.rs
+++ b/src/register/basepri_max.rs
@@ -1,5 +1,8 @@
//! Base Priority Mask Register (conditional write)
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Writes to BASEPRI *if*
///
/// - `basepri != 0` AND `basepri::read() == 0`, OR
@@ -7,15 +10,31 @@
///
/// **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.
+#[cfg(cortex_m)]
#[inline]
pub fn write(basepri: u8) {
#[cfg(feature = "cm7-r0p1")]
{
- call_asm!(__basepri_max_cm7_r0p1(basepri: u8));
+ unsafe {
+ asm!(
+ "mrs {1}, PRIMASK",
+ "cpsid i",
+ "tst.w {1}, #1",
+ "msr BASEPRI_MAX, {0}",
+ "it ne",
+ "bxne lr",
+ "cpsie i",
+ in(reg) basepri,
+ out(reg) _,
+ options(nomem, nostack, preserves_flags),
+ );
+ }
}
#[cfg(not(feature = "cm7-r0p1"))]
{
- call_asm!(__basepri_max(basepri: u8));
+ unsafe {
+ asm!("msr BASEPRI_MAX, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
+ }
}
}
diff --git a/src/register/control.rs b/src/register/control.rs
index a991625..d781913 100644
--- a/src/register/control.rs
+++ b/src/register/control.rs
@@ -1,5 +1,10 @@
//! Control register
+#[cfg(cortex_m)]
+use core::arch::asm;
+#[cfg(cortex_m)]
+use core::sync::atomic::{compiler_fence, Ordering};
+
/// Control register
#[derive(Clone, Copy, Debug)]
pub struct Control {
@@ -150,15 +155,29 @@ impl Fpca {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Control {
- let bits: u32 = call_asm!(__control_r() -> u32);
+ let bits;
+ unsafe { asm!("mrs {}, CONTROL", out(reg) bits, options(nomem, nostack, preserves_flags)) };
Control { bits }
}
/// Writes to the CPU register.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(control: Control) {
let control = control.bits();
- call_asm!(__control_w(control: u32));
+
+ // ISB is required after writing to CONTROL,
+ // per ARM architectural requirements (see Application Note 321).
+ asm!(
+ "msr CONTROL, {}",
+ "isb",
+ in(reg) control,
+ options(nomem, nostack, preserves_flags),
+ );
+
+ // Ensure memory accesses are not reordered around the CONTROL update.
+ compiler_fence(Ordering::SeqCst);
}
diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs
index e57fa28..1d32709 100644
--- a/src/register/faultmask.rs
+++ b/src/register/faultmask.rs
@@ -1,5 +1,8 @@
//! Fault Mask Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// All exceptions are ...
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Faultmask {
@@ -24,9 +27,11 @@ impl Faultmask {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Faultmask {
- let r: u32 = call_asm!(__faultmask_r() -> u32);
+ let r: u32;
+ unsafe { asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
if r & (1 << 0) == (1 << 0) {
Faultmask::Inactive
} else {
diff --git a/src/register/fpscr.rs b/src/register/fpscr.rs
index 68692c7..bffed6c 100644
--- a/src/register/fpscr.rs
+++ b/src/register/fpscr.rs
@@ -1,5 +1,7 @@
//! Floating-point Status Control Register
+use core::arch::asm;
+
/// Floating-point Status Control Register
#[derive(Clone, Copy, Debug)]
pub struct Fpscr {
@@ -293,7 +295,8 @@ impl RMode {
/// Read the FPSCR register
#[inline]
pub fn read() -> Fpscr {
- let r: u32 = call_asm!(__fpscr_r() -> u32);
+ let r;
+ unsafe { asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags)) };
Fpscr::from_bits(r)
}
@@ -301,5 +304,5 @@ pub fn read() -> Fpscr {
#[inline]
pub unsafe fn write(fpscr: Fpscr) {
let fpscr = fpscr.bits();
- call_asm!(__fpscr_w(fpscr: u32));
+ asm!("vmsr fpscr, {}", in(reg) fpscr, options(nomem, nostack));
}
diff --git a/src/register/lr.rs b/src/register/lr.rs
index 1aa546c..02708ae 100644
--- a/src/register/lr.rs
+++ b/src/register/lr.rs
@@ -1,17 +1,20 @@
//! Link register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__lr_r() -> u32)
+ let r;
+ unsafe { asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__lr_w(bits: u32));
+ asm!("mov lr, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/mod.rs b/src/register/mod.rs
index 48d157a..aee7d21 100644
--- a/src/register/mod.rs
+++ b/src/register/mod.rs
@@ -56,13 +56,8 @@ pub mod msplim;
#[cfg(armv8m_main)]
pub mod psplim;
-// Accessing these registers requires inline assembly because their contents are tied to the current
-// stack frame
-#[cfg(feature = "inline-asm")]
pub mod apsr;
-#[cfg(feature = "inline-asm")]
pub mod lr;
-#[cfg(feature = "inline-asm")]
pub mod pc;
diff --git a/src/register/msp.rs b/src/register/msp.rs
index bccc2ae..22ce7d9 100644
--- a/src/register/msp.rs
+++ b/src/register/msp.rs
@@ -1,16 +1,27 @@
//! Main Stack Pointer
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__msp_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
+#[cfg(cortex_m)]
#[inline]
#[deprecated = "calling this function invokes Undefined Behavior, consider asm::bootstrap as an alternative"]
pub unsafe fn write(bits: u32) {
- call_asm!(__msp_w(bits: u32));
+ // Technically is writing to the stack pointer "not pushing any data to the stack"?
+ // In any event, if we don't set `nostack` here, this method is useless as the new
+ // stack value is immediately mutated by returning. Really this is just not a good
+ // method and its use is marked as deprecated.
+ asm!("msr MSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
/// Reads the Non-Secure CPU register from Secure state.
@@ -19,7 +30,9 @@ pub unsafe fn write(bits: u32) {
#[cfg(armv8m)]
#[inline]
pub fn read_ns() -> u32 {
- call_asm!(__msp_ns_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the Non-Secure CPU register from Secure state.
@@ -28,5 +41,5 @@ pub fn read_ns() -> u32 {
#[cfg(armv8m)]
#[inline]
pub unsafe fn write_ns(bits: u32) {
- call_asm!(__msp_ns_w(bits: u32));
+ asm!("msr MSP_NS, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/msplim.rs b/src/register/msplim.rs
index ac6f9ed..7b45b33 100644
--- a/src/register/msplim.rs
+++ b/src/register/msplim.rs
@@ -1,13 +1,17 @@
//! Main Stack Pointer Limit Register
+use core::arch::asm;
+
/// Reads the CPU register
#[inline]
pub fn read() -> u32 {
- call_asm!(__msplim_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__msplim_w(bits: u32))
+ asm!("msr MSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/pc.rs b/src/register/pc.rs
index 0b33629..3460664 100644
--- a/src/register/pc.rs
+++ b/src/register/pc.rs
@@ -1,17 +1,20 @@
//! Program counter
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__pc_r() -> u32)
+ let r;
+ unsafe { asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__pc_w(bits: u32));
+ asm!("mov pc, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/primask.rs b/src/register/primask.rs
index 842ca49..e95276f 100644
--- a/src/register/primask.rs
+++ b/src/register/primask.rs
@@ -1,5 +1,8 @@
//! Priority mask register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// All exceptions with configurable priority are ...
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Primask {
@@ -24,9 +27,11 @@ impl Primask {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Primask {
- let r: u32 = call_asm!(__primask_r() -> u32);
+ let r: u32;
+ unsafe { asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
if r & (1 << 0) == (1 << 0) {
Primask::Inactive
} else {
diff --git a/src/register/psp.rs b/src/register/psp.rs
index 0bca22c..c8f53b9 100644
--- a/src/register/psp.rs
+++ b/src/register/psp.rs
@@ -1,13 +1,22 @@
//! Process Stack Pointer
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__psp_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__psp_w(bits: u32))
+ // See comment on msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
+ // if MSP is currently being used as the stack pointer.
+ asm!("msr PSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/psplim.rs b/src/register/psplim.rs
index 8ee1e94..832f9c6 100644
--- a/src/register/psplim.rs
+++ b/src/register/psplim.rs
@@ -1,13 +1,17 @@
//! Process Stack Pointer Limit Register
+use core::arch::asm;
+
/// Reads the CPU register
#[inline]
pub fn read() -> u32 {
- call_asm!(__psplim_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__psplim_w(bits: u32))
+ asm!("msr PSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}