diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm.rs | 28 | ||||
-rw-r--r-- | src/interrupt.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/peripheral/icb.rs | 30 | ||||
-rw-r--r-- | src/peripheral/itm.rs | 13 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 49 | ||||
-rw-r--r-- | src/peripheral/mpu.rs | 37 | ||||
-rw-r--r-- | src/peripheral/scb.rs | 26 | ||||
-rw-r--r-- | src/register/apsr.rs | 2 | ||||
-rw-r--r-- | src/register/basepri.rs | 6 | ||||
-rw-r--r-- | src/register/basepri_max.rs | 4 | ||||
-rw-r--r-- | src/register/control.rs | 4 | ||||
-rw-r--r-- | src/register/faultmask.rs | 2 | ||||
-rw-r--r-- | src/register/fpscr.rs | 343 | ||||
-rw-r--r-- | src/register/lr.rs | 4 | ||||
-rw-r--r-- | src/register/mod.rs | 7 | ||||
-rw-r--r-- | src/register/msp.rs | 4 | ||||
-rw-r--r-- | src/register/msplim.rs | 4 | ||||
-rw-r--r-- | src/register/pc.rs | 4 | ||||
-rw-r--r-- | src/register/primask.rs | 2 | ||||
-rw-r--r-- | src/register/psp.rs | 4 | ||||
-rw-r--r-- | src/register/psplim.rs | 4 |
22 files changed, 533 insertions, 52 deletions
@@ -8,7 +8,7 @@ pub fn bkpt() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("bkpt" :::: "volatile") }, + () => unsafe { llvm_asm!("bkpt" :::: "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -36,7 +36,7 @@ pub fn delay(_n: u32) { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] () => unsafe { - asm!("1: + llvm_asm!("1: nop subs $0, $$1 bne.n 1b" @@ -65,7 +65,7 @@ pub fn delay(_n: u32) { pub fn nop() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("nop" :::: "volatile") }, + () => unsafe { llvm_asm!("nop" :::: "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -90,7 +90,7 @@ pub fn udf() -> ! { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] () => unsafe { - asm!("udf" :::: "volatile"); + llvm_asm!("udf" :::: "volatile"); core::hint::unreachable_unchecked(); }, @@ -115,7 +115,7 @@ pub fn udf() -> ! { pub fn wfe() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("wfe" :::: "volatile") }, + () => unsafe { llvm_asm!("wfe" :::: "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -136,7 +136,7 @@ pub fn wfe() { pub fn wfi() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("wfi" :::: "volatile") }, + () => unsafe { llvm_asm!("wfi" :::: "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -157,7 +157,7 @@ pub fn wfi() { pub fn sev() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("sev" :::: "volatile") }, + () => unsafe { llvm_asm!("sev" :::: "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -181,7 +181,7 @@ pub fn sev() { pub fn isb() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("isb 0xF" ::: "memory" : "volatile") }, + () => unsafe { llvm_asm!("isb 0xF" ::: "memory" : "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -209,7 +209,7 @@ pub fn isb() { pub fn dsb() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("dsb 0xF" ::: "memory" : "volatile") }, + () => unsafe { llvm_asm!("dsb 0xF" ::: "memory" : "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -235,7 +235,7 @@ pub fn dsb() { pub fn dmb() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { asm!("dmb 0xF" ::: "memory" : "volatile") }, + () => unsafe { llvm_asm!("dmb 0xF" ::: "memory" : "volatile") }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => unsafe { @@ -267,7 +267,7 @@ pub fn tt(addr: *mut u32) -> u32 { () => { let tt_resp: u32; unsafe { - asm!("tt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); + llvm_asm!("tt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); } tt_resp } @@ -302,7 +302,7 @@ pub fn ttt(addr: *mut u32) -> u32 { () => { let tt_resp: u32; unsafe { - asm!("ttt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); + llvm_asm!("ttt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); } tt_resp } @@ -338,7 +338,7 @@ pub fn tta(addr: *mut u32) -> u32 { () => { let tt_resp: u32; unsafe { - asm!("tta $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); + llvm_asm!("tta $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); } tt_resp } @@ -374,7 +374,7 @@ pub fn ttat(addr: *mut u32) -> u32 { () => { let tt_resp: u32; unsafe { - asm!("ttat $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); + llvm_asm!("ttat $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); } tt_resp } diff --git a/src/interrupt.rs b/src/interrupt.rs index 2d53865..4d5ef0f 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -10,7 +10,7 @@ pub fn disable() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] () => unsafe { - asm!("cpsid i" ::: "memory" : "volatile"); + llvm_asm!("cpsid i" ::: "memory" : "volatile"); }, #[cfg(all(cortex_m, not(feature = "inline-asm")))] @@ -37,7 +37,7 @@ pub fn disable() { pub unsafe fn enable() { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => asm!("cpsie i" ::: "memory" : "volatile"), + () => llvm_asm!("cpsie i" ::: "memory" : "volatile"), #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => { @@ -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 (`asm!`) instead of external assembly (FFI into separate +//! `register` modules use inline assembly (`llvm_asm!`) instead of external assembly (FFI into separate //! assembly files pre-compiled using `arm-none-eabi-gcc`). The advantages of enabling `inline-asm` //! are: //! @@ -29,7 +29,7 @@ //! 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(asm))] +#![cfg_attr(feature = "inline-asm", feature(llvm_asm))] #![deny(missing_docs)] #![no_std] #![allow(clippy::identity_op)] diff --git a/src/peripheral/icb.rs b/src/peripheral/icb.rs new file mode 100644 index 0000000..77ffd5d --- /dev/null +++ b/src/peripheral/icb.rs @@ -0,0 +1,30 @@ +//! Implementation Control Block + +use volatile_register::{RO, RW}; + +/// Register block +#[repr(C)] +pub struct RegisterBlock { + /// Interrupt Controller Type Register + /// + /// The bottom four bits of this register give the number of implemented + /// interrupt lines, divided by 32. So a value of `0b0010` indicates 64 + /// interrupts. + #[cfg(any(armv7m, armv8m, target_arch = "x86_64"))] + pub ictr: RO<u32>, + + /// The ICTR is not defined in the ARMv6-M Architecture Reference manual, so + /// we replace it with this. + #[cfg(not(any(armv7m, armv8m, target_arch = "x86_64")))] + _reserved: u32, + + /// Auxiliary Control Register + /// + /// This register is entirely implementation defined -- the standard gives + /// it an address, but does not define its role or contents. + pub actlr: RW<u32>, + + /// Coprocessor Power Control Register + #[cfg(armv8m)] + pub cppwr: RW<u32>, +} diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs index 0b63524..c0d560f 100644 --- a/src/peripheral/itm.rs +++ b/src/peripheral/itm.rs @@ -53,8 +53,19 @@ impl Stim { } /// Returns `true` if the stimulus port is ready to accept more data + #[cfg(not(armv8m))] #[inline] pub fn is_fifo_ready(&self) -> bool { - unsafe { ptr::read_volatile(self.register.get()) == 1 } + unsafe { ptr::read_volatile(self.register.get()) & 0b1 == 1 } + } + + /// Returns `true` if the stimulus port is ready to accept more data + #[cfg(armv8m)] + #[inline] + pub fn is_fifo_ready(&self) -> bool { + // ARMv8-M adds a disabled bit; we indicate that we are ready to + // proceed with a stimulus write if the port is either ready (bit 0) or + // disabled (bit 1). + unsafe { ptr::read_volatile(self.register.get()) & 0b11 != 0 } } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 04fae31..0838dca 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -55,7 +55,7 @@ //! //! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3 -// TODO stand-alone registers: ICTR, ACTLR and STIR +// TODO stand-alone register: STIR use core::marker::PhantomData; use core::ops; @@ -72,6 +72,7 @@ pub mod fpb; // NOTE(target_arch) is for documentation purposes #[cfg(any(has_fpu, target_arch = "x86_64"))] pub mod fpu; +pub mod icb; #[cfg(all(not(armv6m), not(armv8m_base)))] pub mod itm; pub mod mpu; @@ -90,6 +91,7 @@ mod test; /// Core peripherals #[allow(non_snake_case)] +#[allow(clippy::manual_non_exhaustive)] pub struct Peripherals { /// Cache and branch predictor maintenance operations. /// Not available on Armv6-M. @@ -111,6 +113,12 @@ pub struct Peripherals { /// Floating Point Unit. pub FPU: FPU, + /// Implementation Control Block. + /// + /// The name is from the v8-M spec, but the block existed in earlier + /// revisions, without a name. + pub ICB: ICB, + /// Instrumentation Trace Macrocell. /// Not available on Armv6-M and Armv8-M Baseline. pub ITM: ITM, @@ -181,6 +189,9 @@ impl Peripherals { FPU: FPU { _marker: PhantomData, }, + ICB: ICB { + _marker: PhantomData, + }, ITM: ITM { _marker: PhantomData, }, @@ -364,6 +375,42 @@ impl ops::Deref for FPU { } } +/// Implementation Control Block. +/// +/// This block contains implementation-defined registers like `ictr` and +/// `actlr`. It's called the "implementation control block" in the ARMv8-M +/// standard, but earlier standards contained the registers, just without a +/// name. +pub struct ICB { + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for ICB {} + +impl ICB { + /// Returns a pointer to the register block + #[inline(always)] + pub fn ptr() -> *mut icb::RegisterBlock { + 0xE000_E004 as *mut _ + } +} + +impl ops::Deref for ICB { + type Target = self::icb::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } +} + +impl ops::DerefMut for ICB { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *Self::ptr() } + } +} + /// Instrumentation Trace Macrocell pub struct ITM { _marker: PhantomData<*const ()>, diff --git a/src/peripheral/mpu.rs b/src/peripheral/mpu.rs index 09d06f0..4d53eb5 100644 --- a/src/peripheral/mpu.rs +++ b/src/peripheral/mpu.rs @@ -2,7 +2,8 @@ use volatile_register::{RO, RW}; -/// Register block +/// Register block for ARMv7-M +#[cfg(any(armv6m, armv7m, target_arch = "x86_64"))] // x86-64 is for rustdoc #[repr(C)] pub struct RegisterBlock { /// Type @@ -28,3 +29,37 @@ pub struct RegisterBlock { /// Alias 3 of RSAR pub rsar_a3: RW<u32>, } + +/// Register block for ARMv8-M +#[cfg(armv8m)] +#[repr(C)] +pub struct RegisterBlock { + /// Type + pub _type: RO<u32>, + /// Control + pub ctrl: RW<u32>, + /// Region Number + pub rnr: RW<u32>, + /// Region Base Address + pub rbar: RW<u32>, + /// Region Limit Address + pub rlar: RW<u32>, + /// Alias 1 of RBAR + pub rbar_a1: RW<u32>, + /// Alias 1 of RLAR + pub rlar_a1: RW<u32>, + /// Alias 2 of RBAR + pub rbar_a2: RW<u32>, + /// Alias 2 of RLAR + pub rlar_a2: RW<u32>, + /// Alias 3 of RBAR + pub rbar_a3: RW<u32>, + /// Alias 3 of RLAR + pub rlar_a3: RW<u32>, + + // Reserved word at offset 0xBC + _reserved: u32, + + /// Memory Attribute Indirection register 0 and 1 + pub mair: [RW<u32>; 2], +} diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 7fb4505..001bb14 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -331,11 +331,15 @@ impl SCB { cbp.iciallu(); // Enable I-cache - // NOTE(unsafe): We have synchronised access by &mut self - unsafe { self.ccr.modify(|r| r | SCB_CCR_IC_MASK) }; + extern "C" { + // see asm-v7m.s + fn __enable_icache(); + } - crate::asm::dsb(); - crate::asm::isb(); + // NOTE(unsafe): The asm routine manages exclusive access to the SCB + // registers and applies the proper barriers; it is technically safe on + // its own, and is only `unsafe` here because it's `extern "C"`. + unsafe { __enable_icache(); } } /// Disables I-cache if currently enabled. @@ -400,11 +404,15 @@ impl SCB { unsafe { self.invalidate_dcache(cpuid) }; // Now turn on the D-cache - // NOTE(unsafe): We have synchronised access by &mut self - unsafe { self.ccr.modify(|r| r | SCB_CCR_DC_MASK) }; + extern "C" { + // see asm-v7m.s + fn __enable_dcache(); + } - crate::asm::dsb(); - crate::asm::isb(); + // NOTE(unsafe): The asm routine manages exclusive access to the SCB + // registers and applies the proper barriers; it is technically safe on + // its own, and is only `unsafe` here because it's `extern "C"`. + unsafe { __enable_dcache(); } } /// Disables D-cache if currently enabled. @@ -877,7 +885,7 @@ impl SCB { } } - /// Set the PENDSTCLR bit in the ICSR register which will clear a pending SysTick interrupt + /// Set the PENDSTSET bit in the ICSR register which will pend a SysTick interrupt #[inline] pub fn set_pendst() { unsafe { diff --git a/src/register/apsr.rs b/src/register/apsr.rs index 97a9f01..3db8aeb 100644 --- a/src/register/apsr.rs +++ b/src/register/apsr.rs @@ -55,7 +55,7 @@ pub fn read() -> Apsr { () => { let r: u32; unsafe { - asm!("mrs $0, APSR" : "=r"(r) ::: "volatile"); + llvm_asm!("mrs $0, APSR" : "=r"(r) ::: "volatile"); } Apsr { bits: r } } diff --git a/src/register/basepri.rs b/src/register/basepri.rs index a09e34b..6caf938 100644 --- a/src/register/basepri.rs +++ b/src/register/basepri.rs @@ -8,7 +8,7 @@ pub fn read() -> u8 { () => { let r: u32; unsafe { - asm!("mrs $0, BASEPRI" : "=r"(r) ::: "volatile"); + llvm_asm!("mrs $0, BASEPRI" : "=r"(r) ::: "volatile"); } r as u8 } @@ -37,10 +37,10 @@ pub unsafe fn write(_basepri: u8) { #[cfg(all(cortex_m, feature = "inline-asm"))] () => match () { #[cfg(not(feature = "cm7-r0p1"))] - () => asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), + () => llvm_asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), #[cfg(feature = "cm7-r0p1")] () => crate::interrupt::free( - |_| asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), + |_| llvm_asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"), ), }, diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs index 694fd75..0e66f69 100644 --- a/src/register/basepri_max.rs +++ b/src/register/basepri_max.rs @@ -14,10 +14,10 @@ pub fn write(_basepri: u8) { () => unsafe { match () { #[cfg(not(feature = "cm7-r0p1"))] - () => asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), + () => llvm_asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), #[cfg(feature = "cm7-r0p1")] () => crate::interrupt::free( - |_| asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), + |_| llvm_asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"), ), } }, diff --git a/src/register/control.rs b/src/register/control.rs index 07b26c3..211b532 100644 --- a/src/register/control.rs +++ b/src/register/control.rs @@ -163,7 +163,7 @@ pub fn read() -> Control { #[cfg(feature = "inline-asm")] () => { let r: u32; - unsafe { asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") } r } @@ -194,7 +194,7 @@ pub unsafe fn write(_control: Control) { #[cfg(feature = "inline-asm")] () => { let control = _control.bits(); - asm!("msr CONTROL, $0" :: "r"(control) : "memory" : "volatile"); + llvm_asm!("msr CONTROL, $0" :: "r"(control) : "memory" : "volatile"); } #[cfg(not(feature = "inline-asm"))] diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs index 811385f..06f60fe 100644 --- a/src/register/faultmask.rs +++ b/src/register/faultmask.rs @@ -34,7 +34,7 @@ pub fn read() -> Faultmask { #[cfg(feature = "inline-asm")] () => { let r: u32; - unsafe { asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") } r } diff --git a/src/register/fpscr.rs b/src/register/fpscr.rs new file mode 100644 index 0000000..569d3a7 --- /dev/null +++ b/src/register/fpscr.rs @@ -0,0 +1,343 @@ +//! Floating-point Status Control Register + +/// Floating-point Status Control Register +#[allow(clippy::missing_inline_in_public_items)] +#[derive(Clone, Copy, Debug)] +pub struct Fpscr { + bits: u32, +} + +impl Fpscr { + /// Creates a `Fspcr` value from raw bits. + #[inline] + pub fn from_bits(bits: u32) -> Self { + Self { bits } + } + + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(self) -> u32 { + self.bits + } + + /// Read the Negative condition code flag + #[inline] + pub fn n(self) -> bool { + self.bits & (1 << 31) != 0 + } + + /// Sets the Negative condition code flag + #[inline] + pub fn set_n(&mut self, n: bool) { + let mask = 1 << 31; + match n { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Zero condition code flag + #[inline] + pub fn z(self) -> bool { + self.bits & (1 << 30) != 0 + } + + /// Sets the Zero condition code flag + #[inline] + pub fn set_z(&mut self, z: bool) { + let mask = 1 << 30; + match z { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Carry condition code flag + #[inline] + pub fn c(self) -> bool { + self.bits & (1 << 29) != 0 + } + + /// Sets the Carry condition code flag + #[inline] + pub fn set_c(&mut self, c: bool) { + let mask = 1 << 29; + match c { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Overflow condition code flag + #[inline] + pub fn v(self) -> bool { + self.bits & (1 << 28) != 0 + } + + /// Sets the Zero condition code flag + #[inline] + pub fn set_v(&mut self, v: bool) { + let mask = 1 << 28; + match v { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Alternative Half Precision bit + #[inline] + pub fn ahp(self) -> bool { + self.bits & (1 << 26) != 0 + } + + /// Sets the Alternative Half Precision bit + #[inline] + pub fn set_ahp(&mut self, ahp: bool) { + let mask = 1 << 26; + match ahp { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Default NaN mode bit + #[inline] + pub fn dn(self) -> bool { + self.bits & (1 << 25) != 0 + } + + /// Sets the Default NaN mode bit + #[inline] + pub fn set_dn(&mut self, dn: bool) { + let mask = 1 << 25; + match dn { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Flush to Zero mode bit + #[inline] + pub fn fz(self) -> bool { + self.bits & (1 << 24) != 0 + } + + /// Sets the Flush to Zero mode bit + #[inline] + pub fn set_fz(&mut self, fz: bool) { + let mask = 1 << 24; + match fz { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Rounding Mode control field + #[inline] + pub fn rmode(self) -> RMode { + match (self.bits & (3 << 22)) >> 22 { + 0 => RMode::Nearest, + 1 => RMode::PlusInfinity, + 2 => RMode::MinusInfinity, + _ => RMode::Zero, + } + } + + /// Sets the Rounding Mode control field + #[inline] + pub fn set_rmode(&mut self, rmode: RMode) { + let mask = 3 << 22; + match rmode { + RMode::Nearest => self.bits = self.bits & !mask, + RMode::PlusInfinity => self.bits = (self.bits & !mask) | (1 << 22), + RMode::MinusInfinity => self.bits = (self.bits & !mask) | (2 << 22), + RMode::Zero => self.bits = self.bits | mask, + } + } + + /// Read the Input Denormal cumulative exception bit + #[inline] + pub fn idc(self) -> bool { + self.bits & (1 << 7) != 0 + } + + /// Sets the Input Denormal cumulative exception bit + #[inline] + pub fn set_idc(&mut self, idc: bool) { + let mask = 1 << 7; + match idc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Inexact cumulative exception bit + #[inline] + pub fn ixc(self) -> bool { + self.bits & (1 << 4) != 0 + } + + /// Sets the Inexact cumulative exception bit + #[inline] + pub fn set_ixc(&mut self, ixc: bool) { + let mask = 1 << 4; + match ixc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Underflow cumulative exception bit + #[inline] + pub fn ufc(self) -> bool { + self.bits & (1 << 3) != 0 + } + + /// Sets the Underflow cumulative exception bit + #[inline] + pub fn set_ufc(&mut self, ufc: bool) { + let mask = 1 << 3; + match ufc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Overflow cumulative exception bit + #[inline] + pub fn ofc(self) -> bool { + self.bits & (1 << 2) != 0 + } + + /// Sets the Overflow cumulative exception bit + #[inline] + pub fn set_ofc(&mut self, ofc: bool) { + let mask = 1 << 2; + match ofc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Division by Zero cumulative exception bit + #[inline] + pub fn dzc(self) -> bool { + self.bits & (1 << 1) != 0 + } + + /// Sets the Division by Zero cumulative exception bit + #[inline] + pub fn set_dzc(&mut self, dzc: bool) { + let mask = 1 << 1; + match dzc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } + + /// Read the Invalid Operation cumulative exception bit + #[inline] + pub fn ioc(self) -> bool { + self.bits & (1 << 0) != 0 + } + + /// Sets the Invalid Operation cumulative exception bit + #[inline] + pub fn set_ioc(&mut self, ioc: bool) { + let mask = 1 << 0; + match ioc { + true => self.bits |= mask, + false => self.bits &= !mask, + } + } +} + +/// Rounding mode +#[allow(clippy::missing_inline_in_public_items)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum RMode { + /// Round to Nearest (RN) mode. This is the reset value. + Nearest, + /// Round towards Plus Infinity (RP) mode. + PlusInfinity, + /// Round towards Minus Infinity (RM) mode. + MinusInfinity, + /// Round towards Zero (RZ) mode. + Zero, +} + +impl RMode { + /// Is Nearest the current rounding mode? + #[inline] + pub fn is_nearest(self) -> bool { + self == RMode::Nearest + } + + /// Is Plus Infinity the current rounding mode? + #[inline] + pub fn is_plus_infinity(self) -> bool { + self == RMode::PlusInfinity + } + + /// Is Minus Infinity the current rounding mode? + #[inline] + pub fn is_minus_infinity(self) -> bool { + self == RMode::MinusInfinity + } + + /// Is Zero the current rounding mode? + #[inline] + pub fn is_zero(self) -> bool { + self == RMode::Zero + } +} + +/// 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!(), + } +} + +/// 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!(), + } +} diff --git a/src/register/lr.rs b/src/register/lr.rs index a17f7ac..6919e10 100644 --- a/src/register/lr.rs +++ b/src/register/lr.rs @@ -9,7 +9,7 @@ pub fn read() -> u32 { #[cfg(cortex_m)] () => { let r: u32; - unsafe { asm!("mov $0,R14" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mov $0,R14" : "=r"(r) ::: "volatile") } r } @@ -25,7 +25,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(cortex_m)] - () => asm!("mov R14,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("mov R14,$0" :: "r"(_bits) :: "volatile"), #[cfg(not(cortex_m))] () => unimplemented!(), diff --git a/src/register/mod.rs b/src/register/mod.rs index d69c1a5..efbe6ef 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -22,6 +22,10 @@ //! - BASEPRI //! - FAULTMASK //! +//! The following registers are only available for devices with an FPU: +//! +//! - FPSCR +//! //! # References //! //! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers @@ -37,6 +41,9 @@ pub mod control; #[cfg(all(not(armv6m), not(armv8m_base)))] pub mod faultmask; +#[cfg(has_fpu)] +pub mod fpscr; + pub mod msp; pub mod primask; diff --git a/src/register/msp.rs b/src/register/msp.rs index 082a7fc..b5460ed 100644 --- a/src/register/msp.rs +++ b/src/register/msp.rs @@ -7,7 +7,7 @@ pub fn read() -> u32 { #[cfg(all(cortex_m, feature = "inline-asm"))] () => { let r; - unsafe { asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") } r } @@ -30,7 +30,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => asm!("msr MSP,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("msr MSP,$0" :: "r"(_bits) :: "volatile"), #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => { diff --git a/src/register/msplim.rs b/src/register/msplim.rs index df3642a..68915c4 100644 --- a/src/register/msplim.rs +++ b/src/register/msplim.rs @@ -7,7 +7,7 @@ pub fn read() -> u32 { #[cfg(all(cortex_m, feature = "inline-asm"))] () => { let r; - unsafe { asm!("mrs $0,MSPLIM" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0,MSPLIM" : "=r"(r) ::: "volatile") } r } @@ -30,7 +30,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => asm!("msr MSPLIM,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("msr MSPLIM,$0" :: "r"(_bits) :: "volatile"), #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => { diff --git a/src/register/pc.rs b/src/register/pc.rs index 37176e8..f4486c4 100644 --- a/src/register/pc.rs +++ b/src/register/pc.rs @@ -9,7 +9,7 @@ pub fn read() -> u32 { #[cfg(cortex_m)] () => { let r; - unsafe { asm!("mov $0,R15" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mov $0,R15" : "=r"(r) ::: "volatile") } r } @@ -25,7 +25,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(cortex_m)] - () => asm!("mov R15,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("mov R15,$0" :: "r"(_bits) :: "volatile"), #[cfg(not(cortex_m))] () => unimplemented!(), diff --git a/src/register/primask.rs b/src/register/primask.rs index 018c45b..4b6df3c 100644 --- a/src/register/primask.rs +++ b/src/register/primask.rs @@ -34,7 +34,7 @@ pub fn read() -> Primask { #[cfg(feature = "inline-asm")] () => { let r: u32; - unsafe { asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") } r } diff --git a/src/register/psp.rs b/src/register/psp.rs index b6618b0..c020e4f 100644 --- a/src/register/psp.rs +++ b/src/register/psp.rs @@ -7,7 +7,7 @@ pub fn read() -> u32 { #[cfg(all(cortex_m, feature = "inline-asm"))] () => { let r; - unsafe { asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") } r } @@ -30,7 +30,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => asm!("msr PSP,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("msr PSP,$0" :: "r"(_bits) :: "volatile"), #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => { diff --git a/src/register/psplim.rs b/src/register/psplim.rs index 6c27008..8cb8f1c 100644 --- a/src/register/psplim.rs +++ b/src/register/psplim.rs @@ -7,7 +7,7 @@ pub fn read() -> u32 { #[cfg(all(cortex_m, feature = "inline-asm"))] () => { let r; - unsafe { asm!("mrs $0,PSPLIM" : "=r"(r) ::: "volatile") } + unsafe { llvm_asm!("mrs $0,PSPLIM" : "=r"(r) ::: "volatile") } r } @@ -30,7 +30,7 @@ pub fn read() -> u32 { pub unsafe fn write(_bits: u32) { match () { #[cfg(all(cortex_m, feature = "inline-asm"))] - () => asm!("msr PSPLIM,$0" :: "r"(_bits) :: "volatile"), + () => llvm_asm!("msr PSPLIM,$0" :: "r"(_bits) :: "volatile"), #[cfg(all(cortex_m, not(feature = "inline-asm")))] () => { |