Skip to content

Commit 4f94476

Browse files
committed
Support loading names with placeholders
1 parent 4224c73 commit 4f94476

1 file changed

Lines changed: 204 additions & 102 deletions

File tree

src/svd2ir.rs

Lines changed: 204 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clap::ValueEnum;
33
use log::*;
44
use std::collections::{BTreeMap, BTreeSet};
55
use std::ops::Deref;
6-
use svd_parser::svd::{self, PeripheralInfo};
6+
use svd_parser::svd::{self, MaybeArray, PeripheralInfo};
77

88
use crate::{ir::*, transform};
99

@@ -36,6 +36,107 @@ pub enum NamespaceMode {
3636
BlockWithRegsVals,
3737
}
3838

39+
fn remove_placeholder(str: &str) -> String {
40+
str.replace("[%s]", "").replace("%s", "")
41+
}
42+
43+
fn names<T, F>(array: &MaybeArray<T>, f: F) -> ExpandedMaybeArray
44+
where
45+
F: Fn(&T) -> &str,
46+
{
47+
fn is_numeric(str: &String) -> bool {
48+
str.chars().all(|v| v.is_numeric())
49+
}
50+
51+
fn replace_placeholder(str: &str, replacement: &str) -> String {
52+
str.replace("%s", replacement)
53+
}
54+
55+
fn as_array_name<'a>(
56+
r: &str,
57+
mut dim_element: impl Iterator<Item = &'a String>,
58+
) -> Option<&str> {
59+
if let Some(array) = r.strip_suffix("[%s]") {
60+
Some(array)
61+
} else if let Some(missed_array) = r.strip_suffix("%s") {
62+
// If all dimensions are numeric, the element is an IR
63+
// array because accessing with a number offset makes
64+
// sense.
65+
if dim_element.all(is_numeric) {
66+
Some(missed_array)
67+
} else {
68+
None
69+
}
70+
} else {
71+
None
72+
}
73+
}
74+
75+
match array {
76+
MaybeArray::Single(r) => ExpandedMaybeArray::Single(f(r).to_string()),
77+
MaybeArray::Array(r, dim_element) => {
78+
if let Some(array_name) = as_array_name(f(r), dim_element.dim_index.iter().flatten()) {
79+
ExpandedMaybeArray::Array {
80+
name: array_name.to_string(),
81+
array: Array::Regular(RegularArray {
82+
len: dim_element.dim,
83+
stride: dim_element.dim_increment,
84+
}),
85+
}
86+
} else {
87+
let offsets = (0..).step_by(dim_element.dim_increment as _);
88+
89+
let values = offsets
90+
.zip(
91+
dim_element
92+
.dim_index
93+
.iter()
94+
.flat_map(|v| v.iter())
95+
.map(|dim| replace_placeholder(f(r), dim)),
96+
)
97+
.collect();
98+
99+
ExpandedMaybeArray::Many(values)
100+
}
101+
}
102+
}
103+
}
104+
105+
#[derive(Clone)]
106+
enum ExpandedMaybeArray {
107+
Single(String),
108+
Array { name: String, array: Array },
109+
Many(Vec<(u32, String)>),
110+
}
111+
112+
impl ExpandedMaybeArray {
113+
pub fn array(&self) -> Option<Array> {
114+
match self {
115+
ExpandedMaybeArray::Array { array, .. } => Some(array.clone()),
116+
_ => None,
117+
}
118+
}
119+
}
120+
121+
impl IntoIterator for ExpandedMaybeArray {
122+
type Item = (u32, String);
123+
124+
type IntoIter = std::vec::IntoIter<(u32, String)>;
125+
126+
fn into_iter(self) -> Self::IntoIter {
127+
match self {
128+
ExpandedMaybeArray::Single(s) => vec![(0, s)].into_iter(),
129+
ExpandedMaybeArray::Array { name, .. } => vec![(0, name)].into_iter(),
130+
ExpandedMaybeArray::Many(items) => items.into_iter(),
131+
}
132+
}
133+
}
134+
135+
fn fieldset_name(mut block_name: Vec<String>, reg_name: String) -> Vec<String> {
136+
block_name.push(reg_name);
137+
block_name
138+
}
139+
39140
pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()> {
40141
let mut blocks = Vec::new();
41142
let pname = p.header_struct_name.clone().unwrap_or(p.name.clone());
@@ -47,10 +148,14 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
47148
);
48149

49150
let enum_from_name = enum_map(&blocks);
151+
50152
let mut fieldsets: Vec<ProtoFieldset> = Vec::new();
153+
let mut used_fieldset_names = BTreeMap::new();
154+
let mut inner_block_to_fieldset = BTreeMap::new();
155+
51156
let mut enums: Vec<ProtoEnum> = Vec::new();
52157

