Skip to content

Commit 660f3dd

Browse files
authored
Merge pull request #886 from rust-embedded/settings
inline Settings into Config
2 parents 74eee32 + 8776231 commit 660f3dd

File tree

9 files changed

+103
-45
lines changed

9 files changed

+103
-45
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
- Add `crate_path` setting
11+
- Inline `Settings` into `Config`, add `settings_file`
1012
- Fix MSP430 PAC inner attribute generation when used with the `-m` switch.
1113

1214
## [v0.34.0] - 2024-11-05

src/config.rs

+57-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
use anyhow::{bail, Result};
2+
use proc_macro2::Span;
23
use std::{
34
collections::HashMap,
45
ops::{Deref, DerefMut},
56
path::{Path, PathBuf},
7+
str::FromStr,
68
};
9+
use syn::{punctuated::Punctuated, Ident};
10+
11+
use crate::util::path_segment;
712

813
#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))]
914
#[derive(Clone, PartialEq, Eq, Debug, Default)]
@@ -35,9 +40,10 @@ pub struct Config {
3540
pub ident_formats_theme: Option<IdentFormatsTheme>,
3641
pub field_names_for_enums: bool,
3742
pub base_address_shift: u64,
38-
pub html_url: Option<url::Url>,
3943
/// Path to YAML file with chip-specific settings
40-
pub settings: Option<PathBuf>,
44+
pub settings_file: Option<PathBuf>,
45+
/// Chip-specific settings
46+
pub settings: Settings,
4147
}
4248

4349
#[allow(clippy::upper_case_acronyms)]
@@ -320,8 +326,57 @@ pub enum IdentFormatsTheme {
320326
#[non_exhaustive]
321327
/// Chip-specific settings
322328
pub struct Settings {
329+
/// Path to chip HTML generated by svdtools
330+
pub html_url: Option<url::Url>,
331+
pub crate_path: Option<CratePath>,
323332
/// RISC-V specific settings
324333
pub riscv_config: Option<riscv::RiscvConfig>,
325334
}
326335

336+
impl Settings {
337+
pub fn update_from(&mut self, source: Self) {
338+
if source.html_url.is_some() {
339+
self.html_url = source.html_url;
340+
}
341+
if source.crate_path.is_some() {
342+
self.crate_path = source.crate_path;
343+
}
344+
if source.riscv_config.is_some() {
345+
self.riscv_config = source.riscv_config;
346+
}
347+
}
348+
}
349+
350+
#[derive(Clone, PartialEq, Eq, Debug)]
351+
pub struct CratePath(pub syn::Path);
352+
353+
impl Default for CratePath {
354+
fn default() -> Self {
355+
let mut segments = Punctuated::new();
356+
segments.push(path_segment(Ident::new("crate", Span::call_site())));
357+
Self(syn::Path {
358+
leading_colon: None,
359+
segments,
360+
})
361+
}
362+
}
363+
364+
#[cfg(feature = "serde")]
365+
impl<'de> serde::Deserialize<'de> for CratePath {
366+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
367+
where
368+
D: serde::Deserializer<'de>,
369+
{
370+
let s = String::deserialize(deserializer)?;
371+
Ok(Self::from_str(&s).unwrap())
372+
}
373+
}
374+
375+
impl FromStr for CratePath {
376+
type Err = syn::Error;
377+
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
378+
syn::parse_str(&s).map(Self)
379+
}
380+
}
381+
327382
pub mod riscv;

src/generate/device.rs

+3-24
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,6 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
2828
}
2929
};
3030

