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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// SPDX-License-Identifier: Apache-2.0
use indexmap::IndexMap;
use regex::Regex;
use std::sync::Arc;
use crate::{Intf, ModDef};
impl ModDef {
/// Defines an interface with the given name. `mapping` is a map from
/// function names to tuples of `(port_name, msb, lsb)`. For example, if
/// `mapping` is `{"data": ("a_data", 3, 0), "valid": ("a_valid", 1, 1)}`,
/// this defines an interface with two functions, `data` and `valid`, where
/// the `data` function is provided by the port slice `a_data[3:0]` and the
/// `valid` function is provided by the port slice `[1:1]`.
pub fn def_intf(
&self,
name: impl AsRef<str>,
mapping: IndexMap<String, (String, usize, usize)>,
) -> Intf {
let mut core = self.core.write();
if core.interfaces.contains_key(name.as_ref()) {
panic!(
"Interface {} already exists in module {}",
name.as_ref(),
core.name
);
}
core.interfaces.insert(name.as_ref().to_string(), mapping);
Intf::ModDef {
name: name.as_ref().to_string(),
mod_def_core: Arc::downgrade(&self.core),
}
}
/// Defines an interface with the given name, where the function names are
/// derived from the port names by stripping a common prefix. For example,
/// if the module has ports `a_data`, `a_valid`, `b_data`, and `b_valid`,
/// calling `def_intf_from_prefix("a_intf", "a_")` will define an interface
/// with functions `data` and `valid`, where `data` is provided by the full
/// port `a_data` and `valid` is provided by the full port `a_valid`.
pub fn def_intf_from_prefix(&self, name: impl AsRef<str>, prefix: impl AsRef<str>) -> Intf {
self.def_intf_from_prefixes(name, &[prefix.as_ref()], true)
}
/// Defines an interface with the given name, where the function names are
/// derived from the port names by stripping the prefix `<name>_`. For
/// example, if the module has ports `a_data`, `a_valid`, `b_data`, and
/// `b_valid`, calling `def_intf_from_prefix("a")` will define an
/// interface with functions `data` and `valid`, where `data` is provided by
/// the full port `a_data` and `valid` is provided by the full port
/// `a_valid`.
pub fn def_intf_from_name_underscore(&self, name: impl AsRef<str>) -> Intf {
let prefix = format!("{}_", name.as_ref());
self.def_intf_from_prefix(name, prefix)
}
/// Defines an interface with the given name, where the signals to be
/// included are identified by those that start with one of the provided
/// prefixies. Function names are either the signal names themselves (if
/// `strip_prefix` is `false`) or by stripping the prefix (if `strip_prefix`
/// is true). For example, if the module has ports `a_data`, `a_valid`,
/// `b_data`, and `b_valid`, calling `def_intf_from_prefixes("intf", &["a_",
/// "b_"], false)` will define an interface with functions `a_data`,
/// `a_valid`, `b_data`, and `b_valid`, where each function is provided by
/// the corresponding port.
pub fn def_intf_from_prefixes(
&self,
name: impl AsRef<str>,
prefixes: &[&str],
strip_prefix: bool,
) -> Intf {
let mut mapping = IndexMap::new();
{
let core = self.core.read();
for port_name in core.ports.keys() {
for prefix in prefixes {
if port_name.starts_with(prefix) {
let func_name = if strip_prefix {
port_name.strip_prefix(prefix).unwrap().to_string()
} else {
port_name.clone()
};
let port = self.get_port(port_name);
if mapping.contains_key(&func_name) {
panic!(
"Interface function {}.{}.{} already exists",
core.name,
name.as_ref(),
func_name
);
}
mapping.insert(func_name, (port_name.clone(), port.io().width() - 1, 0));
break;
}
}
}
}
assert!(
!mapping.is_empty(),
"Empty interface definition for {}.{}",
self.get_name(),
name.as_ref()
);
self.def_intf(name, mapping)
}
pub fn def_intf_from_regex(
&self,
name: impl AsRef<str>,
search: impl AsRef<str>,
replace: impl AsRef<str>,
) -> Intf {
self.def_intf_from_regexes(name, &[(search.as_ref(), replace.as_ref())])
}
pub fn def_intf_from_regexes(&self, name: impl AsRef<str>, regexes: &[(&str, &str)]) -> Intf {
let mut mapping = IndexMap::new();
let regexes = regexes
.iter()
.map(|(search, replace)| {
(
Regex::new(search).expect("Failed to compile regex"),
replace,
)
})
.collect::<Vec<_>>();
{
let core = self.core.read();
for port_name in core.ports.keys() {
for (regex, replace) in ®exes {
if regex.is_match(port_name) {
let func_name = regex.replace(port_name, **replace).to_string();
let port = self.get_port(port_name);
if mapping.contains_key(&func_name) {
panic!(
"Interface function {}.{}.{} already exists",
core.name,
name.as_ref(),
func_name
);
}
mapping.insert(func_name, (port_name.clone(), port.io().width() - 1, 0));
break;
}
}
}
}
assert!(
!mapping.is_empty(),
"Empty interface definition for {}.{}",
self.get_name(),
name.as_ref()
);
self.def_intf(name, mapping)
}
/// Returns the interface with the given name; panics if an interface with
/// that name does not exist.
pub fn get_intf(&self, name: impl AsRef<str>) -> Intf {
let core = self.core.read();
if core.interfaces.contains_key(name.as_ref()) {
Intf::ModDef {
name: name.as_ref().to_string(),
mod_def_core: Arc::downgrade(&self.core),
}
} else {
panic!(
"Interface '{}' does not exist in module '{}'",
name.as_ref(),
core.name
);
}
}
/// Returns `true` if this module definition has an interface with the given
/// name.
pub fn has_intf(&self, name: impl AsRef<str>) -> bool {
self.core.read().interfaces.contains_key(name.as_ref())
}
/// Returns a vector of all interfaces on this module definition with the
/// given prefix. If `prefix` is `None`, returns all interfaces.
pub fn get_intfs(&self, prefix: Option<&str>) -> Vec<Intf> {
let inner = self.core.read();
let mut result = Vec::new();
for name in inner.interfaces.keys() {
if prefix.is_none_or(|pfx| name.starts_with(pfx)) {
result.push(Intf::ModDef {
name: name.clone(),
mod_def_core: Arc::downgrade(&self.core),
});
}
}
result
}
}