prjunnamed_netlist/
cell.rs

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