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