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