Skip to content

Commit 0671417

Browse files
authored
Merge pull request #848 from rust-embedded/html
Html
2 parents 5f8950f + 68d69b6 commit 0671417

File tree

7 files changed

+117
-89
lines changed

7 files changed

+117
-89
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
- Add `html-url` option to access `svdtools html` files from docs
1011
- Move `Reg` in separate file
1112
- Use `warning` class in docs
1213
- Refactor `Accessor`

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ serde_json = { version = "1.0.85", optional = true }
5757
serde_yaml = { version = "0.9.11", optional = true }
5858
regex = "1.10.0"
5959
html-escape = "0.2"
60+
url = { version = "2.5", features = ["serde"] }
6061

6162
[dependencies.svd-parser]
6263
features = ["expand"]

src/config.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct Config {
3535
pub ident_formats_theme: Option<IdentFormatsTheme>,
3636
pub field_names_for_enums: bool,
3737
pub base_address_shift: u64,
38+
pub html_url: Option<url::Url>,
3839
}
3940

4041
#[allow(clippy::upper_case_acronyms)]

src/generate/peripheral.rs

+71-79
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::fmt;
55
use svd_parser::expand::{
66
derive_cluster, derive_peripheral, derive_register, BlockPath, Index, RegisterPath,
77
};
8+
use syn::LitInt;
89

910
use crate::config::Config;
1011
use crate::svd::{
@@ -80,6 +81,60 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
8081
}
8182
};
8283

84+
let phtml = config.html_url.as_ref().map(|url| {
85+
let doc = format!("See peripheral [structure]({url}#{})", &path.peripheral);
86+
quote!(#[doc = ""] #[doc = #doc])
87+
});
88+
89+
let per_to_tokens = |out: &mut TokenStream,
90+
feature_attribute: &TokenStream,
91+
description: &str,
92+
p_ty: &Ident,
93+
doc_alias: Option<TokenStream>,
94+
address: LitInt| {
95+
out.extend(quote! {
96+
#[doc = #description]
97+
#phtml
98+
#doc_alias
99+
#feature_attribute
100+
pub struct #p_ty { _marker: PhantomData<*const ()> }
101+
102+
#feature_attribute
103+
unsafe impl Send for #p_ty {}
104+
105+
#feature_attribute
106+
impl #p_ty {
107+
///Pointer to the register block
108+
pub const PTR: *const #base::RegisterBlock = #address as *const _;
109+
110+
///Return the pointer to the register block
111+
#[inline(always)]
112+
pub const fn ptr() -> *const #base::RegisterBlock {
113+
Self::PTR
114+
}
115+
116+
#steal_fn
117+
}
118+
119+
#feature_attribute
120+
impl Deref for #p_ty {
121+
type Target = #base::RegisterBlock;
122+
123+
#[inline(always)]
124+
fn deref(&self) -> &Self::Target {
125+
unsafe { &*Self::PTR }
126+
}
127+
}
128+
129+
#feature_attribute
130+
impl core::fmt::Debug for #p_ty {
131+
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
132+
f.debug_struct(#name_str).finish()
133+
}
134+
}
135+
});
136+
};
137+
83138
match &p {
84139
Peripheral::Array(p, dim) => {
85140
let mut feature_names = Vec::with_capacity(dim.dim as _);
@@ -97,46 +152,14 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
97152
feature_attribute_n.extend(quote! { #[cfg(feature = #p_feature)] })
98153
};
99154
// Insert the peripherals structure
100-
out.extend(quote! {
101-
#[doc = #description]
102-
#doc_alias
103-
#feature_attribute_n
104-
pub struct #p_ty { _marker: PhantomData<*const ()> }
105-
106-
#feature_attribute_n
107-
unsafe impl Send for #p_ty {}
108-
109-
#feature_attribute_n
110-
impl #p_ty {
111-
///Pointer to the register block
112-
pub const PTR: *const #base::RegisterBlock = #address as *const _;
113-
114-
///Return the pointer to the register block
115-
#[inline(always)]
116-
pub const fn ptr() -> *const #base::RegisterBlock {
117-
Self::PTR
118-
}
119-
120-
#steal_fn
121-
}
122-
123-
#feature_attribute_n
124-
impl Deref for #p_ty {
125-
type Target = #base::RegisterBlock;
126-
127-
#[inline(always)]
128-
fn deref(&self) -> &Self::Target {
129-
unsafe { &*Self::PTR }
130-
}
131-
}
132-
133-
#feature_attribute_n
134-
impl core::fmt::Debug for #p_ty {
135-
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
136-
f.debug_struct(#name_str).finish()
137-
}
138-
}
139-
});
155+
per_to_tokens(
156+
&mut out,
157+
&feature_attribute_n,
158+
description,
159+
&p_ty,
160+
doc_alias,
161+
address,
162+
);
140163
}
141164

