diff --git a/src/generate/block.rs b/src/generate/block.rs index 3a7b566..b25e49d 100644 --- a/src/generate/block.rs +++ b/src/generate/block.rs @@ -43,15 +43,33 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result); if let Some(array) = &i.array { - let (len, offs_expr) = super::process_array(array); - items.extend(quote!( - #doc - #[inline(always)] - pub const fn #name(self, n: usize) -> #ty { - assert!(n < #len); - unsafe { #common_path::Reg::from_ptr(self.ptr.wrapping_add(#offset + #offs_expr) as _) } + let (len, offs_expr, indexes) = super::process_array(array); + + if let Some(indexes) = indexes { + for (array_offset, index) in indexes.iter() { + // TODO don't erase %s so we can position the index in the name as our overlords intended? + let name = Ident::new(&format!("{}_{}", i.name, index), span); + let doc = + util::doc(&i.description.clone().map(|s| s.replace("%s", index))); + + items.extend(quote!( + #doc + #[inline(always)] + pub const fn #name(self) -> #ty { + unsafe { #common_path::Reg::from_ptr(self.ptr.wrapping_add(#offset + #array_offset) as _) } + } + )); } - )); + } else { + items.extend(quote!( + #doc + #[inline(always)] + pub const fn #name(self, n: usize) -> #ty { + assert!(n < #len); + unsafe { #common_path::Reg::from_ptr(self.ptr.wrapping_add(#offset + #offs_expr) as _) } + } + )); + } } else { items.extend(quote!( #doc @@ -67,7 +85,7 @@ pub fn render(opts: &super::Options, ir: &IR, b: &Block, path: &str) -> Result Resu BitOffset::Regular(off_in_reg) => { let off_in_reg = off_in_reg as usize; if let Some(array) = &f.array { - let (len, offs_expr) = super::process_array(array); + let (len, offs_expr, _indexes) = super::process_array(array); items.extend(quote!( #doc #[must_use] @@ -144,7 +144,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } if let Some(array) = &f.array { - let (len, offs_expr) = super::process_array(array); + let (len, offs_expr, _indexes) = super::process_array(array); items.extend(quote!( #doc #[must_use] diff --git a/src/generate/mod.rs b/src/generate/mod.rs index f652803..41621d3 100644 --- a/src/generate/mod.rs +++ b/src/generate/mod.rs @@ -214,13 +214,20 @@ fn split_path(s: &str) -> (Vec<&str>, &str) { (v, n) } -fn process_array(array: &Array) -> (usize, TokenStream) { +fn process_array(array: &Array) -> (usize, TokenStream, Option>) { match array { Array::Regular(array) => { let len = array.len as usize; let stride = array.stride as usize; let offs_expr = quote!(n*#stride); - (len, offs_expr) + let indexes = array.indexes.clone().map(|indexes| { + indexes + .into_iter() + .enumerate() + .map(|(i, index_name)| (quote!(#i * #stride), index_name)) + .collect() + }); + (len, offs_expr, indexes) } Array::Cursed(array) => { let len = array.offsets.len(); @@ -230,7 +237,7 @@ fn process_array(array: &Array) -> (usize, TokenStream) { .map(|&x| x as usize) .collect::>(); let offs_expr = quote!(([#(#offsets),*][n] as usize)); - (len, offs_expr) + (len, offs_expr, None) } } } diff --git a/src/ir.rs b/src/ir.rs index f696328..fdcc4c8 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -113,6 +113,7 @@ impl Array { pub struct RegularArray { pub len: u32, pub stride: u32, + pub indexes: Option>, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 8d65855..71c65f6 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -42,15 +42,29 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let mut enums: Vec = Vec::new(); for block in &blocks { + let mut register_name_counts: BTreeMap = BTreeMap::new(); + for r in &block.registers { if let svd::RegisterCluster::Register(r) = r { if r.derived_from.is_some() { continue; } + let register_name_count = register_name_counts.entry(r.name.clone()).or_insert(0); + let mut register_name = r.name.clone(); + *register_name_count += 1; + if *register_name_count > 1 { + if r.is_array() { + register_name = format!("{}{}", register_name, register_name_count); + } else { + // This will blow up in unique_names + error!("Dupe Register: {register_name}"); + } + } + if let Some(fields) = &r.fields { let mut fieldset_name = block.name.clone(); - fieldset_name.push(util::replace_suffix(&r.name, "")); + fieldset_name.push(util::replace_suffix(®ister_name, "")); fieldsets.push(ProtoFieldset { name: fieldset_name.clone(), description: r.description.clone(), @@ -193,9 +207,31 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() }; let array = if let svd::Register::Array(_, dim) = r { + let indexes = match &dim.dim_index { + Some(indexes) => { + // If the indexes are a range of integers treat the register as an array + // TODO: Check the stop, start and finesse the accessors thusly + let indexes = indexes + .iter() + .filter_map(|i| match i.parse::() { + Ok(_) => None, + Err(_) => Some(i.to_lowercase()), + }) + .collect::>(); + + if !indexes.is_empty() { + Some(indexes.clone()) + } else { + None + } + } + None => None, + }; + Some(Array::Regular(RegularArray { len: dim.dim, stride: dim.dim_increment, + indexes, })) } else { None @@ -236,6 +272,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() Some(Array::Regular(RegularArray { len: dim.dim, stride: dim.dim_increment, + indexes: dim.dim_index.clone(), })) } else { None @@ -278,6 +315,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() Some(Array::Regular(RegularArray { len: dim.dim, stride: dim.dim_increment, + indexes: dim.dim_index.clone(), })) } else { None diff --git a/src/transform/common.rs b/src/transform/common.rs index b68c0c7..3c9446d 100644 --- a/src/transform/common.rs +++ b/src/transform/common.rs @@ -311,6 +311,7 @@ pub(crate) fn calc_array(mut offsets: Vec, mode: ArrayMode) -> anyhow::Resu Array::Regular(RegularArray { len: offsets.len() as _, stride, + indexes: None, }), )); } @@ -328,7 +329,14 @@ pub(crate) fn calc_array(mut offsets: Vec, mode: ArrayMode) -> anyhow::Resu } ArrayMode::Holey => { let len = (offsets.last().unwrap() - offsets.first().unwrap()) / stride + 1; - Ok((start_offset, Array::Regular(RegularArray { len, stride }))) + Ok(( + start_offset, + Array::Regular(RegularArray { + len, + stride, + indexes: None, + }), + )) } } } diff --git a/src/transform/sanitize.rs b/src/transform/sanitize.rs index c1d4524..064f576 100644 --- a/src/transform/sanitize.rs +++ b/src/transform/sanitize.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::util::StringExt; +use crate::{ir::BlockItemInner, util::StringExt}; use super::{map_names, NameKind, IR}; @@ -28,6 +28,7 @@ impl Sanitize { rename_duplicate_variants(enumm); } + rename_duplicate_fieldsets(ir); Ok(()) } } @@ -92,3 +93,28 @@ fn rename_duplicate_variants(enumm: &mut crate::ir::Enum) { } } } + +fn rename_duplicate_fieldsets(ir: &mut crate::ir::IR) { + use std::collections::BTreeMap; + + for (_name, blk) in ir.blocks.iter_mut() { + let mut register_name_counts: BTreeMap = BTreeMap::new(); + for block_item in blk.items.iter_mut() { + if let BlockItemInner::Register(r) = &mut block_item.inner { + let name_count = register_name_counts + .entry(block_item.name.clone()) + .or_insert(0); + + *name_count += 1; + + if *name_count > 1 { + block_item.name = format!("{}{}", block_item.name, name_count); + r.fieldset = r + .fieldset + .as_mut() + .map(|path| format!("{}{}", path, name_count)); + } + } + } + } +}