prjunnamed_generic/
simplify.rs

1use prjunnamed_netlist::{Cell, CellRef, ControlNet, Design, FlipFlop, IoBuffer, Net, ParamValue, Trit, Value};
2use prjunnamed_pattern::{netlist_replace, patterns::*};
3
4pub fn simplify(design: &mut Design) -> bool {
5    let rules = netlist_replace! {
6        [PBuf [PAny@a]]                 => a;
7
8        [PNot [PConst@a]]               => a.not();
9        [PNot [PNot [PAny@a]]]          => a;
10
11        [PAnd [PConst@a] [PConst@b]]    => a.and(b);
12        [PAnd [PAny@a]   [POnes]]       => a;
13        [PAnd [POnes]    [PAny@a]]      => a;
14        [PAnd [PAny@a]   [PZero]]       => Value::zero(a.len());
15        [PAnd [PZero]    [PAny@a]]      => Value::zero(a.len());
16
17        [POr  [PConst@a] [PConst@b]]    => a.or(b);
18        [POr  [PAny@a]   [PZero]]       => a;
19        [POr  [PZero]    [PAny@a]]      => a;
20        [POr  [PAny@a]   [POnes]]       => Value::ones(a.len());
21        [POr  [POnes]    [PAny@a]]      => Value::ones(a.len());
22
23        [PXor [PConst@a] [PConst@b]]    => a.xor(b);
24        [PXor [PAny@a]   [PZero]]       => a;
25        [PXor [PZero]    [PAny@a]]      => a;
26        [PXor [PAny@a]   [POnes]]       => design.add_not(a);
27        [PXor [POnes]    [PAny@a]]      => design.add_not(a);
28        [PXor [PAny@a]   [PUndef]]      => Value::undef(a.len());
29        [PXor [PUndef]   [PAny@a]]      => Value::undef(a.len());
30        [PXor [PAny@a]   [PAny@b]]      if a == b => Value::zero(a.len());
31
32        [PAnd [PAny@a] [PNot [PAny@b]]] if a == b => Value::zero(a.len());
33        [PAnd [PNot [PAny@a]] [PAny@b]] if a == b => Value::zero(a.len());
34        [POr  [PAny@a] [PNot [PAny@b]]] if a == b => Value::ones(a.len());
35        [POr  [PNot [PAny@a]] [PAny@b]] if a == b => Value::ones(a.len());
36        [PXor [PAny@a] [PNot [PAny@b]]] if a == b => Value::ones(a.len());
37        [PXor [PNot [PAny@a]] [PAny@b]] if a == b => Value::ones(a.len());
38
39        [PMux [POnes]    [PAny@a]   [PAny]]         => a;
40        [PMux [PZero]    [PAny]     [PAny@b]]       => b;
41        [PMux [PAny]     [PAny@a]   [PUndef]]       => a;
42        [PMux [PAny]     [PUndef]   [PAny@b]]       => b;
43        [PMux [PAny]     [PAny@a]   [PAny@b]]       if a == b => a;
44
45        [PMux@y [PAny@s] [POnes]    [PZero]]        => Value::from(s).sext(y.len());
46        [PMux@y [PAny@s] [PZero]    [POnes]]        => design.add_not(s).sext(y.len());
47
48        [PAnd [PNot [PAny@a]] [PNot [PAny@b]]]      => design.add_not(design.add_or (a, b));
49        [POr  [PNot [PAny@a]] [PNot [PAny@b]]]      => design.add_not(design.add_and(a, b));
50
51        [PXor [PNot [PAny@a]] [PNot [PAny@b]]]      => design.add_xor(a, b);
52        [PXor [PNot [PAny@a]] [PAny@b]]             => design.add_not(design.add_xor(a, b));
53        [PXor [PAny@a]        [PNot [PAny@b]]]      => design.add_not(design.add_xor(a, b));
54
55        [PMux [PNot [PAny@s]] [PAny@a] [PAny@b]]    => design.add_mux(s, b, a);
56
57        [PAdc   [PConst@a] [PConst@b] [PConst@c]]   => a.adc(b, c);
58        [PAdc@y [PAny@a]   [PZero]    [PZero]]      => a.zext(y.len());
59        [PAdc@y [PZero]    [PAny@b]   [PZero]]      => b.zext(y.len());
60        [PAdc@y [PZero]    [PZero]    [PAny@c]]     => Value::from(c).zext(y.len());
61
62        [PAdc   [PAny@a]   [PAny@b]   [PAny@c]]     if let Some(y) = adc_split(design, a, b, c) => y;
63        [PAdc   [PAny@a]   [PAny@b]   [PAny@c]]     if let Some(y) = adc_unsext(design, a, b, c) => y;
64
65        [PAdc@y [PAdc [PAny@a] [PAny@b] [PZero]] [PZExt [PAny@c]] [PZero]] if c.len() == 1 =>
66            design.add_adc(a, b, c[0]).zext(y.len());
67
68        [PEq  [PConst@a] [PConst@b]]    => a.eq(b);
69        [PEq  [PAny@a]   [POnes]]       if a.len() == 1 => a;
70        [PEq  [POnes]    [PAny@a]]      if a.len() == 1 => a;
71        [PEq  [PAny@a]   [PZero]]       if a.len() == 1 => design.add_not(a);
72        [PEq  [PZero]    [PAny@a]]      if a.len() == 1 => design.add_not(a);
73        [PEq  [PAny@a]   [PAny@b]]      if a == b => Trit::One;
74
75        [PULt [PConst@a] [PConst@b]]    => a.ult(b);
76        [PULt [PAny]     [PZero]]       => Trit::Zero;
77        [PULt [POnes]    [PAny]]        => Trit::Zero;
78        [PULt [PHasX]    [PAny]]        => Trit::Undef;
79        [PULt [PAny]     [PHasX]]       => Trit::Undef;
80        [PULt [PAny@a]   [PAny@b]]      if a == b => Trit::Zero;
81
82        [PSLt [PConst@a] [PConst@b]]    => a.slt(b);
83        [PSLt [PHasX]    [PAny]]        => Trit::Undef;
84        [PSLt [PAny]     [PHasX]]       => Trit::Undef;
85        [PSLt [PAny@a]   [PAny@b]]      if a == b => Trit::Zero;
86
87        [PShl    [PAny@a] [PConst@b] [PAny@s]]  => a.shl(b, s);
88        [PShl    [PAny@a] [PAny]     [PZero]]   => a;
89        [PShl@y  [PZero]  [PAny]     [PAny]]    => Value::zero(y.len());
90
91        [PUShr   [PAny@a] [PConst@b] [PAny@s]]  => a.ushr(b, s);
92        [PUShr   [PAny@a] [PAny]     [PZero]]   => a;
93        [PUShr@y [PZero]  [PAny]     [PAny]]    => Value::zero(y.len());
94
95        [PSShr   [PAny@a] [PConst@b] [PAny@s]]  => a.sshr(b, s);
96        [PSShr   [PAny@a] [PAny]     [PZero]]   => a;
97        [PSShr@y [PZero]  [PAny]     [PAny]]    => Value::zero(y.len());
98        [PSShr@y [POnes]  [PAny]     [PAny]]    => Value::ones(y.len());
99
100        [PXShr   [PAny@a] [PConst@b] [PAny@s]]  => a.xshr(b, s);
101        [PXShr   [PAny@a] [PAny]     [PZero]]   => a;
102        [PXShr@y [PZero]  [PAny]     [PAny]]    => Value::zero(y.len());
103
104        [PMul    [PConst@a] [PConst@b]] => a.mul(b);
105        [PMul@y  [PAny]     [PHasX]]    => Value::undef(y.len());
106        [PMul@y  [PHasX]    [PAny]]     => Value::undef(y.len());
107        [PMul@y  [PAny]     [PZero]]    => Value::zero(y.len());
108        [PMul@y  [PZero]    [PAny]]     => Value::zero(y.len());
109        [PMul    [PAny@a]   [PPow2@b]]  => a.shl(Trit::One, b);
110        [PMul    [PPow2@a]  [PAny@b]]   => b.shl(Trit::One, a);
111
112        // [PUDiv   [PConst@a] [PConst@b]] => a.udiv(b);
113        [PUDiv@y [PZero]    [PAny]]     => Value::zero(y.len());
114        [PUDiv@y [PAny]     [PZero]]    => Value::undef(y.len());
115        [PUDiv   [PAny@a]   [PPow2@b]]  => a.ushr(Trit::One, b);
116
117        // [PUMod   [PConst@a] [PConst@b]] => a.umod(b);
118        [PUMod@y [PZero]    [PAny]]     => Value::zero(y.len());
119        [PUMod@y [PAny]     [PZero]]    => Value::undef(y.len());
120        [PUMod   [PAny@a]   [PPow2@b]]  =>
121            if (b as usize) < a.len() { Value::from(&a[..(b as usize)]).zext(a.len()) } else { a };
122
123        [PSDivTrunc@y [PZero] [PAny]]   => Value::zero(y.len());
124        [PSDivTrunc@y [PAny]  [PZero]]  => Value::undef(y.len());
125        [PSModTrunc@y [PZero] [PAny]]   => Value::zero(y.len());
126        [PSModTrunc@y [PAny]  [PZero]]  => Value::undef(y.len());
127
128        [PSDivFloor@y [PZero] [PAny]]   => Value::zero(y.len());
129        [PSDivFloor@y [PAny]  [PZero]]  => Value::undef(y.len());
130        [PSModFloor@y [PZero] [PAny]]   => Value::zero(y.len());
131        [PSModFloor@y [PAny]  [PZero]]  => Value::undef(y.len());
132
133        [PDff@ff [PAny]] if ff.clear.is_always(true) => Value::from(ff.clear_value);
134
135        [PDff@ff [PMux [PAny@r] [PConst@rv] [PAny@d]]] if ff.reset.is_always(false) =>
136            design.add_dff(ff.clone().with_data(d).with_reset_value(ControlNet::Pos(r), rv));
137        [PDff@ff [PMux [PAny@r] [PAny@d] [PConst@rv]]] if ff.reset.is_always(false) =>
138            design.add_dff(ff.clone().with_data(d).with_reset_value(ControlNet::Neg(r), rv));
139
140        [PBind@ffq [PDff@ff [PMux [PAny@en] [PAny@d] [PAny@q]]]] if ff.enable.is_always(true) && ffq == q =>
141            design.add_dff(ff.clone().with_data(d).with_enable(ControlNet::Pos(en)));
142        [PBind@ffq [PDff@ff [PMux [PAny@en] [PAny@q] [PAny@d]]]] if ff.enable.is_always(true) && ffq == q =>
143            design.add_dff(ff.clone().with_data(d).with_enable(ControlNet::Neg(en)));
144    };
145
146    for cell_ref in design.iter_cells() {
147        // Fold inverters into controls first. This only ever replaces the cells themselves.
148        fold_controls(design, cell_ref);
149        // Rules that match individual bits of a cell are more powerful, but some rules must match an entire cell.
150        let value = cell_ref.output();
151        if rules(design, &value) {
152            continue;
153        }
154        for net in &value {
155            rules(design, &Value::from(net));
156        }
157    }
158    design.compact()
159}
160
161/// Finds positions within an `adc` cell where the carry chain up to the position
162/// doesn't affect output bits past the position, then splits the cell into smaller
163/// `adc` cells at these positions.
164///
165/// This function recognizes the following cases:
166///
167/// 1. `a` and `b` have the same net at position `i`:
168///
169///    ```
170///       { a7 a6 a5 ab4 a3 a2 a1 a0 } +
171///       { b7 b6 b5 ab4 b3 b2 b1 b0 } + ci =
172///    { y8 y7 y6 y5  y4 y3 y2 y1 y0 }
173///    ```
174///
175///    In this case, the carry out of position `i` will always be equal to the value
176///    of the common net.  The sum at that position will be equal to carry out of position
177///    `i - 1` (or to carry input, for position 0).  The above example gets split into two
178///    `adc` cells:
179///
180///    ```
181///    { y8 y7 y6 y5 } =
182///       { a7 a6 a5 } +
183///       { b7 b6 b5 } + ab4
184///
185///    { y4 y3 y2 y1 y0 } =
186///       { a3 a2 a1 a0 } +
187///       { b3 b2 b1 b0 } + ci
188///    ```
189///
190/// 2. The low bit of `a` (or `b`) is the same net as the carry input:
191///
192///    ```
193///    { y4 y3 y2 y1 y0 } =
194///       { a3 a2 a1 a0 } +
195///       { b3 b2 b1 b0 } + a0
196///    ```
197///
198///    In this case, The carry out of position `0` will always be equal to `a0`, and the sum
199///    at this position will be equal to `b0`.  The above example gets split up as follows:
200///
201///    ```
202///    { y4 y3 y2 y1 } =
203///       { a3 a2 a1 } +
204///       { b3 b2 b1 } + a0
205///
206///    y0 = b0
207///    ```
208///
209/// This optimization is comically general.  We are mostly interested in it for its useful special
210/// cases:
211///
212/// - `a + a` will get optimized into `{ a 0 }`
213/// - `a + a + ci` will get optimized into `{ a ci }`
214/// - when both operands have const LSBs, the low part is const-folded
215/// - when one operand has const-0 LSBs, and the CI is 0, the low bits of output are replaced with
216///   bits of the other operand
217/// - when one operand has const-1 LSBs, and the CI is 1, the low bits of output are replaced with
218///   bits of the other operand
219/// - when the two operands have disjoint sets of non-zero positions (eg. `{ a0 a1 0 0 } + { 0 0 b2 b3 }`,
220///   the whole cell is replaced by a buffer
221/// - when there's a stretch of zeros in both operands at the same positions, the cell gets split into two `adc`
222/// - when both operands have redundant 0 bits at MSBs, the high bits of output are replaced with 0
223fn adc_split(design: &Design, a: Value, b: Value, c: Net) -> Option<Value> {
224    let mut ci = c;
225    let mut result = Value::new();
226    for (offset, (a_bit, b_bit)) in a.iter().zip(b.iter()).enumerate() {
227        // Note that the following cases are enough to do constant-folding as
228        // well: either the two bits are the same, or they are different.
229        // If they are different, one of them must be equal to whatever
230        // ci currently is.
231        if a_bit == b_bit {
232            result.extend(make_adc(design, &a[result.len()..offset], &b[result.len()..offset], ci));
233            ci = a_bit;
234        } else if offset == result.len() {
235            if a_bit == ci {
236                result.extend([b_bit]);
237                // ci unchanged
238            } else if b_bit == ci {
239                result.extend([a_bit]);
240                // ci unchanged
241            }
242        }
243    }
244    if result.is_empty() {
245        return None;
246    }
247    result.extend(make_adc(design, &a[result.len()..], &b[result.len()..], ci));
248    Some(result)
249}
250
251/// Finds runs of three or more repeating pairs of bits in the inputs of an `adc` cell, shortens
252/// them to just two pairs.  Mostly useful for shortening over-long `adc` cells with sign-extended
253/// inputs.
254///
255/// Observation: given
256///
257/// ```
258/// { a a } +
259/// { b b } + c
260/// ```
261///
262/// the carry out of position 1 will always be the same as carry out of position 0:
263///
264/// - if `a` and `b` are both `0`, the carry-out is `0` on both positions
265/// - if `a` and `b` are both `1`, the carry-out is `1` on both positions
266/// - if `a` and `b` are `0` and `1` (or the other way around), the carry-in of `c` is propagated
267///
268/// Thus, if we have
269///
270/// ```
271/// { y3 y2 y1 y0 } =
272///     { a  a  a } +
273///     { b  b  b } + c
274/// ```
275///
276/// it follows that carry-in to positions 1 and 2 is the same, and so y1 = y2.  Further,
277/// carry out of position 2 is also the same, allowing us to completely remove position 2
278/// from the `adc` as redundant:
279///
280/// ```
281/// { y3 y1 y0 } =
282///     { a  a } +
283///     { b  b } + c
284/// y2 = y1
285/// ```
286///
287/// This applies to any repetition of length ≥ 3.  While mostly applicable to trimming MSBs,
288/// we recognize such repetitions anywhere within the inputs and split the `adc` cell there.
289fn adc_unsext(design: &Design, a: Value, b: Value, c: Net) -> Option<Value> {
290    let mut ci = c;
291    let mut offset = 0;
292    let mut result = Value::new();
293    while offset + 2 < a.len() {
294        let a_bit = a[offset];
295        let b_bit = b[offset];
296        let same_count =
297            a[offset + 1..].iter().zip(&b[offset + 1..]).take_while(|&pair| pair == (&a_bit, &b_bit)).count() + 1;
298
299        if same_count < 3 {
300            offset += same_count;
301            continue;
302        }
303
304        let start_offset = result.len();
305        let end_offset = offset + same_count;
306        let chunk = make_adc(design, &a[start_offset..offset + 2], &b[start_offset..offset + 2], ci);
307        let chunk_sum = chunk.slice(..chunk.len() - 1); // drop cout
308        result.extend(chunk_sum.sext(end_offset - start_offset));
309        ci = chunk.msb();
310        offset = end_offset;
311    }
312    if result.is_empty() {
313        return None;
314    }
315    result.extend(make_adc(design, &a[result.len()..], &b[result.len()..], ci));
316    Some(result)
317}
318
319/// Create an `adc` cell if operands have a non-zero width.
320fn make_adc(design: &Design, a: impl Into<Value>, b: impl Into<Value>, ci: impl Into<Net>) -> Value {
321    let a = a.into();
322    let b = b.into();
323    let ci = ci.into();
324    if a.is_empty() {
325        assert!(b.is_empty());
326        ci.into()
327    } else {
328        design.add_adc(a, b, ci)
329    }
330}
331
332fn fold_controls(design: &Design, cell_ref: CellRef) {
333    let uninvert = |net: Net| -> Option<Net> {
334        if let Ok((cell_ref, offset)) = design.find_cell(net) {
335            if let Cell::Not(value) = &*cell_ref.get() {
336                return Some(value[offset]);
337            }
338        }
339        None
340    };
341
342    let fold_control_net = |control_net: ControlNet| {
343        if let Some(net) = uninvert(control_net.net()) {
344            if control_net.is_positive() {
345                ControlNet::Neg(net)
346            } else {
347                ControlNet::Pos(net)
348            }
349        } else {
350            control_net.canonicalize()
351        }
352    };
353
354    match &*cell_ref.get() {
355        Cell::Dff(flip_flop) => {
356            let mut flip_flop = FlipFlop {
357                clock: fold_control_net(flip_flop.clock),
358                clear: fold_control_net(flip_flop.clear),
359                reset: fold_control_net(flip_flop.reset),
360                enable: fold_control_net(flip_flop.enable),
361                ..flip_flop.clone()
362            };
363            if flip_flop.clock.is_const() {
364                flip_flop.data = Value::undef(flip_flop.data.len());
365                flip_flop.clock = ControlNet::ZERO;
366                flip_flop.reset = ControlNet::ZERO;
367                flip_flop.enable = ControlNet::ZERO;
368            }
369            if flip_flop.reset.is_always(true) {
370                flip_flop.data = flip_flop.reset_value.clone().into();
371                flip_flop.reset = ControlNet::ZERO;
372                if flip_flop.reset_over_enable {
373                    flip_flop.enable = ControlNet::ONE;
374                }
375            }
376            if flip_flop.enable.is_always(false) {
377                if flip_flop.reset_over_enable {
378                    flip_flop.data = flip_flop.reset_value.clone().into();
379                    flip_flop.enable = flip_flop.reset;
380                    flip_flop.reset = ControlNet::ZERO;
381                } else {
382                    flip_flop.data = Value::undef(flip_flop.data.len());
383                    flip_flop.clock = ControlNet::ZERO;
384                    flip_flop.reset = ControlNet::ZERO;
385                    flip_flop.enable = ControlNet::ZERO;
386                }
387            }
388            cell_ref.replace(Cell::Dff(flip_flop));
389        }
390        Cell::IoBuf(io_buffer) => {
391            cell_ref.replace(Cell::IoBuf(IoBuffer {
392                io: io_buffer.io.clone(),
393                output: io_buffer.output.clone(),
394                enable: fold_control_net(io_buffer.enable),
395            }));
396        }
397        Cell::Target(target_cell) => {
398            let mut target_cell = target_cell.clone();
399            let prototype = design.target_prototype(&target_cell);
400            for input in prototype.inputs.iter() {
401                let Some(invert_param_index) = input.invert_param else { continue };
402                let ParamValue::Const(ref mut invert_const) = target_cell.params[invert_param_index] else {
403                    unreachable!()
404                };
405                for offset in input.range.clone() {
406                    let const_offset = offset - input.range.start;
407                    let Some(net) = uninvert(target_cell.inputs[offset]) else { continue };
408                    target_cell.inputs[offset] = net;
409                    invert_const[const_offset] = !invert_const[const_offset];
410                }
411            }
412            cell_ref.replace(Cell::Target(target_cell));
413        }
414        _ => (),
415    }
416}
417
418#[cfg(test)]
419mod test {
420    use std::{collections::BTreeMap, sync::Arc};
421
422    use prjunnamed_netlist::{
423        assert_isomorphic, Const, ControlNet, Design, FlipFlop, IoBuffer, Net, Target, TargetCell, TargetImportError,
424        TargetPrototype, Trit, Value,
425    };
426    use prjunnamed_pattern::{assert_netlist, netlist_match, patterns::*};
427
428    use super::simplify;
429
430    macro_rules! assert_simplify {
431        ( $( |$design:ident| $build:expr ),+ ; $( $match:tt )+ ) => {
432            let rules = netlist_match! { $( $match )+ };
433            $(
434                let mut $design = Design::new();
435                $design.add_output("y", $build);
436                $design.apply();
437                let design_before = $design.clone();
438                simplify(&mut $design);
439                assert_netlist!($design, rules, "simplify failed on:\n{}\nresult:\n{}", design_before, $design);
440            )+
441        };
442    }
443
444    macro_rules! assert_simplify_isomorphic {
445        ( $design:ident, $gold:ident ) => {
446            let (mut design, mut gold) = ($design, $gold);
447            design.apply();
448            simplify(&mut design);
449            gold.apply();
450            assert_isomorphic!(design, gold);
451        };
452    }
453
454    macro_rules! assert_no_simplify {
455        ( $design:ident ) => {
456            let mut design = $design;
457            design.apply();
458            assert!(!simplify(&mut design));
459        };
460    }
461
462    fn iter_interesting_consts() -> impl Iterator<Item = Const> {
463        ["0", "1", "X", "00", "11", "XX", "01", "10"].into_iter().map(Const::lit)
464    }
465
466    fn iter_has_undef_consts() -> impl Iterator<Item = Const> {
467        ["X", "XX", "0X", "X1"].into_iter().map(Const::lit)
468    }
469
470    fn iter_interesting_const_pairs() -> impl Iterator<Item = (Const, Const)> {
471        iter_interesting_consts().flat_map(|value1| {
472            iter_interesting_consts().filter_map(move |value2| {
473                if value1.len() == value2.len() {
474                    Some((value1.clone(), value2))
475                } else {
476                    None
477                }
478            })
479        })
480    }
481
482    #[allow(dead_code)]
483    #[derive(Debug)]
484    struct MockTarget {
485        prototypes: BTreeMap<String, TargetPrototype>,
486    }
487
488    impl MockTarget {
489        #[allow(dead_code)]
490        fn new() -> Arc<Self> {
491            Arc::new(MockTarget {
492                prototypes: BTreeMap::from_iter([
493                    (
494                        "BUF1".into(),
495                        TargetPrototype::new_has_effects()
496                            .add_param_bits("INVERT", Const::zero(1))
497                            .add_input_invertible("I", Const::zero(1), "INVERT")
498                            .add_output("O", 1),
499                    ),
500                    (
501                        "BUF2".into(),
502                        TargetPrototype::new_has_effects()
503                            .add_param_bits("INVERT", Const::zero(2))
504                            .add_input_invertible("I", Const::zero(2), "INVERT")
505                            .add_output("O", 2),
506                    ),
507                ]),
508            })
509        }
510    }
511
512    impl Target for MockTarget {
513        fn name(&self) -> &str {
514            "mock"
515        }
516
517        fn options(&self) -> BTreeMap<String, String> {
518            BTreeMap::new()
519        }
520
521        fn prototype(&self, name: &str) -> Option<&TargetPrototype> {
522            self.prototypes.get(name)
523        }
524
525        fn validate(&self, _design: &Design, _cell: &TargetCell) {}
526
527        fn import(&self, _design: &mut Design) -> Result<(), TargetImportError> {
528            Ok(())
529        }
530
531        fn export(&self, _design: &mut Design) {}
532
533        fn synthesize(&self, _design: &mut Design) -> Result<(), ()> {
534            Ok(())
535        }
536    }
537
538    #[test]
539    fn test_not_const_eval() {
540        for value in iter_interesting_consts() {
541            assert_simplify!(
542                |design| design.add_not(&value);
543                [PConst@a] => (a == value.not());
544            );
545        }
546    }
547
548    #[test]
549    fn test_not_not() {
550        assert_simplify!(
551            |ds| ds.add_not(ds.add_not(ds.add_input("a", 2)));
552            [PInput ("a")] => true;
553        );
554    }
555
556    #[test]
557    fn test_and_const_eval() {
558        for (value1, value2) in iter_interesting_const_pairs() {
559            assert_simplify!(
560                |ds| ds.add_and(&value1, &value2);
561                [PConst@a] => (a == value1.and(&value2));
562            );
563        }
564    }
565
566    #[test]
567    fn test_and_fold() {
568        for size in [1, 2] {
569            assert_simplify!(
570                |ds| ds.add_and(Const::zero(size), ds.add_input("a", size)),
571                |ds| ds.add_and(ds.add_input("a", size), Const::zero(size));
572                [PZero] => true;
573            );
574            assert_simplify!(
575                |ds| ds.add_and(Const::ones(size), ds.add_input("a", size)),
576                |ds| ds.add_and(ds.add_input("a", size), Const::ones(size));
577                [PInput ("a")] => true;
578            );
579            assert_simplify!(
580                |ds| { let a = ds.add_input("a", size); ds.add_and(&a, ds.add_not(&a)) },
581                |ds| { let a = ds.add_input("a", size); ds.add_and(ds.add_not(&a), &a) };
582                [PZero] => true;
583            );
584        }
585    }
586
587    #[test]
588    fn test_or_const_eval() {
589        for (value1, value2) in iter_interesting_const_pairs() {
590            assert_simplify!(
591                |ds| ds.add_or(&value1, &value2);
592                [PConst@a] => a == value1.or(&value2);
593            );
594        }
595    }
596
597    #[test]
598    fn test_or_fold() {
599        for size in [1, 2] {
600            assert_simplify!(
601                |ds| ds.add_or(Const::zero(size), ds.add_input("a", size)),
602                |ds| ds.add_or(ds.add_input("a", size), Const::zero(size));
603                [PInput ("a")] => true;
604            );
605            assert_simplify!(
606                |ds| ds.add_or(Const::ones(size), ds.add_input("a", size)),
607                |ds| ds.add_or(ds.add_input("a", size), Const::ones(size));
608                [POnes] => true;
609            );
610            assert_simplify!(
611                |ds| { let a = ds.add_input("a", size); ds.add_or(&a, ds.add_not(&a)) },
612                |ds| { let a = ds.add_input("a", size); ds.add_or(ds.add_not(&a), &a) };
613                [POnes] => true;
614            );
615        }
616    }
617
618    #[test]
619    fn test_xor_const_eval() {
620        for (value1, value2) in iter_interesting_const_pairs() {
621            assert_simplify!(
622                |ds| ds.add_xor(&value1, &value2);
623                [PConst@a] => a == value1.xor(&value2);
624            );
625        }
626    }
627
628    #[test]
629    fn test_xor_fold() {
630        for size in [1, 2] {
631            assert_simplify!(
632                |ds| ds.add_xor(Const::zero(size), ds.add_input("a", size)),
633                |ds| ds.add_xor(ds.add_input("a", size), Const::zero(size));
634                [PInput ("a")] => true;
635            );
636            assert_simplify!(
637                |ds| ds.add_xor(Const::ones(size), ds.add_input("a", size)),
638                |ds| ds.add_xor(ds.add_input("a", size), Const::ones(size));
639                [PNot [PInput ("a")]] => true;
640            );
641            assert_simplify!(
642                |ds| ds.add_xor(Const::undef(size), ds.add_input("a", size)),
643                |ds| ds.add_xor(ds.add_input("a", size), Const::undef(size));
644                [PUndef] => true;
645            );
646            assert_simplify!(
647                |ds| { let a = ds.add_input("a", size); ds.add_xor(&a, ds.add_not(&a)) },
648                |ds| { let a = ds.add_input("a", size); ds.add_xor(ds.add_not(&a), &a) };
649                [POnes] => true;
650            );
651            assert_simplify!(
652                |ds| {let a = ds.add_input("a", size); ds.add_xor(&a, &a)};
653                [PZero] => true;
654            );
655        }
656    }
657
658    #[test]
659    fn test_mux_fold() {
660        for size in [1, 2] {
661            assert_simplify!(
662                |ds| ds.add_mux(Net::ZERO, ds.add_input("a", size), ds.add_input("b", size));
663                [PInput ("b")] => true;
664            );
665            assert_simplify!(
666                |ds| ds.add_mux(Net::ONE, ds.add_input("a", size), ds.add_input("b", size));
667                [PInput ("a")] => true;
668            );
669            assert_simplify!(
670                |ds| ds.add_mux(ds.add_input1("s"), ds.add_input("a", size), Const::undef(size));
671                [PInput ("a")] => true;
672            );
673            assert_simplify!(
674                |ds| ds.add_mux(ds.add_input1("s"), Const::undef(size), ds.add_input("b", size));
675                [PInput ("b")] => true;
676            );
677            assert_simplify!(
678                |ds| { let a = ds.add_input("a", size); ds.add_mux(ds.add_input1("s"), &a, &a) };
679                [PInput ("a")] => true;
680            );
681            assert_simplify!(
682                |ds| ds.add_mux(ds.add_input1("s"), Const::ones(size), Const::zero(size));
683                [PSExt [PAny@s]] if s.len() == 1 => true;
684            );
685        }
686    }
687
688    #[test]
689    fn test_demorgan() {
690        for size in [1, 2] {
691            assert_simplify!(
692                |ds| ds.add_and(ds.add_not(ds.add_input("a", size)), ds.add_not(ds.add_input("b", size)));
693                [PNot [POr [PInput ("a")] [PInput ("b")]]] => true;
694            );
695            assert_simplify!(
696                |ds| ds.add_or(ds.add_not(ds.add_input("a", size)), ds.add_not(ds.add_input("b", size)));
697                [PNot [PAnd [PInput ("a")] [PInput ("b")]]] => true;
698            );
699        }
700    }
701
702    #[test]
703    fn test_xor_not_push() {
704        for size in [1, 2] {
705            assert_simplify!(
706                |ds| ds.add_xor(ds.add_not(ds.add_input("a", size)), ds.add_not(ds.add_input("b", size)));
707                [PXor [PInput ("a")] [PInput ("b")]] => true;
708            );
709            assert_simplify!(
710                |ds| ds.add_xor(ds.add_not(ds.add_input("a", size)), ds.add_input("b", size)),
711                |ds| ds.add_xor(ds.add_input("a", size), ds.add_not(ds.add_input("b", size)));
712                [PNot [PXor [PInput ("a")] [PInput ("b")]]] => true;
713            );
714        }
715    }
716
717    #[test]
718    fn test_mux_flip() {
719        for size in [1, 2] {
720            assert_simplify!(
721                |ds| ds.add_mux(ds.add_not(ds.add_input("s", 1))[0], ds.add_input("a", size), ds.add_input("b", size));
722                [PMux [PInput ("s")] [PInput ("b")] [PInput ("a")]] => true;
723            );
724        }
725    }
726
727    #[test]
728    fn test_adc_const_eval() {
729        for carry in [Trit::Zero, Trit::One, Trit::Undef] {
730            for (value1, value2) in iter_interesting_const_pairs() {
731                assert_simplify!(
732                    |ds| ds.add_adc(&value1, &value2, carry);
733                    [PConst@a] => a == value1.adc(&value2, carry);
734                );
735            }
736        }
737    }
738
739    #[test]
740    fn test_adc_fold() {
741        for size in [1, 2] {
742            assert_simplify!(
743                |ds| ds.add_adc(Const::zero(size), ds.add_input("a", size), Net::ZERO),
744                |ds| ds.add_adc(ds.add_input("a", size), Const::zero(size), Net::ZERO);
745                [PZExt [PInput ("a")]] => true;
746            );
747            assert_simplify!(
748                |ds| ds.add_adc(Const::zero(size), Const::zero(size), ds.add_input("c", 1)[0]);
749                [PZExt [PInput ("c")]] => true;
750            );
751        }
752    }
753
754    #[test]
755    fn test_adc_split_case1() {
756        let mut design = Design::new();
757        let a = design.add_input("a", 4);
758        let b = design.add_input("b", 4);
759        let ab = design.add_input("ab", 1);
760        let c = design.add_input("c", 1);
761        let y = design.add_adc(
762            a.slice(..2).concat(&ab).concat(a.slice(2..)),
763            b.slice(..2).concat(&ab).concat(b.slice(2..)),
764            c.unwrap_net(),
765        );
766        design.add_output("y", y);
767        design.apply();
768        simplify(&mut design);
769        let mut gold = Design::new();
770        let a = gold.add_input("a", 4);
771        let b = gold.add_input("b", 4);
772        let ab = gold.add_input("ab", 1);
773        let c = gold.add_input("c", 1);
774        let y0 = gold.add_adc(a.slice(..2), b.slice(..2), c.unwrap_net());
775        let y2 = gold.add_adc(a.slice(2..), b.slice(2..), ab.unwrap_net());
776        gold.add_output("y", y0.concat(y2));
777        gold.apply();
778        assert_isomorphic!(design, gold);
779    }
780
781    #[test]
782    fn test_adc_split_case1_top() {
783        let mut design = Design::new();
784        let a = design.add_input("a", 4);
785        let b = design.add_input("b", 4);
786        let ab = design.add_input("ab", 1);
787        let c = design.add_input("c", 1);
788        let y = design.add_adc(a.concat(&ab), b.concat(&ab), c.unwrap_net());
789        design.add_output("y", y);
790        design.apply();
791        simplify(&mut design);
792        let mut gold = Design::new();
793        let a = gold.add_input("a", 4);
794        let b = gold.add_input("b", 4);
795        let ab = gold.add_input("ab", 1);
796        let c = gold.add_input("c", 1);
797        let y = gold.add_adc(a, b, c.unwrap_net());
798        gold.add_output("y", y.concat(ab));
799        gold.apply();
800        assert_isomorphic!(design, gold);
801    }
802
803    #[test]
804    fn test_adc_split_case2() {
805        let mut design = Design::new();
806        let a = design.add_input("a", 4);
807        let b = design.add_input("b", 4);
808        let y = design.add_adc(&a, &b, b.lsb());
809        design.add_output("y", y);
810        design.apply();
811        simplify(&mut design);
812        let mut gold = Design::new();
813        let a = gold.add_input("a", 4);
814        let b = gold.add_input("b", 4);
815        let y = gold.add_adc(&a[1..], &b[1..], b.lsb());
816        gold.add_output("y", Value::from(a.lsb()).concat(y));
817        gold.apply();
818        assert_isomorphic!(design, gold);
819    }
820
821    #[test]
822    fn test_adc_split_case2_swap() {
823        let mut design = Design::new();
824        let a = design.add_input("a", 4);
825        let b = design.add_input("b", 4);
826        let y = design.add_adc(&a, &b, a.lsb());
827        design.add_output("y", y);
828        design.apply();
829        simplify(&mut design);
830        let mut gold = Design::new();
831        let a = gold.add_input("a", 4);
832        let b = gold.add_input("b", 4);
833        let y = gold.add_adc(&a[1..], &b[1..], a.lsb());
834        gold.add_output("y", Value::from(b.lsb()).concat(y));
835        gold.apply();
836        assert_isomorphic!(design, gold);
837    }
838
839    #[test]
840    fn test_adc_split_case2_top() {
841        let mut design = Design::new();
842        let a = design.add_input("a", 1);
843        let b = design.add_input("b", 1);
844        let y = design.add_adc(&a, &b, b.lsb());
845        design.add_output("y", y);
846        design.apply();
847        simplify(&mut design);
848        let mut gold = Design::new();
849        let a = gold.add_input("a", 1);
850        let b = gold.add_input("b", 1);
851        gold.add_output("y", a.concat(b));
852        gold.apply();
853        assert_isomorphic!(design, gold);
854    }
855
856    #[test]
857    fn test_adc_split_a_plus_a() {
858        let mut design = Design::new();
859        let a = design.add_input("a", 4);
860        let y = design.add_adc(&a, &a, Net::ZERO);
861        design.add_output("y", y);
862        design.apply();
863        simplify(&mut design);
864        let mut gold = Design::new();
865        let a = gold.add_input("a", 4);
866        gold.add_output("y", Value::from(Net::ZERO).concat(a));
867        gold.apply();
868        assert_isomorphic!(design, gold);
869    }
870
871    #[test]
872    fn test_adc_split_a_plus_a_carry() {
873        let mut design = Design::new();
874        let a = design.add_input("a", 4);
875        let c = design.add_input("c", 1);
876        let y = design.add_adc(&a, &a, c.unwrap_net());
877        design.add_output("y", y);
878        design.apply();
879        simplify(&mut design);
880        let mut gold = Design::new();
881        let a = gold.add_input("a", 4);
882        let c = gold.add_input("c", 1);
883        gold.add_output("y", c.concat(a));
884        gold.apply();
885        assert_isomorphic!(design, gold);
886    }
887
888    #[test]
889    fn test_adc_split_const_lsb() {
890        let mut design = Design::new();
891        let a = design.add_input("a", 4);
892        let b = design.add_input("b", 4);
893        let y = design.add_adc(
894            Value::from(Const::lit("0111")).concat(&a),
895            Value::from(Const::lit("1101")).concat(&b),
896            Net::ZERO,
897        );
898        design.add_output("y", y);
899        design.apply();
900        simplify(&mut design);
901        let mut gold = Design::new();
902        let a = gold.add_input("a", 4);
903        let b = gold.add_input("b", 4);
904        let y = gold.add_adc(a, b, Net::ONE);
905        gold.add_output("y", Value::from(Const::lit("0100")).concat(&y));
906        gold.apply();
907        assert_isomorphic!(design, gold);
908    }
909
910    #[test]
911    fn test_adc_split_const_zero_lsb() {
912        let mut design = Design::new();
913        let a = design.add_input("a", 8);
914        let b = design.add_input("b", 4);
915        let y = design.add_adc(a, Value::zero(4).concat(&b), Net::ZERO);
916        design.add_output("y", y);
917        design.apply();
918        simplify(&mut design);
919        let mut gold = Design::new();
920        let a = gold.add_input("a", 8);
921        let b = gold.add_input("b", 4);
922        let y = gold.add_adc(&a[4..], b, Net::ZERO);
923        gold.add_output("y", a.slice(..4).concat(&y));
924        gold.apply();
925        assert_isomorphic!(design, gold);
926    }
927
928    #[test]
929    fn test_adc_split_const_ones_lsb() {
930        let mut design = Design::new();
931        let a = design.add_input("a", 8);
932        let b = design.add_input("b", 4);
933        let y = design.add_adc(a, Value::from(Const::lit("1111")).concat(&b), Net::ONE);
934        design.add_output("y", y);
935        design.apply();
936        simplify(&mut design);
937        let mut gold = Design::new();
938        let a = gold.add_input("a", 8);
939        let b = gold.add_input("b", 4);
940        let y = gold.add_adc(&a[4..], b, Net::ONE);
941        gold.add_output("y", a.slice(..4).concat(&y));
942        gold.apply();
943        assert_isomorphic!(design, gold);
944    }
945
946    #[test]
947    fn test_adc_split_disjoint() {
948        let mut design = Design::new();
949        let a = design.add_input("a", 4);
950        let b = design.add_input("b", 4);
951        let y = design.add_adc(a.concat(Value::zero(4)), Value::zero(4).concat(&b), Net::ZERO);
952        design.add_output("y", y);
953        design.apply();
954        simplify(&mut design);
955        let mut gold = Design::new();
956        let a = gold.add_input("a", 4);
957        let b = gold.add_input("b", 4);
958        gold.add_output("y", a.concat(&b).concat(Net::ZERO));
959        gold.apply();
960        assert_isomorphic!(design, gold);
961    }
962
963    #[test]
964    fn test_adc_split_zeros() {
965        let mut design = Design::new();
966        let al = design.add_input("al", 4);
967        let ah = design.add_input("ah", 4);
968        let bl = design.add_input("bl", 4);
969        let bh = design.add_input("bh", 4);
970        let y = design.add_adc(al.concat(Value::zero(4)).concat(ah), bl.concat(Value::zero(4)).concat(bh), Net::ZERO);
971        design.add_output("y", y);
972        design.apply();
973        simplify(&mut design);
974        let mut gold = Design::new();
975        let al = gold.add_input("al", 4);
976        let ah = gold.add_input("ah", 4);
977        let bl = gold.add_input("bl", 4);
978        let bh = gold.add_input("bh", 4);
979        let yl = gold.add_adc(al, bl, Net::ZERO);
980        let yh = gold.add_adc(ah, bh, Net::ZERO);
981        gold.add_output("y", yl.concat(Value::zero(3)).concat(yh));
982        gold.apply();
983        assert_isomorphic!(design, gold);
984    }
985
986    #[test]
987    fn test_adc_split_zext() {
988        let mut design = Design::new();
989        let a = design.add_input("a", 4);
990        let b = design.add_input("b", 4);
991        let c = design.add_input("c", 1);
992        let y = design.add_adc(a.concat(Value::zero(4)), b.concat(Value::zero(4)), c.unwrap_net());
993        design.add_output("y", y);
994        design.apply();
995        simplify(&mut design);
996        let mut gold = Design::new();
997        let a = gold.add_input("a", 4);
998        let b = gold.add_input("b", 4);
999        let c = gold.add_input("c", 1);
1000        let y = gold.add_adc(a, b, c.unwrap_net());
1001        gold.add_output("y", y.concat(Value::zero(4)));
1002        gold.apply();
1003        assert_isomorphic!(design, gold);
1004    }
1005
1006    #[test]
1007    fn test_adc_unsext_sext() {
1008        let mut design = Design::new();
1009        let a = design.add_input("a", 4);
1010        let b = design.add_input("b", 4);
1011        let c = design.add_input("c", 1);
1012        let y = design.add_adc(a.sext(8), b.sext(8), c.unwrap_net());
1013        design.add_output("y", y);
1014        design.apply();
1015        simplify(&mut design);
1016        let mut gold = Design::new();
1017        let a = gold.add_input("a", 4);
1018        let b = gold.add_input("b", 4);
1019        let c = gold.add_input("c", 1);
1020        let y = gold.add_adc(a.sext(5), b.sext(5), c.unwrap_net());
1021        gold.add_output("y", y.slice(..5).sext(8).concat(y.msb()));
1022        gold.apply();
1023        assert_isomorphic!(design, gold);
1024    }
1025
1026    #[test]
1027    fn test_adc_unsext_bi() {
1028        let mut design = Design::new();
1029        let al = design.add_input("al", 1);
1030        let bl = design.add_input("bl", 1);
1031        let ah = design.add_input("ah", 1);
1032        let bh = design.add_input("bh", 1);
1033        let c = design.add_input("c", 1);
1034        let y = design.add_adc(al.sext(4).concat(ah.sext(4)), bl.sext(4).concat(bh.sext(4)), c.unwrap_net());
1035        design.add_output("y", y);
1036        design.apply();
1037        simplify(&mut design);
1038        let mut gold = Design::new();
1039        let al = gold.add_input("al", 1);
1040        let bl = gold.add_input("bl", 1);
1041        let ah = gold.add_input("ah", 1);
1042        let bh = gold.add_input("bh", 1);
1043        let c = gold.add_input("c", 1);
1044        let y0 = gold.add_adc(al.sext(2), bl.sext(2), c.unwrap_net());
1045        let y1 = gold.add_adc(ah.sext(2), bh.sext(2), y0.msb());
1046        gold.add_output("y", y0.slice(..2).sext(4).concat(y1.slice(..2).sext(4)).concat(y1.msb()));
1047        gold.apply();
1048        assert_isomorphic!(design, gold);
1049    }
1050
1051    #[test]
1052    fn test_adc_unsext_only2() {
1053        for size in [1, 2] {
1054            let design = Design::new();
1055            let a = design.add_input("a", size);
1056            let b = design.add_input("b", size);
1057            let c = design.add_input("c", 1);
1058            let y = design.add_adc(a.sext(size + 1), b.sext(size + 1), c.unwrap_net());
1059            design.add_output("y", y);
1060            assert_no_simplify!(design);
1061        }
1062    }
1063
1064    #[test]
1065    fn test_adc_unsext_only3() {
1066        for size in [1, 2] {
1067            let mut design = Design::new();
1068            let a = design.add_input("a", size);
1069            let b = design.add_input("b", size);
1070            let c = design.add_input("c", 1);
1071            let y = design.add_adc(a.sext(size + 2), b.sext(size + 2), c.unwrap_net());
1072            design.add_output("y", y);
1073            design.apply();
1074            simplify(&mut design);
1075            simplify(&mut design); // clean up zero length adcs
1076
1077            let mut gold = Design::new();
1078            let a = gold.add_input("a", size);
1079            let b = gold.add_input("b", size);
1080            let c = gold.add_input("c", 1);
1081            let y = gold.add_adc(a.sext(size + 1), b.sext(size + 1), c.unwrap_net());
1082            gold.add_output("y", y.slice(..size + 1).sext(size + 2).concat(y.msb()));
1083            gold.apply();
1084            assert_isomorphic!(design, gold);
1085        }
1086    }
1087
1088    #[test]
1089    fn test_adc_ci_folding() {
1090        for size in [1, 2] {
1091            assert_simplify!(
1092                |ds| {
1093                    ds.add_adc(
1094                        ds.add_adc(ds.add_input("a", size), ds.add_input("b", size), Net::ZERO),
1095                        ds.add_input("c", 1).zext(size + 1),
1096                        Net::ZERO
1097                    )
1098                };
1099                [PZExt [PAdc [PInput ("a")] [PInput ("b")] [PInput ("c")]]] => true;
1100            );
1101        }
1102    }
1103
1104    #[test]
1105    fn test_eq_const_eval() {
1106        for (value1, value2) in iter_interesting_const_pairs() {
1107            assert_simplify!(
1108                |ds| ds.add_eq(&value1, &value2);
1109                [PConst@a] => a == Const::from(value1.eq(&value2));
1110            );
1111        }
1112    }
1113
1114    #[test]
1115    fn test_eq_fold() {
1116        assert_simplify!(
1117            |ds| ds.add_eq(Const::ones(1), ds.add_input("a", 1)),
1118            |ds| ds.add_eq(ds.add_input("a", 1), Const::ones(1));
1119            [PInput ("a")] => true;
1120        );
1121        assert_simplify!(
1122            |ds| ds.add_eq(Const::zero(1), ds.add_input("a", 1)),
1123            |ds| ds.add_eq(ds.add_input("a", 1), Const::zero(1));
1124            [PNot [PInput ("a")]] => true;
1125        );
1126        for size in [1, 2] {
1127            assert_simplify!(
1128                |ds| {let a = ds.add_input("a", size); ds.add_eq(&a, &a)};
1129                [POnes] => true;
1130            );
1131        }
1132    }
1133
1134    #[test]
1135    fn test_ult_const_eval() {
1136        for (value1, value2) in iter_interesting_const_pairs() {
1137            assert_simplify!(
1138                |ds| ds.add_ult(&value1, &value2);
1139                [PConst@a] => a == Const::from(value1.ult(&value2));
1140            );
1141        }
1142    }
1143
1144    #[test]
1145    fn test_ult_fold() {
1146        for size in [1, 2] {
1147            assert_simplify!(
1148                |ds| ds.add_ult(ds.add_input("a", size), Value::zero(size));
1149                [PZero] => true;
1150            );
1151            assert_simplify!(
1152                |ds| ds.add_ult(Value::ones(size), ds.add_input("a", size));
1153                [PZero] => true;
1154            );
1155            for a in iter_has_undef_consts().filter(|c| c.len() == size) {
1156                assert_simplify!(
1157                    |ds| ds.add_ult(&a, ds.add_input("a", size)),
1158                    |ds| ds.add_ult(ds.add_input("a", size), &a);
1159                    [PUndef] => true;
1160                );
1161            }
1162            assert_simplify!(
1163                |ds| {let a = ds.add_input("a", size); ds.add_ult(&a, &a)};
1164                [PZero] => true;
1165            );
1166        }
1167    }
1168
1169    #[test]
1170    fn test_slt_const_eval() {
1171        for (value1, value2) in iter_interesting_const_pairs() {
1172            assert_simplify!(
1173                |ds| ds.add_slt(&value1, &value2);
1174                [PConst@a] => a == Const::from(value1.slt(&value2));
1175            );
1176        }
1177    }
1178
1179    #[test]
1180    fn test_slt_fold() {
1181        for size in [1, 2] {
1182            for a in iter_has_undef_consts().filter(|c| c.len() == size) {
1183                assert_simplify!(
1184                    |ds| ds.add_slt(&a, ds.add_input("a", size)),
1185                    |ds| ds.add_slt(ds.add_input("a", size), &a);
1186                    [PUndef] => true;
1187                );
1188            }
1189            assert_simplify!(
1190                |ds| {let a = ds.add_input("a", size); ds.add_slt(&a, &a)};
1191                [PZero] => true;
1192            );
1193        }
1194    }
1195
1196    #[test]
1197    fn test_shl_fold() {
1198        for size in [2, 4] {
1199            for size2 in [2, 4] {
1200                assert_simplify!(
1201                    |ds| ds.add_shl(Value::zero(size), ds.add_input("a", size2), 1);
1202                    [PZero] => true;
1203                );
1204                assert_simplify!(
1205                    |ds| ds.add_shl(ds.add_input("a", size), ds.add_input("b", size2), 0);
1206                    [PInput ("a")] => true;
1207                );
1208            }
1209        }
1210    }
1211
1212    #[test]
1213    fn test_ff_simplify_clear() {
1214        for size in [1, 2] {
1215            let design = Design::new();
1216            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1217                .with_clear(ControlNet::Pos(design.add_not(design.add_input("r", 1))[0]));
1218            design.add_output("q", design.add_dff(flip_flop));
1219            let gold = Design::new();
1220            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1221                .with_clear(ControlNet::Neg(gold.add_input1("r")));
1222            gold.add_output("q", gold.add_dff(flip_flop));
1223            assert_simplify_isomorphic!(design, gold);
1224        }
1225        for size in [1, 2] {
1226            let design = Design::new();
1227            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1228                .with_clear(ControlNet::Neg(design.add_not(design.add_input("r", 1))[0]));
1229            design.add_output("q", design.add_dff(flip_flop));
1230            let gold = Design::new();
1231            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1232                .with_clear(ControlNet::Pos(gold.add_input1("r")));
1233            gold.add_output("q", gold.add_dff(flip_flop));
1234            assert_simplify_isomorphic!(design, gold);
1235        }
1236    }
1237
1238    #[test]
1239    fn test_ff_simplify_reset() {
1240        for size in [1, 2] {
1241            let design = Design::new();
1242            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1243                .with_reset(ControlNet::Pos(design.add_not(design.add_input("r", 1))[0]));
1244            design.add_output("q", design.add_dff(flip_flop));
1245            let gold = Design::new();
1246            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1247                .with_reset(ControlNet::Neg(gold.add_input1("r")));
1248            gold.add_output("q", gold.add_dff(flip_flop));
1249            assert_simplify_isomorphic!(design, gold);
1250        }
1251        for size in [1, 2] {
1252            let design = Design::new();
1253            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1254                .with_reset(ControlNet::Neg(design.add_not(design.add_input("r", 1))[0]));
1255            design.add_output("q", design.add_dff(flip_flop));
1256            let gold = Design::new();
1257            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1258                .with_reset(ControlNet::Pos(gold.add_input1("r")));
1259            gold.add_output("q", gold.add_dff(flip_flop));
1260            assert_simplify_isomorphic!(design, gold);
1261        }
1262    }
1263
1264    #[test]
1265    fn test_ff_simplify_enable() {
1266        for size in [1, 2] {
1267            let design = Design::new();
1268            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1269                .with_enable(ControlNet::Pos(design.add_not(design.add_input("e", 1))[0]));
1270            design.add_output("q", design.add_dff(flip_flop));
1271            let gold = Design::new();
1272            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1273                .with_enable(ControlNet::Neg(gold.add_input1("e")));
1274            gold.add_output("q", gold.add_dff(flip_flop));
1275            assert_simplify_isomorphic!(design, gold);
1276        }
1277        for size in [1, 2] {
1278            let design = Design::new();
1279            let flip_flop = FlipFlop::new(design.add_input("d", size), design.add_input1("c"))
1280                .with_enable(ControlNet::Neg(design.add_not(design.add_input("e", 1))[0]));
1281            design.add_output("q", design.add_dff(flip_flop));
1282            let gold = Design::new();
1283            let flip_flop = FlipFlop::new(gold.add_input("d", size), gold.add_input1("c"))
1284                .with_enable(ControlNet::Pos(gold.add_input1("e")));
1285            gold.add_output("q", gold.add_dff(flip_flop));
1286            assert_simplify_isomorphic!(design, gold);
1287        }
1288    }
1289
1290    #[test]
1291    fn test_ff_canonicalize_controls() {
1292        let design = Design::new();
1293        let flip_flop = FlipFlop::new(design.add_input("d", 1), ControlNet::Neg(Net::ONE))
1294            .with_clear(ControlNet::Neg(Net::ONE))
1295            .with_reset(ControlNet::Neg(Net::ONE))
1296            .with_enable(ControlNet::Neg(Net::ONE));
1297        design.add_output("q", design.add_dff(flip_flop));
1298        let gold = Design::new();
1299        let flip_flop = FlipFlop::new(Value::undef(1), Net::ZERO).with_enable(ControlNet::Pos(Net::ZERO));
1300        gold.add_output("q", gold.add_dff(flip_flop));
1301        assert_simplify_isomorphic!(design, gold);
1302    }
1303
1304    #[test]
1305    fn test_ff_simplify_clock_const() {
1306        let design = Design::new();
1307        let flip_flop = FlipFlop::new(design.add_input("d", 1), Net::ZERO)
1308            .with_reset(design.add_input1("r"))
1309            .with_enable(design.add_input1("e"));
1310        design.add_output("q", design.add_dff(flip_flop));
1311        let gold = Design::new();
1312        let flip_flop = FlipFlop::new(Value::undef(1), Net::ZERO).with_enable(ControlNet::Pos(Net::ZERO));
1313        gold.add_output("q", gold.add_dff(flip_flop));
1314        assert_simplify_isomorphic!(design, gold);
1315    }
1316
1317    #[test]
1318    fn test_ff_simplify_reset_always_enable_prio() {
1319        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1320            let design = Design::new();
1321            let flip_flop = FlipFlop::new(design.add_input("d", 1), design.add_input1("c"))
1322                .with_enable(design.add_input1("e"))
1323                .with_reset(Net::ONE)
1324                .with_init(init.clone());
1325            design.add_output("q", design.add_dff(flip_flop));
1326            let gold = Design::new();
1327            let flip_flop = FlipFlop::new(init.into(), gold.add_input1("c"))
1328                .with_enable(gold.add_input1("e"))
1329                .with_init(init.clone());
1330            gold.add_output("q", gold.add_dff(flip_flop));
1331            assert_simplify_isomorphic!(design, gold);
1332        }
1333    }
1334
1335    #[test]
1336    fn test_ff_simplify_reset_always_reset_prio() {
1337        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1338            let design = Design::new();
1339            let flip_flop = FlipFlop::new(design.add_input("d", 1), design.add_input1("c"))
1340                .with_reset(Net::ONE)
1341                .with_enable(design.add_input1("e"))
1342                .with_init(init.clone());
1343            design.add_output("q", design.add_dff(flip_flop));
1344            let gold = Design::new();
1345            let flip_flop =
1346                FlipFlop::new(init.into(), gold.add_input1("c")).with_enable(Net::ONE).with_init(init.clone());
1347            gold.add_output("q", gold.add_dff(flip_flop));
1348            assert_simplify_isomorphic!(design, gold);
1349        }
1350    }
1351
1352    #[test]
1353    fn test_ff_simplify_enable_never_enable_prio() {
1354        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1355            let design = Design::new();
1356            let flip_flop = FlipFlop::new(design.add_input("d", 1), design.add_input1("c"))
1357                .with_enable(Net::ZERO)
1358                .with_reset(design.add_input1("r"))
1359                .with_init(init.clone());
1360            design.add_output("q", design.add_dff(flip_flop));
1361            let gold = Design::new();
1362            let flip_flop = FlipFlop::new(Value::undef(1), Net::ZERO)
1363                .with_reset(Net::ZERO)
1364                .with_enable(Net::ZERO)
1365                .with_init(init.clone());
1366            gold.add_output("q", gold.add_dff(flip_flop));
1367            assert_simplify_isomorphic!(design, gold);
1368        }
1369    }
1370
1371    #[test]
1372    fn test_ff_simplify_enable_never_reset_prio() {
1373        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1374            let design = Design::new();
1375            let flip_flop = FlipFlop::new(design.add_input("d", 1), design.add_input1("c"))
1376                .with_reset(design.add_input1("r"))
1377                .with_enable(Net::ZERO)
1378                .with_init(init.clone());
1379            design.add_output("q", design.add_dff(flip_flop));
1380            let gold = Design::new();
1381            let flip_flop = FlipFlop::new(init.into(), gold.add_input1("c"))
1382                .with_reset(Net::ZERO)
1383                .with_enable(gold.add_input1("r"))
1384                .with_init(init.clone());
1385            gold.add_output("q", gold.add_dff(flip_flop));
1386            assert_simplify_isomorphic!(design, gold);
1387        }
1388    }
1389
1390    #[test]
1391    fn test_ff_simplify_always_clear() {
1392        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1393            let mut design = Design::new();
1394            let flip_flop = FlipFlop::new(design.add_input("d", 1), design.add_input1("c"))
1395                .with_clear(Net::ONE)
1396                .with_init(init.clone());
1397            design.add_output("q", design.add_dff(flip_flop));
1398            design.apply();
1399            simplify(&mut design);
1400            assert_netlist!(design, netlist_match! { [PConst@c] => c == *init; });
1401        }
1402    }
1403
1404    #[test]
1405    fn test_ff_reset_pos_matching() {
1406        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1407            let design = Design::new();
1408            let d = design.add_mux(design.add_input1("r"), init, design.add_input("d", 1));
1409            design.add_output("q", design.add_dff(FlipFlop::new(d, design.add_input1("c"))));
1410            let gold = Design::new();
1411            let ff = FlipFlop::new(gold.add_input("d", 1), gold.add_input1("c"))
1412                .with_reset_value(ControlNet::Pos(gold.add_input1("r")), init.clone());
1413            gold.add_output("q", gold.add_dff(ff));
1414            assert_simplify_isomorphic!(design, gold);
1415        }
1416    }
1417
1418    #[test]
1419    fn test_ff_reset_neg_matching() {
1420        for init in &[Const::undef(1), Const::zero(1), Const::ones(1)] {
1421            let design = Design::new();
1422            let d = design.add_mux(design.add_input1("r"), design.add_input("d", 1), init);
1423            design.add_output("q", design.add_dff(FlipFlop::new(d, design.add_input1("c"))));
1424            let gold = Design::new();
1425            let ff = FlipFlop::new(gold.add_input("d", 1), gold.add_input1("c"))
1426                .with_reset_value(ControlNet::Neg(gold.add_input1("r")), init.clone());
1427            gold.add_output("q", gold.add_dff(ff));
1428            assert_simplify_isomorphic!(design, gold);
1429        }
1430    }
1431
1432    #[test]
1433    fn test_ff_enable_pos_matching() {
1434        let design = Design::new();
1435        let q = design.add_void(1);
1436        let d = design.add_mux(design.add_input1("e"), design.add_input("d", 1), q.clone());
1437        design.replace_value(&q, design.add_dff(FlipFlop::new(d, design.add_input1("c"))));
1438        design.add_output("q", q);
1439        let gold = Design::new();
1440        let ff = FlipFlop::new(gold.add_input("d", 1), gold.add_input1("c"))
1441            .with_enable(ControlNet::Pos(gold.add_input1("e")));
1442        gold.add_output("q", gold.add_dff(ff));
1443        assert_simplify_isomorphic!(design, gold);
1444    }
1445
1446    #[test]
1447    fn test_ff_enable_neg_matching() {
1448        let design = Design::new();
1449        let q = design.add_void(1);
1450        let d = design.add_mux(design.add_input1("e"), q.clone(), design.add_input("d", 1));
1451        design.replace_value(&q, design.add_dff(FlipFlop::new(d, design.add_input1("c"))));
1452        design.add_output("q", q);
1453        let gold = Design::new();
1454        let ff = FlipFlop::new(gold.add_input("d", 1), gold.add_input1("c"))
1455            .with_enable(ControlNet::Neg(gold.add_input1("e")));
1456        gold.add_output("q", gold.add_dff(ff));
1457        assert_simplify_isomorphic!(design, gold);
1458    }
1459
1460    #[test]
1461    fn test_iobuf_simplify_enable() {
1462        for size in [1, 2] {
1463            let design = Design::new();
1464            let io_buffer = IoBuffer {
1465                io: design.add_io("io", size),
1466                output: design.add_input("o", size),
1467                enable: ControlNet::Pos(design.add_not(design.add_input("e", 1))[0]),
1468            };
1469            design.add_output("i", design.add_iobuf(io_buffer));
1470            let gold = Design::new();
1471            let io_buffer = IoBuffer {
1472                io: gold.add_io("io", size),
1473                output: gold.add_input("o", size),
1474                enable: ControlNet::Neg(gold.add_input1("e")),
1475            };
1476            gold.add_output("i", gold.add_iobuf(io_buffer));
1477            assert_simplify_isomorphic!(design, gold);
1478        }
1479        for size in [1, 2] {
1480            let design = Design::new();
1481            let io_buffer = IoBuffer {
1482                io: design.add_io("io", size),
1483                output: design.add_input("o", size),
1484                enable: ControlNet::Neg(design.add_not(design.add_input("e", 1))[0]),
1485            };
1486            design.add_output("i", design.add_iobuf(io_buffer));
1487            let gold = Design::new();
1488            let io_buffer = IoBuffer {
1489                io: gold.add_io("io", size),
1490                output: gold.add_input("o", size),
1491                enable: ControlNet::Pos(gold.add_input1("e")),
1492            };
1493            gold.add_output("i", gold.add_iobuf(io_buffer));
1494            assert_simplify_isomorphic!(design, gold);
1495        }
1496    }
1497
1498    #[test]
1499    fn test_iobuf_canonicalize_controls() {
1500        let design = Design::new();
1501        let io_buffer = IoBuffer {
1502            io: design.add_io("io", 1),
1503            output: design.add_input("o", 1),
1504            enable: ControlNet::Neg(Net::ONE),
1505        };
1506        design.add_output("i", design.add_iobuf(io_buffer));
1507        let gold = Design::new();
1508        let io_buffer =
1509            IoBuffer { io: gold.add_io("io", 1), output: gold.add_input("o", 1), enable: ControlNet::Pos(Net::ZERO) };
1510        gold.add_output("i", gold.add_iobuf(io_buffer));
1511        assert_simplify_isomorphic!(design, gold);
1512    }
1513
1514    #[cfg(not(feature = "verify"))]
1515    #[test]
1516    fn test_target_cell_simplify() {
1517        let target = MockTarget::new();
1518        let prototype = target.prototype("BUF1").unwrap();
1519        let design = Design::with_target(Some(target.clone()));
1520        let mut target_cell = TargetCell::new("BUF1", prototype);
1521        prototype.apply_input(&mut target_cell, "I", design.add_not(design.add_input("i", 1)));
1522        design.add_output("o", design.add_target(target_cell));
1523        let gold = Design::with_target(Some(target.clone()));
1524        let mut target_cell = TargetCell::new("BUF1", prototype);
1525        prototype.apply_input(&mut target_cell, "I", gold.add_input("i", 1));
1526        prototype.apply_param(&mut target_cell, "INVERT", Const::ones(1));
1527        gold.add_output("o", gold.add_target(target_cell));
1528        assert_simplify_isomorphic!(design, gold);
1529    }
1530}