diff --git a/.github/bors.toml b/.github/bors.toml index ca42be0a..638b8674 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -1,4 +1,8 @@ block_labels = ["needs-decision"] delete_merged_branches = true required_approvals = 1 -status = ["continuous-integration/travis-ci/push"] +status = [ + "ci-linux (stable)", + "ci-linux (1.38.0)", + "clippy", +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..72890855 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: CI + +jobs: + ci-linux: + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || false }} + strategy: + matrix: + # All generated code should be running on stable now + rust: [stable] + + include: + # Test MSRV + - rust: 1.38.0 + + # Test nightly but don't fail + - rust: nightly + experimental: true + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Run tests + run: cargo test --all + +# FIXME: test on macOS and Windows diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 00000000..d55d697f --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,25 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request_target: + +name: Clippy check +jobs: + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + if: github.event_name == 'pull_request_target' + with: + ref: refs/pull/${{ github.event.number }}/head + - uses: actions/checkout@v2 + if: github.event_name != 'pull_request_target' + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 88d68cf1..00000000 --- a/.travis.yml +++ /dev/null @@ -1,96 +0,0 @@ -language: rust - -matrix: - allow_failures: - - rust: nightly - include: - - env: TARGET=x86_64-unknown-linux-gnu - rust: stable - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv6m-none-eabi - rust: stable - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7m-none-eabi - rust: stable - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7em-none-eabi - rust: stable - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7em-none-eabihf - rust: stable - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - # MSRV - - env: TARGET=thumbv6m-none-eabi - rust: 1.36.0 - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - # MSRV - - env: TARGET=thumbv7m-none-eabi - rust: 1.36.0 - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - # MSRV - - env: TARGET=thumbv7em-none-eabi - rust: 1.36.0 - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - # MSRV - - env: TARGET=thumbv7em-none-eabihf - rust: 1.36.0 - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv6m-none-eabi - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7m-none-eabi - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7em-none-eabi - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7em-none-eabihf - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv8m.main-none-eabi - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv8m.base-none-eabi - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - -before_install: set -e - -install: - - bash ci/install.sh - - export PATH="$PATH:$PWD/gcc/bin" - -script: - - bash ci/script.sh - -after_script: set +e - -cache: cargo - -before_cache: - - chmod -R a+r $HOME/.cargo; - -branches: - only: - - master - - staging - - trying - - v0.6.x - -notifications: - email: - on_success: never diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc0ce29..efa69055 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.6.5] - 2021-01-13 + +### Changed + +- This release is forwards-compatible with cortex-m 0.7, and depends on and + re-exports many types from that version. Both 0.6.5 and 0.7 may co-exist + in a build. + ## [v0.6.4] - 2020-10-26 ### Changed diff --git a/Cargo.toml b/Cargo.toml index f9d44736..e48dbd79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,17 +11,17 @@ license = "MIT OR Apache-2.0" name = "cortex-m" readme = "README.md" repository = "https://github.com/rust-embedded/cortex-m" -version = "0.6.4" +version = "0.6.5-alpha" edition = "2018" -links = "cortex-m" # prevent multiple versions of this crate to be linked together [dependencies] aligned = "0.3.1" bare-metal = { version = "0.2.0", features = ["const-fn"] } volatile-register = "0.2.0" bitfield = "0.13.2" +cortex_m_0_7 = { package = "cortex-m", version = "0.7.0" } [features] const-fn = [] -cm7-r0p1 = [] -inline-asm = [] +cm7-r0p1 = ["cortex_m_0_7/cm7-r0p1"] +inline-asm = ["cortex_m_0_7/inline-asm"] diff --git a/build.rs b/build.rs index d53dea5c..db281fa1 100644 --- a/build.rs +++ b/build.rs @@ -1,20 +1,7 @@ -use std::path::PathBuf; -use std::{env, fs}; +use std::env; fn main() { let target = env::var("TARGET").unwrap(); - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let name = env::var("CARGO_PKG_NAME").unwrap(); - - if target.starts_with("thumb") { - fs::copy( - format!("bin/{}.a", target), - out_dir.join(format!("lib{}.a", name)), - ).unwrap(); - - println!("cargo:rustc-link-lib=static={}", name); - println!("cargo:rustc-link-search={}", out_dir.display()); - } if target.starts_with("thumbv6m-") { println!("cargo:rustc-cfg=cortex_m"); diff --git a/src/asm.rs b/src/asm.rs deleted file mode 100644 index d9e54b5d..00000000 --- a/src/asm.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Miscellaneous assembly instructions - -/// 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. -#[inline(always)] -pub fn bkpt() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("bkpt" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __bkpt(); - } - - __bkpt(); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Blocks the program for *at least* `n` instruction cycles -/// -/// This is implemented in assembly so its execution time is the same regardless of the optimization -/// level. -/// -/// NOTE that the delay can take much longer if interrupts are serviced during its execution. -#[inline] -pub fn delay(_n: u32) { - // NOTE(divide by 4) is easier to compute than `/ 3` is it's just a shift (`>> 2`). - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("1: - nop - subs $0, #1 - bne.n 1b" - : "+r"(_n / 4 + 1) - : - : "cpsr" - : "volatile"); - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __delay(n: u32); - } - - __delay(_n / 4 + 1); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// A no-operation. Useful to prevent delay loops from being optimized away. -#[inline] -pub fn nop() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("nop" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __nop(); - } - - __nop() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Generate an Undefined Instruction exception. -/// -/// Can be used as a stable alternative to `core::intrinsics::abort`. -#[inline] -pub fn udf() -> ! { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("udf" :::: "volatile"); - core::hint::unreachable_unchecked(); - }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __udf(); - } - - __udf(); - - core::hint::unreachable_unchecked(); - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Wait For Event -#[inline] -pub fn wfe() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("wfe" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __wfe(); - } - - __wfe() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Wait For Interrupt -#[inline] -pub fn wfi() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("wfi" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __wfi(); - } - - __wfi() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Send Event -#[inline] -pub fn sev() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_asm!("sev" :::: "volatile") }, - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __sev(); - } - - __sev() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Instruction Synchronization Barrier -/// -/// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched -/// from cache or memory, after the instruction has been completed. -#[inline] -pub fn isb() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_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: -/// -/// * 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(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_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!(), - } -} - -/// Data Memory Barrier -/// -/// Ensures that all explicit memory accesses that appear in program order before the `DMB` -/// instruction are observed before any explicit memory accesses that appear in program order -/// after the `DMB` instruction. -#[inline] -pub fn dmb() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { llvm_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!(), - } -} - -/// Test Target -/// -/// Queries the Security state and access permissions of a memory location. -/// Returns a Test Target Response Payload (cf section D1.2.215 of -/// Armv8-M Architecture Reference Manual). -#[inline] -#[cfg(armv8m)] -// The __tt function does not dereference the pointer received. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn tt(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("tt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __tt(_: *mut u32) -> u32; - } - - __tt(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Test Target Unprivileged -/// -/// Queries the Security state and access permissions of a memory location for an unprivileged -/// access to that location. -/// Returns a Test Target Response Payload (cf section D1.2.215 of -/// Armv8-M Architecture Reference Manual). -#[inline] -#[cfg(armv8m)] -// The __ttt function does not dereference the pointer received. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn ttt(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("ttt $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __ttt(_: *mut u32) -> u32; - } - - __ttt(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Test Target Alternate Domain -/// -/// Queries the Security state and access permissions of a memory location for a Non-Secure access -/// to that location. This instruction is only valid when executing in Secure state and is -/// undefined if used from Non-Secure state. -/// Returns a Test Target Response Payload (cf section D1.2.215 of -/// Armv8-M Architecture Reference Manual). -#[inline] -#[cfg(armv8m)] -// The __tta function does not dereference the pointer received. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn tta(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("tta $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __tta(_: *mut u32) -> u32; - } - - __tta(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Test Target Alternate Domain Unprivileged -/// -/// Queries the Security state and access permissions of a memory location for a Non-Secure and -/// unprivileged access to that location. This instruction is only valid when executing in Secure -/// state and is undefined if used from Non-Secure state. -/// Returns a Test Target Response Payload (cf section D1.2.215 of -/// Armv8-M Architecture Reference Manual). -#[inline] -#[cfg(armv8m)] -// The __ttat function does not dereference the pointer received. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn ttat(addr: *mut u32) -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let tt_resp: u32; - unsafe { - llvm_asm!("ttat $0, $1" : "=r"(tt_resp) : "r"(addr) :: "volatile"); - } - tt_resp - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __ttat(_: *mut u32) -> u32; - } - - __ttat(addr) - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} diff --git a/src/cmse.rs b/src/cmse.rs deleted file mode 100644 index 393e4638..00000000 --- a/src/cmse.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! Cortex-M Security Extensions -//! -//! This module provides several helper functions to support Armv8-M and Armv8.1-M Security -//! Extensions. -//! Most of this implementation is directly inspired by the "Armv8-M Security Extensions: -//! Requirements on Development Tools" document available here: -//! https://developer.arm.com/docs/ecm0359818/latest -//! -//! Please note that the TT instructions support as described part 4 of the document linked above is -//! not part of CMSE but is still present in this module. The TT instructions return the -//! configuration of the Memory Protection Unit at an address. -//! -//! # Notes -//! -//! * Non-Secure Unprivileged code will always read zeroes from TestTarget and should not use it. -//! * Non-Secure Privileged code can check current (AccessType::Current) and Non-Secure Unprivileged -//! accesses (AccessType::Unprivileged). -//! * Secure Unprivileged code can check Non-Secure Unprivileged accesses (AccessType::NonSecure). -//! * Secure Privileged code can check all access types. -//! -//! # Example -//! -//! ``` -//! use cortex_m::cmse::{TestTarget, AccessType}; -//! -//! // suspect_address was given by Non-Secure to a Secure function to write at it. -//! // But is it allowed to? -//! let suspect_address_test = TestTarget::check(0xDEADBEEF as *mut u32, -//! AccessType::NonSecureUnprivileged); -//! if suspect_address_test.ns_read_and_writable() { -//! // Non-Secure can not read or write this address! -//! } -//! ``` - -use crate::asm::{tt, tta, ttat, ttt}; -use bitfield::bitfield; - -/// Memory access behaviour: determine which privilege execution mode is used and which Memory -/// Protection Unit (MPU) is used. -#[allow(clippy::missing_inline_in_public_items)] -#[derive(PartialEq, Copy, Clone, Debug)] -pub enum AccessType { - /// Access using current privilege level and reading from current security state MPU. - /// Uses the TT instruction. - Current, - /// Unprivileged access reading from current security state MPU. Uses the TTT instruction. - Unprivileged, - /// Access using current privilege level reading from Non-Secure MPU. Uses the TTA instruction. - /// Undefined if used from Non-Secure state. - NonSecure, - /// Unprivilege access reading from Non-Secure MPU. Uses the TTAT instruction. - /// Undefined if used from Non-Secure state. - NonSecureUnprivileged, -} - -/// Abstraction of TT instructions and helper functions to determine the security and privilege -/// attribute of a target address, accessed in different ways. -#[allow(clippy::missing_inline_in_public_items)] -#[derive(PartialEq, Copy, Clone, Debug)] -pub struct TestTarget { - tt_resp: TtResp, - access_type: AccessType, -} - -bitfield! { - /// Test Target Response Payload - /// - /// Provides the response payload from a TT, TTA, TTT or TTAT instruction. - #[derive(PartialEq, Copy, Clone)] - struct TtResp(u32); - impl Debug; - mregion, _: 7, 0; - sregion, _: 15, 8; - mrvalid, _: 16; - srvalid, _: 17; - r, _: 18; - rw, _: 19; - nsr, _: 20; - nsrw, _: 21; - s, _: 22; - irvalid, _: 23; - iregion, _: 31, 24; -} - -impl TestTarget { - /// Creates a Test Target Response Payload by testing addr using access_type. - #[inline] - pub fn check(addr: *mut u32, access_type: AccessType) -> Self { - let tt_resp = match access_type { - AccessType::Current => TtResp(tt(addr)), - AccessType::Unprivileged => TtResp(ttt(addr)), - AccessType::NonSecure => TtResp(tta(addr)), - AccessType::NonSecureUnprivileged => TtResp(ttat(addr)), - }; - - TestTarget { - tt_resp, - access_type, - } - } - - /// Creates a Test Target Response Payload by testing the zone from addr to addr + size - 1 - /// using access_type. - /// Returns None if: - /// * the address zone overlaps SAU, IDAU or MPU region boundaries - /// * size is 0 - /// * addr + size - 1 overflows - #[inline] - pub fn check_range(addr: *mut u32, size: usize, access_type: AccessType) -> Option { - let begin: usize = addr as usize; - // Last address of the range (addr + size - 1). This also checks if size is 0. - let end: usize = begin.checked_add(size.checked_sub(1)?)?; - - // Regions are aligned at 32-byte boundaries. If the address range fits in one 32-byte - // address line, a single TT instruction suffices. This is the case when the following - // constraint holds. - let single_check: bool = (begin % 32).checked_add(size)? <= 32usize; - - let test_start = TestTarget::check(addr, access_type); - - if single_check { - Some(test_start) - } else { - let test_end = TestTarget::check(end as *mut u32, access_type); - // Check that the range does not cross SAU, IDAU or MPU region boundaries. - if test_start != test_end { - None - } else { - Some(test_start) - } - } - } - - /// Access type that was used for this test target. - #[inline] - pub fn access_type(self) -> AccessType { - self.access_type - } - - /// Get the raw u32 value returned by the TT instruction used. - #[inline] - pub fn as_u32(self) -> u32 { - self.tt_resp.0 - } - - /// Read accessibility of the target address. Only returns the MPU settings without checking - /// the Security state of the target. - /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for - /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. - /// Returns false if the TT instruction was executed from an unprivileged mode - /// and the NonSecure access type was not specified. - /// Returns false if the address matches multiple MPU regions. - #[inline] - pub fn readable(self) -> bool { - self.tt_resp.r() - } - - /// Read and write accessibility of the target address. Only returns the MPU settings without - /// checking the Security state of the target. - /// For Unprivileged and NonSecureUnprivileged access types, returns the permissions for - /// unprivileged access, regardless of whether the current mode is privileged or unprivileged. - /// Returns false if the TT instruction was executed from an unprivileged mode - /// and the NonSecure access type was not specified. - /// Returns false if the address matches multiple MPU regions. - #[inline] - pub fn read_and_writable(self) -> bool { - self.tt_resp.rw() - } - - /// Indicate the MPU region number containing the target address. - /// Returns None if the value is not valid: - /// * the MPU is not implemented or MPU_CTRL.ENABLE is set to zero - /// * the register argument specified by the MREGION field does not match any enabled MPU regions - /// * the address matched multiple MPU regions - /// * the address specified by the SREGION field is exempt from the secure memory attribution - /// * the TT instruction was executed from an unprivileged mode and the A flag was not specified. - #[inline] - pub fn mpu_region(self) -> Option { - if self.tt_resp.srvalid() { - // Cast is safe as SREGION field is defined on 8 bits. - Some(self.tt_resp.sregion() as u8) - } else { - None - } - } - - /// Indicates the Security attribute of the target address. Independent of AccessType. - /// Always zero when the test target is done in the Non-Secure state. - #[inline] - pub fn secure(self) -> bool { - self.tt_resp.s() - } - - /// Non-Secure Read accessibility of the target address. - /// Same as readable() && !secure() - #[inline] - pub fn ns_readable(self) -> bool { - self.tt_resp.nsr() - } - - /// Non-Secure Read and Write accessibility of the target address. - /// Same as read_and_writable() && !secure() - #[inline] - pub fn ns_read_and_writable(self) -> bool { - self.tt_resp.nsrw() - } - - /// Indicate the IDAU region number containing the target address. Independent of AccessType. - /// Returns None if the value is not valid: - /// * the IDAU cannot provide a region number - /// * the address is exempt from security attribution - /// * the test target is done from Non-Secure state - #[inline] - pub fn idau_region(self) -> Option { - if self.tt_resp.irvalid() { - // Cast is safe as IREGION field is defined on 8 bits. - Some(self.tt_resp.iregion() as u8) - } else { - None - } - } - - /// Indicate the SAU region number containing the target address. Independent of AccessType. - /// Returns None if the value is not valid: - /// * SAU_CTRL.ENABLE is set to zero - /// * the register argument specified in the SREGION field does not match any enabled SAU regions - /// * the address specified matches multiple enabled SAU regions - /// * the address specified by the SREGION field is exempt from the secure memory attribution - /// * the TT instruction was executed from the Non-secure state or the Security Extension is not - /// implemented - #[inline] - pub fn sau_region(self) -> Option { - if self.tt_resp.srvalid() { - // Cast is safe as SREGION field is defined on 8 bits. - Some(self.tt_resp.sregion() as u8) - } else { - None - } - } -} diff --git a/src/interrupt.rs b/src/interrupt.rs deleted file mode 100644 index 4d5ef0f2..00000000 --- a/src/interrupt.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Interrupts - -// use core::sync::atomic::{self, Ordering}; - -pub use bare_metal::{CriticalSection, Mutex, Nr}; - -/// Disables all interrupts -#[inline] -pub fn disable() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => unsafe { - llvm_asm!("cpsid i" ::: "memory" : "volatile"); - }, - - #[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!(), - } -} - -/// Enables all the interrupts -/// -/// # Safety -/// -/// - Do not call this function inside an `interrupt::free` critical section -#[inline] -pub unsafe fn enable() { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("cpsie i" ::: "memory" : "volatile"), - - #[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!(), - } -} - -/// Execute closure `f` in an interrupt-free context. -/// -/// This as also known as a "critical section". -#[inline] -pub fn free(f: F) -> R -where - F: FnOnce(&CriticalSection) -> R, -{ - let primask = crate::register::primask::read(); - - // disable interrupts - disable(); - - let r = f(unsafe { &CriticalSection::new() }); - - // If the interrupts were active before our `disable` call, then re-enable - // them. Otherwise, keep them disabled - if primask.is_active() { - unsafe { enable() } - } - - r -} diff --git a/src/itm.rs b/src/itm.rs index 6d75d006..58309ef7 100644 --- a/src/itm.rs +++ b/src/itm.rs @@ -6,7 +6,10 @@ use core::{fmt, mem, ptr, slice}; use aligned::{Aligned, A4}; +#[cfg(thumbv8m_base)] use crate::peripheral::itm::Stim; +#[cfg(not(thumbv8m_base))] +use cortex_m_0_7::peripheral::itm::Stim; // NOTE assumes that `bytes` is 32-bit aligned #[allow(clippy::missing_inline_in_public_items)] diff --git a/src/lib.rs b/src/lib.rs index eed126b6..b17a4455 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,16 +52,19 @@ extern crate aligned; extern crate bare_metal; extern crate volatile_register; +extern crate cortex_m_0_7; #[macro_use] mod macros; -pub mod asm; +pub use cortex_m_0_7::{asm, interrupt}; + #[cfg(armv8m)] -pub mod cmse; -pub mod interrupt; +pub use cortex_m_0_7::cmse; + #[cfg(not(armv6m))] pub mod itm; + pub mod peripheral; pub mod register; diff --git a/src/peripheral/cbp.rs b/src/peripheral/cbp.rs index 8d82e2a7..5b7c3ed9 100644 --- a/src/peripheral/cbp.rs +++ b/src/peripheral/cbp.rs @@ -2,35 +2,9 @@ //! //! *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`) -use volatile_register::WO; - use crate::peripheral::CBP; -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// I-cache invalidate all to PoU - pub iciallu: WO, - reserved0: u32, - /// I-cache invalidate by MVA to PoU - pub icimvau: WO, - /// D-cache invalidate by MVA to PoC - pub dcimvac: WO, - /// D-cache invalidate by set-way - pub dcisw: WO, - /// D-cache clean by MVA to PoU - pub dccmvau: WO, - /// D-cache clean by MVA to PoC - pub dccmvac: WO, - /// D-cache clean by set-way - pub dccsw: WO, - /// D-cache clean and invalidate by MVA to PoC - pub dccimvac: WO, - /// D-cache clean and invalidate by set-way - pub dccisw: WO, - /// Branch predictor invalidate all - pub bpiall: WO, -} +pub use cortex_m_0_7::peripheral::cbp::RegisterBlock; const CBP_SW_WAY_POS: u32 = 30; const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs deleted file mode 100644 index 787be5c6..00000000 --- a/src/peripheral/cpuid.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! CPUID - -use volatile_register::RO; -#[cfg(not(armv6m))] -use volatile_register::RW; - -#[cfg(not(armv6m))] -use crate::peripheral::CPUID; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// CPUID base - pub base: RO, - - _reserved0: [u32; 15], - - /// Processor Feature (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub pfr: [RO; 2], - #[cfg(armv6m)] - _reserved1: [u32; 2], - - /// Debug Feature (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub dfr: RO, - #[cfg(armv6m)] - _reserved2: u32, - - /// Auxiliary Feature (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub afr: RO, - #[cfg(armv6m)] - _reserved3: u32, - - /// Memory Model Feature (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub mmfr: [RO; 4], - #[cfg(armv6m)] - _reserved4: [u32; 4], - - /// Instruction Set Attribute (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub isar: [RO; 5], - #[cfg(armv6m)] - _reserved5: [u32; 5], - - _reserved6: u32, - - /// Cache Level ID (only present on Cortex-M7) - #[cfg(not(armv6m))] - pub clidr: RO, - - /// Cache Type (only present on Cortex-M7) - #[cfg(not(armv6m))] - pub ctr: RO, - - /// Cache Size ID (only present on Cortex-M7) - #[cfg(not(armv6m))] - pub ccsidr: RO, - - /// Cache Size Selection (only present on Cortex-M7) - #[cfg(not(armv6m))] - pub csselr: RW, -} - -/// Type of cache to select on CSSELR writes. -#[cfg(not(armv6m))] -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CsselrCacheType { - /// Select DCache or unified cache - DataOrUnified = 0, - /// Select ICache - Instruction = 1, -} - -#[cfg(not(armv6m))] -impl CPUID { - /// Selects the current CCSIDR - /// - /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 - /// * `ind`: select instruction cache or data/unified cache - /// - /// `level` is masked to be between 0 and 7. - #[inline] - pub fn select_cache(&mut self, level: u8, ind: CsselrCacheType) { - const CSSELR_IND_POS: u32 = 0; - const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; - const CSSELR_LEVEL_POS: u32 = 1; - const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; - - unsafe { - self.csselr.write( - ((u32::from(level) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) - | (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK), - ) - } - } - - /// Returns the number of sets and ways in the selected cache - #[inline] - pub fn cache_num_sets_ways(&mut self, level: u8, ind: CsselrCacheType) -> (u16, u16) { - const CCSIDR_NUMSETS_POS: u32 = 13; - const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; - const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; - const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; - - self.select_cache(level, ind); - crate::asm::dsb(); - let ccsidr = self.ccsidr.read(); - ( - (1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS)) as u16, - (1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) as u16, - ) - } -} diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs deleted file mode 100644 index 45bd5d22..00000000 --- a/src/peripheral/dcb.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Debug Control Block - -use volatile_register::{RW, WO}; - -use core::ptr; -use crate::peripheral::DCB; - -const DCB_DEMCR_TRCENA: u32 = 1 << 24; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Debug Halting Control and Status - pub dhcsr: RW, - /// Debug Core Register Selector - pub dcrsr: WO, - /// Debug Core Register Data - pub dcrdr: RW, - /// Debug Exception and Monitor Control - pub demcr: RW, -} - -impl DCB { - /// Enables TRACE. This is for example required by the - /// `peripheral::DWT` cycle counter to work properly. - /// As by STM documentation, this flag is not reset on - /// soft-reset, only on power reset. - #[inline] - pub fn enable_trace(&mut self) { - // set bit 24 / TRCENA - unsafe { - self.demcr.modify(|w| w | DCB_DEMCR_TRCENA); - } - } - - /// Disables TRACE. See `DCB::enable_trace()` for more details - #[inline] - pub fn disable_trace(&mut self) { - // unset bit 24 / TRCENA - unsafe { - self.demcr.modify(|w| w & !DCB_DEMCR_TRCENA); - } - } - - /// Is there a debugger attached? (see note) - /// - /// Note: This function is [reported not to - /// work](http://web.archive.org/web/20180821191012/https://community.nxp.com/thread/424925#comment-782843) - /// on Cortex-M0 devices. Per the ARM v6-M Architecture Reference Manual, "Access to the DHCSR - /// from software running on the processor is IMPLEMENTATION DEFINED". Indeed, from the - /// [Cortex-M0+ r0p1 Technical Reference Manual](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0484c/BABJHEIG.html), "Note Software cannot access the debug registers." - #[inline] - pub fn is_debugger_attached() -> bool { - unsafe { - // do an 8-bit read of the 32-bit DHCSR register, and get the LSB - let value = ptr::read_volatile(Self::ptr() as *const u8); - value & 0x1 == 1 - } - } -} diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs deleted file mode 100644 index 043223a7..00000000 --- a/src/peripheral/dwt.rs +++ /dev/null @@ -1,90 +0,0 @@ -//! Data Watchpoint and Trace unit - -#[cfg(not(armv6m))] -use volatile_register::WO; -use volatile_register::{RO, RW}; - -use crate::peripheral::DWT; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Control - pub ctrl: RW, - /// Cycle Count - #[cfg(not(armv6m))] - pub cyccnt: RW, - /// CPI Count - #[cfg(not(armv6m))] - pub cpicnt: RW, - /// Exception Overhead Count - #[cfg(not(armv6m))] - pub exccnt: RW, - /// Sleep Count - #[cfg(not(armv6m))] - pub sleepcnt: RW, - /// LSU Count - #[cfg(not(armv6m))] - pub lsucnt: RW, - /// Folded-instruction Count - #[cfg(not(armv6m))] - pub foldcnt: RW, - /// Cortex-M0(+) does not have these parts - #[cfg(armv6m)] - reserved: [u32; 6], - /// Program Counter Sample - pub pcsr: RO, - /// Comparators - #[cfg(armv6m)] - pub c: [Comparator; 2], - #[cfg(not(armv6m))] - /// Comparators - pub c: [Comparator; 16], - #[cfg(not(armv6m))] - reserved: [u32; 932], - /// Lock Access - #[cfg(not(armv6m))] - pub lar: WO, - /// Lock Status - #[cfg(not(armv6m))] - pub lsr: RO, -} - -/// Comparator -#[repr(C)] -pub struct Comparator { - /// Comparator - pub comp: RW, - /// Comparator Mask - pub mask: RW, - /// Comparator Function - pub function: RW, - reserved: u32, -} - -impl DWT { - /// Enables the cycle counter - #[cfg(not(armv6m))] - #[inline] - pub fn enable_cycle_counter(&mut self) { - unsafe { self.ctrl.modify(|r| r | 1) } - } - - /// Returns the current clock cycle count - #[cfg(not(armv6m))] - #[inline] - pub fn get_cycle_count() -> u32 { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).cyccnt.read() } - } - - /// Removes the software lock on the DWT - /// - /// Some devices, like the STM32F7, software lock the DWT after a power cycle. - #[cfg(not(armv6m))] - #[inline] - pub fn unlock() { - // NOTE(unsafe) atomic write to a stateless, write-only register - unsafe { (*Self::ptr()).lar.write(0xC5AC_CE55) } - } -} diff --git a/src/peripheral/fpb.rs b/src/peripheral/fpb.rs deleted file mode 100644 index 215d4ff9..00000000 --- a/src/peripheral/fpb.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Flash Patch and Breakpoint unit -//! -//! *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`) - -use volatile_register::{RO, RW, WO}; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Control - pub ctrl: RW, - /// Remap - pub remap: RW, - /// Comparator - pub comp: [RW; 127], - reserved: [u32; 875], - /// Lock Access - pub lar: WO, - /// Lock Status - pub lsr: RO, -} diff --git a/src/peripheral/fpu.rs b/src/peripheral/fpu.rs deleted file mode 100644 index c4e8a1d2..00000000 --- a/src/peripheral/fpu.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Floating Point Unit -//! -//! *NOTE* Available only on ARMv7E-M (`thumbv7em-none-eabihf`) - -use volatile_register::{RO, RW}; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - reserved: u32, - /// Floating Point Context Control - pub fpccr: RW, - /// Floating Point Context Address - pub fpcar: RW, - /// Floating Point Default Status Control - pub fpdscr: RW, - /// Media and FP Feature - pub mvfr: [RO; 3], -} diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 84f6b384..152eb49d 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -78,22 +78,17 @@ use crate::interrupt; #[cfg(not(armv6m))] pub mod cbp; -pub mod cpuid; -pub mod dcb; -pub mod dwt; -#[cfg(not(armv6m))] -pub mod fpb; -// NOTE(target_arch) is for documentation purposes -#[cfg(any(has_fpu, target_arch = "x86_64"))] -pub mod fpu; -#[cfg(not(armv6m))] +#[cfg(armv8m_base)] pub mod itm; pub mod mpu; pub mod nvic; pub mod scb; -pub mod syst; + +pub use cortex_m_0_7::peripheral::{cpuid, dcb, dwt, syst}; #[cfg(not(armv6m))] -pub mod tpiu; +pub use cortex_m_0_7::peripheral::{fpb, tpiu}; +#[cfg(any(has_fpu, target_arch="x86_64"))] +pub use cortex_m_0_7::peripheral::fpu; #[cfg(test)] mod test; @@ -140,70 +135,31 @@ pub struct Peripherals { pub TPIU: TPIU, } -// NOTE `no_mangle` is used here to prevent linking different minor versions of this crate as that -// would let you `take` the core peripherals more than once (one per minor version) -#[no_mangle] -static CORE_PERIPHERALS: () = (); - -/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton. -static mut TAKEN: bool = false; +// NOTE: CORE_PERIPHERALS removed because this crate deliberately allows linking to other cortex-m +// versions by proxying calls to take() and steal() through cortex-m 0.7. +// Since TAKEN is no longer no_mangle nor public we can't set it ourselves. impl Peripherals { /// Returns all the core peripherals *once* #[inline] pub fn take() -> Option { - interrupt::free(|_| { - if unsafe { TAKEN } { - None - } else { - Some(unsafe { Peripherals::steal() }) - } + interrupt::free(|_| match cortex_m_0_7::peripheral::Peripherals::take() { + Some(_) => { Some(unsafe { Peripherals::steal() }) }, + None => None, }) } /// Unchecked version of `Peripherals::take` #[inline] pub unsafe fn steal() -> Self { - TAKEN = true; - - Peripherals { - CBP: CBP { - _marker: PhantomData, - }, - CPUID: CPUID { - _marker: PhantomData, - }, - DCB: DCB { - _marker: PhantomData, - }, - DWT: DWT { - _marker: PhantomData, - }, - FPB: FPB { - _marker: PhantomData, - }, - FPU: FPU { - _marker: PhantomData, - }, - ITM: ITM { - _marker: PhantomData, - }, - MPU: MPU { - _marker: PhantomData, - }, - NVIC: NVIC { - _marker: PhantomData, - }, - SCB: SCB { - _marker: PhantomData, - }, - SYST: SYST { - _marker: PhantomData, - }, - TPIU: TPIU { - _marker: PhantomData, - }, - } + // Ensure peripherals are marked as taken. + cortex_m_0_7::peripheral::Peripherals::steal(); + + // We can't create the imported types like CPUID because + // their _marker field is private, but we can create an + // entire Peripherals out of thin air because all the + // types are zero-sized. + core::mem::transmute(()) } } @@ -240,138 +196,21 @@ impl ops::Deref for CBP { } } -/// CPUID -pub struct CPUID { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for CPUID {} +pub use cortex_m_0_7::peripheral::{CPUID, DCB, DWT, FPB, FPU, SYST, TPIU}; -impl CPUID { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const self::cpuid::RegisterBlock { - 0xE000_ED00 as *const _ - } -} - -impl ops::Deref for CPUID { - type Target = self::cpuid::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -/// Debug Control Block -pub struct DCB { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for DCB {} - -impl DCB { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const dcb::RegisterBlock { - 0xE000_EDF0 as *const _ - } -} - -impl ops::Deref for DCB { - type Target = self::dcb::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*DCB::ptr() } - } -} - -/// Data Watchpoint and Trace unit -pub struct DWT { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for DWT {} - -impl DWT { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const dwt::RegisterBlock { - 0xE000_1000 as *const _ - } -} - -impl ops::Deref for DWT { - type Target = self::dwt::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -/// Flash Patch and Breakpoint unit -pub struct FPB { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for FPB {} - -#[cfg(not(armv6m))] -impl FPB { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const fpb::RegisterBlock { - 0xE000_2000 as *const _ - } -} - -#[cfg(not(armv6m))] -impl ops::Deref for FPB { - type Target = self::fpb::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -/// Floating Point Unit -pub struct FPU { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for FPU {} - -#[cfg(any(has_fpu, target_arch = "x86_64"))] -impl FPU { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const fpu::RegisterBlock { - 0xE000_EF30 as *const _ - } -} - -#[cfg(any(has_fpu, target_arch = "x86_64"))] -impl ops::Deref for FPU { - type Target = self::fpu::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} +#[cfg(not(armv8m_base))] +pub use cortex_m_0_7::peripheral::ITM; +#[cfg(armv8m_base)] /// Instrumentation Trace Macrocell pub struct ITM { _marker: PhantomData<*const ()>, } +#[cfg(armv8m_base)] unsafe impl Send for ITM {} -#[cfg(not(armv6m))] +#[cfg(armv8m_base)] impl ITM { /// Returns a pointer to the register block #[inline(always)] @@ -380,7 +219,7 @@ impl ITM { } } -#[cfg(not(armv6m))] +#[cfg(armv8m_base)] impl ops::Deref for ITM { type Target = self::itm::RegisterBlock; @@ -390,7 +229,7 @@ impl ops::Deref for ITM { } } -#[cfg(not(armv6m))] +#[cfg(armv8m_base)] impl ops::DerefMut for ITM { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { @@ -469,53 +308,3 @@ impl ops::Deref for SCB { unsafe { &*Self::ptr() } } } - -/// SysTick: System Timer -pub struct SYST { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for SYST {} - -impl SYST { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const syst::RegisterBlock { - 0xE000_E010 as *const _ - } -} - -impl ops::Deref for SYST { - type Target = self::syst::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} - -/// Trace Port Interface Unit -pub struct TPIU { - _marker: PhantomData<*const ()>, -} - -unsafe impl Send for TPIU {} - -#[cfg(not(armv6m))] -impl TPIU { - /// Returns a pointer to the register block - #[inline(always)] - pub fn ptr() -> *const tpiu::RegisterBlock { - 0xE004_0000 as *const _ - } -} - -#[cfg(not(armv6m))] -impl ops::Deref for TPIU { - type Target = self::tpiu::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::ptr() } - } -} diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index d710272d..f45d58e0 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -2,111 +2,18 @@ use core::ptr; -use volatile_register::RW; - #[cfg(not(armv6m))] -use super::cpuid::CsselrCacheType; +use cortex_m_0_7::peripheral::cpuid::CsselrCacheType; #[cfg(not(armv6m))] use super::CBP; #[cfg(not(armv6m))] use super::CPUID; use super::SCB; -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Interrupt Control and State - pub icsr: RW, - - /// Vector Table Offset (not present on Cortex-M0 variants) - pub vtor: RW, - - /// Application Interrupt and Reset Control - pub aircr: RW, - - /// System Control - pub scr: RW, - - /// Configuration and Control - pub ccr: RW, - - /// 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 shcsr: RW, - - /// Configurable Fault Status (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub cfsr: RW, - #[cfg(armv6m)] - _reserved2: u32, - - /// HardFault Status (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub hfsr: RW, - #[cfg(armv6m)] - _reserved3: u32, - - /// Debug Fault Status (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub dfsr: RW, - #[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, - #[cfg(armv6m)] - _reserved6: u32, - - /// Auxiliary Fault Status (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub afsr: RW, - #[cfg(armv6m)] - _reserved7: u32, - - _reserved8: [u32; 18], +pub use cortex_m_0_7::peripheral::scb::{RegisterBlock}; - /// Coprocessor Access Control (not present on Cortex-M0 variants) - #[cfg(not(armv6m))] - pub cpacr: RW, - #[cfg(armv6m)] - _reserved9: u32, -} - -/// FPU access mode #[cfg(has_fpu)] -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum FpuAccessMode { - /// FPU is not accessible - Disabled, - /// FPU is accessible in Privileged and User mode - Enabled, - /// FPU is accessible in Privileged mode only - Privileged, -} +pub use cortex_m_0_7::peripheral::scb::FpuAccessMode; #[cfg(has_fpu)] mod fpu_consts { @@ -193,115 +100,7 @@ impl SCB { } } -/// Processor core exceptions (internal interrupts) -#[allow(clippy::missing_inline_in_public_items)] -#[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]` - #[inline] - 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 -#[allow(clippy::missing_inline_in_public_items)] -#[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` - #[inline] - 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(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, - }) - } -} +pub use cortex_m_0_7::peripheral::scb::{Exception, VectActive}; #[cfg(not(armv6m))] mod scb_consts { diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs deleted file mode 100644 index 69bc488b..00000000 --- a/src/peripheral/syst.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! SysTick: System Timer - -use volatile_register::{RO, RW}; - -use crate::peripheral::SYST; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Control and Status - pub csr: RW, - /// Reload Value - pub rvr: RW, - /// Current Value - pub cvr: RW, - /// Calibration Value - pub calib: RO, -} - -/// SysTick clock source -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum SystClkSource { - /// Core-provided clock - Core, - /// External reference clock - External, -} - -const SYST_COUNTER_MASK: u32 = 0x00ff_ffff; - -const SYST_CSR_ENABLE: u32 = 1 << 0; -const SYST_CSR_TICKINT: u32 = 1 << 1; -const SYST_CSR_CLKSOURCE: u32 = 1 << 2; -const SYST_CSR_COUNTFLAG: u32 = 1 << 16; - -const SYST_CALIB_SKEW: u32 = 1 << 30; -const SYST_CALIB_NOREF: u32 = 1 << 31; - -impl SYST { - /// Clears current value to 0 - /// - /// After calling `clear_current()`, the next call to `has_wrapped()` will return `false`. - #[inline] - pub fn clear_current(&mut self) { - unsafe { self.cvr.write(0) } - } - - /// Disables counter - #[inline] - pub fn disable_counter(&mut self) { - unsafe { self.csr.modify(|v| v & !SYST_CSR_ENABLE) } - } - - /// Disables SysTick interrupt - #[inline] - pub fn disable_interrupt(&mut self) { - unsafe { self.csr.modify(|v| v & !SYST_CSR_TICKINT) } - } - - /// Enables counter - /// - /// *NOTE* The reference manual indicates that: - /// - /// "The SysTick counter reload and current value are undefined at reset, the correct - /// initialization sequence for the SysTick counter is: - /// - /// - Program reload value - /// - Clear current value - /// - Program Control and Status register" - /// - /// The sequence translates to `self.set_reload(x); self.clear_current(); self.enable_counter()` - #[inline] - pub fn enable_counter(&mut self) { - unsafe { self.csr.modify(|v| v | SYST_CSR_ENABLE) } - } - - /// Enables SysTick interrupt - #[inline] - pub fn enable_interrupt(&mut self) { - unsafe { self.csr.modify(|v| v | SYST_CSR_TICKINT) } - } - - /// Gets clock source - /// - /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the - /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) - #[inline] - pub fn get_clock_source(&mut self) -> SystClkSource { - // NOTE(unsafe) atomic read with no side effects - if self.csr.read() & SYST_CSR_CLKSOURCE != 0 { - SystClkSource::Core - } else { - SystClkSource::External - } - } - - /// Gets current value - #[inline] - pub fn get_current() -> u32 { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).cvr.read() } - } - - /// Gets reload value - #[inline] - pub fn get_reload() -> u32 { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).rvr.read() } - } - - /// Returns the reload value with which the counter would wrap once per 10 - /// ms - /// - /// Returns `0` if the value is not known (e.g. because the clock can - /// change dynamically). - #[inline] - pub fn get_ticks_per_10ms() -> u32 { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).calib.read() & SYST_COUNTER_MASK } - } - - /// Checks if an external reference clock is available - #[inline] - pub fn has_reference_clock() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).calib.read() & SYST_CALIB_NOREF == 0 } - } - - /// Checks if the counter wrapped (underflowed) since the last check - /// - /// *NOTE* This takes `&mut self` because the read operation is side effectful and will clear - /// the bit of the read register. - #[inline] - pub fn has_wrapped(&mut self) -> bool { - self.csr.read() & SYST_CSR_COUNTFLAG != 0 - } - - /// Checks if counter is enabled - /// - /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the - /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) - #[inline] - pub fn is_counter_enabled(&mut self) -> bool { - self.csr.read() & SYST_CSR_ENABLE != 0 - } - - /// Checks if SysTick interrupt is enabled - /// - /// *NOTE* This takes `&mut self` because the read operation is side effectful and can clear the - /// bit that indicates that the timer has wrapped (cf. `SYST.has_wrapped`) - #[inline] - pub fn is_interrupt_enabled(&mut self) -> bool { - self.csr.read() & SYST_CSR_TICKINT != 0 - } - - /// Checks if the calibration value is precise - /// - /// Returns `false` if using the reload value returned by - /// `get_ticks_per_10ms()` may result in a period significantly deviating - /// from 10 ms. - #[inline] - pub fn is_precise() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).calib.read() & SYST_CALIB_SKEW == 0 } - } - - /// Sets clock source - #[inline] - 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::Core => unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) }, - } - } - - /// Sets reload value - /// - /// Valid values are between `1` and `0x00ffffff`. - /// - /// *NOTE* To make the timer wrap every `N` ticks set the reload value to `N - 1` - #[inline] - pub fn set_reload(&mut self, value: u32) { - unsafe { self.rvr.write(value) } - } -} diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs deleted file mode 100644 index 4115bb32..00000000 --- a/src/peripheral/tpiu.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Trace Port Interface Unit; -//! -//! *NOTE* Available only on ARMv7-M (`thumbv7*m-none-eabi*`) - -use volatile_register::{RO, RW, WO}; - -/// Register block -#[repr(C)] -pub struct RegisterBlock { - /// Supported Parallel Port Sizes - pub sspsr: RO, - /// Current Parallel Port Size - pub cspsr: RW, - reserved0: [u32; 2], - /// Asynchronous Clock Prescaler - pub acpr: RW, - reserved1: [u32; 55], - /// Selected Pin Control - pub sppr: RW, - reserved2: [u32; 132], - /// Formatter and Flush Control - pub ffcr: RW, - reserved3: [u32; 810], - /// Lock Access - pub lar: WO, - /// Lock Status - pub lsr: RO, - reserved4: [u32; 4], - /// TPIU Type - pub _type: RO, -} diff --git a/src/register/control.rs b/src/register/control.rs deleted file mode 100644 index 211b5327..00000000 --- a/src/register/control.rs +++ /dev/null @@ -1,213 +0,0 @@ -//! Control register - -/// Control register -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug)] -pub struct Control { - bits: u32, -} - -impl Control { - /// Creates a `Control` value from raw bits. - #[inline] - pub fn from_bits(bits: u32) -> Self { - Self { bits } - } - - /// Returns the contents of the register as raw bits - #[inline] - pub fn bits(self) -> u32 { - self.bits - } - - /// Thread mode privilege level - #[inline] - pub fn npriv(self) -> Npriv { - if self.bits & (1 << 0) == (1 << 0) { - Npriv::Unprivileged - } else { - Npriv::Privileged - } - } - - /// Sets the thread mode privilege level value (nPRIV). - #[inline] - pub fn set_npriv(&mut self, npriv: Npriv) { - let mask = 1 << 0; - match npriv { - Npriv::Unprivileged => self.bits |= mask, - Npriv::Privileged => self.bits &= !mask, - } - } - - /// Currently active stack pointer - #[inline] - pub fn spsel(self) -> Spsel { - if self.bits & (1 << 1) == (1 << 1) { - Spsel::Psp - } else { - Spsel::Msp - } - } - - /// Sets the SPSEL value. - #[inline] - pub fn set_spsel(&mut self, spsel: Spsel) { - let mask = 1 << 1; - match spsel { - Spsel::Psp => self.bits |= mask, - Spsel::Msp => self.bits &= !mask, - } - } - - /// Whether context floating-point is currently active - #[inline] - pub fn fpca(self) -> Fpca { - if self.bits & (1 << 2) == (1 << 2) { - Fpca::Active - } else { - Fpca::NotActive - } - } - - /// Sets the FPCA value. - #[inline] - pub fn set_fpca(&mut self, fpca: Fpca) { - let mask = 1 << 2; - match fpca { - Fpca::Active => self.bits |= mask, - Fpca::NotActive => self.bits &= !mask, - } - } -} - -/// Thread mode privilege level -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Npriv { - /// Privileged - Privileged, - /// Unprivileged - Unprivileged, -} - -impl Npriv { - /// Is in privileged thread mode? - #[inline] - pub fn is_privileged(self) -> bool { - self == Npriv::Privileged - } - - /// Is in unprivileged thread mode? - #[inline] - pub fn is_unprivileged(self) -> bool { - self == Npriv::Unprivileged - } -} - -/// Currently active stack pointer -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Spsel { - /// MSP is the current stack pointer - Msp, - /// PSP is the current stack pointer - Psp, -} - -impl Spsel { - /// Is MSP the current stack pointer? - #[inline] - pub fn is_msp(self) -> bool { - self == Spsel::Msp - } - - /// Is PSP the current stack pointer? - #[inline] - pub fn is_psp(self) -> bool { - self == Spsel::Psp - } -} - -/// Whether context floating-point is currently active -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Fpca { - /// Floating-point context active. - Active, - /// No floating-point context active - NotActive, -} - -impl Fpca { - /// Is a floating-point context active? - #[inline] - pub fn is_active(self) -> bool { - self == Fpca::Active - } - - /// Is a floating-point context not active? - #[inline] - pub fn is_not_active(self) -> bool { - self == Fpca::NotActive - } -} - -/// Reads the CPU register -#[inline] -pub fn read() -> Control { - match () { - #[cfg(cortex_m)] - () => { - let r = match () { - #[cfg(feature = "inline-asm")] - () => { - let r: u32; - unsafe { llvm_asm!("mrs $0, CONTROL" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(not(feature = "inline-asm"))] - () => unsafe { - extern "C" { - fn __control_r() -> u32; - } - - __control_r() - }, - }; - - Control { bits: r } - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Writes to the CPU register. -#[inline] -pub unsafe fn write(_control: Control) { - match () { - #[cfg(cortex_m)] - () => match () { - #[cfg(feature = "inline-asm")] - () => { - let control = _control.bits(); - llvm_asm!("msr CONTROL, $0" :: "r"(control) : "memory" : "volatile"); - } - - #[cfg(not(feature = "inline-asm"))] - () => { - extern "C" { - fn __control_w(bits: u32); - } - - __control_w(_control.bits()); - } - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} diff --git a/src/register/mod.rs b/src/register/mod.rs index e7879c5c..35606edb 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -27,7 +27,7 @@ //! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers #[cfg(all(not(armv6m), not(armv8m_base)))] -pub mod basepri; +pub use cortex_m_0_7::register::basepri; #[cfg(armv8m_base)] #[deprecated( @@ -37,7 +37,7 @@ pub mod basepri; pub mod basepri; #[cfg(all(not(armv6m), not(armv8m_base)))] -pub mod basepri_max; +pub use cortex_m_0_7::register::basepri_max; #[cfg(armv8m_base)] #[deprecated( @@ -46,10 +46,10 @@ pub mod basepri_max; )] pub mod basepri_max; -pub mod control; +pub use cortex_m_0_7::register::control; #[cfg(all(not(armv6m), not(armv8m_base)))] -pub mod faultmask; +pub use cortex_m_0_7::register::faultmask; #[cfg(armv8m_base)] #[deprecated( @@ -58,25 +58,21 @@ pub mod faultmask; )] pub mod faultmask; -pub mod msp; - -pub mod primask; - -pub mod psp; - -#[cfg(armv8m_main)] -pub mod msplim; +pub use cortex_m_0_7::register::{msp, primask, psp}; #[cfg(armv8m_main)] -pub mod psplim; +pub use cortex_m_0_7::register::{msplim, psplim}; // 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"))] +#[cfg(feature = "inline-asm")] +pub use cortex_m_0_7::register::{apsr, lr, pc}; + +#[cfg(target_arch = "x86_64")] pub mod apsr; -#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] pub mod lr; -#[cfg(any(feature = "inline-asm", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] pub mod pc; diff --git a/src/register/msp.rs b/src/register/msp.rs deleted file mode 100644 index b5460ed0..00000000 --- a/src/register/msp.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Main Stack Pointer - -/// Reads the CPU register -#[inline] -pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,MSP" : "=r"(r) ::: "volatile") } - r - } - - #[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 -#[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_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/msplim.rs b/src/register/msplim.rs deleted file mode 100644 index 68915c4a..00000000 --- a/src/register/msplim.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Main Stack Pointer Limit Register - -/// Reads the CPU register -#[inline] -pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,MSPLIM" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __msplim_r() -> u32; - } - - __msplim_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Writes `bits` to the CPU register -#[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr MSPLIM,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __msplim_w(_: u32); - } - - __msplim_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} diff --git a/src/register/primask.rs b/src/register/primask.rs deleted file mode 100644 index 4b6df3c8..00000000 --- a/src/register/primask.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Priority mask register - -/// All exceptions with configurable priority are ... -#[allow(clippy::missing_inline_in_public_items)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Primask { - /// Active - Active, - /// Inactive - Inactive, -} - -impl Primask { - /// All exceptions with configurable priority are active - #[inline] - pub fn is_active(self) -> bool { - self == Primask::Active - } - - /// All exceptions with configurable priority are inactive - #[inline] - pub fn is_inactive(self) -> bool { - self == Primask::Inactive - } -} - -/// Reads the CPU register -#[inline] -pub fn read() -> Primask { - match () { - #[cfg(cortex_m)] - () => { - let r = match () { - #[cfg(feature = "inline-asm")] - () => { - let r: u32; - unsafe { llvm_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(cortex_m))] - () => unimplemented!(), - } -} diff --git a/src/register/psp.rs b/src/register/psp.rs deleted file mode 100644 index c020e4f9..00000000 --- a/src/register/psp.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Process Stack Pointer - -/// Reads the CPU register -#[inline] -pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,PSP" : "=r"(r) ::: "volatile") } - r - } - - #[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 -#[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_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!(), - } -} diff --git a/src/register/psplim.rs b/src/register/psplim.rs deleted file mode 100644 index 8cb8f1c7..00000000 --- a/src/register/psplim.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Process Stack Pointer Limit Register - -/// Reads the CPU register -#[inline] -pub fn read() -> u32 { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => { - let r; - unsafe { llvm_asm!("mrs $0,PSPLIM" : "=r"(r) ::: "volatile") } - r - } - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => unsafe { - extern "C" { - fn __psplim_r() -> u32; - } - - __psplim_r() - }, - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -} - -/// Writes `bits` to the CPU register -#[inline] -pub unsafe fn write(_bits: u32) { - match () { - #[cfg(all(cortex_m, feature = "inline-asm"))] - () => llvm_asm!("msr PSPLIM,$0" :: "r"(_bits) :: "volatile"), - - #[cfg(all(cortex_m, not(feature = "inline-asm")))] - () => { - extern "C" { - fn __psplim_w(_: u32); - } - - __psplim_w(_bits); - } - - #[cfg(not(cortex_m))] - () => unimplemented!(), - } -}