safety_net/
attribute.rs

1/*!
2
3  Attributes and parameters for nets and node (gates) in the netlist.
4
5*/
6
7use 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
16/// A Verilog attribute assigned to a net or gate in the netlist: (* dont_touch *)
17pub type AttributeKey = String;
18/// A Verilog attribute can be assigned a string value: bitvec = (* dont_touch = true *)
19pub type AttributeValue = Option<String>;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23/// An attribute can add information to instances and wires in string form, like 'dont_touch'
24pub struct Attribute {
25    k: AttributeKey,
26    v: AttributeValue,
27}
28
29impl Attribute {
30    /// Create a new attribute pair
31    pub fn new(k: AttributeKey, v: AttributeValue) -> Self {
32        Self { k, v }
33    }
34
35    /// Get the key of the attribute
36    pub fn key(&self) -> &AttributeKey {
37        &self.k
38    }
39
40    /// Get the value of the attribute
41    pub fn value(&self) -> &AttributeValue {
42        &self.v
43    }
44
45    /// Map a attribute key-value pairs to the Attribute struct
46    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))]
65/// A dedicated type to parameters for instantiables
66pub enum Parameter {
67    /// An unsigned integer parameter
68    Integer(u64),
69    /// A floating-point parameter
70    Real(f32),
71    /// A bit vector parameter, like for a truth table
72    BitVec(BitVec),
73    /// A four-state logic parameter
74    Logic(Logic),
75}
76
77impl Eq for Parameter {}
78
79impl std::fmt::Display for Parameter {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        match self {
82            Parameter::Integer(i) => write!(f, "{i}"),
83            Parameter::Real(_r) => todo!(),
84            Parameter::BitVec(bv) => {
85                if bv.len() >= 4 && bv.len() % 4 == 0 {
86                    write!(f, "{}'h", bv.len())?;
87                    for n in bv.chunks(4).rev() {
88                        let val: u8 = n.load();
89                        write!(f, "{:x}", val)?;
90                    }
91                    Ok(())
92                } else {
93                    write!(
94                        f,
95                        "{}'b{}",
96                        bv.len(),
97                        bv.iter()
98                            .rev()
99                            .map(|b| if *b { '1' } else { '0' })
100                            .collect::<String>()
101                    )
102                }
103            }
104            Parameter::Logic(l) => write!(f, "{l}"),
105        }
106    }
107}
108
109impl Parameter {
110    /// Create a new integer parameter
111    pub fn integer(i: u64) -> Self {
112        Self::Integer(i)
113    }
114
115    /// Create a new real parameter
116    pub fn real(r: f32) -> Self {
117        Self::Real(r)
118    }
119
120    /// Create a new bitvec parameter
121    pub fn bitvec(size: usize, val: u64) -> Self {
122        if size > 64 {
123            panic!("BitVec parameter size cannot be larger than 64");
124        }
125        let mut bv: BitVec = bitvec!(usize, Lsb0; 0; 64);
126        bv[0..64].store::<u64>(val);
127        bv.truncate(size);
128        Self::BitVec(bv)
129    }
130
131    /// Create a new Logic parameter
132    pub fn logic(l: Logic) -> Self {
133        Self::Logic(l)
134    }
135
136    /// Create a new Logic parameter from bool
137    pub fn from_bool(b: bool) -> Self {
138        Self::Logic(Logic::from_bool(b))
139    }
140}
141
142/// Filter nodes/nets in the netlist by some attribute, like "dont_touch"
143pub struct AttributeFilter<'a, I: Instantiable> {
144    // A reference to the underlying netlist
145    _netlist: &'a Netlist<I>,
146    // The keys to filter by
147    keys: Vec<AttributeKey>,
148    /// The mapping of netrefs that have this attribute
149    map: HashMap<AttributeKey, HashSet<NetRef<I>>>,
150    /// Contains a dedup collection of all filtered nodes
151    full_set: HashSet<NetRef<I>>,
152}
153
154impl<'a, I> AttributeFilter<'a, I>
155where
156    I: Instantiable,
157{
158    /// Create a new filter for the netlist
159    fn new(netlist: &'a Netlist<I>, keys: Vec<AttributeKey>) -> Self {
160        let mut map = HashMap::new();
161        let mut full_set = HashSet::new();
162        for nr in netlist.objects() {
163            for attr in nr.attributes() {
164                if keys.contains(attr.key()) {
165                    map.entry(attr.key().clone())
166                        .or_insert_with(HashSet::new)
167                        .insert(nr.clone());
168                    full_set.insert(nr.clone());
169                }
170            }
171        }
172        Self {
173            _netlist: netlist,
174            keys,
175            map,
176            full_set,
177        }
178    }
179
180    /// Check if an node matches any of the filter keys
181    pub fn has(&self, n: &NetRef<I>) -> bool {
182        self.map.values().any(|s| s.contains(n))
183    }
184
185    /// Return a slice to the keys that were used for filtering
186    pub fn keys(&self) -> &[AttributeKey] {
187        &self.keys
188    }
189}
190
191impl<'a, I> IntoIterator for AttributeFilter<'a, I>
192where
193    I: Instantiable,
194{
195    type Item = NetRef<I>;
196
197    type IntoIter = std::collections::hash_set::IntoIter<NetRef<I>>;
198
199    fn into_iter(self) -> Self::IntoIter {
200        self.full_set.into_iter()
201    }
202}
203
204/// Returns a filtering of nodes and nets that are marked as 'dont_touch'
205pub fn dont_touch_filter<'a, I>(netlist: &'a Netlist<I>) -> AttributeFilter<'a, I>
206where
207    I: Instantiable,
208{
209    AttributeFilter::new(netlist, vec!["dont_touch".to_string()])
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215
216    #[test]
217    fn attribute_iter() {
218        let attributes: [(AttributeKey, AttributeValue); 2] = [
219            ("dont_touch".to_string(), Some("true".to_string())),
220            ("synthesizable".to_string(), None),
221        ];
222        let real_attrs: Vec<Attribute> = Attribute::from_pairs(attributes.into_iter()).collect();
223        assert_eq!(real_attrs.len(), 2);
224        assert_eq!(
225            real_attrs.first().unwrap().to_string(),
226            "(* dont_touch = true *)"
227        );
228        assert_eq!(real_attrs.first().unwrap().key(), "dont_touch");
229        assert_eq!(
230            real_attrs.last().unwrap().to_string(),
231            "(* synthesizable *)"
232        );
233        assert!(real_attrs.last().unwrap().value().is_none());
234    }
235
236    #[test]
237    fn test_parameter_fmt() {
238        let p1 = Parameter::Integer(42);
239        // Lsb first
240        let p2 = Parameter::BitVec(bitvec![0, 0, 0, 0, 0, 0, 0, 1]);
241        let p3 = Parameter::Logic(Logic::from_bool(true));
242        let p4 = Parameter::from_bool(true);
243        assert_eq!(p1.to_string(), "42");
244        assert_eq!(p2.to_string(), "8'h80");
245        assert_eq!(p3.to_string(), "1'b1");
246        assert_eq!(p4.to_string(), "1'b1");
247    }
248
249    #[test]
250    fn test_parameter_hex() {
251        let p = Parameter::BitVec(bitvec![1, 1, 1, 0, 1, 0, 0, 0]);
252        assert_eq!(p.to_string(), "8'h17");
253        let p = Parameter::BitVec(bitvec![1, 1, 1, 1, 1, 0, 0, 0]);
254        assert_eq!(p.to_string(), "8'h1f");
255    }
256}