Skip to content
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

check bitmask on _add #258

Draft
wants to merge 2 commits 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
1 change: 1 addition & 0 deletions CHANGELOG-rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,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
9 changes: 9 additions & 0 deletions src/patch/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ impl DeviceExt for Device {
}

fn delete_peripheral(&mut self, pspec: &str) -> PatchResult {
if self
.peripherals
.iter()
.filter(|p| matchname(&p.name, pspec))
.count()
== 0
{
log::info!("Trying to delete absent `{}` peripheral", pspec);
}
self.peripherals.retain(|p| !(matchname(&p.name, pspec)));
Ok(())
}
Expand Down
17 changes: 16 additions & 1 deletion src/patch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use svd_parser::svd::{
WriteConstraintRange,
};
use svd_parser::SVDError::DimIndexParse;
use svd_rs::{BitRange, DimArrayIndex, DimElement, DimElementBuilder, MaybeArray};
use svd_rs::{BitRange, DimArrayIndex, DimElement, DimElementBuilder, Field, MaybeArray};
use yaml_rust::{yaml::Hash, Yaml, YamlLoader};

use hashlink::linked_hash_map;
Expand Down Expand Up @@ -888,6 +888,21 @@ impl Interpolate for FieldPath {
}
}

fn bitmask(f: &Field) -> u64 {
let BitRange { offset, width, .. } = f.bit_range;
let mask = (!0u64 >> (64 - width)) << offset;
match f {
Field::Single(_) => mask,
Field::Array(_, d) => {
let mut bits = 0;
for i in 0..d.dim {
bits |= mask << (i * d.dim_increment);
}
bits
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
24 changes: 19 additions & 5 deletions src/patch/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,22 @@ pub(crate) trait RegisterBlockExt: Name {
}

/// 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() {
if children
.iter()
.filter(
|rc| matches!(rc, RegisterCluster::Register(r) if matchname(&r.name, rspec)),
)
.count()
== 0
{
log::info!(
"Trying to delete absent `{}` register from {}",
rspec,
bpath
);
}
children.retain(
|rc| !matches!(rc, RegisterCluster::Register(r) if matchname(&r.name, rspec)),
);
Expand Down Expand Up @@ -999,7 +1013,7 @@ impl PeripheralExt for Peripheral {
}
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 @@ -1291,6 +1305,8 @@ impl InterruptExt for Peripheral {

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 {
Expand All @@ -1309,7 +1325,7 @@ impl ClusterExt for Cluster {
}
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 @@ -1333,8 +1349,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
25 changes: 15 additions & 10 deletions src/patch/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@ pub(crate) trait RegisterInfoExt {

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
self.fields().fold(0, |mask, f| mask | super::bitmask(f))
}
}

Expand Down Expand Up @@ -68,7 +62,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 @@ -158,7 +152,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 @@ -347,12 +341,23 @@ impl RegisterExt for Register {
} else {
fnew.single()
};
let exist_bits = self.get_bitmask();
if exist_bits & super::bitmask(&fnew) != 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() {
if fields.iter().filter(|f| matchname(&f.name, fspec)).count() == 0 {
log::info!(
"Trying to delete absent `{}` field from register {}",
fspec,
rpath
);
}
fields.retain(|f| !(matchname(&f.name, fspec)));
}
Ok(())
Expand Down
Loading