Skip to content

Commit 961702e

Browse files
bors[bot]burrbull
andauthored
Merge #631
631: use svd-parser Index r=Emilgardis a=burrbull Should fix #528 #610 #623 #625 Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents e7a4558 + 8442c9f commit 961702e

File tree

8 files changed

+238
-405
lines changed

8 files changed

+238
-405
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
rust: [stable]
5151

5252
# All vendor files we want to test on stable
53-
vendor: [Atmel, Freescale, Fujitsu, Holtek, Microchip, Nordic, Nuvoton, NXP, RISC-V, SiliconLabs, Spansion, STMicro, Toshiba]
53+
vendor: [Atmel, Freescale, Fujitsu, GD32, Holtek, Microchip, Nordic, Nuvoton, NXP, RISC-V, SiliconLabs, Spansion, STMicro, Toshiba]
5454

5555
# Options are all, none, strict and const
5656
options: [all, none]

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
- use `svd_parser::expand::Index` for derive
1011
- Generated enum names now consider `name` field in `enumeratedValues`
1112
- Use constant case for structure names; internal rearrangements for
1213
case conversation traits

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ serde_yaml = { version = "0.8.23", optional = true }
5858

5959
[dependencies.svd-parser]
6060
features = ["expand"]
61-
version = "0.13.3"
61+
version = "0.14.0"
6262

6363
[dependencies.svd-rs]
6464
features = ["serde"]
65-
version = "0.13.2"
65+
version = "0.14.0"
6666

6767
[dependencies.syn]
6868
version = "1.0"

ci/script.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,10 @@ main() {
414414
test_svd S6E2CC
415415
;;
416416

417+
GD32)
418+
#test_svd_for_target cortex-m https://q.geek.nz/files/gd32f130.svd.patched
419+
;;
420+
417421
Holtek)
418422
# OK
419423
test_svd ht32f125x

src/generate/device.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::generate::{interrupt, peripheral};
1515

