Skip to content

Commit 09f63af

Browse files
committed
ignore if not exists
1 parent 4286af9 commit 09f63af

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
@@ -6,6 +6,7 @@ This changelog tracks the Python `svdtools` project. See
66
## [Unreleased]
77

88
* `-1` for default enum value
9+
* Ignore rule if starts with "?@" and no matched instances
910

1011
## [v0.1.26] 2023-03-28
1112

CHANGELOG-rust.md

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

1414
## [v0.3.5] 2023-11-30
1515

16+
* Ignore rule if starts with "?@" and no matched instances
1617
* Move field with derived enums before other
1718
* `-1` for default enum value
1819
* 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
@@ -717,3 +717,18 @@ fn common_description(descs: &[Option<&str>], dim_index: &[String]) -> Option<Op
717717
}
718718
same.then(|| desc0.map(Into::into))
719719
}
720+
721+
pub trait Spec {
722+
/// Return specification and `ignore_if_not_exists` flag
723+
fn spec(&self) -> (&str, bool);
724+
}
725+
726+
impl Spec for str {
727+
fn spec(&self) -> (&str, bool) {
728+
if let Some(s) = self.strip_prefix("?@") {
729+
(s, true)
730+
} else {
731+
(self, false)
732+
}
733+
}
734+
}

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)?;
@@ -635,12 +637,13 @@ impl RegisterBlockExt for Peripheral {
635637
// Find all registers that match the spec
636638
let mut rcount = 0;
637639
let pname = self.name.clone();
640+
let (rspec, ignore) = rspec.spec();
638641
for rtag in self.iter_registers(rspec) {
639642
rcount += 1;
640643
rtag.process(rmod, &pname, config)
641644
.with_context(|| format!("Processing register `{}`", rtag.name))?;
642645
}
643-
if rcount == 0 {
646+
if !ignore && rcount == 0 {
644647
Err(anyhow!(
645648
"Could not find `{pname}:{rspec}. Present registers: {}.`",
646649
self.registers().map(|r| r.name.as_str()).join(", ")
@@ -654,12 +657,13 @@ impl RegisterBlockExt for Peripheral {
654657
// Find all clusters that match the spec
655658
let mut ccount = 0;
656659
let pname = self.name.clone();
660+
let (cspec, ignore) = cspec.spec();
657661
for ctag in self.iter_clusters(cspec) {
658662
ccount += 1;
659663
ctag.process(cmod, &pname, config)
660664
.with_context(|| format!("Processing cluster `{}`", ctag.name))?;
661665
}
662-
if ccount == 0 {
666+
if !ignore && ccount == 0 {
663667
Err(anyhow!(
664668
"Could not find `{pname}:{cspec}. Present clusters: {}.`",
665669
self.clusters().map(|c| c.name.as_str()).join(", ")
@@ -1090,12 +1094,13 @@ impl RegisterBlockExt for Cluster {
10901094
// Find all registers that match the spec
10911095
let mut rcount = 0;
10921096
let pname = self.name.clone();
1097+
let (rspec, ignore) = rspec.spec();
10931098
for rtag in self.iter_registers(rspec) {
10941099
rcount += 1;
10951100
rtag.process(rmod, &pname, config)
10961101
.with_context(|| format!("Processing register `{}`", rtag.name))?;
10971102
}
1098-
if rcount == 0 {
1103+
if !ignore && rcount == 0 {
10991104
Err(anyhow!(
11001105
"Could not find `{pname}:{}:{rspec}. Present registers: {}.`",
11011106
self.name,
@@ -1110,12 +1115,13 @@ impl RegisterBlockExt for Cluster {
11101115
// Find all clusters that match the spec
11111116
let mut ccount = 0;
11121117
let pname = self.name.clone();
1118+
let (cspec, ignore) = cspec.spec();
11131119
for ctag in self.iter_clusters(cspec) {
11141120
ccount += 1;
11151121
ctag.process(cmod, &pname, config)
11161122
.with_context(|| format!("Processing cluster `{}`", ctag.name))?;
11171123
}
1118-
if ccount == 0 {
1124+
if !ignore && ccount == 0 {
11191125
Err(anyhow!(
11201126
"Could not find `{pname}:{}:{cspec}. Present clusters: {}.`",
11211127
self.name,
@@ -1137,6 +1143,7 @@ fn collect_in_array(
11371143
let mut registers = Vec::new();
11381144
let mut place = usize::MAX;
11391145
let mut i = 0;
1146+
let (rspec, ignore) = rspec.spec();
11401147
while i < regs.len() {
11411148
match &regs[i] {
11421149
RegisterCluster::Register(Register::Single(r)) if matchname(&r.name, rspec) => {
@@ -1149,6 +1156,9 @@ fn collect_in_array(
11491156
}
11501157
}
11511158
if registers.is_empty() {
1159+
if ignore {
1160+
return Ok(());
1161+
}
11521162
return Err(anyhow!(
11531163
"{path}: registers {rspec} not found. Present registers: {}.`",
11541164
regs.iter()
@@ -1277,9 +1287,9 @@ fn collect_in_cluster(
12771287
if rspec == "description" {
12781288
continue;
12791289
}
1280-
rspecs.push(rspec.to_string());
12811290
let mut registers = Vec::new();
12821291
let mut i = 0;
1292+
let (rspec, ignore) = rspec.spec();
12831293
while i < regs.len() {
12841294
match &regs[i] {
12851295
RegisterCluster::Register(Register::Single(r)) if matchname(&r.name, rspec) => {
@@ -1292,6 +1302,9 @@ fn collect_in_cluster(
12921302
}
12931303
}
12941304
if registers.is_empty() {
1305+
if ignore {
1306+
continue;
1307+
}
12951308
return Err(anyhow!(
12961309
"{path}: registers {rspec} not found. Present registers: {}.`",
12971310
regs.iter()
@@ -1302,6 +1315,7 @@ fn collect_in_cluster(
13021315
.join(", ")
13031316
));
13041317
}
1318+
rspecs.push(rspec.to_string());
13051319
if single {
13061320
if registers.len() > 1 {
13071321
return Err(anyhow!("{path}: more than one registers {rspec} found"));
@@ -1362,6 +1376,11 @@ fn collect_in_cluster(
13621376
}
13631377
rdict.insert(rspec.to_string(), registers);
13641378
}
1379+
if rdict.is_empty() {
1380+
return Err(anyhow!(
1381+
"{path}: registers cannot be collected into {cname} cluster. No matches found"
1382+
));
1383+
}
13651384
let address_offset = rdict
13661385
.values()
13671386
.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)