From 05cd08240825529fec4d6740fa4744fcdfd93617 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 3 May 2026 21:48:03 +0200 Subject: [PATCH 1/3] turn enum extraction into a function --- src/svd2ir.rs | 201 +++++++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 94 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 938b7f28..14fcb81c 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Context}; use clap::ValueEnum; use log::*; use std::collections::{BTreeMap, BTreeSet}; -use svd_parser::svd::{self, PeripheralInfo}; +use svd_parser::svd::{self, FieldInfo, PeripheralInfo}; use crate::{ir::*, transform}; @@ -70,10 +70,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() 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 = @@ -83,98 +79,16 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() 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 + let enum_name = fieldset_name.iter().chain(std::iter::once(&field_name)); + let enumm = + if let Some(enumm) = extract_enum(enum_name, &enum_from_name, &f)? { + let name = enumm.name.clone(); + enums.push(enumm); + Some(name) } 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() - } + None }; - 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)); } @@ -445,6 +359,105 @@ pub fn convert_svd(svd: &svd::Device, namespace: NamespaceMode) -> anyhow::Resul Ok(ir) } +fn extract_enum<'a>( + enum_name: impl Iterator, + enum_from_name: &BTreeMap<&str, &svd::EnumeratedValues>, + field: &FieldInfo, +) -> anyhow::Result> { + let mut enum_read = None; + let mut enum_write = None; + let mut enum_readwrite = None; + + for e in &field.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!") + } + }; + + 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() + } + }; + + Ok(Some(ProtoEnum { + name: enum_name.cloned().collect(), + bit_size: field.bit_range.width, + variants, + })) + } else { + Ok(None) + } +} + /// Create a map of all enums by name. /// Ignores potential duplicates of names. fn enum_map(blocks: &[ProtoBlock]) -> BTreeMap<&'_ str, &'_ svd::EnumeratedValues> { From 0b7987120232e7a635c274a2480c8d44aaa7f93d Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 3 May 2026 22:20:46 +0200 Subject: [PATCH 2/3] simplify extract_enum --- src/svd2ir.rs | 125 +++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 77 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 14fcb81c..180cd94a 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -1,8 +1,8 @@ -use anyhow::{bail, Context}; +use anyhow::Context; use clap::ValueEnum; use log::*; -use std::collections::{BTreeMap, BTreeSet}; -use svd_parser::svd::{self, FieldInfo, PeripheralInfo}; +use std::collections::BTreeMap; +use svd_parser::svd::{self, EnumeratedValue, FieldInfo, PeripheralInfo}; use crate::{ir::*, transform}; @@ -81,7 +81,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() let enum_name = fieldset_name.iter().chain(std::iter::once(&field_name)); let enumm = - if let Some(enumm) = extract_enum(enum_name, &enum_from_name, &f)? { + if let Some(enumm) = extract_enum(enum_name, &enum_from_name, &f) { let name = enumm.name.clone(); enums.push(enumm); Some(name) @@ -363,17 +363,16 @@ fn extract_enum<'a>( enum_name: impl Iterator, enum_from_name: &BTreeMap<&str, &svd::EnumeratedValues>, field: &FieldInfo, -) -> anyhow::Result> { - let mut enum_read = None; - let mut enum_write = None; - let mut enum_readwrite = None; +) -> Option { + let mut r = Vec::new(); + let mut w = Vec::new(); for e in &field.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 + "unknown enum to derive from ({} -> {derived_from})", + field.name ); continue; }; @@ -383,79 +382,51 @@ fn extract_enum<'a>( }; 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, + match usage { + svd::Usage::Read => r.extend_from_slice(&e.values), + svd::Usage::Write => w.extend_from_slice(&e.values), + svd::Usage::ReadWrite => { + r.extend_from_slice(&e.values); + w.extend_from_slice(&e.values); + } }; - - 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 variants = if !r.is_empty() || !w.is_empty() { + fn value_to_kv(v: &EnumeratedValue) -> Option<(u64, &EnumeratedValue)> { + v.value.map(|value| (value, v)) } - }; - - 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() - } - }; - Ok(Some(ProtoEnum { - name: enum_name.cloned().collect(), - bit_size: field.bit_range.width, - variants, - })) + let r: BTreeMap<_, _> = r.iter().filter_map(value_to_kv).collect(); + let w: BTreeMap<_, _> = w.iter().filter_map(value_to_kv).collect(); + let mut enum_values: Vec<_> = r.keys().chain(w.keys()).collect(); + enum_values.sort(); + enum_values.dedup(); + + enum_values + .into_iter() + .map(|v| match (r.get(&v), w.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() } else { - Ok(None) - } + return None; + }; + + Some(ProtoEnum { + name: enum_name.cloned().collect(), + bit_size: field.bit_range.width, + variants, + }) } /// Create a map of all enums by name. From 41c5424f965179f9e57245dca76dc0b38291bb25 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Wed, 27 May 2026 21:17:41 +0200 Subject: [PATCH 3/3] No more right shift :) --- src/svd2ir.rs | 84 ++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 180cd94a..fe702f17 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -53,53 +53,55 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() for block in &blocks { for r in &block.registers { - if let svd::RegisterCluster::Register(r) = r { - if r.derived_from.is_some() { + let svd::RegisterCluster::Register(r) = r else { + continue; + }; + + if r.derived_from.is_some() { + continue; + } + + let Some(fields) = &r.fields else { + continue; + }; + + 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; } - 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 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); - } - - let enum_name = fieldset_name.iter().chain(std::iter::once(&field_name)); - let enumm = - if let Some(enumm) = extract_enum(enum_name, &enum_from_name, &f) { - let name = enumm.name.clone(); - enums.push(enumm); - Some(name) - } else { - None - }; - - out_fields.push((f.clone(), enumm)); - } + let mut field_name = replace_suffix(&f.name, ""); - fieldsets.push(ProtoFieldset { - name: fieldset_name.clone(), - description: r.description.clone(), - bit_size: r.properties.size.unwrap_or(32), - fields: out_fields, - }); + 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); + } + + let enum_name = fieldset_name.iter().chain(std::iter::once(&field_name)); + let enumm = if let Some(enumm) = extract_enum(enum_name, &enum_from_name, &f) { + let name = enumm.name.clone(); + enums.push(enumm); + 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, + }); } }