aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs294
-rw-r--r--src/cmse.rs238
-rw-r--r--src/critical_section.rs22
-rw-r--r--src/delay.rs136
-rw-r--r--src/interrupt.rs95
-rw-r--r--src/itm.rs158
-rw-r--r--src/lib.rs79
-rw-r--r--src/macros.rs117
-rw-r--r--src/peripheral/ac.rs93
-rw-r--r--src/peripheral/cbp.rs138
-rw-r--r--src/peripheral/cpuid.rs140
-rw-r--r--src/peripheral/dcb.rs81
-rw-r--r--src/peripheral/dwt.rs507
-rw-r--r--src/peripheral/fpb.rs21
-rw-r--r--src/peripheral/fpu.rs19
-rw-r--r--src/peripheral/icb.rs32
-rw-r--r--src/peripheral/itm.rs216
-rw-r--r--src/peripheral/mod.rs592
-rw-r--r--src/peripheral/mpu.rs65
-rw-r--r--src/peripheral/nvic.rs272
-rw-r--r--src/peripheral/sau.rs242
-rw-r--r--src/peripheral/scb.rs1110
-rw-r--r--src/peripheral/syst.rs185
-rw-r--r--src/peripheral/test.rs170
-rw-r--r--src/peripheral/tpiu.rs160
-rw-r--r--src/register/apsr.rs57
-rw-r--r--src/register/basepri.rs42
-rw-r--r--src/register/basepri_max.rs40
-rw-r--r--src/register/control.rs183
-rw-r--r--src/register/faultmask.rs40
-rw-r--r--src/register/fpscr.rs308
-rw-r--r--src/register/lr.rs20
-rw-r--r--src/register/mod.rs63
-rw-r--r--src/register/msp.rs45
-rw-r--r--src/register/msplim.rs17
-rw-r--r--src/register/pc.rs20
-rw-r--r--src/register/primask.rs40
-rw-r--r--src/register/psp.rs22
-rw-r--r--src/register/psplim.rs17
39 files changed, 0 insertions, 6096 deletions
diff --git a/src/asm.rs b/src/asm.rs
deleted file mode 100644
index 3a3485a..0000000
--- a/src/asm.rs
+++ /dev/null
@@ -1,294 +0,0 @@
-//! Miscellaneous assembly instructions
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-use core::sync::atomic::{compiler_fence, Ordering};
-
-/// 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.
-#[cfg(cortex_m)]
-#[inline(always)]
-pub fn bkpt() {
- unsafe { asm!("bkpt", options(nomem, nostack, preserves_flags)) };
-}
-
-/// Blocks the program for *at least* `cycles` CPU cycles.
-///
-/// This is implemented in assembly so its execution time is independent of the optimization
-/// level, however it is dependent on the specific architecture and core configuration.
-///
-/// NOTE that the delay can take much longer if interrupts are serviced during its execution
-/// and the execution time may vary with other factors. This delay is mainly useful for simple
-/// timer-less initialization of peripherals if and only if accurate timing is not essential. In
-/// any other case please use a more accurate method to produce a delay.
-#[cfg(cortex_m)]
-#[inline]
-pub fn delay(cycles: u32) {
- // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
- // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
- // for more cycles is okay.
- // Add 1 to prevent an integer underflow which would cause a long freeze
- let real_cycles = 1 + cycles / 2;
- unsafe {
- asm!(
- // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
- "1:",
- "subs {}, #1",
- "bne 1b",
- inout(reg) real_cycles => _,
- options(nomem, nostack),
- )
- };
-}
-
-/// A no-operation. Useful to prevent delay loops from being optimized away.
-#[inline(always)]
-pub fn nop() {
- // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
- // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
- // nops when they call `nop` N times, let's not add that option.
- #[cfg(cortex_m)]
- unsafe {
- asm!("nop", options(nomem, nostack, preserves_flags))
- };
-}
-
-/// Generate an Undefined Instruction exception.
-///
-/// Can be used as a stable alternative to `core::intrinsics::abort`.
-#[cfg(cortex_m)]
-#[inline(always)]
-pub fn udf() -> ! {
- unsafe { asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)) };
-}
-
-/// Wait For Event
-#[cfg(cortex_m)]
-#[inline(always)]
-pub fn wfe() {
- unsafe { asm!("wfe", options(nomem, nostack, preserves_flags)) };
-}
-
-/// Wait For Interrupt
-#[cfg(cortex_m)]
-#[inline(always)]
-pub fn wfi() {
- unsafe { asm!("wfi", options(nomem, nostack, preserves_flags)) };
-}
-
-/// Send Event
-#[cfg(cortex_m)]
-#[inline(always)]
-pub fn sev() {
- unsafe { asm!("sev", options(nomem, nostack, preserves_flags)) };
-}
-
-/// 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(always)]
-pub fn isb() {
- compiler_fence(Ordering::SeqCst);
- #[cfg(cortex_m)]
- unsafe {
- asm!("isb", options(nomem, nostack, preserves_flags))
- };
- compiler_fence(Ordering::SeqCst);
-}
-
-/// 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(always)]
-pub fn dsb() {
- compiler_fence(Ordering::SeqCst);
- #[cfg(cortex_m)]
- unsafe {
- asm!("dsb", options(nomem, nostack, preserves_flags))
- };
- compiler_fence(Ordering::SeqCst);
-}
-
-/// 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(always)]
-pub fn dmb() {
- compiler_fence(Ordering::SeqCst);
- #[cfg(cortex_m)]
- unsafe {
- asm!("dmb", options(nomem, nostack, preserves_flags))
- };
- compiler_fence(Ordering::SeqCst);
-}
-
-/// 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(always)]
-#[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 {
- let mut target = addr as u32;
- unsafe {
- asm!(
- "tt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- )
- };
- target
-}
-
-/// 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(always)]
-#[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 {
- let mut target = addr as u32;
- unsafe {
- asm!(
- "ttt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- )
- };
- target
-}
-
-/// 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(always)]
-#[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 {
- let mut target = addr as u32;
- unsafe {
- asm!(
- "tta {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- )
- };
- target
-}
-
-/// 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(always)]
-#[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 {
- let mut target = addr as u32;
- unsafe {
- asm!(
- "ttat {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- )
- };
- target
-}
-
-/// Branch and Exchange Non-secure
-///
-/// See section C2.4.26 of Armv8-M Architecture Reference Manual for details.
-/// Undefined if executed in Non-Secure state.
-#[inline(always)]
-#[cfg(armv8m)]
-pub unsafe fn bx_ns(addr: u32) {
- asm!("bxns {}", in(reg) addr, options(nomem, nostack, preserves_flags));
-}
-
-/// Semihosting syscall.
-///
-/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
-#[cfg(cortex_m)]
-#[inline(always)]
-pub unsafe fn semihosting_syscall(mut nr: u32, arg: u32) -> u32 {
- asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nostack, preserves_flags));
- nr
-}
-
-/// Bootstrap.
-///
-/// Clears CONTROL.SPSEL (setting the main stack to be the active stack),
-/// updates the main stack pointer to the address in `msp`, then jumps
-/// to the address in `rv`.
-///
-/// # Safety
-///
-/// `msp` and `rv` must point to valid stack memory and executable code,
-/// respectively.
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
- // Ensure thumb mode is set.
- let rv = (rv as u32) | 1;
- let msp = msp as u32;
- asm!(
- "mrs {tmp}, CONTROL",
- "bics {tmp}, {spsel}",
- "msr CONTROL, {tmp}",
- "isb",
- "msr MSP, {msp}",
- "bx {rv}",
- // `out(reg) _` is not permitted in a `noreturn` asm! call,
- // so instead use `in(reg) 0` and don't restore it afterwards.
- tmp = in(reg) 0,
- spsel = in(reg) 2,
- msp = in(reg) msp,
- rv = in(reg) rv,
- options(noreturn, nomem, nostack),
- );
-}
-
-/// Bootload.
-///
-/// Reads the initial stack pointer value and reset vector from
-/// the provided vector table address, sets the active stack to
-/// the main stack, sets the main stack pointer to the new initial
-/// stack pointer, then jumps to the reset vector.
-///
-/// # Safety
-///
-/// The provided `vector_table` must point to a valid vector
-/// table, with a valid stack pointer as the first word and
-/// a valid reset vector as the second word.
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn bootload(vector_table: *const u32) -> ! {
- let msp = core::ptr::read_volatile(vector_table);
- let rv = core::ptr::read_volatile(vector_table.offset(1));
- bootstrap(msp as *const u32, rv as *const u32);
-}
diff --git a/src/cmse.rs b/src/cmse.rs
deleted file mode 100644
index 7826bb8..0000000
--- a/src/cmse.rs
+++ /dev/null
@@ -1,238 +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.
-#[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.
-#[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<Self> {
- 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<u8> {
- if self.tt_resp.mrvalid() {
- // Cast is safe as MREGION field is defined on 8 bits.
- Some(self.tt_resp.mregion() 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<u8> {
- 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<u8> {
- 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/critical_section.rs b/src/critical_section.rs
deleted file mode 100644
index e3d57d1..0000000
--- a/src/critical_section.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use critical_section::{set_impl, Impl, RawRestoreState};
-
-use crate::interrupt;
-use crate::register::primask;
-
-struct SingleCoreCriticalSection;
-set_impl!(SingleCoreCriticalSection);
-
-unsafe impl Impl for SingleCoreCriticalSection {
- unsafe fn acquire() -> RawRestoreState {
- let was_active = primask::read().is_active();
- interrupt::disable();
- was_active
- }
-
- unsafe fn release(was_active: RawRestoreState) {
- // Only re-enable interrupts if they were enabled before the critical section.
- if was_active {
- interrupt::enable()
- }
- }
-}
diff --git a/src/delay.rs b/src/delay.rs
deleted file mode 100644
index 66a63bf..0000000
--- a/src/delay.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-//! A delay driver based on SysTick.
-
-use crate::peripheral::{syst::SystClkSource, SYST};
-use embedded_hal::blocking::delay::{DelayMs, DelayUs};
-
-/// System timer (SysTick) as a delay provider.
-pub struct Delay {
- syst: SYST,
- frequency: u32,
-}
-
-impl Delay {
- /// Configures the system timer (SysTick) as a delay provider.
- ///
- /// `ahb_frequency` is a frequency of the AHB bus in Hz.
- #[inline]
- pub fn new(syst: SYST, ahb_frequency: u32) -> Self {
- Self::with_source(syst, ahb_frequency, SystClkSource::Core)
- }
-
- /// Configures the system timer (SysTick) as a delay provider
- /// with a clock source.
- ///
- /// `frequency` is the frequency of your `clock_source` in Hz.
- #[inline]
- pub fn with_source(mut syst: SYST, frequency: u32, clock_source: SystClkSource) -> Self {
- syst.set_clock_source(clock_source);
-
- Delay { syst, frequency }
- }
-
- /// Releases the system timer (SysTick) resource.
- #[inline]
- pub fn free(self) -> SYST {
- self.syst
- }
-
- /// Delay using the Cortex-M systick for a certain duration, in µs.
- #[allow(clippy::missing_inline_in_public_items)]
- pub fn delay_us(&mut self, us: u32) {
- let ticks = (u64::from(us)) * (u64::from(self.frequency)) / 1_000_000;
-
- let full_cycles = ticks >> 24;
- if full_cycles > 0 {
- self.syst.set_reload(0xffffff);
- self.syst.clear_current();
- self.syst.enable_counter();
-
- for _ in 0..full_cycles {
- while !self.syst.has_wrapped() {}
- }
- }
-
- let ticks = (ticks & 0xffffff) as u32;
- if ticks > 1 {
- self.syst.set_reload(ticks - 1);
- self.syst.clear_current();
- self.syst.enable_counter();
-
- while !self.syst.has_wrapped() {}
- }
-
- self.syst.disable_counter();
- }
-
- /// Delay using the Cortex-M systick for a certain duration, in ms.
- #[inline]
- pub fn delay_ms(&mut self, mut ms: u32) {
- // 4294967 is the highest u32 value which you can multiply by 1000 without overflow
- while ms > 4294967 {
- self.delay_us(4294967000u32);
- ms -= 4294967;
- }
- self.delay_us(ms * 1_000);
- }
-}
-
-impl DelayMs<u32> for Delay {
- #[inline]
- fn delay_ms(&mut self, ms: u32) {
- Delay::delay_ms(self, ms);
- }
-}
-
-// This is a workaround to allow `delay_ms(42)` construction without specifying a type.
-impl DelayMs<i32> for Delay {
- #[inline(always)]
- fn delay_ms(&mut self, ms: i32) {
- assert!(ms >= 0);
- Delay::delay_ms(self, ms as u32);
- }
-}
-
-impl DelayMs<u16> for Delay {
- #[inline(always)]
- fn delay_ms(&mut self, ms: u16) {
- Delay::delay_ms(self, u32::from(ms));
- }
-}
-
-impl DelayMs<u8> for Delay {
- #[inline(always)]
- fn delay_ms(&mut self, ms: u8) {
- Delay::delay_ms(self, u32::from(ms));
- }
-}
-
-impl DelayUs<u32> for Delay {
- #[inline]
- fn delay_us(&mut self, us: u32) {
- Delay::delay_us(self, us);
- }
-}
-
-// This is a workaround to allow `delay_us(42)` construction without specifying a type.
-impl DelayUs<i32> for Delay {
- #[inline(always)]
- fn delay_us(&mut self, us: i32) {
- assert!(us >= 0);
- Delay::delay_us(self, us as u32);
- }
-}
-
-impl DelayUs<u16> for Delay {
- #[inline(always)]
- fn delay_us(&mut self, us: u16) {
- Delay::delay_us(self, u32::from(us))
- }
-}
-
-impl DelayUs<u8> for Delay {
- #[inline(always)]
- fn delay_us(&mut self, us: u8) {
- Delay::delay_us(self, u32::from(us))
- }
-}
diff --git a/src/interrupt.rs b/src/interrupt.rs
deleted file mode 100644
index f6ce990..0000000
--- a/src/interrupt.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-//! Interrupts
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-#[cfg(cortex_m)]
-use core::sync::atomic::{compiler_fence, Ordering};
-
-/// Trait for enums of external interrupt numbers.
-///
-/// This trait should be implemented by a peripheral access crate (PAC)
-/// on its enum of available external interrupts for a specific device.
-/// Each variant must convert to a u16 of its interrupt number,
-/// which is its exception number - 16.
-///
-/// # Safety
-///
-/// This trait must only be implemented on enums of device interrupts. Each
-/// enum variant must represent a distinct value (no duplicates are permitted),
-/// and must always return the same value (do not change at runtime).
-///
-/// These requirements ensure safe nesting of critical sections.
-pub unsafe trait InterruptNumber: Copy {
- /// Return the interrupt number associated with this variant.
- ///
- /// See trait documentation for safety requirements.
- fn number(self) -> u16;
-}
-
-/// Disables all interrupts in the current core.
-#[cfg(cortex_m)]
-#[inline]
-pub fn disable() {
- unsafe {
- asm!("cpsid i", options(nomem, nostack, preserves_flags));
- }
-
- // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
- compiler_fence(Ordering::SeqCst);
-}
-
-/// Enables all the interrupts in the current core.
-///
-/// # Safety
-///
-/// - Do not call this function inside a critical section.
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn enable() {
- // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
- compiler_fence(Ordering::SeqCst);
-
- asm!("cpsie i", options(nomem, nostack, preserves_flags));
-}
-
-/// Execute closure `f` with interrupts disabled in the current core.
-///
-/// This method does not synchronise multiple cores and may disable required
-/// interrupts on some platforms; see the `critical-section` crate for a cross-platform
-/// way to enter a critical section which provides a `CriticalSection` token.
-///
-/// This crate provides an implementation for `critical-section` suitable for single-core systems,
-/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature.
-#[cfg(cortex_m)]
-#[inline]
-pub fn free<F, R>(f: F) -> R
-where
- F: FnOnce() -> R,
-{
- let primask = crate::register::primask::read();
-
- // disable interrupts
- disable();
-
- let r = f();
-
- // If the interrupts were active before our `disable` call, then re-enable
- // them. Otherwise, keep them disabled
- if primask.is_active() {
- unsafe { enable() }
- }
-
- r
-}
-
-// Make a `free()` function available to allow checking dependencies without specifying a target,
-// but that will panic at runtime if executed.
-#[doc(hidden)]
-#[cfg(not(cortex_m))]
-#[inline]
-pub fn free<F, R>(_: F) -> R
-where
- F: FnOnce() -> R,
-{
- panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms");
-}
diff --git a/src/itm.rs b/src/itm.rs
deleted file mode 100644
index 72cb0d9..0000000
--- a/src/itm.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Instrumentation Trace Macrocell
-//!
-//! **NOTE** This module is only available on ARMv7-M and newer.
-
-use core::{fmt, ptr, slice};
-
-use crate::peripheral::itm::Stim;
-
-// NOTE assumes that `bytes` is 32-bit aligned
-unsafe fn write_words(stim: &mut Stim, bytes: &[u32]) {
- let mut p = bytes.as_ptr();
- for _ in 0..bytes.len() {
- while !stim.is_fifo_ready() {}
- stim.write_u32(ptr::read(p));
- p = p.offset(1);
- }
-}
-
-/// Writes an aligned byte slice to the ITM.
-///
-/// `buffer` must be 4-byte aligned.
-unsafe fn write_aligned_impl(port: &mut Stim, buffer: &[u8]) {
- let len = buffer.len();
-
- if len == 0 {
- return;
- }
-
- let split = len & !0b11;
- #[allow(clippy::cast_ptr_alignment)]
- write_words(
- port,
- slice::from_raw_parts(buffer.as_ptr() as *const u32, split >> 2),
- );
-
- // 3 bytes or less left
- let mut left = len & 0b11;
- let mut ptr = buffer.as_ptr().add(split);
-
- // at least 2 bytes left
- if left > 1 {
- while !port.is_fifo_ready() {}
-
- #[allow(clippy::cast_ptr_alignment)]
- port.write_u16(ptr::read(ptr as *const u16));
-
- ptr = ptr.offset(2);
- left -= 2;
- }
-
- // final byte
- if left == 1 {
- while !port.is_fifo_ready() {}
- port.write_u8(*ptr);
- }
-}
-
-struct Port<'p>(&'p mut Stim);
-
-impl<'p> fmt::Write for Port<'p> {
- #[inline]
- fn write_str(&mut self, s: &str) -> fmt::Result {
- write_all(self.0, s.as_bytes());
- Ok(())
- }
-}
-
-/// A wrapper type that aligns its contents on a 4-Byte boundary.
-///
-/// ITM transfers are most efficient when the data is 4-Byte-aligned. This type provides an easy
-/// way to accomplish and enforce such an alignment.
-#[repr(align(4))]
-pub struct Aligned<T: ?Sized>(pub T);
-
-/// Writes `buffer` to an ITM port.
-#[allow(clippy::missing_inline_in_public_items)]
-pub fn write_all(port: &mut Stim, buffer: &[u8]) {
- unsafe {
- let mut len = buffer.len();
- let mut ptr = buffer.as_ptr();
-
- if len == 0 {
- return;
- }
-
- // 0x01 OR 0x03
- if ptr as usize % 2 == 1 {
- while !port.is_fifo_ready() {}
- port.write_u8(*ptr);
-
- // 0x02 OR 0x04
- ptr = ptr.offset(1);
- len -= 1;
- }
-
- // 0x02
- if ptr as usize % 4 == 2 {
- if len > 1 {
- // at least 2 bytes
- while !port.is_fifo_ready() {}
-
- // We checked the alignment above, so this is safe
- #[allow(clippy::cast_ptr_alignment)]
- port.write_u16(ptr::read(ptr as *const u16));
-
- // 0x04
- ptr = ptr.offset(2);
- len -= 2;
- } else {
- if len == 1 {
- // last byte
- while !port.is_fifo_ready() {}
- port.write_u8(*ptr);
- }
-
- return;
- }
- }
-
- // The remaining data is 4-byte aligned, but might not be a multiple of 4 bytes
- write_aligned_impl(port, slice::from_raw_parts(ptr, len));
- }
-}
-
-/// Writes a 4-byte aligned `buffer` to an ITM port.
-///
-/// # Examples
-///
-/// ```no_run
-/// # use cortex_m::{itm::{self, Aligned}, peripheral::ITM};
-/// # let port = unsafe { &mut (*ITM::PTR).stim[0] };
-/// let mut buffer = Aligned([0; 14]);
-///
-/// buffer.0.copy_from_slice(b"Hello, world!\n");
-///
-/// itm::write_aligned(port, &buffer);
-///
-/// // Or equivalently
-/// itm::write_aligned(port, &Aligned(*b"Hello, world!\n"));
-/// ```
-#[allow(clippy::missing_inline_in_public_items)]
-pub fn write_aligned(port: &mut Stim, buffer: &Aligned<[u8]>) {
- unsafe { write_aligned_impl(port, &buffer.0) }
-}
-
-/// Writes `fmt::Arguments` to the ITM `port`
-#[inline]
-pub fn write_fmt(port: &mut Stim, args: fmt::Arguments) {
- use core::fmt::Write;
-
- Port(port).write_fmt(args).ok();
-}
-
-/// Writes a string to the ITM `port`
-#[inline]
-pub fn write_str(port: &mut Stim, string: &str) {
- write_all(port, string.as_bytes())
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 7c1599c..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-//! Low level access to Cortex-M processors
-//!
-//! This crate provides:
-//!
-//! - Access to core peripherals like NVIC, SCB and SysTick.
-//! - Access to core registers like CONTROL, MSP and PSR.
-//! - Interrupt manipulation mechanisms
-//! - Safe wrappers around Cortex-M specific instructions like `bkpt`
-//!
-//! # Optional features
-//!
-//! ## `critical-section-single-core`
-//!
-//! This feature enables a [`critical-section`](https://github.com/rust-embedded/critical-section)
-//! implementation suitable for single-core targets, based on disabling interrupts globally.
-//!
-//! It is **unsound** to enable it on multi-core targets or for code running in unprivileged mode,
-//! and may cause functional problems in systems where some interrupts must be not be disabled
-//! or critical sections are managed as part of an RTOS. In these cases, you should use
-//! a target-specific implementation instead, typically provided by a HAL or RTOS crate.
-//!
-//! ## `cm7-r0p1`
-//!
-//! This feature enables workarounds for errata found on Cortex-M7 chips with revision r0p1. Some
-//! functions in this crate only work correctly on those chips if this Cargo feature is enabled
-//! (the functions are documented accordingly).
-//!
-//! # Minimum Supported Rust Version (MSRV)
-//!
-//! This crate is guaranteed to compile on stable Rust 1.59 and up. It *might*
-//! compile with older versions but that may change in any new patch release.
-
-#![deny(missing_docs)]
-#![no_std]
-#![allow(clippy::identity_op)]
-#![allow(clippy::missing_safety_doc)]
-// Prevent clippy from complaining about empty match expression that are used for cfg gating.
-#![allow(clippy::match_single_binding)]
-// This makes clippy warn about public functions which are not #[inline].
-//
-// Almost all functions in this crate result in trivial or even no assembly.
-// These functions should be #[inline].
-//
-// If you do add a function that's not supposed to be #[inline], you can add
-// #[allow(clippy::missing_inline_in_public_items)] in front of it to add an
-// exception to clippy's rules.
-//
-// This should be done in case of:
-// - A function containing non-trivial logic (such as itm::write_all); or
-// - A generated #[derive(Debug)] function (in which case the attribute needs
-// to be applied to the struct).
-#![deny(clippy::missing_inline_in_public_items)]
-// Don't warn about feature(asm) being stable on Rust >= 1.59.0
-#![allow(stable_features)]
-
-#[macro_use]
-mod macros;
-
-pub mod asm;
-#[cfg(armv8m)]
-pub mod cmse;
-pub mod delay;
-pub mod interrupt;
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-pub mod itm;
-pub mod peripheral;
-pub mod register;
-
-pub use crate::peripheral::Peripherals;
-
-#[cfg(all(cortex_m, feature = "critical-section-single-core"))]
-mod critical_section;
-
-/// Used to reexport items for use in macros. Do not use directly.
-/// Not covered by semver guarantees.
-#[doc(hidden)]
-pub mod _export {
- pub use critical_section;
-}
diff --git a/src/macros.rs b/src/macros.rs
deleted file mode 100644
index 2cf4f89..0000000
--- a/src/macros.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-/// Macro for sending a formatted string through an ITM channel
-#[macro_export]
-macro_rules! iprint {
- ($channel:expr, $s:expr) => {
- $crate::itm::write_str($channel, $s);
- };
- ($channel:expr, $($arg:tt)*) => {
- $crate::itm::write_fmt($channel, format_args!($($arg)*));
- };
-}
-
-/// Macro for sending a formatted string through an ITM channel, with a newline.
-#[macro_export]
-macro_rules! iprintln {
- ($channel:expr) => {
- $crate::itm::write_str($channel, "\n");
- };
- ($channel:expr, $fmt:expr) => {
- $crate::itm::write_str($channel, concat!($fmt, "\n"));
- };
- ($channel:expr, $fmt:expr, $($arg:tt)*) => {
- $crate::itm::write_fmt($channel, format_args!(concat!($fmt, "\n"), $($arg)*));
- };
-}
-
-/// Macro to create a mutable reference to a statically allocated value
-///
-/// This macro returns a value with type `Option<&'static mut $ty>`. `Some($expr)` will be returned
-/// the first time the macro is executed; further calls will return `None`. To avoid `unwrap`ping a
-/// `None` variant the caller must ensure that the macro is called from a function that's executed
-/// at most once in the whole lifetime of the program.
-///
-/// # Notes
-///
-/// This macro requires a `critical-section` implementation to be set. For most single core systems,
-/// you can enable the `critical-section-single-core` feature for this crate. For other systems, you
-/// have to provide one from elsewhere, typically your chip's HAL crate.
-///
-/// For debuggability, you can set an explicit name for a singleton. This name only shows up the
-/// the debugger and is not referencable from other code. See example below.
-///
-/// # Example
-///
-/// ``` no_run
-/// use cortex_m::singleton;
-///
-/// fn main() {
-/// // OK if `main` is executed only once
-/// let x: &'static mut bool = singleton!(: bool = false).unwrap();
-///
-/// let y = alias();
-/// // BAD this second call to `alias` will definitively `panic!`
-/// let y_alias = alias();
-/// }
-///
-/// fn alias() -> &'static mut bool {
-/// singleton!(: bool = false).unwrap()
-/// }
-///
-/// fn singleton_with_name() {
-/// // A name only for debugging purposes
-/// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]);
-/// }
-/// ```
-#[macro_export]
-macro_rules! singleton {
- ($name:ident: $ty:ty = $expr:expr) => {
- $crate::_export::critical_section::with(|_| {
- // this is a tuple of a MaybeUninit and a bool because using an Option here is
- // problematic: Due to niche-optimization, an Option could end up producing a non-zero
- // initializer value which would move the entire static from `.bss` into `.data`...
- static mut $name: (::core::mem::MaybeUninit<$ty>, bool) =
- (::core::mem::MaybeUninit::uninit(), false);
-
- #[allow(unsafe_code)]
- let used = unsafe { $name.1 };
- if used {
- None
- } else {
- let expr = $expr;
-
- #[allow(unsafe_code)]
- unsafe {
- $name.1 = true;
- $name.0 = ::core::mem::MaybeUninit::new(expr);
- Some(&mut *$name.0.as_mut_ptr())
- }
- }
- })
- };
- (: $ty:ty = $expr:expr) => {
- $crate::singleton!(VAR: $ty = $expr)
- };
-}
-
-/// ``` compile_fail
-/// use cortex_m::singleton;
-///
-/// fn foo() {
-/// // check that the call to `uninitialized` requires unsafe
-/// singleton!(: u8 = std::mem::uninitialized());
-/// }
-/// ```
-#[allow(dead_code)]
-const CFAIL: () = ();
-
-/// ```
-/// #![deny(unsafe_code)]
-/// use cortex_m::singleton;
-///
-/// fn foo() {
-/// // check that calls to `singleton!` don't trip the `unsafe_code` lint
-/// singleton!(: u8 = 0);
-/// }
-/// ```
-#[allow(dead_code)]
-const CPASS: () = ();
diff --git a/src/peripheral/ac.rs b/src/peripheral/ac.rs
deleted file mode 100644
index 1ac5be1..0000000
--- a/src/peripheral/ac.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//! Cortex-M7 TCM and Cache access control.
-
-use volatile_register::RW;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Instruction Tightly-Coupled Memory Control Register
- pub itcmcr: RW<u32>,
- /// Data Tightly-Coupled Memory Control Register
- pub dtcmcr: RW<u32>,
- /// AHBP Control Register
- pub ahbpcr: RW<u32>,
- /// L1 Cache Control Register
- pub cacr: RW<u32>,
- /// AHB Slave Control Register
- pub ahbscr: RW<u32>,
- reserved0: u32,
- /// Auxilary Bus Fault Status Register
- pub abfsr: RW<u32>,
-}
-
-/// ITCMCR and DTCMCR TCM enable bit.
-pub const TCM_EN: u32 = 1;
-
-/// ITCMCR and DTCMCR TCM read-modify-write bit.
-pub const TCM_RMW: u32 = 2;
-
-/// ITCMCR and DTCMCR TCM rety phase enable bit.
-pub const TCM_RETEN: u32 = 4;
-
-/// ITCMCR and DTCMCR TCM size mask.
-pub const TCM_SZ_MASK: u32 = 0x78;
-
-/// ITCMCR and DTCMCR TCM shift.
-pub const TCM_SZ_SHIFT: usize = 3;
-
-/// AHBPCR AHBP enable bit.
-pub const AHBPCR_EN: u32 = 1;
-
-/// AHBPCR AHBP size mask.
-pub const AHBPCR_SZ_MASK: u32 = 0x0e;
-
-/// AHBPCR AHBP size shit.
-pub const AHBPCR_SZ_SHIFT: usize = 1;
-
-/// CACR Shared cachedable-is-WT for data cache.
-pub const CACR_SIWT: u32 = 1;
-
-/// CACR ECC in the instruction and data cache (disable).
-pub const CACR_ECCDIS: u32 = 2;
-
-/// CACR Force Write-Through in the data cache.
-pub const CACR_FORCEWT: u32 = 4;
-
-/// AHBSCR AHBS prioritization control mask.
-pub const AHBSCR_CTL_MASK: u32 = 0x03;
-
-/// AHBSCR AHBS prioritization control shift.
-pub const AHBSCR_CTL_SHIFT: usize = 0;
-
-/// AHBSCR Threshold execution prioity for AHBS traffic demotion, mask.
-pub const AHBSCR_TPRI_MASK: u32 = 0x7fc;
-
-/// AHBSCR Threshold execution prioity for AHBS traffic demotion, shift.
-pub const AHBSCR_TPRI_SHIFT: usize = 2;
-
-/// AHBSCR Failness counter initialization value, mask.
-pub const AHBSCR_INITCOUNT_MASK: u32 = 0xf800;
-
-/// AHBSCR Failness counter initialization value, shift.
-pub const AHBSCR_INITCOUNT_SHIFT: usize = 11;
-
-/// ABFSR Async fault on ITCM interface.
-pub const ABFSR_ITCM: u32 = 1;
-
-/// ABFSR Async fault on DTCM interface.
-pub const ABFSR_DTCM: u32 = 2;
-
-/// ABFSR Async fault on AHBP interface.
-pub const ABFSR_AHBP: u32 = 4;
-
-/// ABFSR Async fault on AXIM interface.
-pub const ABFSR_AXIM: u32 = 8;
-
-/// ABFSR Async fault on EPPB interface.
-pub const ABFSR_EPPB: u32 = 16;
-
-/// ABFSR Indicates the type of fault on the AXIM interface, mask.
-pub const ABFSR_AXIMTYPE_MASK: u32 = 0x300;
-
-/// ABFSR Indicates the type of fault on the AXIM interface, shift.
-pub const ABFSR_AXIMTYPE_SHIFT: usize = 8;
diff --git a/src/peripheral/cbp.rs b/src/peripheral/cbp.rs
deleted file mode 100644
index 5aee544..0000000
--- a/src/peripheral/cbp.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-//! Cache and branch predictor maintenance operations
-//!
-//! *NOTE* Not available on Armv6-M.
-
-use volatile_register::WO;
-
-use crate::peripheral::CBP;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// I-cache invalidate all to PoU
- pub iciallu: WO<u32>,
- reserved0: u32,
- /// I-cache invalidate by MVA to PoU
- pub icimvau: WO<u32>,
- /// D-cache invalidate by MVA to PoC
- pub dcimvac: WO<u32>,
- /// D-cache invalidate by set-way
- pub dcisw: WO<u32>,
- /// D-cache clean by MVA to PoU
- pub dccmvau: WO<u32>,
- /// D-cache clean by MVA to PoC
- pub dccmvac: WO<u32>,
- /// D-cache clean by set-way
- pub dccsw: WO<u32>,
- /// D-cache clean and invalidate by MVA to PoC
- pub dccimvac: WO<u32>,
- /// D-cache clean and invalidate by set-way
- pub dccisw: WO<u32>,
- /// Branch predictor invalidate all
- pub bpiall: WO<u32>,
-}
-
-const CBP_SW_WAY_POS: u32 = 30;
-const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS;
-const CBP_SW_SET_POS: u32 = 5;
-const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS;
-
-impl CBP {
- /// I-cache invalidate all to PoU
- #[inline(always)]
- pub fn iciallu(&mut self) {
- unsafe { self.iciallu.write(0) };
- }
-
- /// I-cache invalidate by MVA to PoU
- #[inline(always)]
- pub fn icimvau(&mut self, mva: u32) {
- unsafe { self.icimvau.write(mva) };
- }
-
- /// D-cache invalidate by MVA to PoC
- #[inline(always)]
- pub unsafe fn dcimvac(&mut self, mva: u32) {
- self.dcimvac.write(mva);
- }
-
- /// D-cache invalidate by set-way
- ///
- /// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
- #[inline(always)]
- pub unsafe fn dcisw(&mut self, set: u16, way: u16) {
- // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way
- // operations have a register data format which depends on the implementation's
- // associativity and number of sets. Specifically the 'way' and 'set' fields have
- // offsets 32-log2(ASSOCIATIVITY) and log2(LINELEN) respectively.
- //
- // However, in Cortex-M7 devices, these offsets are fixed at 30 and 5, as per the Cortex-M7
- // Generic User Guide section 4.8.3. Since no other ARMv7-M implementations except the
- // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the
- // CMSIS-Core implementation and use fixed values.
- self.dcisw.write(
- ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
- | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
- );
- }
-
- /// D-cache clean by MVA to PoU
- #[inline(always)]
- pub fn dccmvau(&mut self, mva: u32) {
- unsafe {
- self.dccmvau.write(mva);
- }
- }
-
- /// D-cache clean by MVA to PoC
- #[inline(always)]
- pub fn dccmvac(&mut self, mva: u32) {
- unsafe {
- self.dccmvac.write(mva);
- }
- }
-
- /// D-cache clean by set-way
- ///
- /// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
- #[inline(always)]
- pub fn dccsw(&mut self, set: u16, way: u16) {
- // See comment for dcisw() about the format here
- unsafe {
- self.dccsw.write(
- ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
- | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
- );
- }
- }
-
- /// D-cache clean and invalidate by MVA to PoC
- #[inline(always)]
- pub fn dccimvac(&mut self, mva: u32) {
- unsafe {
- self.dccimvac.write(mva);
- }
- }
-
- /// D-cache clean and invalidate by set-way
- ///
- /// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
- #[inline(always)]
- pub fn dccisw(&mut self, set: u16, way: u16) {
- // See comment for dcisw() about the format here
- unsafe {
- self.dccisw.write(
- ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
- | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
- );
- }
- }
-
- /// Branch predictor invalidate all
- #[inline(always)]
- pub fn bpiall(&mut self) {
- unsafe {
- self.bpiall.write(0);
- }
- }
-}
diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs
deleted file mode 100644
index db85566..0000000
--- a/src/peripheral/cpuid.rs
+++ /dev/null
@@ -1,140 +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<u32>,
-
- _reserved0: [u32; 15],
-
- /// Processor Feature (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub pfr: [RO<u32>; 2],
- #[cfg(armv6m)]
- _reserved1: [u32; 2],
-
- /// Debug Feature (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub dfr: RO<u32>,
- #[cfg(armv6m)]
- _reserved2: u32,
-
- /// Auxiliary Feature (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub afr: RO<u32>,
- #[cfg(armv6m)]
- _reserved3: u32,
-
- /// Memory Model Feature (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub mmfr: [RO<u32>; 4],
- #[cfg(armv6m)]
- _reserved4: [u32; 4],
-
- /// Instruction Set Attribute (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub isar: [RO<u32>; 5],
- #[cfg(armv6m)]
- _reserved5: [u32; 5],
-
- _reserved6: u32,
-
- /// Cache Level ID (only present on Cortex-M7)
- #[cfg(not(armv6m))]
- pub clidr: RO<u32>,
-
- /// Cache Type (only present on Cortex-M7)
- #[cfg(not(armv6m))]
- pub ctr: RO<u32>,
-
- /// Cache Size ID (only present on Cortex-M7)
- #[cfg(not(armv6m))]
- pub ccsidr: RO<u32>,
-
- /// Cache Size Selection (only present on Cortex-M7)
- #[cfg(not(armv6m))]
- pub csselr: RW<u32>,
-}
-
-/// Type of cache to select on CSSELR writes.
-#[cfg(not(armv6m))]
-#[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,
- )
- }
-
- /// Returns log2 of the number of words in the smallest cache line of all the data cache and
- /// unified caches that are controlled by the processor.
- ///
- /// This is the `DminLine` field of the CTR register.
- #[inline(always)]
- pub fn cache_dminline() -> u32 {
- const CTR_DMINLINE_POS: u32 = 16;
- const CTR_DMINLINE_MASK: u32 = 0xF << CTR_DMINLINE_POS;
- let ctr = unsafe { (*Self::PTR).ctr.read() };
- (ctr & CTR_DMINLINE_MASK) >> CTR_DMINLINE_POS
- }
-
- /// Returns log2 of the number of words in the smallest cache line of all the instruction
- /// caches that are controlled by the processor.
- ///
- /// This is the `IminLine` field of the CTR register.
- #[inline(always)]
- pub fn cache_iminline() -> u32 {
- const CTR_IMINLINE_POS: u32 = 0;
- const CTR_IMINLINE_MASK: u32 = 0xF << CTR_IMINLINE_POS;
- let ctr = unsafe { (*Self::PTR).ctr.read() };
- (ctr & CTR_IMINLINE_MASK) >> CTR_IMINLINE_POS
- }
-}
diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs
deleted file mode 100644
index a4db9fc..0000000
--- a/src/peripheral/dcb.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-//! Debug Control Block
-
-use volatile_register::{RW, WO};
-
-use crate::peripheral::DCB;
-use core::ptr;
-
-const DCB_DEMCR_TRCENA: u32 = 1 << 24;
-const DCB_DEMCR_MON_EN: u32 = 1 << 16;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Debug Halting Control and Status
- pub dhcsr: RW<u32>,
- /// Debug Core Register Selector
- pub dcrsr: WO<u32>,
- /// Debug Core Register Data
- pub dcrdr: RW<u32>,
- /// Debug Exception and Monitor Control
- pub demcr: RW<u32>,
-}
-
-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.
- ///
- /// Note: vendor-specific registers may have to be set to completely
- /// enable tracing. For example, on the STM32F401RE, `TRACE_MODE`
- /// and `TRACE_IOEN` must be configured in `DBGMCU_CR` register.
- #[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);
- }
- }
-
- /// Enables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
- #[inline]
- pub fn enable_debug_monitor(&mut self) {
- unsafe {
- self.demcr.modify(|w| w | DCB_DEMCR_MON_EN);
- }
- }
-
- /// Disables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
- #[inline]
- pub fn disable_debug_monitor(&mut self) {
- unsafe {
- self.demcr.modify(|w| w & !DCB_DEMCR_MON_EN);
- }
- }
-
- /// 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 72575d3..0000000
--- a/src/peripheral/dwt.rs
+++ /dev/null
@@ -1,507 +0,0 @@
-//! Data Watchpoint and Trace unit
-
-#[cfg(not(armv6m))]
-use volatile_register::WO;
-use volatile_register::{RO, RW};
-
-use crate::peripheral::DWT;
-use bitfield::bitfield;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Control
- pub ctrl: RW<Ctrl>,
- /// Cycle Count
- #[cfg(not(armv6m))]
- pub cyccnt: RW<u32>,
- /// CPI Count
- #[cfg(not(armv6m))]
- pub cpicnt: RW<u32>,
- /// Exception Overhead Count
- #[cfg(not(armv6m))]
- pub exccnt: RW<u32>,
- /// Sleep Count
- #[cfg(not(armv6m))]
- pub sleepcnt: RW<u32>,
- /// LSU Count
- #[cfg(not(armv6m))]
- pub lsucnt: RW<u32>,
- /// Folded-instruction Count
- #[cfg(not(armv6m))]
- pub foldcnt: RW<u32>,
- /// Cortex-M0(+) does not have these parts
- #[cfg(armv6m)]
- reserved: [u32; 6],
- /// Program Counter Sample
- pub pcsr: RO<u32>,
- /// 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<u32>,
- /// Lock Status
- #[cfg(not(armv6m))]
- pub lsr: RO<u32>,
-}
-
-bitfield! {
- /// Control register.
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Ctrl(u32);
- cyccntena, set_cyccntena: 0;
- pcsamplena, set_pcsamplena: 12;
- exctrcena, set_exctrcena: 16;
- noprfcnt, _: 24;
- nocyccnt, _: 25;
- noexttrig, _: 26;
- notrcpkt, _: 27;
- u8, numcomp, _: 31, 28;
-}
-
-/// Comparator
-#[repr(C)]
-pub struct Comparator {
- /// Comparator
- pub comp: RW<u32>,
- /// Comparator Mask
- pub mask: RW<u32>,
- /// Comparator Function
- pub function: RW<Function>,
- reserved: u32,
-}
-
-bitfield! {
- #[repr(C)]
- #[derive(Copy, Clone)]
- /// Comparator FUNCTIONn register.
- ///
- /// See C1.8.17 "Comparator Function registers, DWT_FUNCTIONn"
- pub struct Function(u32);
- u8, function, set_function: 3, 0;
- emitrange, set_emitrange: 5;
- cycmatch, set_cycmatch: 7;
- datavmatch, set_datavmatch: 8;
- lnk1ena, set_lnk1ena: 9;
- u8, datavsize, set_datavsize: 11, 10;
- u8, datavaddr0, set_datavaddr0: 15, 12;
- u8, datavaddr1, set_datavaddr1: 19, 16;
- matched, _: 24;
-}
-
-impl DWT {
- /// Number of comparators implemented
- ///
- /// A value of zero indicates no comparator support.
- #[inline]
- pub fn num_comp(&self) -> u8 {
- self.ctrl.read().numcomp()
- }
-
- /// Returns `true` if the the implementation supports sampling and exception tracing
- #[cfg(not(armv6m))]
- #[inline]
- pub fn has_exception_trace(&self) -> bool {
- !self.ctrl.read().notrcpkt()
- }
-
- /// Returns `true` if the implementation includes external match signals
- #[cfg(not(armv6m))]
- #[inline]
- pub fn has_external_match(&self) -> bool {
- !self.ctrl.read().noexttrig()
- }
-
- /// Returns `true` if the implementation supports a cycle counter
- #[inline]
- pub fn has_cycle_counter(&self) -> bool {
- #[cfg(not(armv6m))]
- return !self.ctrl.read().nocyccnt();
-
- #[cfg(armv6m)]
- return false;
- }
-
- /// Returns `true` if the implementation the profiling counters
- #[cfg(not(armv6m))]
- #[inline]
- pub fn has_profiling_counter(&self) -> bool {
- !self.ctrl.read().noprfcnt()
- }
-
- /// Enables the cycle counter
- ///
- /// The global trace enable ([`DCB::enable_trace`]) should be set before
- /// enabling the cycle counter, the processor may ignore writes to the
- /// cycle counter enable if the global trace is disabled
- /// (implementation defined behaviour).
- ///
- /// [`DCB::enable_trace`]: crate::peripheral::DCB::enable_trace
- #[cfg(not(armv6m))]
- #[inline]
- pub fn enable_cycle_counter(&mut self) {
- unsafe {
- self.ctrl.modify(|mut r| {
- r.set_cyccntena(true);
- r
- });
- }
- }
-
- /// Disables the cycle counter
- #[cfg(not(armv6m))]
- #[inline]
- pub fn disable_cycle_counter(&mut self) {
- unsafe {
- self.ctrl.modify(|mut r| {
- r.set_cyccntena(false);
- r
- });
- }
- }
-
- /// Returns `true` if the cycle counter is enabled
- #[cfg(not(armv6m))]
- #[inline]
- pub fn cycle_counter_enabled(&self) -> bool {
- self.ctrl.read().cyccntena()
- }
-
- /// Enables exception tracing
- #[cfg(not(armv6m))]
- #[inline]
- pub fn enable_exception_tracing(&mut self) {
- unsafe {
- self.ctrl.modify(|mut r| {
- r.set_exctrcena(true);
- r
- });
- }
- }
-
- /// Disables exception tracing
- #[cfg(not(armv6m))]
- #[inline]
- pub fn disable_exception_tracing(&mut self) {
- unsafe {
- self.ctrl.modify(|mut r| {
- r.set_exctrcena(false);
- r
- });
- }
- }
-
- /// Whether to periodically generate PC samples
- #[cfg(not(armv6m))]
- #[inline]
- pub fn enable_pc_samples(&mut self, bit: bool) {
- unsafe {
- self.ctrl.modify(|mut r| {
- r.set_pcsamplena(bit);
- r
- });
- }
- }
-
- /// Returns the current clock cycle count
- #[cfg(not(armv6m))]
- #[inline]
- #[deprecated(
- since = "0.7.4",
- note = "Use `cycle_count` which follows the C-GETTER convention"
- )]
- pub fn get_cycle_count() -> u32 {
- Self::cycle_count()
- }
-
- /// Returns the current clock cycle count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn cycle_count() -> u32 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).cyccnt.read() }
- }
-
- /// Set the cycle count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_cycle_count(&mut self, count: u32) {
- unsafe { self.cyccnt.write(count) }
- }
-
- /// 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) }
- }
-
- /// Get the CPI count
- ///
- /// Counts additional cycles required to execute multi-cycle instructions,
- /// except those recorded by [`lsu_count`], and counts any instruction fetch
- /// stalls.
- ///
- /// [`lsu_count`]: DWT::lsu_count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn cpi_count() -> u8 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).cpicnt.read() as u8 }
- }
-
- /// Set the CPI count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_cpi_count(&mut self, count: u8) {
- unsafe { self.cpicnt.write(count as u32) }
- }
-
- /// Get the total cycles spent in exception processing
- #[cfg(not(armv6m))]
- #[inline]
- pub fn exception_count() -> u8 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).exccnt.read() as u8 }
- }
-
- /// Set the exception count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_exception_count(&mut self, count: u8) {
- unsafe { self.exccnt.write(count as u32) }
- }
-
- /// Get the total number of cycles that the processor is sleeping
- ///
- /// ARM recommends that this counter counts all cycles when the processor is sleeping,
- /// regardless of whether a WFI or WFE instruction, or the sleep-on-exit functionality,
- /// caused the entry to sleep mode.
- /// However, all sleep features are implementation defined and therefore when
- /// this counter counts is implementation defined.
- #[cfg(not(armv6m))]
- #[inline]
- pub fn sleep_count() -> u8 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).sleepcnt.read() as u8 }
- }
-
- /// Set the sleep count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_sleep_count(&mut self, count: u8) {
- unsafe { self.sleepcnt.write(count as u32) }
- }
-
- /// Get the additional cycles required to execute all load or store instructions
- #[cfg(not(armv6m))]
- #[inline]
- pub fn lsu_count() -> u8 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).lsucnt.read() as u8 }
- }
-
- /// Set the lsu count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_lsu_count(&mut self, count: u8) {
- unsafe { self.lsucnt.write(count as u32) }
- }
-
- /// Get the folded instruction count
- ///
- /// Increments on each instruction that takes 0 cycles.
- #[cfg(not(armv6m))]
- #[inline]
- pub fn fold_count() -> u8 {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).foldcnt.read() as u8 }
- }
-
- /// Set the folded instruction count
- #[cfg(not(armv6m))]
- #[inline]
- pub fn set_fold_count(&mut self, count: u8) {
- unsafe { self.foldcnt.write(count as u32) }
- }
-}
-
-/// Whether the comparator should match on read, write or read/write operations.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum AccessType {
- /// Generate packet only when matched address is read from.
- ReadOnly,
- /// Generate packet only when matched address is written to.
- WriteOnly,
- /// Generate packet when matched address is both read from and written to.
- ReadWrite,
-}
-
-/// The sequence of packet(s) or events that should be emitted/generated on comparator match.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum EmitOption {
- /// Emit only trace data value packet.
- Data,
- /// Emit only trace address packet.
- Address,
- /// Emit only trace PC value packet
- ///
- /// *NOTE* only compatible with [AccessType::ReadWrite].
- PC,
- /// Emit trace address and data value packets.
- AddressData,
- /// Emit trace PC value and data value packets.
- PCData,
- /// Generate a watchpoint debug event. Either halts execution or fires a `DebugMonitor` exception.
- ///
- /// See more in section "Watchpoint debug event generation" page C1-729.
- WatchpointDebugEvent,
- /// Generate a `CMPMATCH[N]` event.
- ///
- /// See more in section "CMPMATCH[N] event generation" page C1-730.
- CompareMatchEvent,
-}
-
-/// Settings for address matching
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub struct ComparatorAddressSettings {
- /// The address to match against.
- pub address: u32,
- /// The address mask to match against.
- pub mask: u32,
- /// What sequence of packet(s) to emit on comparator match.
- pub emit: EmitOption,
- /// Whether to match on read, write or read/write operations.
- pub access_type: AccessType,
-}
-
-/// Settings for cycle count matching
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub struct CycleCountSettings {
- /// The function selection used.
- /// See Table C1-15 for DWT cycle count comparison functions.
- pub emit: EmitOption,
- /// The cycle count value to compare against.
- pub compare: u32,
-}
-
-/// The available functions of a DWT comparator.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-#[non_exhaustive]
-pub enum ComparatorFunction {
- /// Compare accessed memory addresses.
- Address(ComparatorAddressSettings),
- /// Compare cycle count & target value.
- ///
- /// **NOTE**: only supported by comparator 0 and if the HW supports the cycle counter.
- /// Check [`DWT::has_cycle_counter`] for support. See C1.8.1 for more details.
- CycleCount(CycleCountSettings),
-}
-
-/// Possible error values returned on [Comparator::configure].
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-#[non_exhaustive]
-pub enum DwtError {
- /// Invalid combination of [AccessType] and [EmitOption].
- InvalidFunction,
-}
-
-impl Comparator {
- /// Configure the function of the comparator
- #[allow(clippy::missing_inline_in_public_items)]
- pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
- match settings {
- ComparatorFunction::Address(settings) => {
- // FUNCTION, EMITRANGE
- // See Table C1-14
- let (function, emit_range) = match (&settings.access_type, &settings.emit) {
- (AccessType::ReadOnly, EmitOption::Data) => (0b1100, false),
- (AccessType::ReadOnly, EmitOption::Address) => (0b1100, true),
- (AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true),
- (AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false),
- (AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false),
- (AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false),
-
- (AccessType::WriteOnly, EmitOption::Data) => (0b1101, false),
- (AccessType::WriteOnly, EmitOption::Address) => (0b1101, true),
- (AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true),
- (AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false),
- (AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false),
- (AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false),
-
- (AccessType::ReadWrite, EmitOption::Data) => (0b0010, false),
- (AccessType::ReadWrite, EmitOption::Address) => (0b0001, true),
- (AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true),
- (AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false),
- (AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false),
- (AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false),
-
- (AccessType::ReadWrite, EmitOption::PC) => (0b0001, false),
- (_, EmitOption::PC) => return Err(DwtError::InvalidFunction),
- };
-
- unsafe {
- self.function.modify(|mut r| {
- r.set_function(function);
- r.set_emitrange(emit_range);
- // don't compare data value
- r.set_datavmatch(false);
- // don't compare cycle counter value
- // NOTE: only needed for comparator 0, but is SBZP.
- r.set_cycmatch(false);
- // SBZ as needed, see Page 784/C1-724
- r.set_datavsize(0);
- r.set_datavaddr0(0);
- r.set_datavaddr1(0);
-
- r
- });
-
- self.comp.write(settings.address);
- self.mask.write(settings.mask);
- }
- }
- ComparatorFunction::CycleCount(settings) => {
- let function = match &settings.emit {
- EmitOption::PCData => 0b0001,
- EmitOption::WatchpointDebugEvent => 0b0100,
- EmitOption::CompareMatchEvent => 0b1000,
- _ => return Err(DwtError::InvalidFunction),
- };
-
- unsafe {
- self.function.modify(|mut r| {
- r.set_function(function);
- // emit_range is N/A for cycle count compare
- r.set_emitrange(false);
- // don't compare data
- r.set_datavmatch(false);
- // compare cyccnt
- r.set_cycmatch(true);
- // SBZ as needed, see Page 784/C1-724
- r.set_datavsize(0);
- r.set_datavaddr0(0);
- r.set_datavaddr1(0);
-
- r
- });
-
- self.comp.write(settings.compare);
- self.mask.write(0); // SBZ, see Page 784/C1-724
- }
- }
- }
-
- Ok(())
- }
-}
diff --git a/src/peripheral/fpb.rs b/src/peripheral/fpb.rs
deleted file mode 100644
index b86b8b2..0000000
--- a/src/peripheral/fpb.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//! Flash Patch and Breakpoint unit
-//!
-//! *NOTE* Not available on Armv6-M.
-
-use volatile_register::{RO, RW, WO};
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Control
- pub ctrl: RW<u32>,
- /// Remap
- pub remap: RW<u32>,
- /// Comparator
- pub comp: [RW<u32>; 127],
- reserved: [u32; 875],
- /// Lock Access
- pub lar: WO<u32>,
- /// Lock Status
- pub lsr: RO<u32>,
-}
diff --git a/src/peripheral/fpu.rs b/src/peripheral/fpu.rs
deleted file mode 100644
index 9a047d8..0000000
--- a/src/peripheral/fpu.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! Floating Point Unit
-//!
-//! *NOTE* Available only on targets with a Floating Point Unit (FPU) extension.
-
-use volatile_register::{RO, RW};
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- reserved: u32,
- /// Floating Point Context Control
- pub fpccr: RW<u32>,
- /// Floating Point Context Address
- pub fpcar: RW<u32>,
- /// Floating Point Default Status Control
- pub fpdscr: RW<u32>,
- /// Media and FP Feature
- pub mvfr: [RO<u32>; 3],
-}
diff --git a/src/peripheral/icb.rs b/src/peripheral/icb.rs
deleted file mode 100644
index e1de33b..0000000
--- a/src/peripheral/icb.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//! Implementation Control Block
-
-#[cfg(any(armv7m, armv8m, native))]
-use volatile_register::RO;
-use volatile_register::RW;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Interrupt Controller Type Register
- ///
- /// The bottom four bits of this register give the number of implemented
- /// interrupt lines, divided by 32. So a value of `0b0010` indicates 64
- /// interrupts.
- #[cfg(any(armv7m, armv8m, native))]
- pub ictr: RO<u32>,
-
- /// The ICTR is not defined in the ARMv6-M Architecture Reference manual, so
- /// we replace it with this.
- #[cfg(not(any(armv7m, armv8m, native)))]
- _reserved: u32,
-
- /// Auxiliary Control Register
- ///
- /// This register is entirely implementation defined -- the standard gives
- /// it an address, but does not define its role or contents.
- pub actlr: RW<u32>,
-
- /// Coprocessor Power Control Register
- #[cfg(armv8m)]
- pub cppwr: RW<u32>,
-}
diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs
deleted file mode 100644
index 7291ae0..0000000
--- a/src/peripheral/itm.rs
+++ /dev/null
@@ -1,216 +0,0 @@
-//! Instrumentation Trace Macrocell
-//!
-//! *NOTE* Not available on Armv6-M and Armv8-M Baseline.
-
-use core::cell::UnsafeCell;
-use core::ptr;
-
-use volatile_register::{RO, RW, WO};
-
-use crate::peripheral::ITM;
-use bitfield::bitfield;
-
-#[cfg(feature = "serde")]
-use serde::{Deserialize, Serialize};
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Stimulus Port
- pub stim: [Stim; 256],
- reserved0: [u32; 640],
- /// Trace Enable
- pub ter: [RW<u32>; 8],
- reserved1: [u32; 8],
- /// Trace Privilege
- pub tpr: RW<u32>,
- reserved2: [u32; 15],
- /// Trace Control
- pub tcr: RW<Tcr>,
- reserved3: [u32; 75],
- /// Lock Access
- pub lar: WO<u32>,
- /// Lock Status
- pub lsr: RO<u32>,
-}
-
-bitfield! {
- /// Trace Control Register.
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Tcr(u32);
- itmena, set_itmena: 0;
- tsena, set_tsena: 1;
- syncena, set_synena: 2;
- txena, set_txena: 3;
- swoena, set_swoena: 4;
- u8, tsprescale, set_tsprescale: 9, 8;
- u8, gtsfreq, set_gtsfreq: 11, 10;
- u8, tracebusid, set_tracebusid: 22, 16;
- busy, _: 23;
-}
-
-/// Stimulus Port
-pub struct Stim {
- register: UnsafeCell<u32>,
-}
-
-impl Stim {
- /// Writes an `u8` payload into the stimulus port
- #[inline]
- pub fn write_u8(&mut self, value: u8) {
- unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) }
- }
-
- /// Writes an `u16` payload into the stimulus port
- #[inline]
- pub fn write_u16(&mut self, value: u16) {
- unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) }
- }
-
- /// Writes an `u32` payload into the stimulus port
- #[inline]
- pub fn write_u32(&mut self, value: u32) {
- unsafe { ptr::write_volatile(self.register.get(), value) }
- }
-
- /// Returns `true` if the stimulus port is ready to accept more data
- #[cfg(not(armv8m))]
- #[inline]
- pub fn is_fifo_ready(&self) -> bool {
- unsafe { ptr::read_volatile(self.register.get()) & 0b1 == 1 }
- }
-
- /// Returns `true` if the stimulus port is ready to accept more data
- #[cfg(armv8m)]
- #[inline]
- pub fn is_fifo_ready(&self) -> bool {
- // ARMv8-M adds a disabled bit; we indicate that we are ready to
- // proceed with a stimulus write if the port is either ready (bit 0) or
- // disabled (bit 1).
- unsafe { ptr::read_volatile(self.register.get()) & 0b11 != 0 }
- }
-}
-
-/// The possible local timestamp options.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub enum LocalTimestampOptions {
- /// Disable local timestamps.
- Disabled,
- /// Enable local timestamps and use no prescaling.
- Enabled,
- /// Enable local timestamps and set the prescaler to divide the
- /// reference clock by 4.
- EnabledDiv4,
- /// Enable local timestamps and set the prescaler to divide the
- /// reference clock by 16.
- EnabledDiv16,
- /// Enable local timestamps and set the prescaler to divide the
- /// reference clock by 64.
- EnabledDiv64,
-}
-
-#[cfg(feature = "std")]
-impl core::convert::TryFrom<u8> for LocalTimestampOptions {
- type Error = ();
-
- /// Converts an integer value to an enabled [LocalTimestampOptions]
- /// variant. Accepted values are: 1, 4, 16, 64. Any other value
- /// yields `Err(())`.
- #[inline]
- fn try_from(value: u8) -> Result<Self, Self::Error> {
- match value {
- 1 => Ok(Self::Enabled),
- 4 => Ok(Self::EnabledDiv4),
- 16 => Ok(Self::EnabledDiv16),
- 64 => Ok(Self::EnabledDiv64),
- _ => Err(()),
- }
- }
-}
-
-/// The possible global timestamp options.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum GlobalTimestampOptions {
- /// Disable global timestamps.
- Disabled,
- /// Generate a global timestamp approximately every 128 cycles.
- Every128Cycles,
- /// Generate a global timestamp approximately every 8921 cycles.
- Every8192Cycles,
- /// Generate a global timestamp after every packet, if the output FIFO is empty.
- EveryPacket,
-}
-
-/// The possible clock sources for timestamp counters.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum TimestampClkSrc {
- /// Clock timestamp counters using the system processor clock.
- SystemClock,
- /// Clock timestamp counters using the asynchronous clock from the
- /// TPIU interface.
- ///
- /// NOTE: The timestamp counter is held in reset while the output
- /// line is idle.
- AsyncTPIU,
-}
-
-/// Available settings for the ITM peripheral.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub struct ITMSettings {
- /// Whether to enable ITM.
- pub enable: bool,
- /// Whether DWT packets should be forwarded to ITM.
- pub forward_dwt: bool,
- /// The local timestamp options that should be applied.
- pub local_timestamps: LocalTimestampOptions,
- /// The global timestamp options that should be applied.
- pub global_timestamps: GlobalTimestampOptions,
- /// The trace bus ID to use when multi-trace sources are in use.
- /// `None` specifies that only a single trace source is in use and
- /// has the same effect as `Some(0)`.
- pub bus_id: Option<u8>,
- /// The clock that should increase timestamp counters.
- pub timestamp_clk_src: TimestampClkSrc,
-}
-
-impl ITM {
- /// Removes the software lock on the ITM.
- #[inline]
- pub fn unlock(&mut self) {
- // NOTE(unsafe) atomic write to a stateless, write-only register
- unsafe { self.lar.write(0xC5AC_CE55) }
- }
-
- /// Configures the ITM with the passed [ITMSettings].
- #[inline]
- pub fn configure(&mut self, settings: ITMSettings) {
- unsafe {
- self.tcr.modify(|mut r| {
- r.set_itmena(settings.enable);
- r.set_tsena(settings.local_timestamps != LocalTimestampOptions::Disabled);
- r.set_txena(settings.forward_dwt);
- r.set_tsprescale(match settings.local_timestamps {
- LocalTimestampOptions::Disabled | LocalTimestampOptions::Enabled => 0b00,
- LocalTimestampOptions::EnabledDiv4 => 0b10,
- LocalTimestampOptions::EnabledDiv16 => 0b10,
- LocalTimestampOptions::EnabledDiv64 => 0b11,
- });
- r.set_gtsfreq(match settings.global_timestamps {
- GlobalTimestampOptions::Disabled => 0b00,
- GlobalTimestampOptions::Every128Cycles => 0b01,
- GlobalTimestampOptions::Every8192Cycles => 0b10,
- GlobalTimestampOptions::EveryPacket => 0b11,
- });
- r.set_swoena(match settings.timestamp_clk_src {
- TimestampClkSrc::SystemClock => false,
- TimestampClkSrc::AsyncTPIU => true,
- });
- r.set_tracebusid(settings.bus_id.unwrap_or(0));
-
- r
- });
- }
- }
-}
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
deleted file mode 100644
index bf18151..0000000
--- a/src/peripheral/mod.rs
+++ /dev/null
@@ -1,592 +0,0 @@
-//! Core peripherals.
-//!
-//! # API
-//!
-//! To use (most of) the peripheral API first you must get an *instance* of the peripheral. All the
-//! core peripherals are modeled as singletons (there can only ever be, at most, one instance of any
-//! one of them at any given point in time) and the only way to get an instance of them is through
-//! the [`Peripherals::take`](struct.Peripherals.html#method.take) method.
-//!
-//! ``` no_run
-//! # use cortex_m::peripheral::Peripherals;
-//! let mut peripherals = Peripherals::take().unwrap();
-//! peripherals.DCB.enable_trace();
-//! ```
-//!
-//! This method can only be successfully called *once* -- this is why the method returns an
-//! `Option`. Subsequent calls to the method will result in a `None` value being returned.
-//!
-//! ``` no_run, should_panic
-//! # use cortex_m::peripheral::Peripherals;
-//! let ok = Peripherals::take().unwrap();
-//! let panics = Peripherals::take().unwrap();
-//! ```
-//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
-//! API is provided as static methods on the peripheral types. One example is the
-//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method.
-//!
-//! ``` no_run
-//! # use cortex_m::peripheral::{DWT, Peripherals};
-//! {
-//! let mut peripherals = Peripherals::take().unwrap();
-//! peripherals.DCB.enable_trace();
-//! peripherals.DWT.enable_cycle_counter();
-//! } // all the peripheral singletons are destroyed here
-//!
-//! // but this method can be called without a DWT instance
-//! let cyccnt = DWT::cycle_count();
-//! ```
-//!
-//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
-//! available on all the peripheral types. This method is a useful building block for implementing
-//! safe higher level abstractions.
-//!
-//! ``` no_run
-//! # use cortex_m::peripheral::{DWT, Peripherals};
-//! {
-//! let mut peripherals = Peripherals::take().unwrap();
-//! peripherals.DCB.enable_trace();
-//! peripherals.DWT.enable_cycle_counter();
-//! } // all the peripheral singletons are destroyed here
-//!
-//! // actually safe because this is an atomic read with no side effects
-//! let cyccnt = unsafe { (*DWT::PTR).cyccnt.read() };
-//! ```
-//!
-//! # References
-//!
-//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
-
-use core::marker::PhantomData;
-use core::ops;
-
-#[cfg(cm7)]
-pub mod ac;
-#[cfg(not(armv6m))]
-pub mod cbp;
-pub mod cpuid;
-pub mod dcb;
-pub mod dwt;
-#[cfg(not(armv6m))]
-pub mod fpb;
-// NOTE(native) is for documentation purposes
-#[cfg(any(has_fpu, native))]
-pub mod fpu;
-pub mod icb;
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-pub mod itm;
-pub mod mpu;
-pub mod nvic;
-#[cfg(armv8m)]
-pub mod sau;
-pub mod scb;
-pub mod syst;
-#[cfg(not(armv6m))]
-pub mod tpiu;
-
-#[cfg(test)]
-mod test;
-
-// NOTE the `PhantomData` used in the peripherals proxy is to make them `Send` but *not* `Sync`
-
-/// Core peripherals
-#[allow(non_snake_case)]
-#[allow(clippy::manual_non_exhaustive)]
-pub struct Peripherals {
- /// Cortex-M7 TCM and cache access control.
- #[cfg(cm7)]
- pub AC: AC,
-
- /// Cache and branch predictor maintenance operations.
- /// Not available on Armv6-M.
- pub CBP: CBP,
-
- /// CPUID
- pub CPUID: CPUID,
-
- /// Debug Control Block
- pub DCB: DCB,
-
- /// Data Watchpoint and Trace unit
- pub DWT: DWT,
-
- /// Flash Patch and Breakpoint unit.
- /// Not available on Armv6-M.
- pub FPB: FPB,
-
- /// Floating Point Unit.
- pub FPU: FPU,
-
- /// Implementation Control Block.
- ///
- /// The name is from the v8-M spec, but the block existed in earlier
- /// revisions, without a name.
- pub ICB: ICB,
-
- /// Instrumentation Trace Macrocell.
- /// Not available on Armv6-M and Armv8-M Baseline.
- pub ITM: ITM,
-
- /// Memory Protection Unit
- pub MPU: MPU,
-
- /// Nested Vector Interrupt Controller
- pub NVIC: NVIC,
-
- /// Security Attribution Unit
- pub SAU: SAU,
-
- /// System Control Block
- pub SCB: SCB,
-
- /// SysTick: System Timer
- pub SYST: SYST,
-
- /// Trace Port Interface Unit.
- /// Not available on Armv6-M.
- pub TPIU: TPIU,
-
- // Private field making `Peripherals` non-exhaustive. We don't use `#[non_exhaustive]` so we
- // can support older Rust versions.
- _priv: (),
-}
-
-// 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;
-
-impl Peripherals {
- /// Returns all the core peripherals *once*
- #[inline]
- pub fn take() -> Option<Self> {
- critical_section::with(|_| {
- if unsafe { TAKEN } {
- None
- } else {
- Some(unsafe { Peripherals::steal() })
- }
- })
- }
-
- /// Unchecked version of `Peripherals::take`
- #[inline]
- pub unsafe fn steal() -> Self {
- TAKEN = true;
-
- Peripherals {
- #[cfg(cm7)]
- AC: AC {
- _marker: PhantomData,
- },
- CBP: CBP {
- _marker: PhantomData,
- },
- CPUID: CPUID {
- _marker: PhantomData,
- },
- DCB: DCB {
- _marker: PhantomData,
- },
- DWT: DWT {
- _marker: PhantomData,
- },
- FPB: FPB {
- _marker: PhantomData,
- },
- FPU: FPU {
- _marker: PhantomData,
- },
- ICB: ICB {
- _marker: PhantomData,
- },
- ITM: ITM {
- _marker: PhantomData,
- },
- MPU: MPU {
- _marker: PhantomData,
- },
- NVIC: NVIC {
- _marker: PhantomData,
- },
- SAU: SAU {
- _marker: PhantomData,
- },
- SCB: SCB {
- _marker: PhantomData,
- },
- SYST: SYST {
- _marker: PhantomData,
- },
- TPIU: TPIU {
- _marker: PhantomData,
- },
- _priv: (),
- }
- }
-}
-
-/// Access control
-#[cfg(cm7)]
-pub struct AC {
- _marker: PhantomData<*const ()>,
-}
-
-#[cfg(cm7)]
-unsafe impl Send for AC {}
-
-#[cfg(cm7)]
-impl AC {
- /// Pointer to the register block
- pub const PTR: *const self::ac::RegisterBlock = 0xE000_EF90 as *const _;
-}
-
-/// Cache and branch predictor maintenance operations
-#[allow(clippy::upper_case_acronyms)]
-pub struct CBP {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for CBP {}
-
-#[cfg(not(armv6m))]
-impl CBP {
- #[inline(always)]
- pub(crate) const unsafe fn new() -> Self {
- CBP {
- _marker: PhantomData,
- }
- }
-
- /// Pointer to the register block
- pub const PTR: *const self::cbp::RegisterBlock = 0xE000_EF50 as *const _;
-}
-
-#[cfg(not(armv6m))]
-impl ops::Deref for CBP {
- type Target = self::cbp::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// CPUID
-#[allow(clippy::upper_case_acronyms)]
-pub struct CPUID {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for CPUID {}
-
-impl CPUID {
- /// Pointer to the register block
- pub const 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
-#[allow(clippy::upper_case_acronyms)]
-pub struct DCB {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for DCB {}
-
-impl DCB {
- /// Pointer to the register block
- pub const 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
-#[allow(clippy::upper_case_acronyms)]
-pub struct DWT {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for DWT {}
-
-impl DWT {
- /// Pointer to the register block
- pub const 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
-#[allow(clippy::upper_case_acronyms)]
-pub struct FPB {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for FPB {}
-
-#[cfg(not(armv6m))]
-impl FPB {
- /// Pointer to the register block
- pub const 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
-#[allow(clippy::upper_case_acronyms)]
-pub struct FPU {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for FPU {}
-
-#[cfg(any(has_fpu, native))]
-impl FPU {
- /// Pointer to the register block
- pub const PTR: *const fpu::RegisterBlock = 0xE000_EF30 as *const _;
-}
-
-#[cfg(any(has_fpu, native))]
-impl ops::Deref for FPU {
- type Target = self::fpu::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// Implementation Control Block.
-///
-/// This block contains implementation-defined registers like `ictr` and
-/// `actlr`. It's called the "implementation control block" in the ARMv8-M
-/// standard, but earlier standards contained the registers, just without a
-/// name.
-#[allow(clippy::upper_case_acronyms)]
-pub struct ICB {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for ICB {}
-
-impl ICB {
- /// Pointer to the register block
- pub const PTR: *mut icb::RegisterBlock = 0xE000_E004 as *mut _;
-}
-
-impl ops::Deref for ICB {
- type Target = self::icb::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-impl ops::DerefMut for ICB {
- #[inline(always)]
- fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe { &mut *Self::PTR }
- }
-}
-
-/// Instrumentation Trace Macrocell
-#[allow(clippy::upper_case_acronyms)]
-pub struct ITM {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for ITM {}
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-impl ITM {
- /// Pointer to the register block
- pub const PTR: *mut itm::RegisterBlock = 0xE000_0000 as *mut _;
-}
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-impl ops::Deref for ITM {
- type Target = self::itm::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-impl ops::DerefMut for ITM {
- #[inline(always)]
- fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe { &mut *Self::PTR }
- }
-}
-
-/// Memory Protection Unit
-#[allow(clippy::upper_case_acronyms)]
-pub struct MPU {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for MPU {}
-
-impl MPU {
- /// Pointer to the register block
- pub const PTR: *const mpu::RegisterBlock = 0xE000_ED90 as *const _;
-}
-
-impl ops::Deref for MPU {
- type Target = self::mpu::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// Nested Vector Interrupt Controller
-#[allow(clippy::upper_case_acronyms)]
-pub struct NVIC {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for NVIC {}
-
-impl NVIC {
- /// Pointer to the register block
- pub const PTR: *const nvic::RegisterBlock = 0xE000_E100 as *const _;
-}
-
-impl ops::Deref for NVIC {
- type Target = self::nvic::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// Security Attribution Unit
-#[allow(clippy::upper_case_acronyms)]
-pub struct SAU {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for SAU {}
-
-#[cfg(armv8m)]
-impl SAU {
- /// Pointer to the register block
- pub const PTR: *const sau::RegisterBlock = 0xE000_EDD0 as *const _;
-}
-
-#[cfg(armv8m)]
-impl ops::Deref for SAU {
- type Target = self::sau::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// System Control Block
-#[allow(clippy::upper_case_acronyms)]
-pub struct SCB {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for SCB {}
-
-impl SCB {
- /// Pointer to the register block
- pub const PTR: *const scb::RegisterBlock = 0xE000_ED04 as *const _;
-}
-
-impl ops::Deref for SCB {
- type Target = self::scb::RegisterBlock;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- unsafe { &*Self::PTR }
- }
-}
-
-/// SysTick: System Timer
-#[allow(clippy::upper_case_acronyms)]
-pub struct SYST {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for SYST {}
-
-impl SYST {
- /// Pointer to the register block
- pub const 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
-#[allow(clippy::upper_case_acronyms)]
-pub struct TPIU {
- _marker: PhantomData<*const ()>,
-}
-
-unsafe impl Send for TPIU {}
-
-#[cfg(not(armv6m))]
-impl TPIU {
- /// Pointer to the register block
- pub const 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/mpu.rs b/src/peripheral/mpu.rs
deleted file mode 100644
index 3a5f5b4..0000000
--- a/src/peripheral/mpu.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-//! Memory Protection Unit
-
-use volatile_register::{RO, RW};
-
-/// Register block for ARMv7-M
-#[cfg(not(armv8m))]
-#[repr(C)]
-pub struct RegisterBlock {
- /// Type
- pub _type: RO<u32>,
- /// Control
- pub ctrl: RW<u32>,
- /// Region Number
- pub rnr: RW<u32>,
- /// Region Base Address
- pub rbar: RW<u32>,
- /// Region Attribute and Size
- pub rasr: RW<u32>,
- /// Alias 1 of RBAR
- pub rbar_a1: RW<u32>,
- /// Alias 1 of RASR
- pub rasr_a1: RW<u32>,
- /// Alias 2 of RBAR
- pub rbar_a2: RW<u32>,
- /// Alias 2 of RASR
- pub rasr_a2: RW<u32>,
- /// Alias 3 of RBAR
- pub rbar_a3: RW<u32>,
- /// Alias 3 of RASR
- pub rasr_a3: RW<u32>,
-}
-
-/// Register block for ARMv8-M
-#[cfg(armv8m)]
-#[repr(C)]
-pub struct RegisterBlock {
- /// Type
- pub _type: RO<u32>,
- /// Control
- pub ctrl: RW<u32>,
- /// Region Number
- pub rnr: RW<u32>,
- /// Region Base Address
- pub rbar: RW<u32>,
- /// Region Limit Address
- pub rlar: RW<u32>,
- /// Alias 1 of RBAR
- pub rbar_a1: RW<u32>,
- /// Alias 1 of RLAR
- pub rlar_a1: RW<u32>,
- /// Alias 2 of RBAR
- pub rbar_a2: RW<u32>,
- /// Alias 2 of RLAR
- pub rlar_a2: RW<u32>,
- /// Alias 3 of RBAR
- pub rbar_a3: RW<u32>,
- /// Alias 3 of RLAR
- pub rlar_a3: RW<u32>,
-
- // Reserved word at offset 0xBC
- _reserved: u32,
-
- /// Memory Attribute Indirection register 0 and 1
- pub mair: [RW<u32>; 2],
-}
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
deleted file mode 100644
index fccd6a2..0000000
--- a/src/peripheral/nvic.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-//! Nested Vector Interrupt Controller
-
-use volatile_register::RW;
-#[cfg(not(armv6m))]
-use volatile_register::{RO, WO};
-
-use crate::interrupt::InterruptNumber;
-use crate::peripheral::NVIC;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Interrupt Set-Enable
- pub iser: [RW<u32>; 16],
-
- _reserved0: [u32; 16],
-
- /// Interrupt Clear-Enable
- pub icer: [RW<u32>; 16],
-
- _reserved1: [u32; 16],
-
- /// Interrupt Set-Pending
- pub ispr: [RW<u32>; 16],
-
- _reserved2: [u32; 16],
-
- /// Interrupt Clear-Pending
- pub icpr: [RW<u32>; 16],
-
- _reserved3: [u32; 16],
-
- /// Interrupt Active Bit (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub iabr: [RO<u32>; 16],
- #[cfg(armv6m)]
- _reserved4: [u32; 16],
-
- _reserved5: [u32; 16],
-
- #[cfg(armv8m)]
- /// Interrupt Target Non-secure (only present on Arm v8-M)
- pub itns: [RW<u32>; 16],
- #[cfg(not(armv8m))]
- _reserved6: [u32; 16],
-
- _reserved7: [u32; 16],
-
- /// Interrupt Priority
- ///
- /// On ARMv7-M, 124 word-sized registers are available. Each of those
- /// contains of 4 interrupt priorities of 8 byte each.The architecture
- /// specifically allows accessing those along byte boundaries, so they are
- /// represented as 496 byte-sized registers, for convenience, and to allow
- /// atomic priority updates.
- ///
- /// On ARMv6-M, the registers must only be accessed along word boundaries,
- /// so convenient byte-sized representation wouldn't work on that
- /// architecture.
- #[cfg(not(armv6m))]
- pub ipr: [RW<u8>; 496],
-
- /// Interrupt Priority
- ///
- /// On ARMv7-M, 124 word-sized registers are available. Each of those
- /// contains of 4 interrupt priorities of 8 byte each.The architecture
- /// specifically allows accessing those along byte boundaries, so they are
- /// represented as 496 byte-sized registers, for convenience, and to allow
- /// atomic priority updates.
- ///
- /// On ARMv6-M, the registers must only be accessed along word boundaries,
- /// so convenient byte-sized representation wouldn't work on that
- /// architecture.
- #[cfg(armv6m)]
- pub ipr: [RW<u32>; 8],
-
- #[cfg(not(armv6m))]
- _reserved8: [u32; 580],
-
- /// Software Trigger Interrupt
- #[cfg(not(armv6m))]
- pub stir: WO<u32>,
-}
-
-impl NVIC {
- /// Request an IRQ in software
- ///
- /// Writing a value to the INTID field is the same as manually pending an interrupt by setting
- /// the corresponding interrupt bit in an Interrupt Set Pending Register. This is similar to
- /// [`NVIC::pend`].
- ///
- /// This method is not available on ARMv6-M chips.
- ///
- /// [`NVIC::pend`]: #method.pend
- #[cfg(not(armv6m))]
- #[inline]
- pub fn request<I>(interrupt: I)
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
-
- // NOTE(ptr) this is a write to a stateless register
- unsafe { (*Self::PTR).stir.write(u32::from(nr)) }
- }
-
- /// Disables `interrupt`
- #[inline]
- pub fn mask<I>(interrupt: I)
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
- // NOTE(unsafe) this is a write to a stateless register
- unsafe { (*Self::PTR).icer[usize::from(nr / 32)].write(1 << (nr % 32)) }
- }
-
- /// Enables `interrupt`
- ///
- /// This function is `unsafe` because it can break mask-based critical sections
- #[inline]
- pub unsafe fn unmask<I>(interrupt: I)
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
- // NOTE(ptr) this is a write to a stateless register
- (*Self::PTR).iser[usize::from(nr / 32)].write(1 << (nr % 32))
- }
-
- /// Returns the NVIC priority of `interrupt`
- ///
- /// *NOTE* NVIC encodes priority in the highest bits of a byte so values like `1` and `2` map
- /// to the same priority. Also for NVIC priorities, a lower value (e.g. `16`) has higher
- /// priority (urgency) than a larger value (e.g. `32`).
- #[inline]
- pub fn get_priority<I>(interrupt: I) -> u8
- where
- I: InterruptNumber,
- {
- #[cfg(not(armv6m))]
- {
- let nr = interrupt.number();
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).ipr[usize::from(nr)].read() }
- }
-
- #[cfg(armv6m)]
- {
- // NOTE(unsafe) atomic read with no side effects
- let ipr_n = unsafe { (*Self::PTR).ipr[Self::ipr_index(interrupt)].read() };
- let prio = (ipr_n >> Self::ipr_shift(interrupt)) & 0x0000_00ff;
- prio as u8
- }
- }
-
- /// Is `interrupt` active or pre-empted and stacked
- #[cfg(not(armv6m))]
- #[inline]
- pub fn is_active<I>(interrupt: I) -> bool
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
- let mask = 1 << (nr % 32);
-
- // NOTE(unsafe) atomic read with no side effects
- unsafe { ((*Self::PTR).iabr[usize::from(nr / 32)].read() & mask) == mask }
- }
-
- /// Checks if `interrupt` is enabled
- #[inline]
- pub fn is_enabled<I>(interrupt: I) -> bool
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
- let mask = 1 << (nr % 32);
-
- // NOTE(unsafe) atomic read with no side effects
- unsafe { ((*Self::PTR).iser[usize::from(nr / 32)].read() & mask) == mask }
- }
-
- /// Checks if `interrupt` is pending
- #[inline]
- pub fn is_pending<I>(interrupt: I) -> bool
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
- let mask = 1 << (nr % 32);
-
- // NOTE(unsafe) atomic read with no side effects
- unsafe { ((*Self::PTR).ispr[usize::from(nr / 32)].read() & mask) == mask }
- }
-
- /// Forces `interrupt` into pending state
- #[inline]
- pub fn pend<I>(interrupt: I)
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
-
- // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
- unsafe { (*Self::PTR).ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
- }
-
- /// Sets the "priority" of `interrupt` to `prio`
- ///
- /// *NOTE* See [`get_priority`](struct.NVIC.html#method.get_priority) method for an explanation
- /// of how NVIC priorities work.
- ///
- /// On ARMv6-M, updating an interrupt priority requires a read-modify-write operation. On
- /// ARMv7-M, the operation is performed in a single atomic write operation.
- ///
- /// # Unsafety
- ///
- /// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](crate::register::basepri)) and compromise memory safety.
- #[inline]
- pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
- where
- I: InterruptNumber,
- {
- #[cfg(not(armv6m))]
- {
- let nr = interrupt.number();
- self.ipr[usize::from(nr)].write(prio)
- }
-
- #[cfg(armv6m)]
- {
- self.ipr[Self::ipr_index(interrupt)].modify(|value| {
- let mask = 0x0000_00ff << Self::ipr_shift(interrupt);
- let prio = u32::from(prio) << Self::ipr_shift(interrupt);
-
- (value & !mask) | prio
- })
- }
- }
-
- /// Clears `interrupt`'s pending state
- #[inline]
- pub fn unpend<I>(interrupt: I)
- where
- I: InterruptNumber,
- {
- let nr = interrupt.number();
-
- // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
- unsafe { (*Self::PTR).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
- }
-
- #[cfg(armv6m)]
- #[inline]
- fn ipr_index<I>(interrupt: I) -> usize
- where
- I: InterruptNumber,
- {
- usize::from(interrupt.number()) / 4
- }
-
- #[cfg(armv6m)]
- #[inline]
- fn ipr_shift<I>(interrupt: I) -> usize
- where
- I: InterruptNumber,
- {
- (usize::from(interrupt.number()) % 4) * 8
- }
-}
diff --git a/src/peripheral/sau.rs b/src/peripheral/sau.rs
deleted file mode 100644
index 6b8477f..0000000
--- a/src/peripheral/sau.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-//! Security Attribution Unit
-//!
-//! *NOTE* Available only on Armv8-M and Armv8.1-M, for the following Rust target triples:
-//! * `thumbv8m.base-none-eabi`
-//! * `thumbv8m.main-none-eabi`
-//! * `thumbv8m.main-none-eabihf`
-//!
-//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual.
-
-use crate::peripheral::SAU;
-use bitfield::bitfield;
-use volatile_register::{RO, RW};
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Control Register
- pub ctrl: RW<Ctrl>,
- /// Type Register
- pub _type: RO<Type>,
- /// Region Number Register
- pub rnr: RW<Rnr>,
- /// Region Base Address Register
- pub rbar: RW<Rbar>,
- /// Region Limit Address Register
- pub rlar: RW<Rlar>,
- /// Secure Fault Status Register
- pub sfsr: RO<Sfsr>,
- /// Secure Fault Address Register
- pub sfar: RO<Sfar>,
-}
-
-bitfield! {
- /// Control Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Ctrl(u32);
- get_enable, set_enable: 0;
- get_allns, set_allns: 1;
-}
-
-bitfield! {
- /// Type Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Type(u32);
- u8;
- sregion, _: 7, 0;
-}
-
-bitfield! {
- /// Region Number Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Rnr(u32);
- u8;
- get_region, set_region: 7, 0;
-}
-
-bitfield! {
- /// Region Base Address Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Rbar(u32);
- u32;
- get_baddr, set_baddr: 31, 5;
-}
-
-bitfield! {
- /// Region Limit Address Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Rlar(u32);
- u32;
- get_laddr, set_laddr: 31, 5;
- get_nsc, set_nsc: 1;
- get_enable, set_enable: 0;
-}
-
-bitfield! {
- /// Secure Fault Status Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Sfsr(u32);
- invep, _: 0;
- invis, _: 1;
- inver, _: 2;
- auviol, _: 3;
- invtran, _: 4;
- lsperr, _: 5;
- sfarvalid, _: 6;
- lserr, _: 7;
-}
-
-bitfield! {
- /// Secure Fault Address Register description
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct Sfar(u32);
- u32;
- address, _: 31, 0;
-}
-
-/// Possible attribute of a SAU region.
-#[derive(Debug)]
-pub enum SauRegionAttribute {
- /// SAU region is Secure
- Secure,
- /// SAU region is Non-Secure Callable
- NonSecureCallable,
- /// SAU region is Non-Secure
- NonSecure,
-}
-
-/// Description of a SAU region.
-#[derive(Debug)]
-pub struct SauRegion {
- /// First address of the region, its 5 least significant bits must be set to zero.
- pub base_address: u32,
- /// Last address of the region, its 5 least significant bits must be set to one.
- pub limit_address: u32,
- /// Attribute of the region.
- pub attribute: SauRegionAttribute,
-}
-
-/// Possible error values returned by the SAU methods.
-#[derive(Debug)]
-pub enum SauError {
- /// The region number parameter to set or get a region must be between 0 and
- /// region_numbers() - 1.
- RegionNumberTooBig,
- /// Bits 0 to 4 of the base address of a SAU region must be set to zero.
- WrongBaseAddress,
- /// Bits 0 to 4 of the limit address of a SAU region must be set to one.
- WrongLimitAddress,
-}
-
-impl SAU {
- /// Get the number of implemented SAU regions.
- #[inline]
- pub fn region_numbers(&self) -> u8 {
- self._type.read().sregion()
- }
-
- /// Enable the SAU.
- #[inline]
- pub fn enable(&mut self) {
- unsafe {
- self.ctrl.modify(|mut ctrl| {
- ctrl.set_enable(true);
- ctrl
- });
- }
- }
-
- /// Set a SAU region to a region number.
- /// SAU regions must be 32 bytes aligned and their sizes must be a multiple of 32 bytes. It
- /// means that the 5 least significant bits of the base address of a SAU region must be set to
- /// zero and the 5 least significant bits of the limit address must be set to one.
- /// The region number must be valid.
- /// This function is executed under a critical section to prevent having inconsistent results.
- #[inline]
- pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
- critical_section::with(|_| {
- let base_address = region.base_address;
- let limit_address = region.limit_address;
- let attribute = region.attribute;
-
- if region_number >= self.region_numbers() {
- Err(SauError::RegionNumberTooBig)
- } else if base_address & 0x1F != 0 {
- Err(SauError::WrongBaseAddress)
- } else if limit_address & 0x1F != 0x1F {
- Err(SauError::WrongLimitAddress)
- } else {
- // All fields of these registers are going to be modified so we don't need to read them
- // before.
- let mut rnr = Rnr(0);
- let mut rbar = Rbar(0);
- let mut rlar = Rlar(0);
-
- rnr.set_region(region_number);
- rbar.set_baddr(base_address >> 5);
- rlar.set_laddr(limit_address >> 5);
-
- match attribute {
- SauRegionAttribute::Secure => {
- rlar.set_nsc(false);
- rlar.set_enable(false);
- }
- SauRegionAttribute::NonSecureCallable => {
- rlar.set_nsc(true);
- rlar.set_enable(true);
- }
- SauRegionAttribute::NonSecure => {
- rlar.set_nsc(false);
- rlar.set_enable(true);
- }
- }
-
- unsafe {
- self.rnr.write(rnr);
- self.rbar.write(rbar);
- self.rlar.write(rlar);
- }
-
- Ok(())
- }
- })
- }
-
- /// Get a region from the SAU.
- /// The region number must be valid.
- /// This function is executed under a critical section to prevent having inconsistent results.
- #[inline]
- pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
- critical_section::with(|_| {
- if region_number >= self.region_numbers() {
- Err(SauError::RegionNumberTooBig)
- } else {
- unsafe {
- self.rnr.write(Rnr(region_number.into()));
- }
-
- let rbar = self.rbar.read();
- let rlar = self.rlar.read();
-
- let attribute = match (rlar.get_enable(), rlar.get_nsc()) {
- (false, _) => SauRegionAttribute::Secure,
- (true, false) => SauRegionAttribute::NonSecure,
- (true, true) => SauRegionAttribute::NonSecureCallable,
- };
-
- Ok(SauRegion {
- base_address: rbar.get_baddr() << 5,
- limit_address: (rlar.get_laddr() << 5) | 0x1F,
- attribute,
- })
- }
- })
- }
-}
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
deleted file mode 100644
index b9cf0e4..0000000
--- a/src/peripheral/scb.rs
+++ /dev/null
@@ -1,1110 +0,0 @@
-//! System Control Block
-
-use core::ptr;
-
-use volatile_register::RW;
-
-#[cfg(not(armv6m))]
-use super::cpuid::CsselrCacheType;
-#[cfg(not(armv6m))]
-use super::CBP;
-#[cfg(not(armv6m))]
-use super::CPUID;
-use super::SCB;
-#[cfg(feature = "serde")]
-use serde::{Deserialize, Serialize};
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Interrupt Control and State
- pub icsr: RW<u32>,
-
- /// Vector Table Offset (not present on Cortex-M0 variants)
- pub vtor: RW<u32>,
-
- /// Application Interrupt and Reset Control
- pub aircr: RW<u32>,
-
- /// System Control
- pub scr: RW<u32>,
-
- /// Configuration and Control
- pub ccr: RW<u32>,
-
- /// System Handler Priority (word accessible only on Cortex-M0 variants)
- ///
- /// On ARMv7-M, `shpr[0]` points to SHPR1
- ///
- /// On ARMv6-M, `shpr[0]` points to SHPR2
- #[cfg(not(armv6m))]
- pub shpr: [RW<u8>; 12],
- #[cfg(armv6m)]
- _reserved1: u32,
- /// System Handler Priority (word accessible only on Cortex-M0 variants)
- ///
- /// On ARMv7-M, `shpr[0]` points to SHPR1
- ///
- /// On ARMv6-M, `shpr[0]` points to SHPR2
- #[cfg(armv6m)]
- pub shpr: [RW<u32>; 2],
-
- /// System Handler Control and State
- pub shcsr: RW<u32>,
-
- /// Configurable Fault Status (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub cfsr: RW<u32>,
- #[cfg(armv6m)]
- _reserved2: u32,
-
- /// HardFault Status (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub hfsr: RW<u32>,
- #[cfg(armv6m)]
- _reserved3: u32,
-
- /// Debug Fault Status (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub dfsr: RW<u32>,
- #[cfg(armv6m)]
- _reserved4: u32,
-
- /// MemManage Fault Address (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub mmfar: RW<u32>,
- #[cfg(armv6m)]
- _reserved5: u32,
-
- /// BusFault Address (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub bfar: RW<u32>,
- #[cfg(armv6m)]
- _reserved6: u32,
-
- /// Auxiliary Fault Status (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub afsr: RW<u32>,
- #[cfg(armv6m)]
- _reserved7: u32,
-
- _reserved8: [u32; 18],
-
- /// Coprocessor Access Control (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- pub cpacr: RW<u32>,
- #[cfg(armv6m)]
- _reserved9: u32,
-}
-
-/// FPU access mode
-#[cfg(has_fpu)]
-#[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,
-}
-
-#[cfg(has_fpu)]
-mod fpu_consts {
- pub const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20;
- pub const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20;
- pub const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20;
-}
-
-#[cfg(has_fpu)]
-use self::fpu_consts::*;
-
-#[cfg(has_fpu)]
-impl SCB {
- /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Disabled)`
- #[inline]
- pub fn disable_fpu(&mut self) {
- self.set_fpu_access_mode(FpuAccessMode::Disabled)
- }
-
- /// Shorthand for `set_fpu_access_mode(FpuAccessMode::Enabled)`
- #[inline]
- pub fn enable_fpu(&mut self) {
- self.set_fpu_access_mode(FpuAccessMode::Enabled)
- }
-
- /// Gets FPU access mode
- #[inline]
- pub fn fpu_access_mode() -> FpuAccessMode {
- // NOTE(unsafe) atomic read operation with no side effects
- let cpacr = unsafe { (*Self::PTR).cpacr.read() };
-
- if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER {
- FpuAccessMode::Enabled
- } else if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE {
- FpuAccessMode::Privileged
- } else {
- FpuAccessMode::Disabled
- }
- }
-
- /// Sets FPU access mode
- ///
- /// *IMPORTANT* Any function that runs fully or partly with the FPU disabled must *not* take any
- /// floating-point arguments or have any floating-point local variables. Because the compiler
- /// might inline such a function into a caller that does have floating-point arguments or
- /// variables, any such function must be also marked #[inline(never)].
- #[inline]
- pub fn set_fpu_access_mode(&mut self, mode: FpuAccessMode) {
- let mut cpacr = self.cpacr.read() & !SCB_CPACR_FPU_MASK;
- match mode {
- FpuAccessMode::Disabled => (),
- FpuAccessMode::Privileged => cpacr |= SCB_CPACR_FPU_ENABLE,
- FpuAccessMode::Enabled => cpacr |= SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER,
- }
- unsafe { self.cpacr.write(cpacr) }
- }
-}
-
-impl SCB {
- /// Returns the active exception number
- #[inline]
- pub fn vect_active() -> VectActive {
- let icsr =
- unsafe { ptr::read_volatile(&(*SCB::PTR).icsr as *const _ as *const u32) } & 0x1FF;
-
- match icsr as u16 {
- 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, native))]
- 7 => VectActive::Exception(Exception::SecureFault),
- 11 => VectActive::Exception(Exception::SVCall),
- #[cfg(not(armv6m))]
- 12 => VectActive::Exception(Exception::DebugMonitor),
- 14 => VectActive::Exception(Exception::PendSV),
- 15 => VectActive::Exception(Exception::SysTick),
- irqn => VectActive::Interrupt { irqn: irqn - 16 },
- }
- }
-}
-
-/// Processor core exceptions (internal interrupts)
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", derive(PartialOrd, Hash))]
-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, native))]
- 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, native))]
- Exception::SecureFault => -9,
- Exception::SVCall => -5,
- #[cfg(not(armv6m))]
- Exception::DebugMonitor => -4,
- Exception::PendSV => -2,
- Exception::SysTick => -1,
- }
- }
-}
-
-/// Active exception number
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[cfg_attr(feature = "std", derive(PartialOrd, Hash))]
-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, 512)` (9 bit)
- irqn: u16,
- },
-}
-
-impl VectActive {
- /// Converts a vector number into `VectActive`
- #[inline]
- pub fn from(vect_active: u16) -> Option<Self> {
- Some(match vect_active {
- 0 => VectActive::ThreadMode,
- 2 => VectActive::Exception(Exception::NonMaskableInt),
- 3 => VectActive::Exception(Exception::HardFault),
- #[cfg(not(armv6m))]
- 4 => VectActive::Exception(Exception::MemoryManagement),
- #[cfg(not(armv6m))]
- 5 => VectActive::Exception(Exception::BusFault),
- #[cfg(not(armv6m))]
- 6 => VectActive::Exception(Exception::UsageFault),
- #[cfg(any(armv8m, native))]
- 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 (16..512).contains(&irqn) => VectActive::Interrupt { irqn: irqn - 16 },
- _ => return None,
- })
- }
-}
-
-#[cfg(not(armv6m))]
-mod scb_consts {
- pub const SCB_CCR_IC_MASK: u32 = 1 << 17;
- pub const SCB_CCR_DC_MASK: u32 = 1 << 16;
-}
-
-#[cfg(not(armv6m))]
-use self::scb_consts::*;
-
-#[cfg(not(armv6m))]
-impl SCB {
- /// Enables I-cache if currently disabled.
- ///
- /// This operation first invalidates the entire I-cache.
- #[inline]
- pub fn enable_icache(&mut self) {
- // Don't do anything if I-cache is already enabled
- if Self::icache_enabled() {
- return;
- }
-
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- // Invalidate I-cache
- cbp.iciallu();
-
- // Enable I-cache
- extern "C" {
- // see asm-v7m.s
- fn __enable_icache();
- }
-
- // NOTE(unsafe): The asm routine manages exclusive access to the SCB
- // registers and applies the proper barriers; it is technically safe on
- // its own, and is only `unsafe` here because it's `extern "C"`.
- unsafe {
- __enable_icache();
- }
- }
-
- /// Disables I-cache if currently enabled.
- ///
- /// This operation invalidates the entire I-cache after disabling.
- #[inline]
- pub fn disable_icache(&mut self) {
- // Don't do anything if I-cache is already disabled
- if !Self::icache_enabled() {
- return;
- }
-
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- // Disable I-cache
- // NOTE(unsafe): We have synchronised access by &mut self
- unsafe { self.ccr.modify(|r| r & !SCB_CCR_IC_MASK) };
-
- // Invalidate I-cache
- cbp.iciallu();
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Returns whether the I-cache is currently enabled.
- #[inline(always)]
- pub fn icache_enabled() -> bool {
- crate::asm::dsb();
- crate::asm::isb();
-
- // NOTE(unsafe): atomic read with no side effects
- unsafe { (*Self::PTR).ccr.read() & SCB_CCR_IC_MASK == SCB_CCR_IC_MASK }
- }
-
- /// Invalidates the entire I-cache.
- #[inline]
- pub fn invalidate_icache(&mut self) {
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- // Invalidate I-cache
- cbp.iciallu();
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Enables D-cache if currently disabled.
- ///
- /// This operation first invalidates the entire D-cache, ensuring it does
- /// not contain stale values before being enabled.
- #[inline]
- pub fn enable_dcache(&mut self, cpuid: &mut CPUID) {
- // Don't do anything if D-cache is already enabled
- if Self::dcache_enabled() {
- return;
- }
-
- // Invalidate anything currently in the D-cache
- unsafe { self.invalidate_dcache(cpuid) };
-
- // Now turn on the D-cache
- extern "C" {
- // see asm-v7m.s
- fn __enable_dcache();
- }
-
- // NOTE(unsafe): The asm routine manages exclusive access to the SCB
- // registers and applies the proper barriers; it is technically safe on
- // its own, and is only `unsafe` here because it's `extern "C"`.
- unsafe {
- __enable_dcache();
- }
- }
-
- /// Disables D-cache if currently enabled.
- ///
- /// This operation subsequently cleans and invalidates the entire D-cache,
- /// ensuring all contents are safely written back to main memory after disabling.
- #[inline]
- pub fn disable_dcache(&mut self, cpuid: &mut CPUID) {
- // Don't do anything if D-cache is already disabled
- if !Self::dcache_enabled() {
- return;
- }
-
- // Turn off the D-cache
- // NOTE(unsafe): We have synchronised access by &mut self
- unsafe { self.ccr.modify(|r| r & !SCB_CCR_DC_MASK) };
-
- // Clean and invalidate whatever was left in it
- self.clean_invalidate_dcache(cpuid);
- }
-
- /// Returns whether the D-cache is currently enabled.
- #[inline]
- pub fn dcache_enabled() -> bool {
- crate::asm::dsb();
- crate::asm::isb();
-
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*Self::PTR).ccr.read() & SCB_CCR_DC_MASK == SCB_CCR_DC_MASK }
- }
-
- /// Invalidates the entire D-cache.
- ///
- /// Note that calling this while the dcache is enabled will probably wipe out the
- /// stack, depending on optimisations, therefore breaking returning to the call point.
- ///
- /// It's used immediately before enabling the dcache, but not exported publicly.
- #[inline]
- unsafe fn invalidate_dcache(&mut self, cpuid: &mut CPUID) {
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = CBP::new();
-
- // Read number of sets and ways
- let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified);
-
- // Invalidate entire D-cache
- for set in 0..sets {
- for way in 0..ways {
- cbp.dcisw(set, way);
- }
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Cleans the entire D-cache.
- ///
- /// This function causes everything in the D-cache to be written back to main memory,
- /// overwriting whatever is already there.
- #[inline]
- pub fn clean_dcache(&mut self, cpuid: &mut CPUID) {
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- // Read number of sets and ways
- let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified);
-
- for set in 0..sets {
- for way in 0..ways {
- cbp.dccsw(set, way);
- }
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Cleans and invalidates the entire D-cache.
- ///
- /// This function causes everything in the D-cache to be written back to main memory,
- /// and then marks the entire D-cache as invalid, causing future reads to first fetch
- /// from main memory.
- #[inline]
- pub fn clean_invalidate_dcache(&mut self, cpuid: &mut CPUID) {
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- // Read number of sets and ways
- let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified);
-
- for set in 0..sets {
- for way in 0..ways {
- cbp.dccisw(set, way);
- }
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Invalidates D-cache by address.
- ///
- /// * `addr`: The address to invalidate, which must be cache-line aligned.
- /// * `size`: Number of bytes to invalidate, which must be a multiple of the cache line size.
- ///
- /// Invalidates D-cache cache lines, starting from the first line containing `addr`,
- /// finishing once at least `size` bytes have been invalidated.
- ///
- /// Invalidation causes the next read access to memory to be fetched from main memory instead
- /// of the cache.
- ///
- /// # Cache Line Sizes
- ///
- /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed
- /// to 32 bytes, which means `addr` must be 32-byte aligned and `size` must be a multiple
- /// of 32. At the time of writing, no other Cortex-M cores have data caches.
- ///
- /// If `addr` is not cache-line aligned, or `size` is not a multiple of the cache line size,
- /// other data before or after the desired memory would also be invalidated, which can very
- /// easily cause memory corruption and undefined behaviour.
- ///
- /// # Safety
- ///
- /// After invalidating, the next read of invalidated data will be from main memory. This may
- /// cause recent writes to be lost, potentially including writes that initialized objects.
- /// Therefore, this method may cause uninitialized memory or invalid values to be read,
- /// resulting in undefined behaviour. You must ensure that main memory contains valid and
- /// initialized values before invalidating.
- ///
- /// `addr` **must** be aligned to the size of the cache lines, and `size` **must** be a
- /// multiple of the cache line size, otherwise this function will invalidate other memory,
- /// easily leading to memory corruption and undefined behaviour. This precondition is checked
- /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid
- /// a runtime-dependent `panic!()` call.
- #[inline]
- pub unsafe fn invalidate_dcache_by_address(&mut self, addr: usize, size: usize) {
- // No-op zero sized operations
- if size == 0 {
- return;
- }
-
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = CBP::new();
-
- // dminline is log2(num words), so 2**dminline * 4 gives size in bytes
- let dminline = CPUID::cache_dminline();
- let line_size = (1 << dminline) * 4;
-
- debug_assert!((addr & (line_size - 1)) == 0);
- debug_assert!((size & (line_size - 1)) == 0);
-
- crate::asm::dsb();
-
- // Find number of cache lines to invalidate
- let num_lines = ((size - 1) / line_size) + 1;
-
- // Compute address of first cache line
- let mask = 0xFFFF_FFFF - (line_size - 1);
- let mut addr = addr & mask;
-
- for _ in 0..num_lines {
- cbp.dcimvac(addr as u32);
- addr += line_size;
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Invalidates an object from the D-cache.
- ///
- /// * `obj`: The object to invalidate.
- ///
- /// Invalidates D-cache starting from the first cache line containing `obj`,
- /// continuing to invalidate cache lines until all of `obj` has been invalidated.
- ///
- /// Invalidation causes the next read access to memory to be fetched from main memory instead
- /// of the cache.
- ///
- /// # Cache Line Sizes
- ///
- /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed
- /// to 32 bytes, which means `obj` must be 32-byte aligned, and its size must be a multiple
- /// of 32 bytes. At the time of writing, no other Cortex-M cores have data caches.
- ///
- /// If `obj` is not cache-line aligned, or its size is not a multiple of the cache line size,
- /// other data before or after the desired memory would also be invalidated, which can very
- /// easily cause memory corruption and undefined behaviour.
- ///
- /// # Safety
- ///
- /// After invalidating, `obj` will be read from main memory on next access. This may cause
- /// recent writes to `obj` to be lost, potentially including the write that initialized it.
- /// Therefore, this method may cause uninitialized memory or invalid values to be read,
- /// resulting in undefined behaviour. You must ensure that main memory contains a valid and
- /// initialized value for T before invalidating `obj`.
- ///
- /// `obj` **must** be aligned to the size of the cache lines, and its size **must** be a
- /// multiple of the cache line size, otherwise this function will invalidate other memory,
- /// easily leading to memory corruption and undefined behaviour. This precondition is checked
- /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid
- /// a runtime-dependent `panic!()` call.
- #[inline]
- pub unsafe fn invalidate_dcache_by_ref<T>(&mut self, obj: &mut T) {
- self.invalidate_dcache_by_address(obj as *const T as usize, core::mem::size_of::<T>());
- }
-
- /// Invalidates a slice from the D-cache.
- ///
- /// * `slice`: The slice to invalidate.
- ///
- /// Invalidates D-cache starting from the first cache line containing members of `slice`,
- /// continuing to invalidate cache lines until all of `slice` has been invalidated.
- ///
- /// Invalidation causes the next read access to memory to be fetched from main memory instead
- /// of the cache.
- ///
- /// # Cache Line Sizes
- ///
- /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed
- /// to 32 bytes, which means `slice` must be 32-byte aligned, and its size must be a multiple
- /// of 32 bytes. At the time of writing, no other Cortex-M cores have data caches.
- ///
- /// If `slice` is not cache-line aligned, or its size is not a multiple of the cache line size,
- /// other data before or after the desired memory would also be invalidated, which can very
- /// easily cause memory corruption and undefined behaviour.
- ///
- /// # Safety
- ///
- /// After invalidating, `slice` will be read from main memory on next access. This may cause
- /// recent writes to `slice` to be lost, potentially including the write that initialized it.
- /// Therefore, this method may cause uninitialized memory or invalid values to be read,
- /// resulting in undefined behaviour. You must ensure that main memory contains valid and
- /// initialized values for T before invalidating `slice`.
- ///
- /// `slice` **must** be aligned to the size of the cache lines, and its size **must** be a
- /// multiple of the cache line size, otherwise this function will invalidate other memory,
- /// easily leading to memory corruption and undefined behaviour. This precondition is checked
- /// in debug builds using a `debug_assert!()`, but not checked in release builds to avoid
- /// a runtime-dependent `panic!()` call.
- #[inline]
- pub unsafe fn invalidate_dcache_by_slice<T>(&mut self, slice: &mut [T]) {
- self.invalidate_dcache_by_address(
- slice.as_ptr() as usize,
- slice.len() * core::mem::size_of::<T>(),
- );
- }
-
- /// Cleans D-cache by address.
- ///
- /// * `addr`: The address to start cleaning at.
- /// * `size`: The number of bytes to clean.
- ///
- /// Cleans D-cache cache lines, starting from the first line containing `addr`,
- /// finishing once at least `size` bytes have been invalidated.
- ///
- /// Cleaning the cache causes whatever data is present in the cache to be immediately written
- /// to main memory, overwriting whatever was in main memory.
- ///
- /// # Cache Line Sizes
- ///
- /// Cache line sizes vary by core. For all Cortex-M7 cores, the cache line size is fixed
- /// to 32 bytes, which means `addr` should generally be 32-byte aligned and `size` should be a
- /// multiple of 32. At the time of writing, no other Cortex-M cores have data caches.
- ///
- /// If `addr` is not cache-line aligned, or `size` is not a multiple of the cache line size,
- /// other data before or after the desired memory will also be cleaned. From the point of view
- /// of the core executing this function, memory remains consistent, so this is not unsound,
- /// but is worth knowing about.
- #[inline]
- pub fn clean_dcache_by_address(&mut self, addr: usize, size: usize) {
- // No-op zero sized operations
- if size == 0 {
- return;
- }
-
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- crate::asm::dsb();
-
- let dminline = CPUID::cache_dminline();
- let line_size = (1 << dminline) * 4;
- let num_lines = ((size - 1) / line_size) + 1;
-
- let mask = 0xFFFF_FFFF - (line_size - 1);
- let mut addr = addr & mask;
-
- for _ in 0..num_lines {
- cbp.dccmvac(addr as u32);
- addr += line_size;
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-
- /// Cleans an object from the D-cache.
- ///
- /// * `obj`: The object to clean.
- ///
- /// Cleans D-cache starting from the first cache line containing `obj`,
- /// continuing to clean cache lines until all of `obj` has been cleaned.
- ///
- /// It is recommended that `obj` is both aligned to the cache line size and a multiple of
- /// the cache line size long, otherwise surrounding data will also be cleaned.
- ///
- /// Cleaning the cache causes whatever data is present in the cache to be immediately written
- /// to main memory, overwriting whatever was in main memory.
- #[inline]
- pub fn clean_dcache_by_ref<T>(&mut self, obj: &T) {
- self.clean_dcache_by_address(obj as *const T as usize, core::mem::size_of::<T>());
- }
-
- /// Cleans a slice from D-cache.
- ///
- /// * `slice`: The slice to clean.
- ///
- /// Cleans D-cache starting from the first cache line containing members of `slice`,
- /// continuing to clean cache lines until all of `slice` has been cleaned.
- ///
- /// It is recommended that `slice` is both aligned to the cache line size and a multiple of
- /// the cache line size long, otherwise surrounding data will also be cleaned.
- ///
- /// Cleaning the cache causes whatever data is present in the cache to be immediately written
- /// to main memory, overwriting whatever was in main memory.
- #[inline]
- pub fn clean_dcache_by_slice<T>(&mut self, slice: &[T]) {
- self.clean_dcache_by_address(
- slice.as_ptr() as usize,
- slice.len() * core::mem::size_of::<T>(),
- );
- }
-
- /// Cleans and invalidates D-cache by address.
- ///
- /// * `addr`: The address to clean and invalidate.
- /// * `size`: The number of bytes to clean and invalidate.
- ///
- /// Cleans and invalidates D-cache starting from the first cache line containing `addr`,
- /// finishing once at least `size` bytes have been cleaned and invalidated.
- ///
- /// It is recommended that `addr` is aligned to the cache line size and `size` is a multiple of
- /// the cache line size, otherwise surrounding data will also be cleaned.
- ///
- /// Cleaning and invalidating causes data in the D-cache to be written back to main memory,
- /// and then marks that data in the D-cache as invalid, causing future reads to first fetch
- /// from main memory.
- #[inline]
- pub fn clean_invalidate_dcache_by_address(&mut self, addr: usize, size: usize) {
- // No-op zero sized operations
- if size == 0 {
- return;
- }
-
- // NOTE(unsafe): No races as all CBP registers are write-only and stateless
- let mut cbp = unsafe { CBP::new() };
-
- crate::asm::dsb();
-
- // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M
- const LINESIZE: usize = 32;
- let num_lines = ((size - 1) / LINESIZE) + 1;
-
- let mut addr = addr & 0xFFFF_FFE0;
-
- for _ in 0..num_lines {
- cbp.dccimvac(addr as u32);
- addr += LINESIZE;
- }
-
- crate::asm::dsb();
- crate::asm::isb();
- }
-}
-
-const SCB_SCR_SLEEPDEEP: u32 = 0x1 << 2;
-
-impl SCB {
- /// Set the SLEEPDEEP bit in the SCR register
- #[inline]
- pub fn set_sleepdeep(&mut self) {
- unsafe {
- self.scr.modify(|scr| scr | SCB_SCR_SLEEPDEEP);
- }
- }
-
- /// Clear the SLEEPDEEP bit in the SCR register
- #[inline]
- pub fn clear_sleepdeep(&mut self) {
- unsafe {
- self.scr.modify(|scr| scr & !SCB_SCR_SLEEPDEEP);
- }
- }
-}
-
-const SCB_SCR_SLEEPONEXIT: u32 = 0x1 << 1;
-
-impl SCB {
- /// Set the SLEEPONEXIT bit in the SCR register
- #[inline]
- pub fn set_sleeponexit(&mut self) {
- unsafe {
- self.scr.modify(|scr| scr | SCB_SCR_SLEEPONEXIT);
- }
- }
-
- /// Clear the SLEEPONEXIT bit in the SCR register
- #[inline]
- pub fn clear_sleeponexit(&mut self) {
- unsafe {
- self.scr.modify(|scr| scr & !SCB_SCR_SLEEPONEXIT);
- }
- }
-}
-
-const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16;
-const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x7 << 8;
-const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2;
-
-impl SCB {
- /// Initiate a system reset request to reset the MCU
- #[inline]
- pub fn sys_reset() -> ! {
- crate::asm::dsb();
- unsafe {
- (*Self::PTR).aircr.modify(
- |r| {
- SCB_AIRCR_VECTKEY | // otherwise the write is ignored
- r & SCB_AIRCR_PRIGROUP_MASK | // keep priority group unchanged
- SCB_AIRCR_SYSRESETREQ
- }, // set the bit
- )
- };
- crate::asm::dsb();
- loop {
- // wait for the reset
- crate::asm::nop(); // avoid rust-lang/rust#28728
- }
- }
-}
-
-const SCB_ICSR_PENDSVSET: u32 = 1 << 28;
-const SCB_ICSR_PENDSVCLR: u32 = 1 << 27;
-
-const SCB_ICSR_PENDSTSET: u32 = 1 << 26;
-const SCB_ICSR_PENDSTCLR: u32 = 1 << 25;
-
-impl SCB {
- /// Set the PENDSVSET bit in the ICSR register which will pend the PendSV interrupt
- #[inline]
- pub fn set_pendsv() {
- unsafe {
- (*Self::PTR).icsr.write(SCB_ICSR_PENDSVSET);
- }
- }
-
- /// Check if PENDSVSET bit in the ICSR register is set meaning PendSV interrupt is pending
- #[inline]
- pub fn is_pendsv_pending() -> bool {
- unsafe { (*Self::PTR).icsr.read() & SCB_ICSR_PENDSVSET == SCB_ICSR_PENDSVSET }
- }
-
- /// Set the PENDSVCLR bit in the ICSR register which will clear a pending PendSV interrupt
- #[inline]
- pub fn clear_pendsv() {
- unsafe {
- (*Self::PTR).icsr.write(SCB_ICSR_PENDSVCLR);
- }
- }
-
- /// Set the PENDSTSET bit in the ICSR register which will pend a SysTick interrupt
- #[inline]
- pub fn set_pendst() {
- unsafe {
- (*Self::PTR).icsr.write(SCB_ICSR_PENDSTSET);
- }
- }
-
- /// Check if PENDSTSET bit in the ICSR register is set meaning SysTick interrupt is pending
- #[inline]
- pub fn is_pendst_pending() -> bool {
- unsafe { (*Self::PTR).icsr.read() & SCB_ICSR_PENDSTSET == SCB_ICSR_PENDSTSET }
- }
-
- /// Set the PENDSTCLR bit in the ICSR register which will clear a pending SysTick interrupt
- #[inline]
- pub fn clear_pendst() {
- unsafe {
- (*Self::PTR).icsr.write(SCB_ICSR_PENDSTCLR);
- }
- }
-}
-
-/// System handlers, exceptions with configurable priority
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[repr(u8)]
-pub enum SystemHandler {
- // NonMaskableInt, // priority is fixed
- // HardFault, // priority is fixed
- /// Memory management interrupt (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- MemoryManagement = 4,
-
- /// Bus fault interrupt (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- BusFault = 5,
-
- /// Usage fault interrupt (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- UsageFault = 6,
-
- /// Secure fault interrupt (only on ARMv8-M)
- #[cfg(any(armv8m, native))]
- SecureFault = 7,
-
- /// SV call interrupt
- SVCall = 11,
-
- /// Debug monitor interrupt (not present on Cortex-M0 variants)
- #[cfg(not(armv6m))]
- DebugMonitor = 12,
-
- /// Pend SV interrupt
- PendSV = 14,
-
- /// System Tick interrupt
- SysTick = 15,
-}
-
-impl SCB {
- /// Returns the hardware priority of `system_handler`
- ///
- /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
- /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
- #[inline]
- pub fn get_priority(system_handler: SystemHandler) -> u8 {
- let index = system_handler as u8;
-
- #[cfg(not(armv6m))]
- {
- // NOTE(unsafe) atomic read with no side effects
-
- // NOTE(unsafe): Index is bounded to [4,15] by SystemHandler design.
- // TODO: Review it after rust-lang/rust/issues/13926 will be fixed.
- let priority_ref = unsafe { (*Self::PTR).shpr.get_unchecked(usize::from(index - 4)) };
-
- priority_ref.read()
- }
-
- #[cfg(armv6m)]
- {
- // NOTE(unsafe) atomic read with no side effects
-
- // NOTE(unsafe): Index is bounded to [11,15] by SystemHandler design.
- // TODO: Review it after rust-lang/rust/issues/13926 will be fixed.
- let priority_ref = unsafe {
- (*Self::PTR)
- .shpr
- .get_unchecked(usize::from((index - 8) / 4))
- };
-
- let shpr = priority_ref.read();
- let prio = (shpr >> (8 * (index % 4))) & 0x0000_00ff;
- prio as u8
- }
- }
-
- /// Sets the hardware priority of `system_handler` to `prio`
- ///
- /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
- /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
- ///
- /// On ARMv6-M, updating a system handler priority requires a read-modify-write operation. On
- /// ARMv7-M, the operation is performed in a single, atomic write operation.
- ///
- /// # Unsafety
- ///
- /// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](crate::register::basepri)) and compromise memory safety.
- #[inline]
- pub unsafe fn set_priority(&mut self, system_handler: SystemHandler, prio: u8) {
- let index = system_handler as u8;
-
- #[cfg(not(armv6m))]
- {
- // NOTE(unsafe): Index is bounded to [4,15] by SystemHandler design.
- // TODO: Review it after rust-lang/rust/issues/13926 will be fixed.
- let priority_ref = (*Self::PTR).shpr.get_unchecked(usize::from(index - 4));
-
- priority_ref.write(prio)
- }
-
- #[cfg(armv6m)]
- {
- // NOTE(unsafe): Index is bounded to [11,15] by SystemHandler design.
- // TODO: Review it after rust-lang/rust/issues/13926 will be fixed.
- let priority_ref = (*Self::PTR)
- .shpr
- .get_unchecked(usize::from((index - 8) / 4));
-
- priority_ref.modify(|value| {
- let shift = 8 * (index % 4);
- let mask = 0x0000_00ff << shift;
- let prio = u32::from(prio) << shift;
-
- (value & !mask) | prio
- });
- }
- }
-
- /// Return the bit position of the exception enable bit in the SHCSR register
- #[inline]
- #[cfg(not(any(armv6m, armv8m_base)))]
- fn shcsr_enable_shift(exception: Exception) -> Option<u32> {
- match exception {
- Exception::MemoryManagement => Some(16),
- Exception::BusFault => Some(17),
- Exception::UsageFault => Some(18),
- #[cfg(armv8m_main)]
- Exception::SecureFault => Some(19),
- _ => None,
- }
- }
-
- /// Enable the exception
- ///
- /// If the exception is enabled, when the exception is triggered, the exception handler will be executed instead of the
- /// HardFault handler.
- /// This function is only allowed on the following exceptions:
- /// * `MemoryManagement`
- /// * `BusFault`
- /// * `UsageFault`
- /// * `SecureFault` (can only be enabled from Secure state)
- ///
- /// Calling this function with any other exception will do nothing.
- #[inline]
- #[cfg(not(any(armv6m, armv8m_base)))]
- pub fn enable(&mut self, exception: Exception) {
- if let Some(shift) = SCB::shcsr_enable_shift(exception) {
- // The mutable reference to SCB makes sure that only this code is currently modifying
- // the register.
- unsafe { self.shcsr.modify(|value| value | (1 << shift)) }
- }
- }
-
- /// Disable the exception
- ///
- /// If the exception is disabled, when the exception is triggered, the HardFault handler will be executed instead of the
- /// exception handler.
- /// This function is only allowed on the following exceptions:
- /// * `MemoryManagement`
- /// * `BusFault`
- /// * `UsageFault`
- /// * `SecureFault` (can not be changed from Non-secure state)
- ///
- /// Calling this function with any other exception will do nothing.
- #[inline]
- #[cfg(not(any(armv6m, armv8m_base)))]
- pub fn disable(&mut self, exception: Exception) {
- if let Some(shift) = SCB::shcsr_enable_shift(exception) {
- // The mutable reference to SCB makes sure that only this code is currently modifying
- // the register.
- unsafe { self.shcsr.modify(|value| value & !(1 << shift)) }
- }
- }
-
- /// Check if an exception is enabled
- ///
- /// This function is only allowed on the following exception:
- /// * `MemoryManagement`
- /// * `BusFault`
- /// * `UsageFault`
- /// * `SecureFault` (can not be read from Non-secure state)
- ///
- /// Calling this function with any other exception will read `false`.
- #[inline]
- #[cfg(not(any(armv6m, armv8m_base)))]
- pub fn is_enabled(&self, exception: Exception) -> bool {
- if let Some(shift) = SCB::shcsr_enable_shift(exception) {
- (self.shcsr.read() & (1 << shift)) > 0
- } else {
- false
- }
- }
-}
diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs
deleted file mode 100644
index 345acc2..0000000
--- a/src/peripheral/syst.rs
+++ /dev/null
@@ -1,185 +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<u32>,
- /// Reload Value
- pub rvr: RW<u32>,
- /// Current Value
- pub cvr: RW<u32>,
- /// Calibration Value
- pub calib: RO<u32>,
-}
-
-/// SysTick clock source
-#[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/test.rs b/src/peripheral/test.rs
deleted file mode 100644
index cab064a..0000000
--- a/src/peripheral/test.rs
+++ /dev/null
@@ -1,170 +0,0 @@
-#[test]
-fn cpuid() {
- let cpuid = unsafe { &*crate::peripheral::CPUID::PTR };
-
- assert_eq!(address(&cpuid.base), 0xE000_ED00);
- assert_eq!(address(&cpuid.pfr), 0xE000_ED40);
- assert_eq!(address(&cpuid.dfr), 0xE000_ED48);
- assert_eq!(address(&cpuid.afr), 0xE000_ED4C);
- assert_eq!(address(&cpuid.mmfr), 0xE000_ED50);
- assert_eq!(address(&cpuid.isar), 0xE000_ED60);
- assert_eq!(address(&cpuid.clidr), 0xE000_ED78);
- assert_eq!(address(&cpuid.ctr), 0xE000_ED7C);
- assert_eq!(address(&cpuid.ccsidr), 0xE000_ED80);
- assert_eq!(address(&cpuid.csselr), 0xE000_ED84);
-}
-
-#[test]
-fn dcb() {
- let dcb = unsafe { &*crate::peripheral::DCB::PTR };
-
- assert_eq!(address(&dcb.dhcsr), 0xE000_EDF0);
- assert_eq!(address(&dcb.dcrsr), 0xE000_EDF4);
- assert_eq!(address(&dcb.dcrdr), 0xE000_EDF8);
- assert_eq!(address(&dcb.demcr), 0xE000_EDFC);
-}
-
-#[test]
-fn dwt() {
- let dwt = unsafe { &*crate::peripheral::DWT::PTR };
-
- assert_eq!(address(&dwt.ctrl), 0xE000_1000);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.cyccnt), 0xE000_1004);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.cpicnt), 0xE000_1008);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.exccnt), 0xE000_100C);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.sleepcnt), 0xE000_1010);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.lsucnt), 0xE000_1014);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.foldcnt), 0xE000_1018);
- assert_eq!(address(&dwt.pcsr), 0xE000_101C);
- assert_eq!(address(&dwt.c[0].comp), 0xE000_1020);
- assert_eq!(address(&dwt.c[0].mask), 0xE000_1024);
- assert_eq!(address(&dwt.c[0].function), 0xE000_1028);
- assert_eq!(address(&dwt.c[1].comp), 0xE000_1030);
- assert_eq!(address(&dwt.c[1].mask), 0xE000_1034);
- assert_eq!(address(&dwt.c[1].function), 0xE000_1038);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.lar), 0xE000_1FB0);
- #[cfg(not(armv6m))]
- assert_eq!(address(&dwt.lsr), 0xE000_1FB4);
-}
-
-#[test]
-fn fpb() {
- let fpb = unsafe { &*crate::peripheral::FPB::PTR };
-
- assert_eq!(address(&fpb.ctrl), 0xE000_2000);
- assert_eq!(address(&fpb.remap), 0xE000_2004);
- assert_eq!(address(&fpb.comp), 0xE000_2008);
- assert_eq!(address(&fpb.comp[1]), 0xE000_200C);
- assert_eq!(address(&fpb.lar), 0xE000_2FB0);
- assert_eq!(address(&fpb.lsr), 0xE000_2FB4);
-}
-
-#[test]
-fn fpu() {
- let fpu = unsafe { &*crate::peripheral::FPU::PTR };
-
- assert_eq!(address(&fpu.fpccr), 0xE000_EF34);
- assert_eq!(address(&fpu.fpcar), 0xE000_EF38);
- assert_eq!(address(&fpu.fpdscr), 0xE000_EF3C);
- assert_eq!(address(&fpu.mvfr), 0xE000_EF40);
- assert_eq!(address(&fpu.mvfr[1]), 0xE000_EF44);
- assert_eq!(address(&fpu.mvfr[2]), 0xE000_EF48);
-}
-
-#[test]
-fn itm() {
- let itm = unsafe { &*crate::peripheral::ITM::PTR };
-
- assert_eq!(address(&itm.stim), 0xE000_0000);
- assert_eq!(address(&itm.ter), 0xE000_0E00);
- assert_eq!(address(&itm.tpr), 0xE000_0E40);
- assert_eq!(address(&itm.tcr), 0xE000_0E80);
- assert_eq!(address(&itm.lar), 0xE000_0FB0);
- assert_eq!(address(&itm.lsr), 0xE000_0FB4);
-}
-
-#[test]
-fn mpu() {
- let mpu = unsafe { &*crate::peripheral::MPU::PTR };
-
- assert_eq!(address(&mpu._type), 0xE000ED90);
- assert_eq!(address(&mpu.ctrl), 0xE000ED94);
- assert_eq!(address(&mpu.rnr), 0xE000ED98);
- assert_eq!(address(&mpu.rbar), 0xE000ED9C);
- assert_eq!(address(&mpu.rasr), 0xE000EDA0);
- assert_eq!(address(&mpu.rbar_a1), 0xE000EDA4);
- assert_eq!(address(&mpu.rasr_a1), 0xE000EDA8);
- assert_eq!(address(&mpu.rbar_a2), 0xE000EDAC);
- assert_eq!(address(&mpu.rasr_a2), 0xE000EDB0);
- assert_eq!(address(&mpu.rbar_a3), 0xE000EDB4);
- assert_eq!(address(&mpu.rasr_a3), 0xE000EDB8);
-}
-
-#[test]
-fn nvic() {
- let nvic = unsafe { &*crate::peripheral::NVIC::PTR };
-
- assert_eq!(address(&nvic.iser), 0xE000E100);
- assert_eq!(address(&nvic.icer), 0xE000E180);
- assert_eq!(address(&nvic.ispr), 0xE000E200);
- assert_eq!(address(&nvic.icpr), 0xE000E280);
- assert_eq!(address(&nvic.iabr), 0xE000E300);
- assert_eq!(address(&nvic.ipr), 0xE000E400);
- #[cfg(not(armv6m))]
- assert_eq!(address(&nvic.stir), 0xE000EF00);
-}
-
-#[test]
-fn scb() {
- let scb = unsafe { &*crate::peripheral::SCB::PTR };
-
- assert_eq!(address(&scb.icsr), 0xE000_ED04);
- assert_eq!(address(&scb.vtor), 0xE000_ED08);
- assert_eq!(address(&scb.aircr), 0xE000_ED0C);
- 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.shcsr), 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.mmfar), 0xE000_ED34);
- assert_eq!(address(&scb.bfar), 0xE000_ED38);
- assert_eq!(address(&scb.afsr), 0xE000_ED3C);
- assert_eq!(address(&scb.cpacr), 0xE000_ED88);
-}
-
-#[test]
-fn syst() {
- let syst = unsafe { &*crate::peripheral::SYST::PTR };
-
- assert_eq!(address(&syst.csr), 0xE000_E010);
- assert_eq!(address(&syst.rvr), 0xE000_E014);
- assert_eq!(address(&syst.cvr), 0xE000_E018);
- assert_eq!(address(&syst.calib), 0xE000_E01C);
-}
-
-#[test]
-fn tpiu() {
- let tpiu = unsafe { &*crate::peripheral::TPIU::PTR };
-
- assert_eq!(address(&tpiu.sspsr), 0xE004_0000);
- assert_eq!(address(&tpiu.cspsr), 0xE004_0004);
- assert_eq!(address(&tpiu.acpr), 0xE004_0010);
- assert_eq!(address(&tpiu.sppr), 0xE004_00F0);
- assert_eq!(address(&tpiu.ffcr), 0xE004_0304);
- assert_eq!(address(&tpiu.lar), 0xE004_0FB0);
- assert_eq!(address(&tpiu.lsr), 0xE004_0FB4);
- assert_eq!(address(&tpiu._type), 0xE004_0FC8);
-}
-
-fn address<T>(r: *const T) -> usize {
- r as usize
-}
diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs
deleted file mode 100644
index 14dd35c..0000000
--- a/src/peripheral/tpiu.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-//! Trace Port Interface Unit;
-//!
-//! *NOTE* Not available on Armv6-M.
-
-use volatile_register::{RO, RW, WO};
-
-use crate::peripheral::TPIU;
-use bitfield::bitfield;
-
-/// Register block
-#[repr(C)]
-pub struct RegisterBlock {
- /// Supported Parallel Port Sizes
- pub sspsr: RO<u32>,
- /// Current Parallel Port Size
- pub cspsr: RW<u32>,
- reserved0: [u32; 2],
- /// Asynchronous Clock Prescaler
- pub acpr: RW<u32>,
- reserved1: [u32; 55],
- /// Selected Pin Control
- pub sppr: RW<Sppr>,
- reserved2: [u32; 132],
- /// Formatter and Flush Control
- pub ffcr: RW<Ffcr>,
- reserved3: [u32; 810],
- /// Lock Access
- pub lar: WO<u32>,
- /// Lock Status
- pub lsr: RO<u32>,
- reserved4: [u32; 4],
- /// TPIU Type
- pub _type: RO<Type>,
-}
-
-bitfield! {
- /// Formatter and flush control register.
- #[repr(C)]
- #[derive(Clone, Copy)]
- pub struct Ffcr(u32);
- enfcont, set_enfcont: 1;
-}
-
-bitfield! {
- /// TPIU Type Register.
- #[repr(C)]
- #[derive(Clone, Copy)]
- pub struct Type(u32);
- u8, fifosz, _: 8, 6;
- ptinvalid, _: 9;
- mancvalid, _: 10;
- nrzvalid, _: 11;
-}
-
-bitfield! {
- /// Selected pin protocol register.
- #[repr(C)]
- #[derive(Clone, Copy)]
- pub struct Sppr(u32);
- u8, txmode, set_txmode: 1, 0;
-}
-
-/// The available protocols for the trace output.
-#[repr(u8)]
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum TraceProtocol {
- /// Parallel trace port mode
- Parallel = 0b00,
- /// Asynchronous SWO, using Manchester encoding
- AsyncSWOManchester = 0b01,
- /// Asynchronous SWO, using NRZ encoding
- AsyncSWONRZ = 0b10,
-}
-impl core::convert::TryFrom<u8> for TraceProtocol {
- type Error = ();
-
- /// Tries to convert from a `TXMODE` field value. Fails if the set mode is
- /// unknown (and thus unpredictable).
- #[inline]
- fn try_from(value: u8) -> Result<Self, Self::Error> {
- match value {
- x if x == Self::Parallel as u8 => Ok(Self::Parallel),
- x if x == Self::AsyncSWOManchester as u8 => Ok(Self::AsyncSWOManchester),
- x if x == Self::AsyncSWONRZ as u8 => Ok(Self::AsyncSWONRZ),
- _ => Err(()), // unknown and unpredictable mode
- }
- }
-}
-
-/// The SWO options supported by the TPIU, and the mimimum size of the
-/// FIFO output queue for trace data.
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub struct SWOSupports {
- /// Whether UART/NRZ encoding is supported for SWO.
- pub nrz_encoding: bool,
- /// Whether Manchester encoding is supported for SWO.
- pub manchester_encoding: bool,
- /// Whether parallel trace port operation is supported.
- pub parallel_operation: bool,
- /// The minimum implemented FIFO queue size of the TPIU for trace data.
- pub min_queue_size: u8,
-}
-
-impl TPIU {
- /// Sets the prescaler value for a wanted baud rate of the Serial
- /// Wire Output (SWO) in relation to a given asynchronous refernce
- /// clock rate.
- #[inline]
- pub fn set_swo_baud_rate(&mut self, ref_clk_rate: u32, baud_rate: u32) {
- unsafe {
- self.acpr.write((ref_clk_rate / baud_rate) - 1);
- }
- }
-
- /// The used protocol for the trace output. Return `None` if an
- /// unknown (and thus unpredicable mode) is configured by means
- /// other than
- /// [`trace_output_protocol`](Self::set_trace_output_protocol).
- #[inline]
- pub fn trace_output_protocol(&self) -> Option<TraceProtocol> {
- self.sppr.read().txmode().try_into().ok()
- }
-
- /// Sets the used protocol for the trace output.
- #[inline]
- pub fn set_trace_output_protocol(&mut self, proto: TraceProtocol) {
- unsafe {
- self.sppr.modify(|mut r| {
- r.set_txmode(proto as u8);
- r
- });
- }
- }
-
- /// Whether to enable the formatter. If disabled, only ITM and DWT
- /// trace sources are passed through. Data from the ETM is
- /// discarded.
- #[inline]
- pub fn enable_continuous_formatting(&mut self, bit: bool) {
- unsafe {
- self.ffcr.modify(|mut r| {
- r.set_enfcont(bit);
- r
- });
- }
- }
-
- /// Reads the supported trace output modes and the minimum size of
- /// the TPIU FIFO queue for trace data.
- #[inline]
- pub fn swo_supports() -> SWOSupports {
- let _type = unsafe { (*Self::PTR)._type.read() };
- SWOSupports {
- nrz_encoding: _type.nrzvalid(),
- manchester_encoding: _type.mancvalid(),
- parallel_operation: !_type.ptinvalid(),
- min_queue_size: _type.fifosz(),
- }
- }
-}
diff --git a/src/register/apsr.rs b/src/register/apsr.rs
deleted file mode 100644
index edb8737..0000000
--- a/src/register/apsr.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-//! Application Program Status Register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Application Program Status Register
-#[derive(Clone, Copy, Debug)]
-pub struct Apsr {
- bits: u32,
-}
-
-impl Apsr {
- /// Returns the contents of the register as raw bits
- #[inline]
- pub fn bits(self) -> u32 {
- self.bits
- }
-
- /// DSP overflow and saturation flag
- #[inline]
- pub fn q(self) -> bool {
- self.bits & (1 << 27) == (1 << 27)
- }
-
- /// Overflow flag
- #[inline]
- pub fn v(self) -> bool {
- self.bits & (1 << 28) == (1 << 28)
- }
-
- /// Carry or borrow flag
- #[inline]
- pub fn c(self) -> bool {
- self.bits & (1 << 29) == (1 << 29)
- }
-
- /// Zero flag
- #[inline]
- pub fn z(self) -> bool {
- self.bits & (1 << 30) == (1 << 30)
- }
-
- /// Negative flag
- #[inline]
- pub fn n(self) -> bool {
- self.bits & (1 << 31) == (1 << 31)
- }
-}
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> Apsr {
- let bits;
- unsafe { asm!("mrs {}, APSR", out(reg) bits, options(nomem, nostack, preserves_flags)) };
- Apsr { bits }
-}
diff --git a/src/register/basepri.rs b/src/register/basepri.rs
deleted file mode 100644
index cffb379..0000000
--- a/src/register/basepri.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-//! Base Priority Mask Register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> u8 {
- let r;
- unsafe { asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes to the CPU register
-///
-/// **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(cortex_m)]
-#[inline]
-pub unsafe fn write(basepri: u8) {
- #[cfg(feature = "cm7-r0p1")]
- {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) basepri,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
-
- #[cfg(not(feature = "cm7-r0p1"))]
- {
- asm!("msr BASEPRI, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
- }
-}
diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs
deleted file mode 100644
index 2881c4f..0000000
--- a/src/register/basepri_max.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Base Priority Mask Register (conditional write)
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Writes to BASEPRI *if*
-///
-/// - `basepri != 0` AND `basepri::read() == 0`, OR
-/// - `basepri != 0` AND `basepri < basepri::read()`
-///
-/// **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(cortex_m)]
-#[inline]
-pub fn write(basepri: u8) {
- #[cfg(feature = "cm7-r0p1")]
- {
- unsafe {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI_MAX, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) basepri,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
- }
-
- #[cfg(not(feature = "cm7-r0p1"))]
- {
- unsafe {
- asm!("msr BASEPRI_MAX, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
- }
- }
-}
diff --git a/src/register/control.rs b/src/register/control.rs
deleted file mode 100644
index d781913..0000000
--- a/src/register/control.rs
+++ /dev/null
@@ -1,183 +0,0 @@
-//! Control register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-#[cfg(cortex_m)]
-use core::sync::atomic::{compiler_fence, Ordering};
-
-/// Control register
-#[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
-#[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
-#[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
-#[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
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> Control {
- let bits;
- unsafe { asm!("mrs {}, CONTROL", out(reg) bits, options(nomem, nostack, preserves_flags)) };
- Control { bits }
-}
-
-/// Writes to the CPU register.
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn write(control: Control) {
- let control = control.bits();
-
- // ISB is required after writing to CONTROL,
- // per ARM architectural requirements (see Application Note 321).
- asm!(
- "msr CONTROL, {}",
- "isb",
- in(reg) control,
- options(nomem, nostack, preserves_flags),
- );
-
- // Ensure memory accesses are not reordered around the CONTROL update.
- compiler_fence(Ordering::SeqCst);
-}
diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs
deleted file mode 100644
index 1d32709..0000000
--- a/src/register/faultmask.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Fault Mask Register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// All exceptions are ...
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Faultmask {
- /// Active
- Active,
- /// Inactive, expect for NMI
- Inactive,
-}
-
-impl Faultmask {
- /// All exceptions are active
- #[inline]
- pub fn is_active(self) -> bool {
- self == Faultmask::Active
- }
-
- /// All exceptions, except for NMI, are inactive
- #[inline]
- pub fn is_inactive(self) -> bool {
- self == Faultmask::Inactive
- }
-}
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> Faultmask {
- let r: u32;
- unsafe { asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
- if r & (1 << 0) == (1 << 0) {
- Faultmask::Inactive
- } else {
- Faultmask::Active
- }
-}
diff --git a/src/register/fpscr.rs b/src/register/fpscr.rs
deleted file mode 100644
index bffed6c..0000000
--- a/src/register/fpscr.rs
+++ /dev/null
@@ -1,308 +0,0 @@
-//! Floating-point Status Control Register
-
-use core::arch::asm;
-
-/// Floating-point Status Control Register
-#[derive(Clone, Copy, Debug)]
-pub struct Fpscr {
- bits: u32,
-}
-
-impl Fpscr {
- /// Creates a `Fspcr` 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
- }
-
- /// Read the Negative condition code flag
- #[inline]
- pub fn n(self) -> bool {
- self.bits & (1 << 31) != 0
- }
-
- /// Sets the Negative condition code flag
- #[inline]
- pub fn set_n(&mut self, n: bool) {
- let mask = 1 << 31;
- match n {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Zero condition code flag
- #[inline]
- pub fn z(self) -> bool {
- self.bits & (1 << 30) != 0
- }
-
- /// Sets the Zero condition code flag
- #[inline]
- pub fn set_z(&mut self, z: bool) {
- let mask = 1 << 30;
- match z {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Carry condition code flag
- #[inline]
- pub fn c(self) -> bool {
- self.bits & (1 << 29) != 0
- }
-
- /// Sets the Carry condition code flag
- #[inline]
- pub fn set_c(&mut self, c: bool) {
- let mask = 1 << 29;
- match c {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Overflow condition code flag
- #[inline]
- pub fn v(self) -> bool {
- self.bits & (1 << 28) != 0
- }
-
- /// Sets the Zero condition code flag
- #[inline]
- pub fn set_v(&mut self, v: bool) {
- let mask = 1 << 28;
- match v {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Alternative Half Precision bit
- #[inline]
- pub fn ahp(self) -> bool {
- self.bits & (1 << 26) != 0
- }
-
- /// Sets the Alternative Half Precision bit
- #[inline]
- pub fn set_ahp(&mut self, ahp: bool) {
- let mask = 1 << 26;
- match ahp {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Default NaN mode bit
- #[inline]
- pub fn dn(self) -> bool {
- self.bits & (1 << 25) != 0
- }
-
- /// Sets the Default NaN mode bit
- #[inline]
- pub fn set_dn(&mut self, dn: bool) {
- let mask = 1 << 25;
- match dn {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Flush to Zero mode bit
- #[inline]
- pub fn fz(self) -> bool {
- self.bits & (1 << 24) != 0
- }
-
- /// Sets the Flush to Zero mode bit
- #[inline]
- pub fn set_fz(&mut self, fz: bool) {
- let mask = 1 << 24;
- match fz {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Rounding Mode control field
- #[inline]
- pub fn rmode(self) -> RMode {
- match (self.bits & (3 << 22)) >> 22 {
- 0 => RMode::Nearest,
- 1 => RMode::PlusInfinity,
- 2 => RMode::MinusInfinity,
- _ => RMode::Zero,
- }
- }
-
- /// Sets the Rounding Mode control field
- #[inline]
- pub fn set_rmode(&mut self, rmode: RMode) {
- let mask = 3 << 22;
- match rmode {
- RMode::Nearest => self.bits &= !mask,
- RMode::PlusInfinity => self.bits = (self.bits & !mask) | (1 << 22),
- RMode::MinusInfinity => self.bits = (self.bits & !mask) | (2 << 22),
- RMode::Zero => self.bits |= mask,
- }
- }
-
- /// Read the Input Denormal cumulative exception bit
- #[inline]
- pub fn idc(self) -> bool {
- self.bits & (1 << 7) != 0
- }
-
- /// Sets the Input Denormal cumulative exception bit
- #[inline]
- pub fn set_idc(&mut self, idc: bool) {
- let mask = 1 << 7;
- match idc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Inexact cumulative exception bit
- #[inline]
- pub fn ixc(self) -> bool {
- self.bits & (1 << 4) != 0
- }
-
- /// Sets the Inexact cumulative exception bit
- #[inline]
- pub fn set_ixc(&mut self, ixc: bool) {
- let mask = 1 << 4;
- match ixc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Underflow cumulative exception bit
- #[inline]
- pub fn ufc(self) -> bool {
- self.bits & (1 << 3) != 0
- }
-
- /// Sets the Underflow cumulative exception bit
- #[inline]
- pub fn set_ufc(&mut self, ufc: bool) {
- let mask = 1 << 3;
- match ufc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Overflow cumulative exception bit
- #[inline]
- pub fn ofc(self) -> bool {
- self.bits & (1 << 2) != 0
- }
-
- /// Sets the Overflow cumulative exception bit
- #[inline]
- pub fn set_ofc(&mut self, ofc: bool) {
- let mask = 1 << 2;
- match ofc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Division by Zero cumulative exception bit
- #[inline]
- pub fn dzc(self) -> bool {
- self.bits & (1 << 1) != 0
- }
-
- /// Sets the Division by Zero cumulative exception bit
- #[inline]
- pub fn set_dzc(&mut self, dzc: bool) {
- let mask = 1 << 1;
- match dzc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-
- /// Read the Invalid Operation cumulative exception bit
- #[inline]
- pub fn ioc(self) -> bool {
- self.bits & (1 << 0) != 0
- }
-
- /// Sets the Invalid Operation cumulative exception bit
- #[inline]
- pub fn set_ioc(&mut self, ioc: bool) {
- let mask = 1 << 0;
- match ioc {
- true => self.bits |= mask,
- false => self.bits &= !mask,
- }
- }
-}
-
-/// Rounding mode
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum RMode {
- /// Round to Nearest (RN) mode. This is the reset value.
- Nearest,
- /// Round towards Plus Infinity (RP) mode.
- PlusInfinity,
- /// Round towards Minus Infinity (RM) mode.
- MinusInfinity,
- /// Round towards Zero (RZ) mode.
- Zero,
-}
-
-impl RMode {
- /// Is Nearest the current rounding mode?
- #[inline]
- pub fn is_nearest(self) -> bool {
- self == RMode::Nearest
- }
-
- /// Is Plus Infinity the current rounding mode?
- #[inline]
- pub fn is_plus_infinity(self) -> bool {
- self == RMode::PlusInfinity
- }
-
- /// Is Minus Infinity the current rounding mode?
- #[inline]
- pub fn is_minus_infinity(self) -> bool {
- self == RMode::MinusInfinity
- }
-
- /// Is Zero the current rounding mode?
- #[inline]
- pub fn is_zero(self) -> bool {
- self == RMode::Zero
- }
-}
-
-/// Read the FPSCR register
-#[inline]
-pub fn read() -> Fpscr {
- let r;
- unsafe { asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags)) };
- Fpscr::from_bits(r)
-}
-
-/// Set the value of the FPSCR register
-#[inline]
-pub unsafe fn write(fpscr: Fpscr) {
- let fpscr = fpscr.bits();
- asm!("vmsr fpscr, {}", in(reg) fpscr, options(nomem, nostack));
-}
diff --git a/src/register/lr.rs b/src/register/lr.rs
deleted file mode 100644
index 02708ae..0000000
--- a/src/register/lr.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//! Link register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn write(bits: u32) {
- asm!("mov lr, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
diff --git a/src/register/mod.rs b/src/register/mod.rs
deleted file mode 100644
index aee7d21..0000000
--- a/src/register/mod.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! Processor core registers
-//!
-//! The following registers can only be accessed in PRIVILEGED mode:
-//!
-//! - BASEPRI
-//! - CONTROL
-//! - FAULTMASK
-//! - MSP
-//! - PRIMASK
-//!
-//! The rest of registers (see list below) can be accessed in either, PRIVILEGED
-//! or UNPRIVILEGED, mode.
-//!
-//! - APSR
-//! - LR
-//! - PC
-//! - PSP
-//!
-//! The following registers are NOT available on ARMv6-M devices
-//! (`thumbv6m-none-eabi`):
-//!
-//! - BASEPRI
-//! - FAULTMASK
-//!
-//! The following registers are only available for devices with an FPU:
-//!
-//! - FPSCR
-//!
-//! # References
-//!
-//! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-pub mod basepri;
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-pub mod basepri_max;
-
-pub mod control;
-
-#[cfg(all(not(armv6m), not(armv8m_base)))]
-pub mod faultmask;
-
-#[cfg(has_fpu)]
-pub mod fpscr;
-
-pub mod msp;
-
-pub mod primask;
-
-pub mod psp;
-
-#[cfg(armv8m_main)]
-pub mod msplim;
-
-#[cfg(armv8m_main)]
-pub mod psplim;
-
-pub mod apsr;
-
-pub mod lr;
-
-pub mod pc;
diff --git a/src/register/msp.rs b/src/register/msp.rs
deleted file mode 100644
index 22ce7d9..0000000
--- a/src/register/msp.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-//! Main Stack Pointer
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[cfg(cortex_m)]
-#[inline]
-#[deprecated = "calling this function invokes Undefined Behavior, consider asm::bootstrap as an alternative"]
-pub unsafe fn write(bits: u32) {
- // Technically is writing to the stack pointer "not pushing any data to the stack"?
- // In any event, if we don't set `nostack` here, this method is useless as the new
- // stack value is immediately mutated by returning. Really this is just not a good
- // method and its use is marked as deprecated.
- asm!("msr MSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
-
-/// Reads the Non-Secure CPU register from Secure state.
-///
-/// Executing this function in Non-Secure state will return zeroes.
-#[cfg(armv8m)]
-#[inline]
-pub fn read_ns() -> u32 {
- let r;
- unsafe { asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the Non-Secure CPU register from Secure state.
-///
-/// Executing this function in Non-Secure state will be ignored.
-#[cfg(armv8m)]
-#[inline]
-pub unsafe fn write_ns(bits: u32) {
- asm!("msr MSP_NS, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
diff --git a/src/register/msplim.rs b/src/register/msplim.rs
deleted file mode 100644
index 7b45b33..0000000
--- a/src/register/msplim.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! Main Stack Pointer Limit Register
-
-use core::arch::asm;
-
-/// Reads the CPU register
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[inline]
-pub unsafe fn write(bits: u32) {
- asm!("msr MSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
diff --git a/src/register/pc.rs b/src/register/pc.rs
deleted file mode 100644
index 3460664..0000000
--- a/src/register/pc.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//! Program counter
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn write(bits: u32) {
- asm!("mov pc, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
diff --git a/src/register/primask.rs b/src/register/primask.rs
deleted file mode 100644
index e95276f..0000000
--- a/src/register/primask.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Priority mask register
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// All exceptions with configurable priority are ...
-#[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
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> Primask {
- let r: u32;
- unsafe { asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
- if r & (1 << 0) == (1 << 0) {
- Primask::Inactive
- } else {
- Primask::Active
- }
-}
diff --git a/src/register/psp.rs b/src/register/psp.rs
deleted file mode 100644
index c8f53b9..0000000
--- a/src/register/psp.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//! Process Stack Pointer
-
-#[cfg(cortex_m)]
-use core::arch::asm;
-
-/// Reads the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[cfg(cortex_m)]
-#[inline]
-pub unsafe fn write(bits: u32) {
- // See comment on msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
- // if MSP is currently being used as the stack pointer.
- asm!("msr PSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}
diff --git a/src/register/psplim.rs b/src/register/psplim.rs
deleted file mode 100644
index 832f9c6..0000000
--- a/src/register/psplim.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! Process Stack Pointer Limit Register
-
-use core::arch::asm;
-
-/// Reads the CPU register
-#[inline]
-pub fn read() -> u32 {
- let r;
- unsafe { asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
- r
-}
-
-/// Writes `bits` to the CPU register
-#[inline]
-pub unsafe fn write(bits: u32) {
- asm!("msr PSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
-}