Skip to content

check bitmask on _add #258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -63,4 +63,4 @@ jobs:
python -m pip install --upgrade pip
pip install .
- name: Check
run: bash tools/check_${{ matrix.target }}.sh
run: RUST_LOG=warn bash tools/check_${{ matrix.target }}.sh
2 changes: 2 additions & 0 deletions CHANGELOG-rust.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ This changelog tracks the Rust `svdtools` project. See
## [Unreleased]

* Calculate `_add` position for peripherals and registers
* Update `svd-rs` to 0.4.10

## [v0.4.4] 2025-02-08

@@ -32,6 +33,7 @@ This changelog tracks the Rust `svdtools` project. See
## [v0.3.21] 2024-12-31

* `_derive` field
* WARN when add field intersecting with other fields

## [v0.3.20] 2024-11-14

3 changes: 1 addition & 2 deletions src/html/html_cli.rs
Original file line number Diff line number Diff line change
@@ -283,8 +283,7 @@ fn parse_register(

let foffset = ftag.bit_offset();
let fwidth = ftag.bit_width();
let bit_mask = (u64::MAX >> (u64::BITS - fwidth)) << foffset;
filling |= bit_mask;
filling |= ftag.bitmask();

let faccs = ftag.access.map(Access::as_str).unwrap_or(raccs);
let enums = ftag.enumerated_values.first();
10 changes: 9 additions & 1 deletion src/patch/device.rs
Original file line number Diff line number Diff line change
@@ -183,7 +183,15 @@ impl DeviceExt for Device {
}

fn delete_peripheral(&mut self, pspec: &str) -> PatchResult {
self.peripherals.retain(|p| !(matchname(&p.name, pspec)));
let mut done = false;
self.peripherals.retain(|p| {
let del = matchname(&p.name, pspec);
done |= del;
!del
});
if !done {
log::info!("Trying to delete absent `{}` peripheral", pspec);
}
Ok(())
}

89 changes: 57 additions & 32 deletions src/patch/peripheral.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use svd_parser::svd::{
use yaml_rust::{yaml::Hash, Yaml};

use super::iterators::{MatchIter, Matched};
use super::register::{RegisterExt, RegisterInfoExt};
use super::register::RegisterExt;
use super::yaml_ext::{AsType, GetVal, ToYaml};
use super::{
adding_pos, check_offsets, common_description, make_dim_element, matchname, matchsubspec,
@@ -170,21 +170,43 @@ pub(crate) trait RegisterBlockExt: Name {
}

/// Delete registers and clusters matched by rspec inside ptag
fn delete_child(&mut self, rcspec: &str) -> PatchResult {
fn delete_child(&mut self, rcspec: &str, bpath: &BlockPath) -> PatchResult {
if let Some(children) = self.children_mut() {
children.retain(|rc| !matchname(rc.name(), rcspec));
let mut done = false;
children.retain(|rc| {
let del = matchname(rc.name(), rcspec);
done |= del;
!del
});
if !done {
log::info!(
"Trying to delete absent `{}` register/cluster from {}",
rcspec,
bpath
);
}
Ok(())
} else {
Err(anyhow!("No registers or clusters"))
}
}

/// Delete registers matched by rspec inside ptag
fn delete_register(&mut self, rspec: &str) -> PatchResult {
fn delete_register(&mut self, rspec: &str, bpath: &BlockPath) -> PatchResult {
if let Some(children) = self.children_mut() {
children.retain(
|rc| !matches!(rc, RegisterCluster::Register(r) if matchname(&r.name, rspec)),
);
let mut done = false;
children.retain(|rc| {
let del = matches!(rc, RegisterCluster::Register(r) if matchname(&r.name, rspec));
done |= del;
!del
});
if !done {
log::info!(
"Trying to delete absent `{}` register from {}",
rspec,
bpath
);
}
Ok(())
} else {
Err(anyhow!("No registers or clusters"))
@@ -195,16 +217,13 @@ pub(crate) trait RegisterBlockExt: Name {
let (cspec, ignore) = cspec.spec();

if let Some(children) = self.children_mut() {
let mut deleted = false;
let mut done = false;
children.retain(|rc| {
let retain =
!matches!(rc, RegisterCluster::Cluster(c) if matchname(&c.name, cspec));
if !retain {
deleted = true;
}
retain
let del = matches!(rc, RegisterCluster::Cluster(c) if matchname(&c.name, cspec));
done |= del;
!del
});
if !deleted && !ignore {
if !done && !ignore {
Err(anyhow!("No matching clusters found"))
} else {
Ok(())
@@ -1061,21 +1080,21 @@ impl PeripheralExt for Peripheral {
if let Some(deletions) = pmod.get_yaml("_delete") {
match deletions {
Yaml::String(rcspec) => {
self.delete_child(rcspec).with_context(|| {
self.delete_child(rcspec, &ppath).with_context(|| {
format!("Deleting registers and clusters matched to `{rcspec}`")
})?;
}
Yaml::Array(deletions) => {
for rcspec in deletions {
let rcspec = rcspec.str()?;
self.delete_child(rcspec).with_context(|| {
self.delete_child(rcspec, &ppath).with_context(|| {
format!("Deleting registers and clusters matched to `{rcspec}`")
})?;
}
}
Yaml::Hash(deletions) => {
for rspec in deletions.str_vec_iter("_registers")? {
self.delete_register(rspec)
self.delete_register(rspec, &ppath)
.with_context(|| format!("Deleting registers matched to `{rspec}`"))?;
}
for cspec in deletions.str_vec_iter("_clusters")? {
@@ -1369,32 +1388,46 @@ impl InterruptExt for Peripheral {
}

fn delete_interrupt(&mut self, ispec: &str) -> PatchResult {
self.interrupt.retain(|i| !(matchname(&i.name, ispec)));
let mut done = false;
self.interrupt.retain(|i| {
let del = matchname(&i.name, ispec);
done |= del;
!del
});
if !done {
log::info!(
"Trying to delete absent `{}` interrupt from {}",
ispec,
self.name
);
}
Ok(())
}
}

impl ClusterExt for Cluster {
fn pre_process(&mut self, cmod: &Hash, parent: &BlockPath, _config: &Config) -> PatchResult {
let cpath = parent.new_cluster(&self.name);

// Handle deletions
if let Some(deletions) = cmod.get_yaml("_delete") {
match deletions {
Yaml::String(rcspec) => {
self.delete_child(rcspec).with_context(|| {
self.delete_child(rcspec, &cpath).with_context(|| {
format!("Deleting registers and clusters matched to `{rcspec}`")
})?;
}
Yaml::Array(deletions) => {
for rcspec in deletions {
let rcspec = rcspec.str()?;
self.delete_child(rcspec).with_context(|| {
self.delete_child(rcspec, &cpath).with_context(|| {
format!("Deleting registers and clusters matched to `{rcspec}`")
})?;
}
}
Yaml::Hash(deletions) => {
for rspec in deletions.str_vec_iter("_registers")? {
self.delete_register(rspec)
self.delete_register(rspec, &cpath)
.with_context(|| format!("Deleting registers matched to `{rspec}`"))?;
}
for cspec in deletions.str_vec_iter("_clusters")? {
@@ -1418,8 +1451,6 @@ impl ClusterExt for Cluster {
}
}

let cpath = parent.new_cluster(&self.name);

// Handle any copied peripherals
for (rname, rcopy) in cmod.hash_iter("_copy") {
let rname = rname.str()?;
@@ -1675,10 +1706,7 @@ fn collect_in_array(
if !check_offsets(&offsets, dim_increment) {
return Err(anyhow!("{path}: registers cannot be collected into {rspec} array. Different addressOffset increments"));
}
let bitmasks = registers
.iter()
.map(RegisterInfo::get_bitmask)
.collect::<Vec<_>>();
let bitmasks = registers.iter().map(|r| r.bitmask()).collect::<Vec<_>>();
if !bitmasks.iter().all(|&m| m == bitmasks[0]) {
return Err(anyhow!(
"{path}: registers cannot be collected into {rspec} array. Different bit masks"
@@ -1801,10 +1829,7 @@ fn collect_in_cluster(
"Some of `{rspec}` registers are arrays and some are not"
));
}
let bitmasks = registers
.iter()
.map(|r| RegisterInfo::get_bitmask(r))
.collect::<Vec<_>>();
let bitmasks = registers.iter().map(|r| r.bitmask()).collect::<Vec<_>>();
let new_dim_index = registers
.iter()
.map(|r| {
43 changes: 21 additions & 22 deletions src/patch/register.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use itertools::Itertools;
use svd_parser::expand::{BlockPath, RegisterPath};
use svd_parser::svd::{
Access, BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues,
ReadAction, Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange,
ReadAction, Register, Usage, WriteConstraint, WriteConstraintRange,
};
use yaml_rust::{yaml::Hash, Yaml};

@@ -21,23 +21,6 @@ use super::{make_derived_enumerated_values, make_ev_array, make_ev_name, make_fi

pub type FieldMatchIterMut<'a, 'b> = MatchIter<'b, std::slice::IterMut<'a, Field>>;

pub(crate) trait RegisterInfoExt {
/// Calculate filling of register
fn get_bitmask(&self) -> u64;
}

impl RegisterInfoExt for RegisterInfo {
fn get_bitmask(&self) -> u64 {
let mut mask = 0x0;
if let Some(fields) = self.fields.as_ref() {
for ftag in fields {
mask |= (!0 >> (64 - ftag.bit_range.width)) << ftag.bit_range.offset;
}
}
mask
}
}

/// Collecting methods for processing register contents
pub trait RegisterExt {
const KEYWORDS: &'static [&'static str] = &[
@@ -70,7 +53,7 @@ pub trait RegisterExt {
fn add_field(&mut self, fname: &str, fadd: &Hash, rpath: &RegisterPath) -> PatchResult;

/// Delete fields matched by fspec inside rtag
fn delete_field(&mut self, fspec: &str) -> PatchResult;
fn delete_field(&mut self, fspec: &str, rpath: &RegisterPath) -> PatchResult;

/// Clear field from rname and mark it as derivedFrom rderive.
fn derive_field(&mut self, fname: &str, fderive: &Yaml, rpath: &RegisterPath) -> PatchResult;
@@ -166,7 +149,7 @@ impl RegisterExt for Register {

// Handle deletions
for fspec in rmod.str_vec_iter("_delete")? {
self.delete_field(fspec)
self.delete_field(fspec, &rpath)
.with_context(|| format!("Deleting fields matched to `{fspec}`"))?;
}

@@ -380,13 +363,29 @@ impl RegisterExt for Register {
} else {
fnew.single()
};
let exist_bits = self.bitmask();
if exist_bits & fnew.bitmask() != 0 {
log::warn!("field {fname} conflicts with other fields in register {rpath}");
}
self.fields.get_or_insert_with(Default::default).push(fnew);
Ok(())
}

fn delete_field(&mut self, fspec: &str) -> PatchResult {
fn delete_field(&mut self, fspec: &str, rpath: &RegisterPath) -> PatchResult {
if let Some(fields) = self.fields.as_mut() {
fields.retain(|f| !(matchname(&f.name, fspec)));
let mut done = false;
fields.retain(|f| {
let del = matchname(&f.name, fspec);
done |= del;
!del
});
if !done {
log::info!(
"Trying to delete absent `{}` field from register {}",
fspec,
rpath
);
}
}
Ok(())
}