Skip to content

Commit bb884ab

Browse files
authored
Merge pull request #118 from stm32-rs/errors
improve derive for registers (breaking)
2 parents 2b1a9a1 + 953f914 commit bb884ab

File tree

4 files changed

+238
-72
lines changed

4 files changed

+238
-72
lines changed

src/patch/device.rs

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,23 @@
11
use anyhow::{anyhow, Context};
22
use svd_parser::svd::{Device, Peripheral, PeripheralInfo};
3-
use yaml_rust::yaml::Hash;
3+
use yaml_rust::{yaml::Hash, Yaml};
44

5+
use std::collections::HashSet;
56
use std::{fs::File, io::Read, path::Path};
67

8+
use super::iterators::{MatchIter, Matched};
79
use super::modify_register_properties;
810
use super::peripheral::PeripheralExt;
911
use super::yaml_ext::{AsType, GetVal};
1012
use super::{abspath, matchname, PatchResult, VAL_LVL};
1113
use super::{make_address_block, make_address_blocks, make_cpu, make_interrupt, make_peripheral};
1214

13-
pub struct PerIter<'a, 'b> {
14-
it: std::slice::IterMut<'a, Peripheral>,
15-
spec: &'b str,
16-
check_derived: bool,
17-
}
18-
19-
impl<'a, 'b> Iterator for PerIter<'a, 'b> {
20-
type Item = &'a mut Peripheral;
21-
fn next(&mut self) -> Option<Self::Item> {
22-
self.it.by_ref().find(|next| {
23-
matchname(&next.name, self.spec) && !(self.check_derived && next.derived_from.is_some())
24-
})
25-
}
26-
}
15+
pub type PerMatchIterMut<'a, 'b> = MatchIter<'b, std::slice::IterMut<'a, Peripheral>>;
2716

