Skip to main content

safety_net/
circuit.rs

1/*!
2
3  Types for the constructs found within a digital circuit.
4
5*/
6
7use crate::{attribute::Parameter, logic::Logic};
8
9/// Signals in a circuit can be binary, tri-state, or four-state.
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum DataType {
13    /// A logical 0 or 1
14    TwoState,
15    /// A logical 0, 1, or high-Z
16    ThreeState,
17    /// A logical 0, 1, high-Z, or unknown (X)
18    FourState,
19}
20
21impl DataType {
22    /// Returns the data type for bools (1'b0 and 1'b1)
23    pub fn boolean() -> Self {
24        DataType::TwoState
25    }
26
27    /// Returns the data type for tri-state signals (1'b0, 1'b1, and 1'bz)
28    pub fn tristate() -> Self {
29        DataType::ThreeState
30    }
31
32    /// Returns the data type for four-state signals (1'b0, 1'b1, 1'bz, and 1'bx)
33    pub fn fourstate() -> Self {
34        DataType::FourState
35    }
36
37    /// Returns the data type for four-state signals (1'b0, 1'b1, 1'bz, and 1'bx)
38    pub fn logic() -> Self {
39        DataType::FourState
40    }
41}
42
43/// An identifier of a node in a circuit
44#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46pub struct Identifier {
47    /// The name of the identifier
48    name: String,
49    /// Is the identifier escaped
50    escaped: bool,
51    /// The bit index of the identifier, if it is part of a bus.
52    idx: Option<usize>,
53}
54
55impl Identifier {
56    /// Creates a new identifier with the given name
57    pub fn new(name: String) -> Self {
58        if name.is_empty() {
59            panic!("Identifier name cannot be empty");
60        }
61
62        if let Some(root) = name.strip_prefix('\\') {
63            return Identifier {
64                name: root.to_string(),
65                escaped: true,
66                idx: None,
67            };
68        }
69
70        // Check if first char is a digit
71        let esc_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
72        if esc_chars.contains(&name.chars().next().unwrap()) {
73            return Identifier {
74                name,
75                escaped: true,
76                idx: None,
77            };
78        }
79
80        // Certainly not an exhaustive list.
81        // TODO(matth2k): Implement a true isEscaped()
82        let esc_chars = [
83            ' ', '\\', '(', ')', ',', '+', '-', '$', '\'', '~', ';', '.', ',', '?', '!',
84        ];
85        if name.chars().any(|c| esc_chars.contains(&c)) {
86            return Identifier {
87                name,
88                escaped: true,
89                idx: None,
90            };
91        }
92
93        if name.contains('[') && name.ends_with(']') {
94            let name_ind = name.find('[').unwrap();
95            let rname = &name[..name_ind];
96            let index_start = name_ind + 1;
97            let slice = name[index_start..name.len() - 1].parse::<usize>();
98            if let Ok(s) = slice {
99                let id = Identifier::new(rname.to_string());
100                if !id.is_sliced() {
101                    return Identifier { idx: Some(s), ..id };
102                }
103            }
104        }
105
106        Identifier {
107            name,
108            escaped: false,
109            idx: None,
110        }
111    }
112
113    /// Returns a bus with length `bw`
114    ///
115    /// # Panics
116    ///
117    /// if `name` already includes slicing brackets
118    pub fn new_bus(name: String, bw: usize) -> Vec<Self> {
119        let mut vec = Vec::new();
120        let id = Identifier::new(name.clone());
121        if id.is_sliced() {
122            panic!("Cannot create a bus from an identifier that is sliced by string");
123        }
124        for i in 0..bw {
125            vec.push(Identifier {
126                idx: Some(i),
127                ..id.clone()
128            });
129        }
130        vec
131    }
132
133    /// Returns the stem of the identifier
134    pub fn get_stem(&self) -> &str {
135        &self.name
136    }
137
138    /// Returns the bit index, if the identifier is a bit-slice
139    pub fn get_bit_index(&self) -> Option<usize> {
140        self.idx
141    }
142
143    /// Returns `true` if the identifier is a slice of a wire bus
144    pub fn is_sliced(&self) -> bool {
145        self.idx.is_some()
146    }
147
148    /// The identifier is escaped, as defined by Verilog
149    pub fn is_escaped(&self) -> bool {
150        self.escaped
151    }
152
153    /// Emit the name as suitable for an HDL like Verilog. This takes into account bit-slicing and escaped identifiers
154    pub fn emit_name(&self) -> String {
155        let stem = match self.escaped {
156            false => self.name.clone(),
157            true => format!("\\{} ", self.name),
158        };
159        match self.idx {
160            Some(i) => format!("{stem}[{i}]"),
161            None => stem,
162        }
163    }
164}
165
166impl std::ops::Add for &Identifier {
167    type Output = Identifier;
168
169    fn add(self, rhs: Self) -> Identifier {
170        let lname = self.name.as_str();
171        let rname = rhs.name.as_str();
172        let escaped = self.escaped || rhs.escaped;
173
174        let new_name = match (self.idx, rhs.idx) {
175            (Some(l), Some(r)) => {
176                format!("{}_{}_{}_{}", lname, l, rname, r)
177            }
178            (Some(l), None) => format!("{}_{}_{}", lname, l, rname),
179            (None, Some(r)) => format!("{}_{}_{}", lname, rname, r),
180            _ => format!("{}_{}", lname, rname),
181        };
182
183        Identifier {
184            name: new_name,
185            escaped,
186            idx: None,
187        }
188    }
189}
190
191impl std::ops::Add for Identifier {
192    type Output = Identifier;
193
194    fn add(self, rhs: Self) -> Identifier {
195        &self + &rhs
196    }
197}
198
199impl From<&str> for Identifier {
200    fn from(name: &str) -> Self {
201        Identifier::new(name.to_string())
202    }
203}
204
205impl From<String> for Identifier {
206    fn from(name: String) -> Self {
207        Identifier::new(name)
208    }
209}
210
211impl std::fmt::Display for Identifier {
212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213        if self.escaped {
214            write!(f, "\\")?;
215        }
216        write!(f, "{}", self.name)?;
217        if self.escaped {
218            write!(f, " ")?;
219        }
220        if let Some(idx) = self.idx {
221            write!(f, "[{idx}]")?;
222        }
223        Ok(())
224    }
225}
226
227/// A net in a circuit, which is identified with a name and data type.
228#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub struct Net {
231    identifier: Identifier,
232    data_type: DataType,
233}
234
235impl Net {
236    /// Creates a new net with the given identifier and data type
237    pub fn new(identifier: Identifier, data_type: DataType) -> Self {
238        Self {
239            identifier,
240            data_type,
241        }
242    }
243
244    /// Create a new net for SystemVerilog-like four-state logic
245    pub fn new_logic(name: Identifier) -> Self {
246        Self::new(name, DataType::logic())
247    }
248
249    /// Create a wire bus
250    pub fn new_logic_bus(name: String, bw: usize) -> Vec<Self> {
251        let ids = Identifier::new_bus(name, bw);
252        ids.into_iter()
253            .map(|id| Self::new(id, DataType::logic()))
254            .collect()
255    }
256
257    /// Sets the identifier of the net
258    pub fn set_identifier(&mut self, identifier: Identifier) {
259        self.identifier = identifier;
260    }
261
262    /// Returns the full identifier to the net
263    pub fn get_identifier(&self) -> &Identifier {
264        &self.identifier
265    }
266
267    /// Returns the full identifier to the net
268    pub fn take_identifier(self) -> Identifier {
269        self.identifier
270    }
271
272    /// Returns the data type of the net
273    pub fn get_type(&self) -> &DataType {
274        &self.data_type
275    }
276
277    /// Returns a net of the same type but with a different [Identifier].
278    pub fn with_name(&self, name: Identifier) -> Self {
279        Self::new(name, self.data_type)
280    }
281}
282
283/// Functions like the [format!] macro, but returns an [Identifier]
284#[macro_export]
285macro_rules! format_id {
286    ($($arg:tt)*) => {
287        $crate::Identifier::new(format!($($arg)*))
288    }
289}
290
291impl std::fmt::Display for Net {
292    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293        self.identifier.fmt(f)
294    }
295}
296
297impl From<&str> for Net {
298    fn from(name: &str) -> Self {
299        Net::new_logic(name.into())
300    }
301}
302
303/// A trait for primitives in a digital circuit, such as gates or other components.
304pub trait Instantiable: Clone {
305    /// Returns the name of the primitive
306    fn get_name(&self) -> &Identifier;
307
308    /// Returns the input ports of the primitive
309    fn get_input_ports(&self) -> impl IntoIterator<Item = &Net>;
310
311    /// Returns the output ports of the primitive
312    fn get_output_ports(&self) -> impl IntoIterator<Item = &Net>;
313
314    /// Returns `true` if the type intakes a parameter with this name.
315    fn has_parameter(&self, id: &Identifier) -> bool;
316
317    /// Returns the parameter value for the given key, if it exists.
318    fn get_parameter(&self, id: &Identifier) -> Option<Parameter>;
319
320    /// Returns the old parameter value for the given key, if it existed.
321    fn set_parameter(&mut self, id: &Identifier, val: Parameter) -> Option<Parameter>;
322
323    /// Returns an iterator over the parameters of the primitive.
324    fn parameters(&self) -> impl Iterator<Item = (Identifier, Parameter)>;
325
326    /// Creates the primitive used to represent a constant value, like VDD or GND.
327    /// If the implementer does not support the specific constant, `None` is returned.
328    fn from_constant(val: Logic) -> Option<Self>;
329
330    /// Returns the constant value represented by this primitive, if it is constant.
331    fn get_constant(&self) -> Option<Logic>;
332
333    /// Returns 'true' if the primitive is sequential.
334    fn is_seq(&self) -> bool;
335
336    /// Returns `true` if the primitive is parameterized (has at least one parameter).
337    fn is_parameterized(&self) -> bool {
338        self.parameters().next().is_some()
339    }
340
341    /// Returns the single output port of the primitive.
342    fn get_single_output_port(&self) -> &Net {
343        let mut iter = self.get_output_ports().into_iter();
344        let ret = iter.next().expect("Primitive has no output ports");
345        if iter.next().is_some() {
346            panic!("Primitive has more than one output port");
347        }
348        ret
349    }
350
351    /// Returns the output port at the given index.
352    /// # Panics
353    ///
354    /// If the index is out of bounds.
355    fn get_output_port(&self, index: usize) -> &Net {
356        self.get_output_ports()
357            .into_iter()
358            .nth(index)
359            .expect("Index out of bounds for output ports")
360    }
361
362    /// Returns the input port at the given index.
363    /// # Panics
364    ///
365    /// If the index is out of bounds.
366    fn get_input_port(&self, index: usize) -> &Net {
367        self.get_input_ports()
368            .into_iter()
369            .nth(index)
370            .expect("Index out of bounds for output ports")
371    }
372
373    /// Returns the index of the input port with the given identifier, if it exists.
374    /// **This method should be overriden if the implemenation is capable of O(1) lookup.**
375    fn find_input(&self, id: &Identifier) -> Option<usize> {
376        self.get_input_ports()
377            .into_iter()
378            .position(|n| n.get_identifier() == id)
379    }
380
381    /// Returns the index of the output port with the given identifier, if it exists.
382    /// **This method should be overriden if the implemenation is capable of O(1) lookup.**
383    fn find_output(&self, id: &Identifier) -> Option<usize> {
384        self.get_output_ports()
385            .into_iter()
386            .position(|n| n.get_identifier() == id)
387    }
388
389    /// Returns `true` if the primitive has no input ports. In most cases, this means the cell represents a constant.
390    /// **This method should be overriden if the implemenation of `get_input_ports()` is expensive.**
391    fn is_driverless(&self) -> bool {
392        self.get_input_ports().into_iter().next().is_none()
393    }
394}
395
396/// A tagged union for objects in a digital circuit, which can be either an input net or an instance of a module or primitive.
397#[derive(Debug, Clone)]
398#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
399pub enum Object<I>
400where
401    I: Instantiable,
402{
403    /// A principal input to the circuit
404    Input(Net),
405    /// An instance of a module or primitive
406    Instance(Vec<Net>, Identifier, I),
407}
408
409impl<I> Object<I>
410where
411    I: Instantiable,
412{
413    /// Returns the net driven by this object.
414    pub fn get_single_net(&self) -> &Net {
415        match self {
416            Object::Input(net) => net,
417            Object::Instance(nets, _, _) => {
418                if nets.len() > 1 {
419                    panic!("Instance has more than one output net");
420                } else {
421                    nets.first().expect("Instance has no output net")
422                }
423            }
424        }
425    }
426
427    /// Returns the net driven by this object at the index
428    pub fn get_net(&self, index: usize) -> &Net {
429        match self {
430            Object::Input(net) => {
431                if index > 0 {
432                    panic!("Index out of bounds for input net.")
433                }
434                net
435            }
436            Object::Instance(nets, _, _) => &nets[index],
437        }
438    }
439
440    /// Returns the instance within the object, if the object represents one
441    pub fn get_instance_type(&self) -> Option<&I> {
442        match self {
443            Object::Input(_) => None,
444            Object::Instance(_, _, instance) => Some(instance),
445        }
446    }
447
448    /// Returns a mutable reference to the instance type within the object, if the object represents one
449    pub fn get_instance_type_mut(&mut self) -> Option<&mut I> {
450        match self {
451            Object::Input(_) => None,
452            Object::Instance(_, _, instance) => Some(instance),
453        }
454    }
455
456    /// Returns all the nets driven at this circuit node.
457    pub fn get_nets(&self) -> &[Net] {
458        match self {
459            Object::Input(net) => std::slice::from_ref(net),
460            Object::Instance(nets, _, _) => nets,
461        }
462    }
463
464    /// Returns a mutable reference to all the nets driven at this circuit node.
465    pub fn get_nets_mut(&mut self) -> &mut [Net] {
466        match self {
467            Object::Input(net) => std::slice::from_mut(net),
468            Object::Instance(nets, _, _) => nets,
469        }
470    }
471}
472
473impl<I> std::fmt::Display for Object<I>
474where
475    I: Instantiable,
476{
477    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
478        match self {
479            Object::Input(net) => write!(f, "Input({net})"),
480            Object::Instance(_nets, name, instance) => {
481                write!(f, "{}({})", instance.get_name(), name)
482            }
483        }
484    }
485}
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490
491    #[test]
492    fn identifier_parsing() {
493        let id = Identifier::new("wire".to_string());
494        assert!(!id.is_escaped());
495        assert!(!id.is_sliced());
496        assert!(id.get_bit_index().is_none());
497        let id = Identifier::new("\\wire".to_string());
498        assert!(id.is_escaped());
499        assert!(!id.is_sliced());
500        let id = Identifier::new("wire[3]".to_string());
501        assert!(!id.is_escaped());
502        assert!(id.is_sliced());
503        assert_eq!(id.get_bit_index(), Some(3));
504    }
505
506    #[test]
507    fn assume_escaped_identifier() {
508        let id = Identifier::new("C++".to_string());
509        assert!(id.is_escaped());
510    }
511
512    #[test]
513    fn identifier_emission() {
514        let id = Identifier::new("wire".to_string());
515        assert_eq!(id.emit_name(), "wire");
516        let id = Identifier::new("\\wire".to_string());
517        assert!(id.is_escaped());
518        assert_eq!(id.emit_name(), "\\wire ");
519        assert_eq!(format!("{id}"), "\\wire ");
520        let id = Identifier::new("wire[3]".to_string());
521        assert!(id.is_sliced());
522        assert_eq!(id.emit_name(), "wire[3]");
523    }
524
525    #[test]
526    fn test_implicits() {
527        let net: Net = "hey".into();
528        assert_ne!(*net.get_type(), DataType::boolean());
529        assert_ne!(*net.get_type(), DataType::tristate());
530        assert_eq!(*net.get_type(), DataType::logic());
531        assert_eq!(*net.get_type(), DataType::fourstate());
532    }
533}