@@ -5,12 +5,13 @@ use volatile_register::WO;
5
5
use volatile_register:: { RO , RW } ;
6
6
7
7
use crate :: peripheral:: DWT ;
8
+ use bitfield:: bitfield;
8
9
9
10
/// Register block
10
11
#[ repr( C ) ]
11
12
pub struct RegisterBlock {
12
13
/// Control
13
- pub ctrl : RW < u32 > ,
14
+ pub ctrl : RW < Ctrl > ,
14
15
/// Cycle Count
15
16
#[ cfg( not( armv6m) ) ]
16
17
pub cyccnt : RW < u32 > ,
@@ -50,6 +51,21 @@ pub struct RegisterBlock {
50
51
pub lsr : RO < u32 > ,
51
52
}
52
53
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
+
53
69
/// Comparator
54
70
#[ repr( C ) ]
55
71
pub struct Comparator {
@@ -58,58 +74,57 @@ pub struct Comparator {
58
74
/// Comparator Mask
59
75
pub mask : RW < u32 > ,
60
76
/// Comparator Function
61
- pub function : RW < u32 > ,
77
+ pub function : RW < Function > ,
62
78
reserved : u32 ,
63
79
}
64
80
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
+ }
72
92
73
93
impl DWT {
74
94
/// Number of comparators implemented
75
95
///
76
96
/// A value of zero indicates no comparator support.
77
97
#[ 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 ( )
81
100
}
82
101
83
102
/// Returns `true` if the the implementation supports sampling and exception tracing
84
103
#[ cfg( not( armv6m) ) ]
85
104
#[ 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 ( )
89
107
}
90
108
91
109
/// Returns `true` if the implementation includes external match signals
92
110
#[ cfg( not( armv6m) ) ]
93
111
#[ 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 ( )
97
114
}
98
115
99
116
/// Returns `true` if the implementation supports a cycle counter
100
117
#[ cfg( not( armv6m) ) ]
101
118
#[ 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 ( )
105
121
}
106
122
107
123
/// Returns `true` if the implementation the profiling counters
108
124
#[ cfg( not( armv6m) ) ]
109
125
#[ 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 ( )
113
128
}
114
129
115
130
/// Enables the cycle counter
@@ -123,22 +138,55 @@ impl DWT {
123
138
#[ cfg( not( armv6m) ) ]
124
139
#[ inline]
125
140
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
+ }
127
147
}
128
148
129
- /// Disables the cycle counter
149
+ /// Returns `true` if the cycle counter is enabled
130
150
#[ cfg( not( armv6m) ) ]
131
151
#[ 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 ( )
134
154
}
135
155
136
- /// Returns `true` if the cycle counter is enabled
156
+ /// Enables exception tracing
137
157
#[ cfg( not( armv6m) ) ]
138
158
#[ 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
+ }
142
190
}
143
191
144
192
/// Returns the current clock cycle count
@@ -266,3 +314,111 @@ impl DWT {
266
314
unsafe { self . foldcnt . write ( count as u32 ) }
267
315
}
268
316
}
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