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