Skip to content

Commit dbffe2a

Browse files
committed
Merge commit 'cb134d2b48f8eec34dd752f2283e20694386cb69' into derived
2 parents 36a661e + cb134d2 commit dbffe2a

File tree

1 file changed

+100
-14
lines changed

1 file changed

+100
-14
lines changed

src/generate/peripheral.rs

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::borrow::Cow;
22
use std::cmp::Ordering;
3+
use std::collections::HashMap;
34

45
use quote::{ToTokens, Tokens};
5-
use crate::svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register, RegisterCluster};
6+
use crate::svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register, RegisterCluster, RegisterInfo};
67
use syn::{self, Ident};
78
use log::warn;
89

@@ -12,26 +13,36 @@ use crate::util::{self, ToSanitizedSnakeCase, ToSanitizedUpperCase, BITS_PER_BYT
1213
use crate::generate::register;
1314

1415
pub fn render(
15-
p: &Peripheral,
16+
p_original: &Peripheral,
1617
all_peripherals: &[Peripheral],
1718
defaults: &Defaults,
1819
nightly: bool,
1920
) -> Result<Vec<Tokens>> {
2021
let mut out = vec![];
2122

23+
let p_derivedfrom = p_original.derived_from.as_ref().and_then(|s| {
24+
all_peripherals.iter().find(|x| x.name == *s)
25+
});
26+
27+
let p_merged = p_derivedfrom.map(|ancestor| p_original.derive_from(ancestor));
28+
let p = p_merged.as_ref().unwrap_or(p_original);
29+
30+
if p_original.derived_from.is_some() && p_derivedfrom.is_none() {
31+
eprintln!("Couldn't find derivedFrom original: {} for {}, skipping",
32+
p_original.derived_from.as_ref().unwrap(), p_original.name);
33+
return Ok(out);
34+
}
35+
2236
let name_pc = Ident::new(&*p.name.to_sanitized_upper_case());
2337
let address = util::hex(p.base_address);
24-
let description =
25-
util::escape_brackets(util::respace(p.description.as_ref().unwrap_or(&p.name)).as_ref());
38+
let description = util::respace(p.description.as_ref().unwrap_or(&p.name));
39+
let derive_regs = p_derivedfrom.is_some() && p_original.registers.is_none();
2640

2741
let name_sc = Ident::new(&*p.name.to_sanitized_snake_case());
28-
let (base, derived) = if let Some(base) = p.derived_from.as_ref() {
29-
// TODO Verify that base exists
30-
// TODO We don't handle inheritance style `derivedFrom`, we should raise
31-
// an error in that case
32-
(Ident::new(&*base.to_sanitized_snake_case()), true)
42+
let base = if derive_regs {
43+
Ident::new(&*p_derivedfrom.unwrap().name.to_sanitized_snake_case())
3344
} else {
34-
(name_sc.clone(), false)
45+
name_sc.clone()
3546
};
3647

3748
// Insert the peripheral structure
@@ -57,17 +68,92 @@ pub fn render(
5768
}
5869
});
5970

60-
// Derived peripherals do not require re-implementation, and will instead
61-
// use a single definition of the non-derived version
62-
if derived {
71+
// Derived peripherals may not require re-implementation, and will instead
72+
// use a single definition of the non-derived version.
73+
if derive_regs {
6374
return Ok(out);
6475
}
6576

6677
// erc: *E*ither *R*egister or *C*luster
6778
let ercs = p.registers.as_ref().map(|x| x.as_ref()).unwrap_or(&[][..]);
68-
6979
let registers: &[&Register] = &util::only_registers(&ercs)[..];
80+
81+
// make a pass to expand derived registers. Ideally, for the most minimal
82+
// code size, we'd do some analysis to figure out if we can 100% reuse the
83+
// code that we're deriving from. For the sake of proving the concept, we're
84+
// just going to emit a second copy of the accessor code. It'll probably
85+
// get inlined by the compiler anyway, right? :-)
86+
87+
// Build a map so that we can look up registers within this peripheral
88+
let mut reg_map = HashMap::new();
89+
for r in registers {
90+
reg_map.insert(&r.name, r.clone());
91+
}
92+
93+
// Compute the effective, derived version of a register given the definition
94+
// with the derived_from property on it (`info`) and its `ancestor`
95+
fn derive_reg_info(info: &RegisterInfo, ancestor: &RegisterInfo) -> RegisterInfo {
96+
let mut derived = info.clone();
97+
98+
if derived.size.is_none() {
99+
derived.size = ancestor.size.clone();
100+
}
101+
if derived.access.is_none() {
102+
derived.access = ancestor.access.clone();
103+
}
104+
if derived.reset_value.is_none() {
105+
derived.reset_value = ancestor.reset_value.clone();
106+
}
107+
if derived.reset_mask.is_none() {
108+
derived.reset_mask = ancestor.reset_mask.clone();
109+
}
110+
if derived.fields.is_none() {
111+
derived.fields = ancestor.fields.clone();
112+
}
113+
if derived.write_constraint.is_none() {
114+
derived.write_constraint = ancestor.write_constraint.clone();
115+
}
116+
117+
derived
118+
}
119+
120+
// Build up an alternate erc list by expanding any derived registers
121+
let mut alt_erc :Vec<RegisterCluster> = registers.iter().filter_map(|r| {
122+
match r.derived_from {
123+
Some(ref derived) => {
124+
let ancestor = match reg_map.get(derived) {
125+
Some(r) => r,
126+
None => {
127+
eprintln!("register {} derivedFrom missing register {}", r.name, derived);
128+
return None
129+
}
130+
};
131+
132+
let d = match **ancestor {
133+
Register::Array(ref info, ref array_info) => {
134+
Some(RegisterCluster::Register(Register::Array(derive_reg_info(*r, info), array_info.clone())))
135+
}
136+
Register::Single(ref info) => {
137+
Some(RegisterCluster::Register(Register::Single(derive_reg_info(*r, info))))
138+
}
139+
};
140+
141+
d
142+
}
143+
None => Some(RegisterCluster::Register((*r).clone())),
144+
}
145+
}).collect();
146+
147+
// Now add the clusters to our alternate erc list
148+
let clusters = util::only_clusters(ercs);
149+
for cluster in &clusters {
150+
alt_erc.push(RegisterCluster::Cluster((*cluster).clone()));
151+
}
152+
153+
// And revise registers, clusters and ercs to refer to our expanded versions
154+
let registers: &[&Register] = &util::only_registers(&alt_erc)[..];
70155
let clusters = util::only_clusters(ercs);
156+
let ercs = &alt_erc;
71157

72158
// No `struct RegisterBlock` can be generated
73159
if registers.is_empty() && clusters.is_empty() {

0 commit comments

Comments
 (0)