Skip to content

Commit b4f7e2d

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

1 file changed

Lines changed: 210 additions & 100 deletions

File tree

src/svd2ir.rs

Lines changed: 210 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 inner_block_to_fieldset = BTreeMap::new();
154+
let mut used_fieldset_names = BTreeSet::new();
155+
51156
let mut enums: Vec<ProtoEnum> = Vec::new();
52157

53158
let usable_register_clusters = blocks
@@ -66,13 +171,35 @@ 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 without_placeholder = remove_placeholder(&r.name);
175+
let mut fs_name = fieldset_name(b.clone(), without_placeholder.clone());
176+
177+
let mut counter = 0;
178+
loop {
179+
if counter != 0 {
180+
let last = fs_name.last_mut().unwrap();
181+
*last = format!("{}_{}", without_placeholder, counter);
182+
}
183+
184+
counter += 1;
185+
186+
if !used_fieldset_names.contains(&fs_name) {
187+
break;
188+
}
189+
}
190+
191+
used_fieldset_names.insert(fs_name.clone());
192+
193+
for (_, full_name) in names(r, |r| &r.name) {
194+
let full_name: Vec<_> = fieldset_name(b.clone(), full_name);
195+
inner_block_to_fieldset.insert(full_name, fs_name.clone());
196+
}
197+
198+
Some((fs_name, r.deref(), fields))
70199
});
71200

72-
for (block_name, r, fields) in usable_register_clusters {
73-
let mut fieldset_name = block_name.clone();
201+
for (fieldset_name, r, fields) in usable_register_clusters {
74202
let mut field_name_counts: BTreeMap<String, usize> = BTreeMap::new();
75-
fieldset_name.push(remove_placeholder(&r.name));
76203
fieldsets.push(ProtoFieldset {
77204
name: fieldset_name.clone(),
78205
description: r.description.clone(),
@@ -90,7 +217,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
90217
let mut enum_readwrite = None;
91218

92219
let mut field_name = remove_placeholder(&f.name);
93-
94220
let field_name_count = field_name_counts.entry(field_name.clone()).or_insert(0);
95221
*field_name_count += 1;
96222
if *field_name_count > 1 {
@@ -209,74 +335,66 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
209335
continue;
210336
}
211337

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)
338+
let names = crate::svd2ir::names(&r, |r| &r.name);
339+
let array = names.array();
340+
341+
for (offset, name) in names {
342+
let fieldset_name = if r.fields.is_some() {
343+
let fieldset_full_name =
344+
fieldset_name(proto.name.clone(), name.clone());
345+
let fieldset_name =
346+
inner_block_to_fieldset.get(&fieldset_full_name).unwrap();
347+
Some(fieldset_names.get(fieldset_name).unwrap().clone())
348+
} else {
349+
None
350+
};
351+
352+
let access = match r.properties.access {
353+
None => Access::ReadWrite,
354+
Some(svd::Access::ReadOnly) => Access::Read,
355+
Some(svd::Access::WriteOnly) => Access::Write,
356+
Some(svd::Access::WriteOnce) => Access::Write,
357+
Some(svd::Access::ReadWrite) => Access::ReadWrite,
358+
Some(svd::Access::ReadWriteOnce) => Access::ReadWrite,
359+
};
360+
361+
let block_item = BlockItem {
362+
name: name,
363+
description: r.description.clone(),
364+
array: array.clone(),
365+
byte_offset: r.address_offset + offset,
366+
inner: BlockItemInner::Register(Register {
367+
access, // todo
368+
bit_size: r.properties.size.unwrap_or(32),
369+
fieldset: fieldset_name.clone(),
370+
}),
371+
};
372+
373+
block.items.push(block_item)
374+
}
251375
}
252376
svd::RegisterCluster::Cluster(c) => {
253377
if c.derived_from.is_some() {
254378
warn!("unsupported derived_from in clusters");
255379
continue;
256380
}
257381

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-
});
382+
let names = names(c, |c| &c.name);
383+
let array = names.array();
384+
385+
for (offset, cname) in names {
386+
let mut block_name = proto.name.clone();
387+
block_name.push(cname.clone());
388+
let block_name = block_names.get(&block_name).unwrap().clone();
389+
390+
block.items.push(BlockItem {
391+
name: cname.clone(),
392+
description: c.description.clone(),
393+
array: array.clone(),
394+
byte_offset: c.address_offset + offset,
395+
inner: BlockItemInner::Block(BlockItemBlock { block: block_name }),
396+
});
397+
}
280398
}
281399
}
282400
}
@@ -299,37 +417,31 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<()
299417
warn!("unsupported derived_from in fieldset");
300418
}
301419

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-
};
420+
let names = names(f, |f| &f.name);
421+
let array = names.array();
310422

311-
let field_name = remove_placeholder(&f.name);
423+
for (offset, field_name) in names {
424+
let mut field = Field {
425+
name: field_name.clone(),
426+
description: f.description.clone(),
427+
bit_offset: BitOffset::Regular(f.bit_range.offset + offset),
428+
bit_size: f.bit_range.width,
429+
array: array.clone(),
430+
enumm: None,
431+
};
312432

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-
};
433+
if !f.enumerated_values.is_empty() {
434+
let mut enum_name = proto.name.clone();
435+
enum_name.push(field_name);
321436

322-
if !f.enumerated_values.is_empty() {
323-
let mut enum_name = proto.name.clone();
324-
enum_name.push(field_name);
437+
trace!("finding enum {:?}", enum_name);
438+
let enum_name = enum_names.get(&enum_name).unwrap().clone();
439+
trace!("found {:?}", enum_name);
440+
field.enumm = Some(enum_name.clone())
441+
}
325442

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())
443+
fieldset.fields.push(field)
330444
}
331-
332-
fieldset.fields.push(field)
333445
}
334446

335447
let fieldset_name = fieldset_names.get(&proto.name).unwrap().clone();
@@ -492,9 +604,11 @@ fn collect_blocks(
492604
continue;
493605
}
494606

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);
607+
for (_, block) in names(c, |c| &c.name) {
608+
let mut block_name = block_name.clone();
609+
block_name.push(block);
610+
collect_blocks(out, block_name, c.description.clone(), &c.children);
611+
}
498612
}
499613
}
500614
}
@@ -588,7 +702,3 @@ pub fn namespace_names(peripheral: &PeripheralInfo, ir: &mut IR, namespace: Name
588702
}
589703
});
590704
}
591-
592-
pub fn remove_placeholder(name: &str) -> String {
593-
name.replace("[%s]", "").replace("%s", "")
594-
}

0 commit comments

Comments
 (0)