142165
let feature_any_attribute = quote! {#[cfg(any(#(feature = #feature_names),*))]};
@@ -159,45 +182,14 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
159182
feature_attribute.extend(quote! { #[cfg(feature = #p_feature)] })
160183
};
161184
// Insert the peripheral structure
162-
out.extend(quote! {
163-
#[doc = #description]
164-
#feature_attribute
165-
pub struct #p_ty { _marker: PhantomData<*const ()> }
166-
167-
#feature_attribute
168-
unsafe impl Send for #p_ty {}
169-
170-
#feature_attribute
171-
impl #p_ty {
172-
///Pointer to the register block
173-
pub const PTR: *const #base::RegisterBlock = #address as *const _;
174-
175-
///Return the pointer to the register block
176-
#[inline(always)]
177-
pub const fn ptr() -> *const #base::RegisterBlock {
178-
Self::PTR
179-
}
180-
181-
#steal_fn
182-
}
183-
184-
#feature_attribute
185-
impl Deref for #p_ty {
186-
type Target = #base::RegisterBlock;
187-
188-
#[inline(always)]
189-
fn deref(&self) -> &Self::Target {
190-
unsafe { &*Self::PTR }
191-
}
192-
}
193-
194-
#feature_attribute
195-
impl core::fmt::Debug for #p_ty {
196-
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
197-
f.debug_struct(#name_str).finish()
198-
}
199-
}
200-
});
185+
per_to_tokens(
186+
&mut out,
187+
&feature_attribute,
188+
&description,
189+
&p_ty,
190+
None,
191+
address,
192+
);
201193

202194
// Derived peripherals may not require re-implementation, and will instead
203195
// use a single definition of the non-derived version.

src/generate/register.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub fn render(
108108
return Err(anyhow!("Incorrect access of register {}", register.name));
109109
};
110110

111+
let rpath = path.new_register(&register.name);
111112
let mut alias_doc = format!(
112113
"{name} ({accs}) register accessor: {description}{}{}",
113114
api_docs(
@@ -116,6 +117,9 @@ pub fn render(
116117
register.properties.reset_value.is_some(),
117118
&mod_ty,
118119
false,
120+
&register,
121+
&rpath,
122+
config,
119123
)?,
120124
read_action_docs(access.can_read(), register.read_action),
121125
);
@@ -128,13 +132,7 @@ pub fn render(
128132
#doc_alias
129133
pub type #reg_ty = crate::Reg<#mod_ty::#regspec_ty>;
130134
});
131-
let mod_items = render_register_mod(
132-
register,
133-
access,
134-
&path.new_register(&register.name),
135-
index,
136-
config,
137-
)?;
135+
let mod_items = render_register_mod(register, access, &rpath, index, config)?;
138136

139137
out.extend(quote! {
140138
#[doc = #description]
@@ -170,6 +168,9 @@ fn api_docs(
170168
can_reset: bool,
171169
module: &Ident,
172170
inmodule: bool,
171+
register: &Register,
172+
rpath: &RegisterPath,
173+
config: &Config,
173174
) -> Result<String, std::fmt::Error> {
174175
fn method(s: &str) -> String {
175176
format!("[`{s}`](crate::Reg::{s})")
@@ -211,13 +212,35 @@ fn api_docs(
211212

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

215+
if let Some(url) = config.html_url.as_ref() {
216+
let first_idx = if let Register::Array(_, dim) = &register {
217+
dim.indexes().next()
218+
} else {
219+
None
220+
};
221+
let rname = if let Some(idx) = first_idx {
222+
let idx = format!("[{idx}]");
223+
rpath.name.replace("[%s]", &idx).replace("%s", &idx)
224+
} else {
225+
rpath.name.to_string()
226+
};
227+
// TODO: support html_urls for registers in cluster
228+
if rpath.block.path.is_empty() {
229+
doc.push_str(&format!(
230+
"\n\nSee register [structure]({url}#{}:{})",
231+
rpath.peripheral(),
232+
rname
233+
));
234+
}
235+
}
236+
214237
Ok(doc)
215238
}
216239

217240
pub fn render_register_mod(
218241
register: &Register,
219242
access: Access,
220-
path: &RegisterPath,
243+
rpath: &RegisterPath,
221244
index: &Index,
222245
config: &Config,
223246
) -> Result<TokenStream> {
@@ -312,7 +335,7 @@ pub fn render_register_mod(
312335
access,
313336
properties,
314337
&mut mod_items,
315-
path,
338+
rpath,
316339
index,
317340
config,
318341
)?;
@@ -361,7 +384,7 @@ pub fn render_register_mod(
361384

362385
let doc = format!(
363386
"{description}{}{}",
364-
api_docs(can_read, can_write, can_reset, &mod_ty, true)?,
387+
api_docs(can_read, can_write, can_reset, &mod_ty, true, register, rpath, config)?,
365388
read_action_docs(access.can_read(), register.read_action),
366389
);
367390

src/main.rs

+8
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,14 @@ Allowed cases are `unchanged` (''), `pascal` ('p'), `constant` ('c') and `snake`
267267
Useful for soft-cores where the peripheral address range isn't necessarily fixed.
268268
Ignore this option if you are not building your own FPGA based soft-cores."),
269269
)
270+
.arg(
271+
Arg::new("html_url")
272+
.long("html-url")
273+
.alias("html_url")
274+
.help("Path to chip HTML generated by svdtools")
275+
.action(ArgAction::Set)
276+
.value_name("URL"),
277+
)
270278
.arg(
271279
Arg::new("log_level")
272280
.long("log")

0 commit comments

Comments
 (0)