Skip to content

Commit 65f2428

Browse files
committed
expand derived registers
This is a very basic first cut at expanding registers with derivedFrom. This commit requires rust-embedded/svd#50
1 parent f976901 commit 65f2428

File tree

1 file changed

+98
-3
lines changed

1 file changed

+98
-3
lines changed

src/generate/peripheral.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
11
use std::borrow::Cow;
2+
use std::collections::HashMap;
23

34
use either::Either;
45
use quote::{ToTokens, Tokens};
5-
use svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register};
6+
use svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register, RegisterInfo};
67
use syn::{self, Ident};
78

89
use errors::*;
910
use util::{self, ToSanitizedSnakeCase, ToSanitizedUpperCase, BITS_PER_BYTE};
1011

1112
use generate::register;
1213

14+
// This is a clone of the helper function from https://github.com/japaric/svd/pull/49
15+
// and can go away once that is resolved
16+
fn derive_peripheral(p: &Peripheral, other: &Peripheral) -> Peripheral {
17+
let mut derived = p.clone();
18+
if derived.group_name.is_none() {
19+
derived.group_name = other.group_name.clone();
20+
}
21+
if derived.description.is_none() {
22+
derived.description = other.description.clone();
23+
}
24+
if derived.registers.is_none() {
25+
derived.registers = other.registers.clone();
26+
}
27+
if derived.interrupt.is_empty() {
28+
derived.interrupt = other.interrupt.clone();
29+
}
30+
derived
31+
}
32+
1333
pub fn render(
1434
p_original: &Peripheral,
1535
all_peripherals: &[Peripheral],
@@ -21,7 +41,7 @@ pub fn render(
2141
all_peripherals.iter().find(|x| x.name == *s)
2242
});
2343

24-
let p_merged = p_derivedfrom.map(|x| p_original.derive_from(x));
44+
let p_merged = p_derivedfrom.map(|ancestor| derive_peripheral(p_original, ancestor));
2545
let p = p_merged.as_ref().unwrap_or(p_original);
2646

2747
if p_original.derived_from.is_some() && p_derivedfrom.is_none() {
@@ -73,9 +93,84 @@ pub fn render(
7393

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

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

0 commit comments

Comments
 (0)