Skip to main content

prjunnamed_netlist/
cell.rs

1use std::{borrow::Cow, hash::Hash};
2
3use crate::{ControlNet, Design, Net, TargetCellPurity, Trit, Value};
4
5mod decision;
6mod flip_flop;
7mod memory;
8mod io_buffer;
9mod target;
10mod instance;
11
12pub use decision::{MatchCell, AssignCell};
13pub use flip_flop::FlipFlop;
14pub use memory::{Memory, MemoryWritePort, MemoryReadPort, MemoryReadFlipFlop, MemoryPortRelation};
15pub use io_buffer::IoBuffer;
16pub use target::TargetCell;
17pub use instance::Instance;
18
19/// Compact, 16-byte representation for cells common in fine netlists.
20///
21/// This type is used internally within [`Design`]. Cells that can be
22/// represented with [`CellRepr`] get stored without a separate heap
23/// allocation. All others get represented as [`CellRepr::Coarse`].
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub(crate) enum CellRepr {
26    /// Constant.  There are always exactly three constant cells in a design,
27    /// occupying the first three indices, corresponding to the three possible values:
28    /// 0, 1, X (in that order).
29    Const(Trit),
30
31    /// Reserved index. Can be created with [`Design::add_void`] for later
32    /// replacement with [`Design::replace_value`], or left over
33    /// after [`CellRef::unalive`].
34    ///
35    /// [`CellRef::unalive`]: crate::CellRef::unalive
36    Void,
37
38    /// Represents an index taken by a cell with more than one bit of
39    /// output. Stores the base index of the cell in question.
40    Skip(u32),
41
42    Buf(Net),
43    Not(Net),
44    And(Net, Net),
45    Or(Net, Net),
46    Xor(Net, Net),
47    Mux(Net, Net, Net), // a ? b : c
48    Adc(Net, Net, Net), // a + b + ci
49    Aig(Net, bool, Net, bool),
50
51    Boxed(Box<Cell>),
52}
53
54/// A unit of logic.
55///
56/// Within a [`Design`], each cell is identified by a range of indices,
57/// with each index corresponding to one of the output bits of the cell.
58/// As such, the cell itself only contains information about its inputs,
59/// with the outputs being implicit.
60///
61/// (do note that cells without any outputs, such as [`output`][Cell::Output]
62/// or [`name`][Cell::Name], still get assigned an index)
63#[derive(Clone, Debug, PartialEq, Eq, Hash)]
64pub enum Cell {
65    Const(Trit),
66    Buf(Value),
67    Not(Value),
68    /// `a & b`.
69    ///
70    /// Has short-circuiting behavior for inputs containing `X` — if the other
71    /// bit is `0`, the output is `0` and the `X` doesn't propagate.
72    And(Value, Value),
73    /// `a | b`.
74    ///
75    /// Has short-circuiting behavior for inputs containing `X` — if the other
76    /// bit is `1`, the output is `1` and the `X` doesn't propagate.
77    Or(Value, Value),
78    Xor(Value, Value),
79    /// `a ? b : c`.
80    ///
81    /// Muxes are glitch free — if `a` is `X`, the bit positions that match
82    /// between `b` and `c` still have a defined value. The `X` propagates
83    /// only at the positions where `b` and `c` differ.
84    Mux(Net, Value, Value),
85    /// `a + b + ci` — add with carry.
86    ///
87    /// Output is one bit wider than `a` and `b` — the most significant bit
88    /// is the carry-out.
89    ///
90    /// `X`s in the input propagate only to the more significant bits, and
91    /// do not affect the less significant bits.
92    Adc(Value, Value, Net), // a + b + ci
93    /// `a & b`, single-bit wide, both inputs freely invertible.
94    ///
95    /// A variant of the `And` cell meant for fine logic optimization.
96    Aig(ControlNet, ControlNet),
97
98    Eq(Value, Value),
99    ULt(Value, Value),
100    SLt(Value, Value),
101
102    /// `a << (b * c)`. The bottom bits are filled with zeros.
103    ///
104    /// General notes for all shift cells:
105    /// - output is the same width as `a`. If you need wider output,
106    ///   zero-extend or sign-extend your input first, as appropriate.
107    /// - the shift count does not wrap. If you shift by more than
108    ///   `a.len() - 1`, you get the same result as if you made an equivalent
109    ///   sequence of 1-bit shifts (i.e. all zeros, all sign bits, or all `X`,
110    ///   as appropriate).
111    /// - shift cells are one of the few cells which *do not* expect their
112    ///   inputs to be of the same width. In fact, that is the expected case.
113    Shl(Value, Value, u32),
114    /// `a >> (b * c)`. The top bits are filled with zeros.
115    ///
116    /// See also [general notes above][Cell::Shl].
117    UShr(Value, Value, u32),
118    /// `a >> (b * c)`. The top bits are filled with copies of the top bit
119    /// of the input.
120    ///
121    /// `a` must be at least one bit wide (as otherwise there would be no sign
122    /// bit to propagate, and while there wouldn't be anywhere to propagate it
123    /// *to*, it's an edge-case it doesn't make sense to bother handling).
124    ///
125    /// See also [general notes above][Cell::Shl].
126    SShr(Value, Value, u32),
127    /// `a >> (b * c)`. The top bits are filled with `X`.
128    ///
129    /// See also [general notes above][Cell::Shl].
130    XShr(Value, Value, u32),
131
132    // future possibilities: popcnt, count leading/trailing zeros, powers
133    Mul(Value, Value),
134    UDiv(Value, Value),
135    UMod(Value, Value),
136    SDivTrunc(Value, Value),
137    SDivFloor(Value, Value),
138    SModTrunc(Value, Value),
139    SModFloor(Value, Value),
140
141    Match(MatchCell),
142    Assign(AssignCell),
143
144    Dff(FlipFlop),
145    Memory(Memory),
146    IoBuf(IoBuffer),
147    Target(TargetCell),
148    Other(Instance),
149
150    /// Design input of a given width.
151    ///
152    /// If synthesizing for a specified target, and not in out-of-context mode,
153    /// an input will be replaced with an [`IoBuffer`] and attached to a pin on
154    /// the target device.
155    Input(String, usize),
156    /// Design output. Attaches a name to a given value.
157    ///
158    /// If synthesizing for a specified target, and not in out-of-context mode,
159    /// an output will be replaced with an [`IoBuffer`] and attached to a pin on
160    /// the target device.
161    Output(String, Value),
162    /// Attaches a name to a given value for debugging.
163    ///
164    /// `Name` keeps a given value alive during optimization and makes it easily
165    /// available to be poked at during simulation.
166    ///
167    /// Do note that the [`unname` pass][unname], which runs during
168    /// target-dependent synthesis, replaces all `Name` cells with [`Debug`]
169    /// cells.
170    ///
171    /// [unname]: ../prjunnamed_generic/fn.unname.html
172    /// [`Debug`]: Cell::Debug
173    Name(String, Value),
174    /// Tentatively attaches a name to a given value.
175    ///
176    /// `Debug` gives a name to a particular value, without insisting on keeping
177    /// it alive during optimization. This helps correlate the output of
178    /// synthesis with the corresponding input logic.
179    ///
180    /// If at any point a value is being kept alive only by a `Debug` cell,
181    /// it will be optimized out and the input to the `Debug` cell will
182    /// be replaced with `X`.
183    ///
184    /// See also: [`Name`][Cell::Name].
185    Debug(String, Value),
186}
187
188impl Cell {
189    pub fn validate(&self, design: &Design) {
190        match self {
191            Cell::Const(_) => (),
192            Cell::Buf(_) => (),
193            Cell::Not(_) => (),
194            Cell::Aig(..) => (),
195            Cell::And(arg1, arg2)
196            | Cell::Or(arg1, arg2)
197            | Cell::Xor(arg1, arg2)
198            | Cell::Mux(_, arg1, arg2)
199            | Cell::Adc(arg1, arg2, _)
200            | Cell::Eq(arg1, arg2)
201            | Cell::ULt(arg1, arg2)
202            | Cell::Mul(arg1, arg2)
203            | Cell::UDiv(arg1, arg2)
204            | Cell::UMod(arg1, arg2) => assert_eq!(arg1.len(), arg2.len()),
205            Cell::SLt(arg1, arg2)
206            | Cell::SDivTrunc(arg1, arg2)
207            | Cell::SDivFloor(arg1, arg2)
208            | Cell::SModTrunc(arg1, arg2)
209            | Cell::SModFloor(arg1, arg2) => {
210                assert_eq!(arg1.len(), arg2.len());
211                assert!(!arg1.is_empty());
212            }
213
214            Cell::Shl(..) => (),
215            Cell::UShr(..) => (),
216            Cell::SShr(arg1, _, _) => assert!(!arg1.is_empty()),
217            Cell::XShr(..) => (),
218
219            Cell::Match(match_cell) => {
220                for alternates in &match_cell.patterns {
221                    for pattern in alternates {
222                        assert_eq!(match_cell.value.len(), pattern.len());
223                    }
224                }
225            }
226            Cell::Assign(assign_cell) => {
227                assert!(assign_cell.value.len() >= assign_cell.update.len() + assign_cell.offset);
228            }
229
230            Cell::Dff(flip_flop) => {
231                assert_eq!(flip_flop.data.len(), flip_flop.init_value.len());
232                assert_eq!(flip_flop.data.len(), flip_flop.clear_value.len());
233                assert_eq!(flip_flop.data.len(), flip_flop.reset_value.len());
234            }
235            Cell::Memory(memory) => {
236                assert_eq!(memory.init_value.len(), memory.depth * memory.width);
237                for port in &memory.write_ports {
238                    assert_eq!(port.data.len(), port.mask.len());
239                    if memory.width == 0 {
240                        assert_eq!(port.data.len(), 0);
241                    } else {
242                        assert_eq!(port.data.len() % memory.width, 0);
243                        let wide_factor = port.data.len() / memory.width;
244                        assert!(wide_factor.is_power_of_two());
245                        assert_eq!(memory.depth % wide_factor, 0);
246                    }
247                }
248                for port in &memory.read_ports {
249                    if memory.width == 0 {
250                        assert_eq!(port.data_len, 0);
251                    } else {
252                        assert_eq!(port.data_len % memory.width, 0);
253                        let wide_factor = port.data_len / memory.width;
254                        assert!(wide_factor.is_power_of_two());
255                        assert_eq!(memory.depth % wide_factor, 0);
256                    }
257                    if let Some(ref flip_flop) = port.flip_flop {
258                        assert_eq!(flip_flop.clear_value.len(), port.data_len);
259                        assert_eq!(flip_flop.reset_value.len(), port.data_len);
260                        assert_eq!(flip_flop.init_value.len(), port.data_len);
261                        assert_eq!(flip_flop.relations.len(), memory.write_ports.len());
262                        for (write_port_index, &relation) in flip_flop.relations.iter().enumerate() {
263                            if relation != MemoryPortRelation::Undefined {
264                                assert_eq!(memory.write_ports[write_port_index].clock, flip_flop.clock);
265                            }
266                        }
267                    }
268                }
269            }
270            Cell::IoBuf(io_buffer) => {
271                assert_eq!(io_buffer.output.len(), io_buffer.io.len());
272            }
273            Cell::Target(target_cell) => {
274                let prototype = design.target_prototype(target_cell);
275                assert_eq!(target_cell.params.len(), prototype.params.len());
276                for (param, value) in prototype.params.iter().zip(target_cell.params.iter()) {
277                    assert!(param.kind.is_valid(value));
278                }
279                assert_eq!(target_cell.inputs.len(), prototype.input_len);
280                assert_eq!(target_cell.output_len, prototype.output_len);
281                assert_eq!(target_cell.ios.len(), prototype.io_len);
282                let target = design.target().unwrap();
283                target.validate(design, target_cell);
284            }
285            Cell::Other(_instance) => {
286                // TODO
287            }
288            Cell::Input(..) => (),
289            Cell::Output(..) => (),
290            Cell::Name(..) | Cell::Debug(..) => (),
291        }
292    }
293
294    /// If possible, return a cell that computes only a slice of the outputs
295    /// of this cell.
296    pub fn slice(&self, range: impl std::ops::RangeBounds<usize> + Clone) -> Option<Cell> {
297        match self {
298            Cell::Buf(arg) => Some(Cell::Buf(arg.slice(range))),
299            Cell::Not(arg) => Some(Cell::Not(arg.slice(range))),
300            Cell::And(arg1, arg2) => Some(Cell::And(arg1.slice(range.clone()), arg2.slice(range))),
301            Cell::Or(arg1, arg2) => Some(Cell::Or(arg1.slice(range.clone()), arg2.slice(range))),
302            Cell::Xor(arg1, arg2) => Some(Cell::Xor(arg1.slice(range.clone()), arg2.slice(range))),
303            Cell::Mux(arg1, arg2, arg3) => Some(Cell::Mux(*arg1, arg2.slice(range.clone()), arg3.slice(range))),
304            Cell::Dff(flip_flop) => Some(Cell::Dff(flip_flop.slice(range))),
305            Cell::IoBuf(io_buffer) => Some(Cell::IoBuf(io_buffer.slice(range))),
306            _ => None,
307        }
308    }
309}
310
311impl<'a> From<&'a Cell> for Cow<'a, Cell> {
312    fn from(value: &'a Cell) -> Self {
313        Cow::Borrowed(value)
314    }
315}
316
317impl From<Cell> for Cow<'_, Cell> {
318    fn from(value: Cell) -> Self {
319        Cow::Owned(value)
320    }
321}
322
323impl CellRepr {
324    pub fn get(&self) -> Cow<'_, Cell> {
325        match *self {
326            CellRepr::Void => unreachable!("void cell"),
327            CellRepr::Skip(_) => unreachable!("skip cell"),
328
329            CellRepr::Const(trit) => Cow::Owned(Cell::Const(trit)),
330            CellRepr::Buf(arg) => Cow::Owned(Cell::Buf(Value::from(arg))),
331            CellRepr::Not(arg) => Cow::Owned(Cell::Not(Value::from(arg))),
332            CellRepr::And(arg1, arg2) => Cow::Owned(Cell::And(Value::from(arg1), Value::from(arg2))),
333            CellRepr::Or(arg1, arg2) => Cow::Owned(Cell::Or(Value::from(arg1), Value::from(arg2))),
334            CellRepr::Xor(arg1, arg2) => Cow::Owned(Cell::Xor(Value::from(arg1), Value::from(arg2))),
335            CellRepr::Mux(arg1, arg2, arg3) => Cow::Owned(Cell::Mux(arg1, Value::from(arg2), Value::from(arg3))),
336            CellRepr::Adc(arg1, arg2, arg3) => Cow::Owned(Cell::Adc(Value::from(arg1), Value::from(arg2), arg3)),
337            CellRepr::Aig(arg1, inv1, arg2, inv2) => {
338                Cow::Owned(Cell::Aig(ControlNet::from_net_invert(arg1, inv1), ControlNet::from_net_invert(arg2, inv2)))
339            }
340
341            CellRepr::Boxed(ref cell) => Cow::Borrowed(cell),
342        }
343    }
344}
345
346impl From<Cell> for CellRepr {
347    fn from(value: Cell) -> Self {
348        match value {
349            Cell::Buf(arg) if arg.len() == 1 => CellRepr::Buf(arg[0]),
350            Cell::Not(arg) if arg.len() == 1 => CellRepr::Not(arg[0]),
351            Cell::And(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::And(arg1[0], arg2[0]),
352            Cell::Or(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Or(arg1[0], arg2[0]),
353            Cell::Xor(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Xor(arg1[0], arg2[0]),
354            Cell::Mux(arg1, arg2, arg3) if arg2.len() == 1 && arg3.len() == 1 => CellRepr::Mux(arg1, arg2[0], arg3[0]),
355            Cell::Adc(arg1, arg2, arg3) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Adc(arg1[0], arg2[0], arg3),
356            Cell::Aig(arg1, arg2) => CellRepr::Aig(arg1.net(), arg1.is_negative(), arg2.net(), arg2.is_negative()),
357
358            cell => CellRepr::Boxed(Box::new(cell)),
359        }
360    }
361}
362
363impl CellRepr {
364    pub fn output_len(&self) -> usize {
365        match self {
366            CellRepr::Void => unreachable!("void cell"),
367            CellRepr::Skip(_) => unreachable!("skip cell"),
368
369            CellRepr::Const(_)
370            | CellRepr::Buf(..)
371            | CellRepr::Not(..)
372            | CellRepr::And(..)
373            | CellRepr::Or(..)
374            | CellRepr::Xor(..)
375            | CellRepr::Mux(..)
376            | CellRepr::Aig(..) => 1,
377            CellRepr::Adc(..) => 2,
378
379            CellRepr::Boxed(cell) => cell.output_len(),
380        }
381    }
382
383    pub(crate) fn visit(&self, mut f: impl FnMut(Net)) {
384        match self {
385            CellRepr::Void => unreachable!("void cell"),
386            CellRepr::Skip(_) => unreachable!("skip cell"),
387
388            CellRepr::Const(_) => (),
389            CellRepr::Buf(arg) | CellRepr::Not(arg) => arg.visit(&mut f),
390            CellRepr::And(arg1, arg2)
391            | CellRepr::Or(arg1, arg2)
392            | CellRepr::Xor(arg1, arg2)
393            | CellRepr::Aig(arg1, _, arg2, _) => {
394                arg1.visit(&mut f);
395                arg2.visit(&mut f);
396            }
397            CellRepr::Mux(arg1, arg2, arg3) | CellRepr::Adc(arg1, arg2, arg3) => {
398                arg1.visit(&mut f);
399                arg2.visit(&mut f);
400                arg3.visit(&mut f);
401            }
402
403            CellRepr::Boxed(cell) => cell.visit(&mut f),
404        }
405    }
406
407    pub(crate) fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
408        match self {
409            CellRepr::Void => unreachable!("void cell"),
410            CellRepr::Skip(_) => unreachable!("skip cell"),
411
412            CellRepr::Const(_) => (),
413            CellRepr::Buf(arg) | CellRepr::Not(arg) => arg.visit_mut(&mut f),
414            CellRepr::And(arg1, arg2)
415            | CellRepr::Or(arg1, arg2)
416            | CellRepr::Xor(arg1, arg2)
417            | CellRepr::Aig(arg1, _, arg2, _) => {
418                arg1.visit_mut(&mut f);
419                arg2.visit_mut(&mut f);
420            }
421            CellRepr::Mux(arg1, arg2, arg3) | CellRepr::Adc(arg1, arg2, arg3) => {
422                arg1.visit_mut(&mut f);
423                arg2.visit_mut(&mut f);
424                arg3.visit_mut(&mut f);
425            }
426
427            CellRepr::Boxed(cell) => cell.visit_mut(&mut f),
428        }
429    }
430}
431
432impl Cell {
433    pub fn output_len(&self) -> usize {
434        match self {
435            Cell::Const(_) => 1,
436            Cell::Buf(arg) | Cell::Not(arg) => arg.len(),
437            Cell::And(arg1, arg2) | Cell::Or(arg1, arg2) | Cell::Xor(arg1, arg2) | Cell::Mux(_, arg1, arg2) => {
438                debug_assert_eq!(arg1.len(), arg2.len());
439                arg1.len()
440            }
441            Cell::Adc(arg1, arg2, _) => {
442                debug_assert_eq!(arg1.len(), arg2.len());
443                arg1.len() + 1
444            }
445            Cell::Aig(..) => 1,
446
447            Cell::Eq(..) | Cell::ULt(..) | Cell::SLt(..) => 1,
448
449            Cell::Shl(arg1, _, _) | Cell::UShr(arg1, _, _) | Cell::SShr(arg1, _, _) | Cell::XShr(arg1, _, _) => {
450                arg1.len()
451            }
452
453            Cell::Mul(arg1, arg2)
454            | Cell::UDiv(arg1, arg2)
455            | Cell::UMod(arg1, arg2)
456            | Cell::SDivTrunc(arg1, arg2)
457            | Cell::SDivFloor(arg1, arg2)
458            | Cell::SModTrunc(arg1, arg2)
459            | Cell::SModFloor(arg1, arg2) => {
460                debug_assert_eq!(arg1.len(), arg2.len());
461                arg1.len()
462            }
463
464            Cell::Match(match_cell) => match_cell.output_len(),
465            Cell::Assign(assign_cell) => assign_cell.output_len(),
466
467            Cell::Dff(flip_flop) => flip_flop.output_len(),
468            Cell::Memory(memory) => memory.output_len(),
469            Cell::IoBuf(io_buffer) => io_buffer.output_len(),
470            Cell::Target(target_cell) => target_cell.output_len,
471            Cell::Other(instance) => instance.output_len(),
472
473            Cell::Input(_, width) => *width,
474            Cell::Output(..) => 0,
475            Cell::Name(..) | Cell::Debug(..) => 0,
476        }
477    }
478
479    pub fn has_effects(&self, design: &Design) -> bool {
480        match self {
481            Cell::IoBuf(_) | Cell::Other(_) | Cell::Input(..) | Cell::Output(..) | Cell::Name(..) => true,
482            Cell::Target(target_cell) => design.target_prototype(target_cell).purity == TargetCellPurity::HasEffects,
483            _ => false,
484        }
485    }
486
487    pub fn has_state(&self, design: &Design) -> bool {
488        match self {
489            Cell::IoBuf(_)
490            | Cell::Other(_)
491            | Cell::Input(..)
492            | Cell::Output(..)
493            | Cell::Name(..)
494            | Cell::Memory(..)
495            | Cell::Dff(..) => true,
496            Cell::Target(target_cell) => design.target_prototype(target_cell).purity != TargetCellPurity::Pure,
497            _ => false,
498        }
499    }
500
501    pub fn visit(&self, mut f: impl FnMut(Net)) {
502        match self {
503            Cell::Const(_) => (),
504            Cell::Input(..) => (),
505            Cell::Buf(arg) | Cell::Not(arg) | Cell::Output(_, arg) | Cell::Name(_, arg) | Cell::Debug(_, arg) => {
506                arg.visit(&mut f)
507            }
508            Cell::And(arg1, arg2)
509            | Cell::Or(arg1, arg2)
510            | Cell::Xor(arg1, arg2)
511            | Cell::Mul(arg1, arg2)
512            | Cell::UDiv(arg1, arg2)
513            | Cell::UMod(arg1, arg2)
514            | Cell::SDivTrunc(arg1, arg2)
515            | Cell::SDivFloor(arg1, arg2)
516            | Cell::SModTrunc(arg1, arg2)
517            | Cell::SModFloor(arg1, arg2)
518            | Cell::Eq(arg1, arg2)
519            | Cell::ULt(arg1, arg2)
520            | Cell::SLt(arg1, arg2)
521            | Cell::Shl(arg1, arg2, _)
522            | Cell::UShr(arg1, arg2, _)
523            | Cell::SShr(arg1, arg2, _)
524            | Cell::XShr(arg1, arg2, _) => {
525                arg1.visit(&mut f);
526                arg2.visit(&mut f);
527            }
528            Cell::Aig(arg1, arg2) => {
529                arg1.visit(&mut f);
530                arg2.visit(&mut f);
531            }
532            Cell::Mux(net, value1, value2) | Cell::Adc(value1, value2, net) => {
533                value1.visit(&mut f);
534                value2.visit(&mut f);
535                net.visit(&mut f);
536            }
537            Cell::Match(match_cell) => match_cell.visit(&mut f),
538            Cell::Assign(assign_cell) => assign_cell.visit(&mut f),
539            Cell::Dff(flip_flop) => flip_flop.visit(&mut f),
540            Cell::Memory(memory) => memory.visit(&mut f),
541            Cell::IoBuf(io_buffer) => io_buffer.visit(&mut f),
542            Cell::Target(target_cell) => target_cell.visit(&mut f),
543            Cell::Other(instance) => instance.visit(&mut f),
544        }
545    }
546
547    pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
548        match self {
549            Cell::Const(_) => (),
550            Cell::Input(..) => (),
551            Cell::Buf(arg) | Cell::Not(arg) | Cell::Output(_, arg) | Cell::Name(_, arg) | Cell::Debug(_, arg) => {
552                arg.visit_mut(&mut f)
553            }
554            Cell::And(arg1, arg2)
555            | Cell::Or(arg1, arg2)
556            | Cell::Xor(arg1, arg2)
557            | Cell::Mul(arg1, arg2)
558            | Cell::UDiv(arg1, arg2)
559            | Cell::UMod(arg1, arg2)
560            | Cell::SDivTrunc(arg1, arg2)
561            | Cell::SDivFloor(arg1, arg2)
562            | Cell::SModTrunc(arg1, arg2)
563            | Cell::SModFloor(arg1, arg2)
564            | Cell::Eq(arg1, arg2)
565            | Cell::ULt(arg1, arg2)
566            | Cell::SLt(arg1, arg2)
567            | Cell::Shl(arg1, arg2, _)
568            | Cell::UShr(arg1, arg2, _)
569            | Cell::SShr(arg1, arg2, _)
570            | Cell::XShr(arg1, arg2, _) => {
571                arg1.visit_mut(&mut f);
572                arg2.visit_mut(&mut f);
573            }
574            Cell::Aig(arg1, arg2) => {
575                arg1.visit_mut(&mut f);
576                arg2.visit_mut(&mut f);
577            }
578            Cell::Mux(net, value1, value2) | Cell::Adc(value1, value2, net) => {
579                value1.visit_mut(&mut f);
580                value2.visit_mut(&mut f);
581                net.visit_mut(&mut f);
582            }
583            Cell::Match(match_cell) => match_cell.visit_mut(&mut f),
584            Cell::Assign(assign_cell) => assign_cell.visit_mut(&mut f),
585            Cell::Dff(flip_flop) => flip_flop.visit_mut(&mut f),
586            Cell::Memory(memory) => memory.visit_mut(&mut f),
587            Cell::IoBuf(io_buffer) => io_buffer.visit_mut(&mut f),
588            Cell::Target(target_cell) => target_cell.visit_mut(&mut f),
589            Cell::Other(instance) => instance.visit_mut(&mut f),
590        }
591    }
592}
593
594#[cfg(test)]
595mod test {
596    use crate::cell::CellRepr;
597
598    #[test]
599    fn test_size() {
600        assert!(size_of::<CellRepr>() == 16);
601    }
602}