1616
/// Whole device generation
1717
pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<TokenStream> {
18+
let index = svd_parser::expand::Index::create(d);
1819
let mut out = TokenStream::new();
1920

2021
let commit_info = {
@@ -217,7 +218,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
217218
}
218219

219220
debug!("Rendering peripheral {}", p.name);
220-
match peripheral::render(p, &d.peripherals, config) {
221+
match peripheral::render(p, &index, config) {
221222
Ok(periph) => out.extend(periph),
222223
Err(e) => {
223224
let descrip = p.description.as_deref().unwrap_or("No description");

src/generate/peripheral.rs

Lines changed: 104 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use std::borrow::Cow;
22
use std::cmp::Ordering;
3-
use std::collections::HashMap;
3+
use svd_parser::expand::{derive_cluster, derive_peripheral, derive_register, BlockPath, Index};
44

55
use crate::svd::{
6-
array::names, Cluster, ClusterInfo, DeriveFrom, DimElement, Peripheral, Register,
7-
RegisterCluster,
6+
array::names, Cluster, ClusterInfo, DimElement, Peripheral, Register, RegisterCluster,
87
};
98
use log::{debug, trace, warn};
109
use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream};
@@ -19,41 +18,32 @@ use anyhow::{anyhow, bail, Context, Result};
1918

2019
use crate::generate::register;
2120

22-
pub fn render(
23-
p_original: &Peripheral,
24-
all_peripherals: &[Peripheral],
25-
config: &Config,
26-
) -> Result<TokenStream> {
21+
pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result<TokenStream> {
2722
let mut out = TokenStream::new();
2823

29-
let p_derivedfrom = p_original
30-
.derived_from
31-
.as_ref()
32-
.and_then(|s| all_peripherals.iter().find(|x| x.name == *s));
33-
34-
let p_merged = p_derivedfrom.map(|ancestor| p_original.derive_from(ancestor));
35-
let p = p_merged.as_ref().unwrap_or(p_original);
36-
37-
if let (Some(df), None) = (p_original.derived_from.as_ref(), &p_derivedfrom) {
38-
return Err(anyhow!(
39-
"Couldn't find derivedFrom original: {} for {}, skipping",
40-
df,
41-
p_original.name
42-
));
24+
let mut p = p_original.clone();
25+
let mut path = None;
26+
let dpath = p.derived_from.take();
27+
if let Some(dpath) = dpath {
28+
path = derive_peripheral(&mut p, &dpath, index)?;
4329
}
4430

45-
let name = util::name_of(p, config.ignore_groups);
31+
let name = util::name_of(&p, config.ignore_groups);
4632
let span = Span::call_site();
4733
let name_str = name.to_sanitized_constant_case();
4834
let name_constant_case = Ident::new(&name_str, span);
4935
let address = util::hex(p.base_address as u64);
5036
let description = util::respace(p.description.as_ref().unwrap_or(&p.name));
5137

5238
let name_snake_case = Ident::new(&name.to_sanitized_snake_case(), span);
53-
let (derive_regs, base) = if let (Some(df), None) = (p_derivedfrom, &p_original.registers) {
54-
(true, Ident::new(&df.name.to_sanitized_snake_case(), span))
39+
let (derive_regs, base, path) = if let Some(path) = path {
40+
(
41+
true,
42+
Ident::new(&path.peripheral.to_sanitized_snake_case(), span),
43+
path,
44+
)
5545
} else {
56-
(false, name_snake_case.clone())
46+
(false, name_snake_case.clone(), BlockPath::new(&p.name))
5747
};
5848

5949
let feature_attribute = if config.feature_group && p.group_name.is_some() {
@@ -63,7 +53,7 @@ pub fn render(
6353
quote! {}
6454
};
6555

66-
match p_original {
56+
match &p {
6757
Peripheral::Array(p, dim) => {
6858
let names: Vec<Cow<str>> = names(p, dim).map(|n| n.into()).collect();
6959
let names_str = names.iter().map(|n| n.to_sanitized_constant_case());
@@ -166,68 +156,63 @@ pub fn render(
166156
return Ok(out);
167157
}
168158

169-
// erc: *E*ither *R*egister or *C*luster
170-
let ercs_in = p.registers.as_ref().map(|x| x.as_ref()).unwrap_or(&[][..]);
171-
172-
// make a pass to expand derived registers and clusters. Ideally, for the most minimal
173-
// code size, we'd do some analysis to figure out if we can 100% reuse the
174-
// code that we're deriving from. For the sake of proving the concept, we're
175-
// just going to emit a second copy of the accessor code. It'll probably
176-
// get inlined by the compiler anyway, right? :-)
177-
178-
// Build a map so that we can look up registers within this peripheral
179-
let mut erc_map = HashMap::new();
180-
for erc in ercs_in {
181-
erc_map.insert(util::erc_name(erc), erc);
182-
}
159+
let description = util::escape_brackets(
160+
util::respace(p.description.as_ref().unwrap_or(&name.as_ref().to_owned())).as_ref(),
161+
);
183162

184163
// Build up an alternate erc list by expanding any derived registers/clusters
185-
let mut ercs = Vec::with_capacity(ercs_in.len());
186-
for erc in ercs_in {
187-
ercs.push(derive_register_cluster(erc, &erc_map)?.into_owned());
188-
}
189-
190-
// And revise registers, clusters and ercs to refer to our expanded versions
191-
let registers: &[&Register] = &util::only_registers(&ercs)[..];
192-
let clusters = util::only_clusters(&ercs);
164+
// erc: *E*ither *R*egister or *C*luster
165+
let mut ercs = p.registers.take().unwrap_or_default();
193166

194167
// No `struct RegisterBlock` can be generated
195-
if registers.is_empty() && clusters.is_empty() {
168+
if ercs.is_empty() {
196169
// Drop the definition of the peripheral
197170
return Ok(TokenStream::new());
198171
}
199172

200-
// Push any register or cluster blocks into the output
201-
debug!(
202-
"Pushing {} register or cluster blocks into output",
203-
ercs.len()
204-
);
173+
debug!("Pushing cluster & register information into output");
174+
// Push all cluster & register related information into the peripheral module
175+
205176
let mut mod_items = TokenStream::new();
206-
mod_items.extend(register_or_cluster_block(&ercs, None, config)?);
207177

208-
debug!("Pushing cluster information into output");
209-
// Push all cluster related information into the peripheral module
210-
for c in &clusters {
211-
trace!("Cluster: {}", c.name);
212-
mod_items.extend(cluster_block(c, p, all_peripherals, config)?);
213-
}
178+
for erc in &mut ercs {
179+
match erc {
180+
RegisterCluster::Cluster(c) => {
181+
trace!("Cluster: {}", c.name);
182+
let mut cpath = None;
183+
let dpath = c.derived_from.take();
184+
if let Some(dpath) = dpath {
185+
cpath = derive_cluster(c, &dpath, &path, index)?;
186+
}
187+
let cpath = cpath.unwrap_or_else(|| path.new_cluster(&c.name));
188+
mod_items.extend(cluster_block(c, &cpath, index, config)?);
189+
}
214190

215-
debug!("Pushing register information into output");
216-
// Push all register related information into the peripheral module
217-
for reg in registers {
218-
trace!("Register: {}", reg.name);
219-
match register::render(reg, registers, p, all_peripherals, config) {
220-
Ok(rendered_reg) => mod_items.extend(rendered_reg),
221-
Err(e) => {
222-
let res: Result<TokenStream> = Err(e);
223-
return handle_reg_error("Error rendering register", *reg, res);
191+
RegisterCluster::Register(reg) => {
192+
trace!("Register: {}", reg.name);
193+
let mut rpath = None;
194+
let dpath = reg.derived_from.take();
195+
if let Some(dpath) = dpath {
196+
rpath = derive_register(reg, &dpath, &path, index)?;
197+
}
198+
let rpath = rpath.unwrap_or_else(|| path.new_register(&reg.name));
199+
match register::render(reg, &rpath, index, config) {
200+
Ok(rendered_reg) => mod_items.extend(rendered_reg),
201+
Err(e) => {
202+
let res: Result<TokenStream> = Err(e);
203+
return handle_reg_error("Error rendering register", reg, res);
204+
}
205+
};
224206
}
225-
};
207+
}
226208
}
227209

228-
let description = util::escape_brackets(
229-
util::respace(p.description.as_ref().unwrap_or(&name.as_ref().to_owned())).as_ref(),
210+
// Push any register or cluster blocks into the output
211+
debug!(
212+
"Pushing {} register or cluster blocks into output",
213+
ercs.len()
230214
);
215+
let reg_block = register_or_cluster_block(&ercs, None, config)?;
231216

232217
let open = Punct::new('{', Spacing::Alone);
233218
let close = Punct::new('}', Spacing::Alone);
@@ -238,47 +223,14 @@ pub fn render(
238223
pub mod #name_snake_case #open
239224
});
240225

226+
out.extend(reg_block);
241227
out.extend(mod_items);
242228

243229
close.to_tokens(&mut out);
244230

245-
Ok(out)
246-
}
247-
248-
fn derive_register_cluster<'a>(
249-
erc: &'a RegisterCluster,
250-
erc_map: &'a HashMap<&'a String, &'a RegisterCluster>,
251-
) -> Result<Cow<'a, RegisterCluster>> {
252-
Ok(if let Some(derived) = util::erc_derived_from(erc) {
253-
let ancestor = erc_map.get(derived).ok_or_else(|| {
254-
anyhow!(
255-
"register/cluster {} derivedFrom missing register/cluster {}",
256-
util::erc_name(erc),
257-
derived
258-
)
259-
})?;
231+
p.registers = Some(ercs);
260232

261-
let ancestor = derive_register_cluster(ancestor, erc_map)?;
262-
263-
use RegisterCluster::*;
264-
match (erc, ancestor.as_ref()) {
265-
(Register(reg), Register(other_reg)) => {
266-
Cow::Owned(Register(reg.derive_from(other_reg)))
267-
}
268-
(Cluster(cluster), Cluster(other_cluster)) => {
269-
Cow::Owned(Cluster(cluster.derive_from(other_cluster)))
270-
}
271-
_ => {
272-
return Err(anyhow!(
273-
"{} can't be derived from {}",
274-
util::erc_name(erc),
275-
util::erc_name(&ancestor)
276-
));
277-
}
278-
}
279-
} else {
280-
Cow::Borrowed(erc)
281-
})
233+
Ok(out)
282234
}
283235

284236
#[derive(Clone, Debug)]
@@ -956,16 +908,48 @@ fn expand_register(
956908

957909
/// Render a Cluster Block into `TokenStream`
958910
fn cluster_block(
959-
c: &Cluster,
960-
p: &Peripheral,
961-
all_peripherals: &[Peripheral],
911+
c: &mut Cluster,
912+
path: &BlockPath,
913+
index: &Index,
962914
config: &Config,
963915
) -> Result<TokenStream> {
964916
let mut mod_items = TokenStream::new();
965917

966-
// name_snake_case needs to take into account array type.
967-
let description =
968-
util::escape_brackets(util::respace(c.description.as_ref().unwrap_or(&c.name)).as_ref());
918+
for rc in &mut c.children {
919+
match rc {
920+
// Generate the sub-cluster blocks.
921+
RegisterCluster::Cluster(c) => {
922+
let mut cpath = None;
923+
let dpath = c.derived_from.take();
924+
if let Some(dpath) = dpath {
925+
cpath = derive_cluster(c, &dpath, path, index)?;
926+
}
927+
let cpath = cpath.unwrap_or_else(|| path.new_cluster(&c.name));
928+
mod_items.extend(cluster_block(c, &cpath, index, config)?);
929+
}
930+
931+
// Generate definition for each of the registers.
932+
RegisterCluster::Register(reg) => {
933+
let mut rpath = None;
934+
let dpath = reg.derived_from.take();
935+
if let Some(dpath) = dpath {
936+
rpath = derive_register(reg, &dpath, path, index)?;
937+
}
938+
let rpath = rpath.unwrap_or_else(|| path.new_register(&reg.name));
939+
match register::render(reg, &rpath, index, config) {
940+
Ok(rendered_reg) => mod_items.extend(rendered_reg),
941+
Err(e) => {
942+
let res: Result<TokenStream> = Err(e);
943+
return handle_reg_error(
944+
"Error generating register definition for a register cluster",
945+
reg,
946+
res,
947+
);
948+
}
949+
};
950+
}
951+
}
952+
}
969953

970954
// Generate the register block.
971955
let mod_name = util::replace_suffix(
@@ -975,31 +959,14 @@ fn cluster_block(
975959
},
976960
"",
977961
);
978-
let name_snake_case = Ident::new(&mod_name.to_sanitized_snake_case(), Span::call_site());
979962

980963
let reg_block = register_or_cluster_block(&c.children, Some(&mod_name), config)?;
981964

982-
// Generate definition for each of the registers.
983-
let registers = util::only_registers(&c.children);
984-
for reg in &registers {
985-
match register::render(reg, &registers, p, all_peripherals, config) {
986-
Ok(rendered_reg) => mod_items.extend(rendered_reg),
987-
Err(e) => {
988-
let res: Result<TokenStream> = Err(e);
989-
return handle_reg_error(
990-
"Error generating register definition for a register cluster",
991-
*reg,
992-
res,
993-
);
994-
}
995-
};
996-
}
965+
// name_snake_case needs to take into account array type.
966+
let description =
967+
util::escape_brackets(util::respace(c.description.as_ref().unwrap_or(&c.name)).as_ref());
997968

998-
// Generate the sub-cluster blocks.
999-
let clusters = util::only_clusters(&c.children);
1000-
for c in &clusters {
1001-
mod_items.extend(cluster_block(c, p, all_peripherals, config)?);
1002-
}
969+
let name_snake_case = Ident::new(&mod_name.to_sanitized_snake_case(), Span::call_site());
1003970

1004971
Ok(quote! {
1005972
#reg_block

0 commit comments

Comments
 (0)