53-
let usable_register_clusters = blocks
158+
let usable_register_clusters: Vec<_> = blocks
54159
.iter()
55160
.flat_map(|b| std::iter::repeat(&b.name).zip(b.registers.iter()))
56161
.filter_map(|(b, r)| {
@@ -66,13 +171,27 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
66171
return None;
67172
};
68173

69-
Some((b, r.deref().clone(), fields))
70-
});
174+
let mut fs_name = fieldset_name(b.clone(), remove_placeholder(&r.name));
175+
176+
let entry = used_fieldset_names.entry(fs_name.clone()).or_insert(0);
177+
178+
if *entry != 0 {
179+
fs_name.last_mut().map(|v| *v = format!("{v}{entry}"));
180+
}
181+
182+
*entry += 1;
183+
184+
for (_, full_name) in names(r, |r| &r.name) {
185+
let full_name: Vec<_> = fieldset_name(b.clone(), full_name);
186+
inner_block_to_fieldset.insert(full_name, fs_name.clone());
187+
}
71188

72-
for (block_name, r, fields) in usable_register_clusters {
73-
let mut fieldset_name = block_name.clone();
189+
Some((fs_name, r.deref(), fields))
190+
})
191+
.collect();
192+
193+
for (fieldset_name, r, fields) in usable_register_clusters.clone() {
74194
let mut field_name_counts: BTreeMap<String, usize> = BTreeMap::new();
75-
fieldset_name.push(remove_placeholder(&r.name));
76195
fieldsets.push(ProtoFieldset {
77196
name: fieldset_name.clone(),
78197
description: r.description.clone(),
@@ -90,7 +209,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
90209
let mut enum_readwrite = None;
91210

92211
let mut field_name = remove_placeholder(&f.name);
93-
94212
let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0);
95213
*field_name_count += 1;
96214
if *field_name_count > 1 {
@@ -209,74 +327,66 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
209327
continue;
210328
}
211329

212-
let fieldset_name = if r.fields.is_some() {
213-
let mut fieldset_name = proto.name.clone();
214-
fieldset_name.push(remove_placeholder(&r.name));
215-
Some(fieldset_names.get(&fieldset_name).unwrap().clone())
216-
} else {
217-
None
218-
};
219-
220-
let array = if let svd::Register::Array(_, dim) = r {
221-
Some(Array::Regular(RegularArray {
222-
len: dim.dim,
223-
stride: dim.dim_increment,
224-
}))
225-
} else {
226-
None
227-
};
228-
229-
let access = match r.properties.access {
230-
None => Access::ReadWrite,
231-
Some(svd::Access::ReadOnly) => Access::Read,
232-
Some(svd::Access::WriteOnly) => Access::Write,
233-
Some(svd::Access::WriteOnce) => Access::Write,
234-
Some(svd::Access::ReadWrite) => Access::ReadWrite,
235-
Some(svd::Access::ReadWriteOnce) => Access::ReadWrite,
236-
};
237-
238-
let block_item = BlockItem {
239-
name: remove_placeholder(&r.name),
240-
description: r.description.clone(),
241-
array,
242-
byte_offset: r.address_offset,
243-
inner: BlockItemInner::Register(Register {
244-
access, // todo
245-
bit_size: r.properties.size.unwrap_or(32),
246-
fieldset: fieldset_name.clone(),
247-
}),
248-
};
249-
250-
block.items.push(block_item)
330+
let names = crate::svd2ir::names(&r, |r| &r.name);
331+
let array = names.array();
332+
333+
for (offset, name) in names {
334+
let fieldset_name = if r.fields.is_some() {
335+
let fieldset_full_name =
336+
fieldset_name(proto.name.clone(), name.clone());
337+
let fieldset_name =
338+
inner_block_to_fieldset.get(&fieldset_full_name).unwrap();
339+
Some(fieldset_names.get(fieldset_name).unwrap().clone())
340+
} else {
341+
None
342+
};
343+
344+
let access = match r.properties.access {
345+
None => Access::ReadWrite,
346+
Some(svd::Access::ReadOnly) => Access::Read,
347+
Some(svd::Access::WriteOnly) => Access::Write,
348+
Some(svd::Access::WriteOnce) => Access::Write,
349+
Some(svd::Access::ReadWrite) => Access::ReadWrite,
350+
Some(svd::Access::ReadWriteOnce) => Access::ReadWrite,
351+
};
352+
353+
let block_item = BlockItem {
354+
name: name,
355+
description: r.description.clone(),
356+
array: array.clone(),
357+
byte_offset: r.address_offset + offset,
358+
inner: BlockItemInner::Register(Register {
359+
access, // todo
360+
bit_size: r.properties.size.unwrap_or(32),
361+
fieldset: fieldset_name.clone(),
362+
}),
363+
};
364+
365+
block.items.push(block_item)
366+
}
251367
}
252368
svd::RegisterCluster::Cluster(c) => {
253369
if c.derived_from.is_some() {
254370
warn!("unsupported derived_from in clusters");
255371
continue;
256372
}
257373

258-
let cname = remove_placeholder(&c.name);
259-
260-
let array = if let svd::Cluster::Array(_, dim) = c {
261-
Some(Array::Regular(RegularArray {
262-
len: dim.dim,
263-
stride: dim.dim_increment,
264-
}))
265-
} else {
266-
None
267-
};
268-
269-
let mut block_name = proto.name.clone();
270-
block_name.push(remove_placeholder(&c.name));
271-
let block_name = block_names.get(&block_name).unwrap().clone();
272-
273-
block.items.push(BlockItem {
274-
name: cname.clone(),
275-
description: c.description.clone(),
276-
array,
277-
byte_offset: c.address_offset,
278-
inner: BlockItemInner::Block(BlockItemBlock { block: block_name }),
279-
});
374+
let names = names(c, |c| &c.name);
375+
let array = names.array();
376+
377+
for (offset, cname) in names {
378+
let mut block_name = proto.name.clone();
379+
block_name.push(cname.clone());
380+
let block_name = block_names.get(&block_name).unwrap().clone();
381+
382+
block.items.push(BlockItem {
383+
name: cname.clone(),
384+
description: c.description.clone(),
385+
array: array.clone(),
386+
byte_offset: c.address_offset + offset,
387+
inner: BlockItemInner::Block(BlockItemBlock { block: block_name }),
388+
});
389+
}
280390
}
281391
}
282392
}
@@ -299,37 +409,31 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
299409
warn!("unsupported derived_from in fieldset");
300410
}
301411

