aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md17
-rw-r--r--Cargo.toml3
-rw-r--r--src/peripheral/ac.rs93
-rw-r--r--src/peripheral/dwt.rs173
-rw-r--r--src/peripheral/mod.rs35
-rw-r--r--src/peripheral/nvic.rs2
-rw-r--r--src/peripheral/scb.rs4
7 files changed, 320 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3f8211..2e7d1e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Added
+- Added support for additional DWT counters (#349)
+ - CPI counter
+ - Exception overhead counter
+ - LSU counter
+ - Folded-instruction counter
+- Added `DWT.set_cycle_count` (#347).
+- Added support for the Cortex-M7 TCM and cache access control registers.
+ There is a feature `cm7` to enable access to these.
+
+### Deprecated
+
+- `DWT::get_cycle_count` has been deprecated in favor of `DWT::cycle_count`.
+ This change was made for consistency with the [C-GETTER] convention. (#349)
+
+[C-GETTER]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter
+
## [v0.7.3] - 2021-07-03
### Fixed
diff --git a/Cargo.toml b/Cargo.toml
index 26aad27..19aa249 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,8 @@ bitfield = "0.13.2"
embedded-hal = "0.2.4"
[features]
-cm7-r0p1 = []
+cm7 = []
+cm7-r0p1 = ["cm7"]
inline-asm = []
linker-plugin-lto = []
diff --git a/src/peripheral/ac.rs b/src/peripheral/ac.rs
new file mode 100644
index 0000000..1ac5be1
--- /dev/null
+++ b/src/peripheral/ac.rs
@@ -0,0 +1,93 @@
+//! 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/dwt.rs b/src/peripheral/dwt.rs
index 8e376a8..9e8e638 100644
--- a/src/peripheral/dwt.rs
+++ b/src/peripheral/dwt.rs
@@ -62,7 +62,56 @@ pub struct Comparator {
reserved: u32,
}
+// DWT CTRL register fields
+const NUMCOMP_OFFSET: u32 = 28;
+const NOTRCPKT: u32 = 1 << 27;
+const NOEXTTRIG: u32 = 1 << 26;
+const NOCYCCNT: u32 = 1 << 25;
+const NOPRFCNT: u32 = 1 << 24;
+const CYCCNTENA: u32 = 1 << 0;
+
impl DWT {
+ /// Number of comparators implemented
+ ///
+ /// A value of zero indicates no comparator support.
+ #[inline]
+ pub fn num_comp() -> u8 {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { ((*Self::ptr()).ctrl.read() >> NUMCOMP_OFFSET) as u8 }
+ }
+
+ /// Returns `true` if the the implementation supports sampling and exception tracing
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_exception_trace() -> bool {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ctrl.read() & NOTRCPKT == 0 }
+ }
+
+ /// Returns `true` if the implementation includes external match signals
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_external_match() -> bool {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ctrl.read() & NOEXTTRIG == 0 }
+ }
+
+ /// Returns `true` if the implementation supports a cycle counter
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_cycle_counter() -> bool {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ctrl.read() & NOCYCCNT == 0 }
+ }
+
+ /// Returns `true` if the implementation the profiling counters
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn has_profiling_counter() -> bool {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ctrl.read() & NOPRFCNT == 0 }
+ }
+
/// Enables the cycle counter
///
/// The global trace enable ([`DCB::enable_trace`]) should be set before
@@ -74,17 +123,50 @@ impl DWT {
#[cfg(not(armv6m))]
#[inline]
pub fn enable_cycle_counter(&mut self) {
- unsafe { self.ctrl.modify(|r| r | 1) }
+ unsafe { self.ctrl.modify(|r| r | CYCCNTENA) }
+ }
+
+ /// Disables the cycle counter
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn disable_cycle_counter(&mut self) {
+ unsafe { self.ctrl.modify(|r| r & !CYCCNTENA) }
+ }
+
+ /// Returns `true` if the cycle counter is enabled
+ #[cfg(not(armv6m))]
+ #[inline]
+ pub fn cycle_counter_enabled() -> bool {
+ // NOTE(unsafe) atomic read with no side effects
+ unsafe { (*Self::ptr()).ctrl.read() & CYCCNTENA != 0 }
}
/// 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.
@@ -94,4 +176,93 @@ impl DWT {
// 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) }
+ }
}
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index 8155a8f..5c5e7ce 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -23,7 +23,7 @@
//! ```
//! 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::get_cycle_count`](struct.DWT.html#method.get_cycle_count) method.
+//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method.
//!
//! ``` no_run
//! # use cortex_m::peripheral::{DWT, Peripherals};
@@ -34,7 +34,7 @@
//! } // all the peripheral singletons are destroyed here
//!
//! // but this method can be called without a DWT instance
-//! let cyccnt = DWT::get_cycle_count();
+//! let cyccnt = DWT::cycle_count();
//! ```
//!
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
@@ -62,6 +62,8 @@ use core::ops;
use crate::interrupt;
+#[cfg(cm7)]
+pub mod ac;
#[cfg(not(armv6m))]
pub mod cbp;
pub mod cpuid;
@@ -93,6 +95,10 @@ mod test;
#[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,
@@ -174,6 +180,10 @@ impl Peripherals {
TAKEN = true;
Peripherals {
+ #[cfg(cm7)]
+ AC: AC {
+ _marker: PhantomData,
+ },
CBP: CBP {
_marker: PhantomData,
},
@@ -221,6 +231,27 @@ impl Peripherals {
}
}
+/// 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 _;
+
+ /// Returns a pointer to the register block (to be deprecated in 0.7)
+ #[inline(always)]
+ pub const fn ptr() -> *const self::ac::RegisterBlock {
+ Self::PTR
+ }
+}
+
/// Cache and branch predictor maintenance operations
pub struct CBP {
_marker: PhantomData<*const ()>,
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 4332707..f0c5457 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -210,7 +210,7 @@ impl NVIC {
/// # Unsafety
///
/// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ /// [`register::basepri`](crate::register::basepri)) and compromise memory safety.
#[inline]
pub unsafe fn set_priority<I>(&mut self, interrupt: I, prio: u8)
where
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
index b619328..688c431 100644
--- a/src/peripheral/scb.rs
+++ b/src/peripheral/scb.rs
@@ -832,7 +832,7 @@ impl SCB {
}
const SCB_AIRCR_VECTKEY: u32 = 0x05FA << 16;
-const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x5 << 8;
+const SCB_AIRCR_PRIGROUP_MASK: u32 = 0x7 << 8;
const SCB_AIRCR_SYSRESETREQ: u32 = 1 << 2;
impl SCB {
@@ -994,7 +994,7 @@ impl SCB {
/// # Unsafety
///
/// Changing priority levels can break priority-based critical sections (see
- /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
+ /// [`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;