aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml49
-rw-r--r--CHANGELOG.md45
-rw-r--r--Cargo.toml11
-rw-r--r--asm/basepri_max-cm7-r0p1.s11
-rw-r--r--asm/basepri_max.s4
-rw-r--r--asm/basepri_r.s4
-rw-r--r--asm/basepri_w-cm7-r0p1.s11
-rw-r--r--asm/basepri_w.s4
-rw-r--r--asm/bkpt.s4
-rw-r--r--asm/control.s4
-rw-r--r--asm/cpsid.s4
-rw-r--r--asm/cpsie.s4
-rw-r--r--asm/dmb.s4
-rw-r--r--asm/dsb.s4
-rw-r--r--asm/faultmask.s4
-rw-r--r--asm/isb.s4
-rw-r--r--asm/msp_r.s4
-rw-r--r--asm/msp_w.s4
-rw-r--r--asm/nop.s3
-rw-r--r--asm/primask.s4
-rw-r--r--asm/psp_r.s4
-rw-r--r--asm/psp_w.s4
-rw-r--r--asm/sev.s4
-rw-r--r--asm/wfe.s4
-rw-r--r--asm/wfi.s4
-rw-r--r--build.rs42
-rw-r--r--ci/script.sh16
-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
50 files changed, 946 insertions, 300 deletions
diff --git a/.travis.yml b/.travis.yml
index fbdc1dc..1e00ce6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,15 +3,62 @@ language: rust
matrix:
include:
- env: TARGET=x86_64-unknown-linux-gnu
- rust: nightly
+
+ - env: TARGET=thumbv6m-none-eabi
+ rust: beta
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
+ - env: TARGET=thumbv7m-none-eabi
+ rust: beta
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
+ - env: TARGET=thumbv7em-none-eabi
+ rust: beta
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
+ - env: TARGET=thumbv7em-none-eabihf
+ rust: beta
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
- env: TARGET=thumbv6m-none-eabi
rust: nightly
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
- env: TARGET=thumbv7m-none-eabi
rust: nightly
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
- env: TARGET=thumbv7em-none-eabi
rust: nightly
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
+
- env: TARGET=thumbv7em-none-eabihf
rust: nightly
+ addons:
+ apt:
+ packages:
+ - gcc-arm-none-eabi
before_install: set -e
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0711395..87801ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,50 @@ 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.
+
+- [breaking-change] Several of the variants of the `Exception` enumeration have been renamed to
+ match the CMSIS specification.
+
+- [breaking-change] fixed typo in `shcrs` field of `scb::RegisterBlock`; it was previously named
+ `shpcrs`.
+
+- [breaking-change] removed several fields from `scb::RegisterBlock` on ARMv6-M. These registers are
+ not available on that sub-architecture.
+
+- [breaking-change] changed the type of `scb::RegisterBlock.shpr` from `RW<u8>` to `RW<u32>` on
+ ARMv6-M. These registers are word accessible only on that sub-architecture.
+
+- [breaking-change] renamed the `mmar` field of `scb::RegisterBlock` to `mmfar` to match the CMSIS
+ name.
+
+- [breaking-change] removed the `iabr` field from `scb::RegisterBlock` on ARMv6-M. This register is
+ not available on that sub-architecture.
+
+- [breaking-change] removed several fields from `cpuid::RegisterBlock` on ARMv6-M. These registers
+ are not available on that sub-architecture.
+
+### 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 2582ae5..8aec300 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,13 +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.3"
+version = "0.5.0"
+
+[build-dependencies]
+cc = "1.0.10"
[dependencies]
-aligned = "0.1.1"
-bare-metal = "0.1.0"
+aligned = "0.2.0"
+bare-metal = "0.2.0"
volatile-register = "0.2.0"
-untagged-option = "0.1.1"
[features]
cm7-r0p1 = []
+inline-asm = []
diff --git a/asm/basepri_max-cm7-r0p1.s b/asm/basepri_max-cm7-r0p1.s
new file mode 100644
index 0000000..573bd9c
--- /dev/null
+++ b/asm/basepri_max-cm7-r0p1.s
@@ -0,0 +1,11 @@
+ .global __basepri_max
+ .syntax unified
+__basepri_max:
+ mrs r1, PRIMASK
+ cpsid i
+ tst.w r1, #1
+ msr BASEPRI_MAX, r0
+ it ne
+ bxne lr
+ cpsie i
+ bx lr
diff --git a/asm/basepri_max.s b/asm/basepri_max.s
new file mode 100644
index 0000000..0ac3a5e
--- /dev/null
+++ b/asm/basepri_max.s
@@ -0,0 +1,4 @@
+ .global __basepri_max
+__basepri_max:
+ msr BASEPRI_MAX, r0
+ bx lr
diff --git a/asm/basepri_r.s b/asm/basepri_r.s
new file mode 100644
index 0000000..9f727ab
--- /dev/null
+++ b/asm/basepri_r.s
@@ -0,0 +1,4 @@
+ .global __basepri_r
+__basepri_r:
+ mrs r0, BASEPRI
+ bx lr
diff --git a/asm/basepri_w-cm7-r0p1.s b/asm/basepri_w-cm7-r0p1.s
new file mode 100644
index 0000000..5ac0209
--- /dev/null
+++ b/asm/basepri_w-cm7-r0p1.s
@@ -0,0 +1,11 @@
+ .global __basepri_w
+ .syntax unified
+__basepri_w:
+ mrs r1, PRIMASK
+ cpsid i
+ tst.w r1, #1
+ msr BASEPRI, r0
+ it ne
+ bxne lr
+ cpsie i
+ bx lr
diff --git a/asm/basepri_w.s b/asm/basepri_w.s
new file mode 100644
index 0000000..b1f8709
--- /dev/null
+++ b/asm/basepri_w.s
@@ -0,0 +1,4 @@
+ .global __basepri_w
+__basepri_w:
+ msr BASEPRI, r0
+ bx lr
diff --git a/asm/bkpt.s b/asm/bkpt.s
new file mode 100644
index 0000000..3d9d347
--- /dev/null
+++ b/asm/bkpt.s
@@ -0,0 +1,4 @@
+ .global __bkpt
+__bkpt:
+ bkpt
+ bx lr
diff --git a/asm/control.s b/asm/control.s
new file mode 100644
index 0000000..81c35e6
--- /dev/null
+++ b/asm/control.s
@@ -0,0 +1,4 @@
+ .global __control
+__control:
+ mrs r0, CONTROL
+ bx lr
diff --git a/asm/cpsid.s b/asm/cpsid.s
new file mode 100644
index 0000000..ae4701d
--- /dev/null
+++ b/asm/cpsid.s
@@ -0,0 +1,4 @@
+ .global __cpsid
+__cpsid:
+ cpsid i
+ bx lr
diff --git a/asm/cpsie.s b/asm/cpsie.s
new file mode 100644
index 0000000..cba3a39
--- /dev/null
+++ b/asm/cpsie.s
@@ -0,0 +1,4 @@
+ .global __cpsie
+__cpsie:
+ cpsie i
+ bx lr
diff --git a/asm/dmb.s b/asm/dmb.s
new file mode 100644
index 0000000..9fd38dd
--- /dev/null
+++ b/asm/dmb.s
@@ -0,0 +1,4 @@
+ .global __dmb
+__dmb:
+ dmb 0xF
+ bx lr
diff --git a/asm/dsb.s b/asm/dsb.s
new file mode 100644
index 0000000..a5f1da1
--- /dev/null
+++ b/asm/dsb.s
@@ -0,0 +1,4 @@
+ .global __dsb
+__dsb:
+ dsb 0xF
+ bx lr
diff --git a/asm/faultmask.s b/asm/faultmask.s
new file mode 100644
index 0000000..5f08370
--- /dev/null
+++ b/asm/faultmask.s
@@ -0,0 +1,4 @@
+ .global __faultmask
+__faultmask:
+ mrs r0, FAULTMASK
+ bx lr
diff --git a/asm/isb.s b/asm/isb.s
new file mode 100644
index 0000000..a007a79
--- /dev/null
+++ b/asm/isb.s
@@ -0,0 +1,4 @@
+ .global __isb
+__isb:
+ isb 0xF
+ bx lr
diff --git a/asm/msp_r.s b/asm/msp_r.s
new file mode 100644
index 0000000..b31a715
--- /dev/null
+++ b/asm/msp_r.s
@@ -0,0 +1,4 @@
+ .global __msp_r
+__msp_r:
+ mrs r0, MSP
+ bx lr
diff --git a/asm/msp_w.s b/asm/msp_w.s
new file mode 100644
index 0000000..c589c0e
--- /dev/null
+++ b/asm/msp_w.s
@@ -0,0 +1,4 @@
+ .global __msp_w
+__msp_w:
+ msr MSP, r0
+ bx lr
diff --git a/asm/nop.s b/asm/nop.s
new file mode 100644
index 0000000..be35529
--- /dev/null
+++ b/asm/nop.s
@@ -0,0 +1,3 @@
+ .global __nop
+__nop:
+ bx lr
diff --git a/asm/primask.s b/asm/primask.s
new file mode 100644
index 0000000..a3ff709
--- /dev/null
+++ b/asm/primask.s
@@ -0,0 +1,4 @@
+ .global __primask
+__primask:
+ mrs r0, PRIMASK
+ bx lr
diff --git a/asm/psp_r.s b/asm/psp_r.s
new file mode 100644
index 0000000..1c5ff81
--- /dev/null
+++ b/asm/psp_r.s
@@ -0,0 +1,4 @@
+ .global __psp_r
+__psp_r:
+ mrs r0, PSP
+ bx lr
diff --git a/asm/psp_w.s b/asm/psp_w.s
new file mode 100644
index 0000000..8ad1559
--- /dev/null
+++ b/asm/psp_w.s
@@ -0,0 +1,4 @@
+ .global __psp_w
+__psp_w:
+ msr PSP, r0
+ bx lr
diff --git a/asm/sev.s b/asm/sev.s
new file mode 100644
index 0000000..2fa80a0
--- /dev/null
+++ b/asm/sev.s
@@ -0,0 +1,4 @@
+ .global __sev
+__sev:
+ sev
+ bx lr
diff --git a/asm/wfe.s b/asm/wfe.s
new file mode 100644
index 0000000..8a30570
--- /dev/null
+++ b/asm/wfe.s
@@ -0,0 +1,4 @@
+ .global __wfe
+__wfe:
+ wfe
+ bx lr
diff --git a/asm/wfi.s b/asm/wfi.s
new file mode 100644
index 0000000..2f31cf6
--- /dev/null
+++ b/asm/wfi.s
@@ -0,0 +1,4 @@
+ .global __wfi
+__wfi:
+ wfi
+ bx lr
diff --git a/build.rs b/build.rs
index 4d5a706..4866ed2 100644
--- a/build.rs
+++ b/build.rs
@@ -1,18 +1,58 @@
+extern crate cc;
+
use std::env;
fn main() {
let target = env::var("TARGET").unwrap();
+ if target.starts_with("thumb") && env::var_os("CARGO_FEATURE_INLINE_ASM").is_none() {
+ // NOTE we need to place each routine in a separate assembly file or the linker won't be
+ // able to discard the unused routines
+ let mut build = cc::Build::new();
+ build
+ .file("asm/basepri_r.s")
+ .file("asm/bkpt.s")
+ .file("asm/control.s")
+ .file("asm/cpsid.s")
+ .file("asm/cpsie.s")
+ .file("asm/dmb.s")
+ .file("asm/dsb.s")
+ .file("asm/faultmask.s")
+ .file("asm/isb.s")
+ .file("asm/msp_r.s")
+ .file("asm/msp_w.s")
+ .file("asm/nop.s")
+ .file("asm/primask.s")
+ .file("asm/psp_r.s")
+ .file("asm/psp_w.s")
+ .file("asm/sev.s")
+ .file("asm/wfe.s")
+ .file("asm/wfi.s");
+
+ if env::var_os("CARGO_FEATURE_CM7_R0P1").is_some() {
+ build.file("asm/basepri_max-cm7-r0p1.s");
+ build.file("asm/basepri_w-cm7-r0p1.s");
+ } else {
+ build.file("asm/basepri_max.s");
+ build.file("asm/basepri_w.s");
+ }
+
+ build.compile("asm");
+ }
+
if target.starts_with("thumbv6m-") {
+ println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv6m");
} else if target.starts_with("thumbv7m-") {
+ println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
} else if target.starts_with("thumbv7em-") {
+ println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
//println!("cargo:rustc-cfg=armv7em");
}
- if target.ends_with("eabihf") {
+ if target.ends_with("-eabihf") {
println!("cargo:rustc-cfg=has_fpu");
}
}
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/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!(),
}
}