Skip to content

Commit bb41983

Browse files
bors[bot]newAM
andauthored
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 <[email protected]>
2 parents ea91f18 + ba479bd commit bb41983

File tree

3 files changed

+181
-3
lines changed

3 files changed

+181
-3
lines changed

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
- Added support for additional DWT counters (#349)
12+
- CPI counter
13+
- Exception overhead counter
14+
- LSU counter
15+
- Folded-instruction counter
16+
17+
### Deprecated
18+
19+
- `DWT::get_cycle_count` has been deprecated in favor of `DWT::cycle_count`.
20+
This change was made for consistency with the [C-GETTER] convention. (#349)
21+
22+
[C-GETTER]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter
23+
1024
## [v0.7.3] - 2021-07-03
1125

1226
### Fixed

src/peripheral/dwt.rs

+165-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,56 @@ pub struct Comparator {
6262
reserved: u32,
6363
}
6464

65+
// DWT CTRL register fields
66+
const NUMCOMP_OFFSET: u32 = 28;
67+
const NOTRCPKT: u32 = 1 << 27;
68+
const NOEXTTRIG: u32 = 1 << 26;
69+
const NOCYCCNT: u32 = 1 << 25;
70+
const NOPRFCNT: u32 = 1 << 24;
71+
const CYCCNTENA: u32 = 1 << 0;
72+
6573
impl DWT {
74+
/// Number of comparators implemented
75+
///
76+
/// A value of zero indicates no comparator support.
77+
#[inline]
78+
pub fn num_comp() -> u8 {
79+
// NOTE(unsafe) atomic read with no side effects
80+
unsafe { ((*Self::ptr()).ctrl.read() >> NUMCOMP_OFFSET) as u8 }
81+
}
82+
83+
/// Returns `true` if the the implementation supports sampling and exception tracing
84+
#[cfg(not(armv6m))]
85+
#[inline]
86+
pub fn has_exception_trace() -> bool {
87+
// NOTE(unsafe) atomic read with no side effects
88+
unsafe { (*Self::ptr()).ctrl.read() & NOTRCPKT == 0 }
89+
}
90+
91+
/// Returns `true` if the implementation includes external match signals
92+
#[cfg(not(armv6m))]
93+
#[inline]
94+
pub fn has_external_match() -> bool {
95+
// NOTE(unsafe) atomic read with no side effects
96+
unsafe { (*Self::ptr()).ctrl.read() & NOEXTTRIG == 0 }
97+
}
98+
99+
/// Returns `true` if the implementation supports a cycle counter
100+
#[cfg(not(armv6m))]
101+
#[inline]
102+
pub fn has_cycle_counter() -> bool {
103+
// NOTE(unsafe) atomic read with no side effects
104+
unsafe { (*Self::ptr()).ctrl.read() & NOCYCCNT == 0 }
105+
}
106+
107+
/// Returns `true` if the implementation the profiling counters
108+
#[cfg(not(armv6m))]
109+
#[inline]
110+
pub fn has_profiling_counter() -> bool {
111+
// NOTE(unsafe) atomic read with no side effects
112+
unsafe { (*Self::ptr()).ctrl.read() & NOPRFCNT == 0 }
113+
}
114+
66115
/// Enables the cycle counter
67116
///
68117
/// The global trace enable ([`DCB::enable_trace`]) should be set before
@@ -74,13 +123,39 @@ impl DWT {
74123
#[cfg(not(armv6m))]
75124
#[inline]
76125
pub fn enable_cycle_counter(&mut self) {
77-
unsafe { self.ctrl.modify(|r| r | 1) }
126+
unsafe { self.ctrl.modify(|r| r | CYCCNTENA) }
127+
}
128+
129+
/// Disables the cycle counter
130+
#[cfg(not(armv6m))]
131+
#[inline]
132+
pub fn disable_cycle_counter(&mut self) {
133+
unsafe { self.ctrl.modify(|r| r & !CYCCNTENA) }
134+
}
135+
136+
/// Returns `true` if the cycle counter is enabled
137+
#[cfg(not(armv6m))]
138+
#[inline]
139+
pub fn cycle_counter_enabled() -> bool {
140+
// NOTE(unsafe) atomic read with no side effects
141+
unsafe { (*Self::ptr()).ctrl.read() & CYCCNTENA != 0 }
78142
}
79143

80144
/// Returns the current clock cycle count
81145
#[cfg(not(armv6m))]
82146
#[inline]
147+
#[deprecated(
148+
since = "0.7.4",
149+
note = "Use `cycle_count` which follows the C-GETTER convention"
150+
)]
83151
pub fn get_cycle_count() -> u32 {
152+
Self::cycle_count()
153+
}
154+
155+
/// Returns the current clock cycle count
156+
#[cfg(not(armv6m))]
157+
#[inline]
158+
pub fn cycle_count() -> u32 {
84159
// NOTE(unsafe) atomic read with no side effects
85160
unsafe { (*Self::ptr()).cyccnt.read() }
86161
}
@@ -94,4 +169,93 @@ impl DWT {
94169
// NOTE(unsafe) atomic write to a stateless, write-only register
95170
unsafe { (*Self::ptr()).lar.write(0xC5AC_CE55) }
96171
}
172+
173+
/// Get the CPI count
174+
///
175+
/// Counts additional cycles required to execute multi-cycle instructions,
176+
/// except those recorded by [`lsu_count`], and counts any instruction fetch
177+
/// stalls.
178+
///
179+
/// [`lsu_count`]: DWT::lsu_count
180+
#[cfg(not(armv6m))]
181+
#[inline]
182+
pub fn cpi_count() -> u8 {
183+
// NOTE(unsafe) atomic read with no side effects
184+
unsafe { (*Self::ptr()).cpicnt.read() as u8 }
185+
}
186+
187+
/// Set the CPI count
188+
#[cfg(not(armv6m))]
189+
#[inline]
190+
pub fn set_cpi_count(&mut self, count: u8) {
191+
unsafe { self.cpicnt.write(count as u32) }
192+
}
193+
194+
/// Get the total cycles spent in exception processing
195+
#[cfg(not(armv6m))]
196+
#[inline]
197+
pub fn exception_count() -> u8 {
198+
// NOTE(unsafe) atomic read with no side effects
199+
unsafe { (*Self::ptr()).exccnt.read() as u8 }
200+
}
201+
202+
/// Set the exception count
203+
#[cfg(not(armv6m))]
204+
#[inline]
205+
pub fn set_exception_count(&mut self, count: u8) {
206+
unsafe { self.exccnt.write(count as u32) }
207+
}
208+
209+
/// Get the total number of cycles that the processor is sleeping
210+
///
211+
/// ARM recommends that this counter counts all cycles when the processor is sleeping,
212+
/// regardless of whether a WFI or WFE instruction, or the sleep-on-exit functionality,
213+
/// caused the entry to sleep mode.
214+
/// However, all sleep features are implementation defined and therefore when
215+
/// this counter counts is implementation defined.
216+
#[cfg(not(armv6m))]
217+
#[inline]
218+
pub fn sleep_count() -> u8 {
219+
// NOTE(unsafe) atomic read with no side effects
220+
unsafe { (*Self::ptr()).sleepcnt.read() as u8 }
221+
}
222+
223+
/// Set the sleep count
224+
#[cfg(not(armv6m))]
225+
#[inline]
226+
pub fn set_sleep_count(&mut self, count: u8) {
227+
unsafe { self.sleepcnt.write(count as u32) }
228+
}
229+
230+
/// Get the additional cycles required to execute all load or store instructions
231+
#[cfg(not(armv6m))]
232+
#[inline]
233+
pub fn lsu_count() -> u8 {
234+
// NOTE(unsafe) atomic read with no side effects
235+
unsafe { (*Self::ptr()).lsucnt.read() as u8 }
236+
}
237+
238+
/// Set the lsu count
239+
#[cfg(not(armv6m))]
240+
#[inline]
241+
pub fn set_lsu_count(&mut self, count: u8) {
242+
unsafe { self.lsucnt.write(count as u32) }
243+
}
244+
245+
/// Get the folded instruction count
246+
///
247+
/// Increments on each instruction that takes 0 cycles.
248+
#[cfg(not(armv6m))]
249+
#[inline]
250+
pub fn fold_count() -> u8 {
251+
// NOTE(unsafe) atomic read with no side effects
252+
unsafe { (*Self::ptr()).foldcnt.read() as u8 }
253+
}
254+
255+
/// Set the folded instruction count
256+
#[cfg(not(armv6m))]
257+
#[inline]
258+
pub fn set_fold_count(&mut self, count: u8) {
259+
unsafe { self.foldcnt.write(count as u32) }
260+
}
97261
}

src/peripheral/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
//! ```
2424
//! A part of the peripheral API doesn't require access to a peripheral instance. This part of the
2525
//! API is provided as static methods on the peripheral types. One example is the
26-
//! [`DWT::get_cycle_count`](struct.DWT.html#method.get_cycle_count) method.
26+
//! [`DWT::cycle_count`](struct.DWT.html#method.cycle_count) method.
2727
//!
2828
//! ``` no_run
2929
//! # use cortex_m::peripheral::{DWT, Peripherals};
@@ -33,7 +33,7 @@
3333
//! } // all the peripheral singletons are destroyed here
3434
//!
3535
//! // but this method can be called without a DWT instance
36-
//! let cyccnt = DWT::get_cycle_count();
36+
//! let cyccnt = DWT::cycle_count();
3737
//! ```
3838
//!
3939
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is

0 commit comments

Comments
 (0)