Skip to content

Commit c9aa6c6

Browse files
committed
ignore if not exists
1 parent 94de5e3 commit c9aa6c6

File tree

8 files changed

+114
-19
lines changed

8 files changed

+114
-19
lines changed

CHANGELOG-python.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This changelog tracks the Python `svdtools` project. See
88
* Support `_include` in peripherals in `device.yaml`
99
* `-1` for default enum value
1010
* Strip `alternateRegister` too
11+
* Ignore rule if starts with "?@" and no matched instances
1112

1213
## [v0.1.26] 2023-03-28
1314

CHANGELOG-rust.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This changelog tracks the Rust `svdtools` project. See
1717

1818
## [v0.3.5] 2023-11-30
1919

20+
* Ignore rule if starts with "?@" and no matched instances
2021
* Move field with derived enums before other
2122
* `-1` for default enum value
2223
* Update `displayName` during collect, improve searching common `description`

README.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,18 @@ _rebase:
351351
_strip_end:
352352
- "_POSTFIX_"
353353

354-
354+
# You can list glob-like rules separated by commas to cover more periperals or registers at time.
355+
# If rule is optional (peripheral may be missing in some devices) add `?@` in the header.
356+
# Don't abuse it. First test not optional rule.
357+
"?@TIM[18],TIM20":
358+
CR2:
359+
# Fields also support collecting in arrays
360+
_array:
361+
OIS?:
362+
description: Output Idle state %s (OC%s output)
363+
# Optional rules are supported here too
364+
"?@OIS?N":
365+
description: Output Idle state %s (OC%sN output)
355366
```
356367
357368
### Name Matching

src/patch/device.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{fs::File, io::Read, path::Path};
99
use super::iterators::{MatchIter, Matched};
1010
use super::peripheral::{PeripheralExt, RegisterBlockExt};
1111
use super::yaml_ext::{AsType, GetVal};
12-
use super::{abspath, matchname, Config, PatchResult, VAL_LVL};
12+
use super::{abspath, matchname, Config, PatchResult, Spec, VAL_LVL};
1313
use super::{make_address_block, make_address_blocks, make_cpu, make_interrupt, make_peripheral};
1414
use super::{make_dim_element, modify_dim_element, modify_register_properties};
1515

@@ -418,12 +418,13 @@ impl DeviceExt for Device {
418418
) -> PatchResult {
419419
// Find all peripherals that match the spec
420420
let mut pcount = 0;
421+
let (pspec, ignore) = pspec.spec();
421422
for ptag in self.iter_peripherals(pspec) {
422423
pcount += 1;
423424
ptag.process(peripheral, config)
424425
.with_context(|| format!("Processing peripheral `{}`", ptag.name))?;
425426
}
426-
if pcount == 0 {
427+
if !ignore && pcount == 0 {
427428
Err(anyhow!(
428429
"Could not find `{pspec}. Present peripherals: {}.`",
429430
self.peripherals.iter().map(|p| p.name.as_str()).join(", ")

src/patch/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -726,3 +726,18 @@ fn common_description(descs: &[Option<&str>], dim_index: &[String]) -> Option<Op
726726
}
727727
same.then(|| desc0.map(Into::into))
728728
}
729+
730+
pub trait Spec {
731+
/// Return specification and `ignore_if_not_exists` flag
732+
fn spec(&self) -> (&str, bool);
733+
}
734+
735+
impl Spec for str {
736+
fn spec(&self) -> (&str, bool) {
737+
if let Some(s) = self.strip_prefix("?@") {
738+
(s, true)
739+
} else {
740+
(self, false)
741+
}
742+
}
743+
}

src/patch/peripheral.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::register::{RegisterExt, RegisterInfoExt};
1111
use super::yaml_ext::{AsType, GetVal, ToYaml};
1212
use super::{
1313
check_offsets, common_description, make_dim_element, matchname, matchsubspec,
14-
modify_dim_element, spec_ind, Config, PatchResult, VAL_LVL,
14+
modify_dim_element, spec_ind, Config, PatchResult, Spec, VAL_LVL,
1515
};
1616
use super::{make_cluster, make_interrupt, make_register};
1717

@@ -407,6 +407,7 @@ impl RegisterBlockExt for Peripheral {
407407
}
408408

409409
fn modify_register(&mut self, rspec: &str, rmod: &Hash) -> PatchResult {
410+
// TODO: empty error
410411
let rtags = self.iter_registers(rspec).collect::<Vec<_>>();
411412
if !rtags.is_empty() {
412413
let register_builder = make_register(rmod)?;
@@ -557,6 +558,7 @@ impl RegisterBlockExt for Peripheral {
557558
}
558559

559560
fn modify_cluster(&mut self, cspec: &str, cmod: &Hash) -> PatchResult {
561+
// TODO: empty error
560562
let ctags = self.iter_clusters(cspec).collect::<Vec<_>>();
561563
if !ctags.is_empty() {
562564
let cluster_builder = make_cluster(cmod)?;
@@ -646,12 +648,13 @@ impl RegisterBlockExt for Peripheral {
646648
// Find all registers that match the spec
647649
let mut rcount = 0;
648650
let pname = self.name.clone();
651+
let (rspec, ignore) = rspec.spec();
649652
for rtag in self.iter_registers(rspec) {
650653
rcount += 1;
651654
rtag.process(rmod, &pname, config)
652655
.with_context(|| format!("Processing register `{}`", rtag.name))?;
653656
}
654-
if rcount == 0 {
657+
if !ignore && rcount == 0 {
655658
Err(anyhow!(
656659
"Could not find `{pname}:{rspec}. Present registers: {}.`",
657660
self.registers().map(|r| r.name.as_str()).join(", ")
@@ -665,12 +668,13 @@ impl RegisterBlockExt for Peripheral {
665668
// Find all clusters that match the spec
666669
let mut ccount = 0;
667670
let pname = self.name.clone();
671+
let (cspec, ignore) = cspec.spec();
668672
for ctag in self.iter_clusters(cspec) {
669673
ccount += 1;
670674
ctag.process(cmod, &pname, config)
671675
.with_context(|| format!("Processing cluster `{}`", ctag.name))?;
672676
}
673-
if ccount == 0 {
677+
if !ignore && ccount == 0 {
674678
Err(anyhow!(
675679
"Could not find `{pname}:{cspec}. Present clusters: {}.`",
676680
self.clusters().map(|c| c.name.as_str()).join(", ")
@@ -1112,12 +1116,13 @@ impl RegisterBlockExt for Cluster {
11121116
// Find all registers that match the spec
11131117
let mut rcount = 0;
11141118
let pname = self.name.clone();
1119+
let (rspec, ignore) = rspec.spec();
11151120
for rtag in self.iter_registers(rspec) {
11161121
rcount += 1;
11171122
rtag.process(rmod, &pname, config)
11181123
.with_context(|| format!("Processing register `{}`", rtag.name))?;
11191124
}
1120-
if rcount == 0 {
1125+
if !ignore && rcount == 0 {
11211126
Err(anyhow!(
11221127
"Could not find `{pname}:{}:{rspec}. Present registers: {}.`",
11231128
self.name,
@@ -1132,12 +1137,13 @@ impl RegisterBlockExt for Cluster {
11321137
// Find all clusters that match the spec
11331138
let mut ccount = 0;
11341139
let pname = self.name.clone();
1140+
let (cspec, ignore) = cspec.spec();
11351141
for ctag in self.iter_clusters(cspec) {
11361142
ccount += 1;
11371143
ctag.process(cmod, &pname, config)
11381144
.with_context(|| format!("Processing cluster `{}`", ctag.name))?;
11391145
}
1140-
if ccount == 0 {
1146+
if !ignore && ccount == 0 {
11411147
Err(anyhow!(
11421148
"Could not find `{pname}:{}:{cspec}. Present clusters: {}.`",
11431149
self.name,
@@ -1159,6 +1165,7 @@ fn collect_in_array(
11591165
let mut registers = Vec::new();
11601166
let mut place = usize::MAX;
11611167
let mut i = 0;
1168+
let (rspec, ignore) = rspec.spec();
11621169
while i < regs.len() {
11631170
match &regs[i] {
11641171
RegisterCluster::Register(Register::Single(r)) if matchname(&r.name, rspec) => {
@@ -1171,6 +1178,9 @@ fn collect_in_array(
11711178
}
11721179
}
11731180
if registers.is_empty() {
1181+
if ignore {
1182+
return Ok(());
1183+
}
11741184
return Err(anyhow!(
11751185
"{path}: registers {rspec} not found. Present registers: {}.`",
11761186
regs.iter()
@@ -1299,9 +1309,9 @@ fn collect_in_cluster(
12991309
if rspec == "description" {
13001310
continue;
13011311
}
1302-
rspecs.push(rspec.to_string());
13031312
let mut registers = Vec::new();
13041313
let mut i = 0;
1314+
let (rspec, ignore) = rspec.spec();
13051315
while i < regs.len() {
13061316
match &regs[i] {
13071317
RegisterCluster::Register(Register::Single(r)) if matchname(&r.name, rspec) => {
@@ -1314,6 +1324,9 @@ fn collect_in_cluster(
13141324
}
13151325
}
13161326
if registers.is_empty() {
1327+
if ignore {
1328+
continue;
1329+
}
13171330
return Err(anyhow!(
13181331
"{path}: registers {rspec} not found. Present registers: {}.`",
13191332
regs.iter()
@@ -1324,6 +1337,7 @@ fn collect_in_cluster(
13241337
.join(", ")
13251338
));
13261339
}
1340+
rspecs.push(rspec.to_string());
13271341
if single {
13281342
if registers.len() > 1 {
13291343
return Err(anyhow!("{path}: more than one registers {rspec} found"));
@@ -1384,6 +1398,11 @@ fn collect_in_cluster(
13841398
}
13851399
rdict.insert(rspec.to_string(), registers);
13861400
}
1401+
if rdict.is_empty() {
1402+
return Err(anyhow!(
1403+
"{path}: registers cannot be collected into {cname} cluster. No matches found"
1404+
));
1405+
}
13871406
let address_offset = rdict
13881407
.values()
13891408
.min_by_key(|rs| rs[0].address_offset)

src/patch/register.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::iterators::{MatchIter, Matched};
1212
use super::yaml_ext::{AsType, GetVal, ToYaml};
1313
use super::{
1414
check_offsets, common_description, make_dim_element, matchname, modify_dim_element, spec_ind,
15-
Config, PatchResult, VAL_LVL,
15+
Config, PatchResult, Spec, VAL_LVL,
1616
};
1717
use super::{make_derived_enumerated_values, make_ev_array, make_ev_name, make_field};
1818

@@ -370,6 +370,7 @@ impl RegisterExt for Register {
370370
let mut fields = Vec::new();
371371
let mut place = usize::MAX;
372372
let mut i = 0;
373+
let (fspec, ignore) = fspec.spec();
373374
while i < fs.len() {
374375
match &fs[i] {
375376
Field::Single(f) if matchname(&f.name, fspec) => {
@@ -382,6 +383,9 @@ impl RegisterExt for Register {
382383
}
383384
}
384385
if fields.is_empty() {
386+
if ignore {
387+
return Ok(());
388+
}
385389
return Err(anyhow!(
386390
"{}: fields {fspec} not found. Present fields: {}.`",
387391
self.name,
@@ -448,9 +452,13 @@ impl RegisterExt for Register {
448452
Ok(())
449453
}
450454
fn split_fields(&mut self, fspec: &str, fsplit: &Hash) -> PatchResult {
455+
let (fspec, ignore) = fspec.spec();
451456
let mut it = self.iter_fields(fspec);
452457
let (new_fields, name) = match (it.next(), it.next()) {
453458
(None, _) => {
459+
if ignore {
460+
return Ok(());
461+
}
454462
return Err(anyhow!(
455463
"Could not find any fields to split {}:{fspec}. Present fields: {}.`",
456464
self.name,
@@ -721,13 +729,17 @@ impl RegisterExt for Register {
721729
set_enum(ftag, evs.clone(), orig_usage, true, access)?;
722730
}
723731
} else {
732+
let (fspec, ignore) = fspec.spec();
724733
let mut offsets: Vec<_> = Vec::new();
725734
for (i, f) in self.fields().enumerate() {
726735
if matchname(&f.name, fspec) {
727736
offsets.push((f.bit_range.offset, f.name.to_string(), i));
728737
}
729738
}
730739
if offsets.is_empty() {
740+
if ignore {
741+
return Ok(());
742+
}
731743
return Err(anyhow!(
732744
"Could not find field {pname}:{}:{fspec}. Present fields: {}.`",
733745
self.name,
@@ -779,14 +791,15 @@ impl RegisterExt for Register {
779791

780792
fn process_field_range(&mut self, pname: &str, fspec: &str, fmod: &[Yaml]) -> PatchResult {
781793
let mut set_any = false;
794+
let (fspec, ignore) = fspec.spec();
782795
for ftag in self.iter_fields(fspec) {
783796
ftag.write_constraint = Some(WriteConstraint::Range(WriteConstraintRange {
784797
min: fmod[0].i64()? as u64,
785798
max: fmod[1].i64()? as u64,
786799
}));
787800
set_any = true;
788801
}
789-
if !set_any {
802+
if !ignore && !set_any {
790803
return Err(anyhow!(
791804
"Could not find field {pname}:{}:{fspec}. Present fields: {}.`",
792805
self.name,

0 commit comments

Comments
 (0)