diff options
author | 2020-08-29 02:17:35 +0200 | |
---|---|---|
committer | 2020-08-29 02:47:05 +0200 | |
commit | a3572979cb88b0ca5760b4a672f652250dadf3bb (patch) | |
tree | d46c96861950cce6aa9e9a1872c9f55a18e5cf30 /asm/inline.rs | |
parent | 54f541c87b0723ad8976f978b2233d56100702b6 (diff) | |
download | cortex-m-a3572979cb88b0ca5760b4a672f652250dadf3bb.tar.gz cortex-m-a3572979cb88b0ca5760b4a672f652250dadf3bb.tar.zst cortex-m-a3572979cb88b0ca5760b4a672f652250dadf3bb.zip |
Merge asm implementations
Diffstat (limited to 'asm/inline.rs')
-rw-r--r-- | asm/inline.rs | 345 |
1 files changed, 345 insertions, 0 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); + } +} |