From 0da1028cbf4ae9d0accb3bb47f5d7341b31a1779 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Mon, 13 Dec 2021 16:25:36 -0800 Subject: [PATCH 01/12] add methods needed for cycle count comparisons --- src/peripheral/dcb.rs | 15 ++++++++++ src/peripheral/dwt.rs | 66 +++++++++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs index 056150bc..b2bbd570 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,20 @@ impl DCB { } } + /// Enables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception + 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 + 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 11dd5455..b827dcea 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -356,12 +356,23 @@ pub struct ComparatorAddressSettings { pub access_type: AccessType, } +/// Settings for cycle count matching +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub struct CycleCountSettings { + /// The cycle count value to compare against. + pub compare: u32, + /// The cycle count mask value to use. + pub mask: 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. + CycleCount(CycleCountSettings), } /// Possible error values returned on [Comparator::configure]. @@ -376,8 +387,8 @@ impl Comparator { /// Configure the function of the comparator #[allow(clippy::missing_inline_in_public_items)] pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> { - match settings { - ComparatorFunction::Address(settings) => unsafe { + let (func, emit, data_match, cyc_match, comp, mask) = match settings { + ComparatorFunction::Address(settings) => { // FUNCTION, EMITRANGE // See Table C1-14 let (function, emit_range) = match (&settings.access_type, &settings.emit) { @@ -400,25 +411,50 @@ impl Comparator { (_, EmitOption::PC) => return Err(DwtError::InvalidFunction), }; - self.function.modify(|mut r| { - r.set_function(function); - r.set_emitrange(emit_range); - + ( + function, + emit_range, // don't compare data value - r.set_datavmatch(false); - + false, // don't compare cycle counter value // NOTE: only needed for comparator 0, but is SBZP. - r.set_cycmatch(false); + false, + settings.address, + settings.mask, + ) + } + ComparatorFunction::CycleCount(settings) => { + ( + // emit a Debug Watchpoint event, either halting execution or + // firing a `DebugMonitor` exception + 0b0111, + // don't emit (we're going to fire an exception not trace) + false, + // don't compare data + false, + // compare cyccnt + true, + settings.compare, + settings.mask, + ) + } + }; - r - }); + unsafe { + self.function.modify(|mut r| { + r.set_function(func); + r.set_emitrange(emit); + r.set_datavmatch(data_match); - self.comp.write(settings.address); - self.mask.write(settings.mask); - }, - } + // NOTE: only valid for comparator 0, but is SBZP. + r.set_cycmatch(cyc_match); + + r + }); + self.comp.write(comp); + self.mask.write(mask); + } Ok(()) } } From 1b9b2293cd72842902869bbfb22246817089b049 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Tue, 14 Dec 2021 08:21:09 -0800 Subject: [PATCH 02/12] inline --- src/peripheral/dcb.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs index b2bbd570..ef879ac6 100644 --- a/src/peripheral/dcb.rs +++ b/src/peripheral/dcb.rs @@ -48,6 +48,7 @@ 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); @@ -55,6 +56,7 @@ impl DCB { } /// 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); From 12c4c8283cf8e4ad87be00434af4ac7308559383 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Tue, 14 Dec 2021 08:24:23 -0800 Subject: [PATCH 03/12] more correct comment --- src/peripheral/dwt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index b827dcea..7c3e3448 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -428,7 +428,7 @@ impl Comparator { // emit a Debug Watchpoint event, either halting execution or // firing a `DebugMonitor` exception 0b0111, - // don't emit (we're going to fire an exception not trace) + // emit_range is N/A for cycle count compare false, // don't compare data false, From 333584504479a15b788696befc6e1565f1646b5a Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Tue, 14 Dec 2021 09:06:38 -0800 Subject: [PATCH 04/12] review suggestions --- src/peripheral/dwt.rs | 77 ++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 7c3e3448..54b28c83 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -387,7 +387,7 @@ impl Comparator { /// Configure the function of the comparator #[allow(clippy::missing_inline_in_public_items)] pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> { - let (func, emit, data_match, cyc_match, comp, mask) = match settings { + match settings { ComparatorFunction::Address(settings) => { // FUNCTION, EMITRANGE // See Table C1-14 @@ -411,50 +411,45 @@ impl Comparator { (_, EmitOption::PC) => return Err(DwtError::InvalidFunction), }; - ( - function, - emit_range, - // don't compare data value - false, - // don't compare cycle counter value - // NOTE: only needed for comparator 0, but is SBZP. - false, - settings.address, - settings.mask, - ) + 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); + + r + }); + + self.comp.write(settings.address); + self.mask.write(settings.mask); + } } ComparatorFunction::CycleCount(settings) => { - ( - // emit a Debug Watchpoint event, either halting execution or - // firing a `DebugMonitor` exception - 0b0111, - // emit_range is N/A for cycle count compare - false, - // don't compare data - false, - // compare cyccnt - true, - settings.compare, - settings.mask, - ) + unsafe { + self.function.modify(|mut r| { + // emit a Debug Watchpoint event, either halting execution or + // firing a `DebugMonitor` exception + // See Table C1-15 DWT cycle count comparison functions + r.set_function(0b0100); + // 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); + r + }); + + self.comp.write(settings.compare); + self.mask.write(settings.mask); + } } - }; - - unsafe { - self.function.modify(|mut r| { - r.set_function(func); - r.set_emitrange(emit); - r.set_datavmatch(data_match); - - // NOTE: only valid for comparator 0, but is SBZP. - r.set_cycmatch(cyc_match); - - r - }); - - self.comp.write(comp); - self.mask.write(mask); } + Ok(()) } } From 0e8bc7913f04e3aa19950e1f5bb7f1fe51f0174b Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Tue, 14 Dec 2021 11:15:19 -0800 Subject: [PATCH 05/12] further comments - factor out function selection and more documentation --- src/peripheral/dwt.rs | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 54b28c83..8bc44d37 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -318,15 +318,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 +341,15 @@ 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 @@ -359,6 +368,9 @@ pub struct ComparatorAddressSettings { /// Settings for cycle count matching #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub struct CycleCountSettings { + /// The function selection used. + /// See Table C1-15 DWT cycle count comparison functions + pub emit: EmitOption, /// The cycle count value to compare against. pub compare: u32, /// The cycle count mask value to use. @@ -396,16 +408,22 @@ 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), @@ -429,12 +447,16 @@ impl Comparator { } } ComparatorFunction::CycleCount(settings) => { + let function = match &settings.emit { + EmitOption::PCData => 0b0001, + EmitOption::WatchpointDebugEvent => 0b0100, + EmitOption::CompareMatchEvent => 0b1000, + _ => return Err(DwtError::InvalidFunction), + }; + unsafe { self.function.modify(|mut r| { - // emit a Debug Watchpoint event, either halting execution or - // firing a `DebugMonitor` exception - // See Table C1-15 DWT cycle count comparison functions - r.set_function(0b0100); + r.set_function(function); // emit_range is N/A for cycle count compare r.set_emitrange(false); // don't compare data From 67835ae2270c82650423524518047e37c8922be3 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Tue, 14 Dec 2021 12:54:18 -0800 Subject: [PATCH 06/12] tidy up doc comments --- src/peripheral/dwt.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 8bc44d37..4101860a 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -341,14 +341,13 @@ pub enum EmitOption { AddressData, /// Emit trace PC value and data value packets. PCData, - /// Generate a watchpoint debug event. + /// Generate a watchpoint debug event. Either halts execution or fires a `DebugMonitor` exception. /// - /// either halts execution or fires a `DebugMonitor` exception. - /// See more in section "Watchpoint debug event generation" page C1-729 + /// 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 + /// See more in section "CMPMATCH[N] event generation" page C1-730. CompareMatchEvent, } @@ -369,7 +368,7 @@ pub struct ComparatorAddressSettings { #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub struct CycleCountSettings { /// The function selection used. - /// See Table C1-15 DWT cycle count comparison functions + /// See Table C1-15 for DWT cycle count comparison functions. pub emit: EmitOption, /// The cycle count value to compare against. pub compare: u32, From cd66d339cce732e6cea18441c7ae414209091340 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Wed, 15 Dec 2021 10:59:45 -0800 Subject: [PATCH 07/12] SBZ fields as needed, check if block supports cycle count compare --- src/peripheral/dwt.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 4101860a..a45032ff 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: 2, 10; + u8, datavaddr0, set_datavaddr0: 4, 12; + u8, datavaddr1, set_datavaddr1: 4, 16; matched, _: 24; } @@ -372,8 +378,6 @@ pub struct CycleCountSettings { pub emit: EmitOption, /// The cycle count value to compare against. pub compare: u32, - /// The cycle count mask value to use. - pub mask: u32, } /// The available functions of a DWT comparator. @@ -383,6 +387,8 @@ pub enum ComparatorFunction { /// Compare accessed memory addresses. Address(ComparatorAddressSettings), /// Compare cycle count & target value. + /// + /// **NOTE**: only supported by comparator 0. See C1.8.1. CycleCount(CycleCountSettings), } @@ -392,12 +398,14 @@ pub enum ComparatorFunction { pub enum DwtError { /// Invalid combination of [AccessType] and [EmitOption]. InvalidFunction, + /// The DWT block does not implement cycle count capabilities. + NoCycleCount, } impl Comparator { /// Configure the function of the comparator #[allow(clippy::missing_inline_in_public_items)] - pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> { + pub fn configure(&self, dwt: &DWT, settings: ComparatorFunction) -> Result<(), DwtError> { match settings { ComparatorFunction::Address(settings) => { // FUNCTION, EMITRANGE @@ -446,6 +454,10 @@ impl Comparator { } } ComparatorFunction::CycleCount(settings) => { + if !dwt.has_cycle_counter() { + return Err(DwtError::NoCycleCount); + } + let function = match &settings.emit { EmitOption::PCData => 0b0001, EmitOption::WatchpointDebugEvent => 0b0100, @@ -462,11 +474,16 @@ impl Comparator { 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(settings.mask); + self.mask.write(0); // SBZ, see Page 784/C1-724 } } } From a77280cedc9b08e4b280445444fe4eab02d43ba7 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Wed, 15 Dec 2021 11:13:45 -0800 Subject: [PATCH 08/12] enable has_cycle_counter for all arches. armv6m always returns false --- src/peripheral/dwt.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index a45032ff..24305ed8 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -120,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 From a0ffab5ca628a98f691568aa43cbf437a3b7f925 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Wed, 15 Dec 2021 12:10:18 -0800 Subject: [PATCH 09/12] fix fields, SBZ as needed for address compare --- src/peripheral/dwt.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 24305ed8..9751d7a2 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -90,9 +90,9 @@ bitfield! { cycmatch, set_cycmatch: 7; datavmatch, set_datavmatch: 8; lnk1ena, set_lnk1ena: 9; - u8, datavsize, set_datavsize: 2, 10; - u8, datavaddr0, set_datavaddr0: 4, 12; - u8, datavaddr1, set_datavaddr1: 4, 16; + u8, datavsize, set_datavsize: 11, 10; + u8, datavaddr0, set_datavaddr0: 15, 12; + u8, datavaddr1, set_datavaddr1: 19, 16; matched, _: 24; } @@ -448,6 +448,10 @@ impl Comparator { // 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 }); From 1b5b39e5d9de9e8e715aeec71f8b0476b9aa9c8f Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Thu, 16 Dec 2021 09:28:54 -0800 Subject: [PATCH 10/12] change has_cycle_counter to a recommended end user call --- src/peripheral/dwt.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 9751d7a2..e4845c7d 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -389,9 +389,10 @@ pub struct CycleCountSettings { pub enum ComparatorFunction { /// Compare accessed memory addresses. Address(ComparatorAddressSettings), - /// Compare cycle count & target value. + /// Compare cycle count & target value. /// - /// **NOTE**: only supported by comparator 0. See C1.8.1. + /// **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), } @@ -408,7 +409,7 @@ pub enum DwtError { impl Comparator { /// Configure the function of the comparator #[allow(clippy::missing_inline_in_public_items)] - pub fn configure(&self, dwt: &DWT, settings: ComparatorFunction) -> Result<(), DwtError> { + pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> { match settings { ComparatorFunction::Address(settings) => { // FUNCTION, EMITRANGE @@ -461,10 +462,6 @@ impl Comparator { } } ComparatorFunction::CycleCount(settings) => { - if !dwt.has_cycle_counter() { - return Err(DwtError::NoCycleCount); - } - let function = match &settings.emit { EmitOption::PCData => 0b0001, EmitOption::WatchpointDebugEvent => 0b0100, From ec48cf3c24e7debb27770e31cec6ba54fb1484a0 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Thu, 16 Dec 2021 09:37:54 -0800 Subject: [PATCH 11/12] remove unused error --- src/peripheral/dwt.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index e4845c7d..3886b430 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -402,8 +402,6 @@ pub enum ComparatorFunction { pub enum DwtError { /// Invalid combination of [AccessType] and [EmitOption]. InvalidFunction, - /// The DWT block does not implement cycle count capabilities. - NoCycleCount, } impl Comparator { From 4d2c1989644cf628788073400ad1a263ab2de6c1 Mon Sep 17 00:00:00 2001 From: Tyler Holmes Date: Thu, 16 Dec 2021 10:00:39 -0800 Subject: [PATCH 12/12] make intra-doc link --- src/peripheral/dwt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 3886b430..db0398d0 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -392,7 +392,7 @@ pub enum ComparatorFunction { /// 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. + /// Check [`DWT::has_cycle_counter`] for support. See C1.8.1 for more details. CycleCount(CycleCountSettings), }