diff options
author | 2018-05-11 17:04:05 +0200 | |
---|---|---|
committer | 2018-05-11 17:09:36 +0200 | |
commit | 93abfac2a7e092d739e3e9b61bcd4f8614541428 (patch) | |
tree | 716486743e0fb0de56b5a9ed05e2af57e80a627d /src | |
parent | b098b6af6aa48826aa1471ba3359a42d6d3e059a (diff) | |
download | cortex-m-93abfac2a7e092d739e3e9b61bcd4f8614541428.tar.gz cortex-m-93abfac2a7e092d739e3e9b61bcd4f8614541428.tar.zst cortex-m-93abfac2a7e092d739e3e9b61bcd4f8614541428.zip |
stable by default, remove exception module, add SCB.vect_active, ..
tweak Exception enum to match CMSIS names, document the parts of the API that require opting into
`"inline-asm"`.
Diffstat (limited to 'src')
-rw-r--r-- | src/exception.rs | 72 | ||||
-rw-r--r-- | src/lib.rs | 35 | ||||
-rw-r--r-- | src/macros.rs | 11 | ||||
-rw-r--r-- | src/peripheral/nvic.rs | 2 | ||||
-rw-r--r-- | src/peripheral/scb.rs | 143 | ||||
-rw-r--r-- | src/peripheral/syst.rs | 5 | ||||
-rw-r--r-- | src/register/apsr.rs | 2 | ||||
-rw-r--r-- | src/register/basepri.rs | 2 | ||||
-rw-r--r-- | src/register/lr.rs | 4 | ||||
-rw-r--r-- | src/register/mod.rs | 6 | ||||
-rw-r--r-- | src/register/pc.rs | 4 | ||||
-rw-r--r-- | src/register/psp.rs | 2 |
12 files changed, 190 insertions, 98 deletions
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, -} @@ -5,11 +5,35 @@ //! - 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)] -#![cfg_attr(feature = "inline-asm", feature(asm))] #![no_std] extern crate aligned; @@ -20,16 +44,11 @@ extern crate volatile_register; mod macros; pub mod asm; -pub mod exception; pub mod interrupt; -// NOTE(target_arch) is for documentation purposes +// NOTE(target_arch = "x86_64") is used throughout this crate for documentation purposes #[cfg(any(armv7m, target_arch = "x86_64"))] pub mod itm; pub mod peripheral; pub mod register; pub use peripheral::Peripherals; - -#[cfg(feature = "singleton")] -#[doc(hidden)] -pub use untagged_option::UntaggedOption; diff --git a/src/macros.rs b/src/macros.rs index 7bbc9be..e41cdc5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -63,16 +63,19 @@ macro_rules! singleton { let expr = $expr; #[allow(unsafe_code)] - unsafe { VAR = Some(expr) } + unsafe { + VAR = Some(expr) + } #[allow(unsafe_code)] - unsafe { VAR.as_mut() } + unsafe { + VAR.as_mut() + } } }) - } + }; } - /// ``` compile_fail /// #[macro_use(singleton)] /// extern crate cortex_m; diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs index ecfdd7e..7ce31ba 100644 --- a/src/peripheral/nvic.rs +++ b/src/peripheral/nvic.rs @@ -2,8 +2,8 @@ use volatile_register::{RO, RW}; -use peripheral::NVIC; use interrupt::Nr; +use peripheral::NVIC; /// Register block #[repr(C)] diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 41f3825..70144c1 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -1,13 +1,15 @@ //! 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"))] use super::cpuid::CsselrCacheType; +#[cfg(any(armv7m, target_arch = "x86_64"))] +use super::CPUID; +#[cfg(any(armv7m, has_fpu, target_arch = "x86_64"))] +use super::{CBP, SCB}; /// Register block #[repr(C)] @@ -108,6 +110,139 @@ impl SCB { } } +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(any(not(armv6m), target_arch = "x86_64"))] + 4 => VectActive::Exception(Exception::MemoryManagement), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 5 => VectActive::Exception(Exception::BusFault), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 6 => VectActive::Exception(Exception::UsageFault), + #[cfg(any(armv8m, target_arch = "x86_64"))] + 7 => VectActive::Exception(Exception::SecureFault), + 11 => VectActive::Exception(Exception::SVCall), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 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(any(not(armv6m), target_arch = "x86_64"))] + MemoryManagement, + + /// Bus fault interrupt (not present on Cortex-M0 variants) + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + BusFault, + + /// Usage fault interrupt (not present on Cortex-M0 variants) + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 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(any(not(armv6m), target_arch = "x86_64"))] + 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(any(not(armv6m), target_arch = "x86_64"))] + Exception::MemoryManagement => -12, + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + Exception::BusFault => -11, + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + Exception::UsageFault => -10, + #[cfg(any(armv8m, target_arch = "x86_64"))] + Exception::SecureFault => -9, + Exception::SVCall => -5, + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 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(any(not(armv6m), target_arch = "x86_64"))] + 4 => VectActive::Exception(Exception::MemoryManagement), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 5 => VectActive::Exception(Exception::BusFault), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 6 => VectActive::Exception(Exception::UsageFault), + #[cfg(any(armv8m, target_arch = "x86_64"))] + 7 => VectActive::Exception(Exception::SecureFault), + 11 => VectActive::Exception(Exception::SVCall), + #[cfg(any(not(armv6m), target_arch = "x86_64"))] + 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(any(armv7m, target_arch = "x86_64"))] mod scb_consts { pub const SCB_CCR_IC_MASK: u32 = (1 << 17); 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/register/apsr.rs b/src/register/apsr.rs index 280fd24..1312598 100644 --- a/src/register/apsr.rs +++ b/src/register/apsr.rs @@ -39,6 +39,8 @@ 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 () { diff --git a/src/register/basepri.rs b/src/register/basepri.rs index 086d8cf..6604ea0 100644 --- a/src/register/basepri.rs +++ b/src/register/basepri.rs @@ -51,7 +51,7 @@ pub unsafe fn write(_basepri: u8) { } __basepri_w(_basepri); - }, + } #[cfg(not(cortex_m))] () => unimplemented!(), diff --git a/src/register/lr.rs b/src/register/lr.rs index 60828d0..a17f7ac 100644 --- a/src/register/lr.rs +++ b/src/register/lr.rs @@ -1,6 +1,8 @@ //! 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 () { @@ -17,6 +19,8 @@ pub fn read() -> u32 { } /// Writes `bits` to the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] pub unsafe fn write(_bits: u32) { match () { diff --git a/src/register/mod.rs b/src/register/mod.rs index 37692c8..1444aff 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -45,11 +45,11 @@ pub mod psp; // Accessing these registers requires inline assembly because their contents are tied to the current // stack frame -#[cfg(feature = "nightly")] +#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] pub mod apsr; -#[cfg(feature = "nightly")] +#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] pub mod lr; -#[cfg(feature = "nightly")] +#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] pub mod pc; diff --git a/src/register/pc.rs b/src/register/pc.rs index b41383d..37176e8 100644 --- a/src/register/pc.rs +++ b/src/register/pc.rs @@ -1,6 +1,8 @@ //! 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 () { @@ -17,6 +19,8 @@ pub fn read() -> u32 { } /// Writes `bits` to the CPU register +/// +/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature. #[inline] pub unsafe fn write(_bits: u32) { match () { diff --git a/src/register/psp.rs b/src/register/psp.rs index 9f4889c..b6618b0 100644 --- a/src/register/psp.rs +++ b/src/register/psp.rs @@ -18,7 +18,7 @@ pub fn read() -> u32 { } __psp_r() - } + }, #[cfg(not(cortex_m))] () => unimplemented!(), |