From ccc1936eb4c503450b207caf974fac1f74a5401f Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Tue, 21 Apr 2026 22:39:46 +0200 Subject: [PATCH 1/7] reduce significant rightward drift --- src/svd2ir.rs | 267 ++++++++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 129 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 938b7f28..f30d6c56 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -2,6 +2,7 @@ use anyhow::{bail, Context}; use clap::ValueEnum; use log::*; use std::collections::{BTreeMap, BTreeSet}; +use std::ops::Deref; use svd_parser::svd::{self, PeripheralInfo}; use crate::{ir::*, transform}; @@ -51,142 +52,150 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let mut fieldsets: Vec = Vec::new(); let mut enums: Vec = Vec::new(); - for block in &blocks { - for r in &block.registers { - if let svd::RegisterCluster::Register(r) = r { - if r.derived_from.is_some() { + let usable_register_clusters = blocks + .iter() + .flat_map(|b| std::iter::repeat(&b.name).zip(b.registers.iter())) + .filter_map(|(b, r)| { + let svd::RegisterCluster::Register(r) = r else { + return None; + }; + + if r.derived_from.is_some() { + return None; + } + + let Some(fields) = r.fields.as_ref() else { + return None; + }; + + Some((b, r.deref().clone(), fields)) + }); + + for (block_name, r, fields) in usable_register_clusters { + let mut fieldset_name = block_name.clone(); + let mut field_name_counts: BTreeMap = BTreeMap::new(); + fieldset_name.push(replace_suffix(&r.name, "")); + + let mut out_fields = Vec::with_capacity(fields.len()); + + for f in fields { + if f.derived_from.is_some() { + continue; + } + + let mut enum_read = None; + let mut enum_write = None; + let mut enum_readwrite = None; + + let mut field_name = replace_suffix(&f.name, ""); + + let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0); + *field_name_count += 1; + if *field_name_count > 1 { + field_name = format!("{}{}", field_name, field_name_count); + } + + for e in &f.enumerated_values { + let e = if let Some(derived_from) = &e.derived_from { + let Some(e) = enum_from_name.get(derived_from.as_str()) else { + warn!( + "unknown enum to derive from ({} -> {})", + field_name, derived_from + ); + continue; + }; + e + } else { + e + }; + + let usage = e.usage.unwrap_or(svd::Usage::ReadWrite); + let target = match usage { + svd::Usage::Read => &mut enum_read, + svd::Usage::Write => &mut enum_write, + svd::Usage::ReadWrite => &mut enum_readwrite, + }; + + if target.is_some() { + warn!("ignoring enum with dup usage {:?}", usage); continue; } - if let Some(fields) = &r.fields { - let mut fieldset_name = block.name.clone(); - let mut field_name_counts: BTreeMap = BTreeMap::new(); - fieldset_name.push(replace_suffix(&r.name, "")); - - let mut out_fields = Vec::with_capacity(fields.len()); - - for f in fields { - if f.derived_from.is_some() { - continue; - } - - let mut enum_read = None; - let mut enum_write = None; - let mut enum_readwrite = None; - - let mut field_name = replace_suffix(&f.name, ""); - - let field_name_count = - field_name_counts.entry(field_name.clone()).or_insert(0); - *field_name_count += 1; - if *field_name_count > 1 { - field_name = format!("{}{}", field_name, field_name_count); - } - - for e in &f.enumerated_values { - let e = if let Some(derived_from) = &e.derived_from { - let Some(e) = enum_from_name.get(derived_from.as_str()) else { - warn!( - "unknown enum to derive from ({} -> {})", - field_name, derived_from - ); - continue; - }; - e - } else { - e - }; - - let usage = e.usage.unwrap_or(svd::Usage::ReadWrite); - let target = match usage { - svd::Usage::Read => &mut enum_read, - svd::Usage::Write => &mut enum_write, - svd::Usage::ReadWrite => &mut enum_readwrite, - }; - - if target.is_some() { - warn!("ignoring enum with dup usage {:?}", usage); - continue; - } - - *target = Some(e) - } - - enum EnumSet<'a> { - Single(&'a svd::EnumeratedValues), - ReadWrite(&'a svd::EnumeratedValues, &'a svd::EnumeratedValues), - } - - let set = match (enum_read, enum_write, enum_readwrite) { - (None, None, None) => None, - (Some(e), None, None) => Some(EnumSet::Single(e)), - (None, Some(e), None) => Some(EnumSet::Single(e)), - (None, None, Some(e)) => Some(EnumSet::Single(e)), - (Some(r), Some(w), None) => Some(EnumSet::ReadWrite(r, w)), - (Some(r), None, Some(w)) => Some(EnumSet::ReadWrite(r, w)), - (None, Some(w), Some(r)) => Some(EnumSet::ReadWrite(r, w)), - (Some(_), Some(_), Some(_)) => { - bail!("cannot have enumeratedvalues for read, write and readwrite!") - } - }; - - let enumm = if let Some(set) = set { - let variants = match set { - EnumSet::Single(e) => e.values.clone(), - EnumSet::ReadWrite(r, w) => { - let r_values = r.values.iter().map(|v| v.value.unwrap()); - let w_values = w.values.iter().map(|v| v.value.unwrap()); - let values: BTreeSet<_> = r_values.chain(w_values).collect(); - let mut values: Vec<_> = values.iter().collect(); - values.sort(); - - let r_values: BTreeMap<_, _> = - r.values.iter().map(|v| (v.value.unwrap(), v)).collect(); - let w_values: BTreeMap<_, _> = - w.values.iter().map(|v| (v.value.unwrap(), v)).collect(); - - values - .into_iter() - .map(|&v| match (r_values.get(&v), w_values.get(&v)) { - (None, None) => unreachable!(), - (Some(&r), None) => r.clone(), - (None, Some(&w)) => w.clone(), - (Some(&r), Some(&w)) => { - let mut m = r.clone(); - if r.name != w.name { - m.name = format!("R_{}_W_{}", r.name, w.name); - } - m - } - }) - .collect() + *target = Some(e) + } + + enum EnumSet<'a> { + Single(&'a svd::EnumeratedValues), + ReadWrite(&'a svd::EnumeratedValues, &'a svd::EnumeratedValues), + } + + let set = match (enum_read, enum_write, enum_readwrite) { + (None, None, None) => None, + (Some(e), None, None) => Some(EnumSet::Single(e)), + (None, Some(e), None) => Some(EnumSet::Single(e)), + (None, None, Some(e)) => Some(EnumSet::Single(e)), + (Some(r), Some(w), None) => Some(EnumSet::ReadWrite(r, w)), + (Some(r), None, Some(w)) => Some(EnumSet::ReadWrite(r, w)), + (None, Some(w), Some(r)) => Some(EnumSet::ReadWrite(r, w)), + (Some(_), Some(_), Some(_)) => { + bail!("cannot have enumeratedvalues for read, write and readwrite!") + } + }; + + let enumm = if let Some(set) = set { + let variants = match set { + EnumSet::Single(e) => e.values.clone(), + EnumSet::ReadWrite(r, w) => { + let r_values = r.values.iter().map(|v| v.value.unwrap()); + let w_values = w.values.iter().map(|v| v.value.unwrap()); + let values: BTreeSet<_> = r_values.chain(w_values).collect(); + let mut values: Vec<_> = values.iter().collect(); + values.sort(); + + let r_values: BTreeMap<_, _> = + r.values.iter().map(|v| (v.value.unwrap(), v)).collect(); + let w_values: BTreeMap<_, _> = + w.values.iter().map(|v| (v.value.unwrap(), v)).collect(); + + values + .into_iter() + .map(|&v| match (r_values.get(&v), w_values.get(&v)) { + (None, None) => unreachable!(), + (Some(&r), None) => r.clone(), + (None, Some(&w)) => w.clone(), + (Some(&r), Some(&w)) => { + let mut m = r.clone(); + if r.name != w.name { + m.name = format!("R_{}_W_{}", r.name, w.name); + } + m } - }; - - let mut name = fieldset_name.clone(); - name.push(field_name); - enums.push(ProtoEnum { - name: name.clone(), - bit_size: f.bit_range.width, - variants, - }); - Some(name) - } else { - None - }; - - out_fields.push((f.clone(), enumm)); + }) + .collect() } - - fieldsets.push(ProtoFieldset { - name: fieldset_name.clone(), - description: r.description.clone(), - bit_size: r.properties.size.unwrap_or(32), - fields: out_fields, - }); }; - } + + let mut name = fieldset_name.clone(); + name.push(field_name); + enums.push(ProtoEnum { + name: name.clone(), + bit_size: f.bit_range.width, + variants, + }); + Some(name) + } else { + None + }; + + out_fields.push((f.clone(), enumm)); } + + fieldsets.push(ProtoFieldset { + name: fieldset_name.clone(), + description: r.description.clone(), + bit_size: r.properties.size.unwrap_or(32), + fields: out_fields, + }); } // Make all collected names unique by prefixing with parents' names if needed. From 1d3423c031be2009783b7407aa490c9258185db8 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 19 Apr 2026 13:59:22 +0200 Subject: [PATCH 2/7] replace_suffix -> remove_placeholder --- src/svd2ir.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index f30d6c56..88abf6e3 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -74,7 +74,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() for (block_name, r, fields) in usable_register_clusters { let mut fieldset_name = block_name.clone(); let mut field_name_counts: BTreeMap = BTreeMap::new(); - fieldset_name.push(replace_suffix(&r.name, "")); + fieldset_name.push(remove_placeholder(&r.name)); let mut out_fields = Vec::with_capacity(fields.len()); @@ -87,7 +87,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let mut enum_write = None; let mut enum_readwrite = None; - let mut field_name = replace_suffix(&f.name, ""); + let mut field_name = remove_placeholder(&f.name); let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0); *field_name_count += 1; @@ -221,7 +221,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let fieldset_name = if r.fields.is_some() { let mut fieldset_name = proto.name.clone(); - fieldset_name.push(replace_suffix(&r.name, "")); + fieldset_name.push(remove_placeholder(&r.name)); Some(fieldset_names.get(&fieldset_name).unwrap().clone()) } else { None @@ -246,7 +246,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() }; let block_item = BlockItem { - name: replace_suffix(&r.name, ""), + name: remove_placeholder(&r.name), description: r.description.clone(), array, byte_offset: r.address_offset, @@ -265,7 +265,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() continue; } - let cname = replace_suffix(&c.name, ""); + let cname = remove_placeholder(&c.name); let array = if let svd::Cluster::Array(_, dim) = c { Some(Array::Regular(RegularArray { @@ -277,7 +277,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() }; let mut block_name = proto.name.clone(); - block_name.push(replace_suffix(&c.name, "")); + block_name.push(remove_placeholder(&c.name)); let block_name = block_names.get(&block_name).unwrap().clone(); block.items.push(BlockItem { @@ -318,7 +318,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() None }; - let field_name = replace_suffix(&f.name, ""); + let field_name = remove_placeholder(&f.name); let field = Field { name: field_name.clone(), @@ -498,7 +498,7 @@ fn collect_blocks( } let mut block_name = block_name.clone(); - block_name.push(replace_suffix(&c.name, "")); + block_name.push(remove_placeholder(&c.name)); collect_blocks(out, block_name, c.description.clone(), &c.children); } } @@ -594,10 +594,6 @@ pub fn namespace_names(peripheral: &PeripheralInfo, ir: &mut IR, namespace: Name }); } -pub fn replace_suffix(name: &str, suffix: &str) -> String { - if name.contains("[%s]") { - name.replace("[%s]", suffix) - } else { - name.replace("%s", suffix) - } +pub fn remove_placeholder(name: &str) -> String { + name.replace("[%s]", "").replace("%s", "") } From 828faca5e14e825dc4625dc3d42a327dbb9d3435 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Tue, 21 Apr 2026 22:49:28 +0200 Subject: [PATCH 3/7] Split out create_block_item --- src/svd2ir.rs | 85 ++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 88abf6e3..50e6aa8e 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -3,7 +3,7 @@ use clap::ValueEnum; use log::*; use std::collections::{BTreeMap, BTreeSet}; use std::ops::Deref; -use svd_parser::svd::{self, PeripheralInfo}; +use svd_parser::svd::{self, MaybeArray, PeripheralInfo, RegisterInfo}; use crate::{ir::*, transform}; @@ -219,44 +219,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() continue; } - let fieldset_name = if r.fields.is_some() { - let mut fieldset_name = proto.name.clone(); - fieldset_name.push(remove_placeholder(&r.name)); - Some(fieldset_names.get(&fieldset_name).unwrap().clone()) - } else { - None - }; - - let array = if let svd::Register::Array(_, dim) = r { - Some(Array::Regular(RegularArray { - len: dim.dim, - stride: dim.dim_increment, - })) - } else { - None - }; - - let access = match r.properties.access { - None => Access::ReadWrite, - Some(svd::Access::ReadOnly) => Access::Read, - Some(svd::Access::WriteOnly) => Access::Write, - Some(svd::Access::WriteOnce) => Access::Write, - Some(svd::Access::ReadWrite) => Access::ReadWrite, - Some(svd::Access::ReadWriteOnce) => Access::ReadWrite, - }; - - let block_item = BlockItem { - name: remove_placeholder(&r.name), - description: r.description.clone(), - array, - byte_offset: r.address_offset, - inner: BlockItemInner::Register(Register { - access, // todo - bit_size: r.properties.size.unwrap_or(32), - fieldset: fieldset_name.clone(), - }), - }; - + let block_item = create_block_item(proto, &fieldset_names, r); block.items.push(block_item) } svd::RegisterCluster::Cluster(c) => { @@ -372,6 +335,50 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() Ok(()) } +fn create_block_item( + proto: &ProtoBlock, + fieldset_names: &BTreeMap, String>, + r: &MaybeArray, +) -> BlockItem { + let fieldset_name = if r.fields.is_some() { + let mut fieldset_name = proto.name.clone(); + fieldset_name.push(remove_placeholder(&r.name)); + Some(fieldset_names.get(&fieldset_name).unwrap().clone()) + } else { + None + }; + + let array = if let svd::Register::Array(_, dim) = r { + Some(Array::Regular(RegularArray { + len: dim.dim, + stride: dim.dim_increment, + })) + } else { + None + }; + + let access = match r.properties.access { + None => Access::ReadWrite, + Some(svd::Access::ReadOnly) => Access::Read, + Some(svd::Access::WriteOnly) => Access::Write, + Some(svd::Access::WriteOnce) => Access::Write, + Some(svd::Access::ReadWrite) => Access::ReadWrite, + Some(svd::Access::ReadWriteOnce) => Access::ReadWrite, + }; + + BlockItem { + name: remove_placeholder(&r.name), + description: r.description.clone(), + array, + byte_offset: r.address_offset, + inner: BlockItemInner::Register(Register { + access, // todo + bit_size: r.properties.size.unwrap_or(32), + fieldset: fieldset_name.clone(), + }), + } +} + /// Convert an entire SVD to IR. pub fn convert_svd(svd: &svd::Device, namespace: NamespaceMode) -> anyhow::Result { let mut ir = IR::new(); From 6bce837145a9f9caefc4a86b5430b676d61821d0 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 18 Apr 2026 22:20:59 +0200 Subject: [PATCH 4/7] Support loading names with placeholders --- src/svd2ir.rs | 278 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 202 insertions(+), 76 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 50e6aa8e..f038e541 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -38,6 +38,107 @@ pub enum NamespaceMode { BlockWithRegsVals, } +fn remove_placeholder(str: &str) -> String { + str.replace("[%s]", "").replace("%s", "") +} + +fn names(array: &MaybeArray, f: F) -> ExpandedMaybeArray +where + F: Fn(&T) -> &str, +{ + fn is_numeric(str: &String) -> bool { + str.chars().all(|v| v.is_numeric()) + } + + fn replace_placeholder(str: &str, replacement: &str) -> String { + str.replace("%s", replacement) + } + + fn as_array_name<'a>( + r: &str, + mut dim_element: impl Iterator, + ) -> Option<&str> { + if let Some(array) = r.strip_suffix("[%s]") { + Some(array) + } else if let Some(missed_array) = r.strip_suffix("%s") { + // If all dimensions are numeric, the element is an IR + // array because accessing with a number offset makes + // sense. + if dim_element.all(is_numeric) { + Some(missed_array) + } else { + None + } + } else { + None + } + } + + match array { + MaybeArray::Single(r) => ExpandedMaybeArray::Single(f(r).to_string()), + MaybeArray::Array(r, dim_element) => { + if let Some(array_name) = as_array_name(f(r), dim_element.dim_index.iter().flatten()) { + ExpandedMaybeArray::Array { + name: array_name.to_string(), + array: Array::Regular(RegularArray { + len: dim_element.dim, + stride: dim_element.dim_increment, + }), + } + } else { + let offsets = (0..).step_by(dim_element.dim_increment as _); + + let values = offsets + .zip( + dim_element + .dim_index + .iter() + .flat_map(|v| v.iter()) + .map(|dim| replace_placeholder(f(r), dim)), + ) + .collect(); + + ExpandedMaybeArray::Many(values) + } + } + } +} + +#[derive(Clone)] +enum ExpandedMaybeArray { + Single(String), + Array { name: String, array: Array }, + Many(Vec<(u32, String)>), +} + +impl ExpandedMaybeArray { + pub fn array(&self) -> Option { + match self { + ExpandedMaybeArray::Array { array, .. } => Some(array.clone()), + _ => None, + } + } +} + +impl IntoIterator for ExpandedMaybeArray { + type Item = (u32, String); + + type IntoIter = std::vec::IntoIter<(u32, String)>; + + fn into_iter(self) -> Self::IntoIter { + match self { + ExpandedMaybeArray::Single(s) => vec![(0, s)].into_iter(), + ExpandedMaybeArray::Array { name, .. } => vec![(0, name)].into_iter(), + ExpandedMaybeArray::Many(items) => items.into_iter(), + } + } +} + +fn fieldset_name(mut block_name: Vec, reg_name: String) -> Vec { + block_name.push(reg_name); + block_name +} + pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()> { let mut blocks = Vec::new(); let pname = p.header_struct_name.clone().unwrap_or(p.name.clone()); @@ -49,8 +150,15 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() ); let enum_from_name = enum_map(&blocks); + let mut fieldsets: Vec = Vec::new(); let mut enums: Vec = Vec::new(); + // A map mapping fully expanded fieldset names to their unique + // equivalent. E.g. `blocka::REG%s` with dimensions `A`, `B`, `C` would + // add `blocka::REGA -> blocka::REG`, `blocka::REGB -> blocka::REG` and + // `blocka::REGC -> REG` to this map. + let mut fieldset_mapping = BTreeMap::new(); + let mut used_fieldset_names = BTreeSet::new(); let usable_register_clusters = blocks .iter() @@ -68,14 +176,39 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() return None; }; - Some((b, r.deref().clone(), fields)) + let without_placeholder = remove_placeholder(&r.name); + let mut unique_fs_name = fieldset_name(b.clone(), without_placeholder.clone()); + + let mut counter = 0; + loop { + if counter != 0 { + let last = unique_fs_name.last_mut().unwrap(); + if last.ends_with('_') { + *last = format!("{}{}", last, counter); + } else { + *last = format!("{}_{}", without_placeholder, counter); + } + } + + counter += 1; + + if !used_fieldset_names.contains(&unique_fs_name) { + break; + } + } + + used_fieldset_names.insert(unique_fs_name.clone()); + + for (_, full_name) in names(r, |r| &r.name) { + let full_name: Vec<_> = fieldset_name(b.clone(), full_name); + fieldset_mapping.insert(full_name, unique_fs_name.clone()); + } + + Some((unique_fs_name, r.deref(), fields)) }); - for (block_name, r, fields) in usable_register_clusters { - let mut fieldset_name = block_name.clone(); + for (fieldset_name, r, fields) in usable_register_clusters { let mut field_name_counts: BTreeMap = BTreeMap::new(); - fieldset_name.push(remove_placeholder(&r.name)); - let mut out_fields = Vec::with_capacity(fields.len()); for f in fields { @@ -88,7 +221,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let mut enum_readwrite = None; let mut field_name = remove_placeholder(&f.name); - let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0); *field_name_count += 1; if *field_name_count > 1 { @@ -219,8 +351,21 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() continue; } - let block_item = create_block_item(proto, &fieldset_names, r); - block.items.push(block_item) + let names = crate::svd2ir::names(&r, |r| &r.name); + let array = names.array(); + + for (offset, name) in names { + let block_item = create_block_item( + name, + offset, + proto, + &fieldset_mapping, + &fieldset_names, + array.as_ref(), + r, + ); + block.items.push(block_item) + } } svd::RegisterCluster::Cluster(c) => { if c.derived_from.is_some() { @@ -228,28 +373,22 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() continue; } - let cname = remove_placeholder(&c.name); - - let array = if let svd::Cluster::Array(_, dim) = c { - Some(Array::Regular(RegularArray { - len: dim.dim, - stride: dim.dim_increment, - })) - } else { - None - }; - - let mut block_name = proto.name.clone(); - block_name.push(remove_placeholder(&c.name)); - let block_name = block_names.get(&block_name).unwrap().clone(); - - block.items.push(BlockItem { - name: cname.clone(), - description: c.description.clone(), - array, - byte_offset: c.address_offset, - inner: BlockItemInner::Block(BlockItemBlock { block: block_name }), - }); + let names = names(c, |c| &c.name); + let array = names.array(); + + for (offset, cname) in names { + let mut block_name = proto.name.clone(); + block_name.push(cname.clone()); + let block_name = block_names.get(&block_name).unwrap().clone(); + + block.items.push(BlockItem { + name: cname.clone(), + description: c.description.clone(), + array: array.clone(), + byte_offset: c.address_offset + offset, + inner: BlockItemInner::Block(BlockItemBlock { block: block_name }), + }); + } } } } @@ -272,32 +411,26 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() warn!("unsupported derived_from in fieldset"); } - let array = if let svd::Field::Array(_, dim) = f { - Some(Array::Regular(RegularArray { - len: dim.dim, - stride: dim.dim_increment, - })) - } else { - None - }; + let names = names(f, |f| &f.name); + let array = names.array(); - let field_name = remove_placeholder(&f.name); - - let field = Field { - name: field_name.clone(), - description: f.description.clone(), - bit_offset: BitOffset::Regular(f.bit_range.offset), - bit_size: f.bit_range.width, - array, - enumm: enumm.as_ref().map(|v| { - enum_names - .get(v) - .cloned() - .expect("All enums have a unique-name mapping") - }), - }; + for (offset, field_name) in names { + let field = Field { + name: field_name.clone(), + description: f.description.clone(), + bit_offset: BitOffset::Regular(f.bit_range.offset + offset), + bit_size: f.bit_range.width, + array: array.clone(), + enumm: enumm.as_ref().map(|v| { + enum_names + .get(v) + .cloned() + .expect("All enums have a unique-name mapping") + }), + }; - fieldset.fields.push(field) + fieldset.fields.push(field) + } } let fieldset_name = fieldset_names.get(&proto.name).unwrap().clone(); @@ -336,23 +469,18 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() } fn create_block_item( + name: String, + offset: u32, proto: &ProtoBlock, + inner_block_to_fieldset: &BTreeMap, Vec>, fieldset_names: &BTreeMap, String>, + array: Option<&Array>, r: &MaybeArray, ) -> BlockItem { let fieldset_name = if r.fields.is_some() { - let mut fieldset_name = proto.name.clone(); - fieldset_name.push(remove_placeholder(&r.name)); - Some(fieldset_names.get(&fieldset_name).unwrap().clone()) - } else { - None - }; - - let array = if let svd::Register::Array(_, dim) = r { - Some(Array::Regular(RegularArray { - len: dim.dim, - stride: dim.dim_increment, - })) + let fieldset_full_name = fieldset_name(proto.name.clone(), name.clone()); + let fieldset_name = inner_block_to_fieldset.get(&fieldset_full_name).unwrap(); + Some(fieldset_names.get(fieldset_name).unwrap().clone()) } else { None }; @@ -367,10 +495,10 @@ fn create_block_item( }; BlockItem { - name: remove_placeholder(&r.name), + name: name, description: r.description.clone(), - array, - byte_offset: r.address_offset, + array: array.cloned(), + byte_offset: r.address_offset + offset, inner: BlockItemInner::Register(Register { access, // todo bit_size: r.properties.size.unwrap_or(32), @@ -504,9 +632,11 @@ fn collect_blocks( continue; } - let mut block_name = block_name.clone(); - block_name.push(remove_placeholder(&c.name)); - collect_blocks(out, block_name, c.description.clone(), &c.children); + for (_, block) in names(c, |c| &c.name) { + let mut block_name = block_name.clone(); + block_name.push(block); + collect_blocks(out, block_name, c.description.clone(), &c.children); + } } } } @@ -600,7 +730,3 @@ pub fn namespace_names(peripheral: &PeripheralInfo, ir: &mut IR, namespace: Name } }); } - -pub fn remove_placeholder(name: &str) -> String { - name.replace("[%s]", "").replace("%s", "") -} From 1a90983dfc0bb828913f43c401ca781212e18f02 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 3 May 2026 16:32:23 +0200 Subject: [PATCH 5/7] don't treat clusters ending in numbers as arrays --- src/svd2ir.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index f038e541..7c45f4de 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -46,29 +46,13 @@ fn names(array: &MaybeArray, f: F) -> ExpandedMaybeArray where F: Fn(&T) -> &str, { - fn is_numeric(str: &String) -> bool { - str.chars().all(|v| v.is_numeric()) - } - fn replace_placeholder(str: &str, replacement: &str) -> String { str.replace("%s", replacement) } - fn as_array_name<'a>( - r: &str, - mut dim_element: impl Iterator, - ) -> Option<&str> { + fn as_array_name<'a>(r: &str) -> Option<&str> { if let Some(array) = r.strip_suffix("[%s]") { Some(array) - } else if let Some(missed_array) = r.strip_suffix("%s") { - // If all dimensions are numeric, the element is an IR - // array because accessing with a number offset makes - // sense. - if dim_element.all(is_numeric) { - Some(missed_array) - } else { - None - } } else { None } @@ -77,7 +61,7 @@ where match array { MaybeArray::Single(r) => ExpandedMaybeArray::Single(f(r).to_string()), MaybeArray::Array(r, dim_element) => { - if let Some(array_name) = as_array_name(f(r), dim_element.dim_index.iter().flatten()) { + if let Some(array_name) = as_array_name(f(r)) { ExpandedMaybeArray::Array { name: array_name.to_string(), array: Array::Regular(RegularArray { From 1fd3478a2b31fb50b6e7f2d9865c3c95e02f6e70 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Tue, 26 May 2026 18:59:08 +0200 Subject: [PATCH 6/7] Fix for dim_increment == 0 --- src/svd2ir.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 7c45f4de..c6d2b669 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -61,7 +61,8 @@ where match array { MaybeArray::Single(r) => ExpandedMaybeArray::Single(f(r).to_string()), MaybeArray::Array(r, dim_element) => { - if let Some(array_name) = as_array_name(f(r)) { + let name = f(r); + if let Some(array_name) = as_array_name(name) { ExpandedMaybeArray::Array { name: array_name.to_string(), array: Array::Regular(RegularArray { @@ -70,7 +71,20 @@ where }), } } else { - let offsets = (0..).step_by(dim_element.dim_increment as _); + // `dim_increment` may be 0 for `dim == 1` (degenerate "array" of + // one element); `step_by(0)` would panic, so clamp to 1. For + // `dim > 1`, a zero stride is nonsensical and we fail loudly. + let stride = if dim_element.dim_increment == 0 { + assert!( + dim_element.dim == 1, + "dimIncrement=0 with dim={} > 1 in {name}", + dim_element.dim, + ); + 1 + } else { + dim_element.dim_increment + }; + let offsets = (0..).step_by(stride as _); let values = offsets .zip( @@ -78,7 +92,7 @@ where .dim_index .iter() .flat_map(|v| v.iter()) - .map(|dim| replace_placeholder(f(r), dim)), + .map(|dim| replace_placeholder(name, dim)), ) .collect(); From c476cf3dd39c0a99a36ea1881f037094db5d7ef8 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Tue, 26 May 2026 18:59:35 +0200 Subject: [PATCH 7/7] ci: print which file we're currently processing --- tests/svd2ir.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/svd2ir.rs b/tests/svd2ir.rs index fda5f335..8337b6d0 100644 --- a/tests/svd2ir.rs +++ b/tests/svd2ir.rs @@ -49,6 +49,7 @@ fn ensure_svds_repo() -> PathBuf { } fn process_svd(svd_path: &Path, out_dir: &Path) { + eprintln!("Processing {}...", svd_path.display()); let chip = svd_path.file_stem().unwrap().to_str().unwrap(); let chip_out = out_dir.join(chip); if chip_out.exists() {