Skip to content

Commit bc00af3

Browse files
bors[bot]TDHolmes
andauthored
Merge #367
367: add methods needed for cycle count comparisons r=adamgreig a=TDHolmes Extends the existing DWT comparator code to include cycle count comparisons which fire a `DebugMonitor` exception, if enabled with `enable_debug_monitor`. See working example [here](https://github.com/TDHolmes/embedded-profiling/blob/58d8b106921977816e2b5a05bcb43e976197edaf/ep-dwt/src/lib.rs#L57) Co-authored-by: Tyler Holmes <[email protected]>
2 parents f6c0312 + 4d2c198 commit bc00af3

File tree

2 files changed

+111
-23
lines changed

2 files changed

+111
-23
lines changed

src/peripheral/dcb.rs

+17
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::peripheral::DCB;
66
use core::ptr;
77

88
const DCB_DEMCR_TRCENA: u32 = 1 << 24;
9+
const DCB_DEMCR_MON_EN: u32 = 1 << 16;
910

1011
/// Register block
1112
#[repr(C)]
@@ -46,6 +47,22 @@ impl DCB {
4647
}
4748
}
4849

50+
/// Enables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
51+
#[inline]
52+
pub fn enable_debug_monitor(&mut self) {
53+
unsafe {
54+
self.demcr.modify(|w| w | DCB_DEMCR_MON_EN);
55+
}
56+
}
57+
58+
/// Disables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
59+
#[inline]
60+
pub fn disable_debug_monitor(&mut self) {
61+
unsafe {
62+
self.demcr.modify(|w| w & !DCB_DEMCR_MON_EN);
63+
}
64+
}
65+
4966
/// Is there a debugger attached? (see note)
5067
///
5168
/// Note: This function is [reported not to

src/peripheral/dwt.rs

+94-23
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,17 @@ bitfield! {
8282
#[repr(C)]
8383
#[derive(Copy, Clone)]
8484
/// Comparator FUNCTIONn register.
85+
///
86+
/// See C1.8.17 "Comparator Function registers, DWT_FUNCTIONn"
8587
pub struct Function(u32);
8688
u8, function, set_function: 3, 0;
8789
emitrange, set_emitrange: 5;
8890
cycmatch, set_cycmatch: 7;
8991
datavmatch, set_datavmatch: 8;
92+
lnk1ena, set_lnk1ena: 9;
93+
u8, datavsize, set_datavsize: 11, 10;
94+
u8, datavaddr0, set_datavaddr0: 15, 12;
95+
u8, datavaddr1, set_datavaddr1: 19, 16;
9096
matched, _: 24;
9197
}
9298

@@ -114,10 +120,13 @@ impl DWT {
114120
}
115121

116122
/// Returns `true` if the implementation supports a cycle counter
117-
#[cfg(not(armv6m))]
118123
#[inline]
119124
pub fn has_cycle_counter(&self) -> bool {
120-
!self.ctrl.read().nocyccnt()
125+
#[cfg(not(armv6m))]
126+
return !self.ctrl.read().nocyccnt();
127+
128+
#[cfg(armv6m)]
129+
return false;
121130
}
122131

