aboutsummaryrefslogtreecommitdiff
path: root/src/peripheral/dwt.rs
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2021-08-14 19:42:25 +0000
committerGravatar GitHub <noreply@github.com> 2021-08-14 19:42:25 +0000
commitbb41983ad51a8d6bbde70507358b792cdbdbd3be (patch)
tree8e8ada068d35c953191eb101143ca8449b594c25 /src/peripheral/dwt.rs
parentea91f18004a408f763a7d11532cdc7e14c62d80c (diff)
parentba479bde8a55b88f9b5b77069f68081ffda171fd (diff)
downloadcortex-m-bb41983ad51a8d6bbde70507358b792cdbdbd3be.tar.gz
cortex-m-bb41983ad51a8d6bbde70507358b792cdbdbd3be.tar.zst
cortex-m-bb41983ad51a8d6bbde70507358b792cdbdbd3be.zip
Merge #349
349: Add support for additional DWT counters r=adamgreig a=newAM This adds support for these DWT counters: * CPI counter * Exception overhead counter * LSU counter * Folded-instruction counter The getters do not have the `get_` prefix per the [C-GETTER](https://rust-lang.github.io/api-guidelines/naming.html#c-getter) API guidelines. This does not match the existing `get_cycle_count` method. I was not sure if I should maintain consistency or not, let me know if you want this changed. Here is the documentation to validate each of the added methods: * [ARMv7-M DWT register summary](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/DWT-register-summary) * [Control Register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Control-register--DWT-CTRL) * `num_comp` * [ARMv6-M DWT register summary](https://developer.arm.com/documentation/ddi0419/c/Debug-Architecture/ARMv6-M-Debug/The-Data-Watchpoint-and-Trace-unit/DWT-register-summary) * The `num_comp` method is not guarded with `#[cfg(not(armv6m))]` because it is valid for both. * `has_exception_trace` * `has_external_match` * `has_cycle_counter` * `has_profiling_counter` * `disable_cycle_counter` * `cycle_counter_enabled` * [CPI count register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/CPI-Count-register--DWT-CPICNT) * `cpi_count` * `set_cpi_count` * [Exception Overhead Count register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Exception-Overhead-Count-register--DWT-EXCCNT) * `exception_count` * `set_exception_count` * [Sleep Count register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Sleep-Count-register--DWT-SLEEPCNT) * `sleep_count` * `set_sleep_count` * [LSU Count register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/LSU-Count-register--DWT-LSUCNT) * `lsu_count` * `set_lsu_count` * [Folded-instruction Count register](https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Folded-instruction-Count-register--DWT-FOLDCNT) * `fold_count` * `set_fold_count` Co-authored-by: Alex Martens <alexmgit@protonmail.com>
Diffstat (limited to 'src/peripheral/dwt.rs')
-rw-r--r--src/peripheral/dwt.rs166
1 files changed, 165 insertions, 1 deletions
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs
index 8e376a8..21af4f1 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,13 +123,39 @@ 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() }
}
@@ -94,4 +169,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) }
+ }
}