Skip to content

Commit 9a9d61d

Browse files
committed
Support loading names with placeholders
1 parent 4224c73 commit 9a9d61d

1 file changed

Lines changed: 201 additions & 100 deletions

File tree

src/svd2ir.rs

Lines changed: 201 additions & 100 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,7 +148,11 @@ 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

53158
let usable_register_clusters = blocks
@@ -66,13 +171,26 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
66171
return None;
67172
};
68173

69-
Some((b, r.deref().clone(), fields))
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+
}
188+
189+
Some((fs_name, r.deref(), fields))
70190
});
71191

72-
for (block_name, r, fields) in usable_register_clusters {
73-
let mut fieldset_name = block_name.clone();
192+
for (fieldset_name, r, fields) in usable_register_clusters {
74193
let mut field_name_counts: BTreeMap<String, usize> = BTreeMap::new();
75-
fieldset_name.push(remove_placeholder(&r.name));
76194
fieldsets.push(ProtoFieldset {
77195
name: fieldset_name.clone(),
78196
description: r.description.clone(),
@@ -90,7 +208,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
90208
let mut enum_readwrite = None;
91209

92210
let mut field_name = remove_placeholder(&f.name);
93-
94211
let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0);
95212
*field_name_count += 1;
96213
if *field_name_count > 1 {
@@ -209,74 +326,66 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
209326
continue;
210327
}
211328

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)
329+
let names = crate::svd2ir::names(&r, |r| &r.name);
330+
let array = names.array();
331+
332+
for (offset, name) in names {
333+
let fieldset_name = if r.fields.is_some() {
334+
let fieldset_full_name =
335+
fieldset_name(proto.name.clone(), name.clone());
336+
let fieldset_name =
337+
inner_block_to_fieldset.get(&fieldset_full_name).unwrap();
338+
Some(fieldset_names.get(fieldset_name).unwrap().clone())
339+
} else {
340+
None
341+
};
342+
343+
let access = match r.properties.access {
344+
None => Access::ReadWrite,
345+
Some(svd::Access::ReadOnly) => Access::Read,
346+
Some(svd::Access::WriteOnly) => Access::Write,
347+
Some(svd::Access::WriteOnce) => Access::Write,
348+
Some(svd::Access::ReadWrite) => Access::ReadWrite,
349+
Some(svd::Access::ReadWriteOnce) => Access::ReadWrite,
350+
};
351+
352+
let block_item = BlockItem {
353+
name: name,
354+
description: r.description.clone(),
355+
array: array.clone(),
356+
byte_offset: r.address_offset + offset,
357+
inner: BlockItemInner::Register(Register {
358+
access, // todo
359+
bit_size: r.properties.size.unwrap_or(32),
360+
fieldset: fieldset_name.clone(),
361+
}),
362+
};
363+
364+
block.items.push(block_item)
365+
}
251366
}
252367
svd::RegisterCluster::Cluster(c) => {
253368
if c.derived_from.is_some() {
254369
warn!("unsupported derived_from in clusters");
255370
continue;
256371
}
257372

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-
});
373+
let names = names(c, |c| &c.name);
374+
let array = names.array();
375+
376+
for (offset, cname) in names {
377+
let mut block_name = proto.name.clone();
378+
block_name.push(cname.clone());
379+
let block_name = block_names.get(&block_name).unwrap().clone();
380+
381+
block.items.push(BlockItem {
382+
name: cname.clone(),
383+
description: c.description.clone(),
384+
array: array.clone(),
385+
byte_offset: c.address_offset + offset,
386+
inner: BlockItemInner::Block(BlockItemBlock { block: block_name }),
387+
});
388+
}
280389
}
281390
}
282391
}
@@ -299,37 +408,31 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
299408
warn!("unsupported derived_from in fieldset");
300409
}
301410

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-
};
411+
let names = names(f, |f| &f.name);
412+
let array = names.array();
310413

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

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-
};
424+
if !f.enumerated_values.is_empty() {
425+
let mut enum_name = proto.name.clone();
426+
enum_name.push(field_name);
321427

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

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())
434+
fieldset.fields.push(field)
330435
}
331-
332-
fieldset.fields.push(field)
333436
}
334437

335438
let fieldset_name = fieldset_names.get(&proto.name).unwrap().clone();
@@ -492,9 +595,11 @@ fn collect_blocks(
492595
continue;
493596
}
494597

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);
598+
for (_, block) in names(c, |c| &c.name) {
599+
let mut block_name = block_name.clone();
600+
block_name.push(block);
601+
collect_blocks(out, block_name, c.description.clone(), &c.children);
602+
}
498603
}
499604
}
500605
}
@@ -588,7 +693,3 @@ pub fn namespace_names(peripheral: &PeripheralInfo, ir: &mut IR, namespace: Name
588693
}
589694
});
590695
}
591-
592-
pub fn remove_placeholder(name: &str) -> String {
593-
name.replace("[%s]", "").replace("%s", "")
594-
}

0 commit comments

Comments
 (0)