Skip to content

Commit 7a02a17

Browse files
authored
Merge pull request #130 from stm32-rs/arrays
add/modify arrays (rust)
2 parents ca2b585 + aef9baa commit 7a02a17

File tree

5 files changed

+158
-77
lines changed

5 files changed

+158
-77
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ edition = "2021"
2727
clap = { version = "3.2", features = ["derive", "cargo"] }
2828
serde = { version = "1.0", features = ["derive"] }
2929
quick-xml = { version = "0.25", features = ["serialize"] }
30-
svd-rs = { version = "0.14.0", features = ["serde", "derive-from"] }
31-
svd-parser = { version = "0.14.0", features = ["expand"] }
30+
svd-rs = { version = "0.14.1", features = ["serde", "derive-from"] }
31+
svd-parser = { version = "0.14.1", features = ["expand"] }
3232
svd-encoder = "0.14.1"
3333
yaml-rust = "0.4"
3434
# serde_yaml 0.9.x looks broken

src/patch/device.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use std::collections::HashSet;
66
use std::{fs::File, io::Read, path::Path};
77

88
use super::iterators::{MatchIter, Matched};
9-
use super::modify_register_properties;
109
use super::peripheral::PeripheralExt;
1110
use super::yaml_ext::{AsType, GetVal};
1211
use super::{abspath, matchname, PatchResult, VAL_LVL};
1312
use super::{make_address_block, make_address_blocks, make_cpu, make_interrupt, make_peripheral};
13+
use super::{make_dim_element, modify_dim_element, modify_register_properties};
1414

1515
pub type PerMatchIterMut<'a, 'b> = MatchIter<'b, std::slice::IterMut<'a, Peripheral>>;
1616

