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