aboutsummaryrefslogtreecommitdiff
path: root/asm/inline.rs
diff options
context:
space:
mode:
Diffstat (limited to 'asm/inline.rs')
-rw-r--r--asm/inline.rs448
1 files changed, 0 insertions, 448 deletions
diff --git a/asm/inline.rs b/asm/inline.rs
deleted file mode 100644
index bbc04d2..0000000
--- a/asm/inline.rs
+++ /dev/null
@@ -1,448 +0,0 @@
-//! 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.
-
-use core::arch::asm;
-use core::sync::atomic::{compiler_fence, Ordering};
-
-#[inline(always)]
-pub unsafe fn __bkpt() {
- asm!("bkpt", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __control_r() -> u32 {
- let r;
- asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __control_w(w: u32) {
- // ISB is required after writing to CONTROL,
- // per ARM architectural requirements (see Application Note 321).
- asm!(
- "msr CONTROL, {}",
- "isb",
- in(reg) w,
- options(nomem, nostack, preserves_flags),
- );
-
- // Ensure memory accesses are not reordered around the CONTROL update.
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __cpsid() {
- asm!("cpsid i", options(nomem, nostack, preserves_flags));
-
- // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __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));
-}
-
-#[inline(always)]
-pub unsafe fn __delay(cyc: 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_cyc = 1 + cyc / 2;
- asm!(
- // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
- "1:",
- "subs {}, #1",
- "bne 1b",
- inout(reg) real_cyc => _,
- options(nomem, nostack),
- );
-}
-
-#[inline(always)]
-pub unsafe fn __dmb() {
- compiler_fence(Ordering::SeqCst);
- asm!("dmb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __dsb() {
- compiler_fence(Ordering::SeqCst);
- asm!("dsb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __isb() {
- compiler_fence(Ordering::SeqCst);
- asm!("isb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __msp_r() -> u32 {
- let r;
- asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __msp_w(val: 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 higher-level use is marked as deprecated in cortex-m.
- asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __apsr_r() -> u32 {
- let r;
- asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags));
- 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", options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __pc_r() -> u32 {
- let r;
- asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __pc_w(val: u32) {
- asm!("mov pc, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __lr_r() -> u32 {
- let r;
- asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __lr_w(val: u32) {
- asm!("mov lr, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __primask_r() -> u32 {
- let r;
- asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __psp_r() -> u32 {
- let r;
- asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __psp_w(val: 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) val, options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __sev() {
- asm!("sev", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __udf() -> ! {
- asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __wfe() {
- asm!("wfe", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __wfi() {
- asm!("wfi", options(nomem, nostack, preserves_flags));
-}
-
-/// Semihosting syscall.
-#[inline(always)]
-pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 {
- asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
- nr
-}
-
-/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`.
-#[inline(always)]
-pub unsafe fn __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),
- );
-}
-
-// v7m *AND* v8m.main, but *NOT* v8m.base
-#[cfg(any(armv7m, armv8m_main))]
-pub use self::v7m::*;
-#[cfg(any(armv7m, armv8m_main))]
-mod v7m {
- use core::arch::asm;
- use core::sync::atomic::{compiler_fence, Ordering};
-
- #[inline(always)]
- pub unsafe fn __basepri_max(val: u8) {
- asm!("msr BASEPRI_MAX, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_r() -> u8 {
- let r;
- asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_w(val: u8) {
- asm!("msr BASEPRI, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __faultmask_r() -> u32 {
- let r;
- asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __enable_icache() {
- asm!(
- "ldr {0}, =0xE000ED14", // CCR
- "mrs {2}, PRIMASK", // save critical nesting info
- "cpsid i", // mask interrupts
- "ldr {1}, [{0}]", // read CCR
- "orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC
- "str {1}, [{0}]", // write it back
- "dsb", // ensure store completes
- "isb", // synchronize pipeline
- "msr PRIMASK, {2}", // unnest critical section
- out(reg) _,
- out(reg) _,
- out(reg) _,
- options(nostack),
- );
- compiler_fence(Ordering::SeqCst);
- }
-
- #[inline(always)]
- pub unsafe fn __enable_dcache() {
- asm!(
- "ldr {0}, =0xE000ED14", // CCR
- "mrs {2}, PRIMASK", // save critical nesting info
- "cpsid i", // mask interrupts
- "ldr {1}, [{0}]", // read CCR
- "orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC
- "str {1}, [{0}]", // write it back
- "dsb", // ensure store completes
- "isb", // synchronize pipeline
- "msr PRIMASK, {2}", // unnest critical section
- out(reg) _,
- out(reg) _,
- out(reg) _,
- options(nostack),
- );
- compiler_fence(Ordering::SeqCst);
- }
-}
-
-#[cfg(armv7em)]
-pub use self::v7em::*;
-#[cfg(armv7em)]
-mod v7em {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI_MAX, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) val,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) val,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
-}
-
-#[cfg(armv8m)]
-pub use self::v8m::*;
-/// Baseline and Mainline.
-#[cfg(armv8m)]
-mod v8m {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __tt(mut target: u32) -> u32 {
- asm!(
- "tt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __ttt(mut target: u32) -> u32 {
- asm!(
- "ttt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __tta(mut target: u32) -> u32 {
- asm!(
- "tta {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __ttat(mut target: u32) -> u32 {
- asm!(
- "ttat {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __msp_ns_r() -> u32 {
- let r;
- asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __msp_ns_w(val: u32) {
- asm!("msr MSP_NS, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __bxns(val: u32) {
- asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-}
-
-#[cfg(armv8m_main)]
-pub use self::v8m_main::*;
-/// Mainline only.
-#[cfg(armv8m_main)]
-mod v8m_main {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __msplim_r() -> u32 {
- let r;
- asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __msplim_w(val: u32) {
- asm!("msr MSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __psplim_r() -> u32 {
- let r;
- asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __psplim_w(val: u32) {
- asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-}
-
-#[cfg(has_fpu)]
-pub use self::fpu::*;
-/// All targets with FPU.
-#[cfg(has_fpu)]
-mod fpu {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __fpscr_r() -> u32 {
- let r;
- asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __fpscr_w(val: u32) {
- asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack));
- }
-}