aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs134
-rw-r--r--src/exception.rs72
-rw-r--r--src/interrupt.rs32
-rw-r--r--src/itm.rs2
-rw-r--r--src/lib.rs36
-rw-r--r--src/macros.rs22
-rw-r--r--src/peripheral/cpuid.rs64
-rw-r--r--src/peripheral/mod.rs81
-rw-r--r--src/peripheral/nvic.rs31
-rw-r--r--src/peripheral/scb.rs228
-rw-r--r--src/peripheral/syst.rs5
-rw-r--r--src/peripheral/test.rs4
-rw-r--r--src/register/apsr.rs7
-rw-r--r--src/register/basepri.rs39
-rw-r--r--src/register/basepri_max.rs25
-rw-r--r--src/register/control.rs25
-rw-r--r--src/register/faultmask.rs26
-rw-r--r--src/register/lr.rs19
-rw-r--r--src/register/mod.rs20
-rw-r--r--src/register/msp.rs33
-rw-r--r--src/register/pc.rs19
-rw-r--r--src/register/primask.rs25
-rw-r--r--src/register/psp.rs33
23 files changed, 692 insertions, 290 deletions
diff --git a/src/asm.rs b/src/asm.rs
index 9a2d481..6e90f09 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -1,16 +1,25 @@
//! Miscellaneous assembly instructions
-/// Puts the processor in Debug state. Debuggers can pick this up as a
-/// "breakpoint".
+/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
///
-/// NOTE calling `bkpt` when the processor is not connected to a debugger will
-/// cause an exception
+/// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an
+/// exception.
#[inline(always)]
pub fn bkpt() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe { asm!("bkpt" :::: "volatile") },
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __bkpt();
+ }
+
+ __bkpt();
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -19,19 +28,40 @@ pub fn bkpt() {
#[inline]
pub fn nop() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe { asm!("nop" :::: "volatile") },
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __nop();
+ }
+
+ __nop()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
+
/// Wait For Event
#[inline]
pub fn wfe() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe { asm!("wfe" :::: "volatile") },
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __wfe();
+ }
+
+ __wfe()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -40,9 +70,19 @@ pub fn wfe() {
#[inline]
pub fn wfi() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe { asm!("wfi" :::: "volatile") },
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __wfi();
+ }
+
+ __wfi()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -51,9 +91,19 @@ pub fn wfi() {
#[inline]
pub fn sev() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe { asm!("sev" :::: "volatile") },
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __sev();
+ }
+
+ __sev()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -65,27 +115,48 @@ pub fn sev() {
#[inline]
pub fn isb() {
match () {
- #[cfg(target_arch = "arm")]
- () => unsafe { asm!("isb 0xF" : : : "memory" : "volatile") },
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => unsafe { asm!("isb 0xF" ::: "memory" : "volatile") },
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __isb();
+ }
+
+ __isb()
+ // XXX do we need a explicit compiler barrier here?
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
/// Data Synchronization Barrier
///
-/// Acts as a special kind of memory barrier. No instruction in program order after this
-/// instruction can execute until this instruction completes. This instruction completes only when
-/// both:
+/// Acts as a special kind of memory barrier. No instruction in program order after this instruction
+/// can execute until this instruction completes. This instruction completes only when both:
///
/// * any explicit memory access made before this instruction is complete
/// * all cache and branch predictor maintenance operations before this instruction complete
#[inline]
pub fn dsb() {
match () {
- #[cfg(target_arch = "arm")]
- () => unsafe { asm!("dsb 0xF" : : : "memory" : "volatile") },
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => unsafe { asm!("dsb 0xF" ::: "memory" : "volatile") },
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __dsb();
+ }
+
+ __dsb()
+ // XXX do we need a explicit compiler barrier here?
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -98,9 +169,20 @@ pub fn dsb() {
#[inline]
pub fn dmb() {
match () {
- #[cfg(target_arch = "arm")]
- () => unsafe { asm!("dmb 0xF" : : : "memory" : "volatile") },
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => unsafe { asm!("dmb 0xF" ::: "memory" : "volatile") },
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __dmb();
+ }
+
+ __dmb()
+ // XXX do we need a explicit compiler barrier here?
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/exception.rs b/src/exception.rs
deleted file mode 100644
index b40cf1b..0000000
--- a/src/exception.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-//! Exceptions
-
-/// Enumeration of all the exception types
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Exception {
- /// Non-maskable interrupt
- NMI,
- /// Other type of faults and unhandled faults
- HardFault,
- /// Memory protection related fault
- MenManage,
- /// Pre-fetch or memory access fault
- BusFault,
- /// Fault due to undefined instruction or illegal state
- UsageFault,
- /// Supervisor call
- SVCall,
- /// Pendable request for system-level service
- PendSV,
- /// System timer exception
- SysTick,
- /// An interrupt
- Interrupt(u8),
- // Unreachable variant
- #[doc(hidden)] Reserved,
-}
-
-impl Exception {
- /// Returns the type of the exception that's currently active
- ///
- /// Returns `None` if no exception is currently active
- pub fn active() -> Option<Exception> {
- // NOTE(safe) atomic read with no side effects
- let icsr = unsafe { (*::peripheral::SCB::ptr()).icsr.read() };
-
- Some(match icsr as u8 {
- 0 => return None,
- 2 => Exception::NMI,
- 3 => Exception::HardFault,
- 4 => Exception::MenManage,
- 5 => Exception::BusFault,
- 6 => Exception::UsageFault,
- 11 => Exception::SVCall,
- 14 => Exception::PendSV,
- 15 => Exception::SysTick,
- n if n >= 16 => Exception::Interrupt(n - 16),
- _ => Exception::Reserved,
- })
- }
-}
-
-/// Registers stacked (pushed into the stack) during an exception
-#[derive(Clone, Copy, Debug)]
-#[repr(C)]
-pub struct ExceptionFrame {
- /// (General purpose) Register 0
- pub r0: u32,
- /// (General purpose) Register 1
- pub r1: u32,
- /// (General purpose) Register 2
- pub r2: u32,
- /// (General purpose) Register 3
- pub r3: u32,
- /// (General purpose) Register 12
- pub r12: u32,
- /// Linker Register
- pub lr: u32,
- /// Program Counter
- pub pc: u32,
- /// Program Status Register
- pub xpsr: u32,
-}
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 5880dd4..b57cc80 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -1,16 +1,29 @@
//! Interrupts
+// use core::sync::atomic::{self, Ordering};
+
pub use bare_metal::{CriticalSection, Mutex, Nr};
/// Disables all interrupts
#[inline]
pub fn disable() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe {
asm!("cpsid i" ::: "memory" : "volatile");
},
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __cpsid();
+ }
+
+ // XXX do we need a explicit compiler barrier here?
+ __cpsid();
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -23,9 +36,20 @@ pub fn disable() {
#[inline]
pub unsafe fn enable() {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => asm!("cpsie i" ::: "memory" : "volatile"),
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => {
+ extern "C" {
+ fn __cpsie();
+ }
+
+ // XXX do we need a explicit compiler barrier here?
+ __cpsie();
+ }
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/itm.rs b/src/itm.rs
index 02ada53..0e32e3c 100644
--- a/src/itm.rs
+++ b/src/itm.rs
@@ -1,4 +1,6 @@
//! Instrumentation Trace Macrocell
+//!
+//! **NOTE** This module is only available on ARMv7-M and newer
use core::{fmt, mem, ptr, slice};
diff --git a/src/lib.rs b/src/lib.rs
index 6af60d7..df0ccbb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,31 +5,49 @@
//! - Access to core peripherals like NVIC, SCB and SysTick.
//! - Access to core registers like CONTROL, MSP and PSR.
//! - Interrupt manipulation mechanisms
-//! - Safe wrappers around assembly instructions like `bkpt`
+//! - Safe wrappers around Cortex-M specific instructions like `bkpt`
+//!
+//! # Requirements
+//!
+//! To use this crate on the stable or beta channel `arm-none-eabi-gcc` needs to be installed and
+//! available in your `$PATH`.
+//!
+//! # Optional features
+//!
+//! ## `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
+//! assembly files compiled using `arm-none-eabi-gcc`). The advantages the enabling `inline-asm`
+//! are:
+//!
+//! - Reduced overhead. FFI eliminates the possibility of inlining so all operations include a
+//! function call overhead when `inline-asm` is not enabled.
+//!
+//! - `arm-none-eabi-gcc` is not required for building this crate.
+//!
+//! - Some of the `register` API only becomes available only when `inline-asm` is enabled. Check the
+//! API docs for details.
+//!
+//! The disadvantage is that `inline-asm` requires a nightly toolchain.
+#![cfg_attr(feature = "inline-asm", feature(asm))]
#![deny(missing_docs)]
#![deny(warnings)]
-#![feature(asm)]
-#![feature(const_fn)]
#![no_std]
extern crate aligned;
extern crate bare_metal;
-extern crate untagged_option;
extern crate volatile_register;
#[macro_use]
mod macros;
-#[macro_use]
pub mod asm;
-pub mod exception;
pub mod interrupt;
-// NOTE(target_arch) is for documentation purposes
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub mod itm;
pub mod peripheral;
pub mod register;
pub use peripheral::Peripherals;
-pub use untagged_option::UntaggedOption;
diff --git a/src/macros.rs b/src/macros.rs
index 7d2cf6a..e41cdc5 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -53,33 +53,29 @@ macro_rules! iprintln {
macro_rules! singleton {
(: $ty:ty = $expr:expr) => {
$crate::interrupt::free(|_| {
- static mut USED: bool = false;
- static mut VAR: $crate::UntaggedOption<$ty> = $crate::UntaggedOption { none: () };
-
+ static mut VAR: Option<$ty> = None;
#[allow(unsafe_code)]
- let used = unsafe { USED };
+ let used = unsafe { VAR.is_some() };
if used {
None
} else {
- #[allow(unsafe_code)]
- unsafe { USED = true }
-
let expr = $expr;
#[allow(unsafe_code)]
- unsafe { VAR.some = expr }
+ unsafe {
+ VAR = Some(expr)
+ }
#[allow(unsafe_code)]
- let var: &'static mut _ = unsafe { &mut VAR.some };
-
- Some(var)
+ unsafe {
+ VAR.as_mut()
+ }
}
})
- }
+ };
}
-
/// ``` compile_fail
/// #[macro_use(singleton)]
/// extern crate cortex_m;
diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs
index 94a2c20..d9dc027 100644
--- a/src/peripheral/cpuid.rs
+++ b/src/peripheral/cpuid.rs
@@ -1,10 +1,10 @@
//! CPUID
use volatile_register::RO;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
use volatile_register::RW;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
use peripheral::CPUID;
/// Register block
@@ -12,34 +12,60 @@ use peripheral::CPUID;
pub struct RegisterBlock {
/// CPUID base
pub base: RO<u32>,
- reserved0: [u32; 15],
- /// Processor Feature
+
+ _reserved0: [u32; 15],
+
+ /// Processor Feature (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub pfr: [RO<u32>; 2],
- /// Debug Feature
+ #[cfg(armv6m)]
+ _reserved1: [u32; 2],
+
+ /// Debug Feature (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub dfr: RO<u32>,
- /// Auxiliary Feature
+ #[cfg(armv6m)]
+ _reserved2: u32,
+
+ /// Auxiliary Feature (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub afr: RO<u32>,
- /// Memory Model Feature
+ #[cfg(armv6m)]
+ _reserved3: u32,
+
+ /// Memory Model Feature (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub mmfr: [RO<u32>; 4],
- /// Instruction Set Attribute
+ #[cfg(armv6m)]
+ _reserved4: [u32; 4],
+
+ /// Instruction Set Attribute (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub isar: [RO<u32>; 5],
- reserved1: u32,
- /// Cache Level ID
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+ #[cfg(armv6m)]
+ _reserved5: [u32; 5],
+
+ _reserved6: u32,
+
+ /// Cache Level ID (only present on Cortex-M7)
+ #[cfg(not(armv6m))]
pub clidr: RO<u32>,
- /// Cache Type
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Cache Type (only present on Cortex-M7)
+ #[cfg(not(armv6m))]
pub ctr: RO<u32>,
- /// Cache Size ID
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Cache Size ID (only present on Cortex-M7)
+ #[cfg(not(armv6m))]
pub ccsidr: RO<u32>,
- /// Cache Size Selection
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Cache Size Selection (only present on Cortex-M7)
+ #[cfg(not(armv6m))]
pub csselr: RW<u32>,
}
/// Type of cache to select on CSSELR writes.
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub enum CsselrCacheType {
/// Select DCache or unified cache
DataOrUnified = 0,
@@ -47,7 +73,7 @@ pub enum CsselrCacheType {
Instruction = 1,
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl CPUID {
/// Selects the current CCSIDR
///
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index 4462136..fe52bd1 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -84,23 +84,23 @@ use core::ops;
use interrupt;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub mod cbp;
pub mod cpuid;
pub mod dcb;
pub mod dwt;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub mod fpb;
+// NOTE(target_arch) is for documentation purposes
#[cfg(any(has_fpu, target_arch = "x86_64"))]
pub mod fpu;
-// NOTE(target_arch) is for documentation purposes
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub mod itm;
pub mod mpu;
pub mod nvic;
pub mod scb;
pub mod syst;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
pub mod tpiu;
#[cfg(test)]
@@ -111,34 +111,40 @@ mod test;
/// Core peripherals
#[allow(non_snake_case)]
pub struct Peripherals {
- /// Cache and branch predictor maintenance operations
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+ /// Cache and branch predictor maintenance operations (not present on Cortex-M0 variants)
pub CBP: CBP,
+
/// CPUID
pub CPUID: CPUID,
+
/// Debug Control Block
pub DCB: DCB,
+
/// Data Watchpoint and Trace unit
pub DWT: DWT,
- /// Flash Patch and Breakpoint unit
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Flash Patch and Breakpoint unit (not present on Cortex-M0 variants)
pub FPB: FPB,
- /// Floating Point Unit
- #[cfg(any(has_fpu, target_arch = "x86_64"))]
+
+ /// Floating Point Unit (only present on `thumbv7em-none-eabihf`)
pub FPU: FPU,
- /// Instrumentation Trace Macrocell
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Instrumentation Trace Macrocell (not present on Cortex-M0 variants)
pub ITM: ITM,
+
/// Memory Protection Unit
pub MPU: MPU,
+
/// Nested Vector Interrupt Controller
pub NVIC: NVIC,
+
/// System Control Block
pub SCB: SCB,
+
/// SysTick: System Timer
pub SYST: SYST,
- /// Trace Port Interface Unit;
- #[cfg(any(armv7m, target_arch = "x86_64"))]
+
+ /// Trace Port Interface Unit (not present on Cortex-M0 variants)
pub TPIU: TPIU,
}
@@ -167,7 +173,6 @@ impl Peripherals {
CORE_PERIPHERALS = true;
Peripherals {
- #[cfg(any(armv7m, target_arch = "x86_64"))]
CBP: CBP {
_marker: PhantomData,
},
@@ -180,15 +185,12 @@ impl Peripherals {
DWT: DWT {
_marker: PhantomData,
},
- #[cfg(any(armv7m, target_arch = "x86_64"))]
FPB: FPB {
_marker: PhantomData,
},
- #[cfg(any(has_fpu, target_arch = "x86_64"))]
FPU: FPU {
_marker: PhantomData,
},
- #[cfg(any(armv7m, target_arch = "x86_64"))]
ITM: ITM {
_marker: PhantomData,
},
@@ -204,7 +206,6 @@ impl Peripherals {
SYST: SYST {
_marker: PhantomData,
},
- #[cfg(any(armv7m, target_arch = "x86_64"))]
TPIU: TPIU {
_marker: PhantomData,
},
@@ -213,17 +214,13 @@ impl Peripherals {
}
/// Cache and branch predictor maintenance operations
-///
-/// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
-#[cfg(any(armv7m, target_arch = "x86_64"))]
pub struct CBP {
_marker: PhantomData<*const ()>,
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
unsafe impl Send for CBP {}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl CBP {
pub(crate) unsafe fn new() -> Self {
CBP {
@@ -237,7 +234,7 @@ impl CBP {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ops::Deref for CBP {
type Target = self::cbp::RegisterBlock;
@@ -313,17 +310,13 @@ impl ops::Deref for DWT {
}
/// Flash Patch and Breakpoint unit
-///
-/// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
-#[cfg(any(armv7m, target_arch = "x86_64"))]
pub struct FPB {
_marker: PhantomData<*const ()>,
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
unsafe impl Send for FPB {}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl FPB {
/// Returns a pointer to the register block
pub fn ptr() -> *const fpb::RegisterBlock {
@@ -331,7 +324,7 @@ impl FPB {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ops::Deref for FPB {
type Target = self::fpb::RegisterBlock;
@@ -341,14 +334,10 @@ impl ops::Deref for FPB {
}
/// Floating Point Unit
-///
-/// *NOTE* Available only on ARMv7E-M (`thumbv7em-none-eabihf`)
-#[cfg(any(has_fpu, target_arch = "x86_64"))]
pub struct FPU {
_marker: PhantomData<*const ()>,
}
-#[cfg(any(has_fpu, target_arch = "x86_64"))]
unsafe impl Send for FPU {}
#[cfg(any(has_fpu, target_arch = "x86_64"))]
@@ -369,17 +358,13 @@ impl ops::Deref for FPU {
}
/// Instrumentation Trace Macrocell
-///
-/// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
-#[cfg(any(armv7m, target_arch = "x86_64"))]
pub struct ITM {
_marker: PhantomData<*const ()>,
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
unsafe impl Send for ITM {}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ITM {
/// Returns a pointer to the register block
pub fn ptr() -> *mut itm::RegisterBlock {
@@ -387,7 +372,7 @@ impl ITM {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ops::Deref for ITM {
type Target = self::itm::RegisterBlock;
@@ -396,7 +381,7 @@ impl ops::Deref for ITM {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ops::DerefMut for ITM {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *Self::ptr() }
@@ -491,18 +476,14 @@ impl ops::Deref for SYST {
}
}
-/// Trace Port Interface Unit;
-///
-/// *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`)
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+/// Trace Port Interface Unit
pub struct TPIU {
_marker: PhantomData<*const ()>,
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
unsafe impl Send for TPIU {}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl TPIU {
/// Returns a pointer to the register block
pub fn ptr() -> *const tpiu::RegisterBlock {
@@ -510,7 +491,7 @@ impl TPIU {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl ops::Deref for TPIU {
type Target = self::tpiu::RegisterBlock;
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index ecfdd7e..1a6a027 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -1,28 +1,42 @@
//! Nested Vector Interrupt Controller
-use volatile_register::{RO, RW};
+#[cfg(not(armv6m))]
+use volatile_register::RO;
+use volatile_register::RW;
-use peripheral::NVIC;
use interrupt::Nr;
+use peripheral::NVIC;
/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// Interrupt Set-Enable
pub iser: [RW<u32>; 16],
- reserved0: [u32; 16],
+
+ _reserved0: [u32; 16],
+
/// Interrupt Clear-Enable
pub icer: [RW<u32>; 16],
- reserved1: [u32; 16],
+
+ _reserved1: [u32; 16],
+
/// Interrupt Set-Pending
pub ispr: [RW<u32>; 16],
- reserved2: [u32; 16],
+
+ _reserved2: [u32; 16],
+
/// Interrupt Clear-Pending
pub icpr: [RW<u32>; 16],
- reserved3: [u32; 16],
- /// Interrupt Active Bit
+
+ _reserved3: [u32; 16],
+
+ /// Interrupt Active Bit (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub iabr: [RO<u32>; 16],
- reserved4: [u32; 48],
+ #[cfg(armv6m)]
+ _reserved4: [u32; 16],
+
+ _reserved5: [u32; 48],
#[cfg(not(armv6m))]
/// Interrupt Priority
@@ -110,6 +124,7 @@ impl NVIC {
}
/// Is `interrupt` active or pre-empted and stacked
+ #[cfg(not(armv6m))]
pub fn is_active<I>(interrupt: I) -> bool
where
I: Nr,
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
index 41f3825..58e083b 100644
--- a/src/peripheral/scb.rs
+++ b/src/peripheral/scb.rs
@@ -1,46 +1,101 @@
//! System Control Block
+use core::ptr;
+
use volatile_register::RW;
-#[cfg(any(armv7m, has_fpu, target_arch = "x86_64"))]
-use super::{CBP, SCB};
-#[cfg(any(armv7m, target_arch = "x86_64"))]
-use super::CPUID;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
use super::cpuid::CsselrCacheType;
+#[cfg(not(armv6m))]
+use super::CPUID;
+#[cfg(not(armv6m))]
+use super::CBP;
+use super::SCB;
/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// Interrupt Control and State
pub icsr: RW<u32>,
- /// Vector Table Offset
+
+ /// Vector Table Offset (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub vtor: RW<u32>,
+ #[cfg(armv6m)]
+ _reserved0: u32,
+
/// Application Interrupt and Reset Control
pub aircr: RW<u32>,
+
/// System Control
pub scr: RW<u32>,
+
/// Configuration and Control
pub ccr: RW<u32>,
- /// System Handler Priority
+
+ /// System Handler Priority (word accessible only on Cortex-M0 variants)
+ ///
+ /// On ARMv7-M, `shpr[0]` points to SHPR1
+ ///
+ /// On ARMv6-M, `shpr[0]` points to SHPR2
+ #[cfg(not(armv6m))]
pub shpr: [RW<u8>; 12],
+ #[cfg(armv6m)]
+ _reserved1: u32,
+ /// System Handler Priority (word accessible only on Cortex-M0 variants)
+ ///
+ /// On ARMv7-M, `shpr[0]` points to SHPR1
+ ///
+ /// On ARMv6-M, `shpr[0]` points to SHPR2
+ #[cfg(armv6m)]
+ pub shpr: [RW<u32>; 2],
+
/// System Handler Control and State
- pub shpcrs: RW<u32>,
- /// Configurable Fault Status
+ pub shcrs: RW<u32>,
+
+ /// Configurable Fault Status (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub cfsr: RW<u32>,
- /// HardFault Status
+ #[cfg(armv6m)]
+ _reserved2: u32,
+
+ /// HardFault Status (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub hfsr: RW<u32>,
- /// Debug Fault Status
+ #[cfg(armv6m)]
+ _reserved3: u32,
+
+ /// Debug Fault Status (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub dfsr: RW<u32>,
- /// MemManage Fault Address
- pub mmar: RW<u32>,
- /// BusFault Address
+ #[cfg(armv6m)]
+ _reserved4: u32,
+
+ /// MemManage Fault Address (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ pub mmfar: RW<u32>,
+ #[cfg(armv6m)]
+ _reserved5: u32,
+
+ /// BusFault Address (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub bfar: RW<u32>,
- /// Auxiliary Fault Status
+ #[cfg(armv6m)]
+ _reserved6: u32,
+
+ /// Auxiliary Fault Status (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub afsr: RW<u32>,
- reserved: [u32; 18],
- /// Coprocessor Access Control
+ #[cfg(armv6m)]
+ _reserved7: u32,
+
+ _reserved8: [u32; 18],
+
+ /// Coprocessor Access Control (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
pub cpacr: RW<u32>,
+ #[cfg(armv6m)]
+ _reserved9: u32,
}
/// FPU access mode
@@ -108,16 +163,149 @@ impl SCB {
}
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+impl SCB {
+ /// Returns the active exception number
+ pub fn vect_active() -> VectActive {
+ let icsr = unsafe { ptr::read(&(*SCB::ptr()).icsr as *const _ as *const u32) };
+
+ match icsr as u8 {
+ 0 => VectActive::ThreadMode,
+ 2 => VectActive::Exception(Exception::NonMaskableInt),
+ 3 => VectActive::Exception(Exception::HardFault),
+ #[cfg(not(armv6m))]
+ 4 => VectActive::Exception(Exception::MemoryManagement),
+ #[cfg(not(armv6m))]
+ 5 => VectActive::Exception(Exception::BusFault),
+ #[cfg(not(armv6m))]
+ 6 => VectActive::Exception(Exception::UsageFault),
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ 7 => VectActive::Exception(Exception::SecureFault),
+ 11 => VectActive::Exception(Exception::SVCall),
+ #[cfg(not(armv6m))]
+ 12 => VectActive::Exception(Exception::DebugMonitor),
+ 14 => VectActive::Exception(Exception::PendSV),
+ 15 => VectActive::Exception(Exception::SysTick),
+ irqn => VectActive::Interrupt { irqn: irqn - 16 },
+ }
+ }
+}
+
+/// Processor core exceptions (internal interrupts)
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum Exception {
+ /// Non maskable interrupt
+ NonMaskableInt,
+
+ /// Hard fault interrupt
+ HardFault,
+
+ /// Memory management interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ MemoryManagement,
+
+ /// Bus fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ BusFault,
+
+ /// Usage fault interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ UsageFault,
+
+ /// Secure fault interrupt (only on ARMv8-M)
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ SecureFault,
+
+ /// SV call interrupt
+ SVCall,
+
+ /// Debug monitor interrupt (not present on Cortex-M0 variants)
+ #[cfg(not(armv6m))]
+ DebugMonitor,
+
+ /// Pend SV interrupt
+ PendSV,
+
+ /// System Tick interrupt
+ SysTick,
+}
+
+impl Exception {
+ /// Returns the IRQ number of this `Exception`
+ ///
+ /// The return value is always within the closed range `[-1, -14]`
+ pub fn irqn(&self) -> i8 {
+ match *self {
+ Exception::NonMaskableInt => -14,
+ Exception::HardFault => -13,
+ #[cfg(not(armv6m))]
+ Exception::MemoryManagement => -12,
+ #[cfg(not(armv6m))]
+ Exception::BusFault => -11,
+ #[cfg(not(armv6m))]
+ Exception::UsageFault => -10,
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ Exception::SecureFault => -9,
+ Exception::SVCall => -5,
+ #[cfg(not(armv6m))]
+ Exception::DebugMonitor => -4,
+ Exception::PendSV => -2,
+ Exception::SysTick => -1,
+ }
+ }
+}
+
+/// Active exception number
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum VectActive {
+ /// Thread mode
+ ThreadMode,
+
+ /// Processor core exception (internal interrupts)
+ Exception(Exception),
+
+ /// Device specific exception (external interrupts)
+ Interrupt {
+ /// Interrupt number. This number is always within half open range `[0, 240)`
+ irqn: u8,
+ },
+}
+
+impl VectActive {
+ /// Converts a `byte` into `VectActive`
+ pub fn from(vect_active: u8) -> Option<Self> {
+ Some(match vect_active {
+ 0 => VectActive::ThreadMode,
+ 2 => VectActive::Exception(Exception::NonMaskableInt),
+ 3 => VectActive::Exception(Exception::HardFault),
+ #[cfg(not(armv6m))]
+ 4 => VectActive::Exception(Exception::MemoryManagement),
+ #[cfg(not(armv6m))]
+ 5 => VectActive::Exception(Exception::BusFault),
+ #[cfg(not(armv6m))]
+ 6 => VectActive::Exception(Exception::UsageFault),
+ #[cfg(any(armv8m, target_arch = "x86_64"))]
+ 7 => VectActive::Exception(Exception::SecureFault),
+ 11 => VectActive::Exception(Exception::SVCall),
+ #[cfg(not(armv6m))]
+ 12 => VectActive::Exception(Exception::DebugMonitor),
+ 14 => VectActive::Exception(Exception::PendSV),
+ 15 => VectActive::Exception(Exception::SysTick),
+ irqn if irqn >= 16 => VectActive::Interrupt { irqn },
+ _ => return None,
+ })
+ }
+}
+
+#[cfg(not(armv6m))]
mod scb_consts {
pub const SCB_CCR_IC_MASK: u32 = (1 << 17);
pub const SCB_CCR_DC_MASK: u32 = (1 << 16);
}
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
use self::scb_consts::*;
-#[cfg(any(armv7m, target_arch = "x86_64"))]
+#[cfg(not(armv6m))]
impl SCB {
/// Enables I-Cache if currently disabled
#[inline]
diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs
index ddffcde..ecefaea 100644
--- a/src/peripheral/syst.rs
+++ b/src/peripheral/syst.rs
@@ -153,9 +153,7 @@ impl SYST {
/// 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::External => unsafe { self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) },
SystClkSource::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) },
}
}
@@ -168,5 +166,4 @@ impl SYST {
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 39f7de5..cc3e292 100644
--- a/src/peripheral/test.rs
+++ b/src/peripheral/test.rs
@@ -121,11 +121,11 @@ fn scb() {
assert_eq!(address(&scb.scr), 0xE000_ED10);
assert_eq!(address(&scb.ccr), 0xE000_ED14);
assert_eq!(address(&scb.shpr), 0xE000_ED18);
- assert_eq!(address(&scb.shpcrs), 0xE000_ED24);
+ assert_eq!(address(&scb.shcrs), 0xE000_ED24);
assert_eq!(address(&scb.cfsr), 0xE000_ED28);
assert_eq!(address(&scb.hfsr), 0xE000_ED2C);
assert_eq!(address(&scb.dfsr), 0xE000_ED30);
- assert_eq!(address(&scb.mmar), 0xE000_ED34);
+ assert_eq!(address(&scb.mmfar), 0xE000_ED34);
assert_eq!(address(&scb.bfar), 0xE000_ED38);
assert_eq!(address(&scb.afsr), 0xE000_ED3C);
assert_eq!(address(&scb.cpacr), 0xE000_ED88);
diff --git a/src/register/apsr.rs b/src/register/apsr.rs
index 60dd364..1312598 100644
--- a/src/register/apsr.rs
+++ b/src/register/apsr.rs
@@ -39,10 +39,12 @@ impl Apsr {
}
/// Reads the CPU register
+///
+/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
#[inline]
pub fn read() -> Apsr {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
let r: u32;
unsafe {
@@ -50,7 +52,8 @@ pub fn read() -> Apsr {
}
Apsr { bits: r }
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/basepri.rs b/src/register/basepri.rs
index c9be9d3..c9f09cc 100644
--- a/src/register/basepri.rs
+++ b/src/register/basepri.rs
@@ -4,7 +4,7 @@
#[inline]
pub fn read() -> u8 {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => {
let r: u32;
unsafe {
@@ -12,7 +12,17 @@ pub fn read() -> u8 {
}
r as u8
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __basepri_r() -> u8;
+ }
+
+ __basepri_r()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
@@ -21,20 +31,29 @@ pub fn read() -> u8 {
///
/// **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) {
+pub unsafe fn write(_basepri: u8) {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => match () {
#[cfg(not(feature = "cm7-r0p1"))]
- () => asm!("msr BASEPRI, $0" :: "r"(basepri) : "memory" : "volatile"),
+ () => asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"),
#[cfg(feature = "cm7-r0p1")]
- () => asm!("cpsid i
- msr BASEPRI, $0
- cpsie i" :: "r"(basepri) : "memory" : "volatile"),
+ () => ::interrupt::free(
+ |_| asm!("msr BASEPRI, $0" :: "r"(_basepri) : "memory" : "volatile"),
+ ),
},
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => {
+ extern "C" {
+ fn __basepri_w(_: u8);
+ }
+
+ __basepri_w(_basepri);
+ }
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs
index c386e86..91698b6 100644
--- a/src/register/basepri_max.rs
+++ b/src/register/basepri_max.rs
@@ -7,22 +7,31 @@
///
/// **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) {
+pub fn write(_basepri: u8) {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => unsafe {
match () {
#[cfg(not(feature = "cm7-r0p1"))]
- () => asm!("msr BASEPRI_MAX, $0" :: "r"(basepri) : "memory" : "volatile"),
+ () => 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"),
+ () => ::interrupt::free(
+ |_| asm!("msr BASEPRI_MAX, $0" :: "r"(_basepri) : "memory" : "volatile"),
+ ),
}
},
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __basepri_max(_: u8);
+ }
+
+ __basepri_max(_basepri)
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/control.rs b/src/register/control.rs
index 93c497f..b6b6676 100644
--- a/src/register/control.rs
+++ b/src/register/control.rs
@@ -107,13 +107,30 @@ impl Fpca {
#[inline]
pub fn read() -> Control {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
- let r: u32;
- unsafe { asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") }
+ let r = match () {
+ #[cfg(feature = "inline-asm")]
+ () => {
+ let r: u32;
+ unsafe { asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") }
+ r
+ }
+
+ #[cfg(not(feature = "inline-asm"))]
+ () => unsafe {
+ extern "C" {
+ fn __control() -> u32;
+ }
+
+ __control()
+ },
+ };
+
Control { bits: r }
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs
index 3e0980e..9cd1892 100644
--- a/src/register/faultmask.rs
+++ b/src/register/faultmask.rs
@@ -25,17 +25,35 @@ impl Faultmask {
#[inline]
pub fn read() -> Faultmask {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
- let r: u32;
- unsafe { asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") }
+ let r = match () {
+ #[cfg(feature = "inline-asm")]
+ () => {
+ let r: u32;
+ unsafe { asm!("mrs $0, FAULTMASK" : "=r"(r) ::: "volatile") }
+ r
+ }
+
+ #[cfg(not(feature = "inline-asm"))]
+ () => unsafe {
+ extern "C" {
+ fn __faultmask() -> u32;
+
+ }
+
+ __faultmask()
+ },
+ };
+
if r & (1 << 0) == (1 << 0) {
Faultmask::Inactive
} else {
Faultmask::Active
}
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/lr.rs b/src/register/lr.rs
index ddbc07d..a17f7ac 100644
--- a/src/register/lr.rs
+++ b/src/register/lr.rs
@@ -1,28 +1,33 @@
//! Link register
/// Reads the CPU register
+///
+/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
#[inline]
pub fn read() -> u32 {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
let r: u32;
unsafe { asm!("mov $0,R14" : "=r"(r) ::: "volatile") }
r
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
/// Writes `bits` to the CPU register
-#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
+///
+/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
#[inline]
-pub unsafe fn write(bits: u32) {
+pub unsafe fn write(_bits: u32) {
match () {
- #[cfg(target_arch = "arm")]
- () => asm!("mov R14,$0" :: "r"(bits) :: "volatile"),
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(cortex_m)]
+ () => 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 17f6fda..1444aff 100644
--- a/src/register/mod.rs
+++ b/src/register/mod.rs
@@ -26,16 +26,30 @@
//!
//! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers
-pub mod apsr;
#[cfg(not(armv6m))]
pub mod basepri;
+
#[cfg(not(armv6m))]
pub mod basepri_max;
+
pub mod control;
+
#[cfg(not(armv6m))]
pub mod faultmask;
-pub mod lr;
+
pub mod msp;
-pub mod pc;
+
pub mod primask;
+
pub mod psp;
+
+// Accessing these registers requires inline assembly because their contents are tied to the current
+// stack frame
+#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))]
+pub mod apsr;
+
+#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))]
+pub mod lr;
+
+#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))]
+pub mod pc;
diff --git a/src/register/msp.rs b/src/register/msp.rs
index 3b83353..082a7fc 100644
--- a/src/register/msp.rs
+++ b/src/register/msp.rs
@@ -4,25 +4,44 @@
#[inline]
pub fn read() -> u32 {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => {
let r;
unsafe { asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") }
r
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __msp_r() -> u32;
+ }
+
+ __msp_r()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
/// Writes `bits` to the CPU register
-#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
#[inline]
-pub unsafe fn write(bits: u32) {
+pub unsafe fn write(_bits: u32) {
match () {
- #[cfg(target_arch = "arm")]
- () => asm!("msr MSP,$0" :: "r"(bits) :: "volatile"),
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => asm!("msr MSP,$0" :: "r"(_bits) :: "volatile"),
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => {
+ extern "C" {
+ fn __msp_w(_: u32);
+ }
+
+ __msp_w(_bits);
+ }
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/pc.rs b/src/register/pc.rs
index 7a7ef19..37176e8 100644
--- a/src/register/pc.rs
+++ b/src/register/pc.rs
@@ -1,28 +1,33 @@
//! Program counter
/// Reads the CPU register
+///
+/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
#[inline]
pub fn read() -> u32 {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
let r;
unsafe { asm!("mov $0,R15" : "=r"(r) ::: "volatile") }
r
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
/// Writes `bits` to the CPU register
-#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
+///
+/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
#[inline]
-pub unsafe fn write(bits: u32) {
+pub unsafe fn write(_bits: u32) {
match () {
- #[cfg(target_arch = "arm")]
- () => asm!("mov R15,$0" :: "r"(bits) :: "volatile"),
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(cortex_m)]
+ () => 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 c9dc39a..cb8faf9 100644
--- a/src/register/primask.rs
+++ b/src/register/primask.rs
@@ -25,17 +25,34 @@ impl Primask {
#[inline]
pub fn read() -> Primask {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(cortex_m)]
() => {
- let r: u32;
- unsafe { asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") }
+ let r = match () {
+ #[cfg(feature = "inline-asm")]
+ () => {
+ let r: u32;
+ unsafe { asm!("mrs $0, PRIMASK" : "=r"(r) ::: "volatile") }
+ r
+ }
+
+ #[cfg(not(feature = "inline-asm"))]
+ () => {
+ extern "C" {
+ fn __primask() -> u32;
+ }
+
+ unsafe { __primask() }
+ }
+ };
+
if r & (1 << 0) == (1 << 0) {
Primask::Inactive
} else {
Primask::Active
}
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
diff --git a/src/register/psp.rs b/src/register/psp.rs
index d7232db..b6618b0 100644
--- a/src/register/psp.rs
+++ b/src/register/psp.rs
@@ -4,25 +4,44 @@
#[inline]
pub fn read() -> u32 {
match () {
- #[cfg(target_arch = "arm")]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
() => {
let r;
unsafe { asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") }
r
}
- #[cfg(not(target_arch = "arm"))]
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => unsafe {
+ extern "C" {
+ fn __psp_r() -> u32;
+ }
+
+ __psp_r()
+ },
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}
/// Writes `bits` to the CPU register
-#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
#[inline]
-pub unsafe fn write(bits: u32) {
+pub unsafe fn write(_bits: u32) {
match () {
- #[cfg(target_arch = "arm")]
- () => asm!("msr PSP,$0" :: "r"(bits) :: "volatile"),
- #[cfg(not(target_arch = "arm"))]
+ #[cfg(all(cortex_m, feature = "inline-asm"))]
+ () => asm!("msr PSP,$0" :: "r"(_bits) :: "volatile"),
+
+ #[cfg(all(cortex_m, not(feature = "inline-asm")))]
+ () => {
+ extern "C" {
+ fn __psp_w(_: u32);
+ }
+
+ __psp_w(_bits);
+ }
+
+ #[cfg(not(cortex_m))]
() => unimplemented!(),
}
}