Skip to content

Commit e5ab476

Browse files
committed
mmaps: fields coverage
1 parent f30e86b commit e5ab476

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

CHANGELOG-rust.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This changelog tracks the Rust `svdtools` project. See
55

66
## [Unreleased]
77

8+
* Show number of covered fields in `mmaps`
89
* Sugar for simple `_split` and `_merge`
910

1011
## [v0.3.18] 2024-08-10

src/mmap/mmap_cli.rs

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ use anyhow::{Context, Result};
44
use std::{fs::File, io::Read, path::Path};
55
use svd::PeripheralInfo;
66
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+
}
714

815
/// Output sorted text of every peripheral, register, field, and interrupt
916
/// in the device, such that automated diffing is possible.
@@ -28,28 +35,46 @@ fn get_text<R: Read>(svd: &mut R) -> Result<String> {
2835

2936
fn to_text(peripherals: &[Peripheral]) -> String {
3037
let mut mmap: Vec<String> = vec![];
38+
let mut coverage = CoveredFields::default();
3139

3240
for p in peripherals {
3341
match p {
3442
Peripheral::Single(p) => {
3543
get_peripheral(p, &mut mmap);
3644
get_interrupts(p, &mut mmap);
3745
let registers = get_periph_registers(p, peripherals);
38-
get_registers(p.base_address, registers.as_ref(), "", &mut mmap);
46+
get_registers(
47+
p.base_address,
48+
registers.as_ref(),
49+
"",
50+
&mut mmap,
51+
&mut coverage,
52+
);
3953
}
4054
Peripheral::Array(p, d) => {
4155
for pi in svd::peripheral::expand(p, d) {
4256
get_peripheral(&pi, &mut mmap);
4357
get_interrupts(&pi, &mut mmap);
4458
let registers = get_periph_registers(&pi, peripherals);
45-
get_registers(pi.base_address, registers.as_ref(), "", &mut mmap);
59+
get_registers(
60+
pi.base_address,
61+
registers.as_ref(),
62+
"",
63+
&mut mmap,
64+
&mut coverage,
65+
);
4666
}
4767
}
4868
}
4969
}
5070

5171
mmap.sort();
52-
mmap.join("\n")
72+
let mut mmap = mmap.join("\n");
73+
mmap.push_str(&format!(
74+
"\nCovered {} from {} fields.",
75+
coverage.covered, coverage.all
76+
));
77+
mmap
5378
}
5479

5580
fn get_periph_registers<'a>(
@@ -104,6 +129,7 @@ fn get_registers(
104129
registers: Option<&Vec<RegisterCluster>>,
105130
suffix: &str,
106131
mmap: &mut Vec<String>,
132+
coverage: &mut CoveredFields,
107133
) {
108134
if let Some(registers) = registers {
109135
for r in registers {
@@ -121,7 +147,7 @@ fn get_registers(
121147
"{addr} B REGISTER {rname}{derived}{access}: {description}"
122148
);
123149
mmap.push(text);
124-
get_fields(r, &addr, mmap);
150+
get_fields(r, &addr, mmap, coverage);
125151
}
126152
Register::Array(r, d) => {
127153
for ri in svd::register::expand(r, d) {
@@ -134,7 +160,7 @@ fn get_registers(
134160
"{addr} B REGISTER {rname}{derived}{access}: {description}"
135161
);
136162
mmap.push(text);
137-
get_fields(&ri, &addr, mmap);
163+
get_fields(&ri, &addr, mmap, coverage);
138164
}
139165
}
140166
}
@@ -149,7 +175,7 @@ fn get_registers(
149175
let description = str_utils::get_description(&c.description);
150176
let text = format!("{addr} B CLUSTER {cname}{derived}: {description}");
151177
mmap.push(text);
152-
get_registers(caddr, Some(&c.children), "", mmap);
178+
get_registers(caddr, Some(&c.children), "", mmap, coverage);
153179
}
154180
Cluster::Array(c, d) => {
155181
for (ci, idx) in svd::cluster::expand(c, d).zip(d.indexes()) {
@@ -160,7 +186,7 @@ fn get_registers(
160186
let text =
161187
format!("{addr} B CLUSTER {cname}{derived}: {description}");
162188
mmap.push(text);
163-
get_registers(caddr, Some(&c.children), &idx, mmap);
189+
get_registers(caddr, Some(&c.children), &idx, mmap, coverage);
164190
}
165191
}
166192
}
@@ -170,7 +196,12 @@ fn get_registers(
170196
}
171197
}
172198

173-
fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
199+
fn get_fields(
200+
register: &RegisterInfo,
201+
addr: &str,
202+
mmap: &mut Vec<String>,
203+
coverage: &mut CoveredFields,
204+
) {
174205
if let Some(fields) = &register.fields {
175206
for f in fields {
176207
let derived = derived_str(&f.derived_from);
@@ -185,6 +216,12 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
185216
"{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
186217
);
187218
mmap.push(text);
219+
if f.derived_from.is_none() {
220+
coverage.all += 1;
221+
if is_covered(f) {
222+
coverage.covered += 1;
223+
}
224+
}
188225
}
189226
Field::Array(f, d) => {
190227
for fi in svd::field::expand(f, d) {
@@ -195,14 +232,24 @@ fn get_fields(register: &RegisterInfo, addr: &str, mmap: &mut Vec<String>) {
195232
let text = format!(
196233
"{addr} C FIELD {bit_offset:02}w{bit_width:02} {fname}{derived}{access}: {description}"
197234
);
198-
mmap.push(text);
235+
if fi.derived_from.is_none() {
236+
mmap.push(text);
237+
coverage.all += 1;
238+
if is_covered(&fi) {
239+
coverage.covered += 1;
240+
}
241+
}
199242
}
200243
}
201244
}
202245
}
203246
}
204247
}
205248

