aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs73
-rw-r--r--src/exception.rs3
-rw-r--r--src/interrupt.rs22
-rw-r--r--src/itm.rs12
-rw-r--r--src/peripheral/cbp.rs44
-rw-r--r--src/peripheral/cpuid.rs9
-rw-r--r--src/peripheral/dwt.rs22
-rw-r--r--src/peripheral/itm.rs6
-rw-r--r--src/peripheral/mod.rs83
-rw-r--r--src/peripheral/nvic.rs67
-rw-r--r--src/peripheral/scb.rs116
-rw-r--r--src/peripheral/syst.rs135
-rw-r--r--src/peripheral/test.rs2
-rw-r--r--src/register/apsr.rs21
-rw-r--r--src/register/basepri.rs45
-rw-r--r--src/register/basepri_max.rs26
-rw-r--r--src/register/control.rs19
-rw-r--r--src/register/faultmask.rs27
-rw-r--r--src/register/lr.rs33
-rw-r--r--src/register/msp.rs33
-rw-r--r--src/register/pc.rs33
-rw-r--r--src/register/primask.rs27
-rw-r--r--src/register/psp.rs33
23 files changed, 514 insertions, 377 deletions
diff --git a/src/asm.rs b/src/asm.rs
index daa7b55..aab772e 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -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!(),
}
}
diff --git a/src/itm.rs b/src/itm.rs
index 5a2722d..02ada53 100644
--- a/src/itm.rs
+++ b/src/itm.rs
@@ -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!(),
+ }
}