diff --git a/.travis.yml b/.travis.yml index fbdc1dc3..1e00ce60 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 0711395f..28cb7e4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,47 @@ 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] 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` to `RW` 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 2582ae52..8aec3008 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 00000000..573bd9c5 --- /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 00000000..0ac3a5e6 --- /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 00000000..9f727ab1 --- /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 00000000..5ac0209a --- /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 00000000..b1f8709c --- /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 00000000..3d9d347f --- /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 00000000..81c35e67 --- /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 00000000..ae4701df --- /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 00000000..cba3a391 --- /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 00000000..9fd38ddd --- /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 00000000..a5f1da15 --- /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 00000000..5f08370d --- /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 00000000..a007a79e --- /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 00000000..b31a7152 --- /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 00000000..c589c0ee --- /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 00000000..be355296 --- /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 00000000..a3ff7094 --- /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 00000000..1c5ff81e --- /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 00000000..8ad1559a --- /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 00000000..2fa80a06 --- /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 00000000..8a30570c --- /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 00000000..2f31cf66 --- /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 4d5a706b..4866ed2a 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 0cf0da02..e017b54b 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 9a2d4817..6e90f095 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 b40cf1b5..00000000 --- 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 { - // 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 5880dd4a..b57cc809 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 02ada539..0e32e3cf 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 6af60d7b..96403635 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,31 +5,50 @@ //! - 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 +// 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; -pub use untagged_option::UntaggedOption; diff --git a/src/macros.rs b/src/macros.rs index 7d2cf6aa..e41cdc5e 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 94a2c202..e1d7637d 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,29 +12,55 @@ use peripheral::CPUID; pub struct RegisterBlock { /// CPUID base pub base: RO, - reserved0: [u32; 15], - /// Processor Feature + + _reserved0: [u32; 15], + + /// Processor Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub pfr: [RO; 2], - /// Debug Feature + #[cfg(armv6m)] + _reserved1: [u32; 2], + + /// Debug Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub dfr: RO, - /// Auxiliary Feature + #[cfg(armv6m)] + _reserved2: u32, + + /// Auxiliary Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub afr: RO, - /// Memory Model Feature + #[cfg(armv6m)] + _reserved3: u32, + + /// Memory Model Feature (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub mmfr: [RO; 4], - /// Instruction Set Attribute + #[cfg(armv6m)] + _reserved4: [u32; 4], + + /// Instruction Set Attribute (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub isar: [RO; 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, - /// Cache Type - #[cfg(any(armv7m, target_arch = "x86_64"))] + + /// Cache Type (only present on Cortex-M7) + #[cfg(not(armv6m))] pub ctr: RO, - /// Cache Size ID - #[cfg(any(armv7m, target_arch = "x86_64"))] + + /// Cache Size ID (only present on Cortex-M7) + #[cfg(not(armv6m))] pub ccsidr: RO, - /// Cache Size Selection - #[cfg(any(armv7m, target_arch = "x86_64"))] + + /// Cache Size Selection (only present on Cortex-M7) + #[cfg(not(armv6m))] pub csselr: RW, } @@ -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 44621363..d46622d5 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -84,6 +84,7 @@ use core::ops; use interrupt; +// NOTE(target_arch) is for documentation purposes #[cfg(any(armv7m, target_arch = "x86_64"))] pub mod cbp; pub mod cpuid; @@ -93,7 +94,6 @@ pub mod dwt; pub mod fpb; #[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"))] pub mod itm; pub mod mpu; diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs index ecfdd7e8..1a6a0271 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; 16], - reserved0: [u32; 16], + + _reserved0: [u32; 16], + /// Interrupt Clear-Enable pub icer: [RW; 16], - reserved1: [u32; 16], + + _reserved1: [u32; 16], + /// Interrupt Set-Pending pub ispr: [RW; 16], - reserved2: [u32; 16], + + _reserved2: [u32; 16], + /// Interrupt Clear-Pending pub icpr: [RW; 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; 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(interrupt: I) -> bool where I: Nr, diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 41f38253..0a3a66a1 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"))] 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; +use super::SCB; /// Register block #[repr(C)] pub struct RegisterBlock { /// Interrupt Control and State pub icsr: RW, - /// Vector Table Offset + + /// Vector Table Offset (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub vtor: RW, + #[cfg(armv6m)] + _reserved0: u32, + /// Application Interrupt and Reset Control pub aircr: RW, + /// System Control pub scr: RW, + /// Configuration and Control pub ccr: RW, - /// 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; 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; 2], + /// System Handler Control and State - pub shpcrs: RW, - /// Configurable Fault Status + pub shcrs: RW, + + /// Configurable Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub cfsr: RW, - /// HardFault Status + #[cfg(armv6m)] + _reserved2: u32, + + /// HardFault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub hfsr: RW, - /// Debug Fault Status + #[cfg(armv6m)] + _reserved3: u32, + + /// Debug Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub dfsr: RW, - /// MemManage Fault Address - pub mmar: RW, - /// BusFault Address + #[cfg(armv6m)] + _reserved4: u32, + + /// MemManage Fault Address (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] + pub mmfar: RW, + #[cfg(armv6m)] + _reserved5: u32, + + /// BusFault Address (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub bfar: RW, - /// Auxiliary Fault Status + #[cfg(armv6m)] + _reserved6: u32, + + /// Auxiliary Fault Status (not present on Cortex-M0 variants) + #[cfg(not(armv6m))] pub afsr: RW, - 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, + #[cfg(armv6m)] + _reserved9: u32, } /// FPU access mode @@ -108,6 +163,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 { + 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 ddffcde9..ecefaeae 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 39f7de5a..cc3e292d 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 60dd3646..1312598d 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 c9be9d3f..6604ea0a 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 c386e869..edcd11dd 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 93c497fc..b6b66766 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 3e0980ef..9cd1892f 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 ddbc07de..a17f7ac8 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 17f6fdad..1444aff6 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 3b83353c..082a7fc1 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 7a7ef19a..37176e87 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 c9dc39a6..cb8faf9c 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 d7232db7..b6618b0c 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!(), } }