302-
let array = if let svd::Field::Array(_, dim) = f {
303-
Some(Array::Regular(RegularArray {
304-
len: dim.dim,
305-
stride: dim.dim_increment,
306-
}))
307-
} else {
308-
None
309-
};
412+
let names = names(f, |f| &f.name);
413+
let array = names.array();
310414

311-
let field_name = remove_placeholder(&f.name);
415+
for (offset, field_name) in names {
416+
let mut field = Field {
417+
name: field_name.clone(),
418+
description: f.description.clone(),
419+
bit_offset: BitOffset::Regular(f.bit_range.offset + offset),
420+
bit_size: f.bit_range.width,
421+
array: array.clone(),
422+
enumm: None,
423+
};
312424

313-
let mut field = Field {
314-
name: field_name.clone(),
315-
description: f.description.clone(),
316-
bit_offset: BitOffset::Regular(f.bit_range.offset),
317-
bit_size: f.bit_range.width,
318-
array,
319-
enumm: None,
320-
};
425+
if !f.enumerated_values.is_empty() {
426+
let mut enum_name = proto.name.clone();
427+
enum_name.push(field_name);
321428

322-
if !f.enumerated_values.is_empty() {
323-
let mut enum_name = proto.name.clone();
324-
enum_name.push(field_name);
429+
trace!("finding enum {:?}", enum_name);
430+
let enum_name = enum_names.get(&enum_name).unwrap().clone();
431+
trace!("found {:?}", enum_name);
432+
field.enumm = Some(enum_name.clone())
433+
}
325434

326-
trace!("finding enum {:?}", enum_name);
327-
let enum_name = enum_names.get(&enum_name).unwrap().clone();
328-
trace!("found {:?}", enum_name);
329-
field.enumm = Some(enum_name.clone())
435+
fieldset.fields.push(field)
330436
}
331-
332-
fieldset.fields.push(field)
333437
}
334438

335439
let fieldset_name = fieldset_names.get(&proto.name).unwrap().clone();
@@ -492,9 +596,11 @@ fn collect_blocks(
492596
continue;
493597
}
494598

495-
let mut block_name = block_name.clone();
496-
block_name.push(remove_placeholder(&c.name));
497-
collect_blocks(out, block_name, c.description.clone(), &c.children);
599+
for (_, block) in names(c, |c| &c.name) {
600+
let mut block_name = block_name.clone();
601+
block_name.push(block);
602+
collect_blocks(out, block_name, c.description.clone(), &c.children);
603+
}
498604
}
499605
}
500606
}
@@ -588,7 +694,3 @@ pub fn namespace_names(peripheral: &PeripheralInfo, ir: &mut IR, namespace: Name
588694
}
589695
});
590696
}
591-
592-
pub fn remove_placeholder(name: &str) -> String {
593-
name.replace("[%s]", "").replace("%s", "")
594-
}

0 commit comments

Comments
 (0)