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
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Up @@ -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

Expand All @@ -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

Expand Down
3 changes: 1 addition & 2 deletions src/html/html_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
10 changes: 9 additions & 1 deletion src/patch/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
89 changes: 57 additions & 32 deletions src/patch/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"))
Expand All @@ -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(())
Expand Down Expand Up @@ -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")? {
Expand Down Expand Up @@ -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")? {
Expand All @@ -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()?;
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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| {
Expand Down
43 changes: 21 additions & 22 deletions src/patch/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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] = &[
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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}`"))?;
}

Expand Down Expand Up @@ -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(())
}
Expand Down