@@ -219,31 +219,37 @@ impl DeviceExt for Device {
219219

220220
fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash) -> PatchResult {
221221
let mut modified = HashSet::new();
222-
for ptag in self.iter_peripherals(pspec) {
223-
modified.insert(ptag.name.clone());
224-
225-
ptag.modify_from(make_peripheral(pmod, true)?, VAL_LVL)?;
226-
if let Some(ints) = pmod.get_hash("interrupts")? {
227-
for (iname, val) in ints {
228-
let iname = iname.str()?;
229-
let int = make_interrupt(val.hash()?)?;
230-
for i in &mut ptag.interrupt {
231-
if i.name == iname {
232-
i.modify_from(int, VAL_LVL)?;
233-
break;
222+
let ptags = self.iter_peripherals(pspec).collect::<Vec<_>>();
223+
if !ptags.is_empty() {
224+
let peripheral_builder = make_peripheral(pmod, true)?;
225+
let dim = make_dim_element(pmod)?;
226+
for ptag in ptags {
227+
modified.insert(ptag.name.clone());
228+
229+
modify_dim_element(ptag, &dim)?;
230+
ptag.modify_from(peripheral_builder.clone(), VAL_LVL)?;
231+
if let Some(ints) = pmod.get_hash("interrupts")? {
232+
for (iname, val) in ints {
233+
let iname = iname.str()?;
234+
let int = make_interrupt(val.hash()?)?;
235+
for i in &mut ptag.interrupt {
236+
if i.name == iname {
237+
i.modify_from(int, VAL_LVL)?;
238+
break;
239+
}
234240
}
235241
}
236242
}
237-
}
238-
if let Some(abmod) = pmod.get_hash("addressBlock").ok().flatten() {
239-
let v = &mut ptag.address_block;
240-
let ab = make_address_block(abmod)?;
241-
match v.as_deref_mut() {
242-
Some([adb]) => adb.modify_from(ab, VAL_LVL)?,
243-
_ => *v = Some(vec![ab.build(VAL_LVL)?]),
243+
if let Some(abmod) = pmod.get_hash("addressBlock").ok().flatten() {
244+
let v = &mut ptag.address_block;
245+
let ab = make_address_block(abmod)?;
246+
match v.as_deref_mut() {
247+
Some([adb]) => adb.modify_from(ab, VAL_LVL)?,
248+
_ => *v = Some(vec![ab.build(VAL_LVL)?]),
249+
}
250+
} else if let Some(abmod) = pmod.get_vec("addressBlocks").ok().flatten() {
251+
ptag.address_block = Some(make_address_blocks(abmod)?);
244252
}
245-
} else if let Some(abmod) = pmod.get_vec("addressBlocks").ok().flatten() {
246-
ptag.address_block = Some(make_address_blocks(abmod)?);
247253
}
248254
}
249255
// If this peripheral has derivations, update the derived
@@ -265,12 +271,16 @@ impl DeviceExt for Device {
265271
return Err(anyhow!("device already has a peripheral {pname}"));
266272
}
267273

268-
self.peripherals.push(
269-
make_peripheral(padd, false)?
270-
.name(pname.to_string())
271-
.build(VAL_LVL)?
272-
.single(),
273-
);
274+
let pnew = make_peripheral(padd, false)?
275+
.name(pname.to_string())
276+
.build(VAL_LVL)?;
277+
let pnew = if let Some(dim) = make_dim_element(padd)? {
278+
pnew.array(dim.build(VAL_LVL)?)
279+
} else {
280+
pnew.single()
281+
};
282+
283+
self.peripherals.push(pnew);
274284
Ok(())
275285
}
276286

src/patch/mod.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use svd_parser::svd::{
1111
PeripheralInfo, PeripheralInfoBuilder, RegisterCluster, RegisterInfo, RegisterInfoBuilder,
1212
RegisterProperties, Usage, ValidateLevel,
1313
};
14+
use svd_parser::SVDError::DimIndexParse;
15+
use svd_rs::{DimElement, DimElementBuilder, MaybeArray};
1416
use yaml_rust::{yaml::Hash, Yaml, YamlLoader};
1517

16-
use anyhow::{anyhow, Context, Result};
18+
use anyhow::{anyhow, Context, Ok, Result};
1719
pub type PatchResult = anyhow::Result<()>;
1820

1921
mod device;
@@ -304,6 +306,55 @@ fn make_address_block(h: &Hash) -> Result<AddressBlockBuilder> {
304306
Ok(ab)
305307
}
306308

309+
fn make_dim_element(h: &Hash) -> Result<Option<DimElementBuilder>> {
310+
let mut d = DimElement::builder()
311+
.dim_index(if let Some(y) = h.get(&"dimIndex".to_yaml()) {
312+
match y {
313+
Yaml::String(text) => Some(DimElement::parse_indexes(text).ok_or(DimIndexParse)?),
314+
Yaml::Array(a) => {
315+
let mut v = Vec::new();
316+
for s in a {
317+
v.push(s.as_str().ok_or(DimIndexParse)?.to_string());
318+
}
319+
Some(v)
320+
}
321+
_ => return Err(DimIndexParse).map_err(Into::into),
322+
}
323+
} else {
324+
None
325+
})
326+
.dim_name(h.get_string("dimName")?)
327+
// TODO
328+
.dim_array_index(None);
329+
if let Some(dim) = h.get_u32("dim")? {
330+
d = d.dim(dim)
331+
}
332+
if let Some(dim_increment) = h.get_u32("dimIncrement")? {
333+
d = d.dim_increment(dim_increment)
334+
}
335+
Ok(if d == DimElement::builder() {
336+
None
337+
} else {
338+
Some(d)
339+
})
340+
}
341+
342+
fn modify_dim_element<T: Clone>(
343+
tag: &mut MaybeArray<T>,
344+
dim: &Option<DimElementBuilder>,
345+
) -> PatchResult {
346+
if let Some(dim) = dim.as_ref() {
347+
match tag {
348+
MaybeArray::Array(_, array_info) => array_info.modify_from(dim.clone(), VAL_LVL)?,
349+
MaybeArray::Single(info) => {
350+
let array_info = dim.clone().build(VAL_LVL)?;
351+
*tag = MaybeArray::Array(info.clone(), array_info);
352+
}
353+
}
354+
}
355+
Ok(())
356+
}
357+
307358
fn make_field(fadd: &Hash) -> Result<FieldInfoBuilder> {
308359
let mut fnew = FieldInfo::builder()
309360
.description(fadd.get_string("description")?)

src/patch/peripheral.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use yaml_rust::{yaml::Hash, Yaml};
77
use super::iterators::{MatchIter, Matched};
88
use super::register::{RegisterExt, RegisterInfoExt};
99
use super::yaml_ext::{AsType, GetVal, ToYaml};
10-
use super::{check_offsets, matchname, matchsubspec, spec_ind, PatchResult, VAL_LVL};
10+
use super::{
11+
check_offsets, make_dim_element, matchname, matchsubspec, modify_dim_element, spec_ind,
12+
PatchResult, VAL_LVL,
13+
};
1114
use super::{make_cluster, make_interrupt, make_register};
1215

1316
use svd::registercluster::{AllRegistersIterMut, ClusterIterMut};
@@ -328,10 +331,16 @@ impl PeripheralExt for Peripheral {
328331
}
329332

330333
fn modify_register(&mut self, rspec: &str, rmod: &Hash) -> PatchResult {
331-
for rtag in self.iter_registers(rspec) {
332-
rtag.modify_from(make_register(rmod)?, VAL_LVL)?;
333-
if let Some("") = rmod.get_str("access")? {
334-
rtag.properties.access = None;
334+
let rtags = self.iter_registers(rspec).collect::<Vec<_>>();
335+
if !rtags.is_empty() {
336+
let register_builder = make_register(rmod)?;
337+
let dim = make_dim_element(rmod)?;
338+
for rtag in rtags {
339+
modify_dim_element(rtag, &dim)?;
340+
rtag.modify_from(register_builder.clone(), VAL_LVL)?;
341+
if let Some("") = rmod.get_str("access")? {
342+
rtag.properties.access = None;
343+
}
335344
}
336345
}
337346
Ok(())
@@ -346,12 +355,14 @@ impl PeripheralExt for Peripheral {
346355
}
347356
self.registers
348357
.get_or_insert_with(Default::default)
349-
.push(RegisterCluster::Register(
350-
make_register(radd)?
351-
.name(rname.into())
352-
.build(VAL_LVL)?
353-
.single(),
354-
));
358+
.push(RegisterCluster::Register({
359+
let reg = make_register(radd)?.name(rname.into()).build(VAL_LVL)?;
360+
if let Some(dim) = make_dim_element(radd)? {
361+
reg.array(dim.build(VAL_LVL)?)
362+
} else {
363+
reg.single()
364+
}
365+
}));
355366
Ok(())
356367
}
357368

src/patch/register.rs

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use yaml_rust::{yaml::Hash, Yaml};
77

88
use super::iterators::{MatchIter, Matched};
99
use super::yaml_ext::{AsType, GetVal, ToYaml};
10-
use super::{check_offsets, matchname, spec_ind, PatchResult, VAL_LVL};
10+
use super::{
11+
check_offsets, make_dim_element, matchname, modify_dim_element, spec_ind, PatchResult, VAL_LVL,
12+
};
1113
use super::{make_derived_enumerated_values, make_ev_array, make_ev_name, make_field};
1214

1315
pub type FieldMatchIterMut<'a, 'b> = MatchIter<'b, std::slice::IterMut<'a, Field>>;
@@ -215,35 +217,41 @@ impl RegisterExt for Register {
215217
}
216218

217219
fn modify_field(&mut self, fspec: &str, fmod: &Hash) -> PatchResult {
218-
for ftag in self.iter_fields(fspec) {
219-
if let Some(value) = fmod
220-
.get(&"_write_constraint".to_yaml())
221-
.or_else(|| fmod.get(&"writeConstraint".to_yaml()))
222-
{
223-
let wc = match value {
224-
Yaml::String(s) if s == "none" => {
225-
// Completely remove the existing writeConstraint
226-
None
227-
}
228-
Yaml::String(s) if s == "enum" => {
229-
// Only allow enumerated values
230-
Some(WriteConstraint::UseEnumeratedValues(true))
231-
}
232-
Yaml::Array(a) => {
233-
// Allow a certain range
234-
Some(WriteConstraint::Range(WriteConstraintRange {
235-
min: a[0].i64()? as u64,
236-
max: a[1].i64()? as u64,
237-
}))
238-
}
239-
_ => return Err(anyhow!("Unknown writeConstraint type {value:?}")),
240-
};
241-
ftag.write_constraint = wc;
242-
}
243-
// For all other tags, just set the value
244-
ftag.modify_from(make_field(fmod)?, VAL_LVL)?;
245-
if let Some("") = fmod.get_str("access")? {
246-
ftag.access = None;
220+
let ftags = self.iter_fields(fspec).collect::<Vec<_>>();
221+
let field_builder = make_field(fmod)?;
222+
let dim = make_dim_element(fmod)?;
223+
if !ftags.is_empty() {
224+
for ftag in ftags {
225+
modify_dim_element(ftag, &dim)?;
226+
if let Some(value) = fmod
227+
.get(&"_write_constraint".to_yaml())
228+
.or_else(|| fmod.get(&"writeConstraint".to_yaml()))
229+
{
230+
let wc = match value {
231+
Yaml::String(s) if s == "none" => {
232+
// Completely remove the existing writeConstraint
233+
None
234+
}
235+
Yaml::String(s) if s == "enum" => {
236+
// Only allow enumerated values
237+
Some(WriteConstraint::UseEnumeratedValues(true))
238+
}
239+
Yaml::Array(a) => {
240+
// Allow a certain range
241+
Some(WriteConstraint::Range(WriteConstraintRange {
242+
min: a[0].i64()? as u64,
243+
max: a[1].i64()? as u64,
244+
}))
245+
}
246+
_ => return Err(anyhow!("Unknown writeConstraint type {value:?}")),
247+
};
248+
ftag.write_constraint = wc;
249+
}
250+
// For all other tags, just set the value
251+
ftag.modify_from(field_builder.clone(), VAL_LVL)?;
252+
if let Some("") = fmod.get_str("access")? {
253+
ftag.access = None;
254+
}
247255
}
248256
}
249257
Ok(())
@@ -256,11 +264,12 @@ impl RegisterExt for Register {
256264
self.name
257265
));
258266
}
259-
// TODO: add field arrays
260-
let fnew = make_field(fadd)?
261-
.name(fname.into())
262-
.build(VAL_LVL)?
263-
.single();
267+
let fnew = make_field(fadd)?.name(fname.into()).build(VAL_LVL)?;
268+
let fnew = if let Some(dim) = make_dim_element(fadd)? {
269+
fnew.array(dim.build(VAL_LVL)?)
270+
} else {
271+
fnew.single()
272+
};
264273
self.fields.get_or_insert_with(Default::default).push(fnew);
265274
Ok(())
266275
}

0 commit comments

Comments
 (0)