prjunnamed_netlist/cell/
flip_flop.rs

1use crate::{Const, ControlNet, Design, Net, Value};
2
3/// A flip-flop cell.
4///
5/// The output is determined by the following rules:
6///
7/// - at the beginning of time, the output is set to `init_value`
8/// - whenever `clear` as active, the output is set to `clear_value`
9/// - whenever `clear` is not active, and an active edge happens on `clock`:
10///   - if `reset_over_enable` is true:
11///     - if `reset` is active, the output is set to `reset_value`
12///     - if `enable` is false, output value is unchanged
13///   - if `reset_over_enable` is false:
14///     - if `enable` is false, output value is unchanged
15///     - if `reset` is active, the output is set to `reset_value`
16///   - otherwise, the output is set to `data`
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct FlipFlop {
19    pub data: Value,
20    /// The clock.  The active edge is rising if it is a [`ControlNet::Pos`], and falling if it is
21    /// a [`ControlNet::Neg`].
22    pub clock: ControlNet,
23    /// Asynchronous reset.
24    pub clear: ControlNet,
25    /// Synchronous reset.
26    pub reset: ControlNet,
27    /// Clock enable.
28    pub enable: ControlNet,
29    /// If true, `reset` has priority over `enable`.  Otherwise, `enable` has priority over `reset`.
30    pub reset_over_enable: bool,
31
32    /// Must have the same width as `data`.
33    pub clear_value: Const,
34    /// Must have the same width as `data`.
35    pub reset_value: Const,
36    /// Must have the same width as `data`.
37    pub init_value: Const,
38}
39
40impl FlipFlop {
41    pub fn new(data: Value, clock: impl Into<ControlNet>) -> Self {
42        let size = data.len();
43        FlipFlop {
44            data,
45            clock: clock.into(),
46            clear: ControlNet::ZERO,
47            reset: ControlNet::ZERO,
48            enable: ControlNet::ONE,
49            reset_over_enable: false,
50            clear_value: Const::undef(size),
51            reset_value: Const::undef(size),
52            init_value: Const::undef(size),
53        }
54    }
55
56    pub fn with_data(self, data: impl Into<Value>) -> Self {
57        Self { data: data.into(), ..self }
58    }
59
60    pub fn with_clock(self, clock: impl Into<ControlNet>) -> Self {
61        Self { clock: clock.into(), ..self }
62    }
63
64    pub fn with_clear(self, clear: impl Into<ControlNet>) -> Self {
65        Self { clear: clear.into(), ..self }
66    }
67
68    pub fn with_clear_value(self, clear: impl Into<ControlNet>, clear_value: impl Into<Const>) -> Self {
69        Self { clear: clear.into(), clear_value: clear_value.into(), ..self }
70    }
71
72    pub fn with_reset(self, reset: impl Into<ControlNet>) -> Self {
73        Self { reset: reset.into(), reset_over_enable: false, ..self }
74    }
75
76    pub fn with_reset_value(self, reset: impl Into<ControlNet>, reset_value: impl Into<Const>) -> Self {
77        Self { reset: reset.into(), reset_over_enable: false, reset_value: reset_value.into(), ..self }
78    }
79
80    pub fn with_enable(self, enable: impl Into<ControlNet>) -> Self {
81        Self { enable: enable.into(), reset_over_enable: true, ..self }
82    }
83
84    pub fn with_init(self, value: impl Into<Const>) -> Self {
85        let value = value.into();
86        Self { clear_value: value.clone(), reset_value: value.clone(), init_value: value, ..self }
87    }
88
89    pub fn output_len(&self) -> usize {
90        self.data.len()
91    }
92
93    pub fn has_clock(&self) -> bool {
94        !self.clock.is_const()
95    }
96
97    pub fn has_enable(&self) -> bool {
98        !self.enable.is_always(true)
99    }
100
101    pub fn has_reset(&self) -> bool {
102        !self.reset.is_always(false)
103    }
104
105    pub fn has_reset_value(&self) -> bool {
106        !self.reset_value.is_undef()
107    }
108
109    pub fn has_clear(&self) -> bool {
110        !self.clear.is_always(false)
111    }
112
113    pub fn has_clear_value(&self) -> bool {
114        !self.clear_value.is_undef()
115    }
116
117    pub fn has_init_value(&self) -> bool {
118        !self.init_value.is_undef()
119    }
120
121    pub fn slice(&self, range: impl std::ops::RangeBounds<usize> + Clone) -> FlipFlop {
122        FlipFlop {
123            data: self.data.slice(range.clone()),
124            clock: self.clock,
125            clear: self.clear,
126            reset: self.reset,
127            enable: self.enable,
128            reset_over_enable: self.reset_over_enable,
129            clear_value: self.clear_value.slice(range.clone()),
130            reset_value: self.reset_value.slice(range.clone()),
131            init_value: self.init_value.slice(range.clone()),
132        }
133    }
134
135    pub fn remap_reset_over_enable(&mut self, design: &Design) {
136        if self.reset_over_enable {
137            return;
138        }
139        self.reset_over_enable = true;
140        if self.reset.is_always(false) || self.enable.is_always(true) {
141            return;
142        }
143        let reset = self.reset.into_pos(design);
144        let enable = self.enable.into_pos(design);
145        self.reset = ControlNet::Pos(design.add_and(reset, enable).unwrap_net());
146    }
147
148    pub fn remap_enable_over_reset(&mut self, design: &Design) {
149        if !self.reset_over_enable {
150            return;
151        }
152        self.reset_over_enable = false;
153        if self.reset.is_always(false) || self.enable.is_always(true) {
154            return;
155        }
156        let reset = self.reset.into_pos(design);
157        let enable = self.enable.into_pos(design);
158        self.enable = ControlNet::Pos(design.add_or(reset, enable).unwrap_net());
159    }
160
161    pub fn unmap_reset(&mut self, design: &Design) {
162        self.remap_enable_over_reset(design);
163        self.data = design.add_mux(self.reset, &self.reset_value, &self.data);
164        self.reset = ControlNet::ZERO;
165    }
166
167    pub fn unmap_enable(&mut self, design: &Design, output: &Value) {
168        self.remap_reset_over_enable(design);
169        self.data = design.add_mux(self.enable, &self.data, output);
170        self.enable = ControlNet::ONE;
171    }
172
173    pub fn invert(&mut self, design: &Design, output: &Value) -> Value {
174        self.data = design.add_not(&self.data);
175        self.clear_value = self.clear_value.not();
176        self.reset_value = self.reset_value.not();
177        self.init_value = self.init_value.not();
178        let new_output = design.add_void(self.data.len());
179        design.replace_value(output, design.add_not(&new_output));
180        new_output
181    }
182
183    pub fn visit(&self, mut f: impl FnMut(Net)) {
184        self.data.visit(&mut f);
185        self.clock.visit(&mut f);
186        self.enable.visit(&mut f);
187        self.reset.visit(&mut f);
188        self.clear.visit(&mut f);
189    }
190
191    pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
192        self.data.visit_mut(&mut f);
193        self.clock.visit_mut(&mut f);
194        self.enable.visit_mut(&mut f);
195        self.reset.visit_mut(&mut f);
196        self.clear.visit_mut(&mut f);
197    }
198}