From 4a1847c6f474cb0944263b23a91412f4d5b329ef Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 9 Jun 2024 17:09:44 +0300 Subject: [PATCH 1/2] peripheral to tokens closure --- src/generate/peripheral.rs | 144 +++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 79 deletions(-) diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index f7ea1520..23bf309e 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -5,6 +5,7 @@ use std::fmt; use svd_parser::expand::{ derive_cluster, derive_peripheral, derive_register, BlockPath, Index, RegisterPath, }; +use syn::LitInt; use crate::config::Config; use crate::svd::{ @@ -80,6 +81,54 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result } }; + let per_to_tokens = |out: &mut TokenStream, + feature_attribute: &TokenStream, + description: &str, + p_ty: &Ident, + doc_alias: Option, + address: LitInt| { + out.extend(quote! { + #[doc = #description] + #doc_alias + #feature_attribute + pub struct #p_ty { _marker: PhantomData<*const ()> } + + #feature_attribute + unsafe impl Send for #p_ty {} + + #feature_attribute + impl #p_ty { + ///Pointer to the register block + pub const PTR: *const #base::RegisterBlock = #address as *const _; + + ///Return the pointer to the register block + #[inline(always)] + pub const fn ptr() -> *const #base::RegisterBlock { + Self::PTR + } + + #steal_fn + } + + #feature_attribute + impl Deref for #p_ty { + type Target = #base::RegisterBlock; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*Self::PTR } + } + } + + #feature_attribute + impl core::fmt::Debug for #p_ty { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct(#name_str).finish() + } + } + }); + }; + match &p { Peripheral::Array(p, dim) => { let mut feature_names = Vec::with_capacity(dim.dim as _); @@ -97,46 +146,14 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result feature_attribute_n.extend(quote! { #[cfg(feature = #p_feature)] }) }; // Insert the peripherals structure - out.extend(quote! { - #[doc = #description] - #doc_alias - #feature_attribute_n - pub struct #p_ty { _marker: PhantomData<*const ()> } - - #feature_attribute_n - unsafe impl Send for #p_ty {} - - #feature_attribute_n - impl #p_ty { - ///Pointer to the register block - pub const PTR: *const #base::RegisterBlock = #address as *const _; - - ///Return the pointer to the register block - #[inline(always)] - pub const fn ptr() -> *const #base::RegisterBlock { - Self::PTR - } - - #steal_fn - } - - #feature_attribute_n - impl Deref for #p_ty { - type Target = #base::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::PTR } - } - } - - #feature_attribute_n - impl core::fmt::Debug for #p_ty { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - f.debug_struct(#name_str).finish() - } - } - }); + per_to_tokens( + &mut out, + &feature_attribute_n, + description, + &p_ty, + doc_alias, + address, + ); } let feature_any_attribute = quote! {#[cfg(any(#(feature = #feature_names),*))]}; @@ -159,45 +176,14 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result feature_attribute.extend(quote! { #[cfg(feature = #p_feature)] }) }; // Insert the peripheral structure - out.extend(quote! { - #[doc = #description] - #feature_attribute - pub struct #p_ty { _marker: PhantomData<*const ()> } - - #feature_attribute - unsafe impl Send for #p_ty {} - - #feature_attribute - impl #p_ty { - ///Pointer to the register block - pub const PTR: *const #base::RegisterBlock = #address as *const _; - - ///Return the pointer to the register block - #[inline(always)] - pub const fn ptr() -> *const #base::RegisterBlock { - Self::PTR - } - - #steal_fn - } - - #feature_attribute - impl Deref for #p_ty { - type Target = #base::RegisterBlock; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - unsafe { &*Self::PTR } - } - } - - #feature_attribute - impl core::fmt::Debug for #p_ty { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - f.debug_struct(#name_str).finish() - } - } - }); + per_to_tokens( + &mut out, + &feature_attribute, + &description, + &p_ty, + None, + address, + ); // Derived peripherals may not require re-implementation, and will instead // use a single definition of the non-derived version. From 68d69b637ba45072e39e24695e90c05cfbdb3c24 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 9 Jun 2024 19:03:15 +0300 Subject: [PATCH 2/2] html-url --- CHANGELOG.md | 1 + Cargo.lock | 2 ++ Cargo.toml | 1 + src/config.rs | 1 + src/generate/peripheral.rs | 6 ++++++ src/generate/register.rs | 43 +++++++++++++++++++++++++++++--------- src/main.rs | 8 +++++++ 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 503ac041..4c35b266 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Add `html-url` option to access `svdtools html` files from docs - Move `Reg` in separate file - Use `warning` class in docs - Refactor `Accessor` diff --git a/Cargo.lock b/Cargo.lock index ddd7927c..109572a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1239,6 +1239,7 @@ dependencies = [ "svd-rs", "syn 2.0.42", "thiserror", + "url", ] [[package]] @@ -1547,6 +1548,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 38fb5b1b..790bf34e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ serde_json = { version = "1.0.85", optional = true } serde_yaml = { version = "0.9.11", optional = true } regex = "1.10.0" html-escape = "0.2" +url = { version = "2.5", features = ["serde"] } [dependencies.svd-parser] features = ["expand"] diff --git a/src/config.rs b/src/config.rs index e53a2e33..79522ecd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,6 +35,7 @@ pub struct Config { pub ident_formats_theme: Option, pub field_names_for_enums: bool, pub base_address_shift: u64, + pub html_url: Option, } #[allow(clippy::upper_case_acronyms)] diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index 23bf309e..27c54bbe 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -81,6 +81,11 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result } }; + let phtml = config.html_url.as_ref().map(|url| { + let doc = format!("See peripheral [structure]({url}#{})", &path.peripheral); + quote!(#[doc = ""] #[doc = #doc]) + }); + let per_to_tokens = |out: &mut TokenStream, feature_attribute: &TokenStream, description: &str, @@ -89,6 +94,7 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result address: LitInt| { out.extend(quote! { #[doc = #description] + #phtml #doc_alias #feature_attribute pub struct #p_ty { _marker: PhantomData<*const ()> } diff --git a/src/generate/register.rs b/src/generate/register.rs index 1c1c6512..569454cb 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -108,6 +108,7 @@ pub fn render( return Err(anyhow!("Incorrect access of register {}", register.name)); }; + let rpath = path.new_register(®ister.name); let mut alias_doc = format!( "{name} ({accs}) register accessor: {description}{}{}", api_docs( @@ -116,6 +117,9 @@ pub fn render( register.properties.reset_value.is_some(), &mod_ty, false, + ®ister, + &rpath, + config, )?, read_action_docs(access.can_read(), register.read_action), ); @@ -128,13 +132,7 @@ pub fn render( #doc_alias pub type #reg_ty = crate::Reg<#mod_ty::#regspec_ty>; }); - let mod_items = render_register_mod( - register, - access, - &path.new_register(®ister.name), - index, - config, - )?; + let mod_items = render_register_mod(register, access, &rpath, index, config)?; out.extend(quote! { #[doc = #description] @@ -170,6 +168,9 @@ fn api_docs( can_reset: bool, module: &Ident, inmodule: bool, + register: &Register, + rpath: &RegisterPath, + config: &Config, ) -> Result { fn method(s: &str) -> String { format!("[`{s}`](crate::Reg::{s})") @@ -211,13 +212,35 @@ 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() { + let first_idx = if let Register::Array(_, dim) = ®ister { + dim.indexes().next() + } else { + None + }; + let rname = if let Some(idx) = first_idx { + let idx = format!("[{idx}]"); + rpath.name.replace("[%s]", &idx).replace("%s", &idx) + } else { + rpath.name.to_string() + }; + // TODO: support html_urls for registers in cluster + if rpath.block.path.is_empty() { + doc.push_str(&format!( + "\n\nSee register [structure]({url}#{}:{})", + rpath.peripheral(), + rname + )); + } + } + Ok(doc) } pub fn render_register_mod( register: &Register, access: Access, - path: &RegisterPath, + rpath: &RegisterPath, index: &Index, config: &Config, ) -> Result { @@ -312,7 +335,7 @@ pub fn render_register_mod( access, properties, &mut mod_items, - path, + rpath, index, config, )?; @@ -361,7 +384,7 @@ pub fn render_register_mod( let doc = format!( "{description}{}{}", - api_docs(can_read, can_write, can_reset, &mod_ty, true)?, + api_docs(can_read, can_write, can_reset, &mod_ty, true, register, rpath, config)?, read_action_docs(access.can_read(), register.read_action), ); diff --git a/src/main.rs b/src/main.rs index be54cbb3..aabec8f6 100755 --- a/src/main.rs +++ b/src/main.rs @@ -267,6 +267,14 @@ 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")