31-
let settings = match config.settings.as_ref() {
32-
#[cfg(feature = "yaml")]
33-
Some(settings) => {
34-
let file = std::fs::read_to_string(settings).context("could not read settings file")?;
35-
Some(serde_yaml::from_str(&file).context("could not parse settings file")?)
36-
}
37-
#[cfg(not(feature = "yaml"))]
38-
Some(_) => {
39-
return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature"));
40-
}
41-
None => None,
42-
};
43-
4431
// make_mod option explicitly disables inner attributes.
4532
if config.target == Target::Msp430 && !config.make_mod {
4633
out.extend(quote! {
@@ -203,7 +190,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
203190

204191
match config.target {
205192
Target::RISCV => {
206-
if settings.is_none() {
193+
if config.settings.riscv_config.is_none() {
207194
warn!("No settings file provided for RISC-V target. Using legacy interrupts rendering");
208195
warn!("Please, consider migrating your PAC to riscv 0.12.0 or later");
209196
out.extend(interrupt::render(
@@ -214,12 +201,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
214201
)?);
215202
} else {
216203
debug!("Rendering RISC-V specific code");
217-
out.extend(riscv::render(
218-
&d.peripherals,
219-
device_x,
220-
settings.as_ref().unwrap(),
221-
config,
222-
)?);
204+
out.extend(riscv::render(&d.peripherals, device_x, config)?);
223205
}
224206
}
225207
_ => {
@@ -241,10 +223,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
241223
// Core peripherals are handled above
242224
continue;
243225
}
244-
if config.target == Target::RISCV
245-
&& settings.is_some()
246-
&& riscv::is_riscv_peripheral(p, settings.as_ref().unwrap())
247-
{
226+
if config.target == Target::RISCV && riscv::is_riscv_peripheral(p, &config.settings) {
248227
// RISC-V specific peripherals are handled above
249228
continue;
250229
}

src/generate/peripheral.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
8181
}
8282
};
8383

84-
let phtml = config.html_url.as_ref().map(|url| {
84+
let phtml = config.settings.html_url.as_ref().map(|url| {
8585
let doc = format!("See peripheral [structure]({url}#{})", &path.peripheral);
8686
quote!(#[doc = ""] #[doc = #doc])
8787
});

src/generate/register.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ fn api_docs(
210210

211211
doc.push_str("See [API](https://docs.rs/svd2rust/#read--modify--write-api).");
212212

213-
if let Some(url) = config.html_url.as_ref() {
213+
if let Some(url) = config.settings.html_url.as_ref() {
214214
let first_idx = if let Register::Array(_, dim) = &register {
215215
dim.indexes().next()
216216
} else {

src/generate/riscv.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub fn is_riscv_peripheral(p: &Peripheral, s: &Settings) -> bool {
2020
pub fn render(
2121
peripherals: &[Peripheral],
2222
device_x: &mut String,
23-
settings: &Settings,
2423
config: &Config,
2524
) -> Result<TokenStream> {
2625
let mut mod_items = TokenStream::new();
@@ -30,7 +29,7 @@ pub fn render(
3029
.as_ref()
3130
.map(|feature| quote!(#[cfg_attr(feature = #feature, derive(defmt::Format))]));
3231

33-
if let Some(c) = settings.riscv_config.as_ref() {
32+
if let Some(c) = config.settings.riscv_config.as_ref() {
3433
if !c.core_interrupts.is_empty() {
3534
debug!("Rendering target-specific core interrupts");
3635
writeln!(device_x, "/* Core interrupt sources and trap handlers */")?;
@@ -216,7 +215,7 @@ pub fn render(
216215
}
217216

218217
let mut riscv_peripherals = TokenStream::new();
219-
if let Some(c) = &settings.riscv_config {
218+
if let Some(c) = config.settings.riscv_config.as_ref() {
220219
let harts = match c.harts.is_empty() {
221220
true => vec![],
222221
false => c

src/lib.rs

+16
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,22 @@ pub fn generate(input: &str, config: &Config) -> Result<Generation> {
628628
use std::fmt::Write;
629629

630630
let mut config = config.clone();
631+
632+
match config.settings_file.as_ref() {
633+
#[cfg(feature = "yaml")]
634+
Some(settings) => {
635+
let file = std::fs::read_to_string(settings).context("could not read settings file")?;
636+
config
637+
.settings
638+
.update_from(serde_yaml::from_str(&file).context("could not parse settings file")?)
639+
}
640+
#[cfg(not(feature = "yaml"))]
641+
Some(_) => {
642+
return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature"));
643+
}
644+
None => {}
645+
};
646+
631647
let mut ident_formats = match config.ident_formats_theme {
632648
Some(IdentFormatsTheme::Legacy) => IdentFormats::legacy_theme(),
633649
_ => IdentFormats::default_theme(),

src/main.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn run() -> Result<()> {
101101
.value_name("TOML_FILE"),
102102
)
103103
.arg(
104-
Arg::new("settings")
104+
Arg::new("settings_file")
105105
.long("settings")
106106
.help("Target-specific settings YAML file")
107107
.action(ArgAction::Set)
@@ -276,14 +276,6 @@ Allowed cases are `unchanged` (''), `pascal` ('p'), `constant` ('c') and `snake`
276276
Useful for soft-cores where the peripheral address range isn't necessarily fixed.
277277
Ignore this option if you are not building your own FPGA based soft-cores."),
278278
)
279-
.arg(
280-
Arg::new("html_url")
281-
.long("html-url")
282-
.alias("html_url")
283-
.help("Path to chip HTML generated by svdtools")
284-
.action(ArgAction::Set)
285-
.value_name("URL"),
286-
)
287279
.arg(
288280
Arg::new("log_level")
289281
.long("log")
@@ -330,6 +322,21 @@ Ignore this option if you are not building your own FPGA based soft-cores."),
330322
}
331323
}
332324

325+
match config.settings_file.as_ref() {
326+
#[cfg(feature = "yaml")]
327+
Some(settings) => {
328+
let file = std::fs::read_to_string(settings).context("could not read settings file")?;
329+
config
330+
.settings
331+
.update_from(serde_yaml::from_str(&file).context("could not parse settings file")?)
332+
}
333+
#[cfg(not(feature = "yaml"))]
334+
Some(_) => {
335+
return Err(anyhow::anyhow!("Support for yaml config files is not available because svd2rust was compiled without the yaml feature"));
336+
}
337+
None => {}
338+
};
339+
333340
if let Some(file) = config.input.as_ref() {
334341
config.source_type = SourceType::from_path(file)
335342
}

src/util.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -293,18 +293,18 @@ pub fn block_path_to_ty(
293293
config: &Config,
294294
span: Span,
295295
) -> TypePath {
296-
let mut segments = Punctuated::new();
297-
segments.push(path_segment(Ident::new("crate", span)));
298-
segments.push(path_segment(ident(
296+
let mut path = config.settings.crate_path.clone().unwrap_or_default().0;
297+
path.segments.push(path_segment(ident(
299298
&bpath.peripheral,
300299
config,
301300
"peripheral_mod",
302301
span,
303302
)));
304303
for ps in &bpath.path {
305-
segments.push(path_segment(ident(ps, config, "cluster_mod", span)));
304+
path.segments
305+
.push(path_segment(ident(ps, config, "cluster_mod", span)));
306306
}
307-
type_path(segments)
307+
TypePath { qself: None, path }
308308
}
309309

310310
pub fn register_path_to_ty(

0 commit comments

Comments
 (0)