Skip to content

Commit 33a6b16

Browse files
committed
Add support for additional DWT counters
This adds support for these counters: * CPI counter * Exception overhead counter * LSU counter * Folded-instruction counter
1 parent ea91f18 commit 33a6b16

File tree

2 files changed

+161
-1
lines changed

2 files changed

+161
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ 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+
1017
## [v0.7.3] - 2021-07-03
1118

1219
### Fixed

src/peripheral/dwt.rs

Lines changed: 154 additions & 1 deletion
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,7 +123,22 @@ 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
@@ -94,4 +158,93 @@ impl DWT {
94158
// NOTE(unsafe) atomic write to a stateless, write-only register
95159
unsafe { (*Self::ptr()).lar.write(0xC5AC_CE55) }
96160
}
161+
162+
/// Get the CPI count
163+
///
164+
/// Counts additional cycles required to execute multi-cycle instructions,
165+
/// except those recorded by [`lsu_count`], and counts any instruction fetch
166+
/// stalls.
167+
///
168+
/// [`lsu_count`]: DWT::lsu_count
169+
#[cfg(not(armv6m))]
170+
#[inline]
171+
pub fn cpi_count() -> u8 {
172+
// NOTE(unsafe) atomic read with no side effects
173+
unsafe { (*Self::ptr()).cpicnt.read() as u8 }
174+
}
175+
176+
/// Set the CPI count
177+
#[cfg(not(armv6m))]
178+
#[inline]
179+
pub fn set_cpi_count(&mut self, count: u8) {
180+
unsafe { self.cpicnt.write(count as u32) }
181+
}
182+
183+
/// Get the total cycles spent in exception processing
184+
#[cfg(not(armv6m))]
185+
#[inline]
186+
pub fn exception_count() -> u8 {
187+
// NOTE(unsafe) atomic read with no side effects
188+
unsafe { (*Self::ptr()).exccnt.read() as u8 }
189+
}
190+
191+
/// Set the exception count
192+
#[cfg(not(armv6m))]
193+
#[inline]
194+
pub fn set_exception_count(&mut self, count: u8) {
195+
unsafe { self.exccnt.write(count as u32) }
196+
}
197+
198+
/// Get the total number of cycles that the processor is sleeping
199+
///
200+
/// ARM recommends that this counter counts all cycles when the processor is sleeping,
201+
/// regardless of whether a WFI or WFE instruction, or the sleep-on-exit functionality,
202+
/// caused the entry to sleep mode.
203+
/// However, all sleep features are implementation defined and therefore when
204+
/// this counter counts is implementation defined.
205+
#[cfg(not(armv6m))]
206+
#[inline]
207+
pub fn sleep_count() -> u8 {
208+
// NOTE(unsafe) atomic read with no side effects
209+
unsafe { (*Self::ptr()).sleepcnt.read() as u8 }
210+
}
211+
212+
/// Set the sleep count
213+
#[cfg(not(armv6m))]
214+
#[inline]
215+
pub fn set_sleep_count(&mut self, count: u8) {
216+
unsafe { self.sleepcnt.write(count as u32) }
217+
}
218+
219+
/// Get the additional cycles required to execute all load or store instructions
220+
#[cfg(not(armv6m))]
221+
#[inline]
222+
pub fn lsu_count() -> u8 {
223+
// NOTE(unsafe) atomic read with no side effects
224+
unsafe { (*Self::ptr()).lsucnt.read() as u8 }
225+
}
226+
227+
/// Set the lsu count
228+
#[cfg(not(armv6m))]
229+
#[inline]
230+
pub fn set_lsu_count(&mut self, count: u8) {
231+
unsafe { self.lsucnt.write(count as u32) }
232+
}
233+
234+
/// Get the folded instruction count
235+
///
236+
/// Increments on each instruction that takes 0 cycles.
237+
#[cfg(not(armv6m))]
238+
#[inline]
239+
pub fn fold_count() -> u8 {
240+
// NOTE(unsafe) atomic read with no side effects
241+
unsafe { (*Self::ptr()).foldcnt.read() as u8 }
242+
}
243+
244+
/// Set the folded instruction count
245+
#[cfg(not(armv6m))]
246+
#[inline]
247+
pub fn set_fold_count(&mut self, count: u8) {
248+
unsafe { self.foldcnt.write(count as u32) }
249+
}
97250
}

0 commit comments

Comments
 (0)