From e22d7842c5cab57ed4602f40a6cb5f1e0faad0c9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 9 Jul 2024 07:02:18 +0300 Subject: [PATCH] extract enums --- src/cli.rs | 27 ++++++++ src/enum_extract/mod.rs | 144 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/patch/mod.rs | 3 +- 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/enum_extract/mod.rs diff --git a/src/cli.rs b/src/cli.rs index 0db90b37..97a6c1b2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,6 +4,7 @@ use std::{fs::File, io::Write, path::PathBuf, str::FromStr}; use svdtools::{ convert::convert_cli, + enum_extract::enum_extract, html::html_cli, html::htmlcompare_cli, info, @@ -134,6 +135,16 @@ enum Command { /// Describe requested information request: String, }, + /// Makes patch file with enums extracted from SVD + ExtractEnums { + /// Path to input file + in_path: PathBuf, + /// Format of input file (XML, JSON or YAML) + #[clap(long = "input-format")] + input_format: Option, + /// Path to output file + out_path: PathBuf, + }, } impl Command { @@ -226,6 +237,22 @@ impl Command { let response = request.process(&device)?; print!("{response}") } + Self::ExtractEnums { + in_path, + input_format, + out_path, + } => { + let device = convert_cli::open_svd( + in_path, + *input_format, + convert_cli::ParserConfig::default(), + )?; + let yml = enum_extract(&device); + let mut out_str = String::new(); + let mut emitter = yaml_rust::YamlEmitter::new(&mut out_str); + emitter.dump(&yml).unwrap(); + File::create(out_path)?.write_all(out_str.as_bytes())?; + } } Ok(()) } diff --git a/src/enum_extract/mod.rs b/src/enum_extract/mod.rs new file mode 100644 index 00000000..7e3d28b6 --- /dev/null +++ b/src/enum_extract/mod.rs @@ -0,0 +1,144 @@ +use crate::patch::ToYaml; +use svd_rs::EnumeratedValues; +use yaml_rust::yaml::{self, Yaml}; + +pub trait HasEnums { + fn has_enums(&self) -> bool; +} + +impl HasEnums for svd_rs::Field { + fn has_enums(&self) -> bool { + !self.enumerated_values.is_empty() + } +} + +impl HasEnums for svd_rs::Register { + fn has_enums(&self) -> bool { + if let Some(fields) = self.fields.as_ref() { + for f in fields { + if f.has_enums() { + return true; + } + } + } + false + } +} + +impl HasEnums for svd_rs::RegisterCluster { + fn has_enums(&self) -> bool { + match self { + svd_rs::RegisterCluster::Cluster(c) => c.has_enums(), + svd_rs::RegisterCluster::Register(r) => r.has_enums(), + } + } +} + +impl HasEnums for svd_rs::Cluster { + fn has_enums(&self) -> bool { + for rc in &self.children { + if rc.has_enums() { + return true; + } + } + false + } +} + +impl HasEnums for svd_rs::Peripheral { + fn has_enums(&self) -> bool { + if let Some(regs) = self.registers.as_ref() { + for rc in regs { + if rc.has_enums() { + return true; + } + } + } + false + } +} + +fn evs_to_hash(evs: &EnumeratedValues) -> yaml::Hash { + let mut hash = yaml::Hash::with_capacity(evs.values.len()); + if let Some(n) = evs.name.as_ref() { + hash.insert("_name".to_yaml(), n.to_yaml()); + } + if let Some(d) = evs.derived_from.as_ref() { + hash.insert("_derivedFrom".to_yaml(), d.to_yaml()); + } else { + for ev in &evs.values { + let val = if let Some(val) = ev.value { + Yaml::Integer(val as _) + } else if ev.is_default() { + Yaml::Integer(-1) + } else { + panic!("EnumeratedValue without value"); + }; + hash.insert( + ev.name.to_yaml(), + Yaml::Array(vec![val, ev.description.as_deref().unwrap_or("").to_yaml()]), + ); + } + } + hash +} + +fn rc_enum_extact(regs: &[svd_rs::RegisterCluster]) -> Yaml { + let mut phash = yaml::Hash::new(); + let mut pchash = yaml::Hash::new(); + for rc in regs { + if rc.has_enums() { + match rc { + svd_rs::RegisterCluster::Cluster(c) => { + pchash.insert(c.name.to_yaml(), rc_enum_extact(&c.children)); + } + svd_rs::RegisterCluster::Register(r) => { + let mut rhash = yaml::Hash::new(); + for f in r.fields() { + if f.has_enums() { + let mut fhash = yaml::Hash::with_capacity(f.enumerated_values.len()); + for evs in &f.enumerated_values { + match evs.usage { + Some(svd_rs::Usage::Read) => { + fhash.insert( + "_read".to_yaml(), + Yaml::Hash(evs_to_hash(evs)), + ); + } + Some(svd_rs::Usage::Write) => { + fhash.insert( + "_write".to_yaml(), + Yaml::Hash(evs_to_hash(evs)), + ); + } + _ => { + assert_eq!(f.enumerated_values.len(), 1); + fhash.extend(evs_to_hash(evs)); + } + } + } + rhash.insert(f.name.to_yaml(), Yaml::Hash(fhash)); + } + } + phash.insert(r.name.to_yaml(), Yaml::Hash(rhash)); + } + } + } + } + if !pchash.is_empty() { + phash.insert("_clusters".to_yaml(), Yaml::Hash(pchash)); + } + Yaml::Hash(phash) +} + +pub fn enum_extract(device: &svd_rs::Device) -> Yaml { + let mut hash = yaml::Hash::new(); + for p in &device.peripherals { + if let Some(regs) = p.registers.as_ref() { + if p.has_enums() { + hash.insert(p.name.to_yaml(), rc_enum_extact(regs)); + } + } + } + Yaml::Hash(hash) +} diff --git a/src/lib.rs b/src/lib.rs index 78f4866c..01660cd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use std::{fs::File, path::Path, str::FromStr}; pub mod common; pub mod convert; +pub mod enum_extract; pub mod html; pub mod info; pub mod interrupts; diff --git a/src/patch/mod.rs b/src/patch/mod.rs index 558ce692..1972e8ae 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -26,7 +26,8 @@ mod iterators; mod peripheral; mod register; mod yaml_ext; -use yaml_ext::{AsType, GetVal, ToYaml}; +pub(crate) use yaml_ext::ToYaml; +use yaml_ext::{AsType, GetVal}; use crate::get_encoder_config;