diff options
Diffstat (limited to 'src/peripheral/dwt.rs')
-rw-r--r-- | src/peripheral/dwt.rs | 209 |
1 files changed, 177 insertions, 32 deletions
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 9e8e638..720511b 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -5,12 +5,13 @@ use volatile_register::WO; use volatile_register::{RO, RW}; use crate::peripheral::DWT; +use bitfield::bitfield; /// Register block #[repr(C)] pub struct RegisterBlock { /// Control - pub ctrl: RW<u32>, + pub ctrl: RW<Ctrl>, /// Cycle Count #[cfg(not(armv6m))] pub cyccnt: RW<u32>, @@ -50,6 +51,21 @@ pub struct RegisterBlock { pub lsr: RO<u32>, } +bitfield! { + /// Control register. + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Ctrl(u32); + get_cyccntena, set_cyccntena: 0; + get_pcsamplena, set_pcsamplena: 12; + get_exctrcena, set_exctrcena: 16; + get_noprfcnt, _: 24; + get_nocyccnt, _: 25; + get_noexttrig, _: 26; + get_notrcpkt, _: 27; + u8, get_numcomp, _: 31, 28; +} + /// Comparator #[repr(C)] pub struct Comparator { @@ -58,58 +74,57 @@ pub struct Comparator { /// Comparator Mask pub mask: RW<u32>, /// Comparator Function - pub function: RW<u32>, + pub function: RW<Function>, reserved: u32, } -// DWT CTRL register fields -const NUMCOMP_OFFSET: u32 = 28; -const NOTRCPKT: u32 = 1 << 27; -const NOEXTTRIG: u32 = 1 << 26; -const NOCYCCNT: u32 = 1 << 25; -const NOPRFCNT: u32 = 1 << 24; -const CYCCNTENA: u32 = 1 << 0; +bitfield! { + #[repr(C)] + #[derive(Copy, Clone)] + /// Comparator FUNCTIONn register. + pub struct Function(u32); + u8, get_function, set_function: 3, 0; + get_emitrange, set_emitrange: 5; + get_cycmatch, set_cycmatch: 7; + get_datavmatch, set_datavmatch: 8; + get_matched, _: 24; +} impl DWT { /// Number of comparators implemented /// /// A value of zero indicates no comparator support. #[inline] - pub fn num_comp() -> u8 { - // NOTE(unsafe) atomic read with no side effects - unsafe { ((*Self::ptr()).ctrl.read() >> NUMCOMP_OFFSET) as u8 } + pub fn num_comp(&self) -> u8 { + self.ctrl.read().get_numcomp() } /// Returns `true` if the the implementation supports sampling and exception tracing #[cfg(not(armv6m))] #[inline] - pub fn has_exception_trace() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).ctrl.read() & NOTRCPKT == 0 } + pub fn has_exception_trace(&self) -> bool { + self.ctrl.read().get_notrcpkt() == false } /// Returns `true` if the implementation includes external match signals #[cfg(not(armv6m))] #[inline] - pub fn has_external_match() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).ctrl.read() & NOEXTTRIG == 0 } + pub fn has_external_match(&self) -> bool { + self.ctrl.read().get_noexttrig() == false } /// Returns `true` if the implementation supports a cycle counter #[cfg(not(armv6m))] #[inline] - pub fn has_cycle_counter() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).ctrl.read() & NOCYCCNT == 0 } + pub fn has_cycle_counter(&self) -> bool { + self.ctrl.read().get_nocyccnt() == false } /// Returns `true` if the implementation the profiling counters #[cfg(not(armv6m))] #[inline] - pub fn has_profiling_counter() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).ctrl.read() & NOPRFCNT == 0 } + pub fn has_profiling_counter(&self) -> bool { + self.ctrl.read().get_noprfcnt() == false } /// Enables the cycle counter @@ -123,22 +138,43 @@ impl DWT { #[cfg(not(armv6m))] #[inline] pub fn enable_cycle_counter(&mut self) { - unsafe { self.ctrl.modify(|r| r | CYCCNTENA) } + unsafe { + self.ctrl.modify(|mut r| { + r.set_cyccntena(true); + r + }); + } } - /// Disables the cycle counter + /// Returns `true` if the cycle counter is enabled #[cfg(not(armv6m))] #[inline] - pub fn disable_cycle_counter(&mut self) { - unsafe { self.ctrl.modify(|r| r & !CYCCNTENA) } + pub fn cycle_counter_enabled(&self) -> bool { + self.ctrl.read().get_cyccntena() } - /// Returns `true` if the cycle counter is enabled + /// Whether to enable exception tracing #[cfg(not(armv6m))] #[inline] - pub fn cycle_counter_enabled() -> bool { - // NOTE(unsafe) atomic read with no side effects - unsafe { (*Self::ptr()).ctrl.read() & CYCCNTENA != 0 } + pub fn enable_exception_tracing(&mut self, bit: bool) { + unsafe { + self.ctrl.modify(|mut r| { + r.set_exctrcena(bit); + r + }); + } + } + + /// Whether to periodically generate PC samples + #[cfg(not(armv6m))] + #[inline] + pub fn enable_pc_samples(&mut self, bit: bool) { + unsafe { + self.ctrl.modify(|mut r| { + r.set_pcsamplena(bit); + r + }); + } } /// Returns the current clock cycle count @@ -266,3 +302,112 @@ impl DWT { unsafe { self.foldcnt.write(count as u32) } } } + +/// Whether the comparator should match on read, write or read/write operations. +#[derive(Debug, PartialEq)] +pub enum AccessType { + /// Generate packet only when matched adress is read from. + ReadOnly, + /// Generate packet only when matched adress is written to. + WriteOnly, + /// Generate packet when matched adress is both read from and written to. + ReadWrite, +} + +/// The sequence of packet(s) that should be emitted on comparator match. +#[derive(Debug, PartialEq)] +pub enum EmitOption { + /// Emit only trace data value packet. + Data, + /// Emit only trace address packet. + Address, + /// Emit only trace PC value packet + /// NOTE: only compatible with [AccessType::ReadWrite]. + PC, + /// Emit trace address and data value packets. + AddressData, + /// Emit trace PC value and data value packets. + PCData, +} + +/// Settings for address matching +#[derive(Debug)] +pub struct ComparatorAddressSettings { + /// The address to match against. + pub address: u32, + /// The address mask to match against. + pub mask: u32, + /// What sequence of packet(s) to emit on comparator match. + pub emit: EmitOption, + /// Whether to match on read, write or read/write operations. + pub access_type: AccessType, +} + +/// The available functions of a DWT comparator. +#[derive(Debug)] +pub enum ComparatorFunction { + /// Compare accessed memory addresses. + Address(ComparatorAddressSettings), +} + +/// Possible error values returned on [Comparator::configure]. +#[derive(Debug)] +pub enum DWTError { + /// Invalid combination of [AccessType] and [EmitOption]. + InvalidFunction, +} + +impl Comparator { + /// Configure the function of the comparator + #[inline] + pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DWTError> { + match settings { + ComparatorFunction::Address(settings) => unsafe { + if settings.emit == EmitOption::PC && settings.access_type != AccessType::ReadWrite + { + return Err(DWTError::InvalidFunction); + } + + self.function.modify(|mut r| { + // 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); + + // 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::WriteOnly, EmitOption::Data) => (0b1101, false), + (AccessType::WriteOnly, EmitOption::Address) => (0b1101, true), + (AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true), + (AccessType::WriteOnly, EmitOption::PCData) => (0b1111, 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::PC) => (0b0001, false), + (_, EmitOption::PC) => unreachable!(), // cannot return Err here; handled above + }; + r.set_function(function); + r.set_emitrange(emit_range); + + r + }); + + self.comp.write(settings.address); + self.mask.write(settings.mask); + }, + } + + Ok(()) + } +} |