aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2018-05-11 17:04:05 +0200
committerGravatar Jorge Aparicio <jorge@japaric.io> 2018-05-11 17:09:36 +0200
commit93abfac2a7e092d739e3e9b61bcd4f8614541428 (patch)
tree716486743e0fb0de56b5a9ed05e2af57e80a627d
parentb098b6af6aa48826aa1471ba3359a42d6d3e059a (diff)
downloadcortex-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.yml19
-rw-r--r--CHANGELOG.md24
-rw-r--r--Cargo.toml13
-rw-r--r--asm/nop.s1
-rw-r--r--ci/script.sh16
-rw-r--r--src/exception.rs72
-rw-r--r--src/lib.rs35
-rw-r--r--src/macros.rs11
-rw-r--r--src/peripheral/nvic.rs2
-rw-r--r--src/peripheral/scb.rs143
-rw-r--r--src/peripheral/syst.rs5
-rw-r--r--src/register/apsr.rs2
-rw-r--r--src/register/basepri.rs2
-rw-r--r--src/register/lr.rs4
-rw-r--r--src/register/mod.rs6
-rw-r--r--src/register/pc.rs4
-rw-r--r--src/register/psp.rs2
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
diff --git a/Cargo.toml b/Cargo.toml
index 4d93dbb..8aec300 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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 = []
diff --git a/asm/nop.s b/asm/nop.s
index 2fd1bf6..be35529 100644
--- a/asm/nop.s
+++ b/asm/nop.s
@@ -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,
-}
diff --git a/src/lib.rs b/src/lib.rs
index 407c5ac..9640363 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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!(),