123132
/// Returns `true` if the implementation the profiling counters
@@ -318,15 +327,15 @@ impl DWT {
318327
/// Whether the comparator should match on read, write or read/write operations.
319328
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
320329
pub enum AccessType {
321-
/// Generate packet only when matched adress is read from.
330+
/// Generate packet only when matched address is read from.
322331
ReadOnly,
323-
/// Generate packet only when matched adress is written to.
332+
/// Generate packet only when matched address is written to.
324333
WriteOnly,
325-
/// Generate packet when matched adress is both read from and written to.
334+
/// Generate packet when matched address is both read from and written to.
326335
ReadWrite,
327336
}
328337

329-
/// The sequence of packet(s) that should be emitted on comparator match.
338+
/// The sequence of packet(s) or events that should be emitted/generated on comparator match.
330339
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
331340
pub enum EmitOption {
332341
/// Emit only trace data value packet.
@@ -341,6 +350,14 @@ pub enum EmitOption {
341350
AddressData,
342351
/// Emit trace PC value and data value packets.
343352
PCData,
353+
/// Generate a watchpoint debug event. Either halts execution or fires a `DebugMonitor` exception.
354+
///
355+
/// See more in section "Watchpoint debug event generation" page C1-729.
356+
WatchpointDebugEvent,
357+
/// Generate a `CMPMATCH[N]` event.
358+
///
359+
/// See more in section "CMPMATCH[N] event generation" page C1-730.
360+
CompareMatchEvent,
344361
}
345362

346363
/// Settings for address matching
@@ -356,12 +373,27 @@ pub struct ComparatorAddressSettings {
356373
pub access_type: AccessType,
357374
}
358375

376+
/// Settings for cycle count matching
377+
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
378+
pub struct CycleCountSettings {
379+
/// The function selection used.
380+
/// See Table C1-15 for DWT cycle count comparison functions.
381+
pub emit: EmitOption,
382+
/// The cycle count value to compare against.
383+
pub compare: u32,
384+
}
385+
359386
/// The available functions of a DWT comparator.
360387
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
361388
#[non_exhaustive]
362389
pub enum ComparatorFunction {
363390
/// Compare accessed memory addresses.
364391
Address(ComparatorAddressSettings),
392+
/// Compare cycle count & target value.
393+
///
394+
/// **NOTE**: only supported by comparator 0 and if the HW supports the cycle counter.
395+
/// Check [`DWT::has_cycle_counter`] for support. See C1.8.1 for more details.
396+
CycleCount(CycleCountSettings),
365397
}
366398

367399
/// Possible error values returned on [Comparator::configure].
@@ -377,46 +409,85 @@ impl Comparator {
377409
#[allow(clippy::missing_inline_in_public_items)]
378410
pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
379411
match settings {
380-
ComparatorFunction::Address(settings) => unsafe {
412+
ComparatorFunction::Address(settings) => {
381413
// FUNCTION, EMITRANGE
382414
// See Table C1-14
383415
let (function, emit_range) = match (&settings.access_type, &settings.emit) {
384416
(AccessType::ReadOnly, EmitOption::Data) => (0b1100, false),
385417
(AccessType::ReadOnly, EmitOption::Address) => (0b1100, true),
386418
(AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true),
387419
(AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false),
420+
(AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false),
421+
(AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false),
388422

389423
(AccessType::WriteOnly, EmitOption::Data) => (0b1101, false),
390424
(AccessType::WriteOnly, EmitOption::Address) => (0b1101, true),
391425
(AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true),
392426
(AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false),
427+
(AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false),
428+
(AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false),
393429

394430
(AccessType::ReadWrite, EmitOption::Data) => (0b0010, false),
395431
(AccessType::ReadWrite, EmitOption::Address) => (0b0001, true),
396432
(AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true),
397433
(AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false),
434+
(AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false),
435+
(AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false),
398436

399437
(AccessType::ReadWrite, EmitOption::PC) => (0b0001, false),
400438
(_, EmitOption::PC) => return Err(DwtError::InvalidFunction),
401439
};
402440

403-
self.function.modify(|mut r| {
404-
r.set_function(function);
405-
r.set_emitrange(emit_range);
406-
407-
// don't compare data value
408-
r.set_datavmatch(false);
409-
410-
// don't compare cycle counter value
411-
// NOTE: only needed for comparator 0, but is SBZP.
412-
r.set_cycmatch(false);
413-
414-
r
415-
});
441+
unsafe {
442+
self.function.modify(|mut r| {
443+
r.set_function(function);
444+
r.set_emitrange(emit_range);
445+
// don't compare data value
446+
r.set_datavmatch(false);
447+
// don't compare cycle counter value
448+
// NOTE: only needed for comparator 0, but is SBZP.
449+
r.set_cycmatch(false);
450+
// SBZ as needed, see Page 784/C1-724
451+
r.set_datavsize(0);
452+
r.set_datavaddr0(0);
453+
r.set_datavaddr1(0);
454+
455+
r
456+
});
457+
458+
self.comp.write(settings.address);
459+
self.mask.write(settings.mask);
460+
}
461+
}
462+
ComparatorFunction::CycleCount(settings) => {
463+
let function = match &settings.emit {
464+
EmitOption::PCData => 0b0001,
465+
EmitOption::WatchpointDebugEvent => 0b0100,
466+
EmitOption::CompareMatchEvent => 0b1000,
467+
_ => return Err(DwtError::InvalidFunction),
468+
};
416469

417-
self.comp.write(settings.address);
418-
self.mask.write(settings.mask);
419-
},
470+
unsafe {
471+
self.function.modify(|mut r| {
472+
r.set_function(function);
473+
// emit_range is N/A for cycle count compare
474+
r.set_emitrange(false);
475+
// don't compare data
476+
r.set_datavmatch(false);
477+
// compare cyccnt
478+
r.set_cycmatch(true);
479+
// SBZ as needed, see Page 784/C1-724
480+
r.set_datavsize(0);
481+
r.set_datavaddr0(0);
482+
r.set_datavaddr1(0);
483+
484+
r
485+
});
486+
487+
self.comp.write(settings.compare);
488+
self.mask.write(0); // SBZ, see Page 784/C1-724
489+
}
490+
}
420491
}
421492

422493
Ok(())

0 commit comments

Comments
 (0)