From 33a6b16b84b6fbe2cd9a82934d9e2837a7237b65 Mon Sep 17 00:00:00 2001 From: Alex Martens Date: Sun, 8 Aug 2021 14:04:28 -0700 Subject: [PATCH 1/3] Add support for additional DWT counters This adds support for these counters: * CPI counter * Exception overhead counter * LSU counter * Folded-instruction counter --- CHANGELOG.md | 7 ++ src/peripheral/dwt.rs | 155 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f82117..84375bd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ 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 + ## [v0.7.3] - 2021-07-03 ### Fixed diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 8e376a83..961f6fd5 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,7 +123,22 @@ 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 @@ -94,4 +158,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) } + } } From 52ff95e1a8ea4e63f6dc7dd7029977481eabe501 Mon Sep 17 00:00:00 2001 From: Alex Martens Date: Sat, 14 Aug 2021 08:15:45 -0700 Subject: [PATCH 2/3] Deprecate get_cycle_count in favor of cycle_count This follows the rust C-GETTER API guidelines. --- src/peripheral/dwt.rs | 11 +++++++++++ src/peripheral/mod.rs | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 961f6fd5..21af4f1c 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -144,7 +144,18 @@ impl DWT { /// 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() } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 961f31d0..8f5678db 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}; @@ -33,7 +33,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 From ba479bde8a55b88f9b5b77069f68081ffda171fd Mon Sep 17 00:00:00 2001 From: Alex Martens Date: Sat, 14 Aug 2021 12:19:10 -0700 Subject: [PATCH 3/3] Update changelog for DWT::get_cycle_count deprecation --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84375bd5..57d7dadd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - LSU counter - Folded-instruction counter +### 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