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) => write!(
85                f,
86                "{}'b{}",
87                bv.len(),
88                bv.iter()
89                    .rev()
90                    .map(|b| if *b { '1' } else { '0' })
91                    .collect::<String>()
92            ),
93            Parameter::Logic(l) => write!(f, "{l}"),
94        }
95    }
96}
97
98impl Parameter {
99    /// Create a new integer parameter
100    pub fn integer(i: u64) -> Self {
101        Self::Integer(i)
102    }
103
104    /// Create a new real parameter
105    pub fn real(r: f32) -> Self {
106        Self::Real(r)
107    }
108
109    /// Create a new bitvec parameter
110    pub fn bitvec(size: usize, val: u64) -> Self {
111        if size > 64 {
112            panic!("BitVec parameter size cannot be larger than 64");
113        }
114        let mut bv: BitVec = bitvec!(usize, Lsb0; 0; 64);
115        bv[0..64].store::<u64>(val);
116        bv.truncate(size);
117        Self::BitVec(bv)
118    }
119
120    /// Create a new Logic parameter
121    pub fn logic(l: Logic) -> Self {
122        Self::Logic(l)
123    }
124
125    /// Create a new Logic parameter from bool
126    pub fn from_bool(b: bool) -> Self {
127        Self::Logic(Logic::from_bool(b))
128    }
129}
130
131/// Filter nodes/nets in the netlist by some attribute, like "dont_touch"
132pub struct AttributeFilter<'a, I: Instantiable> {
133    // A reference to the underlying netlist
134    _netlist: &'a Netlist<I>,
135    // The keys to filter by
136    keys: Vec<AttributeKey>,
137    /// The mapping of netrefs that have this attribute
138    map: HashMap<AttributeKey, HashSet<NetRef<I>>>,
139    /// Contains a dedup collection of all filtered nodes
140    full_set: HashSet<NetRef<I>>,
141}
142
143impl<'a, I> AttributeFilter<'a, I>
144where
145    I: Instantiable,
146{
147    /// Create a new filter for the netlist
148    fn new(netlist: &'a Netlist<I>, keys: Vec<AttributeKey>) -> Self {
149        let mut map = HashMap::new();
150        let mut full_set = HashSet::new();
151        for nr in netlist.objects() {
152            for attr in nr.attributes() {
153                if keys.contains(attr.key()) {
154                    map.entry(attr.key().clone())
155                        .or_insert_with(HashSet::new)
156                        .insert(nr.clone());
157                    full_set.insert(nr.clone());
158                }
159            }
160        }
161        Self {
162            _netlist: netlist,
163            keys,
164            map,
165            full_set,
166        }
167    }
168
169    /// Check if an node matches any of the filter keys
170    pub fn has(&self, n: &NetRef<I>) -> bool {
171        self.map.values().any(|s| s.contains(n))
172    }
173
174    /// Return a slice to the keys that were used for filtering
175    pub fn keys(&self) -> &[AttributeKey] {
176        &self.keys
177    }
178}
179
180impl<'a, I> IntoIterator for AttributeFilter<'a, I>
181where
182    I: Instantiable,
183{
184    type Item = NetRef<I>;
185
186    type IntoIter = std::collections::hash_set::IntoIter<NetRef<I>>;
187
188    fn into_iter(self) -> Self::IntoIter {
189        self.full_set.into_iter()
190    }
191}
192
193/// Returns a filtering of nodes and nets that are marked as 'dont_touch'
194pub fn dont_touch_filter<'a, I>(netlist: &'a Netlist<I>) -> AttributeFilter<'a, I>
195where
196    I: Instantiable,
197{
198    AttributeFilter::new(netlist, vec!["dont_touch".to_string()])
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn attribute_iter() {
207        let attributes: [(AttributeKey, AttributeValue); 2] = [
208            ("dont_touch".to_string(), Some("true".to_string())),
209            ("synthesizable".to_string(), None),
210        ];
211        let real_attrs: Vec<Attribute> = Attribute::from_pairs(attributes.into_iter()).collect();
212        assert_eq!(real_attrs.len(), 2);
213        assert_eq!(
214            real_attrs.first().unwrap().to_string(),
215            "(* dont_touch = true *)"
216        );
217        assert_eq!(real_attrs.first().unwrap().key(), "dont_touch");
218        assert_eq!(
219            real_attrs.last().unwrap().to_string(),
220            "(* synthesizable *)"
221        );
222        assert!(real_attrs.last().unwrap().value().is_none());
223    }
224
225    #[test]
226    fn test_parameter_fmt() {
227        let p1 = Parameter::Integer(42);
228        // Lsb first
229        let p2 = Parameter::BitVec(bitvec![0, 0, 0, 0, 0, 0, 0, 1]);
230        let p3 = Parameter::Logic(Logic::from_bool(true));
231        let p4 = Parameter::from_bool(true);
232        assert_eq!(p1.to_string(), "42");
233        assert_eq!(p2.to_string(), "8'b10000000");
234        assert_eq!(p3.to_string(), "1'b1");
235        assert_eq!(p4.to_string(), "1'b1");
236    }
237}