Skip to content
Merged

Html #848

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct Config {
pub ident_formats_theme: Option<IdentFormatsTheme>,
pub field_names_for_enums: bool,
pub base_address_shift: u64,
pub html_url: Option<url::Url>,
}

#[allow(clippy::upper_case_acronyms)]
Expand Down
150 changes: 71 additions & 79 deletions src/generate/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -80,6 +81,60 @@ 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,
p_ty: &Ident,
doc_alias: Option<TokenStream>,
address: LitInt| {
out.extend(quote! {
#[doc = #description]
#phtml
#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 _);
Expand All @@ -97,46 +152,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),*))]};
Expand All @@ -159,45 +182,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.
Expand Down
43 changes: 33 additions & 10 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ pub fn render(
return Err(anyhow!("Incorrect access of register {}", register.name));
};

let rpath = path.new_register(&register.name);
let mut alias_doc = format!(
"{name} ({accs}) register accessor: {description}{}{}",
api_docs(
Expand All @@ -116,6 +117,9 @@ pub fn render(
register.properties.reset_value.is_some(),
&mod_ty,
false,
&register,
&rpath,
config,
)?,
read_action_docs(access.can_read(), register.read_action),
);
Expand All @@ -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(&register.name),
index,
config,
)?;
let mod_items = render_register_mod(register, access, &rpath, index, config)?;

out.extend(quote! {
#[doc = #description]
Expand Down Expand Up @@ -170,6 +168,9 @@ fn api_docs(
can_reset: bool,
module: &Ident,
inmodule: bool,
register: &Register,
rpath: &RegisterPath,
config: &Config,
) -> Result<String, std::fmt::Error> {
fn method(s: &str) -> String {
format!("[`{s}`](crate::Reg::{s})")
Expand Down Expand Up @@ -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) = &register {
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<TokenStream> {
Expand Down Expand Up @@ -312,7 +335,7 @@ pub fn render_register_mod(
access,
properties,
&mut mod_items,
path,
rpath,
index,
config,
)?;
Expand Down Expand Up @@ -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),
);

Expand Down
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down