logicsim/circuits/bus.rs
1use super::Wire;
2use crate::graph::*;
3
4fn mkname(name: String) -> String {
5 format!("BUS:{}", name)
6}
7
8/// Data structure that helps with managing buses, it allows you to connect &[[GateIndex]] to it as well as providing
9/// a &[[GateIndex]] to connect to other components.
10///
11/// It is basically syntactic sugar for a set of or gates.
12///
13/// # Example
14/// ```
15/// # use logicsim::{GateGraphBuilder,constant,Bus,ON};
16/// # let mut g = GateGraphBuilder::new();
17/// let input1 = constant(0x01u8);
18/// let input2 = constant(0x10u8);
19///
20/// let bus = Bus::new(&mut g, 8, "bus");
21/// bus.connect(&mut g, &input1);
22/// bus.connect(&mut g, &input2);
23///
24/// let output = g.output(bus.bits(), "result");
25///
26/// let ig = &g.init();
27/// assert_eq!(output.u8(ig), 0x11);
28/// ```
29#[derive(Debug, Clone)]
30pub struct Bus {
31 bits: Vec<GateIndex>,
32}
33impl Bus {
34 /// Returns a new [Bus] of width `width` with name `name`.
35 pub fn new<S: Into<String>>(g: &mut GateGraphBuilder, width: usize, name: S) -> Self {
36 let name = mkname(name.into());
37 Self {
38 bits: (0..width).map(|_| g.or(name.clone())).collect(),
39 }
40 }
41
42 /// Connects a &[[GateIndex]] to the bus, each bit of the output of the bus will be set to the or
43 /// of every corresponding bit in the inputs.
44 ///
45 /// # Panics
46 ///
47 /// Will panic if `other.len()` != `self.len()`. Use [connect_some](Bus::connect_some)
48 /// if this is not your desired behavior.
49 pub fn connect(&self, g: &mut GateGraphBuilder, other: &[GateIndex]) {
50 assert_eq!(
51 self.bits.len(),
52 other.len(),
53 "Use connect_some() to connect to a bus of a different width"
54 );
55 self.connect_some(g, other);
56 }
57
58 /// Connects a &[[GateIndex]] to the bus, each bit of the output of the bus will be set to the or
59 /// of every corresponding bit in the inputs.
60 ///
61 /// If there are excess bits in `other`, they won't get connected to the bus.
62 /// If there are missing bits in `other` only other.len() will be connected to the bus.
63 pub fn connect_some(&self, g: &mut GateGraphBuilder, other: &[GateIndex]) {
64 for (or, bit) in self.bits.iter().zip(other) {
65 g.dpush(*or, *bit);
66 }
67 }
68
69 /// Connects the bits of `other` to `self` and returns a clone of `self`.
70 // The signature is very intentional, one does not simply merge buses.
71 pub fn merge(&self, g: &mut GateGraphBuilder, other: Bus) -> Bus {
72 self.connect(g, other.bits());
73 self.clone()
74 }
75
76 /// Returns the width of the bus.
77 pub fn len(&self) -> usize {
78 self.bits.len()
79 }
80
81 /// Returns true if `self.len()` == 0.
82 pub fn is_empty(&self) -> bool {
83 self.bits.len() == 0
84 }
85
86 /// Returns a &[[GateIndex]] to connect to other components.
87 pub fn bits(&self) -> &[GateIndex] {
88 &self.bits
89 }
90
91 /// Returns the [GateIndex] of the `n`th bit in the bus.
92 ///
93 /// # Panics
94 ///
95 /// Will panic if `n` >= `self.len()`.
96 pub fn bx(&self, n: usize) -> GateIndex {
97 self.bits[n]
98 }
99
100 /// Returns the [GateIndex] of the 0th bit in the bus.
101 ///
102 /// # Panics
103 ///
104 /// Will panic if `self.is_empty()`.
105 pub fn b0(&self) -> GateIndex {
106 self.bits[0]
107 }
108
109 /// Connects the bus to a series of [Wires](Wire).
110 ///
111 /// # Panics
112 ///
113 /// Will panic if `self.len()` != `other.len()`.
114 pub fn split_wires(&self, g: &mut GateGraphBuilder, other: &mut [Wire]) {
115 assert_eq!(self.len(), other.len());
116 for (bit, wire) in self.bits.iter().zip(other) {
117 wire.connect(g, *bit)
118 }
119 }
120}
121
122impl Into<Vec<GateIndex>> for Bus {
123 fn into(self) -> Vec<GateIndex> {
124 self.bits
125 }
126}