aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2021-12-29 19:58:46 +0000
committerGravatar GitHub <noreply@github.com> 2021-12-29 19:58:46 +0000
commitbc00af3fd35b5c584048ef4c96400083099abe1b (patch)
treeb05fb888adc536c9e10ca9e4d5cb15634ac84ccd
parentf6c0312074e29dc5bc75224657bad265d9225b91 (diff)
parent4d2c1989644cf628788073400ad1a263ab2de6c1 (diff)
downloadcortex-m-bc00af3fd35b5c584048ef4c96400083099abe1b.tar.gz
cortex-m-bc00af3fd35b5c584048ef4c96400083099abe1b.tar.zst
cortex-m-bc00af3fd35b5c584048ef4c96400083099abe1b.zip
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 <tyler@holmesengineering.com>
-rw-r--r--src/peripheral/dcb.rs17
-rw-r--r--src/peripheral/dwt.rs117
2 files changed, 111 insertions, 23 deletions
diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs
index 056150b..ef879ac 100644
--- a/src/peripheral/dcb.rs
+++ b/src/peripheral/dcb.rs
@@ -6,6 +6,7 @@ use crate::peripheral::DCB;
use core::ptr;
const DCB_DEMCR_TRCENA: u32 = 1 << 24;
+const DCB_DEMCR_MON_EN: u32 = 1 << 16;
/// Register block
#[repr(C)]
@@ -46,6 +47,22 @@ impl DCB {
}
}
+ /// Enables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
+ #[inline]
+ pub fn enable_debug_monitor(&mut self) {
+ unsafe {
+ self.demcr.modify(|w| w | DCB_DEMCR_MON_EN);
+ }
+ }
+
+ /// Disables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception
+ #[inline]
+ pub fn disable_debug_monitor(&mut self) {
+ unsafe {
+ self.demcr.modify(|w| w & !DCB_DEMCR_MON_EN);
+ }
+ }
+
/// Is there a debugger attached? (see note)
///
/// Note: This function is [reported not to
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs
index 11dd545..db0398d 100644
--- a/src/peripheral/dwt.rs
+++ b/src/peripheral/dwt.rs
@@ -82,11 +82,17 @@ bitfield! {
#[repr(C)]
#[derive(Copy, Clone)]
/// Comparator FUNCTIONn register.
+ ///
+ /// See C1.8.17 "Comparator Function registers, DWT_FUNCTIONn"
pub struct Function(u32);
u8, function, set_function: 3, 0;
emitrange, set_emitrange: 5;
cycmatch, set_cycmatch: 7;
datavmatch, set_datavmatch: 8;
+ lnk1ena, set_lnk1ena: 9;
+ u8, datavsize, set_datavsize: 11, 10;
+ u8, datavaddr0, set_datavaddr0: 15, 12;
+ u8, datavaddr1, set_datavaddr1: 19, 16;
matched, _: 24;
}
@@ -114,10 +120,13 @@ impl DWT {
}
/// Returns `true` if the implementation supports a cycle counter
- #[cfg(not(armv6m))]
#[inline]
pub fn has_cycle_counter(&self) -> bool {
- !self.ctrl.read().nocyccnt()
+ #[cfg(not(armv6m))]
+ return !self.ctrl.read().nocyccnt();
+
+ #[cfg(armv6m)]
+ return false;
}
/// Returns `true` if the implementation the profiling counters
@@ -318,15 +327,15 @@ impl DWT {
/// Whether the comparator should match on read, write or read/write operations.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum AccessType {
- /// Generate packet only when matched adress is read from.
+ /// Generate packet only when matched address is read from.
ReadOnly,
- /// Generate packet only when matched adress is written to.
+ /// Generate packet only when matched address is written to.
WriteOnly,
- /// Generate packet when matched adress is both read from and written to.
+ /// Generate packet when matched address is both read from and written to.
ReadWrite,
}
-/// The sequence of packet(s) that should be emitted on comparator match.
+/// The sequence of packet(s) or events that should be emitted/generated on comparator match.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum EmitOption {
/// Emit only trace data value packet.
@@ -341,6 +350,14 @@ pub enum EmitOption {
AddressData,
/// Emit trace PC value and data value packets.
PCData,
+ /// Generate a watchpoint debug event. Either halts execution or fires a `DebugMonitor` exception.
+ ///
+ /// See more in section "Watchpoint debug event generation" page C1-729.
+ WatchpointDebugEvent,
+ /// Generate a `CMPMATCH[N]` event.
+ ///
+ /// See more in section "CMPMATCH[N] event generation" page C1-730.
+ CompareMatchEvent,
}
/// Settings for address matching
@@ -356,12 +373,27 @@ pub struct ComparatorAddressSettings {
pub access_type: AccessType,
}
+/// Settings for cycle count matching
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub struct CycleCountSettings {
+ /// The function selection used.
+ /// See Table C1-15 for DWT cycle count comparison functions.
+ pub emit: EmitOption,
+ /// The cycle count value to compare against.
+ pub compare: u32,
+}
+
/// The available functions of a DWT comparator.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum ComparatorFunction {
/// Compare accessed memory addresses.
Address(ComparatorAddressSettings),
+ /// Compare cycle count & target value.
+ ///
+ /// **NOTE**: only supported by comparator 0 and if the HW supports the cycle counter.
+ /// Check [`DWT::has_cycle_counter`] for support. See C1.8.1 for more details.
+ CycleCount(CycleCountSettings),
}
/// Possible error values returned on [Comparator::configure].
@@ -377,7 +409,7 @@ impl Comparator {
#[allow(clippy::missing_inline_in_public_items)]
pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
match settings {
- ComparatorFunction::Address(settings) => unsafe {
+ ComparatorFunction::Address(settings) => {
// FUNCTION, EMITRANGE
// See Table C1-14
let (function, emit_range) = match (&settings.access_type, &settings.emit) {
@@ -385,38 +417,77 @@ impl Comparator {
(AccessType::ReadOnly, EmitOption::Address) => (0b1100, true),
(AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true),
(AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false),
+ (AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false),
+ (AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false),
(AccessType::WriteOnly, EmitOption::Data) => (0b1101, false),
(AccessType::WriteOnly, EmitOption::Address) => (0b1101, true),
(AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true),
(AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false),
+ (AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false),
+ (AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false),
(AccessType::ReadWrite, EmitOption::Data) => (0b0010, false),
(AccessType::ReadWrite, EmitOption::Address) => (0b0001, true),
(AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true),
(AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false),
+ (AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false),
+ (AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false),
(AccessType::ReadWrite, EmitOption::PC) => (0b0001, false),
(_, EmitOption::PC) => return Err(DwtError::InvalidFunction),
};
- self.function.modify(|mut r| {
- r.set_function(function);
- r.set_emitrange(emit_range);
-
- // don't compare data value
- r.set_datavmatch(false);
-
- // don't compare cycle counter value
- // NOTE: only needed for comparator 0, but is SBZP.
- r.set_cycmatch(false);
-
- r
- });
+ unsafe {
+ self.function.modify(|mut r| {
+ r.set_function(function);
+ r.set_emitrange(emit_range);
+ // don't compare data value
+ r.set_datavmatch(false);
+ // don't compare cycle counter value
+ // NOTE: only needed for comparator 0, but is SBZP.
+ r.set_cycmatch(false);
+ // SBZ as needed, see Page 784/C1-724
+ r.set_datavsize(0);
+ r.set_datavaddr0(0);
+ r.set_datavaddr1(0);
+
+ r
+ });
+
+ self.comp.write(settings.address);
+ self.mask.write(settings.mask);
+ }
+ }
+ ComparatorFunction::CycleCount(settings) => {
+ let function = match &settings.emit {
+ EmitOption::PCData => 0b0001,
+ EmitOption::WatchpointDebugEvent => 0b0100,
+ EmitOption::CompareMatchEvent => 0b1000,
+ _ => return Err(DwtError::InvalidFunction),
+ };
- self.comp.write(settings.address);
- self.mask.write(settings.mask);
- },
+ unsafe {
+ self.function.modify(|mut r| {
+ r.set_function(function);
+ // emit_range is N/A for cycle count compare
+ r.set_emitrange(false);
+ // don't compare data
+ r.set_datavmatch(false);
+ // compare cyccnt
+ r.set_cycmatch(true);
+ // SBZ as needed, see Page 784/C1-724
+ r.set_datavsize(0);
+ r.set_datavaddr0(0);
+ r.set_datavaddr1(0);
+
+ r
+ });
+
+ self.comp.write(settings.compare);
+ self.mask.write(0); // SBZ, see Page 784/C1-724
+ }
+ }
}
Ok(())