diff options
author | 2018-05-11 17:04:05 +0200 | |
---|---|---|
committer | 2018-05-11 17:09:36 +0200 | |
commit | 93abfac2a7e092d739e3e9b61bcd4f8614541428 (patch) | |
tree | 716486743e0fb0de56b5a9ed05e2af57e80a627d | |
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"`.
-rw-r--r-- | .travis.yml | 19 | ||||
-rw-r--r-- | CHANGELOG.md | 24 | ||||
-rw-r--r-- | Cargo.toml | 13 | ||||
-rw-r--r-- | asm/nop.s | 1 | ||||
-rw-r--r-- | ci/script.sh | 16 | ||||
-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 |
17 files changed, 248 insertions, 113 deletions
diff --git a/.travis.yml b/.travis.yml index fbdc1dc..f160be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,13 +3,32 @@ language: rust matrix: include: - env: TARGET=x86_64-unknown-linux-gnu + rust: beta + + - env: TARGET=thumbv6m-none-eabi + rust: beta + + - env: TARGET=thumbv7m-none-eabi + rust: beta + + - env: TARGET=thumbv7em-none-eabi + rust: beta + + - env: TARGET=thumbv7em-none-eabihf + rust: beta + + - env: TARGET=x86_64-unknown-linux-gnu rust: nightly + - env: TARGET=thumbv6m-none-eabi rust: nightly + - env: TARGET=thumbv7m-none-eabi rust: nightly + - env: TARGET=thumbv7em-none-eabi rust: nightly + - env: TARGET=thumbv7em-none-eabihf rust: nightly diff --git a/CHANGELOG.md b/CHANGELOG.md index 0711395..67bb043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [v0.5.0] - 2018-05-11 + +### Added + +- `DebugMonitor` and `SecureFault` variants to the `Exception` enumeration. + +- An optional `"inline-asm"` feature + +### Changed + +- [breaking-change] This crate now requires `arm-none-eabi-gcc` to be installed and available in + `$PATH` when built with the `"inline-asm"` feature disabled (which is disabled by default). + +- [breaking-change] The `register::{apsr,lr,pc}` modules are now behind the `"inline-asm"` feature. + +- [breaking-change] Some variants of the `Exception` enumeration are no longer available on + `thumbv6m-none-eabi`. See API docs for details. + +### Removed + +- [breaking-change] The `exception` module has been removed. A replacement for `Exception::active` + can be found in `SCB::vect_active`. A modified version `exception::Exception` can be found in the + `peripheral::scb` module. ## [v0.4.3] - 2018-01-25 @@ -7,23 +7,16 @@ keywords = ["arm", "cortex-m", "register", "peripheral"] license = "MIT OR Apache-2.0" name = "cortex-m" repository = "https://github.com/japaric/cortex-m" -version = "0.4.4" +version = "0.5.0" [build-dependencies] cc = "1.0.10" [dependencies] +aligned = "0.2.0" +bare-metal = "0.2.0" volatile-register = "0.2.0" -[dependencies.aligned] -default-features = false -version = "0.1.2" - -[dependencies.bare-metal] -default-features = false -version = "0.1.2" - [features] cm7-r0p1 = [] -default = ["inline-asm"] inline-asm = [] @@ -1,4 +1,3 @@ .global __nop __nop: - nop bx lr diff --git a/ci/script.sh b/ci/script.sh index 0cf0da0..e017b54 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -1,15 +1,25 @@ set -euxo pipefail main() { + cargo check --target $TARGET + + if [ $TRAVIS_RUST_VERSION = nightly ]; then + cargo check --target $TARGET --features inline-asm + fi + case $TARGET in thumbv7em-none-eabi*) cargo check --target $TARGET --features cm7-r0p1 - cargo check --target $TARGET + + if [ $TRAVIS_RUST_VERSION = nightly ]; then + cargo check --target $TARGET --features 'cm7-r0p1 inline-asm' + fi ;; + thumbv*-none-eabi*) - cargo check --target $TARGET ;; - *) + + x86_64-unknown-linux-gnu) cargo test --target $TARGET ;; esac 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!(), |