From dc9db51dae0d938f675648a3b6726ec1b0ae972a Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 11 Nov 2024 17:40:48 +0300 Subject: [PATCH 1/2] inline Settings into Config --- CHANGELOG.md | 1 + src/config.rs | 18 ++++++++++++++++-- src/generate/device.rs | 27 +++------------------------ src/generate/peripheral.rs | 2 +- src/generate/register.rs | 2 +- src/generate/riscv.rs | 5 ++--- src/lib.rs | 16 ++++++++++++++++ src/main.rs | 25 ++++++++++++++++--------- 8 files changed, 56 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d6f7e9..2da11759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Inline `Settings` into `Config`, add `settings_file` - Fix MSP430 PAC inner attribute generation when used with the `-m` switch. ## [v0.34.0] - 2024-11-05 diff --git a/src/config.rs b/src/config.rs index 5a48105c..b206d075 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,9 +35,10 @@ pub struct Config { pub ident_formats_theme: Option, pub field_names_for_enums: bool, pub base_address_shift: u64, - pub html_url: Option, /// Path to YAML file with chip-specific settings - pub settings: Option, + pub settings_file: Option, + /// Chip-specific settings + pub settings: Settings, } #[allow(clippy::upper_case_acronyms)] @@ -320,8 +321,21 @@ pub enum IdentFormatsTheme { #[non_exhaustive] /// Chip-specific settings pub struct Settings { + /// Path to chip HTML generated by svdtools + pub html_url: Option, /// RISC-V specific settings pub riscv_config: Option, } +impl Settings { + pub fn update_from(&mut self, source: Self) { + if source.html_url.is_some() { + self.html_url = source.html_url; + } + if source.riscv_config.is_some() { + self.riscv_config = source.riscv_config; + } + } +} + pub mod riscv; diff --git a/src/generate/device.rs b/src/generate/device.rs index 677b7e8d..d2b3ee9c 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -28,19 +28,6 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result { - let file = std::fs::read_to_string(settings).context("could not read settings file")?; - Some(serde_yaml::from_str(&file).context("could not parse settings file")?) - } - #[cfg(not(feature = "yaml"))] - Some(_) => { - return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature")); - } - None => None, - }; - // make_mod option explicitly disables inner attributes. if config.target == Target::Msp430 && !config.make_mod { out.extend(quote! { @@ -203,7 +190,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result { - if settings.is_none() { + if config.settings.riscv_config.is_none() { warn!("No settings file provided for RISC-V target. Using legacy interrupts rendering"); warn!("Please, consider migrating your PAC to riscv 0.12.0 or later"); out.extend(interrupt::render( @@ -214,12 +201,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result { @@ -241,10 +223,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result Result } }; - let phtml = config.html_url.as_ref().map(|url| { + let phtml = config.settings.html_url.as_ref().map(|url| { let doc = format!("See peripheral [structure]({url}#{})", &path.peripheral); quote!(#[doc = ""] #[doc = #doc]) }); diff --git a/src/generate/register.rs b/src/generate/register.rs index 8ab2eeb3..f5abfa65 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -210,7 +210,7 @@ fn api_docs( doc.push_str("See [API](https://docs.rs/svd2rust/#read--modify--write-api)."); - if let Some(url) = config.html_url.as_ref() { + if let Some(url) = config.settings.html_url.as_ref() { let first_idx = if let Register::Array(_, dim) = ®ister { dim.indexes().next() } else { diff --git a/src/generate/riscv.rs b/src/generate/riscv.rs index 9436ef9d..fff9e970 100644 --- a/src/generate/riscv.rs +++ b/src/generate/riscv.rs @@ -20,7 +20,6 @@ pub fn is_riscv_peripheral(p: &Peripheral, s: &Settings) -> bool { pub fn render( peripherals: &[Peripheral], device_x: &mut String, - settings: &Settings, config: &Config, ) -> Result { let mut mod_items = TokenStream::new(); @@ -30,7 +29,7 @@ pub fn render( .as_ref() .map(|feature| quote!(#[cfg_attr(feature = #feature, derive(defmt::Format))])); - if let Some(c) = settings.riscv_config.as_ref() { + if let Some(c) = config.settings.riscv_config.as_ref() { if !c.core_interrupts.is_empty() { debug!("Rendering target-specific core interrupts"); writeln!(device_x, "/* Core interrupt sources and trap handlers */")?; @@ -216,7 +215,7 @@ pub fn render( } let mut riscv_peripherals = TokenStream::new(); - if let Some(c) = &settings.riscv_config { + if let Some(c) = config.settings.riscv_config.as_ref() { let harts = match c.harts.is_empty() { true => vec![], false => c diff --git a/src/lib.rs b/src/lib.rs index edec886e..b5d5c4ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -628,6 +628,22 @@ pub fn generate(input: &str, config: &Config) -> Result { use std::fmt::Write; let mut config = config.clone(); + + match config.settings_file.as_ref() { + #[cfg(feature = "yaml")] + Some(settings) => { + let file = std::fs::read_to_string(settings).context("could not read settings file")?; + config + .settings + .update_from(serde_yaml::from_str(&file).context("could not parse settings file")?) + } + #[cfg(not(feature = "yaml"))] + Some(_) => { + return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature")); + } + None => {} + }; + let mut ident_formats = match config.ident_formats_theme { Some(IdentFormatsTheme::Legacy) => IdentFormats::legacy_theme(), _ => IdentFormats::default_theme(), diff --git a/src/main.rs b/src/main.rs index 880bb4ab..27607bfc 100755 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,7 @@ fn run() -> Result<()> { .value_name("TOML_FILE"), ) .arg( - Arg::new("settings") + Arg::new("settings_file") .long("settings") .help("Target-specific settings YAML file") .action(ArgAction::Set) @@ -276,14 +276,6 @@ Allowed cases are `unchanged` (''), `pascal` ('p'), `constant` ('c') and `snake` Useful for soft-cores where the peripheral address range isn't necessarily fixed. Ignore this option if you are not building your own FPGA based soft-cores."), ) - .arg( - Arg::new("html_url") - .long("html-url") - .alias("html_url") - .help("Path to chip HTML generated by svdtools") - .action(ArgAction::Set) - .value_name("URL"), - ) .arg( Arg::new("log_level") .long("log") @@ -330,6 +322,21 @@ Ignore this option if you are not building your own FPGA based soft-cores."), } } + match config.settings_file.as_ref() { + #[cfg(feature = "yaml")] + Some(settings) => { + let file = std::fs::read_to_string(settings).context("could not read settings file")?; + config + .settings + .update_from(serde_yaml::from_str(&file).context("could not parse settings file")?) + } + #[cfg(not(feature = "yaml"))] + Some(_) => { + return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature")); + } + None => {} + }; + if let Some(file) = config.input.as_ref() { config.source_type = SourceType::from_path(file) } From 8776231b9de4a42fe929609b9d8c9a34379a9ba9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 11 Nov 2024 18:51:21 +0300 Subject: [PATCH 2/2] crate_path --- CHANGELOG.md | 1 + src/config.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/util.rs | 10 +++++----- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da11759..ceff291e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Add `crate_path` setting - Inline `Settings` into `Config`, add `settings_file` - Fix MSP430 PAC inner attribute generation when used with the `-m` switch. diff --git a/src/config.rs b/src/config.rs index b206d075..dc4d0803 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,9 +1,14 @@ use anyhow::{bail, Result}; +use proc_macro2::Span; use std::{ collections::HashMap, ops::{Deref, DerefMut}, path::{Path, PathBuf}, + str::FromStr, }; +use syn::{punctuated::Punctuated, Ident}; + +use crate::util::path_segment; #[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))] #[derive(Clone, PartialEq, Eq, Debug, Default)] @@ -323,6 +328,7 @@ pub enum IdentFormatsTheme { pub struct Settings { /// Path to chip HTML generated by svdtools pub html_url: Option, + pub crate_path: Option, /// RISC-V specific settings pub riscv_config: Option, } @@ -332,10 +338,45 @@ impl Settings { if source.html_url.is_some() { self.html_url = source.html_url; } + if source.crate_path.is_some() { + self.crate_path = source.crate_path; + } if source.riscv_config.is_some() { self.riscv_config = source.riscv_config; } } } +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CratePath(pub syn::Path); + +impl Default for CratePath { + fn default() -> Self { + let mut segments = Punctuated::new(); + segments.push(path_segment(Ident::new("crate", Span::call_site()))); + Self(syn::Path { + leading_colon: None, + segments, + }) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for CratePath { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(Self::from_str(&s).unwrap()) + } +} + +impl FromStr for CratePath { + type Err = syn::Error; + fn from_str(s: &str) -> std::result::Result { + syn::parse_str(&s).map(Self) + } +} + pub mod riscv; diff --git a/src/util.rs b/src/util.rs index 3520bcf3..b1d7ee45 100644 --- a/src/util.rs +++ b/src/util.rs @@ -293,18 +293,18 @@ pub fn block_path_to_ty( config: &Config, span: Span, ) -> TypePath { - let mut segments = Punctuated::new(); - segments.push(path_segment(Ident::new("crate", span))); - segments.push(path_segment(ident( + let mut path = config.settings.crate_path.clone().unwrap_or_default().0; + path.segments.push(path_segment(ident( &bpath.peripheral, config, "peripheral_mod", span, ))); for ps in &bpath.path { - segments.push(path_segment(ident(ps, config, "cluster_mod", span))); + path.segments + .push(path_segment(ident(ps, config, "cluster_mod", span))); } - type_path(segments) + TypePath { qself: None, path } } pub fn register_path_to_ty(