@@ -4,6 +4,29 @@ use anyhow::{Context, Result};
4
4
use std:: { fs:: File , io:: Read , path:: Path } ;
5
5
use svd:: PeripheralInfo ;
6
6
use svd_parser:: svd:: { self , Cluster , Field , Peripheral , Register , RegisterCluster , RegisterInfo } ;
7
+ use svd_rs:: FieldInfo ;
8
+
9
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Default ) ]
10
+ struct CoveredFields {
11
+ all : u32 ,
12
+ covered : u32 ,
13
+ }
14
+
15
+ impl core:: ops:: Add for CoveredFields {
16
+ type Output = Self ;
17
+ fn add ( self , rhs : Self ) -> Self :: Output {
18
+ Self {
19
+ all : self . all + rhs. all ,
20
+ covered : self . covered + rhs. covered ,
21
+ }
22
+ }
23
+ }
24
+
25
+ impl core:: ops:: AddAssign for CoveredFields {
26
+ fn add_assign ( & mut self , rhs : Self ) {
27
+ * self = * self + rhs
28
+ }
29
+ }
7
30
8
31
/// Output sorted text of every peripheral, register, field, and interrupt
9
32
/// in the device, such that automated diffing is possible.
@@ -27,22 +50,59 @@ fn get_text<R: Read>(svd: &mut R) -> Result<String> {
27
50
}
28
51
29
52
fn to_text ( peripherals : & [ Peripheral ] ) -> String {
30
- let mut mmap: Vec < String > = vec ! [ ] ;
53
+ let mut mmap = Vec :: new ( ) ;
54
+ let mut coverage = CoveredFields :: default ( ) ;
31
55
32
56
for p in peripherals {
33
57
match p {
34
58
Peripheral :: Single ( p) => {
35
- get_peripheral ( p, & mut mmap) ;
36
- get_interrupts ( p, & mut mmap) ;
59
+ let mut pcov = CoveredFields :: default ( ) ;
37
60
let registers = get_periph_registers ( p, peripherals) ;
38
- get_registers ( p. base_address , registers. as_ref ( ) , "" , & mut mmap) ;
61
+ let mut rmmap = Vec :: new ( ) ;
62
+ get_registers (
63
+ p. base_address ,
64
+ registers. as_ref ( ) ,
65
+ "" ,
66
+ & mut rmmap,
67
+ & mut pcov,
68
+ ) ;
69
+ get_peripheral (
70
+ p,
71
+ & mut mmap,
72
+ if p. derived_from . is_some ( ) {
73
+ CoveredFields :: default ( )
74
+ } else {
75
+ pcov
76
+ } ,
77
+ ) ;
78
+ get_interrupts ( p, & mut mmap) ;
79
+ mmap. extend ( rmmap) ;
80
+ coverage += pcov;
39
81
}
40
82
Peripheral :: Array ( p, d) => {
83
+ let mut pcov = CoveredFields :: default ( ) ;
41
84
for pi in svd:: peripheral:: expand ( p, d) {
42
- get_peripheral ( & pi, & mut mmap) ;
43
- get_interrupts ( & pi, & mut mmap) ;
44
85
let registers = get_periph_registers ( & pi, peripherals) ;
45
- get_registers ( pi. base_address , registers. as_ref ( ) , "" , & mut mmap) ;
86
+ let mut rmmap = Vec :: new ( ) ;
87
+ get_registers (
88
+ pi. base_address ,
89
+ registers. as_ref ( ) ,
90
+ "" ,
91
+ & mut rmmap,
92
+ & mut pcov,
93
+ ) ;
94
+ get_peripheral (
95
+ & pi,
96
+ & mut mmap,
97
+ if pi. derived_from . is_some ( ) {
98
+ CoveredFields :: default ( )
99
+ } else {
100
+ pcov
101
+ } ,
102
+ ) ;
103
+ get_interrupts ( & pi, & mut mmap) ;
104
+ mmap. extend ( rmmap) ;
105
+ coverage += pcov;
46
106
}
47
107
}
48
108
}
@@ -71,12 +131,22 @@ fn get_periph_registers<'a>(
71
131
}
72
132
}
73
133
74
- fn get_peripheral ( peripheral : & PeripheralInfo , mmap : & mut Vec < String > ) {
75
- let text = format ! (
76
- "{} A PERIPHERAL {}" ,
77
- str_utils:: format_address( peripheral. base_address) ,
78
- peripheral. name
79
- ) ;
134
+ fn get_peripheral ( peripheral : & PeripheralInfo , mmap : & mut Vec < String > , coverage : CoveredFields ) {
135
+ let text = if coverage. all > 0 {
136
+ format ! (
137
+ "{} A PERIPHERAL {} ({}/{} fields covered)" ,
138
+ str_utils:: format_address( peripheral. base_address) ,
139
+ peripheral. name,
140
+ coverage. covered,
141
+ coverage. all,
142
+ )
143
+ } else {
144
+ format ! (
145
+ "{} A PERIPHERAL {}" ,
146
+ str_utils:: format_address( peripheral. base_address) ,
147
+ peripheral. name,
148
+ )
149
+ } ;
80
150
mmap. push ( text) ;
81
151
}
82
152
@@ -104,11 +174,13 @@ fn get_registers(
104
174
registers : Option < & Vec < RegisterCluster > > ,
105
175
suffix : & str ,
106
176
mmap : & mut Vec < String > ,
177
+ coverage : & mut CoveredFields ,
107
178
) {
108
179
if let Some ( registers) = registers {
109
180
for r in registers {
110
181
match & r {
111
182
RegisterCluster :: Register ( r) => {
183
+ let mut rcov = CoveredFields :: default ( ) ;
112
184
let access = svd_utils:: access_with_brace ( r. properties . access ) ;
113
185
let derived = derived_str ( & r. derived_from ) ;
114
186
match r {
@@ -121,7 +193,7 @@ fn get_registers(
121
193
"{addr} B REGISTER {rname}{derived}{access}: {description}"
122
194
) ;
123
195
mmap. push ( text) ;
124
- get_fields ( r, & addr, mmap) ;
196
+ get_fields ( r, & addr, mmap, & mut rcov ) ;
125
197
}
126
198
Register :: Array ( r, d) => {
127
199
for ri in svd:: register:: expand ( r, d) {
@@ -134,10 +206,11 @@ fn get_registers(
134
206
"{addr} B REGISTER {rname}{derived}{access}: {description}"
135
207
) ;
136
208
mmap. push ( text) ;
137
- get_fields ( & ri, & addr, mmap) ;
209
+ get_fields ( & ri, & addr, mmap, & mut rcov ) ;
138
210
}
139
211
}
140
212
}
213
+ * coverage += rcov;
141
214
}
142
215
RegisterCluster :: Cluster ( c) => {
143
216
let derived = derived_str ( & c. derived_from ) ;
@@ -149,7 +222,7 @@ fn get_registers(
149
222
let description = str_utils:: get_description ( & c. description ) ;
150
223
let text = format ! ( "{addr} B CLUSTER {cname}{derived}: {description}" ) ;
151
224
mmap. push ( text) ;
152
- get_registers ( caddr, Some ( & c. children ) , "" , mmap) ;
225
+ get_registers ( caddr, Some ( & c. children ) , "" , mmap, coverage ) ;
153
226
}
154
227
Cluster :: Array ( c, d) => {
155
228
for ( ci, idx) in svd:: cluster:: expand ( c, d) . zip ( d. indexes ( ) ) {
@@ -160,7 +233,7 @@ fn get_registers(
160
233
let text =
161
234
format ! ( "{addr} B CLUSTER {cname}{derived}: {description}" ) ;
162
235
mmap. push ( text) ;
163
- get_registers ( caddr, Some ( & c. children ) , & idx, mmap) ;
236
+ get_registers ( caddr, Some ( & c. children ) , & idx, mmap, coverage ) ;
164
237
}
165
238
}
166
239
}
@@ -170,7 +243,12 @@ fn get_registers(
170
243
}
171
244
}
172
245
173
- fn get_fields ( register : & RegisterInfo , addr : & str , mmap : & mut Vec < String > ) {
246
+ fn get_fields (
247
+ register : & RegisterInfo ,
248
+ addr : & str ,
249
+ mmap : & mut Vec < String > ,
250
+ coverage : & mut CoveredFields ,
251
+ ) {
174
252
if let Some ( fields) = & register. fields {
175
253
for f in fields {
176
254
let derived = derived_str ( & f. derived_from ) ;
@@ -185,6 +263,12 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
185
263
"{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
186
264
) ;
187
265
mmap. push ( text) ;
266
+ if f. derived_from . is_none ( ) {
267
+ coverage. all += 1 ;
268
+ if is_covered ( f) {
269
+ coverage. covered += 1 ;
270
+ }
271
+ }
188
272
}
189
273
Field :: Array ( f, d) => {
190
274
for fi in svd:: field:: expand ( f, d) {
@@ -195,19 +279,29 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
195
279
let text = format ! (
196
280
"{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
197
281
) ;
198
- mmap. push ( text) ;
282
+ if fi. derived_from . is_none ( ) {
283
+ mmap. push ( text) ;
284
+ coverage. all += 1 ;
285
+ if is_covered ( & fi) {
286
+ coverage. covered += 1 ;
287
+ }
288
+ }
199
289
}
200
290
}
201
291
}
202
292
}
203
293
}
204
294
}
205
295
296
+ fn is_covered ( f : & FieldInfo ) -> bool {
297
+ !f. enumerated_values . is_empty ( ) || f. write_constraint . is_some ( )
298
+ }
299
+
206
300
#[ cfg( test) ]
207
301
mod tests {
208
302
use super :: * ;
209
303
210
- static SVD : & str = r"
304
+ static SVD : & str = r## "
211
305
<device>
212
306
<name>dev</name>
213
307
<peripherals>
@@ -231,6 +325,12 @@ mod tests {
231
325
<description>Field 1</description>
232
326
<bitOffset>5</bitOffset>
233
327
<bitWidth>2</bitWidth>
328
+ <writeConstraint>
329
+ <range>
330
+ <minimum>0</minimum>
331
+ <maximum>0x3</maximum>
332
+ </range>
333
+ </writeConstraint>
234
334
</field>
235
335
<field>
236
336
<name>F2</name>
@@ -261,19 +361,49 @@ mod tests {
261
361
<name>REG1</name>
262
362
<addressOffset>0x10</addressOffset>
263
363
<description>Register B1</description>
364
+ <fields>
365
+ <field>
366
+ <name>F3</name>
367
+ <description>Field 3</description>
368
+ <bitOffset>10</bitOffset>
369
+ <bitWidth>1</bitWidth>
370
+ <enumeratedValues>
371
+ <name>EV_NAME</name>
372
+ <enumeratedValue>
373
+ <name>VAL1</name>
374
+ <description>Value description 1</description>
375
+ <value>0</value>
376
+ </enumeratedValue>
377
+ <enumeratedValue>
378
+ <name>VAL2</name>
379
+ <description>Value description 2</description>
380
+ <value>1</value>
381
+ </enumeratedValue>
382
+ </enumeratedValues>
383
+ </field>
384
+ </fields>
264
385
</register>
265
386
</registers>
266
387
</peripheral>
388
+ <peripheral derivedFrom="PeriphB">
389
+ <name>PeriphC</name>
390
+ <description>Peripheral C</description>
391
+ <baseAddress>0x10020000</baseAddress>
392
+ </peripheral>
267
393
</peripherals>
268
- </device>" ;
394
+ </device>"## ;
269
395
270
- static EXPECTED_MMAP : & str = r"0x10000000 A PERIPHERAL PeriphA
396
+ static EXPECTED_MMAP : & str = r"0x10000000 A PERIPHERAL PeriphA (1/2 fields covered)
271
397
0x10000010 B REGISTER REG1: Register A1
272
398
0x10000010 C FIELD 05w02 F1: Field 1
273
399
0x10000010 C FIELD 10w01 F2: Field 2
274
400
0x10000014 B REGISTER REG2: Register A2
275
- 0x10010000 A PERIPHERAL PeriphB
401
+ 0x10010000 A PERIPHERAL PeriphB (1/1 fields covered)
276
402
0x10010010 B REGISTER REG1: Register B1
403
+ 0x10010010 C FIELD 10w01 F3: Field 3
404
+ 0x10020000 A PERIPHERAL PeriphC
405
+ 0x10020010 B REGISTER REG1: Register B1
406
+ 0x10020010 C FIELD 10w01 F3: Field 3
277
407
INTERRUPT 001: INT_A1 (PeriphA): Interrupt A1
278
408
INTERRUPT 002: INT_B2 (PeriphB): Interrupt B2" ;
279
409
0 commit comments