249+
fn is_covered(f: &FieldInfo) -> bool {
250+
!f.enumerated_values.is_empty() || f.write_constraint.is_some()
251+
}
252+
206253
#[cfg(test)]
207254
mod tests {
208255
use super::*;
@@ -231,6 +278,12 @@ mod tests {
231278
<description>Field 1</description>
232279
<bitOffset>5</bitOffset>
233280
<bitWidth>2</bitWidth>
281+
<writeConstraint>
282+
<range>
283+
<minimum>0</minimum>
284+
<maximum>0x3</maximum>
285+
</range>
286+
</writeConstraint>
234287
</field>
235288
<field>
236289
<name>F2</name>
@@ -261,6 +314,27 @@ mod tests {
261314
<name>REG1</name>
262315
<addressOffset>0x10</addressOffset>
263316
<description>Register B1</description>
317+
<fields>
318+
<field>
319+
<name>F3</name>
320+
<description>Field 3</description>
321+
<bitOffset>10</bitOffset>
322+
<bitWidth>1</bitWidth>
323+
<enumeratedValues>
324+
<name>EV_NAME</name>
325+
<enumeratedValue>
326+
<name>VAL1</name>
327+
<description>Value description 1</description>
328+
<value>0</value>
329+
</enumeratedValue>
330+
<enumeratedValue>
331+
<name>VAL2</name>
332+
<description>Value description 2</description>
333+
<value>1</value>
334+
</enumeratedValue>
335+
</enumeratedValues>
336+
</field>
337+
</fields>
264338
</register>
265339
</registers>
266340
</peripheral>
@@ -274,8 +348,10 @@ mod tests {
274348
0x10000014 B REGISTER REG2: Register A2
275349
0x10010000 A PERIPHERAL PeriphB
276350
0x10010010 B REGISTER REG1: Register B1
351+
0x10010010 C FIELD 10w01 F3: Field 3
277352
INTERRUPT 001: INT_A1 (PeriphA): Interrupt A1
278-
INTERRUPT 002: INT_B2 (PeriphB): Interrupt B2";
353+
INTERRUPT 002: INT_B2 (PeriphB): Interrupt B2
354+
Covered 2 from 3 fields.";
279355

280356
#[test]
281357
fn mmap() {

0 commit comments

Comments
 (0)