Skip to content

Commit

Permalink
Merge #367
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bors[bot] and TDHolmes authored Dec 29, 2021
2 parents f6c0312 + 4d2c198 commit bc00af3
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 23 deletions.
17 changes: 17 additions & 0 deletions src/peripheral/dcb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand Down
117 changes: 94 additions & 23 deletions src/peripheral/dwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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].
Expand All @@ -377,46 +409,85 @@ 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) {
(AccessType::ReadOnly, EmitOption::Data) => (0b1100, false),
(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(())
Expand Down

0 comments on commit bc00af3

Please sign in to comment.