@@ -5,12 +5,13 @@ use volatile_register::WO;
55use volatile_register:: { RO , RW } ;
66
77use crate :: peripheral:: DWT ;
8+ use bitfield:: bitfield;
89
910/// Register block
1011#[ repr( C ) ]
1112pub struct RegisterBlock {
1213 /// Control
13- pub ctrl : RW < u32 > ,
14+ pub ctrl : RW < Ctrl > ,
1415 /// Cycle Count
1516 #[ cfg( not( armv6m) ) ]
1617 pub cyccnt : RW < u32 > ,
@@ -50,6 +51,21 @@ pub struct RegisterBlock {
5051 pub lsr : RO < u32 > ,
5152}
5253
54+ bitfield ! {
55+ /// Control register.
56+ #[ repr( C ) ]
57+ #[ derive( Copy , Clone ) ]
58+ pub struct Ctrl ( u32 ) ;
59+ cyccntena, set_cyccntena: 0 ;
60+ pcsamplena, set_pcsamplena: 12 ;
61+ exctrcena, set_exctrcena: 16 ;
62+ noprfcnt, _: 24 ;
63+ nocyccnt, _: 25 ;
64+ noexttrig, _: 26 ;
65+ notrcpkt, _: 27 ;
66+ u8 , numcomp, _: 31 , 28 ;
67+ }
68+
5369/// Comparator
5470#[ repr( C ) ]
5571pub struct Comparator {
@@ -58,58 +74,57 @@ pub struct Comparator {
5874 /// Comparator Mask
5975 pub mask : RW < u32 > ,
6076 /// Comparator Function
61- pub function : RW < u32 > ,
77+ pub function : RW < Function > ,
6278 reserved : u32 ,
6379}
6480
65- // DWT CTRL register fields
66- const NUMCOMP_OFFSET : u32 = 28 ;
67- const NOTRCPKT : u32 = 1 << 27 ;
68- const NOEXTTRIG : u32 = 1 << 26 ;
69- const NOCYCCNT : u32 = 1 << 25 ;
70- const NOPRFCNT : u32 = 1 << 24 ;
71- const CYCCNTENA : u32 = 1 << 0 ;
81+ bitfield ! {
82+ #[ repr( C ) ]
83+ #[ derive( Copy , Clone ) ]
84+ /// Comparator FUNCTIONn register.
85+ pub struct Function ( u32 ) ;
86+ u8 , function, set_function: 3 , 0 ;
87+ emitrange, set_emitrange: 5 ;
88+ cycmatch, set_cycmatch: 7 ;
89+ datavmatch, set_datavmatch: 8 ;
90+ matched, _: 24 ;
91+ }
7292
7393impl DWT {
7494 /// Number of comparators implemented
7595 ///
7696 /// A value of zero indicates no comparator support.
7797 #[ inline]
78- pub fn num_comp ( ) -> u8 {
79- // NOTE(unsafe) atomic read with no side effects
80- unsafe { ( ( * Self :: ptr ( ) ) . ctrl . read ( ) >> NUMCOMP_OFFSET ) as u8 }
98+ pub fn num_comp ( & self ) -> u8 {
99+ self . ctrl . read ( ) . numcomp ( )
81100 }
82101
83102 /// Returns `true` if the the implementation supports sampling and exception tracing
84103 #[ cfg( not( armv6m) ) ]
85104 #[ inline]
86- pub fn has_exception_trace ( ) -> bool {
87- // NOTE(unsafe) atomic read with no side effects
88- unsafe { ( * Self :: ptr ( ) ) . ctrl . read ( ) & NOTRCPKT == 0 }
105+ pub fn has_exception_trace ( & self ) -> bool {
106+ !self . ctrl . read ( ) . notrcpkt ( )
89107 }
90108
91109 /// Returns `true` if the implementation includes external match signals
92110 #[ cfg( not( armv6m) ) ]
93111 #[ inline]
94- pub fn has_external_match ( ) -> bool {
95- // NOTE(unsafe) atomic read with no side effects
96- unsafe { ( * Self :: ptr ( ) ) . ctrl . read ( ) & NOEXTTRIG == 0 }
112+ pub fn has_external_match ( & self ) -> bool {
113+ !self . ctrl . read ( ) . noexttrig ( )
97114 }
98115
99116 /// Returns `true` if the implementation supports a cycle counter
100117 #[ cfg( not( armv6m) ) ]
101118 #[ inline]
102- pub fn has_cycle_counter ( ) -> bool {
103- // NOTE(unsafe) atomic read with no side effects
104- unsafe { ( * Self :: ptr ( ) ) . ctrl . read ( ) & NOCYCCNT == 0 }
119+ pub fn has_cycle_counter ( & self ) -> bool {
120+ !self . ctrl . read ( ) . nocyccnt ( )
105121 }
106122
107123 /// Returns `true` if the implementation the profiling counters
108124 #[ cfg( not( armv6m) ) ]
109125 #[ inline]
110- pub fn has_profiling_counter ( ) -> bool {
111- // NOTE(unsafe) atomic read with no side effects
112- unsafe { ( * Self :: ptr ( ) ) . ctrl . read ( ) & NOPRFCNT == 0 }
126+ pub fn has_profiling_counter ( & self ) -> bool {
127+ !self . ctrl . read ( ) . noprfcnt ( )
113128 }
114129
115130 /// Enables the cycle counter
@@ -123,22 +138,55 @@ impl DWT {
123138 #[ cfg( not( armv6m) ) ]
124139 #[ inline]
125140 pub fn enable_cycle_counter ( & mut self ) {
126- unsafe { self . ctrl . modify ( |r| r | CYCCNTENA ) }
141+ unsafe {
142+ self . ctrl . modify ( |mut r| {
143+ r. set_cyccntena ( true ) ;
144+ r
145+ } ) ;
146+ }
127147 }
128148
129- /// Disables the cycle counter
149+ /// Returns `true` if the cycle counter is enabled
130150 #[ cfg( not( armv6m) ) ]
131151 #[ inline]
132- pub fn disable_cycle_counter ( & mut self ) {
133- unsafe { self . ctrl . modify ( |r| r & ! CYCCNTENA ) }
152+ pub fn cycle_counter_enabled ( & self ) -> bool {
153+ self . ctrl . read ( ) . cyccntena ( )
134154 }
135155
136- /// Returns `true` if the cycle counter is enabled
156+ /// Enables exception tracing
137157 #[ cfg( not( armv6m) ) ]
138158 #[ inline]
139- pub fn cycle_counter_enabled ( ) -> bool {
140- // NOTE(unsafe) atomic read with no side effects
141- unsafe { ( * Self :: ptr ( ) ) . ctrl . read ( ) & CYCCNTENA != 0 }
159+ pub fn enable_exception_tracing ( & mut self ) {
160+ unsafe {
161+ self . ctrl . modify ( |mut r| {
162+ r. set_exctrcena ( true ) ;
163+ r
164+ } ) ;
165+ }
166+ }
167+
168+ /// Disables exception tracing
169+ #[ cfg( not( armv6m) ) ]
170+ #[ inline]
171+ pub fn disable_exception_tracing ( & mut self ) {
172+ unsafe {
173+ self . ctrl . modify ( |mut r| {
174+ r. set_exctrcena ( false ) ;
175+ r
176+ } ) ;
177+ }
178+ }
179+
180+ /// Whether to periodically generate PC samples
181+ #[ cfg( not( armv6m) ) ]
182+ #[ inline]
183+ pub fn enable_pc_samples ( & mut self , bit : bool ) {
184+ unsafe {
185+ self . ctrl . modify ( |mut r| {
186+ r. set_pcsamplena ( bit) ;
187+ r
188+ } ) ;
189+ }
142190 }
143191
144192 /// Returns the current clock cycle count
@@ -266,3 +314,111 @@ impl DWT {
266314 unsafe { self . foldcnt . write ( count as u32 ) }
267315 }
268316}
317+
318+ /// Whether the comparator should match on read, write or read/write operations.
319+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
320+ pub enum AccessType {
321+ /// Generate packet only when matched adress is read from.
322+ ReadOnly ,
323+ /// Generate packet only when matched adress is written to.
324+ WriteOnly ,
325+ /// Generate packet when matched adress is both read from and written to.
326+ ReadWrite ,
327+ }
328+
329+ /// The sequence of packet(s) that should be emitted on comparator match.
330+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
331+ pub enum EmitOption {
332+ /// Emit only trace data value packet.
333+ Data ,
334+ /// Emit only trace address packet.
335+ Address ,
336+ /// Emit only trace PC value packet
337+ ///
338+ /// *NOTE* only compatible with [AccessType::ReadWrite].
339+ PC ,
340+ /// Emit trace address and data value packets.
341+ AddressData ,
342+ /// Emit trace PC value and data value packets.
343+ PCData ,
344+ }
345+
346+ /// Settings for address matching
347+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
348+ pub struct ComparatorAddressSettings {
349+ /// The address to match against.
350+ pub address : u32 ,
351+ /// The address mask to match against.
352+ pub mask : u32 ,
353+ /// What sequence of packet(s) to emit on comparator match.
354+ pub emit : EmitOption ,
355+ /// Whether to match on read, write or read/write operations.
356+ pub access_type : AccessType ,
357+ }
358+
359+ /// The available functions of a DWT comparator.
360+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
361+ #[ non_exhaustive]
362+ pub enum ComparatorFunction {
363+ /// Compare accessed memory addresses.
364+ Address ( ComparatorAddressSettings ) ,
365+ }
366+
367+ /// Possible error values returned on [Comparator::configure].
368+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
369+ #[ non_exhaustive]
370+ pub enum DwtError {
371+ /// Invalid combination of [AccessType] and [EmitOption].
372+ InvalidFunction ,
373+ }
374+
375+ impl Comparator {
376+ /// Configure the function of the comparator
377+ #[ allow( clippy:: missing_inline_in_public_items) ]
378+ pub fn configure ( & self , settings : ComparatorFunction ) -> Result < ( ) , DwtError > {
379+ match settings {
380+ ComparatorFunction :: Address ( settings) => unsafe {
381+ // FUNCTION, EMITRANGE
382+ // See Table C1-14
383+ let ( function, emit_range) = match ( & settings. access_type , & settings. emit ) {
384+ ( AccessType :: ReadOnly , EmitOption :: Data ) => ( 0b1100 , false ) ,
385+ ( AccessType :: ReadOnly , EmitOption :: Address ) => ( 0b1100 , true ) ,
386+ ( AccessType :: ReadOnly , EmitOption :: AddressData ) => ( 0b1110 , true ) ,
387+ ( AccessType :: ReadOnly , EmitOption :: PCData ) => ( 0b1110 , false ) ,
388+
389+ ( AccessType :: WriteOnly , EmitOption :: Data ) => ( 0b1101 , false ) ,
390+ ( AccessType :: WriteOnly , EmitOption :: Address ) => ( 0b1101 , true ) ,
391+ ( AccessType :: WriteOnly , EmitOption :: AddressData ) => ( 0b1111 , true ) ,
392+ ( AccessType :: WriteOnly , EmitOption :: PCData ) => ( 0b1111 , false ) ,
393+
394+ ( AccessType :: ReadWrite , EmitOption :: Data ) => ( 0b0010 , false ) ,
395+ ( AccessType :: ReadWrite , EmitOption :: Address ) => ( 0b0001 , true ) ,
396+ ( AccessType :: ReadWrite , EmitOption :: AddressData ) => ( 0b0010 , true ) ,
397+ ( AccessType :: ReadWrite , EmitOption :: PCData ) => ( 0b0011 , false ) ,
398+
399+ ( AccessType :: ReadWrite , EmitOption :: PC ) => ( 0b0001 , false ) ,
400+ ( _, EmitOption :: PC ) => return Err ( DwtError :: InvalidFunction ) ,
401+ } ;
402+
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+ } ) ;
416+
417+ self . comp . write ( settings. address ) ;
418+ self . mask . write ( settings. mask ) ;
419+ } ,
420+ }
421+
422+ Ok ( ( ) )
423+ }
424+ }
0 commit comments