diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm.rs | 73 | ||||
-rw-r--r-- | src/exception.rs | 3 | ||||
-rw-r--r-- | src/interrupt.rs | 22 | ||||
-rw-r--r-- | src/itm.rs | 12 | ||||
-rw-r--r-- | src/peripheral/cbp.rs | 44 | ||||
-rw-r--r-- | src/peripheral/cpuid.rs | 9 | ||||
-rw-r--r-- | src/peripheral/dwt.rs | 22 | ||||
-rw-r--r-- | src/peripheral/itm.rs | 6 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 83 | ||||
-rw-r--r-- | src/peripheral/nvic.rs | 67 | ||||
-rw-r--r-- | src/peripheral/scb.rs | 116 | ||||
-rw-r--r-- | src/peripheral/syst.rs | 135 | ||||
-rw-r--r-- | src/peripheral/test.rs | 2 | ||||
-rw-r--r-- | src/register/apsr.rs | 21 | ||||
-rw-r--r-- | src/register/basepri.rs | 45 | ||||
-rw-r--r-- | src/register/basepri_max.rs | 26 | ||||
-rw-r--r-- | src/register/control.rs | 19 | ||||
-rw-r--r-- | src/register/faultmask.rs | 27 | ||||
-rw-r--r-- | src/register/lr.rs | 33 | ||||
-rw-r--r-- | src/register/msp.rs | 33 | ||||
-rw-r--r-- | src/register/pc.rs | 33 | ||||
-rw-r--r-- | src/register/primask.rs | 27 | ||||
-rw-r--r-- | src/register/psp.rs | 33 |
23 files changed, 514 insertions, 377 deletions
@@ -7,58 +7,43 @@ /// cause an exception #[inline(always)] pub fn bkpt() { - #[cfg(target_arch = "arm")] - unsafe { - asm!("bkpt" - : - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => unsafe { asm!("bkpt" :::: "volatile") }, + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } } /// A no-operation. Useful to prevent delay loops from being optimized away. -#[inline(always)] +#[inline] pub fn nop() { - unsafe { - asm!("nop" - : - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => unsafe { asm!("nop" :::: "volatile") }, + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } } /// Wait For Event -#[inline(always)] +#[inline] pub fn wfe() { match () { #[cfg(target_arch = "arm")] - () => unsafe { - asm!("wfe" - : - : - : - : "volatile") - }, + () => unsafe { asm!("wfe" :::: "volatile") }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } /// Wait For Interrupt -#[inline(always)] +#[inline] pub fn wfi() { match () { #[cfg(target_arch = "arm")] - () => unsafe{ - asm!("wfi" - : - : - : - : "volatile") - }, + () => unsafe { asm!("wfi" :::: "volatile") }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } @@ -66,15 +51,13 @@ pub fn wfi() { /// /// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched /// from cache or memory, after the instruction has been completed. -#[inline(always)] +#[inline] pub fn isb() { match () { #[cfg(target_arch = "arm")] - () => unsafe { - asm!("isb 0xF" : : : "memory" : "volatile"); - }, + () => unsafe { asm!("isb 0xF" : : : "memory" : "volatile") }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } @@ -86,15 +69,13 @@ pub fn isb() { /// /// * any explicit memory access made before this instruction is complete /// * all cache and branch predictor maintenance operations before this instruction complete -#[inline(always)] +#[inline] pub fn dsb() { match () { #[cfg(target_arch = "arm")] - () => unsafe { - asm!("dsb 0xF" : : : "memory" : "volatile"); - }, + () => unsafe { asm!("dsb 0xF" : : : "memory" : "volatile") }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } @@ -103,14 +84,12 @@ pub fn dsb() { /// Ensures that all explicit memory accesses that appear in program order before the `DMB` /// instruction are observed before any explicit memory accesses that appear in program order /// after the `DMB` instruction. -#[inline(always)] +#[inline] pub fn dmb() { match () { #[cfg(target_arch = "arm")] - () => unsafe { - asm!("dmb 0xF" : : : "memory" : "volatile"); - }, + () => unsafe { asm!("dmb 0xF" : : : "memory" : "volatile") }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } diff --git a/src/exception.rs b/src/exception.rs index 7203dfa..b40cf1b 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -22,8 +22,7 @@ pub enum Exception { /// An interrupt Interrupt(u8), // Unreachable variant - #[doc(hidden)] - Reserved, + #[doc(hidden)] Reserved, } impl Exception { diff --git a/src/interrupt.rs b/src/interrupt.rs index de11125..5880dd4 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -3,19 +3,15 @@ pub use bare_metal::{CriticalSection, Mutex, Nr}; /// Disables all interrupts -#[inline(always)] +#[inline] pub fn disable() { match () { #[cfg(target_arch = "arm")] () => unsafe { - asm!("cpsid i" - : - : - : "memory" - : "volatile"); + asm!("cpsid i" ::: "memory" : "volatile"); }, #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } @@ -24,19 +20,13 @@ pub fn disable() { /// # Safety /// /// - Do not call this function inside an `interrupt::free` critical section -#[inline(always)] +#[inline] pub unsafe fn enable() { match () { #[cfg(target_arch = "arm")] - () => { - asm!("cpsie i" - : - : - : "memory" - : "volatile"); - } + () => asm!("cpsie i" ::: "memory" : "volatile"), #[cfg(not(target_arch = "arm"))] - () => {} + () => unimplemented!(), } } @@ -7,7 +7,7 @@ use aligned::Aligned; use peripheral::itm::Stim; // NOTE assumes that `bytes` is 32-bit aligned -unsafe fn write_words(stim: &Stim, bytes: &[u32]) { +unsafe fn write_words(stim: &mut Stim, bytes: &[u32]) { let mut p = bytes.as_ptr(); for _ in 0..bytes.len() { while !stim.is_fifo_ready() {} @@ -16,7 +16,7 @@ unsafe fn write_words(stim: &Stim, bytes: &[u32]) { } } -struct Port<'p>(&'p Stim); +struct Port<'p>(&'p mut Stim); impl<'p> fmt::Write for Port<'p> { fn write_str(&mut self, s: &str) -> fmt::Result { @@ -26,7 +26,7 @@ impl<'p> fmt::Write for Port<'p> { } /// Writes a `buffer` to the ITM `port` -pub fn write_all(port: &Stim, buffer: &[u8]) { +pub fn write_all(port: &mut Stim, buffer: &[u8]) { unsafe { let mut len = buffer.len(); let mut ptr = buffer.as_ptr(); @@ -84,7 +84,7 @@ pub fn write_all(port: &Stim, buffer: &[u8]) { /// // Or equivalently /// itm::write_aligned(&itm.stim[0], &Aligned(*b"Hello, world!\n")); /// ``` -pub fn write_aligned(port: &Stim, buffer: &Aligned<u32, [u8]>) { +pub fn write_aligned(port: &mut Stim, buffer: &Aligned<u32, [u8]>) { unsafe { let len = buffer.len(); @@ -120,13 +120,13 @@ pub fn write_aligned(port: &Stim, buffer: &Aligned<u32, [u8]>) { } /// Writes `fmt::Arguments` to the ITM `port` -pub fn write_fmt(port: &Stim, args: fmt::Arguments) { +pub fn write_fmt(port: &mut Stim, args: fmt::Arguments) { use core::fmt::Write; Port(port).write_fmt(args).ok(); } /// Writes a string to the ITM `port` -pub fn write_str(port: &Stim, string: &str) { +pub fn write_str(port: &mut Stim, string: &str) { write_all(port, string.as_bytes()) } diff --git a/src/peripheral/cbp.rs b/src/peripheral/cbp.rs index 3397fff..590cb7b 100644 --- a/src/peripheral/cbp.rs +++ b/src/peripheral/cbp.rs @@ -2,6 +2,8 @@ use volatile_register::WO; +use peripheral::CBP; + /// Register block #[repr(C)] pub struct RegisterBlock { @@ -33,26 +35,26 @@ const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; const CBP_SW_SET_POS: u32 = 5; const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; -impl RegisterBlock { +impl CBP { /// I-cache invalidate all to PoU - #[inline(always)] - pub fn iciallu(&self) { + #[inline] + pub fn iciallu(&mut self) { unsafe { self.iciallu.write(0); } } /// I-cache invalidate by MVA to PoU - #[inline(always)] - pub fn icimvau(&self, mva: u32) { + #[inline] + pub fn icimvau(&mut self, mva: u32) { unsafe { self.icimvau.write(mva); } } /// D-cache invalidate by MVA to PoC - #[inline(always)] - pub fn dcimvac(&self, mva: u32) { + #[inline] + pub fn dcimvac(&mut self, mva: u32) { unsafe { self.dcimvac.write(mva); } @@ -61,8 +63,8 @@ impl RegisterBlock { /// D-cache invalidate by set-way /// /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. - #[inline(always)] - pub fn dcisw(&self, set: u16, way: u16) { + #[inline] + pub fn dcisw(&mut self, set: u16, way: u16) { // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way // operations have a register data format which depends on the implementation's // associativity and number of sets. Specifically the 'way' and 'set' fields have @@ -81,16 +83,16 @@ impl RegisterBlock { } /// D-cache clean by MVA to PoU - #[inline(always)] - pub fn dccmvau(&self, mva: u32) { + #[inline] + pub fn dccmvau(&mut self, mva: u32) { unsafe { self.dccmvau.write(mva); } } /// D-cache clean by MVA to PoC - #[inline(always)] - pub fn dccmvac(&self, mva: u32) { + #[inline] + pub fn dccmvac(&mut self, mva: u32) { unsafe { self.dccmvac.write(mva); } @@ -99,8 +101,8 @@ impl RegisterBlock { /// D-cache clean by set-way /// /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. - #[inline(always)] - pub fn dccsw(&self, set: u16, way: u16) { + #[inline] + pub fn dccsw(&mut self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccsw.write( @@ -111,8 +113,8 @@ impl RegisterBlock { } /// D-cache clean and invalidate by MVA to PoC - #[inline(always)] - pub fn dccimvac(&self, mva: u32) { + #[inline] + pub fn dccimvac(&mut self, mva: u32) { unsafe { self.dccimvac.write(mva); } @@ -121,8 +123,8 @@ impl RegisterBlock { /// D-cache clean and invalidate by set-way /// /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. - #[inline(always)] - pub fn dccisw(&self, set: u16, way: u16) { + #[inline] + pub fn dccisw(&mut self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccisw.write( @@ -133,8 +135,8 @@ impl RegisterBlock { } /// Branch predictor invalidate all - #[inline(always)] - pub fn bpiall(&self) { + #[inline] + pub fn bpiall(&mut self) { unsafe { self.bpiall.write(0); } diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs index f0b7e6e..624d5c5 100644 --- a/src/peripheral/cpuid.rs +++ b/src/peripheral/cpuid.rs @@ -4,6 +4,9 @@ use volatile_register::RO; #[cfg(any(armv7m, test))] use volatile_register::RW; +#[cfg(armv7m)] +use peripheral::CPUID; + /// Register block #[repr(C)] pub struct RegisterBlock { @@ -45,14 +48,14 @@ pub enum CsselrCacheType { } #[cfg(armv7m)] -impl RegisterBlock { +impl CPUID { /// Selects the current CCSIDR /// /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 /// * `ind`: select instruction cache or data/unified cache /// /// `level` is masked to be between 0 and 7. - pub fn select_cache(&self, level: u8, ind: CsselrCacheType) { + pub fn select_cache(&mut self, level: u8, ind: CsselrCacheType) { const CSSELR_IND_POS: u32 = 0; const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; const CSSELR_LEVEL_POS: u32 = 1; @@ -67,7 +70,7 @@ impl RegisterBlock { } /// Returns the number of sets and ways in the selected cache - pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) { + pub fn cache_num_sets_ways(&mut self, level: u8, ind: CsselrCacheType) -> (u16, u16) { const CCSIDR_NUMSETS_POS: u32 = 13; const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index b716369..84f002e 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -2,6 +2,8 @@ use volatile_register::{RO, RW, WO}; +use peripheral::DWT; + /// Register block #[repr(C)] pub struct RegisterBlock { @@ -30,13 +32,6 @@ pub struct RegisterBlock { pub lsr: RO<u32>, } -impl RegisterBlock { - /// Enables the cycle counter - pub fn enable_cycle_counter(&self) { - unsafe { self.ctrl.modify(|r| r | 1) } - } -} - /// Comparator #[repr(C)] pub struct Comparator { @@ -48,3 +43,16 @@ pub struct Comparator { pub function: RW<u32>, reserved: u32, } + +impl DWT { + /// Enables the cycle counter + pub fn enable_cycle_counter(&mut self) { + unsafe { self.ctrl.modify(|r| r | 1) } + } + + /// Returns the current clock cycle count + pub fn get_cycle_count() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).cyccnt.read() } + } +} diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs index 17cf869..fd4a2fd 100644 --- a/src/peripheral/itm.rs +++ b/src/peripheral/itm.rs @@ -33,17 +33,17 @@ pub struct Stim { impl Stim { /// Writes an `u8` payload into the stimulus port - pub fn write_u8(&self, value: u8) { + pub fn write_u8(&mut self, value: u8) { unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) } } /// Writes an `u16` payload into the stimulus port - pub fn write_u16(&self, value: u16) { + pub fn write_u16(&mut self, value: u16) { unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) } } /// Writes an `u32` payload into the stimulus port - pub fn write_u32(&self, value: u32) { + pub fn write_u32(&mut self, value: u32) { unsafe { ptr::write_volatile(self.register.get(), value) } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index dbe3e35..ffbb56c 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -1,5 +1,66 @@ //! Core peripherals //! +//! # API +//! +//! To use (most of) the peripheral API first you must get an *instance* of the peripheral. All the +//! core peripherals are modeled as singletons (there can only ever be, at most, one instance of +//! them at any given point in time) and the only way to get an instance of them is through the +//! [`Peripherals::take`](struct.Peripherals.html#method.take) method. +//! +//! ``` no_run +//! extern crate cortex_m; +//! +//! use cortex_m::peripheral::Peripherals; +//! +//! fn main() { +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DWT.enable_cycle_counter(); +//! } +//! ``` +//! +//! This method can only be successfully called *once* -- this is why the method returns an +//! `Option`. Subsequent calls to the method will result in a `None` value being returned. +//! +//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the +//! API is provided as static methods on the peripheral types. One example is the +//! [`DWT::cyccnt`](struct.DWT.html#method.cyccnt) method. +//! +//! ``` no_run +//! extern crate cortex_m; +//! +//! use cortex_m::peripheral::{DWT, Peripherals}; +//! +//! fn main() { +//! { +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DWT.enable_cycle_counter(); +//! } // all the peripheral singletons are destroyed here +//! +//! // but this method can be called without a DWT instance +//! let cyccnt = DWT::get_cycle_count(); +//! } +//! ``` +//! +//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is +//! available on all the peripheral types. This method is a useful building block for implementing +//! higher level and safe abstractions. +//! +//! ``` no_run +//! extern crate cortex_m; +//! +//! use cortex_m::peripheral::{DWT, Peripherals}; +//! +//! fn main() { +//! { +//! let mut peripherals = Peripherals::take().unwrap(); +//! peripherals.DWT.enable_cycle_counter(); +//! } // all the peripheral singletons are destroyed here +//! +//! // actually safe because this is an atomic read with no side effects +//! let cyccnt = unsafe { (*DWT::ptr()).cyccnt.read() }; +//! } +//! ``` +//! //! # References //! //! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3 @@ -9,7 +70,7 @@ #![allow(private_no_mangle_statics)] use core::marker::PhantomData; -use core::ops::Deref; +use core::ops::{Deref, DerefMut}; use interrupt; @@ -69,7 +130,7 @@ static mut CORE_PERIPHERALS: bool = false; impl Peripherals { /// Returns all the core peripherals *once* - #[inline(always)] + #[inline] pub fn take() -> Option<Self> { interrupt::free(|_| { if unsafe { CORE_PERIPHERALS } { @@ -80,7 +141,7 @@ impl Peripherals { }) } - /// Unchecked version of `Peripherals::steal` + /// Unchecked version of `Peripherals::take` pub unsafe fn steal() -> Self { debug_assert!(!CORE_PERIPHERALS); @@ -136,6 +197,12 @@ pub struct CBP { #[cfg(armv7m)] impl CBP { + pub(crate) unsafe fn new() -> Self { + CBP { + _marker: PhantomData, + } + } + /// Returns a pointer to the register block pub fn ptr() -> *const self::cbp::RegisterBlock { 0xE000_EF50 as *const _ @@ -262,8 +329,8 @@ pub struct ITM { impl ITM { /// Returns a pointer to the register block - pub fn ptr() -> *const itm::RegisterBlock { - 0xE000_0000 as *const _ + pub fn ptr() -> *mut itm::RegisterBlock { + 0xE000_0000 as *mut _ } } @@ -275,6 +342,12 @@ impl Deref for ITM { } } +impl DerefMut for ITM { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *Self::ptr() } + } +} + /// Memory Protection Unit pub struct MPU { _marker: PhantomData<*const ()>, diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs index 74c6625..ecfdd7e 100644 --- a/src/peripheral/nvic.rs +++ b/src/peripheral/nvic.rs @@ -2,6 +2,7 @@ use volatile_register::{RO, RW}; +use peripheral::NVIC; use interrupt::Nr; /// Register block @@ -52,9 +53,9 @@ pub struct RegisterBlock { pub ipr: [RW<u32>; 8], } -impl RegisterBlock { +impl NVIC { /// Clears `interrupt`'s pending state - pub fn clear_pending<I>(&self, interrupt: I) + pub fn clear_pending<I>(&mut self, interrupt: I) where I: Nr, { @@ -64,7 +65,7 @@ impl RegisterBlock { } /// Disables `interrupt` - pub fn disable<I>(&self, interrupt: I) + pub fn disable<I>(&mut self, interrupt: I) where I: Nr, { @@ -74,7 +75,7 @@ impl RegisterBlock { } /// Enables `interrupt` - pub fn enable<I>(&self, interrupt: I) + pub fn enable<I>(&mut self, interrupt: I) where I: Nr, { @@ -83,64 +84,69 @@ impl RegisterBlock { unsafe { self.iser[usize::from(nr / 32)].write(1 << (nr % 32)) } } - /// Gets the "priority" of `interrupt` + /// Returns the NVIC priority of `interrupt` /// - /// NOTE NVIC encodes priority in the highest bits of a byte so values like - /// `1` and `2` have the same priority. Also for NVIC priorities, a lower - /// value (e.g. `16`) has higher priority than a larger value (e.g. `32`). - pub fn get_priority<I>(&self, interrupt: I) -> u8 + /// *NOTE* NVIC encodes priority in the highest bits of a byte so values like `1` and `2` map + /// to the same priority. Also for NVIC priorities, a lower value (e.g. `16`) has higher + /// priority (urgency) than a larger value (e.g. `32`). + pub fn get_priority<I>(interrupt: I) -> u8 where I: Nr, { #[cfg(not(armv6m))] { let nr = interrupt.nr(); - self.ipr[usize::from(nr)].read() + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).ipr[usize::from(nr)].read() } } #[cfg(armv6m)] { - let ipr_n = self.ipr[Self::ipr_index(&interrupt)].read(); - let prio = (ipr_n >> Self::ipr_shift(&interrupt)) & 0x000000ff; + // NOTE(unsafe) atomic read with no side effects + let ipr_n = unsafe { (*Self::ptr()).ipr[Self::ipr_index(&interrupt)].read() }; + let prio = (ipr_n >> Self::ipr_shift(&interrupt)) & 0x000000ff; prio as u8 } } /// Is `interrupt` active or pre-empted and stacked - pub fn is_active<I>(&self, interrupt: I) -> bool + pub fn is_active<I>(interrupt: I) -> bool where I: Nr, { let nr = interrupt.nr(); let mask = 1 << (nr % 32); - (self.iabr[usize::from(nr / 32)].read() & mask) == mask + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::ptr()).iabr[usize::from(nr / 32)].read() & mask) == mask } } /// Checks if `interrupt` is enabled - pub fn is_enabled<I>(&self, interrupt: I) -> bool + pub fn is_enabled<I>(interrupt: I) -> bool where I: Nr, { let nr = interrupt.nr(); let mask = 1 << (nr % 32); - (self.iser[usize::from(nr / 32)].read() & mask) == mask + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::ptr()).iser[usize::from(nr / 32)].read() & mask) == mask } } /// Checks if `interrupt` is pending - pub fn is_pending<I>(&self, interrupt: I) -> bool + pub fn is_pending<I>(interrupt: I) -> bool where I: Nr, { let nr = interrupt.nr(); let mask = 1 << (nr % 32); - (self.ispr[usize::from(nr / 32)].read() & mask) == mask + // NOTE(unsafe) atomic read with no side effects + unsafe { ((*Self::ptr()).ispr[usize::from(nr / 32)].read() & mask) == mask } } /// Forces `interrupt` into pending state - pub fn set_pending<I>(&self, interrupt: I) + pub fn set_pending<I>(&mut self, interrupt: I) where I: Nr, { @@ -151,15 +157,12 @@ impl RegisterBlock { /// Sets the "priority" of `interrupt` to `prio` /// - /// NOTE See `get_priority` method for an explanation of how NVIC priorities - /// work. + /// *NOTE* See [`get_priority`](struct.NVIC.html#method.get_priority) method for an explanation + /// of how NVIC priorities work. /// - /// On ARMv6-M, updating an interrupt priority requires a read-modify-write - /// operation, which is not atomic. This is inherently racy, so please - /// ensure proper access to this method. - /// - /// On ARMv7-M, this method is atomic. - pub unsafe fn set_priority<I>(&self, interrupt: I, prio: u8) + /// On ARMv6-M, updating an interrupt priority requires a read-modify-write operation. On + /// ARMv7-M, the operation is performed in a single atomic write operation. + pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8) where I: Nr, { @@ -181,12 +184,18 @@ impl RegisterBlock { } #[cfg(armv6m)] - fn ipr_index<I>(interrupt: &I) -> usize where I: Nr { + fn ipr_index<I>(interrupt: &I) -> usize + where + I: Nr, + { usize::from(interrupt.nr()) / 4 } #[cfg(armv6m)] - fn ipr_shift<I>(interrupt: &I) -> usize where I: Nr { + fn ipr_shift<I>(interrupt: &I) -> usize + where + I: Nr, + { (usize::from(interrupt.nr()) % 4) * 8 } } diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 2a98618..9a922c7 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -2,10 +2,12 @@ use volatile_register::RW; +#[cfg(any(armv7m, has_fpu))] +use super::{CBP, SCB}; #[cfg(armv7m)] -use super::CBP; +use super::CPUID; #[cfg(armv7m)] -use super::cpuid::{self, CsselrCacheType}; +use super::cpuid::CsselrCacheType; /// Register block #[repr(C)] @@ -64,10 +66,22 @@ mod fpu_consts { use self::fpu_consts::*; #[cfg(has_fpu)] -impl RegisterBlock { +impl SCB { + /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Disabled)` + pub fn disable_fpu(&mut self) { + self.set_fpu_access_mode(FpuAccessMode::Disabled) + } + + /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Enabled)` + pub fn enable_fpu(&mut self) { + self.set_fpu_access_mode(FpuAccessMode::Enabled) + } + /// Gets FPU access mode - pub fn fpu_access_mode(&self) -> FpuAccessMode { - let cpacr = self.cpacr.read(); + pub fn fpu_access_mode() -> FpuAccessMode { + // NOTE(unsafe) atomic read operation with no side effects + let cpacr = unsafe { (*Self::ptr()).cpacr.read() }; + if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER { FpuAccessMode::Enabled } else if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE { @@ -83,7 +97,7 @@ impl RegisterBlock { /// floating-point arguments or have any floating-point local variables. Because the compiler /// might inline such a function into a caller that does have floating-point arguments or /// variables, any such function must be also marked #[inline(never)]. - pub fn set_fpu_access_mode(&self, mode: FpuAccessMode) { + pub fn set_fpu_access_mode(&mut self, mode: FpuAccessMode) { let mut cpacr = self.cpacr.read() & !SCB_CPACR_FPU_MASK; match mode { FpuAccessMode::Disabled => (), @@ -92,16 +106,6 @@ impl RegisterBlock { } unsafe { self.cpacr.write(cpacr) } } - - /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Enabled)` - pub fn enable_fpu(&self) { - self.set_fpu_access_mode(FpuAccessMode::Enabled) - } - - /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Disabled)` - pub fn disable_fpu(&self) { - self.set_fpu_access_mode(FpuAccessMode::Disabled) - } } #[cfg(armv7m)] @@ -114,17 +118,17 @@ mod scb_consts { use self::scb_consts::*; #[cfg(armv7m)] -impl RegisterBlock { +impl SCB { /// Enables I-Cache if currently disabled #[inline] - pub fn enable_icache(&self) { + pub fn enable_icache(&mut self) { // Don't do anything if ICache is already enabled - if self.icache_enabled() { + if Self::icache_enabled() { return; } - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Invalidate I-Cache cbp.iciallu(); @@ -138,14 +142,14 @@ impl RegisterBlock { /// Disables I-Cache if currently enabled #[inline] - pub fn disable_icache(&self) { + pub fn disable_icache(&mut self) { // Don't do anything if ICache is already disabled - if !self.icache_enabled() { + if !Self::icache_enabled() { return; } - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Disable I-Cache unsafe { self.ccr.modify(|r| r & !SCB_CCR_IC_MASK) }; @@ -159,17 +163,19 @@ impl RegisterBlock { /// Returns whether the I-Cache is currently enabled #[inline] - pub fn icache_enabled(&self) -> bool { + pub fn icache_enabled() -> bool { ::asm::dsb(); ::asm::isb(); - self.ccr.read() & SCB_CCR_IC_MASK == SCB_CCR_IC_MASK + + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).ccr.read() & SCB_CCR_IC_MASK == SCB_CCR_IC_MASK } } /// Invalidates I-Cache #[inline] - pub fn invalidate_icache(&self) { - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + pub fn invalidate_icache(&mut self) { + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Invalidate I-Cache cbp.iciallu(); @@ -180,9 +186,9 @@ impl RegisterBlock { /// Enables D-cache if currently disabled #[inline] - pub fn enable_dcache(&self, cpuid: &cpuid::RegisterBlock) { + pub fn enable_dcache(&mut self, cpuid: &mut CPUID) { // Don't do anything if DCache is already enabled - if self.dcache_enabled() { + if Self::dcache_enabled() { return; } @@ -198,9 +204,9 @@ impl RegisterBlock { /// Disables D-cache if currently enabled #[inline] - pub fn disable_dcache(&self, cpuid: &cpuid::RegisterBlock) { + pub fn disable_dcache(&mut self, cpuid: &mut CPUID) { // Don't do anything if DCache is already disabled - if !self.dcache_enabled() { + if !Self::dcache_enabled() { return; } @@ -213,10 +219,12 @@ impl RegisterBlock { /// Returns whether the D-Cache is currently enabled #[inline] - pub fn dcache_enabled(&self) -> bool { + pub fn dcache_enabled() -> bool { ::asm::dsb(); ::asm::isb(); - self.ccr.read() & SCB_CCR_DC_MASK == SCB_CCR_DC_MASK + + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).ccr.read() & SCB_CCR_DC_MASK == SCB_CCR_DC_MASK } } /// Invalidates D-cache @@ -225,9 +233,9 @@ impl RegisterBlock { /// stack, depending on optimisations, breaking returning to the call point. /// It's used immediately before enabling the dcache, but not exported publicly. #[inline] - fn invalidate_dcache(&self, cpuid: &cpuid::RegisterBlock) { - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + fn invalidate_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Read number of sets and ways let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); @@ -245,9 +253,9 @@ impl RegisterBlock { /// Cleans D-cache #[inline] - pub fn clean_dcache(&self, cpuid: &cpuid::RegisterBlock) { - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + pub fn clean_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Read number of sets and ways let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); @@ -264,9 +272,9 @@ impl RegisterBlock { /// Cleans and invalidates D-cache #[inline] - pub fn clean_invalidate_dcache(&self, cpuid: &cpuid::RegisterBlock) { - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + pub fn clean_invalidate_dcache(&mut self, cpuid: &mut CPUID) { + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; // Read number of sets and ways let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); @@ -289,14 +297,14 @@ impl RegisterBlock { /// Invalidates cache starting from the lowest 32-byte aligned address represented by `addr`, /// in blocks of 32 bytes until at least `size` bytes have been invalidated. #[inline] - pub fn invalidate_dcache_by_address(&self, addr: usize, size: usize) { + pub fn invalidate_dcache_by_address(&mut self, addr: usize, size: usize) { // No-op zero sized operations if size == 0 { return; } - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; ::asm::dsb(); @@ -323,14 +331,14 @@ impl RegisterBlock { /// Cleans cache starting from the lowest 32-byte aligned address represented by `addr`, /// in blocks of 32 bytes until at least `size` bytes have been cleaned. #[inline] - pub fn clean_dcache_by_address(&self, addr: usize, size: usize) { + pub fn clean_dcache_by_address(&mut self, addr: usize, size: usize) { // No-op zero sized operations if size == 0 { return; } - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; ::asm::dsb(); @@ -358,14 +366,14 @@ impl RegisterBlock { /// by `addr`, in blocks of 32 bytes until at least `size` bytes have been cleaned and /// invalidated. #[inline] - pub fn clean_invalidate_dcache_by_address(&self, addr: usize, size: usize) { + pub fn clean_invalidate_dcache_by_address(&mut self, addr: usize, size: usize) { // No-op zero sized operations if size == 0 { return; } - // All of CBP is write-only so no data races are possible - let cbp = unsafe { &*CBP::ptr() }; + // NOTE(unsafe) All CBP registers are write-only and stateless + let mut cbp = unsafe { CBP::new() }; ::asm::dsb(); diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs index 3f96208..e02275d 100644 --- a/src/peripheral/syst.rs +++ b/src/peripheral/syst.rs @@ -2,6 +2,8 @@ use volatile_register::{RO, RW}; +use peripheral::SYST; + /// Register block #[repr(C)] pub struct RegisterBlock { @@ -34,39 +36,41 @@ const SYST_CSR_COUNTFLAG: u32 = 1 << 16; const SYST_CALIB_SKEW: u32 = 1 << 30; const SYST_CALIB_NOREF: u32 = 1 << 31; -impl RegisterBlock { - /// Checks if counter is enabled - pub fn is_counter_enabled(&self) -> bool { - self.csr.read() & SYST_CSR_ENABLE != 0 - } - - /// Enables counter - pub fn enable_counter(&self) { - unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) } +impl SYST { + /// Clears current value to 0 + /// + /// After calling `clear_current()`, the next call to `has_wrapped()` + /// will return `false`. + pub fn clear_current(&mut self) { + unsafe { self.cvr.write(0) } } /// Disables counter - pub fn disable_counter(&self) { + pub fn disable_counter(&mut self) { unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) } } - /// Checks if SysTick interrupt is enabled - pub fn is_interrupt_enabled(&self) -> bool { - self.csr.read() & SYST_CSR_TICKINT != 0 + /// Disables SysTick interrupt + pub fn disable_interrupt(&mut self) { + unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) } } - /// Enables SysTick interrupt - pub fn enable_interrupt(&self) { - unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) } + /// Enables counter + pub fn enable_counter(&mut self) { + unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) } } - /// Disables SysTick interrupt - pub fn disable_interrupt(&self) { - unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) } + /// Enables SysTick interrupt + pub fn enable_interrupt(&mut self) { + unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) } } /// Gets clock source - pub fn get_clock_source(&self) -> SystClkSource { + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + pub fn get_clock_source(&mut self) -> SystClkSource { + // NOTE(unsafe) atomic read with no side effects let clk_source_bit = self.csr.read() & SYST_CSR_CLKSOURCE != 0; match clk_source_bit { false => SystClkSource::External, @@ -74,51 +78,56 @@ impl RegisterBlock { } } - /// Sets clock source - pub fn set_clock_source(&self, clk_source: SystClkSource) { - match clk_source { - SystClkSource::External => unsafe { self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) }, - SystClkSource::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) }, - } - } - - /// Checks if the counter wrapped (underflowed) since the last check - pub fn has_wrapped(&self) -> bool { - self.csr.read() & SYST_CSR_COUNTFLAG != 0 + /// Gets current value + pub fn get_current() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).cvr.read() } } /// Gets reload value - pub fn get_reload(&self) -> u32 { - self.rvr.read() + pub fn get_reload() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).rvr.read() } } - /// Sets reload value + /// Returns the reload value with which the counter would wrap once per 10 + /// ms /// - /// Valid values are between `1` and `0x00ffffff`. - pub fn set_reload(&self, value: u32) { - unsafe { self.rvr.write(value) } + /// Returns `0` if the value is not known (e.g. because the clock can + /// change dynamically). + pub fn get_ticks_per_10ms() -> u32 { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).calib.read() & SYST_COUNTER_MASK } } - /// Gets current value - pub fn get_current(&self) -> u32 { - self.cvr.read() + /// Checks if an external reference clock is available + pub fn has_reference_clock() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).calib.read() & SYST_CALIB_NOREF == 0 } } - /// Clears current value to 0 + /// Checks if the counter wrapped (underflowed) since the last check /// - /// After calling `clear_current()`, the next call to `has_wrapped()` - /// will return `false`. - pub fn clear_current(&self) { - unsafe { self.cvr.write(0) } + /// *NOTE* This takes `&mut self` because the read operation is side effectful and will clear + /// the bit of the read register. + pub fn has_wrapped(&mut self) -> bool { + self.csr.read() & SYST_CSR_COUNTFLAG != 0 } - /// Returns the reload value with which the counter would wrap once per 10 - /// ms + /// Checks if counter is enabled /// - /// Returns `0` if the value is not known (e.g. because the clock can - /// change dynamically). - pub fn get_ticks_per_10ms(&self) -> u32 { - self.calib.read() & SYST_COUNTER_MASK + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + pub fn is_counter_enabled(&mut self) -> bool { + self.csr.read() & SYST_CSR_ENABLE != 0 + } + + /// Checks if SysTick interrupt is enabled + /// + /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the + /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) + pub fn is_interrupt_enabled(&mut self) -> bool { + self.csr.read() & SYST_CSR_TICKINT != 0 } /// Checks if the calibration value is precise @@ -126,12 +135,26 @@ impl RegisterBlock { /// Returns `false` if using the reload value returned by /// `get_ticks_per_10ms()` may result in a period significantly deviating /// from 10 ms. - pub fn is_precise(&self) -> bool { - self.calib.read() & SYST_CALIB_SKEW == 0 + pub fn is_precise() -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Self::ptr()).calib.read() & SYST_CALIB_SKEW == 0 } } - /// Checks if an external reference clock is available - pub fn has_reference_clock(&self) -> bool { - self.calib.read() & SYST_CALIB_NOREF == 0 + /// Sets clock source + pub fn set_clock_source(&mut self, clk_source: SystClkSource) { + match clk_source { + SystClkSource::External => unsafe { + self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) + }, + SystClkSource::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) }, + } } + + /// Sets reload value + /// + /// Valid values are between `1` and `0x00ffffff`. + pub fn set_reload(&mut self, value: u32) { + unsafe { self.rvr.write(value) } + } + } diff --git a/src/peripheral/test.rs b/src/peripheral/test.rs index d50ece2..39f7de5 100644 --- a/src/peripheral/test.rs +++ b/src/peripheral/test.rs @@ -129,7 +129,6 @@ fn scb() { assert_eq!(address(&scb.bfar), 0xE000_ED38); assert_eq!(address(&scb.afsr), 0xE000_ED3C); assert_eq!(address(&scb.cpacr), 0xE000_ED88); - } #[test] @@ -140,7 +139,6 @@ fn syst() { assert_eq!(address(&syst.rvr), 0xE000_E014); assert_eq!(address(&syst.cvr), 0xE000_E018); assert_eq!(address(&syst.calib), 0xE000_E01C); - } #[test] diff --git a/src/register/apsr.rs b/src/register/apsr.rs index d966de0..60dd364 100644 --- a/src/register/apsr.rs +++ b/src/register/apsr.rs @@ -39,15 +39,18 @@ impl Apsr { } /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> Apsr { - let r: u32; - unsafe { - asm!("mrs $0, APSR" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { + asm!("mrs $0, APSR" : "=r"(r) ::: "volatile"); + } + Apsr { bits: r } + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - Apsr { bits: r } } diff --git a/src/register/basepri.rs b/src/register/basepri.rs index c02fe84..c9be9d3 100644 --- a/src/register/basepri.rs +++ b/src/register/basepri.rs @@ -1,25 +1,40 @@ //! Base Priority Mask Register /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> u8 { - let r: u32; - unsafe { - asm!("mrs $0, BASEPRI" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { + asm!("mrs $0, BASEPRI" : "=r"(r) ::: "volatile"); + } + r as u8 + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - r as u8 } /// Writes to the CPU register -#[inline(always)] +/// +/// **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_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub unsafe fn write(basepri: u8) { - asm!("msr BASEPRI, $0" - : - : "r"(basepri) - : "memory" - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => match () { + #[cfg(not(feature = "cm7-r0p1"))] + () => asm!("msr BASEPRI, $0" :: "r"(basepri) : "memory" : "volatile"), + #[cfg(feature = "cm7-r0p1")] + () => asm!("cpsid i + msr BASEPRI, $0 + cpsie i" :: "r"(basepri) : "memory" : "volatile"), + }, + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), + } } diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs index bcc7cdb..c386e86 100644 --- a/src/register/basepri_max.rs +++ b/src/register/basepri_max.rs @@ -4,13 +4,25 @@ /// /// - `basepri != 0` AND `basepri::read() == 0`, OR /// - `basepri != 0` AND `basepri < basepri::read()` -#[inline(always)] +/// +/// **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_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub fn write(basepri: u8) { - unsafe { - asm!("msr BASEPRI_MAX, $0" - : - : "r"(basepri) - : "memory" - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => unsafe { + match () { + #[cfg(not(feature = "cm7-r0p1"))] + () => asm!("msr BASEPRI_MAX, $0" :: "r"(basepri) : "memory" : "volatile"), + #[cfg(feature = "cm7-r0p1")] + () => asm!("cpsid i + msr BASEPRI_MAX, $0 + cpsie i" :: "r"(basepri) : "memory" : "volatile"), + } + }, + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } } diff --git a/src/register/control.rs b/src/register/control.rs index d5cb8ec..93c497f 100644 --- a/src/register/control.rs +++ b/src/register/control.rs @@ -104,15 +104,16 @@ impl Fpca { } /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> Control { - let r: u32; - unsafe { - asm!("mrs $0, CONTROL" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") } + Control { bits: r } + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - Control { bits: r } } diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs index 7a0d06c..3e0980e 100644 --- a/src/register/faultmask.rs +++ b/src/register/faultmask.rs @@ -22,19 +22,20 @@ impl Faultmask { } /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> Faultmask { - let r: u32; - unsafe { - asm!("mrs $0, FAULTMASK" - : "=r"(r) - : - : - : "volatile"); - } - if r & (1 << 0) == (1 << 0) { - Faultmask::Inactive - } else { - Faultmask::Active + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") } + if r & (1 << 0) == (1 << 0) { + Faultmask::Inactive + } else { + Faultmask::Active + } + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } } diff --git a/src/register/lr.rs b/src/register/lr.rs index fecfecb..ddbc07d 100644 --- a/src/register/lr.rs +++ b/src/register/lr.rs @@ -1,25 +1,28 @@ //! Link register /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> u32 { - let r: u32; - unsafe { - asm!("mov $0,R14" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { asm!("mov $0,R14" : "=r"(r) ::: "volatile") } + r + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - r } /// Writes `bits` to the CPU register -#[inline(always)] +#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub unsafe fn write(bits: u32) { - asm!("mov R14,$0" - : - : "r"(bits) - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => asm!("mov R14,$0" :: "r"(bits) :: "volatile"), + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), + } } diff --git a/src/register/msp.rs b/src/register/msp.rs index ebea6ed..3b83353 100644 --- a/src/register/msp.rs +++ b/src/register/msp.rs @@ -1,25 +1,28 @@ //! Main Stack Pointer /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> u32 { - let r; - unsafe { - asm!("mrs $0,MSP" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r; + unsafe { asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") } + r + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - r } /// Writes `bits` to the CPU register -#[inline(always)] +#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub unsafe fn write(bits: u32) { - asm!("msr MSP,$0" - : - : "r"(bits) - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => asm!("msr MSP,$0" :: "r"(bits) :: "volatile"), + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), + } } diff --git a/src/register/pc.rs b/src/register/pc.rs index 3fec1ae..7a7ef19 100644 --- a/src/register/pc.rs +++ b/src/register/pc.rs @@ -1,25 +1,28 @@ //! Program counter /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> u32 { - let r; - unsafe { - asm!("mov $0,R15" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r; + unsafe { asm!("mov $0,R15" : "=r"(r) ::: "volatile") } + r + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - r } /// Writes `bits` to the CPU register -#[inline(always)] +#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub unsafe fn write(bits: u32) { - asm!("mov R15,$0" - : - : "r"(bits) - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => asm!("mov R15,$0" :: "r"(bits) :: "volatile"), + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), + } } diff --git a/src/register/primask.rs b/src/register/primask.rs index 313693f..c9dc39a 100644 --- a/src/register/primask.rs +++ b/src/register/primask.rs @@ -22,19 +22,20 @@ impl Primask { } /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> Primask { - let r: u32; - unsafe { - asm!("mrs $0, PRIMASK" - : "=r"(r) - : - : - : "volatile"); - } - if r & (1 << 0) == (1 << 0) { - Primask::Inactive - } else { - Primask::Active + match () { + #[cfg(target_arch = "arm")] + () => { + let r: u32; + unsafe { asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") } + if r & (1 << 0) == (1 << 0) { + Primask::Inactive + } else { + Primask::Active + } + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } } diff --git a/src/register/psp.rs b/src/register/psp.rs index ecd6f9c..d7232db 100644 --- a/src/register/psp.rs +++ b/src/register/psp.rs @@ -1,25 +1,28 @@ //! Process Stack Pointer /// Reads the CPU register -#[inline(always)] +#[inline] pub fn read() -> u32 { - let r; - unsafe { - asm!("mrs $0,PSP" - : "=r"(r) - : - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => { + let r; + unsafe { asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") } + r + } + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), } - r } /// Writes `bits` to the CPU register -#[inline(always)] +#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))] +#[inline] pub unsafe fn write(bits: u32) { - asm!("msr PSP,$0" - : - : "r"(bits) - : - : "volatile"); + match () { + #[cfg(target_arch = "arm")] + () => asm!("msr PSP,$0" :: "r"(bits) :: "volatile"), + #[cfg(not(target_arch = "arm"))] + () => unimplemented!(), + } } |