1use bitvec::{bitvec, field::BitField, order::Lsb0, vec::BitVec};
8use std::collections::{HashMap, HashSet};
9
10use crate::{
11 circuit::Instantiable,
12 logic::Logic,
13 netlist::{NetRef, Netlist},
14};
15
16pub type AttributeKey = String;
18pub type AttributeValue = Option<Parameter>;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Attribute {
25 k: AttributeKey,
26 v: AttributeValue,
27}
28
29impl Attribute {
30 pub fn new(k: AttributeKey, v: AttributeValue) -> Self {
32 Self { k, v }
33 }
34
35 pub fn key(&self) -> &AttributeKey {
37 &self.k
38 }
39
40 pub fn value(&self) -> &AttributeValue {
42 &self.v
43 }
44
45 pub fn split(self) -> (AttributeKey, AttributeValue) {
47 (self.k, self.v)
48 }
49
50 pub fn from_pairs(
52 iter: impl Iterator<Item = (AttributeKey, AttributeValue)>,
53 ) -> impl Iterator<Item = Self> {
54 iter.map(|(k, v)| Self::new(k, v))
55 }
56}
57
58impl std::fmt::Display for Attribute {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 if let Some(value) = &self.v {
61 write!(f, "(* {} = {} *)", self.k, value)
62 } else {
63 write!(f, "(* {} *)", self.k)
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub enum Parameter {
72 Integer(u64),
74 Real(f32),
76 BitVec(BitVec),
78 Logic(Logic),
80 String(String),
82}
83
84impl Eq for Parameter {}
85
86impl std::fmt::Display for Parameter {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 match self {
89 Parameter::Integer(i) => write!(f, "{i}"),
90 Parameter::Real(_r) => todo!(),
91 Parameter::BitVec(bv) => {
92 if bv.len() >= 4 && bv.len() % 4 == 0 {
93 write!(f, "{}'h", bv.len())?;
94 for n in bv.chunks(4).rev() {
95 let val: u8 = n.load();
96 write!(f, "{:x}", val)?;
97 }
98 } else {
99 write!(f, "{}'b", bv.len())?;
100 for v in bv.iter().rev() {
101 write!(f, "{}", if *v { '1' } else { '0' })?;
102 }
103 }
104 Ok(())
105 }
106 Parameter::Logic(l) => write!(f, "{l}"),
107 Parameter::String(s) => write!(f, "\"{s}\""),
108 }
109 }
110}
111
112impl Parameter {
113 pub fn integer(i: u64) -> Self {
115 Self::Integer(i)
116 }
117
118 pub fn real(r: f32) -> Self {
120 Self::Real(r)
121 }
122
123 pub fn bitvec(size: usize, val: u64) -> Self {
125 if size > 64 {
126 panic!("BitVec parameter size cannot be larger than 64");
127 }
128 let mut bv: BitVec = bitvec!(usize, Lsb0; 0; 64);
129 bv[0..64].store::<u64>(val);
130 bv.truncate(size);
131 Self::BitVec(bv)
132 }
133
134 pub fn logic(l: Logic) -> Self {
136 Self::Logic(l)
137 }
138
139 pub fn from_bool(b: bool) -> Self {
141 Self::Logic(Logic::from_bool(b))
142 }
143
144 pub fn string(s: String) -> Self {
146 Self::String(s)
147 }
148
149 pub fn get_str(s: &str) -> Self {
151 Self::String(s.to_string())
152 }
153}
154
155pub struct AttributeFilter<'a, I: Instantiable> {
157 _netlist: &'a Netlist<I>,
159 keys: Vec<AttributeKey>,
161 map: HashMap<AttributeKey, HashSet<NetRef<I>>>,
163 full_set: HashSet<NetRef<I>>,
165}
166
167impl<'a, I> AttributeFilter<'a, I>
168where
169 I: Instantiable,
170{
171 fn new(netlist: &'a Netlist<I>, keys: Vec<AttributeKey>) -> Self {
173 let mut map = HashMap::new();
174 let mut full_set = HashSet::new();
175 for nr in netlist.objects() {
176 for attr in nr.attributes() {
177 if keys.contains(attr.key()) {
178 map.entry(attr.key().clone())
179 .or_insert_with(HashSet::new)
180 .insert(nr.clone());
181 full_set.insert(nr.clone());
182 }
183 }
184 }
185 Self {
186 _netlist: netlist,
187 keys,
188 map,
189 full_set,
190 }
191 }
192
193 pub fn has(&self, n: &NetRef<I>) -> bool {
195 self.map.values().any(|s| s.contains(n))
196 }
197
198 pub fn keys(&self) -> &[AttributeKey] {
200 &self.keys
201 }
202}
203
204impl<'a, I> IntoIterator for AttributeFilter<'a, I>
205where
206 I: Instantiable,
207{
208 type Item = NetRef<I>;
209
210 type IntoIter = std::collections::hash_set::IntoIter<NetRef<I>>;
211
212 fn into_iter(self) -> Self::IntoIter {
213 self.full_set.into_iter()
214 }
215}
216
217pub fn dont_touch_filter<'a, I>(netlist: &'a Netlist<I>) -> AttributeFilter<'a, I>
219where
220 I: Instantiable,
221{
222 AttributeFilter::new(netlist, vec!["dont_touch".to_string()])
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn attribute_iter() {
231 let attributes: [(AttributeKey, AttributeValue); 2] = [
232 ("dont_touch".to_string(), Some(Parameter::get_str("true"))),
233 ("synthesizable".to_string(), None),
234 ];
235 let real_attrs: Vec<Attribute> = Attribute::from_pairs(attributes.into_iter()).collect();
236 assert_eq!(real_attrs.len(), 2);
237 assert_eq!(
238 real_attrs.first().unwrap().to_string(),
239 "(* dont_touch = \"true\" *)"
240 );
241 assert_eq!(real_attrs.first().unwrap().key(), "dont_touch");
242 assert_eq!(
243 real_attrs.last().unwrap().to_string(),
244 "(* synthesizable *)"
245 );
246 assert!(real_attrs.last().unwrap().value().is_none());
247 }
248
249 #[test]
250 fn test_parameter_fmt() {
251 let p1 = Parameter::Integer(42);
252 let p2 = Parameter::BitVec(bitvec![0, 0, 0, 0, 0, 0, 0, 1]);
254 let p3 = Parameter::Logic(Logic::from_bool(true));
255 let p4 = Parameter::from_bool(true);
256 assert_eq!(p1.to_string(), "42");
257 assert_eq!(p2.to_string(), "8'h80");
258 assert_eq!(p3.to_string(), "1'b1");
259 assert_eq!(p4.to_string(), "1'b1");
260 }
261
262 #[test]
263 fn test_parameter_hex() {
264 let p = Parameter::BitVec(bitvec![1, 1, 1, 0, 1, 0, 0, 0]);
265 assert_eq!(p.to_string(), "8'h17");
266 let p = Parameter::BitVec(bitvec![1, 1, 1, 1, 1, 0, 0, 0]);
267 assert_eq!(p.to_string(), "8'h1f");
268 }
269}