2817
/// Collecting methods for processing device contents
2918
pub trait DeviceExt {
3019
/// Iterates over all peripherals that match pspec
31-
fn iter_peripherals<'a, 'b>(
32-
&'a mut self,
33-
spec: &'b str,
34-
check_derived: bool,
35-
) -> PerIter<'a, 'b>;
20+
fn iter_peripherals<'a, 'b>(&'a mut self, spec: &'b str) -> PerMatchIterMut<'a, 'b>;
3621

3722
/// Work through a device, handling all peripherals
3823
fn process(&mut self, device: &Hash, update_fields: bool) -> PatchResult;
@@ -54,7 +39,7 @@ pub trait DeviceExt {
5439

5540
/// Remove registers from pname and mark it as derivedFrom pderive.
5641
/// Update all derivedFrom referencing pname
57-
fn derive_peripheral(&mut self, pname: &str, pderive: &str) -> PatchResult;
42+
fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml) -> PatchResult;
5843

5944
/// Move registers from pold to pnew.
6045
/// Update all derivedFrom referencing pold
@@ -73,17 +58,8 @@ pub trait DeviceExt {
7358
}
7459

7560
impl DeviceExt for Device {
76-
fn iter_peripherals<'a, 'b>(
77-
&'a mut self,
78-
spec: &'b str,
79-
check_derived: bool,
80-
) -> PerIter<'a, 'b> {
81-
// check_derived=True
82-
PerIter {
83-
spec,
84-
check_derived,
85-
it: self.peripherals.iter_mut(),
86-
}
61+
fn iter_peripherals<'a, 'b>(&'a mut self, spec: &'b str) -> PerMatchIterMut<'a, 'b> {
62+
self.peripherals.iter_mut().matched(spec)
8763
}
8864

8965
fn process(&mut self, device: &Hash, update_fields: bool) -> PatchResult {
@@ -163,9 +139,8 @@ impl DeviceExt for Device {
163139
// Handle any derived peripherals
164140
for (pname, pderive) in device.hash_iter("_derive") {
165141
let pname = pname.str()?;
166-
let pderive = pderive.str()?;
167142
self.derive_peripheral(pname, pderive)
168-
.with_context(|| format!("Deriving peripheral `{}` from `{}`", pname, pderive))?;
143+
.with_context(|| format!("Deriving peripheral `{}` from `{:?}`", pname, pderive))?;
169144
}
170145

171146
// Handle any rebased peripherals
@@ -246,7 +221,10 @@ impl DeviceExt for Device {
246221
}
247222

248223
fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash) -> PatchResult {
249-
for ptag in self.iter_peripherals(pspec, true) {
224+
let mut modified = HashSet::new();
225+
for ptag in self.iter_peripherals(pspec) {
226+
modified.insert(ptag.name.clone());
227+
250228
ptag.modify_from(make_peripheral(pmod, true)?, VAL_LVL)?;
251229
if let Some(ints) = pmod.get_hash("interrupts")? {
252230
for (iname, val) in ints {
@@ -271,6 +249,17 @@ impl DeviceExt for Device {
271249
ptag.address_block = Some(make_address_blocks(abmod)?);
272250
}
273251
}
252+
// If this peripheral has derivations, update the derived
253+
// peripherals to reference the new name.
254+
if let Some(value) = pmod.get_str("name")? {
255+
for p in self.peripherals.iter_mut() {
256+
if let Some(old_name) = p.derived_from.as_mut() {
257+
if modified.contains(old_name) {
258+
*old_name = value.into();
259+
}
260+
}
261+
}
262+
}
274263
Ok(())
275264
}
276265

@@ -288,15 +277,40 @@ impl DeviceExt for Device {
288277
Ok(())
289278
}
290279

291-
fn derive_peripheral(&mut self, pname: &str, pderive: &str) -> PatchResult {
292-
self.get_peripheral(pderive)
293-
.ok_or_else(|| anyhow!("peripheral {} not found", pderive))?;
294-
self.get_mut_peripheral(pname)
295-
.ok_or_else(|| anyhow!("peripheral {} not found", pname))?
296-
.modify_from(
280+
fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml) -> PatchResult {
281+
let (pderive, info) = if let Some(pderive) = pderive.as_str() {
282+
(
283+
pderive,
297284
PeripheralInfo::builder().derived_from(Some(pderive.into())),
298-
VAL_LVL,
299-
)?;
285+
)
286+
} else if let Some(hash) = pderive.as_hash() {
287+
let pderive = hash.get_str("_from")?.ok_or_else(|| {
288+
anyhow!(
289+
"derive: source peripheral not given, please add a _from field to {}",
290+
pname
291+
)
292+
})?;
293+
(
294+
pderive,
295+
make_peripheral(hash, true)?.derived_from(Some(pderive.into())),
296+
)
297+
} else {
298+
return Err(anyhow!("derive: incorrect syntax for {}", pname));
299+
};
300+
301+
if !pderive.contains('.') {
302+
self.get_peripheral(pderive)
303+
.ok_or_else(|| anyhow!("peripheral {} not found", pderive))?;
304+
}
305+
306+
match self.get_mut_peripheral(pname) {
307+
Some(peripheral) => peripheral.modify_from(info, VAL_LVL)?,
308+
None => {
309+
let peripheral = info.name(pname.into()).build(VAL_LVL)?.single();
310+
self.peripherals.push(peripheral);
311+
}
312+
}
313+
300314
for p in self
301315
.peripherals
302316
.iter_mut()
@@ -343,7 +357,10 @@ impl DeviceExt for Device {
343357
}
344358

345359
fn clear_fields(&mut self, pspec: &str) -> PatchResult {
346-
for ptag in self.iter_peripherals(pspec, false) {
360+
for ptag in self.iter_peripherals(pspec) {
361+
if ptag.derived_from.is_some() {
362+
continue;
363+
}
347364
ptag.clear_fields("*")?;
348365
}
349366
Ok(())
@@ -357,7 +374,7 @@ impl DeviceExt for Device {
357374
) -> PatchResult {
358375
// Find all peripherals that match the spec
359376
let mut pcount = 0;
360-
for ptag in self.iter_peripherals(pspec, false) {
377+
for ptag in self.iter_peripherals(pspec) {
361378
pcount += 1;
362379
ptag.process(peripheral, update_fields)
363380
.with_context(|| format!("Processing peripheral `{}`", ptag.name))?;

src/patch/peripheral.rs

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ pub trait PeripheralExt {
4646
/// Add rname given by radd to ptag
4747
fn add_register(&mut self, rname: &str, radd: &Hash) -> PatchResult;
4848

49+
/// Remove fields from rname and mark it as derivedFrom rderive.
50+
/// Update all derivedFrom referencing rname
51+
fn derive_register(&mut self, rname: &str, rderive: &Yaml) -> PatchResult;
52+
4953
/// Add rname given by deriving from rsource to ptag
5054
fn copy_register(&mut self, rname: &str, rderive: &Hash) -> PatchResult;
5155

@@ -158,6 +162,14 @@ impl PeripheralExt for Peripheral {
158162
}
159163
}
160164

165+
// Handle any copied peripherals
166+
for (rname, rderive) in pmod.hash_iter("_copy") {
167+
let rderive = rderive.hash()?;
168+
let rname = rname.str()?;
169+
self.copy_register(rname, rderive)
170+
.with_context(|| format!("Copying register `{}`", rname))?
171+
}
172+
161173
// Handle modifications
162174
for (rspec, rmod) in pmod.hash_iter("_modify") {
163175
let rmod = rmod.hash()?;
@@ -237,25 +249,27 @@ impl PeripheralExt for Peripheral {
237249
}
238250

239251
for (rname, rderive) in pmod.hash_iter("_derive") {
240-
let rderive = rderive.hash()?;
241252
let rname = rname.str()?;
242253
match rname {
243254
"_registers" => {
244-
for (rname, val) in rderive {
255+
for (rname, val) in rderive.hash()? {
245256
let rname = rname.str()?;
246-
self.copy_register(rname, val.hash()?)
247-
.with_context(|| format!("Copying register `{}`", rname))?;
257+
self.derive_register(rname, val).with_context(|| {
258+
format!("Deriving register `{}` from `{:?}`", rname, val)
259+
})?;
248260
}
249261
}
250-
"_interrupts" => {
262+
"_clusters" => {
251263
return Err(anyhow!(
252-
"deriving interrupts not implemented yet: {}",
264+
"deriving clusters is not implemented yet: {}",
253265
rname
254266
))
255267
}
256-
_ => self
257-
.copy_register(rname, rderive)
258-
.with_context(|| format!("Copying register `{}`", rname))?,
268+
_ => {
269+
self.derive_register(rname, rderive).with_context(|| {
270+
format!("Deriving register `{}` from `{:?}`", rname, rderive)
271+
})?;
272+
}
259273
}
260274
}
261275

@@ -343,6 +357,48 @@ impl PeripheralExt for Peripheral {
343357
Ok(())
344358
}
345359

360+
fn derive_register(&mut self, rname: &str, rderive: &Yaml) -> PatchResult {
361+
let (rderive, info) = if let Some(rderive) = rderive.as_str() {
362+
(
363+
rderive,
364+
RegisterInfo::builder().derived_from(Some(rderive.into())),
365+
)
366+
} else if let Some(hash) = rderive.as_hash() {
367+
let rderive = hash.get_str("_from")?.ok_or_else(|| {
368+
anyhow!(
369+
"derive: source register not given, please add a _from field to {}",
370+
rname
371+
)
372+
})?;
373+
(
374+
rderive,
375+
make_register(hash)?.derived_from(Some(rderive.into())),
376+
)
377+
} else {
378+
return Err(anyhow!("derive: incorrect syntax for {}", rname));
379+
};
380+
381+
self.get_register(rderive)
382+
.ok_or_else(|| anyhow!("register {} not found", rderive))?;
383+
384+
match self.get_mut_register(rname) {
385+
Some(register) => register.modify_from(info, VAL_LVL)?,
386+
None => {
387+
let register = info.name(rname.into()).build(VAL_LVL)?.single();
388+
self.registers
389+
.get_or_insert_with(Default::default)
390+
.push(RegisterCluster::Register(register));
391+
}
392+
}
393+
for r in self
394+
.registers_mut()
395+
.filter(|r| r.derived_from.as_deref() == Some(rname))
396+
{
397+
r.derived_from = Some(rderive.into());
398+
}
399+
Ok(())
400+
}
401+
346402
fn copy_register(&mut self, rname: &str, rderive: &Hash) -> PatchResult {
347403
let srcname = rderive.get_str("_from")?.ok_or_else(|| {
348404
anyhow!(
@@ -668,6 +724,9 @@ impl PeripheralExt for Peripheral {
668724

669725
fn clear_fields(&mut self, rspec: &str) -> PatchResult {
670726
for rtag in self.iter_registers(rspec) {
727+
if rtag.derived_from.is_some() {
728+
continue;
729+
}
671730
rtag.clear_field("*")?;
672731
}
673732
Ok(())

src/patch/register.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub trait RegisterExt {
9090

9191
impl RegisterExt for Register {
9292
fn process(&mut self, rmod: &Hash, pname: &str, update_fields: bool) -> PatchResult {
93+
if self.derived_from.is_some() {
94+
return Ok(());
95+
}
9396
// Handle deletions
9497
for fspec in rmod.str_vec_iter("_delete") {
9598
self.delete_field(fspec)
@@ -272,6 +275,9 @@ impl RegisterExt for Register {
272275

273276
fn clear_field(&mut self, fspec: &str) -> PatchResult {
274277
for ftag in self.iter_fields(fspec) {
278+
if ftag.derived_from.is_some() {
279+
continue;
280+
}
275281
ftag.enumerated_values = Vec::new();
276282
ftag.write_constraint = None;
277283
}

0 commit comments

Comments
 (0)