@@ -4,6 +4,29 @@ use anyhow::{Context, Result};
44use std:: { fs:: File , io:: Read , path:: Path } ;
55use svd:: PeripheralInfo ;
66use 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+ }
730
831/// Output sorted text of every peripheral, register, field, and interrupt
932/// in the device, such that automated diffing is possible.
@@ -27,22 +50,59 @@ fn get_text<R: Read>(svd: &mut R) -> Result<String> {
2750}
2851
2952fn to_text ( peripherals : & [ Peripheral ] ) -> String {
30- let mut mmap: Vec < String > = vec ! [ ] ;
53+ let mut mmap = Vec :: new ( ) ;
54+ let mut coverage = CoveredFields :: default ( ) ;
3155
3256 for p in peripherals {
3357 match p {
3458 Peripheral :: Single ( p) => {
35- get_peripheral ( p, & mut mmap) ;
36- get_interrupts ( p, & mut mmap) ;
59+ let mut pcov = CoveredFields :: default ( ) ;
3760 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;
3981 }
4082 Peripheral :: Array ( p, d) => {
83+ let mut pcov = CoveredFields :: default ( ) ;
4184 for pi in svd:: peripheral:: expand ( p, d) {
42- get_peripheral ( & pi, & mut mmap) ;
43- get_interrupts ( & pi, & mut mmap) ;
4485 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;
46106 }
47107 }
48108 }
@@ -71,12 +131,22 @@ fn get_periph_registers<'a>(
71131 }
72132}
73133
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+ } ;
80150 mmap. push ( text) ;
81151}
82152
@@ -104,11 +174,13 @@ fn get_registers(
104174 registers : Option < & Vec < RegisterCluster > > ,
105175 suffix : & str ,
106176 mmap : & mut Vec < String > ,
177+ coverage : & mut CoveredFields ,
107178) {
108179 if let Some ( registers) = registers {
109180 for r in registers {
110181 match & r {
111182 RegisterCluster :: Register ( r) => {
183+ let mut rcov = CoveredFields :: default ( ) ;
112184 let access = svd_utils:: access_with_brace ( r. properties . access ) ;
113185 let derived = derived_str ( & r. derived_from ) ;
114186 match r {
@@ -121,7 +193,7 @@ fn get_registers(
121193 "{addr} B REGISTER {rname}{derived}{access}: {description}"
122194 ) ;
123195 mmap. push ( text) ;
124- get_fields ( r, & addr, mmap) ;
196+ get_fields ( r, & addr, mmap, & mut rcov ) ;
125197 }
126198 Register :: Array ( r, d) => {
127199 for ri in svd:: register:: expand ( r, d) {
@@ -134,10 +206,11 @@ fn get_registers(
134206 "{addr} B REGISTER {rname}{derived}{access}: {description}"
135207 ) ;
136208 mmap. push ( text) ;
137- get_fields ( & ri, & addr, mmap) ;
209+ get_fields ( & ri, & addr, mmap, & mut rcov ) ;
138210 }
139211 }
140212 }
213+ * coverage += rcov;
141214 }
142215 RegisterCluster :: Cluster ( c) => {
143216 let derived = derived_str ( & c. derived_from ) ;
@@ -149,7 +222,7 @@ fn get_registers(
149222 let description = str_utils:: get_description ( & c. description ) ;
150223 let text = format ! ( "{addr} B CLUSTER {cname}{derived}: {description}" ) ;
151224 mmap. push ( text) ;
152- get_registers ( caddr, Some ( & c. children ) , "" , mmap) ;
225+ get_registers ( caddr, Some ( & c. children ) , "" , mmap, coverage ) ;
153226 }
154227 Cluster :: Array ( c, d) => {
155228 for ( ci, idx) in svd:: cluster:: expand ( c, d) . zip ( d. indexes ( ) ) {
@@ -160,7 +233,7 @@ fn get_registers(
160233 let text =
161234 format ! ( "{addr} B CLUSTER {cname}{derived}: {description}" ) ;
162235 mmap. push ( text) ;
163- get_registers ( caddr, Some ( & c. children ) , & idx, mmap) ;
236+ get_registers ( caddr, Some ( & c. children ) , & idx, mmap, coverage ) ;
164237 }
165238 }
166239 }
@@ -170,7 +243,12 @@ fn get_registers(
170243 }
171244}
172245
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+ ) {
174252 if let Some ( fields) = & register. fields {
175253 for f in fields {
176254 let derived = derived_str ( & f. derived_from ) ;
@@ -185,6 +263,12 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
185263 "{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
186264 ) ;
187265 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+ }
188272 }
189273 Field :: Array ( f, d) => {
190274 for fi in svd:: field:: expand ( f, d) {
@@ -195,19 +279,29 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
195279 let text = format ! (
196280 "{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
197281 ) ;
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+ }
199289 }
200290 }
201291 }
202292 }
203293 }
204294}
205295
296+ fn is_covered ( f : & FieldInfo ) -> bool {
297+ !f. enumerated_values . is_empty ( ) || f. write_constraint . is_some ( )
298+ }
299+
206300#[ cfg( test) ]
207301mod tests {
208302 use super :: * ;
209303
210- static SVD : & str = r"
304+ static SVD : & str = r## "
211305<device>
212306 <name>dev</name>
213307 <peripherals>
@@ -231,6 +325,12 @@ mod tests {
231325 <description>Field 1</description>
232326 <bitOffset>5</bitOffset>
233327 <bitWidth>2</bitWidth>
328+ <writeConstraint>
329+ <range>
330+ <minimum>0</minimum>
331+ <maximum>0x3</maximum>
332+ </range>
333+ </writeConstraint>
234334 </field>
235335 <field>
236336 <name>F2</name>
@@ -261,19 +361,49 @@ mod tests {
261361 <name>REG1</name>
262362 <addressOffset>0x10</addressOffset>
263363 <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>
264385 </register>
265386 </registers>
266387 </peripheral>
388+ <peripheral derivedFrom="PeriphB">
389+ <name>PeriphC</name>
390+ <description>Peripheral C</description>
391+ <baseAddress>0x10020000</baseAddress>
392+ </peripheral>
267393 </peripherals>
268- </device>" ;
394+ </device>"## ;
269395
270- static EXPECTED_MMAP : & str = r"0x10000000 A PERIPHERAL PeriphA
396+ static EXPECTED_MMAP : & str = r"0x10000000 A PERIPHERAL PeriphA (1/2 fields covered)
2713970x10000010 B REGISTER REG1: Register A1
2723980x10000010 C FIELD 05w02 F1: Field 1
2733990x10000010 C FIELD 10w01 F2: Field 2
2744000x10000014 B REGISTER REG2: Register A2
275- 0x10010000 A PERIPHERAL PeriphB
401+ 0x10010000 A PERIPHERAL PeriphB (1/1 fields covered)
2764020x10010010 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
277407INTERRUPT 001: INT_A1 (PeriphA): Interrupt A1
278408INTERRUPT 002: INT_B2 (PeriphB): Interrupt B2" ;
279409
0 commit comments