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