-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathpatch.rs
109 lines (95 loc) · 3.52 KB
/
patch.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Patches for atdf files that can generally be applied
use crate::chip;
use crate::util;
use crate::ElementExt;
use std::collections::BTreeMap;
const NEW_PORT_REGS: [&str; 10] = [
"DIR", "DIRSET", "DIRCLR", "DIRTGL", "OUT", "OUTSET", "OUTCLR", "OUTTGL", "IN", "INTFLAGS",
];
pub fn signals_to_port_fields(chip: &mut chip::Chip, tree: &xmltree::Element) -> crate::Result<()> {
let port_module = tree
.first_child("devices")?
.first_child("device")?
.first_child("peripherals")?
.first_child_by_attr(Some("module"), "name", "PORT")?;
for port in chip
.peripherals
.values_mut()
.filter(|p| p.name.starts_with("PORT") && p.name.len() == 5)
{
let name = port.name.chars().rev().next().unwrap();
let pins: Vec<_> = port_module
.first_child_by_attr(Some("instance"), "name", &port.name)?
.first_child("signals")?
.children
.iter()
.filter_map(|node| node.as_element())
.map(|el| el.attr("index"))
.map(|r| r.and_then(|s| util::parse_int(s)))
.collect::<Result<_, _>>()?;
let fields: BTreeMap<String, chip::Field> = pins
.into_iter()
.map(|p| chip::Field {
name: format!("P{}{}", name, p),
description: Some(format!("Pin {}{}", name, p)),
range: (p, p),
access: chip::AccessMode::ReadWrite,
restriction: chip::ValueRestriction::Any,
})
.map(|f| (f.name.clone(), f))
.collect();
for reg in port.registers.values_mut() {
if reg.name.ends_with(name) || NEW_PORT_REGS.iter().any(|r| r == ®.name) {
reg.fields = fields.clone();
// Ensure that direct access to the register is unsafe
reg.restriction = chip::ValueRestriction::Unsafe;
}
}
}
Ok(())
}
pub fn remove_unsafe_cpu_regs(chip: &mut chip::Chip, _el: &xmltree::Element) -> crate::Result<()> {
if let Some(cpu) = chip.peripherals.get_mut("CPU") {
cpu.registers.remove("SREG");
cpu.registers.remove("SP");
}
Ok(())
}
fn longest_common_prefix<'a>(strings: &[&'a str]) -> &'a str {
if strings.is_empty() {
return "";
}
let mut longest_prefix = "";
for prefix in strings[0]
.char_indices()
.map(|(i, _)| strings[0].split_at(i).0)
{
if strings.iter().all(|s| s.starts_with(prefix)) {
longest_prefix = prefix;
} else {
// This prefix no longer matches so the previous one was the longest.
break;
}
}
longest_prefix
}
pub fn remove_register_common_prefix(chip: &mut chip::Chip) -> crate::Result<()> {
for peripheral in chip.peripherals.values_mut() {
// There's not enough quorum in less than two elements to find a
// prefix.
if peripheral.registers.len() < 2 {
continue;
}
let register_names: Vec<_> = peripheral.registers.keys().map(String::as_str).collect();
let common_prefix = longest_common_prefix(®ister_names).to_string();
let is_valid_prefix = common_prefix.ends_with("_") && common_prefix.chars().count() >= 2;
if is_valid_prefix {
for register in peripheral.registers.values_mut() {
if let Some(s) = register.name.strip_prefix(&common_prefix) {
register.name = s.to_string();
}
}
}
}
Ok(())
}