aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/aiger/.gitignore4
-rwxr-xr-xtests/aiger/run-test.sh2
-rw-r--r--tests/arch/anlogic/dffs.ys3
-rw-r--r--tests/arch/anlogic/latches.ys26
-rwxr-xr-xtests/arch/anlogic/run-test.sh22
-rw-r--r--tests/arch/common/mul.v7
-rw-r--r--tests/arch/ecp5/bug2409.ys24
-rw-r--r--tests/arch/ecp5/fsm.ys6
-rwxr-xr-xtests/arch/ecp5/run-test.sh22
-rw-r--r--tests/arch/efinix/adffs.ys6
-rw-r--r--tests/arch/efinix/dffs.ys3
-rwxr-xr-xtests/arch/efinix/run-test.sh22
-rw-r--r--tests/arch/gowin/init-error.ys5
-rw-r--r--tests/arch/gowin/init.ys31
-rwxr-xr-xtests/arch/gowin/run-test.sh22
-rw-r--r--tests/arch/ice40/fsm.ys2
-rwxr-xr-xtests/arch/ice40/run-test.sh22
-rw-r--r--tests/arch/intel_alm/add_sub.ys10
-rw-r--r--tests/arch/intel_alm/adffs.ys52
-rw-r--r--tests/arch/intel_alm/blockram.ys6
-rw-r--r--tests/arch/intel_alm/counter.ys14
-rw-r--r--tests/arch/intel_alm/dffs.ys25
-rw-r--r--tests/arch/intel_alm/fsm.ys32
-rw-r--r--tests/arch/intel_alm/logic.ys14
-rw-r--r--tests/arch/intel_alm/lutram.ys23
-rw-r--r--tests/arch/intel_alm/mul.ys60
-rw-r--r--tests/arch/intel_alm/mux.ys47
-rw-r--r--tests/arch/intel_alm/quartus_ice.ys14
-rwxr-xr-xtests/arch/intel_alm/run-test.sh22
-rw-r--r--tests/arch/intel_alm/shifter.ys11
-rw-r--r--tests/arch/intel_alm/tribuf.ys14
-rw-r--r--tests/arch/nexus/.gitignore2
-rw-r--r--tests/arch/nexus/add_sub.ys21
-rw-r--r--tests/arch/nexus/adffs.ys44
-rw-r--r--tests/arch/nexus/blockram.ys18
-rw-r--r--tests/arch/nexus/blockram_dc.v25
-rw-r--r--tests/arch/nexus/counter.ys11
-rw-r--r--tests/arch/nexus/dffs.ys19
-rw-r--r--tests/arch/nexus/fsm.ys19
-rw-r--r--tests/arch/nexus/logic.ys8
-rw-r--r--tests/arch/nexus/lutram.ys19
-rw-r--r--tests/arch/nexus/mul.ys50
-rw-r--r--tests/arch/nexus/mux.ys43
-rw-r--r--tests/arch/nexus/run-test.sh4
-rw-r--r--tests/arch/nexus/shifter.ys9
-rw-r--r--tests/arch/nexus/tribuf.ys12
-rw-r--r--tests/arch/xilinx/attributes_test.ys6
-rw-r--r--tests/arch/xilinx/dsp_abc9.ys37
-rw-r--r--tests/arch/xilinx/fsm.ys16
-rw-r--r--tests/arch/xilinx/latches.ys3
-rw-r--r--tests/arch/xilinx/nosrl.ys41
-rw-r--r--tests/arch/xilinx/pmgen_xilinx_srl.ys2
-rwxr-xr-xtests/arch/xilinx/run-test.sh22
-rwxr-xr-xtests/gen-tests-makefile.sh94
-rwxr-xr-xtests/liberty/run-test.sh2
-rwxr-xr-xtests/memories/run-test.sh4
-rw-r--r--tests/opt/.gitignore1
-rw-r--r--tests/opt/bug2221.ys16
-rw-r--r--tests/opt/bug2311.ys14
-rw-r--r--tests/opt/bug2318.ys12
-rw-r--r--tests/opt/opt_clean_mem.ys49
-rw-r--r--tests/opt/opt_dff_arst.ys101
-rw-r--r--tests/opt/opt_dff_clk.ys45
-rw-r--r--tests/opt/opt_dff_const.ys49
-rw-r--r--tests/opt/opt_dff_dffmux.ys129
-rw-r--r--tests/opt/opt_dff_en.ys157
-rw-r--r--tests/opt/opt_dff_mux.ys86
-rw-r--r--tests/opt/opt_dff_qd.ys56
-rw-r--r--tests/opt/opt_dff_sr.ys304
-rw-r--r--tests/opt/opt_dff_srst.ys113
-rw-r--r--tests/opt/opt_expr_combined_assign.ys83
-rw-r--r--tests/opt/opt_rmdff.v26
-rw-r--r--tests/opt/opt_rmdff.ys26
-rw-r--r--tests/opt/opt_rmdff_sat.ys4
-rw-r--r--tests/opt/opt_share_bug2334.ys13
-rw-r--r--tests/opt/opt_share_bug2335.ys27
-rw-r--r--tests/opt/opt_share_bug2336.ys14
-rwxr-xr-xtests/opt/run-test.sh8
-rwxr-xr-xtests/opt_share/run-test.sh21
-rw-r--r--tests/sat/.gitignore1
-rw-r--r--tests/sat/dff.ys21
-rwxr-xr-xtests/sat/run-test.sh10
-rw-r--r--tests/sat/sizebits.sv61
-rw-r--r--tests/simple/const_branch_finish.v39
-rw-r--r--tests/simple/generate.v101
-rwxr-xr-xtests/simple/run-test.sh1
-rw-r--r--tests/simple/string_format.v7
-rw-r--r--tests/svtypes/multirange_array.sv16
-rw-r--r--tests/svtypes/multirange_subarray_access.ys12
-rwxr-xr-xtests/svtypes/run-test.sh22
-rw-r--r--tests/svtypes/static_cast_negative.ys4
-rw-r--r--tests/svtypes/static_cast_nonconst.ys4
-rw-r--r--tests/svtypes/static_cast_simple.sv64
-rw-r--r--tests/svtypes/static_cast_verilog.ys4
-rw-r--r--tests/svtypes/static_cast_zero.ys4
-rw-r--r--tests/svtypes/struct_array.sv22
-rw-r--r--tests/techmap/bug2183.ys11
-rw-r--r--tests/techmap/bug2321.ys15
-rw-r--r--tests/techmap/bug2332.ys11
-rw-r--r--tests/techmap/cellname.ys41
-rw-r--r--tests/techmap/clkbufmap.ys79
-rw-r--r--tests/techmap/dff2dffs.ys50
-rw-r--r--tests/techmap/dfflegalize_adff.ys103
-rw-r--r--tests/techmap/dfflegalize_adff_init.ys279
-rw-r--r--tests/techmap/dfflegalize_adlatch.ys51
-rw-r--r--tests/techmap/dfflegalize_adlatch_init.ys99
-rw-r--r--tests/techmap/dfflegalize_dff.ys306
-rw-r--r--tests/techmap/dfflegalize_dff_init.ys786
-rw-r--r--tests/techmap/dfflegalize_dffsr.ys88
-rw-r--r--tests/techmap/dfflegalize_dffsr_init.ys379
-rw-r--r--tests/techmap/dfflegalize_dlatch.ys42
-rw-r--r--tests/techmap/dfflegalize_dlatch_const.ys53
-rw-r--r--tests/techmap/dfflegalize_dlatch_init.ys82
-rw-r--r--tests/techmap/dfflegalize_dlatchsr.ys37
-rw-r--r--tests/techmap/dfflegalize_dlatchsr_init.ys127
-rw-r--r--tests/techmap/dfflegalize_inv.ys178
-rw-r--r--tests/techmap/dfflegalize_mince.ys53
-rw-r--r--tests/techmap/dfflegalize_minsrst.ys43
-rw-r--r--tests/techmap/dfflegalize_sr.ys74
-rw-r--r--tests/techmap/dfflegalize_sr_init.ys230
-rw-r--r--tests/techmap/dfflibmap-sim.v22
-rw-r--r--tests/techmap/dfflibmap.lib55
-rw-r--r--tests/techmap/dfflibmap.ys58
-rw-r--r--tests/techmap/dffunmap.ys100
-rw-r--r--tests/techmap/mem_simple_4x1_runtest.sh2
-rw-r--r--tests/techmap/recursive_runtest.sh2
-rwxr-xr-xtests/techmap/run-test.sh22
-rw-r--r--tests/techmap/shiftx2mux.ys12
-rw-r--r--tests/techmap/zinit.ys132
-rwxr-xr-xtests/tools/autotest.sh6
-rw-r--r--tests/various/const_arg_loop.v64
-rw-r--r--tests/various/const_arg_loop.ys1
-rw-r--r--tests/various/const_func.v87
-rw-r--r--tests/various/const_func.ys1
-rw-r--r--tests/various/const_func_block_var.v26
-rw-r--r--tests/various/const_func_block_var.ys1
-rw-r--r--tests/various/equiv_opt_undef.ys35
-rw-r--r--tests/various/integer_range_bad_syntax.ys6
-rw-r--r--tests/various/integer_real_bad_syntax.ys6
-rw-r--r--tests/various/logic_param_simple.ys9
-rw-r--r--tests/various/peepopt.ys143
-rw-r--r--tests/various/plugin.cc2
-rwxr-xr-xtests/various/run-test.sh22
-rw-r--r--tests/various/signed.ys28
-rw-r--r--tests/verilog/.gitignore2
-rw-r--r--tests/verilog/const_arst.ys24
-rw-r--r--tests/verilog/const_sr.ys25
-rwxr-xr-xtests/verilog/run-test.sh22
148 files changed, 6375 insertions, 608 deletions
diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore
index b76bdb653..54b4a279b 100644
--- a/tests/aiger/.gitignore
+++ b/tests/aiger/.gitignore
@@ -1,3 +1,3 @@
/*_ref.v
-/*.aag.log
-/*.aig.log
+/*.log
+/neg.out/
diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh
index de7bc68cf..bcf2b964a 100755
--- a/tests/aiger/run-test.sh
+++ b/tests/aiger/run-test.sh
@@ -55,5 +55,5 @@ done
for y in *.ys; do
echo "Running $y."
- ../../yosys $y -ql ${y%.*}.log
+ ../../yosys -ql ${y%.*}.log $y
done
diff --git a/tests/arch/anlogic/dffs.ys b/tests/arch/anlogic/dffs.ys
index d3281ab89..deb90e051 100644
--- a/tests/arch/anlogic/dffs.ys
+++ b/tests/arch/anlogic/dffs.ys
@@ -15,6 +15,5 @@ proc
equiv_opt -assert -map +/anlogic/cells_sim.v synth_anlogic # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffe # Constrain all select calls below inside the top module
-select -assert-count 1 t:AL_MAP_LUT3
select -assert-count 1 t:AL_MAP_SEQ
-select -assert-none t:AL_MAP_LUT3 t:AL_MAP_SEQ %% t:* %D
+select -assert-none t:AL_MAP_SEQ %% t:* %D
diff --git a/tests/arch/anlogic/latches.ys b/tests/arch/anlogic/latches.ys
index 8d66f77b3..34a3b14d0 100644
--- a/tests/arch/anlogic/latches.ys
+++ b/tests/arch/anlogic/latches.ys
@@ -3,31 +3,33 @@ design -save read
hierarchy -top latchp
proc
-# Can't run any sort of equivalence check because latches are blown to LUTs
-synth_anlogic
+equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic
+design -load postopt
cd latchp # Constrain all select calls below inside the top module
-select -assert-count 1 t:AL_MAP_LUT3
-select -assert-none t:AL_MAP_LUT3 %% t:* %D
+select -assert-count 1 t:AL_MAP_SEQ
+select -assert-count 1 t:AL_MAP_LUT1
+select -assert-none t:AL_MAP_SEQ t:AL_MAP_LUT1 %% t:* %D
design -load read
hierarchy -top latchn
proc
-# Can't run any sort of equivalence check because latches are blown to LUTs
-synth_anlogic
+equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic
+design -load postopt
cd latchn # Constrain all select calls below inside the top module
-select -assert-count 1 t:AL_MAP_LUT3
-select -assert-none t:AL_MAP_LUT3 %% t:* %D
+select -assert-count 1 t:AL_MAP_SEQ
+select -assert-none t:AL_MAP_SEQ %% t:* %D
design -load read
hierarchy -top latchsr
proc
-# Can't run any sort of equivalence check because latches are blown to LUTs
-synth_anlogic
+equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic
+design -load postopt
cd latchsr # Constrain all select calls below inside the top module
-select -assert-count 1 t:AL_MAP_LUT5
-select -assert-none t:AL_MAP_LUT5 %% t:* %D
+select -assert-count 1 t:AL_MAP_SEQ
+select -assert-count 2 t:AL_MAP_LUT3
+select -assert-none t:AL_MAP_SEQ t:AL_MAP_LUT3 %% t:* %D
diff --git a/tests/arch/anlogic/run-test.sh b/tests/arch/anlogic/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/anlogic/run-test.sh
+++ b/tests/arch/anlogic/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/common/mul.v b/tests/arch/common/mul.v
index 437a91cfc..baed64fcd 100644
--- a/tests/arch/common/mul.v
+++ b/tests/arch/common/mul.v
@@ -1,9 +1,10 @@
module top
+#(parameter X_WIDTH=6, Y_WIDTH=6, A_WIDTH=12)
(
- input [5:0] x,
- input [5:0] y,
+ input [X_WIDTH-1:0] x,
+ input [Y_WIDTH-1:0] y,
- output [11:0] A,
+ output [A_WIDTH-1:0] A,
);
assign A = x * y;
endmodule
diff --git a/tests/arch/ecp5/bug2409.ys b/tests/arch/ecp5/bug2409.ys
new file mode 100644
index 000000000..5ba9cec17
--- /dev/null
+++ b/tests/arch/ecp5/bug2409.ys
@@ -0,0 +1,24 @@
+read_verilog <<EOT
+module t (...);
+
+input CLK;
+input [10:0] A;
+input WE;
+input C;
+input [7:0] DI;
+output reg [7:0] DO;
+
+reg [7:0] mem[2047:0];
+
+always @(posedge CLK) begin
+ if (C)
+ if (WE)
+ mem[A] <= DI;
+ DO <= mem[A];
+end
+
+endmodule
+EOT
+
+synth_ecp5
+select -assert-count 1 t:DP16KD
diff --git a/tests/arch/ecp5/fsm.ys b/tests/arch/ecp5/fsm.ys
index ba91e5fc0..a77986bbc 100644
--- a/tests/arch/ecp5/fsm.ys
+++ b/tests/arch/ecp5/fsm.ys
@@ -10,8 +10,8 @@ sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd fsm # Constrain all select calls below inside the top module
-select -assert-count 1 t:L6MUX21
-select -assert-count 15 t:LUT4
-select -assert-count 6 t:PFUMX
+select -assert-max 1 t:L6MUX21
+select -assert-max 16 t:LUT4
+select -assert-max 7 t:PFUMX
select -assert-count 6 t:TRELLIS_FF
select -assert-none t:L6MUX21 t:LUT4 t:PFUMX t:TRELLIS_FF %% t:* %D
diff --git a/tests/arch/ecp5/run-test.sh b/tests/arch/ecp5/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/ecp5/run-test.sh
+++ b/tests/arch/ecp5/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/efinix/adffs.ys b/tests/arch/efinix/adffs.ys
index 49dc7f256..86d446439 100644
--- a/tests/arch/efinix/adffs.ys
+++ b/tests/arch/efinix/adffs.ys
@@ -32,9 +32,8 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd dffs # Constrain all select calls below inside the top module
select -assert-count 1 t:EFX_FF
select -assert-count 1 t:EFX_GBUFCE
-select -assert-count 1 t:EFX_LUT4
-select -assert-none t:EFX_FF t:EFX_GBUFCE t:EFX_LUT4 %% t:* %D
+select -assert-none t:EFX_FF t:EFX_GBUFCE %% t:* %D
design -load read
@@ -45,6 +44,5 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:EFX_FF
select -assert-count 1 t:EFX_GBUFCE
-select -assert-count 1 t:EFX_LUT4
-select -assert-none t:EFX_FF t:EFX_GBUFCE t:EFX_LUT4 %% t:* %D
+select -assert-none t:EFX_FF t:EFX_GBUFCE %% t:* %D
diff --git a/tests/arch/efinix/dffs.ys b/tests/arch/efinix/dffs.ys
index af787ab67..f9111873c 100644
--- a/tests/arch/efinix/dffs.ys
+++ b/tests/arch/efinix/dffs.ys
@@ -19,6 +19,5 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd dffe # Constrain all select calls below inside the top module
select -assert-count 1 t:EFX_FF
select -assert-count 1 t:EFX_GBUFCE
-select -assert-count 1 t:EFX_LUT4
-select -assert-none t:EFX_FF t:EFX_GBUFCE t:EFX_LUT4 %% t:* %D
+select -assert-none t:EFX_FF t:EFX_GBUFCE %% t:* %D
diff --git a/tests/arch/efinix/run-test.sh b/tests/arch/efinix/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/efinix/run-test.sh
+++ b/tests/arch/efinix/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/gowin/init-error.ys b/tests/arch/gowin/init-error.ys
new file mode 100644
index 000000000..de3813d6f
--- /dev/null
+++ b/tests/arch/gowin/init-error.ys
@@ -0,0 +1,5 @@
+read_verilog init.v
+chparam -set INIT 0 myDFF*P*
+hierarchy -top myDFFP
+logger -expect error "unsupported initial value and async reset value combination" 1
+synth_gowin
diff --git a/tests/arch/gowin/init.ys b/tests/arch/gowin/init.ys
index ddc0e4757..fba7c2fa5 100644
--- a/tests/arch/gowin/init.ys
+++ b/tests/arch/gowin/init.ys
@@ -30,45 +30,40 @@ select -assert-count 1 t:DFFRE
select -assert-count 1 t:DFFS
select -assert-count 1 t:DFFSE
-delete
design -load read
# these should synth to a flop with reset
chparam -set INIT 1 myDFF myDFFN myDFFE myDFFNE
-# async should give a warning
+# async would give an error
# sync should synth to a mux
-chparam -set INIT 0 myDFF*S* myDFF*P*
-chparam -set INIT 1 myDFF*R* myDFF*C*
+chparam -set INIT 0 myDFF*S*
+chparam -set INIT 1 myDFF*R*
proc
flatten
synth_gowin -run coarse:
# check the flops mapped as expected
-select -assert-count 1 t:DFF
+select -assert-count 2 t:DFF
select -assert-count 1 t:DFFC
select -assert-count 1 t:DFFCE
-select -assert-count 1 t:DFFE
-select -assert-count 1 t:DFFN
+select -assert-count 0 t:DFFE
+select -assert-count 2 t:DFFN
select -assert-count 1 t:DFFNC
select -assert-count 1 t:DFFNCE
-select -assert-count 1 t:DFFNE
+select -assert-count 0 t:DFFNE
select -assert-count 1 t:DFFNP
select -assert-count 1 t:DFFNPE
select -assert-count 0 t:DFFNR
select -assert-count 0 t:DFFNRE
-select -assert-count 2 t:DFFNS
-select -assert-count 2 t:DFFNSE
+select -assert-count 3 t:DFFNS
+select -assert-count 1 t:DFFNSE
select -assert-count 1 t:DFFP
select -assert-count 1 t:DFFPE
select -assert-count 0 t:DFFR
select -assert-count 0 t:DFFRE
-select -assert-count 2 t:DFFS
-select -assert-count 2 t:DFFSE
-select -assert-count 12 t:LUT2
-
-# check the expected leftover init values
-# this would happen if your reset value is not the initial value
-# which would be weird
-select -assert-count 8 a:init
+select -assert-count 3 t:DFFS
+select -assert-count 1 t:DFFSE
+select -assert-count 4 t:LUT2
+select -assert-count 4 t:LUT4
diff --git a/tests/arch/gowin/run-test.sh b/tests/arch/gowin/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/gowin/run-test.sh
+++ b/tests/arch/gowin/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/ice40/fsm.ys b/tests/arch/ice40/fsm.ys
index 223ba070e..e3b746202 100644
--- a/tests/arch/ice40/fsm.ys
+++ b/tests/arch/ice40/fsm.ys
@@ -12,5 +12,5 @@ cd fsm # Constrain all select calls below inside the top module
select -assert-count 4 t:SB_DFF
select -assert-count 2 t:SB_DFFESR
-select -assert-count 15 t:SB_LUT4
+select -assert-max 15 t:SB_LUT4
select -assert-none t:SB_DFFESR t:SB_DFF t:SB_LUT4 %% t:* %D
diff --git a/tests/arch/ice40/run-test.sh b/tests/arch/ice40/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/ice40/run-test.sh
+++ b/tests/arch/ice40/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/intel_alm/add_sub.ys b/tests/arch/intel_alm/add_sub.ys
index 4cb2c2e0d..0f552a27c 100644
--- a/tests/arch/intel_alm/add_sub.ys
+++ b/tests/arch/intel_alm/add_sub.ys
@@ -6,3 +6,13 @@ cd top # Constrain all select calls below inside the top module
stat
select -assert-count 8 t:MISTRAL_ALUT_ARITH
select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D
+
+design -reset
+read_verilog ../common/add_sub.v
+hierarchy -top top
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+stat
+select -assert-count 8 t:MISTRAL_ALUT_ARITH
+select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D
diff --git a/tests/arch/intel_alm/adffs.ys b/tests/arch/intel_alm/adffs.ys
index 5d8d3a220..4565dcc64 100644
--- a/tests/arch/intel_alm/adffs.ys
+++ b/tests/arch/intel_alm/adffs.ys
@@ -13,6 +13,18 @@ select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D
design -load read
+hierarchy -top adff
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adff # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_NOT
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D
+
+
+design -load read
hierarchy -top adffn
proc
equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
@@ -24,6 +36,17 @@ select -assert-none t:MISTRAL_FF %% t:* %D
design -load read
+hierarchy -top adffn
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adffn # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+
+design -load read
hierarchy -top dffs
proc
equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
@@ -36,13 +59,36 @@ select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D
design -load read
+hierarchy -top dffs
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffs # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 1 t:MISTRAL_ALUT2
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D
+
+
+design -load read
hierarchy -top ndffnr
proc
equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd ndffnr # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_FF
-select -assert-count 1 t:MISTRAL_NOT
-select -assert-count 1 t:MISTRAL_ALUT2
+select -assert-count 2 t:MISTRAL_NOT
-select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 %% t:* %D
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D
+
+
+design -load read
+hierarchy -top ndffnr
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd ndffnr # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+select -assert-count 2 t:MISTRAL_NOT
+
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D
diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys
new file mode 100644
index 000000000..610ae1ffd
--- /dev/null
+++ b/tests/arch/intel_alm/blockram.ys
@@ -0,0 +1,6 @@
+read_verilog ../common/blockram.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp
+synth_intel_alm -family cyclonev
+cd sync_ram_sdp
+select -assert-count 1 t:MISTRAL_M10K
+select -assert-none t:MISTRAL_M10K %% t:* %D
diff --git a/tests/arch/intel_alm/counter.ys b/tests/arch/intel_alm/counter.ys
index 945c318d8..50103fefc 100644
--- a/tests/arch/intel_alm/counter.ys
+++ b/tests/arch/intel_alm/counter.ys
@@ -9,5 +9,19 @@ cd top # Constrain all select calls below inside the top module
select -assert-count 2 t:MISTRAL_NOT
select -assert-count 8 t:MISTRAL_ALUT_ARITH
select -assert-count 8 t:MISTRAL_FF
+select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D
+
+
+design -reset
+read_verilog ../common/counter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -async2sync -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 2 t:MISTRAL_NOT
+select -assert-count 8 t:MISTRAL_ALUT_ARITH
+select -assert-count 8 t:MISTRAL_FF
select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D
diff --git a/tests/arch/intel_alm/dffs.ys b/tests/arch/intel_alm/dffs.ys
index cf29ad8e0..9ae6c637a 100644
--- a/tests/arch/intel_alm/dffs.ys
+++ b/tests/arch/intel_alm/dffs.ys
@@ -11,12 +11,33 @@ select -assert-count 1 t:MISTRAL_FF
select -assert-none t:MISTRAL_FF %% t:* %D
design -load read
+hierarchy -top dff
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dff # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+
+design -load read
hierarchy -top dffe
proc
equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclonev # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd dffe # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_FF
-select -assert-count 1 t:MISTRAL_ALUT3
-select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT3 %% t:* %D
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+
+design -load read
+hierarchy -top dffe
+proc
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffe # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_FF
+
+select -assert-none t:MISTRAL_FF %% t:* %D
diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys
index 8bb0ebab2..e54b5c21e 100644
--- a/tests/arch/intel_alm/fsm.ys
+++ b/tests/arch/intel_alm/fsm.ys
@@ -12,7 +12,33 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd fsm # Constrain all select calls below inside the top module
select -assert-count 6 t:MISTRAL_FF
+select -assert-max 1 t:MISTRAL_NOT
select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1
-select -assert-count 5 t:MISTRAL_ALUT5
-select -assert-count 1 t:MISTRAL_ALUT6
-select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
+select -assert-max 1 t:MISTRAL_ALUT3
+select -assert-max 2 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1
+select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4
+select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
+
+design -reset
+read_verilog ../common/fsm.v
+hierarchy -top fsm
+proc
+flatten
+
+equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx
+async2sync
+miter -equiv -make_assert -flatten gold gate miter
+sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
+
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd fsm # Constrain all select calls below inside the top module
+
+select -assert-count 6 t:MISTRAL_FF
+select -assert-max 1 t:MISTRAL_NOT
+select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1
+select -assert-max 2 t:MISTRAL_ALUT3 # Clang returns 2, GCC returns 1
+select -assert-max 2 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1
+select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4
+select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2
+select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
diff --git a/tests/arch/intel_alm/logic.ys b/tests/arch/intel_alm/logic.ys
index fad45db74..e8b26a524 100644
--- a/tests/arch/intel_alm/logic.ys
+++ b/tests/arch/intel_alm/logic.ys
@@ -9,3 +9,17 @@ select -assert-count 1 t:MISTRAL_NOT
select -assert-count 6 t:MISTRAL_ALUT2
select -assert-count 2 t:MISTRAL_ALUT4
select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D
+
+
+design -reset
+read_verilog ../common/logic.v
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_NOT
+select -assert-count 6 t:MISTRAL_ALUT2
+select -assert-count 2 t:MISTRAL_ALUT4
+select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D \ No newline at end of file
diff --git a/tests/arch/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys
index 6f997b67b..66f8a1536 100644
--- a/tests/arch/intel_alm/lutram.ys
+++ b/tests/arch/intel_alm/lutram.ys
@@ -7,7 +7,7 @@ memory
opt -full
miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
+sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
design -load postopt
cd lutram_1w1r
@@ -18,3 +18,24 @@ select -assert-count 8 t:MISTRAL_ALUT3
select -assert-count 17 t:MISTRAL_FF
select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D
+
+design -reset
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
+proc
+memory -nomap
+equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v -map +/intel_alm/common/mem_sim.v synth_intel_alm -family cyclonev -nobram
+memory
+opt -full
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter
+
+design -load postopt
+cd lutram_1w1r
+select -assert-count 16 t:MISTRAL_MLAB
+select -assert-count 1 t:MISTRAL_NOT
+select -assert-count 2 t:MISTRAL_ALUT2
+select -assert-count 8 t:MISTRAL_ALUT3
+select -assert-count 17 t:MISTRAL_FF
+select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D
diff --git a/tests/arch/intel_alm/mul.ys b/tests/arch/intel_alm/mul.ys
new file mode 100644
index 000000000..49934740f
--- /dev/null
+++ b/tests/arch/intel_alm/mul.ys
@@ -0,0 +1,60 @@
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL9X9
+select -assert-none t:MISTRAL_MUL9X9 %% t:* %D
+
+# Cyclone 10 GX does not have 9x9 multipliers.
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL18X18
+select -assert-none t:MISTRAL_MUL18X18 %% t:* %D
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL18X18
+select -assert-none t:MISTRAL_MUL18X18 %% t:* %D
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL27X27
+select -assert-none t:MISTRAL_MUL27X27 %% t:* %D
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL27X27
+select -assert-none t:MISTRAL_MUL27X27 %% t:* %D
diff --git a/tests/arch/intel_alm/mux.ys b/tests/arch/intel_alm/mux.ys
index 308e45268..ac3b9b08f 100644
--- a/tests/arch/intel_alm/mux.ys
+++ b/tests/arch/intel_alm/mux.ys
@@ -1,15 +1,26 @@
read_verilog ../common/mux.v
design -save read
+
hierarchy -top mux2
proc
equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux2 # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_ALUT3
+select -assert-none t:MISTRAL_ALUT3 %% t:* %D
+
+design -load read
+hierarchy -top mux2
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux2 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
select -assert-none t:MISTRAL_ALUT3 %% t:* %D
+
design -load read
hierarchy -top mux4
proc
@@ -17,9 +28,19 @@ equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cycl
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux4 # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_ALUT6
+select -assert-none t:MISTRAL_ALUT6 %% t:* %D
+
+design -load read
+hierarchy -top mux4
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux4 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT6
select -assert-none t:MISTRAL_ALUT6 %% t:* %D
+
design -load read
hierarchy -top mux8
proc
@@ -27,10 +48,20 @@ equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cycl
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux8 # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_ALUT3
-select -assert-count 1 t:MISTRAL_ALUT5
select -assert-count 2 t:MISTRAL_ALUT6
+select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D
+
+
+design -load read
+hierarchy -top mux8
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux8 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
+select -assert-count 2 t:MISTRAL_ALUT6
+select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D
-select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
design -load read
hierarchy -top mux16
@@ -39,6 +70,18 @@ equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cycl
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mux16 # Constrain all select calls below inside the top module
select -assert-count 1 t:MISTRAL_ALUT3
+select -assert-max 2 t:MISTRAL_ALUT5
+select -assert-max 5 t:MISTRAL_ALUT6
+select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D
+
+
+design -load read
+hierarchy -top mux16
+proc
+equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux16 # Constrain all select calls below inside the top module
+select -assert-count 1 t:MISTRAL_ALUT3
select -assert-count 2 t:MISTRAL_ALUT5
select -assert-count 4 t:MISTRAL_ALUT6
diff --git a/tests/arch/intel_alm/quartus_ice.ys b/tests/arch/intel_alm/quartus_ice.ys
index 4b9b54d10..a88226e13 100644
--- a/tests/arch/intel_alm/quartus_ice.ys
+++ b/tests/arch/intel_alm/quartus_ice.ys
@@ -10,3 +10,17 @@ EOT
synth_intel_alm -family cyclonev -quartus
select -assert-none w:*[* w:*]*
+
+design -reset
+read_verilog <<EOT
+// Verilog has syntax for raw identifiers, where you start it with \ and end it with a space.
+// This test crashes Quartus due to it parsing \a[10] as a wire slice and not a raw identifier.
+module top();
+ (* keep *) wire [31:0] \a[10] ;
+ (* keep *) wire b;
+ assign b = \a[10] [31];
+endmodule
+EOT
+
+synth_intel_alm -family cyclone10gx -quartus
+select -assert-none w:*[* w:*]*
diff --git a/tests/arch/intel_alm/run-test.sh b/tests/arch/intel_alm/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/intel_alm/run-test.sh
+++ b/tests/arch/intel_alm/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/intel_alm/shifter.ys b/tests/arch/intel_alm/shifter.ys
index 014dbd1a8..e307b5486 100644
--- a/tests/arch/intel_alm/shifter.ys
+++ b/tests/arch/intel_alm/shifter.ys
@@ -6,5 +6,16 @@ equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 8 t:MISTRAL_FF
+select -assert-none t:MISTRAL_FF %% t:* %D
+
+design -reset
+read_verilog ../common/shifter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:MISTRAL_FF
select -assert-none t:MISTRAL_FF %% t:* %D
diff --git a/tests/arch/intel_alm/tribuf.ys b/tests/arch/intel_alm/tribuf.ys
index 71b05a747..7f3b38493 100644
--- a/tests/arch/intel_alm/tribuf.ys
+++ b/tests/arch/intel_alm/tribuf.ys
@@ -9,5 +9,19 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd tristate # Constrain all select calls below inside the top module
#Internal cell type used. Need support it.
select -assert-count 1 t:$_TBUF_
+select -assert-none t:$_TBUF_ %% t:* %D
+
+design -reset
+read_verilog ../common/tribuf.v
+hierarchy -top tristate
+proc
+tribuf
+flatten
+synth
+equiv_opt -assert -map +/simcells.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd tristate # Constrain all select calls below inside the top module
+#Internal cell type used. Need support it.
+select -assert-count 1 t:$_TBUF_
select -assert-none t:$_TBUF_ %% t:* %D
diff --git a/tests/arch/nexus/.gitignore b/tests/arch/nexus/.gitignore
new file mode 100644
index 000000000..ba42e1ee6
--- /dev/null
+++ b/tests/arch/nexus/.gitignore
@@ -0,0 +1,2 @@
+/*.log
+/run-test.mk
diff --git a/tests/arch/nexus/add_sub.ys b/tests/arch/nexus/add_sub.ys
new file mode 100644
index 000000000..4317bab81
--- /dev/null
+++ b/tests/arch/nexus/add_sub.ys
@@ -0,0 +1,21 @@
+read_verilog ../common/add_sub.v
+hierarchy -top top
+proc
+design -save orig
+
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+stat
+select -assert-count 10 t:LUT4
+select -assert-none t:IB t:OB t:VLO t:LUT4 %% t:* %D
+
+design -load orig
+
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus -abc9 # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+stat
+select -assert-count 6 t:LUT4
+select -assert-count 4 t:WIDEFN9
+select -assert-none t:IB t:OB t:VLO t:LUT4 t:WIDEFN9 %% t:* %D
diff --git a/tests/arch/nexus/adffs.ys b/tests/arch/nexus/adffs.ys
new file mode 100644
index 000000000..f8796425c
--- /dev/null
+++ b/tests/arch/nexus/adffs.ys
@@ -0,0 +1,44 @@
+read_verilog ../common/adffs.v
+design -save read
+
+hierarchy -top adff
+proc
+equiv_opt -async2sync -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adff # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:FD1P3DX
+select -assert-none t:FD1P3DX t:IB t:OB t:VLO t:VHI %% t:* %D
+
+design -load read
+hierarchy -top adffn
+proc
+equiv_opt -async2sync -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd adffn # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:FD1P3DX
+select -assert-count 1 t:INV
+select -assert-none t:FD1P3DX t:INV t:LUT4 t:IB t:OB t:VLO t:VHI %% t:* %D
+
+design -load read
+hierarchy -top dffs
+proc
+equiv_opt -async2sync -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffs # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:FD1P3IX
+select -assert-count 1 t:LUT4
+select -assert-none t:FD1P3IX t:LUT4 t:IB t:OB t:VLO t:VHI %% t:* %D
+
+design -load read
+hierarchy -top ndffnr
+proc
+equiv_opt -async2sync -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd ndffnr # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:FD1P3IX
+select -assert-count 2 t:INV
+select -assert-none t:FD1P3IX t:INV t:LUT4 t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/blockram.ys b/tests/arch/nexus/blockram.ys
new file mode 100644
index 000000000..9540136d5
--- /dev/null
+++ b/tests/arch/nexus/blockram.ys
@@ -0,0 +1,18 @@
+read_verilog ../common/blockram.v
+design -save read
+
+# Check that we use the right dual and single clock variants
+
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_ram_sdp
+synth_nexus -top sync_ram_sdp
+cd sync_ram_sdp
+select -assert-count 1 t:PDPSC16K
+select -assert-none t:PDPSC16K t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
+
+design -reset
+read_verilog blockram_dc.v
+chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_ram_sdp_dc
+synth_nexus -top sync_ram_sdp_dc
+cd sync_ram_sdp_dc
+select -assert-count 1 t:PDP16K
+select -assert-none t:PDP16K t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/blockram_dc.v b/tests/arch/nexus/blockram_dc.v
new file mode 100644
index 000000000..4f5d4f5a6
--- /dev/null
+++ b/tests/arch/nexus/blockram_dc.v
@@ -0,0 +1,25 @@
+
+`default_nettype none
+module sync_ram_sdp_dc #(parameter DATA_WIDTH=8, ADDRESS_WIDTH=10)
+ (input wire clkw, clkr, write_enable,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire [ADDRESS_WIDTH-1:0] address_in_r, address_in_w,
+ output wire [DATA_WIDTH-1:0] data_out);
+
+ localparam WORD = (DATA_WIDTH-1);
+ localparam DEPTH = (2**ADDRESS_WIDTH-1);
+
+ reg [WORD:0] data_out_r;
+ reg [WORD:0] memory [0:DEPTH];
+
+ always @(posedge clkw) begin
+ if (write_enable)
+ memory[address_in_w] <= data_in;
+ end
+ always @(posedge clkr) begin
+ data_out_r <= memory[address_in_r];
+ end
+
+ assign data_out = data_out_r;
+
+endmodule // sync_ram_sdp_dc
diff --git a/tests/arch/nexus/counter.ys b/tests/arch/nexus/counter.ys
new file mode 100644
index 000000000..44421e377
--- /dev/null
+++ b/tests/arch/nexus/counter.ys
@@ -0,0 +1,11 @@
+read_verilog ../common/counter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -multiclock -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+stat
+select -assert-count 5 t:CCU2
+select -assert-count 8 t:FD1P3DX
+select -assert-none t:CCU2 t:FD1P3DX t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/dffs.ys b/tests/arch/nexus/dffs.ys
new file mode 100644
index 000000000..9ebf68bf4
--- /dev/null
+++ b/tests/arch/nexus/dffs.ys
@@ -0,0 +1,19 @@
+read_verilog ../common/dffs.v
+design -save read
+
+hierarchy -top dff
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dff # Constrain all select calls below inside the top module
+select -assert-count 1 t:FD1P3IX
+select -assert-none t:FD1P3IX t:IB t:OB t:VHI t:VLO %% t:* %D
+
+design -load read
+hierarchy -top dffe
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd dffe # Constrain all select calls below inside the top module
+select -assert-count 1 t:FD1P3IX
+select -assert-none t:FD1P3IX t:IB t:OB t:VHI t:VLO %% t:* %D
diff --git a/tests/arch/nexus/fsm.ys b/tests/arch/nexus/fsm.ys
new file mode 100644
index 000000000..24ad8fe5b
--- /dev/null
+++ b/tests/arch/nexus/fsm.ys
@@ -0,0 +1,19 @@
+read_verilog ../common/fsm.v
+hierarchy -top fsm
+proc
+flatten
+
+equiv_opt -run :prove -map +/nexus/cells_sim.v synth_nexus
+miter -equiv -make_assert -flatten gold gate miter
+sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter
+
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd fsm # Constrain all select calls below inside the top module
+
+stat
+
+select -assert-max 1 t:INV
+select -assert-max 2 t:LUT4
+select -assert-max 6 t:WIDEFN9
+select -assert-count 6 t:FD1P3IX
+select -assert-none t:LUT4 t:FD1P3IX t:WIDEFN9 t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/logic.ys b/tests/arch/nexus/logic.ys
new file mode 100644
index 000000000..cff61b509
--- /dev/null
+++ b/tests/arch/nexus/logic.ys
@@ -0,0 +1,8 @@
+read_verilog ../common/logic.v
+hierarchy -top top
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:LUT4
+select -assert-none t:LUT4 t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/lutram.ys b/tests/arch/nexus/lutram.ys
new file mode 100644
index 000000000..cd645f717
--- /dev/null
+++ b/tests/arch/nexus/lutram.ys
@@ -0,0 +1,19 @@
+read_verilog ../common/lutram.v
+hierarchy -top lutram_1w1r
+proc
+memory -nomap
+equiv_opt -run :prove -map +/nexus/cells_sim.v synth_nexus
+memory
+opt -full
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
+
+design -load postopt
+cd lutram_1w1r
+stat
+select -assert-count 8 t:WIDEFN9
+select -assert-count 16 t:LUT4
+select -assert-count 8 t:DPR16X4
+select -assert-count 36 t:FD1P3IX
+select -assert-none t:DPR16X4 t:FD1P3IX t:WIDEFN9 t:LUT4 t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/mul.ys b/tests/arch/nexus/mul.ys
new file mode 100644
index 000000000..65a2fd8c3
--- /dev/null
+++ b/tests/arch/nexus/mul.ys
@@ -0,0 +1,50 @@
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16
+hierarchy -top top
+proc
+
+design -save read
+
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:MULT9X9
+
+select -assert-none t:IB t:OB t:VLO t:VHI t:MULT9X9 %% t:* %D
+
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32
+hierarchy -top top
+proc
+# equivalence checking is too slow here
+synth_nexus
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:MULT18X18
+select -assert-none t:IB t:OB t:VLO t:VHI t:MULT18X18 %% t:* %D
+
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 32 -set Y_WIDTH 16 -set A_WIDTH 48
+hierarchy -top top
+proc
+# equivalence checking is too slow here
+synth_nexus
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:MULT18X36
+select -assert-none t:IB t:OB t:VLO t:VHI t:MULT18X36 %% t:* %D
+
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 32 -set Y_WIDTH 32 -set A_WIDTH 64
+hierarchy -top top
+proc
+# equivalence checking is too slow here
+synth_nexus
+cd top # Constrain all select calls below inside the top module
+select -assert-count 1 t:MULT36X36
+
+select -assert-none t:IB t:OB t:VLO t:VHI t:MULT36X36 %% t:* %D
diff --git a/tests/arch/nexus/mux.ys b/tests/arch/nexus/mux.ys
new file mode 100644
index 000000000..0e12d674a
--- /dev/null
+++ b/tests/arch/nexus/mux.ys
@@ -0,0 +1,43 @@
+read_verilog ../common/mux.v
+design -save read
+
+hierarchy -top mux2
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux2 # Constrain all select calls below inside the top module
+select -assert-count 1 t:LUT4
+select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:WIDEFN9 %% t:* %D
+
+design -load read
+hierarchy -top mux4
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux4 # Constrain all select calls below inside the top module
+select -assert-count 1 t:WIDEFN9
+
+select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:WIDEFN9 %% t:* %D
+
+design -load read
+hierarchy -top mux8
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux8 # Constrain all select calls below inside the top module
+select -assert-count 4 t:LUT4
+select -assert-count 1 t:WIDEFN9
+
+select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:WIDEFN9 %% t:* %D
+
+design -load read
+hierarchy -top mux16
+proc
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd mux16 # Constrain all select calls below inside the top module
+select -assert-min 11 t:LUT4
+select -assert-max 12 t:LUT4
+select -assert-count 1 t:WIDEFN9
+
+select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:WIDEFN9 %% t:* %D
diff --git a/tests/arch/nexus/run-test.sh b/tests/arch/nexus/run-test.sh
new file mode 100644
index 000000000..4be4b70ae
--- /dev/null
+++ b/tests/arch/nexus/run-test.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/arch/nexus/shifter.ys b/tests/arch/nexus/shifter.ys
new file mode 100644
index 000000000..a8e34b0f9
--- /dev/null
+++ b/tests/arch/nexus/shifter.ys
@@ -0,0 +1,9 @@
+read_verilog ../common/shifter.v
+hierarchy -top top
+proc
+flatten
+equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+select -assert-count 8 t:FD1P3IX
+select -assert-none t:FD1P3IX t:WIDEFN9 t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/nexus/tribuf.ys b/tests/arch/nexus/tribuf.ys
new file mode 100644
index 000000000..70fb7cb5f
--- /dev/null
+++ b/tests/arch/nexus/tribuf.ys
@@ -0,0 +1,12 @@
+read_verilog ../common/tribuf.v
+hierarchy -top tristate
+proc
+tribuf
+flatten
+synth
+equiv_opt -assert -map +/nexus/cells_sim.v -map +/simcells.v synth_nexus # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd tristate # Constrain all select calls below inside the top module
+select -assert-count 1 t:OBZ
+select -assert-count 1 t:INV
+select -assert-none t:OBZ t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
diff --git a/tests/arch/xilinx/attributes_test.ys b/tests/arch/xilinx/attributes_test.ys
index 7bdd94a63..58552d8fb 100644
--- a/tests/arch/xilinx/attributes_test.ys
+++ b/tests/arch/xilinx/attributes_test.ys
@@ -16,8 +16,7 @@ select -assert-count 8 t:RAM32X1D
# Set ram_style distributed to blockram memory; will be implemented as distributed
design -reset
read_verilog ../common/memory_attributes/attributes_test.v
-prep
-setattr -mod -set ram_style "distributed" block_ram
+setattr -set ram_style "distributed" block_ram/m:*
synth_xilinx -top block_ram -noiopad
cd block_ram # Constrain all select calls below inside the top module
select -assert-count 32 t:RAM128X1D
@@ -25,8 +24,7 @@ select -assert-count 32 t:RAM128X1D
# Set synthesis, logic_block to blockram memory; will be implemented as distributed
design -reset
read_verilog ../common/memory_attributes/attributes_test.v
-prep
-setattr -mod -set logic_block 1 block_ram
+setattr -set logic_block 1 block_ram/m:*
synth_xilinx -top block_ram -noiopad
cd block_ram # Constrain all select calls below inside the top module
select -assert-count 0 t:RAMB18E1
diff --git a/tests/arch/xilinx/dsp_abc9.ys b/tests/arch/xilinx/dsp_abc9.ys
new file mode 100644
index 000000000..909e54149
--- /dev/null
+++ b/tests/arch/xilinx/dsp_abc9.ys
@@ -0,0 +1,37 @@
+read_verilog <<EOT
+module top(input [24:0] A, input [17:0] B, output [47:0] P);
+DSP48E1 #(.PREG(0)) dsp(.A(A), .B(B), .P(P));
+endmodule
+EOT
+techmap -autoproc -wb -map +/xilinx/cells_sim.v
+opt
+scc -expect 0
+
+
+design -reset
+read_verilog <<EOT
+module top(input signed [24:0] A, input signed [17:0] B, output [47:0] P);
+assign P = A * B;
+endmodule
+EOT
+synth_xilinx -abc9
+techmap -autoproc -wb -map +/xilinx/cells_sim.v
+opt -full -fine
+select -assert-count 1 t:$mul
+select -assert-count 0 t:* t:$mul %D
+
+
+design -reset
+read_verilog -icells -formal <<EOT
+module top(output [42:0] P);
+\$__MUL25X18 mul (.A(42), .B(42), .Y(P));
+assert property (P == 42*42);
+endmodule
+EOT
+techmap -map +/xilinx/xc7_dsp_map.v
+verilog_defaults -add -D ALLOW_WHITEBOX_DSP48E1
+synth_xilinx -abc9
+techmap -autoproc -wb -map +/xilinx/cells_sim.v
+opt -full -fine
+select -assert-count 0 t:* t:$assert %d
+sat -verify -prove-asserts
diff --git a/tests/arch/xilinx/fsm.ys b/tests/arch/xilinx/fsm.ys
index fec4c6082..ace646af4 100644
--- a/tests/arch/xilinx/fsm.ys
+++ b/tests/arch/xilinx/fsm.ys
@@ -13,12 +13,11 @@ design -load postopt # load the post-opt design (otherwise equiv_opt loads the p
cd fsm # Constrain all select calls below inside the top module
stat
select -assert-count 1 t:BUFG
-select -assert-count 4 t:FDRE
-select -assert-count 1 t:FDSE
-select -assert-count 1 t:LUT2
-select -assert-count 3 t:LUT5
+select -assert-count 6 t:FDRE
+select -assert-count 1 t:LUT4
+select -assert-count 4 t:LUT5
select -assert-count 1 t:LUT6
-select -assert-none t:BUFG t:FDRE t:FDSE t:LUT2 t:LUT5 t:LUT6 %% t:* %D
+select -assert-none t:BUFG t:FDRE t:LUT4 t:LUT5 t:LUT6 %% t:* %D
design -load orig
@@ -32,7 +31,6 @@ stat
select -assert-count 1 t:BUFG
select -assert-count 6 t:FDRE
select -assert-count 1 t:LUT1
-select -assert-count 3 t:LUT3
-select -assert-count 6 t:LUT4
-select -assert-count 6 t:MUXF5
-select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT3 t:LUT4 t:MUXF5 %% t:* %D
+select -assert-count 8 t:LUT4
+select -assert-count 5 t:MUXF5
+select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT4 t:MUXF5 %% t:* %D
diff --git a/tests/arch/xilinx/latches.ys b/tests/arch/xilinx/latches.ys
index e226c2ec8..ee87fee21 100644
--- a/tests/arch/xilinx/latches.ys
+++ b/tests/arch/xilinx/latches.ys
@@ -18,9 +18,8 @@ equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad #
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd latchn # Constrain all select calls below inside the top module
select -assert-count 1 t:LDCE
-select -assert-count 1 t:INV
-select -assert-none t:LDCE t:INV %% t:* %D
+select -assert-none t:LDCE %% t:* %D
design -load read
diff --git a/tests/arch/xilinx/nosrl.ys b/tests/arch/xilinx/nosrl.ys
new file mode 100644
index 000000000..31bd5d377
--- /dev/null
+++ b/tests/arch/xilinx/nosrl.ys
@@ -0,0 +1,41 @@
+read_verilog <<EOT
+
+module xilinx_srl_static_test(input i, clk, output [1:0] q);
+reg head = 1'b0;
+reg [3:0] shift1 = 4'b0000;
+reg [3:0] shift2 = 4'b0000;
+
+always @(posedge clk) begin
+ head <= i;
+ shift1 <= {shift1[2:0], head};
+ shift2 <= {shift2[2:0], head};
+end
+
+assign q = {shift2[3], shift1[3]};
+endmodule
+
+EOT
+
+design -save read
+
+hierarchy -top xilinx_srl_static_test
+proc
+#equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
+equiv_opt -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd xilinx_srl_static_test # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:BUFG
+select -assert-count 1 t:SRL16E
+select -assert-none t:BUFG t:SRL16E %% t:* %D
+
+design -load read
+hierarchy -top xilinx_srl_static_test
+proc
+equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -nosrl -noiopad # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd xilinx_srl_static_test # Constrain all select calls below inside the top module
+stat
+select -assert-count 1 t:BUFG
+select -assert-count 5 t:FDRE
+select -assert-none t:BUFG t:FDRE %% t:* %D
diff --git a/tests/arch/xilinx/pmgen_xilinx_srl.ys b/tests/arch/xilinx/pmgen_xilinx_srl.ys
index e76fb20ab..9a5e70ea9 100644
--- a/tests/arch/xilinx/pmgen_xilinx_srl.ys
+++ b/tests/arch/xilinx/pmgen_xilinx_srl.ys
@@ -35,7 +35,6 @@ design -stash gate
design -copy-from gold -as gold pmtest_xilinx_srl_pm_fixed
design -copy-from gate -as gate pmtest_xilinx_srl_pm_fixed
-dff2dffe -unmap # sat does not support flops-with-enable yet
miter -equiv -flatten -make_assert gold gate miter
sat -set-init-zero -seq 5 -verify -prove-asserts miter
@@ -52,6 +51,5 @@ design -stash gate
design -copy-from gold -as gold pmtest_xilinx_srl_pm_variable
design -copy-from gate -as gate pmtest_xilinx_srl_pm_variable
-dff2dffe -unmap # sat does not support flops-with-enable yet
miter -equiv -flatten -make_assert gold gate miter
sat -set-init-zero -seq 5 -verify -prove-asserts miter
diff --git a/tests/arch/xilinx/run-test.sh b/tests/arch/xilinx/run-test.sh
index bf19b887d..4be4b70ae 100755
--- a/tests/arch/xilinx/run-test.sh
+++ b/tests/arch/xilinx/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh
new file mode 100755
index 000000000..ab8fb7013
--- /dev/null
+++ b/tests/gen-tests-makefile.sh
@@ -0,0 +1,94 @@
+set -eu
+
+YOSYS_BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../ >/dev/null 2>&1 && pwd)"
+
+# $ generate_target target_name test_command
+generate_target() {
+ target_name=$1
+ test_command=$2
+ echo "all: $target_name"
+ echo ".PHONY: $target_name"
+ echo "$target_name:"
+ printf "\t@%s\n" "$test_command"
+ printf "\t@echo 'Passed %s'\n" "$target_name"
+}
+
+# $ generate_ys_test ys_file [yosys_args]
+generate_ys_test() {
+ ys_file=$1
+ yosys_args=${2:-}
+ generate_target "$ys_file" "$YOSYS_BASEDIR/yosys -ql ${ys_file%.*}.log $yosys_args $ys_file"
+}
+
+# $ generate_bash_test bash_file
+generate_bash_test() {
+ bash_file=$1
+ generate_target "$bash_file" "bash -v $bash_file >${bash_file%.*}.log 2>&1"
+}
+
+# $ generate_tests [-y|--yosys-scripts] [-s|--prove-sv] [-b|--bash] [-a|--yosys-args yosys_args]
+generate_tests() {
+ do_ys=false
+ do_sv=false
+ do_sh=false
+ yosys_args=""
+
+ while [[ $# -gt 0 ]]; do
+ arg="$1"
+ case "$arg" in
+ -y|--yosys-scripts)
+ do_ys=true
+ shift
+ ;;
+ -s|--prove-sv)
+ do_sv=true
+ shift
+ ;;
+ -b|--bash)
+ do_sh=true
+ shift
+ ;;
+ -a|--yosys-args)
+ yosys_args+="$2"
+ shift
+ shift
+ ;;
+ *)
+ echo >&2 "Unknown argument: $1"
+ exit 1
+ esac
+ done
+
+ if [[ ! ( $do_ys = true || $do_sv = true || $do_sh = true ) ]]; then
+ echo >&2 "Error: No file types selected"
+ exit 1
+ fi
+
+ echo ".PHONY: all"
+ echo "all:"
+
+ if [[ $do_ys = true ]]; then
+ for x in *.ys; do
+ generate_ys_test "$x" "$yosys_args"
+ done
+ fi;
+ if [[ $do_sv = true ]]; then
+ for x in *.sv; do
+ if [ ! -f "${x%.sv}.ys" ]; then
+ generate_ys_test "$x" "-p \"prep -top top; sat -verify -prove-asserts\" $yosys_args"
+ fi;
+ done
+ fi;
+ if [[ $do_sh == true ]]; then
+ for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ generate_bash_test "$s"
+ fi
+ done
+ fi
+}
+
+run_tests() {
+ generate_tests "$@" > run-test.mk
+ exec ${MAKE:-make} -f run-test.mk
+}
diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh
index 7e2ed2370..61f19b09b 100755
--- a/tests/liberty/run-test.sh
+++ b/tests/liberty/run-test.sh
@@ -5,6 +5,6 @@ for x in *.lib; do
echo "Running $x.."
echo "read_verilog small.v" > test.ys
echo "synth -top small" >> test.ys
- echo "dfflibmap -liberty ${x}" >> test.ys
+ echo "dfflibmap -info -liberty ${x}" >> test.ys
../../yosys -ql ${x%.lib}.log -s test.ys
done
diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh
index 8d1a8b413..376f5bf79 100755
--- a/tests/memories/run-test.sh
+++ b/tests/memories/run-test.sh
@@ -9,12 +9,12 @@ while getopts "A:S:" opt
do
case "$opt" in
A) abcopt="-A $OPTARG" ;;
- S) seed="-S $OPTARG" ;;
+ S) seed="$OPTARG" ;;
esac
done
shift "$((OPTIND-1))"
-bash ../tools/autotest.sh $abcopt $seed -G *.v
+${MAKE:-make} -f ../tools/autotest.mk SEED="$seed" EXTRA_FLAGS="$abcopt" *.v
for f in `egrep -l 'expect-(wr-ports|rd-ports|rd-clk)' *.v`; do
echo -n "Testing expectations for $f .."
diff --git a/tests/opt/.gitignore b/tests/opt/.gitignore
index 397b4a762..8355de9dc 100644
--- a/tests/opt/.gitignore
+++ b/tests/opt/.gitignore
@@ -1 +1,2 @@
*.log
+run-test.mk
diff --git a/tests/opt/bug2221.ys b/tests/opt/bug2221.ys
new file mode 100644
index 000000000..8ac380243
--- /dev/null
+++ b/tests/opt/bug2221.ys
@@ -0,0 +1,16 @@
+read_verilog <<EOT
+module test (
+ input [1:0] a,
+ input [1:0] b,
+ output [5:0] y
+);
+
+wire [5:0] aa = {a, 4'h0};
+wire [5:0] bb = {b, 4'h0};
+
+assign y = aa * bb;
+
+endmodule
+EOT
+
+equiv_opt -assert opt_expr
diff --git a/tests/opt/bug2311.ys b/tests/opt/bug2311.ys
new file mode 100644
index 000000000..455147cd3
--- /dev/null
+++ b/tests/opt/bug2311.ys
@@ -0,0 +1,14 @@
+read_verilog -icells << EOT
+
+module top(...);
+
+input A;
+output Y;
+
+$_XNOR_ x (.A(A), .B(A), .Y(Y));
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_expr
diff --git a/tests/opt/bug2318.ys b/tests/opt/bug2318.ys
new file mode 100644
index 000000000..9de6f88ec
--- /dev/null
+++ b/tests/opt/bug2318.ys
@@ -0,0 +1,12 @@
+read_verilog <<EOT
+module t(input [3:0] A, input [3:0] B, output signed [3:0] Y);
+
+wire [7:0] P = A * B;
+wire signed [7:0] SP = P;
+wire signed [3:0] SB = B;
+assign Y = SP / SB;
+
+endmodule
+EOT
+
+equiv_opt -assert peepopt
diff --git a/tests/opt/opt_clean_mem.ys b/tests/opt/opt_clean_mem.ys
new file mode 100644
index 000000000..b35b15871
--- /dev/null
+++ b/tests/opt/opt_clean_mem.ys
@@ -0,0 +1,49 @@
+read_verilog <<EOT
+module top(...);
+
+input [7:0] wa;
+input [7:0] ra1;
+input [7:0] ra2;
+input [7:0] wd;
+input clk;
+wire [7:0] rd1;
+wire [7:0] rd2;
+
+reg [7:0] mem[0:7];
+
+always @(posedge clk)
+ mem[wa] <= wd;
+assign rd1 = mem[ra1];
+assign rd2 = mem[ra2];
+
+initial mem[8'h12] = 8'h34;
+
+endmodule
+EOT
+
+proc
+memory_dff
+
+select -assert-count 2 t:$memrd
+select -assert-count 1 t:$memwr
+select -assert-count 1 t:$meminit
+design -save orig
+
+opt_clean
+select -assert-none t:$memrd
+select -assert-none t:$memwr
+select -assert-none t:$meminit
+
+design -load orig
+expose top/rd1
+opt_clean
+select -assert-count 1 t:$memrd
+select -assert-count 1 t:$memwr
+select -assert-count 1 t:$meminit
+
+design -load orig
+expose top/rd1 top/rd2
+opt_clean
+select -assert-count 2 t:$memrd
+select -assert-count 1 t:$memwr
+select -assert-count 1 t:$meminit
diff --git a/tests/opt/opt_dff_arst.ys b/tests/opt/opt_dff_arst.ys
new file mode 100644
index 000000000..2aa3b7a26
--- /dev/null
+++ b/tests/opt/opt_dff_arst.ys
@@ -0,0 +1,101 @@
+### Always-active ARST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [11:0] Q;
+input ARST;
+input EN;
+
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .ARST(1'b1), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .ARST(1'b0), .EN(EN), .D(D), .Q(Q[3:2]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.EN(EN), .ARST(1'b1), .D(D), .Q(Q[5:4]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .ARST(1'bx), .D(D), .Q(Q[7:6]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .ARST(1'bx), .EN(EN), .D(D), .Q(Q[9:8]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff5 (.EN(EN), .ARST(1'bx), .D(D), .Q(Q[11:10]));
+
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:*
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:*
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$_DFF_???_
+select -assert-count 2 t:$_DFFE_????_
+select -assert-count 2 t:$_DLATCH_???_
+
+design -reset
+
+
+### Never-active ARST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [5:0] Q;
+input ARST;
+input EN;
+
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .ARST(1'b0), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .ARST(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$adlatch #(.EN_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.EN(EN), .ARST(1'b0), .D(D), .Q(Q[5:4]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$adff
+select -assert-none t:$adffe
+select -assert-none t:$adlatch
+select -assert-count 1 t:$dff
+select -assert-count 1 t:$dffe
+select -assert-count 1 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_DFF_???_
+select -assert-none t:$_DFFE_????_
+select -assert-none t:$_DLATCH_???_
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 2 t:$_DFFE_PP_
+select -assert-count 2 t:$_DLATCH_P_
+
+design -reset
diff --git a/tests/opt/opt_dff_clk.ys b/tests/opt/opt_dff_clk.ys
new file mode 100644
index 000000000..f3aefa406
--- /dev/null
+++ b/tests/opt/opt_dff_clk.ys
@@ -0,0 +1,45 @@
+### Never-toggling CLK removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input EN;
+input [1:0] D;
+(* init = 18'h15555 *)
+output [17:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(1'b0), .D(D), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(1'bx), .ARST(ARST), .D(D), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(1'b0), .EN(EN), .ARST(ARST), .D(D), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(1'b1), .SRST(SRST), .D(D), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(1'bx), .EN(EN), .SRST(SRST), .D(D), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(1'bx), .EN(EN), .SRST(SRST), .D(D), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(1'bx), .EN(EN), .SET(SET), .CLR(CLR), .D(D), .Q(Q[17:16]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$dlatch
+select -assert-count 2 t:$sr
+select -assert-none t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 4 t:$_DLATCH_?_
+select -assert-count 4 t:$_SR_??_
+select -assert-none t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
diff --git a/tests/opt/opt_dff_const.ys b/tests/opt/opt_dff_const.ys
new file mode 100644
index 000000000..6a7dec7fa
--- /dev/null
+++ b/tests/opt/opt_dff_const.ys
@@ -0,0 +1,49 @@
+### Replace FFs with a const.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input EN;
+(* init=84'haaaaaaaaaaaaaaaaaaaaa *)
+output [83:0] Q;
+input SRST;
+input ARST;
+input [3:0] CLR;
+input [3:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(4)) ff0 (.CLK(CLK), .D(4'hc), .Q(Q[3:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(4)) ff1 (.CLK(CLK), .EN(EN), .D(4'hc), .Q(Q[7:4]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff2 (.CLK(CLK), .ARST(ARST), .D(8'hcc), .Q(Q[15:8]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(8'hcc), .Q(Q[23:16]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff4 (.CLK(CLK), .SRST(SRST), .D(8'hcc), .Q(Q[31:24]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(8'hcc), .Q(Q[39:32]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(8'hf0), .WIDTH(8)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(8'hcc), .Q(Q[47:40]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(8)) ff7 (.CLK(CLK), .SET({SET, 4'hf}), .CLR({4'h0, CLR}), .D(8'hcc), .Q(Q[55:48]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b0), .SET_POLARITY(1'b1), .WIDTH(8)) ff8 (.CLK(CLK), .EN(EN), .SET({SET, 4'h0}), .CLR({4'hf, CLR}), .D(8'hcc), .Q(Q[63:56]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(4)) ff9 (.EN(EN), .D(4'hc), .Q(Q[67:64]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(8'hf0), .WIDTH(8)) ff10 (.EN(EN), .ARST(ARST), .D(8'hcc), .Q(Q[75:68]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b1), .WIDTH(8)) ff11 (.EN(EN), .SET({SET, 4'h0}), .CLR({4'h0, CLR}), .D(8'hcc), .Q(Q[83:76]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 1 t:$dff r:WIDTH=2 %i
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 1 t:$adff r:WIDTH=6 %i
+select -assert-count 1 t:$adffe r:WIDTH=6 %i
+select -assert-count 1 t:$sdff r:WIDTH=6 %i
+select -assert-count 1 t:$sdffe r:WIDTH=6 %i
+select -assert-count 1 t:$sdffce r:WIDTH=6 %i
+select -assert-count 1 t:$dffsr r:WIDTH=6 %i
+select -assert-count 1 t:$dffsre r:WIDTH=6 %i
+select -assert-count 1 t:$dlatch r:WIDTH=2 %i
+select -assert-count 1 t:$adlatch r:WIDTH=6 %i
+select -assert-count 1 t:$dlatchsr r:WIDTH=6 %i
diff --git a/tests/opt/opt_dff_dffmux.ys b/tests/opt/opt_dff_dffmux.ys
new file mode 100644
index 000000000..43190cc31
--- /dev/null
+++ b/tests/opt/opt_dff_dffmux.ys
@@ -0,0 +1,129 @@
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o);
+ always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o);
+ always @(posedge clk) if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o);
+ always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=2 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+###################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o);
+ always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+select -assert-count 1 t:$dffe r:WIDTH=4 %i
+select -assert-count 0 t:$dffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o);
+ always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i;
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+ always @(posedge clk) begin
+ if (ce) o <= i;
+ if (!rstn) o <= 4'b1111;
+ end
+endmodule
+EOT
+
+proc
+equiv_opt -assert opt
+design -load postopt
+wreduce
+select -assert-count 1 t:$sdffe r:WIDTH=2 %i
+select -assert-count 0 t:$sdffe %% t:* %D
+
+####################
+
+design -reset
+read_verilog <<EOT
+module opt_dffmuxext_signed_rst_init(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
+ initial o <= 4'b0010;
+ always @(posedge clk) begin
+ if (ce) o <= i;
+ if (!rstn) o <= 4'b1111;
+ end
+endmodule
+EOT
+
+proc
+# NB: equiv_opt uses equiv_induct which covers
+# only the induction half of temporal induction
+# --- missing the base-case half
+# This makes it akin to `sat -tempinduct-inductonly`
+# instead of `sat -tempinduct-baseonly` or
+# `sat -tempinduct` which is necessary for this
+# testcase
+#equiv_opt -assert opt
+
+design -save gold
+opt
+wreduce
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -tempinduct -verify -prove-asserts -show-ports miter
+
+design -load gate
+select -assert-count 1 t:$sdffe r:WIDTH=3 %i
+select -assert-count 0 t:$sdffe %% t:* %D
diff --git a/tests/opt/opt_dff_en.ys b/tests/opt/opt_dff_en.ys
new file mode 100644
index 000000000..06ee6c63d
--- /dev/null
+++ b/tests/opt/opt_dff_en.ys
@@ -0,0 +1,157 @@
+### Always-active EN removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [15:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .EN(1'b1), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .EN(1'b0), .ARST(ARST), .D(D), .Q(Q[3:2]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .EN(1'b1), .SRST(SRST), .D(D), .Q(Q[5:4]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(1'b1), .SRST(SRST), .D(D), .Q(Q[7:6]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff4 (.CLK(CLK), .EN(1'b0), .SET(SET), .CLR(CLR), .D(D), .Q(Q[9:8]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff5 (.EN(1'b1), .D(D), .Q(Q[11:10]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff6 (.EN(1'b0), .ARST(ARST), .D(D), .Q(Q[13:12]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.EN(1'b0), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+# Equivalence check will fail for unmapped adlatch and dlatchsr due to negative hold hack.
+delete top/ff6 top/ff7
+equiv_opt -undef -assert -multiclock opt_dff
+
+design -load orig
+delete top/ff6 top/ff7
+simplemap
+equiv_opt -undef -assert -multiclock opt_dff
+
+design -load orig
+opt_dff
+select -assert-count 0 t:$dffe
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$sdffe
+select -assert-count 0 t:$sdffce
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatch
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatchsr
+select -assert-count 1 t:$dff
+select -assert-count 2 t:$sdff
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$dffsr
+
+design -load orig
+simplemap
+opt_dff
+select -assert-count 0 t:$_DFFE_*
+select -assert-count 0 t:$_SDFFE_*
+select -assert-count 0 t:$_SDFFCE_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCH*
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 4 t:$_SDFF_PP?_
+select -assert-count 2 t:$_DFF_PP?_
+select -assert-count 2 t:$_DFFSR_PNP_
+
+design -reset
+
+
+
+### Never-active EN removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+(* init = 32'h55555555 *)
+output [31:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .EN(1'b0), .D(D), .Q(Q[1:0]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .EN(1'b1), .ARST(ARST), .D(D), .Q(Q[3:2]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .EN(1'b0), .SRST(SRST), .D(D), .Q(Q[5:4]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(1'b0), .SRST(SRST), .D(D), .Q(Q[7:6]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff4 (.CLK(CLK), .EN(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[9:8]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff5 (.EN(1'b0), .D(D), .Q(Q[11:10]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff6 (.EN(1'b1), .ARST(ARST), .D(D), .Q(Q[13:12]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.EN(1'b1), .SET(SET), .CLR(CLR), .D(D), .Q(Q[15:14]));
+
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff8 (.CLK(CLK), .EN(1'bx), .D(D), .Q(Q[17:16]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff9 (.CLK(CLK), .EN(1'bx), .ARST(ARST), .D(D), .Q(Q[19:18]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff10 (.CLK(CLK), .EN(1'bx), .SRST(SRST), .D(D), .Q(Q[21:20]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff11 (.CLK(CLK), .EN(1'bx), .SRST(SRST), .D(D), .Q(Q[23:22]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff12 (.CLK(CLK), .EN(1'bx), .SET(SET), .CLR(CLR), .D(D), .Q(Q[25:24]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff13 (.EN(1'bx), .D(D), .Q(Q[27:26]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff14 (.EN(1'bx), .ARST(ARST), .D(D), .Q(Q[29:28]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff15 (.EN(1'bx), .SET(SET), .CLR(CLR), .D(D), .Q(Q[31:30]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 2 t:$dffe
+select -assert-count 4 t:$dlatch
+select -assert-count 4 t:$sr
+select -assert-none t:$dffe t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$dffe
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+select -assert-count 1 t:$dffsre
+select -assert-count 3 t:$dlatch
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatchsr
+select -assert-count 2 t:$sr
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 4 t:$_DFFE_??_
+select -assert-count 8 t:$_DLATCH_?_
+select -assert-count 8 t:$_SR_??_
+select -assert-none t:$_DFFE_??_ t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 4 t:$_DFFE_??_
+select -assert-count 2 t:$_DFFE_????_
+select -assert-count 2 t:$_SDFFE_????_
+select -assert-count 2 t:$_SDFFCE_????_
+select -assert-count 2 t:$_DFFSRE_????_
+select -assert-count 6 t:$_DLATCH_?_
+select -assert-count 2 t:$_DLATCH_???_
+select -assert-count 2 t:$_DLATCHSR_???_
+select -assert-count 4 t:$_SR_??_
diff --git a/tests/opt/opt_dff_mux.ys b/tests/opt/opt_dff_mux.ys
new file mode 100644
index 000000000..ed01bed59
--- /dev/null
+++ b/tests/opt/opt_dff_mux.ys
@@ -0,0 +1,86 @@
+### CE and SRST matching.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input NE, NS;
+input EN;
+output [23:0] Q;
+input [23:0] D;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .D(NS ? 2'h2 : NE ? D[1:0] : Q[1:0]), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(CLK), .EN(EN), .D(NS ? 2'h2 : NE ? D[3:2] : Q[3:2]), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .ARST(ARST), .D(NS ? 2'h2 : NE ? D[5:4] : Q[5:4]), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(NS ? 2'h2 : NE ? D[7:6] : Q[7:6]), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[9:8] : Q[9:8]), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[11:10] : Q[11:10]), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(NS ? 2'h2 : NE ? D[13:12] : Q[13:12]), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(CLK), .SET(SET), .CLR(CLR), .D(NS ? 2'h2 : NE ? D[15:14] : Q[15:14]), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(CLK), .EN(EN), .SET(SET), .CLR(CLR), .D(NS ? 2'h2 : NE ? D[17:16] : Q[17:16]), .Q(Q[17:16]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 0 t:$dffe
+select -assert-count 0 t:$adff
+select -assert-count 2 t:$adffe
+select -assert-count 0 t:$dffsr
+select -assert-count 2 t:$dffsre
+select -assert-count 0 t:$sdff
+select -assert-count 3 t:$sdffe
+select -assert-count 2 t:$sdffce
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -nodffe -nosdff
+design -load postopt
+clean
+select -assert-count 1 t:$dff
+select -assert-count 1 t:$dffe
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+equiv_opt -undef -assert -multiclock opt_dff -nodffe
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 0 t:$dffe
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 2 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 2 t:$sdffce
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -nosdff
+design -load postopt
+clean
+select -assert-count 0 t:$dff
+select -assert-count 2 t:$dffe
+select -assert-count 0 t:$adff
+select -assert-count 2 t:$adffe
+select -assert-count 0 t:$dffsr
+select -assert-count 2 t:$dffsre
+select -assert-count 0 t:$sdff
+select -assert-count 2 t:$sdffe
+select -assert-count 1 t:$sdffce
diff --git a/tests/opt/opt_dff_qd.ys b/tests/opt/opt_dff_qd.ys
new file mode 100644
index 000000000..afc96c42f
--- /dev/null
+++ b/tests/opt/opt_dff_qd.ys
@@ -0,0 +1,56 @@
+### Q = D case.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input EN;
+(* init = 24'h555555 *)
+output [23:0] Q;
+input SRST;
+input ARST;
+input [1:0] CLR;
+input [1:0] SET;
+
+$dff #(.CLK_POLARITY(1'b1), .WIDTH(2)) ff0 (.CLK(CLK), .D(Q[1:0]), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(2)) ff1 (.CLK(CLK), .EN(EN), .D(Q[3:2]), .Q(Q[3:2]));
+$adff #(.CLK_POLARITY(1'b1), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .ARST(ARST), .D(Q[5:4]), .Q(Q[5:4]));
+$adffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .EN(EN), .ARST(ARST), .D(Q[7:6]), .Q(Q[7:6]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(SRST), .D(Q[9:8]), .Q(Q[9:8]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(Q[11:10]), .Q(Q[11:10]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff6 (.CLK(CLK), .EN(EN), .SRST(SRST), .D(Q[13:12]), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b1), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff7 (.CLK(CLK), .SET(SET), .CLR(CLR), .D(Q[15:14]), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff8 (.CLK(CLK), .EN(EN), .SET(SET), .CLR(CLR), .D(Q[17:16]), .Q(Q[17:16]));
+
+$dlatch #(.EN_POLARITY(1'b1), .WIDTH(2)) ff9 (.EN(EN), .D(Q[19:18]), .Q(Q[19:18]));
+$adlatch #(.EN_POLARITY(1'b0), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2), .WIDTH(2)) ff10 (.EN(EN), .ARST(ARST), .D(Q[21:20]), .Q(Q[21:20]));
+$dlatchsr #(.EN_POLARITY(1'b0), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0), .WIDTH(2)) ff11 (.EN(EN), .SET(SET), .CLR(CLR), .D(Q[23:22]), .Q(Q[23:22]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+# Equivalence check will fail for unmapped adlatch and dlatchsr due to negative hold hack.
+delete top/ff10 top/ff11
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+
+design -load orig
+opt_dff -keepdc
+select -assert-count 1 t:$and
+select -assert-count 3 t:$dffe
+select -assert-count 3 t:$dlatch
+select -assert-count 3 t:$sr
+select -assert-none t:$and t:$dffe t:$dlatch t:$sr %% %n t:* %i
+
+design -load orig
+simplemap
+opt_dff -keepdc
+select -assert-count 2 t:$_AND_
+select -assert-count 6 t:$_DFFE_??_
+select -assert-count 6 t:$_DLATCH_?_
+select -assert-count 6 t:$_SR_??_
+select -assert-none t:$_AND_ t:$_DFFE_??_ t:$_DLATCH_?_ t:$_SR_??_ %% %n t:* %i
+
diff --git a/tests/opt/opt_dff_sr.ys b/tests/opt/opt_dff_sr.ys
new file mode 100644
index 000000000..daedb115c
--- /dev/null
+++ b/tests/opt/opt_dff_sr.ys
@@ -0,0 +1,304 @@
+### Always-active SET/CLR removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .D(D), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({CLR, CLR, CLR, 1'b1, 1'b0, 1'bx}), .SET({1'b1, 1'b0, 1'bx, SET, SET, SET}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsr r:WIDTH=2 %i
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dffsre r:WIDTH=2 %i
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$dlatchsr r:WIDTH=2 %i
+select -assert-none t:$sr
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsr r:WIDTH=4 %i
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dffsre r:WIDTH=4 %i
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$dlatchsr r:WIDTH=4 %i
+select -assert-count 1 t:$sr
+select -assert-count 1 t:$sr r:WIDTH=4 %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 1 t:$_DFF_PP0_
+select -assert-count 1 t:$_DFF_PP1_
+select -assert-count 1 t:$_DFFE_PN0P_
+select -assert-count 1 t:$_DFFE_PN1P_
+select -assert-count 1 t:$_DLATCH_PP0_
+select -assert-count 1 t:$_DLATCH_PN1_
+select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_DFFE_PN0P_ t:$_DFFE_PN1P_ t:$_DLATCH_PP0_ t:$_DLATCH_PN1_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$_DFF_PP0_
+select -assert-count 1 t:$_DFF_PP1_
+select -assert-count 2 t:$_DFFSR_PPP_
+select -assert-count 1 t:$_DFFE_PN0P_
+select -assert-count 1 t:$_DFFE_PN1P_
+select -assert-count 2 t:$_DFFSRE_PNNP_
+select -assert-count 1 t:$_DLATCH_PP0_
+select -assert-count 1 t:$_DLATCH_PN1_
+select -assert-count 2 t:$_DLATCHSR_PNP_
+select -assert-count 1 t:$_DLATCH_P_
+select -assert-count 1 t:$_DLATCH_N_
+select -assert-count 2 t:$_SR_PN_
+select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_DFFSR_PPP_ t:$_DFFE_PN0P_ t:$_DFFE_PN1P_ t:$_DFFSRE_PNNP_ t:$_DLATCH_PP0_ t:$_DLATCH_PN1_ t:$_DLATCHSR_PNP_ t:$_NOT_ t:$_DLATCH_N_ t:$_DLATCH_P_ t:$_SR_PN_ %% %n t:* %i
+
+design -reset
+
+
+
+### Never-active CLR removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR(6'h00), .SET({6{SET}}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR(6'h3f), .SET({6{SET}}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR(6'h00), .SET({6{SET}}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR(6'h3f), .SET({6{SET}}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatchsr
+select -assert-count 0 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatch
+
+design -reset
+
+
+
+### Never-active CLR removal (not applicable).
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input ALT;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR(6'h00), .SET({{5{SET}}, ALT}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR(6'h3f), .SET({{5{SET}}, ALT}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR(6'h00), .SET({{5{SET}}, ALT}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR(6'h3f), .SET({{5{SET}}, ALT}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 0 t:$adff
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$_DFFSR_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCHSR_*
+select -assert-count 0 t:$_SR_*
+select -assert-count 6 t:$_DFF_PP1_
+select -assert-count 6 t:$_DFFE_PN1P_
+select -assert-count 6 t:$_DLATCH_PN1_
+select -assert-count 6 t:$_DLATCH_P_
+
+design -reset
+
+
+
+### Never-active SET removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({6{CLR}}), .SET(6'h00), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({6{CLR}}), .SET(6'h3f), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({6{CLR}}), .SET(6'h3f), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({6{CLR}}), .SET(6'h00), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 0 t:$dlatchsr
+select -assert-count 0 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adlatch
+select -assert-count 1 t:$dlatch
+
+design -reset
+
+
+
+### Never-active CLR removal (not applicable).
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input CLR;
+input SET;
+input ALT;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({{5{CLR}}, ALT}), .SET(6'h00), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({{5{CLR}}, ALT}), .SET(6'h3f), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({{5{CLR}}, ALT}), .SET(6'h3f), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({{5{CLR}}, ALT}), .SET(6'h00), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 0 t:$adff
+select -assert-count 0 t:$adffe
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$_DFFSR_*
+select -assert-count 0 t:$_DFFSRE_*
+select -assert-count 0 t:$_DLATCHSR_*
+select -assert-count 0 t:$_SR_*
+select -assert-count 6 t:$_DFF_PP0_
+select -assert-count 6 t:$_DFFE_PN0P_
+select -assert-count 6 t:$_DLATCH_PP0_
+select -assert-count 6 t:$_DLATCH_N_
+
+design -reset
+
+
+
+### SET/CLR merge into ARST.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [5:0] D;
+output [23:0] Q;
+input ARST;
+input EN;
+
+$dffsr #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b1), .CLR_POLARITY(1'b1), .WIDTH(6)) ff0 (.CLK(CLK), .CLR({ARST, 5'h00}), .SET({1'b0, {5{ARST}}}), .D(D), .Q(Q[5:0]));
+$dffsre #(.CLK_POLARITY(1'b1), .SET_POLARITY(1'b0), .CLR_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(6)) ff1 (.CLK(CLK), .EN(EN), .D(D), .CLR({ARST, 5'h1f}), .SET({1'b1, {5{ARST}}}), .Q(Q[11:6]));
+$dlatchsr #(.SET_POLARITY(1'b0), .CLR_POLARITY(1'b1), .EN_POLARITY(1'b1), .WIDTH(6)) ff2 (.EN(EN), .D(D), .CLR({ARST, 5'h00}), .SET({1'b1, {5{ARST}}}), .Q(Q[17:12]));
+$sr #(.SET_POLARITY(1'b1), .CLR_POLARITY(1'b0), .WIDTH(6)) ff3 (.CLR({ARST, 5'h1f}), .SET({1'b0, {5{ARST}}}), .Q(Q[23:18]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 0 t:$dffsr
+select -assert-count 0 t:$dffsre
+select -assert-count 1 t:$dlatchsr
+select -assert-count 1 t:$sr
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adff r:ARST_VALUE=6'h1f %i
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$adffe r:ARST_VALUE=6'h1f %i
+select -assert-count 0 t:$adlatch
+select -assert-count 0 t:$dlatch
diff --git a/tests/opt/opt_dff_srst.ys b/tests/opt/opt_dff_srst.ys
new file mode 100644
index 000000000..4a77de0b8
--- /dev/null
+++ b/tests/opt/opt_dff_srst.ys
@@ -0,0 +1,113 @@
+### Always-active SRST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+(* init=12'h555 *)
+output [11:0] Q;
+input SRST;
+input EN;
+
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .SRST(1'b1), .D(D), .Q(Q[1:0]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .SRST(1'b0), .EN(EN), .D(D), .Q(Q[3:2]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .SRST(1'b0), .EN(EN), .D(D), .Q(Q[5:4]));
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff3 (.CLK(CLK), .SRST(1'bx), .D(D), .Q(Q[7:6]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff4 (.CLK(CLK), .SRST(1'bx), .EN(EN), .D(D), .Q(Q[9:8]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff5 (.CLK(CLK), .SRST(1'bx), .EN(EN), .D(D), .Q(Q[11:10]));
+
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-count 0 t:$sdff
+select -assert-count 0 t:$sdffe
+select -assert-count 0 t:$sdffce
+select -assert-count 4 t:$dff
+select -assert-count 2 t:$dffe
+
+design -load orig
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 1 t:$sdff
+select -assert-count 1 t:$sdffe
+select -assert-count 1 t:$sdffce
+select -assert-count 2 t:$dff
+select -assert-count 1 t:$dffe
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_SDFF_???_
+select -assert-none t:$_SDFFE_????_
+select -assert-none t:$_SDFFCE_????_
+select -assert-count 8 t:$_DFF_?_
+select -assert-count 4 t:$_DFFE_??_
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff -keepdc
+design -load postopt
+select -assert-count 2 t:$_SDFF_???_
+select -assert-count 2 t:$_SDFFE_????_
+select -assert-count 2 t:$_SDFFCE_????_
+select -assert-count 4 t:$_DFF_?_
+select -assert-count 2 t:$_DFFE_??_
+
+design -reset
+
+
+### Never-active SRST removal.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input CLK;
+input [1:0] D;
+output [5:0] Q;
+input SRST;
+input EN;
+
+$sdff #(.CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2), .WIDTH(2)) ff0 (.CLK(CLK), .SRST(1'b0), .D(D), .Q(Q[1:0]));
+$sdffe #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff1 (.CLK(CLK), .SRST(1'b1), .EN(EN), .D(D), .Q(Q[3:2]));
+$sdffce #(.CLK_POLARITY(1'b1), .EN_POLARITY(1'b1), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2), .WIDTH(2)) ff2 (.CLK(CLK), .SRST(1'b1), .EN(EN), .D(D), .Q(Q[5:4]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$sdff
+select -assert-none t:$sdffe
+select -assert-none t:$sdffce
+select -assert-count 1 t:$dff
+select -assert-count 2 t:$dffe
+
+design -load orig
+simplemap
+
+equiv_opt -undef -assert -multiclock opt_dff
+design -load postopt
+select -assert-none t:$_SDFF_???_
+select -assert-none t:$_SDFFE_????_
+select -assert-none t:$_SDFFCE_????_
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 4 t:$_DFFE_PP_
+
+design -reset
+
diff --git a/tests/opt/opt_expr_combined_assign.ys b/tests/opt/opt_expr_combined_assign.ys
new file mode 100644
index 000000000..b18923c7b
--- /dev/null
+++ b/tests/opt/opt_expr_combined_assign.ys
@@ -0,0 +1,83 @@
+read_verilog -sv <<EOT
+module opt_expr_or_test(input [3:0] i, input [7:0] j, output [8:0] o);
+wire[8:0] a = 8'b0;
+initial begin
+ a |= i;
+ a |= j;
+end
+ assign o = a;
+endmodule
+EOT
+proc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$or r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=4 %i %i %i
+
+design -reset
+read_verilog -sv <<EOT
+module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
+wire[8:0] a = 8'b0;
+initial begin
+ a += i;
+ a += j;
+end
+ assign o = a;
+endmodule
+EOT
+proc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$add r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+design -reset
+read_verilog -sv <<EOT
+module opt_expr_xor_test(input [3:0] i, input [7:0] j, output [8:0] o);
+wire[8:0] a = 8'b0;
+initial begin
+ a ^= i;
+ a ^= j;
+end
+ assign o = a;
+endmodule
+EOT
+proc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$xor r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=4 %i %i %i
+
+design -reset
+read_verilog -sv <<EOT
+module opt_expr_sub_test(input [3:0] i, input [7:0] j, output [8:0] o);
+wire[8:0] a = 8'b0;
+initial begin
+ a -= i;
+ a -= j;
+end
+ assign o = a;
+endmodule
+EOT
+proc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$sub r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+design -reset
+read_verilog -sv <<EOT
+module opt_expr_and_test(input [3:0] i, input [7:0] j, output [8:0] o);
+wire[8:0] a = 8'b11111111;
+initial begin
+ a &= i;
+ a &= j;
+end
+ assign o = a;
+endmodule
+EOT
+proc
+equiv_opt -assert opt_expr -fine
+design -load postopt
+
+select -assert-count 1 t:$and r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=4 %i %i %i
diff --git a/tests/opt/opt_rmdff.v b/tests/opt/opt_rmdff.v
index b1c06703c..536bf1d4e 100644
--- a/tests/opt/opt_rmdff.v
+++ b/tests/opt/opt_rmdff.v
@@ -1,50 +1,50 @@
module opt_rmdff_test (input C, input D, input E, output [29:0] Q);
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); // EN is never active
-(* init = "1'b1" *) wire Q1; assign Q[1] = Q1;
+(* init = 1'b1 *) wire Q1; assign Q[1] = Q1;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q1)); // EN is never active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); // EN is don't care
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); // EN is always active
-(* init = "1'b0" *) wire Q4; assign Q[4] = Q4;
+(* init = 1'b0 *) wire Q4; assign Q[4] = Q4;
\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q4)); // EN is always active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[5])); // EN is never active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove6 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[6])); // EN is don't care
-(* init = "1'b0" *) wire Q7; assign Q[7] = Q7;
+(* init = 1'b0 *) wire Q7; assign Q[7] = Q7;
\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep7 (.CLK(C), .D(D), .EN(E), .Q(Q7)); // EN is non constant
\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); // EN is never active
-(* init = "1'b1" *) wire Q9; assign Q[9] = Q9;
+(* init = 1'b1 *) wire Q9; assign Q[9] = Q9;
\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'b0), .Q(Q9)); // EN is never active
\$_DFFE_PP_ remove10 (.C(C), .D(D), .E(1'bx), .Q(Q[10])); // EN is don't care
\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); // EN is always active
-(* init = "1'b0" *) wire Q12; assign Q[12] = Q12;
+(* init = 1'b0 *) wire Q12; assign Q[12] = Q12;
\$_DFFE_PP_ keep12 (.C(C), .D(D), .E(1'b1), .Q(Q12)); // EN is always active
\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); // EN is never active
-(* init = "1'b1" *) wire Q14; assign Q[14] = Q14;
+(* init = 1'b1 *) wire Q14; assign Q[14] = Q14;
\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'b1), .Q(Q14)); // EN is never active
\$_DFFE_NN_ remove15 (.C(C), .D(D), .E(1'bx), .Q(Q[15])); // EN is don't care
\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); // EN is always active
-(* init = "1'b0" *) wire Q17; assign Q[17] = Q17;
+(* init = 1'b0 *) wire Q17; assign Q[17] = Q17;
\$_DFFE_NN_ keep17 (.C(C), .D(D), .E(1'b0), .Q(Q17)); // EN is always active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove18 (.CLK(1'b0), .D(D), .EN(E), .Q(Q[18])); // CLK is constant
-(* init = "1'b1" *) wire Q19; assign Q[19] = Q19;
+(* init = 1'b1 *) wire Q19; assign Q[19] = Q19;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove19 (.CLK(1'b1), .D(D), .EN(E), .Q(Q19)); // CLK is constant
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove20 (.CLK(C), .D(1'bx), .EN(E), .Q(Q[20])); // D is undriven, Q has no initial value
-(* init = "1'b0" *) wire Q21; assign Q[21] = Q21;
+(* init = 1'b0 *) wire Q21; assign Q[21] = Q21;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep21 (.CLK(C), .D(1'bx), .EN(E), .Q(Q21)); // D is undriven, Q has initial value
//\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) remove22 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q[22])); // D is constant, no initial Q value, EN is always active
// // (TODO, Q starts with 1'bx and becomes 1'b0)
-(* init = "1'b0" *) wire Q23; assign Q[23] = Q23;
+(* init = 1'b0 *) wire Q23; assign Q[23] = Q23;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) noenable23 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q23)); // D is constant, initial Q value same as D, EN is always active
-(* init = "1'b1" *) wire Q24; assign Q[24] = Q24;
+(* init = 1'b1 *) wire Q24; assign Q[24] = Q24;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) keep24 (.CLK(C), .D(1'b0), .EN(1'b0), .Q(Q24)); // D is constant, initial Q value NOT same as D, EN is always active
-(* init = "1'b1" *) wire Q25; assign Q[25] = Q25;
+(* init = 1'b1 *) wire Q25; assign Q[25] = Q25;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove25 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q25)); // D is constant, EN is never active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove26 (.CLK(C), .D(Q[26]), .EN(1'b1), .Q(Q[26])); // D is Q, EN is always active
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove27 (.CLK(C), .D(Q[27]), .EN(1'b1), .Q(Q[27])); // D is Q, EN is never active, but no initial value
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove28 (.CLK(C), .D(Q[28]), .EN(E), .Q(Q[28])); // EN is nonconst, but no initial value
-(* init = "1'b1" *) wire Q29; assign Q[29] = Q29;
+(* init = 1'b1 *) wire Q29; assign Q[29] = Q29;
\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep29 (.CLK(C), .D(Q[29]), .EN(1'b1), .Q(Q29)); // EN is always active, but with initial value
endmodule
diff --git a/tests/opt/opt_rmdff.ys b/tests/opt/opt_rmdff.ys
index 83a162f44..998414597 100644
--- a/tests/opt/opt_rmdff.ys
+++ b/tests/opt/opt_rmdff.ys
@@ -1,9 +1,10 @@
read_verilog -icells opt_rmdff.v
prep
design -stash gold
+
read_verilog -icells opt_rmdff.v
proc
-opt_rmdff
+opt_dff
select -assert-count 0 c:remove*
select -assert-min 7 c:keep*
@@ -14,13 +15,18 @@ design -stash gate
design -import gold -as gold
design -import gate -as gate
-equiv_make gold gate equiv
-hierarchy -top equiv
-equiv_simple -undef
-equiv_status -assert
+cd gold
+# fix up the "EN is don't care" cases, so that the gold output can't
+# become defined by using the properties of an undefined enable. (Both
+# remove6 and remove15 have active-low enables.)
+connect -port remove6 EN 1'b1
+connect -port remove15 E 1'b1
+cd ..
+
+clk2fflogic
+opt_clean
+
+miter -equiv -ignore_gold_x -make_assert -make_outputs -make_outcmp -flatten gold gate miter
+hierarchy -top miter
-#design -load gold
-#stat
-#
-#design -load gate
-#stat
+sat -verify -prove-asserts -enable_undef -set-init-undef -seq 10 -show-public miter
diff --git a/tests/opt/opt_rmdff_sat.ys b/tests/opt/opt_rmdff_sat.ys
index 1c3dd9c05..231c43ecb 100644
--- a/tests/opt/opt_rmdff_sat.ys
+++ b/tests/opt/opt_rmdff_sat.ys
@@ -1,5 +1,5 @@
read_verilog opt_rmdff_sat.v
prep -flatten
-opt_rmdff -sat
-synth
+opt_dff -sat -nosdff
+simplemap
select -assert-count 5 t:$_DFF_P_
diff --git a/tests/opt/opt_share_bug2334.ys b/tests/opt/opt_share_bug2334.ys
new file mode 100644
index 000000000..004d98349
--- /dev/null
+++ b/tests/opt/opt_share_bug2334.ys
@@ -0,0 +1,13 @@
+read_verilog <<EOT
+
+module t(input [3:0] A, input [3:0] B, input [3:0] C, input S, output [3:0] Y);
+
+wire [3:0] t = A + C;
+
+assign Y = S ? A + B : {4{t[0]}};
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_share
diff --git a/tests/opt/opt_share_bug2335.ys b/tests/opt/opt_share_bug2335.ys
new file mode 100644
index 000000000..0846a9ec3
--- /dev/null
+++ b/tests/opt/opt_share_bug2335.ys
@@ -0,0 +1,27 @@
+read_verilog <<EOT
+
+module top(...);
+
+input [3:0] A, B, C;
+input S;
+input [1:0] T;
+output [3:0] X;
+output reg [3:0] Y;
+
+wire [3:0] D = A + B;
+
+assign X = S ? D : A + C;
+always @* begin
+ case(T)
+ 2'b01: Y <= A;
+ 2'b10: Y <= B;
+ default: Y <= D;
+ endcase
+end
+
+endmodule
+
+EOT
+
+proc
+equiv_opt -assert opt_share
diff --git a/tests/opt/opt_share_bug2336.ys b/tests/opt/opt_share_bug2336.ys
new file mode 100644
index 000000000..cd472ef46
--- /dev/null
+++ b/tests/opt/opt_share_bug2336.ys
@@ -0,0 +1,14 @@
+read_verilog <<EOT
+
+module top(input [3:0] A, B, C, input S, output [2:0] O);
+
+wire [3:0] tb = A + B;
+wire [3:0] tc = A + C;
+
+assign O = S ? tb[3:1] : tc[3:1];
+
+endmodule
+
+EOT
+
+equiv_opt -assert opt_share
diff --git a/tests/opt/run-test.sh b/tests/opt/run-test.sh
index 44ce7e674..2007cd6e4 100755
--- a/tests/opt/run-test.sh
+++ b/tests/opt/run-test.sh
@@ -1,6 +1,4 @@
#!/bin/bash
-set -e
-for x in *.ys; do
- echo "Running $x.."
- ../../yosys -ql ${x%.ys}.log $x
-done
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts
diff --git a/tests/opt_share/run-test.sh b/tests/opt_share/run-test.sh
index e01552646..e0008a259 100755
--- a/tests/opt_share/run-test.sh
+++ b/tests/opt_share/run-test.sh
@@ -22,12 +22,23 @@ mkdir -p temp
echo "generating tests.."
python3 generate.py -c $count $seed
+{
+ echo ".PHONY: all"
+ echo "all:"
+
+ for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
+ idx=$( printf "%05d" $i )
+ echo ".PHONY: test-$idx"
+ echo "all: test-$idx"
+ echo "test-$idx:"
+ printf "\t@%s\n" \
+ "echo -n [$i]" \
+ "../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys"
+ done
+} > temp/makefile
+
echo "running tests.."
-for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do
- echo -n "[$i]"
- idx=$( printf "%05d" $i )
- ../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys
-done
+${MAKE:-make} -f temp/makefile
echo
failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [246] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) )
diff --git a/tests/sat/.gitignore b/tests/sat/.gitignore
index 397b4a762..8355de9dc 100644
--- a/tests/sat/.gitignore
+++ b/tests/sat/.gitignore
@@ -1 +1,2 @@
*.log
+run-test.mk
diff --git a/tests/sat/dff.ys b/tests/sat/dff.ys
new file mode 100644
index 000000000..ba3625871
--- /dev/null
+++ b/tests/sat/dff.ys
@@ -0,0 +1,21 @@
+# Ensure all sync-only DFFs have usable SAT models.
+
+read_verilog -icells <<EOT
+
+module top(...);
+
+input C, D, R, E;
+output [4:0] Q;
+
+\$dff #(.WIDTH(1), .CLK_POLARITY(1'b1)) ff0 (.CLK(C), .D(D), .Q(Q[0]));
+\$dffe #(.WIDTH(1), .CLK_POLARITY(1'b1), .EN_POLARITY(1'b1)) ff1 (.CLK(C), .D(D), .EN(E), .Q(Q[1]));
+\$sdff #(.WIDTH(1), .CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(1'b0)) ff2 (.CLK(C), .D(D), .SRST(R), .Q(Q[2]));
+\$sdffe #(.WIDTH(1), .CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(1'b0), .EN_POLARITY(1'b1)) ff3 (.CLK(C), .D(D), .EN(E), .SRST(R), .Q(Q[3]));
+\$sdffce #(.WIDTH(1), .CLK_POLARITY(1'b1), .SRST_POLARITY(1'b1), .SRST_VALUE(1'b0), .EN_POLARITY(1'b1)) ff4 (.CLK(C), .D(D), .EN(E), .SRST(R), .Q(Q[4]));
+
+endmodule
+
+EOT
+
+# This ensures that 1) coarse cells have SAT models, 2) fine cells have SAT models, 3) they're equivalent
+equiv_opt -assert simplemap
diff --git a/tests/sat/run-test.sh b/tests/sat/run-test.sh
index 67e1beb23..74589dfeb 100755
--- a/tests/sat/run-test.sh
+++ b/tests/sat/run-test.sh
@@ -1,6 +1,4 @@
-#!/bin/bash
-set -e
-for x in *.ys; do
- echo "Running $x.."
- ../../yosys -ql ${x%.ys}.log $x
-done
+#!/usr/bin/env bash
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts
diff --git a/tests/sat/sizebits.sv b/tests/sat/sizebits.sv
index d7ce2326e..87fa08f89 100644
--- a/tests/sat/sizebits.sv
+++ b/tests/sat/sizebits.sv
@@ -1,5 +1,6 @@
module functions01;
+wire t;
wire [5:2]x;
wire [3:0]y[2:7];
wire [3:0]z[7:2][2:9];
@@ -9,24 +10,84 @@ wire [3:0]z[7:2][2:9];
//wire [$size(y)-1:0]y_size;
//wire [$size(z)-1:0]z_size;
+assert property ($size(t) == 1);
assert property ($size(x) == 4);
assert property ($size({3{x}}) == 3*4);
assert property ($size(y) == 6);
assert property ($size(y, 1) == 6);
assert property ($size(y, (1+1)) == 4);
+// This is unsupported at the moment
+//assert property ($size(y[2], 1) == 4);
+//assert property ($size(y[2][1], 1) == 1);
assert property ($size(z) == 6);
assert property ($size(z, 1) == 6);
assert property ($size(z, 2) == 8);
assert property ($size(z, 3) == 4);
+// This is unsupported at the moment
+assert property ($size(z[3], 1) == 8);
+assert property ($size(z[3][3], 1) == 4);
+//assert property ($size(z[3][3][3], 1) == 1);
// This should trigger an error if enabled (it does).
//assert property ($size(z, 4) == 4);
//wire [$bits(x)-1:0]x_bits;
//wire [$bits({x, x})-1:0]xx_bits;
+assert property ($bits(t) == 1);
assert property ($bits(x) == 4);
assert property ($bits(y) == 4*6);
assert property ($bits(z) == 4*6*8);
+assert property ($high(x) == 5);
+assert property ($high(y) == 7);
+assert property ($high(y, 1) == 7);
+assert property ($high(y, (1+1)) == 3);
+
+assert property ($high(z) == 7);
+assert property ($high(z, 1) == 7);
+assert property ($high(z, 2) == 9);
+assert property ($high(z, 3) == 3);
+assert property ($high(z[3]) == 9);
+assert property ($high(z[3][3]) == 3);
+assert property ($high(z[3], 2) == 3);
+
+assert property ($low(x) == 2);
+assert property ($low(y) == 2);
+assert property ($low(y, 1) == 2);
+assert property ($low(y, (1+1)) == 0);
+
+assert property ($low(z) == 2);
+assert property ($low(z, 1) == 2);
+assert property ($low(z, 2) == 2);
+assert property ($low(z, 3) == 0);
+assert property ($low(z[3]) == 2);
+assert property ($low(z[3][3]) == 0);
+assert property ($low(z[3], 2) == 0);
+
+assert property ($left(x) == 5);
+assert property ($left(y) == 2);
+assert property ($left(y, 1) == 2);
+assert property ($left(y, (1+1)) == 3);
+
+assert property ($left(z) == 7);
+assert property ($left(z, 1) == 7);
+assert property ($left(z, 2) == 2);
+assert property ($left(z, 3) == 3);
+assert property ($left(z[3]) == 2);
+assert property ($left(z[3][3]) == 3);
+assert property ($left(z[3], 2) == 3);
+
+assert property ($right(x) == 2);
+assert property ($right(y) == 7);
+assert property ($right(y, 1) == 7);
+assert property ($right(y, (1+1)) == 0);
+
+assert property ($right(z) == 2);
+assert property ($right(z, 1) == 2);
+assert property ($right(z, 2) == 9);
+assert property ($right(z, 3) == 0);
+assert property ($right(z[3]) == 9);
+assert property ($right(z[3][3]) == 0);
+assert property ($right(z[3], 2) == 0);
endmodule
diff --git a/tests/simple/const_branch_finish.v b/tests/simple/const_branch_finish.v
new file mode 100644
index 000000000..8166688e6
--- /dev/null
+++ b/tests/simple/const_branch_finish.v
@@ -0,0 +1,39 @@
+`define CONSTANT_CHECK \
+ if (WIDTH === 'bx) begin \
+ $display("FAIL"); \
+ $finish; \
+ end
+
+module top;
+ parameter WIDTH = 32;
+ integer j;
+ initial begin
+ `CONSTANT_CHECK
+ if (WIDTH == 32) begin : procedural_conditional_block
+ `CONSTANT_CHECK
+ end
+ case (WIDTH)
+ 32: `CONSTANT_CHECK
+ default: ;
+ endcase
+ for (j = 0; j < 2; j = j + 1) begin : procedural_loop_block
+ `CONSTANT_CHECK
+ end
+ end
+ generate
+ begin : unconditional_block
+ initial `CONSTANT_CHECK
+ end
+ if (WIDTH == 32) begin : conditional_block
+ initial `CONSTANT_CHECK
+ end
+ case (WIDTH)
+ 32: initial `CONSTANT_CHECK
+ default: ;
+ endcase
+ genvar i;
+ for (i = 0; i < 2; i = i + 1) begin : loop_block
+ initial `CONSTANT_CHECK
+ end
+ endgenerate
+endmodule
diff --git a/tests/simple/generate.v b/tests/simple/generate.v
index 0e353ad9b..12327b36e 100644
--- a/tests/simple/generate.v
+++ b/tests/simple/generate.v
@@ -159,3 +159,104 @@ generate
end
endgenerate
endmodule
+
+// ------------------------------------------
+
+module gen_test7;
+ reg [2:0] out1;
+ reg [2:0] out2;
+ wire [2:0] out3;
+ generate
+ begin : cond
+ reg [2:0] sub_out1;
+ reg [2:0] sub_out2;
+ wire [2:0] sub_out3;
+ initial begin : init
+ reg signed [31:0] x;
+ x = 2 ** 2;
+ out1 = x;
+ sub_out1 = x;
+ end
+ always @* begin : proc
+ reg signed [31:0] x;
+ x = 2 ** 1;
+ out2 = x;
+ sub_out2 = x;
+ end
+ genvar x;
+ for (x = 0; x < 3; x = x + 1) begin
+ assign out3[x] = 1;
+ assign sub_out3[x] = 1;
+ end
+ end
+ endgenerate
+
+// `define VERIFY
+`ifdef VERIFY
+ assert property (out1 == 4);
+ assert property (out2 == 2);
+ assert property (out3 == 7);
+ assert property (cond.sub_out1 == 4);
+ assert property (cond.sub_out2 == 2);
+ assert property (cond.sub_out3 == 7);
+`endif
+endmodule
+
+// ------------------------------------------
+
+module gen_test8;
+
+// `define VERIFY
+`ifdef VERIFY
+ `define ASSERT(expr) assert property (expr);
+`else
+ `define ASSERT(expr)
+`endif
+
+ wire [1:0] x = 2'b11;
+ generate
+ begin : A
+ wire [1:0] x;
+ begin : B
+ wire [1:0] x = 2'b00;
+ `ASSERT(x == 0)
+ `ASSERT(A.x == 2)
+ `ASSERT(A.C.x == 1)
+ `ASSERT(A.B.x == 0)
+ `ASSERT(gen_test8.x == 3)
+ `ASSERT(gen_test8.A.x == 2)
+ `ASSERT(gen_test8.A.C.x == 1)
+ `ASSERT(gen_test8.A.B.x == 0)
+ end
+ begin : C
+ wire [1:0] x = 2'b01;
+ `ASSERT(x == 1)
+ `ASSERT(A.x == 2)
+ `ASSERT(A.C.x == 1)
+ `ASSERT(A.B.x == 0)
+ `ASSERT(gen_test8.x == 3)
+ `ASSERT(gen_test8.A.x == 2)
+ `ASSERT(gen_test8.A.C.x == 1)
+ `ASSERT(gen_test8.A.B.x == 0)
+ end
+ assign x = B.x ^ 2'b11 ^ C.x;
+ `ASSERT(x == 2)
+ `ASSERT(A.x == 2)
+ `ASSERT(A.C.x == 1)
+ `ASSERT(A.B.x == 0)
+ `ASSERT(gen_test8.x == 3)
+ `ASSERT(gen_test8.A.x == 2)
+ `ASSERT(gen_test8.A.C.x == 1)
+ `ASSERT(gen_test8.A.B.x == 0)
+ end
+ endgenerate
+
+ `ASSERT(x == 3)
+ `ASSERT(A.x == 2)
+ `ASSERT(A.C.x == 1)
+ `ASSERT(A.B.x == 0)
+ `ASSERT(gen_test8.x == 3)
+ `ASSERT(gen_test8.A.x == 2)
+ `ASSERT(gen_test8.A.C.x == 1)
+ `ASSERT(gen_test8.A.B.x == 0)
+endmodule
diff --git a/tests/simple/run-test.sh b/tests/simple/run-test.sh
index f20fd0d30..47bcfd6da 100755
--- a/tests/simple/run-test.sh
+++ b/tests/simple/run-test.sh
@@ -17,5 +17,4 @@ if ! command -v iverilog > /dev/null ; then
exit 1
fi
-shopt -s nullglob
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.{sv,v}
diff --git a/tests/simple/string_format.v b/tests/simple/string_format.v
new file mode 100644
index 000000000..ce45ca1e9
--- /dev/null
+++ b/tests/simple/string_format.v
@@ -0,0 +1,7 @@
+module top;
+ parameter STR = "something interesting";
+ initial begin
+ $display("A: %s", STR);
+ $display("B: %0s", STR);
+ end
+endmodule
diff --git a/tests/svtypes/multirange_array.sv b/tests/svtypes/multirange_array.sv
new file mode 100644
index 000000000..be0d3dfc2
--- /dev/null
+++ b/tests/svtypes/multirange_array.sv
@@ -0,0 +1,16 @@
+// test for multirange arrays
+
+`define STRINGIFY(x) `"x`"
+`define STATIC_ASSERT(x) if(!(x)) $error({"assert failed: ", `STRINGIFY(x)})
+
+module top;
+
+ logic a [3];
+ logic b [3][5];
+ logic c [3][5][7];
+
+ `STATIC_ASSERT($bits(a) == 3);
+ `STATIC_ASSERT($bits(b) == 15);
+ `STATIC_ASSERT($bits(c) == 105);
+
+endmodule
diff --git a/tests/svtypes/multirange_subarray_access.ys b/tests/svtypes/multirange_subarray_access.ys
new file mode 100644
index 000000000..de57d1423
--- /dev/null
+++ b/tests/svtypes/multirange_subarray_access.ys
@@ -0,0 +1,12 @@
+logger -expect error "Insufficient number of array indices for a." 1
+read_verilog -sv <<EOT
+module foo;
+logic a [6:0][4:0][1:0];
+logic b [1:0];
+
+assign a[0][0][0] = 1'b0;
+assign a[0][0][1] = 1'b1;
+assign b = a[0][0];
+
+endmodule
+EOT
diff --git a/tests/svtypes/run-test.sh b/tests/svtypes/run-test.sh
index 09a30eed1..91ceae227 100755
--- a/tests/svtypes/run-test.sh
+++ b/tests/svtypes/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../yosys -ql ${x%.ys}.log $x"
-done
-for x in *.sv; do
- if [ ! -f "${x%.sv}.ys" ]; then
- echo "all:: check-$x"
- echo "check-$x:"
- echo " @echo 'Checking $x..'"
- echo " @../../yosys -ql ${x%.sv}.log -p \"prep -top top; sat -verify -prove-asserts\" $x"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts --prove-sv
diff --git a/tests/svtypes/static_cast_negative.ys b/tests/svtypes/static_cast_negative.ys
new file mode 100644
index 000000000..4f9e8cf6e
--- /dev/null
+++ b/tests/svtypes/static_cast_negative.ys
@@ -0,0 +1,4 @@
+logger -expect error "Static cast with zero or negative size" 1
+read_verilog -sv <<EOT
+module top; wire [7:0] a = (-1)'(a); endmodule
+EOT
diff --git a/tests/svtypes/static_cast_nonconst.ys b/tests/svtypes/static_cast_nonconst.ys
new file mode 100644
index 000000000..72d8f9910
--- /dev/null
+++ b/tests/svtypes/static_cast_nonconst.ys
@@ -0,0 +1,4 @@
+logger -expect error "Static cast with non constant expression" 1
+read_verilog -sv <<EOT
+module top; wire [7:0] a, b = (a)'(0); endmodule
+EOT
diff --git a/tests/svtypes/static_cast_simple.sv b/tests/svtypes/static_cast_simple.sv
new file mode 100644
index 000000000..2e4ad7d2b
--- /dev/null
+++ b/tests/svtypes/static_cast_simple.sv
@@ -0,0 +1,64 @@
+module top;
+ wire [7:0] a, b, c, d;
+ assign a = 8'd16;
+ assign b = 8'd16;
+ assign c = (a * b) >> 8;
+ assign d = (16'(a) * b) >> 8;
+
+ parameter P = 16;
+
+ wire signed [7:0] s0, s1, s2;
+ wire [7:0] u0, u1, u2, u3, u4, u5, u6;
+ assign s0 = -8'd1;
+ assign s1 = 4'(s0);
+ assign s2 = 4'(unsigned'(s0));
+ assign u0 = -8'd1;
+ assign u1 = 4'(u0);
+ assign u2 = 4'(signed'(u0));
+ assign u3 = 8'(4'(s0));
+ assign u4 = 8'(4'(u0));
+ assign u5 = 8'(4'(signed'(-8'd1)));
+ assign u6 = 8'(4'(unsigned'(-8'd1)));
+
+ wire [8:0] n0, n1, n2, n3, n4, n5, n6, n7, n8, n9;
+ assign n0 = s1;
+ assign n1 = s2;
+ assign n2 = 9'(s1);
+ assign n3 = 9'(s2);
+ assign n4 = 9'(unsigned'(s1));
+ assign n5 = 9'(unsigned'(s2));
+ assign n6 = 9'(u0);
+ assign n7 = 9'(u1);
+ assign n8 = 9'(signed'(u0));
+ assign n9 = 9'(signed'(u1));
+
+ always_comb begin
+ assert(c == 8'b0000_0000);
+ assert(d == 8'b0000_0001);
+
+ assert((P + 1)'(a) == 17'b0_0000_0000_0001_0000);
+ assert((P + 1)'(d - 2) == 17'b1_1111_1111_1111_1111);
+
+ assert(s0 == 8'b1111_1111);
+ assert(s1 == 8'b1111_1111);
+ assert(s2 == 8'b0000_1111);
+ assert(u0 == 8'b1111_1111);
+ assert(u1 == 8'b0000_1111);
+ assert(u2 == 8'b1111_1111);
+ assert(u3 == 8'b1111_1111);
+ assert(u4 == 8'b0000_1111);
+ assert(u5 == 8'b1111_1111);
+ assert(u6 == 8'b0000_1111);
+
+ assert(n0 == 9'b1_1111_1111);
+ assert(n1 == 9'b0_0000_1111);
+ assert(n2 == 9'b1_1111_1111);
+ assert(n3 == 9'b0_0000_1111);
+ assert(n4 == 9'b0_1111_1111);
+ assert(n5 == 9'b0_0000_1111);
+ assert(n6 == 9'b0_1111_1111);
+ assert(n7 == 9'b0_0000_1111);
+ assert(n8 == 9'b1_1111_1111);
+ assert(n9 == 9'b0_0000_1111);
+ end
+endmodule
diff --git a/tests/svtypes/static_cast_verilog.ys b/tests/svtypes/static_cast_verilog.ys
new file mode 100644
index 000000000..fa3680b68
--- /dev/null
+++ b/tests/svtypes/static_cast_verilog.ys
@@ -0,0 +1,4 @@
+logger -expect error "Static cast is only supported in SystemVerilog mode" 1
+read_verilog <<EOT
+module top; wire [7:0] a = 1'(a); endmodule
+EOT
diff --git a/tests/svtypes/static_cast_zero.ys b/tests/svtypes/static_cast_zero.ys
new file mode 100644
index 000000000..d8335ca1b
--- /dev/null
+++ b/tests/svtypes/static_cast_zero.ys
@@ -0,0 +1,4 @@
+logger -expect error "Static cast with zero or negative size" 1
+read_verilog -sv <<EOT
+module top; wire [7:0] a = 0'(a); endmodule
+EOT
diff --git a/tests/svtypes/struct_array.sv b/tests/svtypes/struct_array.sv
index 022ad56c6..873f7befd 100644
--- a/tests/svtypes/struct_array.sv
+++ b/tests/svtypes/struct_array.sv
@@ -1,7 +1,7 @@
// test for array indexing in structures
module top;
-
+
struct packed {
bit [5:0] [7:0] a; // 6 element packed array of bytes
bit [15:0] b; // filler for non-zero offset
@@ -19,4 +19,24 @@ module top;
always_comb assert(s==64'h4200_0012_3400_FFFC);
+ struct packed {
+ bit [7:0] [7:0] a; // 8 element packed array of bytes
+ bit [15:0] b; // filler for non-zero offset
+ } s2;
+
+ initial begin
+ s2 = '0;
+
+ s2.a[2:1] = 16'h1234;
+ s2.a[5] = 8'h42;
+
+ s2.a[7] = '1;
+ s2.a[7][1:0] = '0;
+
+ s2.b = '1;
+ s2.b[1:0] = '0;
+ end
+
+ always_comb assert(s2==80'hFC00_4200_0012_3400_FFFC);
+
endmodule
diff --git a/tests/techmap/bug2183.ys b/tests/techmap/bug2183.ys
new file mode 100644
index 000000000..8dd09458e
--- /dev/null
+++ b/tests/techmap/bug2183.ys
@@ -0,0 +1,11 @@
+read_verilog <<EOT
+module foo(inout a, b);
+ assign a = b;
+endmodule
+module bar(output c);
+ foo f(c, 1'b0);
+endmodule
+EOT
+
+hierarchy -auto-top
+flatten
diff --git a/tests/techmap/bug2321.ys b/tests/techmap/bug2321.ys
new file mode 100644
index 000000000..637528b21
--- /dev/null
+++ b/tests/techmap/bug2321.ys
@@ -0,0 +1,15 @@
+read_verilog <<EOT
+module m (input i, output o);
+wire [1023:0] _TECHMAP_DO_00_ = "CONSTMAP; ";
+endmodule
+EOT
+
+design -stash map
+
+read_verilog <<EOT
+module top(output o);
+m m (.o(o), .i(o));
+endmodule
+EOT
+
+techmap -map %map
diff --git a/tests/techmap/bug2332.ys b/tests/techmap/bug2332.ys
new file mode 100644
index 000000000..ed6b35eb2
--- /dev/null
+++ b/tests/techmap/bug2332.ys
@@ -0,0 +1,11 @@
+read_verilog <<EOT
+module top(input [31:0] a, input signed [2:0] x, output [2:0] o);
+
+wire [5:0] t = x * 3;
+assign o = a >> t;
+
+endmodule
+EOT
+
+wreduce
+equiv_opt -assert peepopt
diff --git a/tests/techmap/cellname.ys b/tests/techmap/cellname.ys
new file mode 100644
index 000000000..2edd6a9fd
--- /dev/null
+++ b/tests/techmap/cellname.ys
@@ -0,0 +1,41 @@
+read_verilog << EOT
+
+module sub (input i, output o);
+parameter _TECHMAP_CELLNAME_ = "";
+namedsub #(.name(_TECHMAP_CELLNAME_)) _TECHMAP_REPLACE_ (i, o);
+endmodule
+
+EOT
+
+design -stash map
+
+read_verilog << EOT
+
+(* blackbox *)
+module sub (input i, output o);
+endmodule
+
+(* blackbox *)
+module namedsub (input i, output o);
+parameter name = "";
+endmodule
+
+module top(input [3:0] i, output [3:0] o);
+
+sub s1 (i[0], o[0]);
+sub subsubsub (i[1], o[1]);
+sub s2 (i[2], o[2]);
+sub xxx (i[3], o[3]);
+
+endmodule
+
+EOT
+
+techmap -map %map
+
+select -assert-count 4 t:namedsub
+select -assert-count 0 t:sub
+select -assert-count 1 t:namedsub r:name=s1 %i
+select -assert-count 1 t:namedsub r:name=subsubsub %i
+select -assert-count 1 t:namedsub r:name=s2 %i
+select -assert-count 1 t:namedsub r:name=xxx %i
diff --git a/tests/techmap/clkbufmap.ys b/tests/techmap/clkbufmap.ys
index b81a35e74..abe830109 100644
--- a/tests/techmap/clkbufmap.ys
+++ b/tests/techmap/clkbufmap.ys
@@ -1,5 +1,7 @@
read_verilog <<EOT
module clkbuf (input i, (* clkbuf_driver *) output o); endmodule
+module inbuf (input i, output o); endmodule
+module clkinbuf (input i, (* clkbuf_driver *) output o); endmodule
module dff ((* clkbuf_sink *) input clk, input d, output q); endmodule
module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule
module latch (input e, d, output q); endmodule
@@ -105,3 +107,80 @@ select -assert-count 0 w:clk1 %a %co t:clkbuf %i
select -assert-count 0 w:clk2 %a %co t:clkbuf %i
select -assert-count 0 top/t:clkbuf
select -assert-count 2 sub/t:clkbuf
+
+# ----------------------
+
+design -load ref
+clkbufmap -buf clkbuf o:i -inpad inbuf o:i
+select -assert-count 3 top/t:clkbuf
+select -assert-count 3 sub/t:clkbuf
+select -assert-count 2 top/t:inbuf
+select -assert-count 0 sub/t:inbuf
+select -set clk1 w:clk1 %a %co t:inbuf %i
+select -assert-count 1 @clk1
+select -assert-count 1 @clk1 %x:+[o] %co t:clkbuf %i
+select -set clk1b @clk1 %x:+[o] %co t:clkbuf %i
+select -assert-count 1 @clk1b %x:+[o] %co c:s* %i
+select -assert-count 1 @clk1b %x:+[o] %co c:s0 %i
+select -set clk2 w:clk2 %a %co t:inbuf %i
+select -assert-count 1 @clk2
+select -assert-count 1 @clk2 %x:+[o] %co t:clkbuf %i
+select -set clk2b @clk2 %x:+[o] %co t:clkbuf %i
+select -assert-count 1 @clk2b %x:+[o] %co c:s* %i
+select -assert-count 1 @clk2b %x:+[o] %co c:s1 %i
+select -set clk5 w:clk5 %a %ci t:clkbuf %i
+select -assert-count 1 @clk5
+select -assert-count 1 @clk5 %x:+[o] %co c:s5 %i
+select -assert-count 1 @clk5 %x:+[i] %ci c:s3 %i
+select -set sclk4 w:sclk4 %a %ci t:clkbuf %i
+select -assert-count 1 @sclk4
+select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i
+select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i
+select -set sclk8 w:sclk8 %a %ci t:clkbuf %i
+select -assert-count 1 @sclk8
+select -assert-count 1 @sclk8 %x:+[o] %co c:s13 %i
+select -assert-count 1 @sclk8 %x:+[i] %ci c:s12 %i
+
+# ----------------------
+
+design -load ref
+clkbufmap -inpad inbuf o:i
+select -assert-count 2 top/t:inbuf
+select -assert-count 0 sub/t:inbuf
+select -set clk1 w:clk1 %a %co t:inbuf %i
+select -assert-count 1 @clk1
+select -assert-count 1 @clk1 %x:+[o] %co c:s* %i
+select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i
+select -set clk2 w:clk2 %a %co t:inbuf %i
+select -assert-count 1 @clk2
+select -assert-count 1 @clk2 %x:+[o] %co c:s* %i
+select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i
+
+# ----------------------
+
+design -load ref
+clkbufmap -buf clkbuf o:i -inpad clkinbuf o:i
+select -assert-count 1 top/t:clkbuf
+select -assert-count 3 sub/t:clkbuf
+select -assert-count 2 top/t:clkinbuf
+select -assert-count 0 sub/t:clkinbuf
+select -set clk1 w:clk1 %a %co t:clkinbuf %i
+select -assert-count 1 @clk1
+select -assert-count 1 @clk1 %x:+[o] %co c:s* %i
+select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i
+select -set clk2 w:clk2 %a %co t:clkinbuf %i
+select -assert-count 1 @clk2
+select -assert-count 1 @clk2 %x:+[o] %co c:s* %i
+select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i
+select -set clk5 w:clk5 %a %ci t:clkbuf %i
+select -assert-count 1 @clk5
+select -assert-count 1 @clk5 %x:+[o] %co c:s5 %i
+select -assert-count 1 @clk5 %x:+[i] %ci c:s3 %i
+select -set sclk4 w:sclk4 %a %ci t:clkbuf %i
+select -assert-count 1 @sclk4
+select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i
+select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i
+select -set sclk8 w:sclk8 %a %ci t:clkbuf %i
+select -assert-count 1 @sclk8
+select -assert-count 1 @sclk8 %x:+[o] %co c:s13 %i
+select -assert-count 1 @sclk8 %x:+[i] %ci c:s12 %i
diff --git a/tests/techmap/dff2dffs.ys b/tests/techmap/dff2dffs.ys
deleted file mode 100644
index 13f1a3cf3..000000000
--- a/tests/techmap/dff2dffs.ys
+++ /dev/null
@@ -1,50 +0,0 @@
-read_verilog << EOT
-module top(...);
-input clk;
-input d;
-input sr;
-output reg q0, q1, q2, q3, q4, q5;
-
-initial q0 = 1'b0;
-initial q1 = 1'b0;
-initial q2 = 1'b1;
-initial q3 = 1'b1;
-initial q4 = 1'bx;
-initial q5 = 1'bx;
-
-always @(posedge clk) begin
- q0 <= sr ? 1'b0 : d;
- q1 <= sr ? 1'b1 : d;
- q2 <= sr ? 1'b0 : d;
- q3 <= sr ? 1'b1 : d;
- q4 <= sr ? 1'b0 : d;
- q5 <= sr ? 1'b1 : d;
-end
-
-endmodule
-EOT
-
-proc
-simplemap
-design -save ref
-
-dff2dffs
-clean
-
-select -assert-count 1 w:q0 %x t:$__DFFS_PP0_ %i
-select -assert-count 1 w:q1 %x t:$__DFFS_PP1_ %i
-select -assert-count 1 w:q2 %x t:$__DFFS_PP0_ %i
-select -assert-count 1 w:q3 %x t:$__DFFS_PP1_ %i
-select -assert-count 1 w:q4 %x t:$__DFFS_PP0_ %i
-select -assert-count 1 w:q5 %x t:$__DFFS_PP1_ %i
-
-design -load ref
-dff2dffs -match-init
-clean
-
-select -assert-count 1 w:q0 %x t:$__DFFS_PP0_ %i
-select -assert-count 0 w:q1 %x t:$__DFFS_PP1_ %i
-select -assert-count 0 w:q2 %x t:$__DFFS_PP0_ %i
-select -assert-count 1 w:q3 %x t:$__DFFS_PP1_ %i
-select -assert-count 1 w:q4 %x t:$__DFFS_PP0_ %i
-select -assert-count 1 w:q5 %x t:$__DFFS_PP1_ %i
diff --git a/tests/techmap/dfflegalize_adff.ys b/tests/techmap/dfflegalize_adff.ys
new file mode 100644
index 000000000..135ae0ab7
--- /dev/null
+++ b/tests/techmap/dfflegalize_adff.ys
@@ -0,0 +1,103 @@
+read_verilog -icells <<EOT
+
+module adff0(input C, R, D, output [2:0] Q);
+$_DFF_PP0_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_DFF_PN0_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_DFF_NP0_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adff1(input C, R, D, output [2:0] Q);
+$_DFF_PP1_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_DFF_PN1_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_DFF_NP1_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adffe0(input C, E, R, D, output [3:0] Q);
+$_DFFE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_DFFE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module adffe1(input C, E, R, D, output [3:0] Q);
+$_DFFE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_DFFE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module top(input C, E, R, D, output [13:0] Q);
+adff0 adff0_(.C(C), .R(R), .D(D), .Q(Q[2:0]));
+adff1 adff1_(.C(C), .R(R), .D(D), .Q(Q[5:3]));
+adffe0 adffe0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[9:6]));
+adffe1 adffe1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[13:10]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ x
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ x
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 2 adffe0/t:$_NOT_
+select -assert-count 10 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 14 t:$_DFF_PP0_
+select -assert-none t:$_DFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ x
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 3 adffe0/t:$_NOT_
+select -assert-count 11 adffe1/t:$_NOT_
+select -assert-count 14 t:$_DFFE_PP0P_
+select -assert-none t:$_DFFE_PP0P_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ x
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 2 adffe0/t:$_NOT_
+select -assert-count 2 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 14 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ x
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 3 adffe0/t:$_NOT_
+select -assert-count 3 adffe1/t:$_NOT_
+select -assert-count 14 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_adff_init.ys b/tests/techmap/dfflegalize_adff_init.ys
new file mode 100644
index 000000000..7764e15a5
--- /dev/null
+++ b/tests/techmap/dfflegalize_adff_init.ys
@@ -0,0 +1,279 @@
+read_verilog -icells <<EOT
+
+module adff0(input C, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_DFF_PP0_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_DFF_PN0_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_DFF_NP0_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adff1(input C, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_DFF_PP1_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_DFF_PN1_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_DFF_NP1_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adffe0(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_DFFE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_DFFE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module adffe1(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_DFFE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_DFFE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module top(input C, E, R, D, output [13:0] Q);
+adff0 adff0_(.C(C), .R(R), .D(D), .Q(Q[2:0]));
+adff1 adff1_(.C(C), .R(R), .D(D), .Q(Q[5:3]));
+adffe0 adffe0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[9:6]));
+adffe1 adffe1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[13:10]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 0 -cell $_DLATCH_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 1 -cell $_DLATCH_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 0 -cell $_DLATCH_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 1 -cell $_DLATCH_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_DLATCH_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 0 -cell $_DLATCH_P_ 0
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 10 adff1/t:$_NOT_
+select -assert-count 2 adffe0/t:$_NOT_
+select -assert-count 12 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 3 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 8 adffe1/t:$_MUX_
+select -assert-count 3 adff0/t:$_DFF_PP0_
+select -assert-count 6 adff1/t:$_DFF_PP0_
+select -assert-count 4 adffe0/t:$_DFF_PP0_
+select -assert-count 8 adffe1/t:$_DFF_PP0_
+select -assert-count 0 adff0/t:$_DLATCH_P_
+select -assert-count 3 adff1/t:$_DLATCH_P_
+select -assert-count 0 adffe0/t:$_DLATCH_P_
+select -assert-count 4 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFF_PP0_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 1 -cell $_DLATCH_P_ 0
+
+select -assert-count 10 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 12 adffe0/t:$_NOT_
+select -assert-count 10 adffe1/t:$_NOT_
+select -assert-count 3 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 8 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 6 adff0/t:$_DFF_PP0_
+select -assert-count 3 adff1/t:$_DFF_PP0_
+select -assert-count 8 adffe0/t:$_DFF_PP0_
+select -assert-count 4 adffe1/t:$_DFF_PP0_
+select -assert-count 3 adff0/t:$_DLATCH_P_
+select -assert-count 0 adff1/t:$_DLATCH_P_
+select -assert-count 4 adffe0/t:$_DLATCH_P_
+select -assert-count 0 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFF_PP0_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 0 -cell $_DLATCH_P_ 0
+
+select -assert-count 10 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 12 adffe0/t:$_NOT_
+select -assert-count 2 adffe1/t:$_NOT_
+select -assert-count 3 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 8 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 6 adff0/t:$_DFF_PP1_
+select -assert-count 3 adff1/t:$_DFF_PP1_
+select -assert-count 8 adffe0/t:$_DFF_PP1_
+select -assert-count 4 adffe1/t:$_DFF_PP1_
+select -assert-count 3 adff0/t:$_DLATCH_P_
+select -assert-count 0 adff1/t:$_DLATCH_P_
+select -assert-count 4 adffe0/t:$_DLATCH_P_
+select -assert-count 0 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFF_PP1_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 1 -cell $_DLATCH_P_ 0
+
+select -assert-count 8 adff0/t:$_NOT_
+select -assert-count 10 adff1/t:$_NOT_
+select -assert-count 10 adffe0/t:$_NOT_
+select -assert-count 12 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 3 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 8 adffe1/t:$_MUX_
+select -assert-count 3 adff0/t:$_DFF_PP1_
+select -assert-count 6 adff1/t:$_DFF_PP1_
+select -assert-count 4 adffe0/t:$_DFF_PP1_
+select -assert-count 8 adffe1/t:$_DFF_PP1_
+select -assert-count 0 adff0/t:$_DLATCH_P_
+select -assert-count 3 adff1/t:$_DLATCH_P_
+select -assert-count 0 adffe0/t:$_DLATCH_P_
+select -assert-count 4 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFF_PP1_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_DLATCH_P_ 1
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 3 adffe0/t:$_NOT_
+select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 3 adff1/t:$_MUX_
+select -assert-count 0 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 3 adff0/t:$_DFFE_PP0P_
+select -assert-count 6 adff1/t:$_DFFE_PP0P_
+select -assert-count 4 adffe0/t:$_DFFE_PP0P_
+select -assert-count 8 adffe1/t:$_DFFE_PP0P_
+select -assert-count 0 adff0/t:$_DLATCH_P_
+select -assert-count 3 adff1/t:$_DLATCH_P_
+select -assert-count 0 adffe0/t:$_DLATCH_P_
+select -assert-count 4 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1
+
+select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 11 adffe1/t:$_NOT_
+select -assert-count 3 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 0 adffe1/t:$_MUX_
+select -assert-count 6 adff0/t:$_DFFE_PP0P_
+select -assert-count 3 adff1/t:$_DFFE_PP0P_
+select -assert-count 8 adffe0/t:$_DFFE_PP0P_
+select -assert-count 4 adffe1/t:$_DFFE_PP0P_
+select -assert-count 3 adff0/t:$_DLATCH_P_
+select -assert-count 0 adff1/t:$_DLATCH_P_
+select -assert-count 4 adffe0/t:$_DLATCH_P_
+select -assert-count 0 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFFE_PP0P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1
+
+select -assert-count 16 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 22 adffe0/t:$_NOT_
+select -assert-count 3 adffe1/t:$_NOT_
+select -assert-count 3 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 0 adffe1/t:$_MUX_
+select -assert-count 6 adff0/t:$_DFFE_PP1P_
+select -assert-count 3 adff1/t:$_DFFE_PP1P_
+select -assert-count 8 adffe0/t:$_DFFE_PP1P_
+select -assert-count 4 adffe1/t:$_DFFE_PP1P_
+select -assert-count 3 adff0/t:$_DLATCH_P_
+select -assert-count 0 adff1/t:$_DLATCH_P_
+select -assert-count 4 adffe0/t:$_DLATCH_P_
+select -assert-count 0 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFFE_PP1P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1
+
+select -assert-count 8 adff0/t:$_NOT_
+select -assert-count 16 adff1/t:$_NOT_
+select -assert-count 11 adffe0/t:$_NOT_
+select -assert-count 22 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 3 adff1/t:$_MUX_
+select -assert-count 0 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 3 adff0/t:$_DFFE_PP1P_
+select -assert-count 6 adff1/t:$_DFFE_PP1P_
+select -assert-count 4 adffe0/t:$_DFFE_PP1P_
+select -assert-count 8 adffe1/t:$_DFFE_PP1P_
+select -assert-count 0 adff0/t:$_DLATCH_P_
+select -assert-count 3 adff1/t:$_DLATCH_P_
+select -assert-count 0 adffe0/t:$_DLATCH_P_
+select -assert-count 4 adffe1/t:$_DLATCH_P_
+select -assert-none t:$_DFFE_PP1P_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 0
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 2 adffe0/t:$_NOT_
+select -assert-count 2 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 14 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 1
+
+select -assert-count 8 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 10 adffe0/t:$_NOT_
+select -assert-count 10 adffe1/t:$_NOT_
+select -assert-count 0 adff0/t:$_MUX_
+select -assert-count 0 adff1/t:$_MUX_
+select -assert-count 4 adffe0/t:$_MUX_
+select -assert-count 4 adffe1/t:$_MUX_
+select -assert-count 14 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 0
+
+select -assert-count 2 adff0/t:$_NOT_
+select -assert-count 2 adff1/t:$_NOT_
+select -assert-count 3 adffe0/t:$_NOT_
+select -assert-count 3 adffe1/t:$_NOT_
+select -assert-count 14 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+select -assert-count 8 adff0/t:$_NOT_
+select -assert-count 8 adff1/t:$_NOT_
+select -assert-count 11 adffe0/t:$_NOT_
+select -assert-count 11 adffe1/t:$_NOT_
+select -assert-count 14 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_adlatch.ys b/tests/techmap/dfflegalize_adlatch.ys
new file mode 100644
index 000000000..b242cc809
--- /dev/null
+++ b/tests/techmap/dfflegalize_adlatch.ys
@@ -0,0 +1,51 @@
+read_verilog -icells <<EOT
+
+module adlatch0(input E, R, D, output [2:0] Q);
+$_DLATCH_PP0_ ff0 (.E(E), .R(R), .D(D), .Q(Q[0]));
+$_DLATCH_PN0_ ff1 (.E(E), .R(R), .D(D), .Q(Q[1]));
+$_DLATCH_NP0_ ff2 (.E(E), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adlatch1(input E, R, D, output [2:0] Q);
+$_DLATCH_PP1_ ff0 (.E(E), .R(R), .D(D), .Q(Q[0]));
+$_DLATCH_PN1_ ff1 (.E(E), .R(R), .D(D), .Q(Q[1]));
+$_DLATCH_NP1_ ff2 (.E(E), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module top(input C, E, R, D, output [13:0] Q);
+adlatch0 adlatch0_(.E(E), .R(R), .D(D), .Q(Q[2:0]));
+adlatch1 adlatch1_(.E(E), .R(R), .D(D), .Q(Q[5:3]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ x
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ x
+
+select -assert-count 2 adlatch0/t:$_NOT_
+select -assert-count 8 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 6 t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ x
+
+select -assert-count 2 adlatch0/t:$_NOT_
+select -assert-count 2 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 6 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_adlatch_init.ys b/tests/techmap/dfflegalize_adlatch_init.ys
new file mode 100644
index 000000000..7b22ea0c0
--- /dev/null
+++ b/tests/techmap/dfflegalize_adlatch_init.ys
@@ -0,0 +1,99 @@
+read_verilog -icells <<EOT
+
+module adlatch0(input E, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_DLATCH_PP0_ ff0 (.E(E), .R(R), .D(D), .Q(Q[0]));
+$_DLATCH_PN0_ ff1 (.E(E), .R(R), .D(D), .Q(Q[1]));
+$_DLATCH_NP0_ ff2 (.E(E), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module adlatch1(input E, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_DLATCH_PP1_ ff0 (.E(E), .R(R), .D(D), .Q(Q[0]));
+$_DLATCH_PN1_ ff1 (.E(E), .R(R), .D(D), .Q(Q[1]));
+$_DLATCH_NP1_ ff2 (.E(E), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module top(input C, E, R, D, output [13:0] Q);
+adlatch0 adlatch0_(.E(E), .R(R), .D(D), .Q(Q[2:0]));
+adlatch1 adlatch1_(.E(E), .R(R), .D(D), .Q(Q[5:3]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 0
+
+select -assert-count 2 adlatch0/t:$_NOT_
+select -assert-count 10 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 3 adlatch1/t:$_MUX_
+select -assert-count 3 adlatch0/t:$_DLATCH_PP0_
+select -assert-count 9 adlatch1/t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 1
+
+select -assert-count 16 adlatch0/t:$_NOT_
+select -assert-count 8 adlatch1/t:$_NOT_
+select -assert-count 3 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 9 adlatch0/t:$_DLATCH_PP0_
+select -assert-count 3 adlatch1/t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_DLATCH_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 0
+
+select -assert-count 10 adlatch0/t:$_NOT_
+select -assert-count 2 adlatch1/t:$_NOT_
+select -assert-count 3 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 9 adlatch0/t:$_DLATCH_PP1_
+select -assert-count 3 adlatch1/t:$_DLATCH_PP1_
+select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 1
+
+select -assert-count 8 adlatch0/t:$_NOT_
+select -assert-count 16 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 3 adlatch1/t:$_MUX_
+select -assert-count 3 adlatch0/t:$_DLATCH_PP1_
+select -assert-count 9 adlatch1/t:$_DLATCH_PP1_
+select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 0
+
+select -assert-count 2 adlatch0/t:$_NOT_
+select -assert-count 2 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 6 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+select -assert-count 8 adlatch0/t:$_NOT_
+select -assert-count 8 adlatch1/t:$_NOT_
+select -assert-count 0 adlatch0/t:$_MUX_
+select -assert-count 0 adlatch1/t:$_MUX_
+select -assert-count 6 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dff.ys b/tests/techmap/dfflegalize_dff.ys
new file mode 100644
index 000000000..63ab47865
--- /dev/null
+++ b/tests/techmap/dfflegalize_dff.ys
@@ -0,0 +1,306 @@
+read_verilog -icells <<EOT
+
+module dff(input C, D, output [1:0] Q);
+$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
+$_DFF_N_ ff1 (.C(C), .D(D), .Q(Q[1]));
+endmodule
+
+module dffe(input C, E, D, output [2:0] Q);
+$_DFFE_PP_ ff0 (.C(C), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PN_ ff1 (.C(C), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_NP_ ff2 (.C(C), .E(E), .D(D), .Q(Q[2]));
+endmodule
+
+module sdff0(input C, R, D, output [2:0] Q);
+$_SDFF_PP0_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_SDFF_PN0_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_SDFF_NP0_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module sdff1(input C, R, D, output [2:0] Q);
+$_SDFF_PP1_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_SDFF_PN1_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_SDFF_NP1_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module sdffe0(input C, E, R, D, output [3:0] Q);
+$_SDFFE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffe1(input C, E, R, D, output [3:0] Q);
+$_SDFFE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffce0(input C, E, R, D, output [3:0] Q);
+$_SDFFCE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFCE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFCE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFCE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffce1(input C, E, R, D, output [3:0] Q);
+$_SDFFCE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFCE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFCE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFCE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module top(input C, E, R, D, output [26:0] Q);
+dff dff_(.C(C), .D(D), .Q(Q[1:0]));
+dffe dffe_(.C(C), .E(E), .D(D), .Q(Q[4:2]));
+sdff0 sdff0_(.C(C), .R(R), .D(D), .Q(Q[7:5]));
+sdff1 sdff1_(.C(C), .R(R), .D(D), .Q(Q[10:8]));
+sdffe0 sdffe0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[14:11]));
+sdffe1 sdffe1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[18:15]));
+sdffce0 sdffce0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[22:19]));
+sdffce1 sdffce1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[26:23]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_P_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFE_PP0P_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFCE_PP0P_ x
+
+# Convert everything to DFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_P_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_P_
+select -assert-none t:$_DFF_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP_
+select -assert-none t:$_DFFE_PP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_PP0_
+select -assert-none t:$_DFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP0P_
+select -assert-none t:$_DFFE_PP0P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFs.
+
+design -load orig
+dfflegalize -cell $_SDFF_PP0_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 2 sdffe0/t:$_NOT_
+select -assert-count 10 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 4 sdffe0/t:$_MUX_
+select -assert-count 4 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* sdffce1/* %u %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFF_PP0_
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFEs.
+
+design -load orig
+dfflegalize -cell $_SDFFE_PP0P_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 3 sdffe0/t:$_NOT_
+select -assert-count 11 sdffe1/t:$_NOT_
+select -assert-count 3 sdffce0/t:$_NOT_
+select -assert-count 11 sdffce1/t:$_NOT_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* sdffce1/* %u %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFE_PP0P_
+select -assert-none t:$_SDFFE_PP0P_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFCEs.
+
+design -load orig
+dfflegalize -cell $_SDFFCE_PP0P_ x
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 3 sdffe0/t:$_NOT_
+select -assert-count 11 sdffe1/t:$_NOT_
+select -assert-count 3 sdffce0/t:$_NOT_
+select -assert-count 11 sdffce1/t:$_NOT_
+select -assert-count 0 t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffe0/* sdffe1/* %u %n %i
+select -assert-count 2 sdffe0/t:$_OR_
+select -assert-count 2 sdffe1/t:$_OR_
+select -assert-count 1 sdffe0/t:$_ORNOT_
+select -assert-count 1 sdffe1/t:$_ORNOT_
+select -assert-count 1 sdffe0/t:$_ANDNOT_
+select -assert-count 1 sdffe1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFCE_PP0P_
+select -assert-none t:$_SDFFCE_PP0P_ t:$_NOT_ t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dff_init.ys b/tests/techmap/dfflegalize_dff_init.ys
new file mode 100644
index 000000000..741ac39d0
--- /dev/null
+++ b/tests/techmap/dfflegalize_dff_init.ys
@@ -0,0 +1,786 @@
+read_verilog -icells <<EOT
+
+module dff(input C, D, (* init = 2'b00 *) output [1:0] Q);
+$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
+$_DFF_N_ ff1 (.C(C), .D(D), .Q(Q[1]));
+endmodule
+
+module dffe(input C, E, D, (* init = 3'b000 *) output [2:0] Q);
+$_DFFE_PP_ ff0 (.C(C), .E(E), .D(D), .Q(Q[0]));
+$_DFFE_PN_ ff1 (.C(C), .E(E), .D(D), .Q(Q[1]));
+$_DFFE_NP_ ff2 (.C(C), .E(E), .D(D), .Q(Q[2]));
+endmodule
+
+module sdff0(input C, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_SDFF_PP0_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_SDFF_PN0_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_SDFF_NP0_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module sdff1(input C, R, D, (* init = 3'b000 *) output [2:0] Q);
+$_SDFF_PP1_ ff0 (.C(C), .R(R), .D(D), .Q(Q[0]));
+$_SDFF_PN1_ ff1 (.C(C), .R(R), .D(D), .Q(Q[1]));
+$_SDFF_NP1_ ff2 (.C(C), .R(R), .D(D), .Q(Q[2]));
+endmodule
+
+module sdffe0(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_SDFFE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffe1(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_SDFFE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffce0(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_SDFFCE_PP0P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFCE_PP0N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFCE_PN0P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFCE_NP0P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module sdffce1(input C, E, R, D, (* init = 4'b0000 *) output [3:0] Q);
+$_SDFFCE_PP1P_ ff0 (.C(C), .R(R), .E(E), .D(D), .Q(Q[0]));
+$_SDFFCE_PP1N_ ff1 (.C(C), .R(R), .E(E), .D(D), .Q(Q[1]));
+$_SDFFCE_PN1P_ ff2 (.C(C), .R(R), .E(E), .D(D), .Q(Q[2]));
+$_SDFFCE_NP1P_ ff3 (.C(C), .R(R), .E(E), .D(D), .Q(Q[3]));
+endmodule
+
+module top(input C, E, R, D, output [26:0] Q);
+dff dff_(.C(C), .D(D), .Q(Q[1:0]));
+dffe dffe_(.C(C), .E(E), .D(D), .Q(Q[4:2]));
+sdff0 sdff0_(.C(C), .R(R), .D(D), .Q(Q[7:5]));
+sdff1 sdff1_(.C(C), .R(R), .D(D), .Q(Q[10:8]));
+sdffe0 sdffe0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[14:11]));
+sdffe1 sdffe1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[18:15]));
+sdffce0 sdffce0_(.C(C), .R(R), .E(E), .D(D), .Q(Q[22:19]));
+sdffce1 sdffce1_(.C(C), .R(R), .E(E), .D(D), .Q(Q[26:23]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP0_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP0_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP1_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP1_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFE_PP0P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFE_PP0P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFE_PP1P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFE_PP1P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFCE_PP0P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFCE_PP0P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFCE_PP1P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFFCE_PP1P_ 1
+
+# Convert everything to DFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_P_
+select -assert-none t:$_DFF_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_P_
+select -assert-none t:$_DFF_P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP_
+select -assert-none t:$_DFFE_PP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP_
+select -assert-none t:$_DFFE_PP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_PP0_
+select -assert-none t:$_DFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_PP0_
+select -assert-none t:$_DFF_PP0_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_PP1_
+select -assert-none t:$_DFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFF_PP1_
+select -assert-none t:$_DFF_PP1_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP0P_
+select -assert-none t:$_DFFE_PP0P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP0P_
+select -assert-none t:$_DFFE_PP0P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP1P_
+select -assert-none t:$_DFFE_PP1P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFE_PP1P_
+select -assert-none t:$_DFFE_PP1P_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 27 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFs.
+
+design -load orig
+dfflegalize -cell $_SDFF_PP0_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 2 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 1 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 4 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFF_PP0_
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFF_PP0_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 10 sdffe1/t:$_NOT_
+select -assert-count 9 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 4 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFF_PP0_
+select -assert-none t:$_SDFF_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFF_PP1_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 1 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 2 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 2 sdffe1/t:$_NOT_
+select -assert-count 1 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 4 sdffe1/t:$_MUX_
+select -assert-count 8 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFF_PP1_
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFF_PP1_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 7 dffe/t:$_NOT_
+select -assert-count 8 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 10 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 9 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 3 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 4 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 8 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFF_PP1_
+select -assert-none t:$_SDFF_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFEs.
+
+design -load orig
+dfflegalize -cell $_SDFFE_PP0P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 3 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 3 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 0 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 0 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFE_PP0P_
+select -assert-none t:$_SDFFE_PP0P_ t:$_NOT_ t:$_MUX_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFE_PP0P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 11 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 11 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 0 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 0 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFE_PP0P_
+select -assert-none t:$_SDFFE_PP0P_ t:$_NOT_ t:$_MUX_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFE_PP1P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 2 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 3 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 3 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 0 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 0 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce1/* %n %i
+select -assert-count 2 sdffce1/t:$_AND_
+select -assert-count 1 sdffce1/t:$_ORNOT_
+select -assert-count 1 sdffce1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFE_PP1P_
+select -assert-none t:$_SDFFE_PP1P_ t:$_NOT_ t:$_MUX_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFE_PP1P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 8 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 11 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 11 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 0 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 0 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffce0/* %n %i
+select -assert-count 2 sdffce0/t:$_AND_
+select -assert-count 1 sdffce0/t:$_ORNOT_
+select -assert-count 1 sdffce0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFE_PP1P_
+select -assert-none t:$_SDFFE_PP1P_ t:$_NOT_ t:$_MUX_ t:$_AND_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+
+# Convert everything to SDFFCEs.
+
+design -load orig
+dfflegalize -cell $_SDFFCE_PP0P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 2 sdff0/t:$_NOT_
+select -assert-count 1 sdff1/t:$_NOT_
+select -assert-count 3 sdffe0/t:$_NOT_
+select -assert-count 1 sdffe1/t:$_NOT_
+select -assert-count 3 sdffce0/t:$_NOT_
+select -assert-count 2 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 0 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 0 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffe0/* %n %i
+select -assert-count 2 sdffe0/t:$_OR_
+select -assert-count 1 sdffe0/t:$_ORNOT_
+select -assert-count 1 sdffe0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFCE_PP0P_
+select -assert-none t:$_SDFFCE_PP0P_ t:$_NOT_ t:$_MUX_ t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFCE_PP0P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 7 sdff0/t:$_NOT_
+select -assert-count 8 sdff1/t:$_NOT_
+select -assert-count 9 sdffe0/t:$_NOT_
+select -assert-count 11 sdffe1/t:$_NOT_
+select -assert-count 10 sdffce0/t:$_NOT_
+select -assert-count 11 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 0 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 0 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffe1/* %n %i
+select -assert-count 2 sdffe1/t:$_OR_
+select -assert-count 1 sdffe1/t:$_ORNOT_
+select -assert-count 1 sdffe1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFCE_PP0P_
+select -assert-none t:$_SDFFCE_PP0P_ t:$_NOT_ t:$_MUX_ t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFCE_PP1P_ 0
+
+select -assert-count 1 dff/t:$_NOT_
+select -assert-count 2 dffe/t:$_NOT_
+select -assert-count 1 sdff0/t:$_NOT_
+select -assert-count 2 sdff1/t:$_NOT_
+select -assert-count 1 sdffe0/t:$_NOT_
+select -assert-count 3 sdffe1/t:$_NOT_
+select -assert-count 2 sdffce0/t:$_NOT_
+select -assert-count 3 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 3 sdff0/t:$_MUX_
+select -assert-count 0 sdff1/t:$_MUX_
+select -assert-count 8 sdffe0/t:$_MUX_
+select -assert-count 0 sdffe1/t:$_MUX_
+select -assert-count 4 sdffce0/t:$_MUX_
+select -assert-count 0 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffe1/* %n %i
+select -assert-count 2 sdffe1/t:$_OR_
+select -assert-count 1 sdffe1/t:$_ORNOT_
+select -assert-count 1 sdffe1/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFCE_PP1P_
+select -assert-none t:$_SDFFCE_PP1P_ t:$_NOT_ t:$_MUX_ t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SDFFCE_PP1P_ 1
+
+select -assert-count 5 dff/t:$_NOT_
+select -assert-count 8 dffe/t:$_NOT_
+select -assert-count 8 sdff0/t:$_NOT_
+select -assert-count 7 sdff1/t:$_NOT_
+select -assert-count 11 sdffe0/t:$_NOT_
+select -assert-count 9 sdffe1/t:$_NOT_
+select -assert-count 11 sdffce0/t:$_NOT_
+select -assert-count 10 sdffce1/t:$_NOT_
+select -assert-count 0 dff/t:$_MUX_
+select -assert-count 0 dffe/t:$_MUX_
+select -assert-count 0 sdff0/t:$_MUX_
+select -assert-count 3 sdff1/t:$_MUX_
+select -assert-count 0 sdffe0/t:$_MUX_
+select -assert-count 8 sdffe1/t:$_MUX_
+select -assert-count 0 sdffce0/t:$_MUX_
+select -assert-count 4 sdffce1/t:$_MUX_
+select -assert-count 0 t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ %% sdffe0/* %n %i
+select -assert-count 2 sdffe0/t:$_OR_
+select -assert-count 1 sdffe0/t:$_ORNOT_
+select -assert-count 1 sdffe0/t:$_ANDNOT_
+select -assert-count 27 t:$_SDFFCE_PP1P_
+select -assert-none t:$_SDFFCE_PP1P_ t:$_NOT_ t:$_MUX_ t:$_OR_ t:$_ORNOT_ t:$_ANDNOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dffsr.ys b/tests/techmap/dfflegalize_dffsr.ys
new file mode 100644
index 000000000..49a7237a2
--- /dev/null
+++ b/tests/techmap/dfflegalize_dffsr.ys
@@ -0,0 +1,88 @@
+read_verilog -icells <<EOT
+
+module dffsr(input C, R, S, D, output [3:0] Q);
+$_DFFSR_PPP_ ff0 (.C(C), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DFFSR_PPN_ ff1 (.C(C), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DFFSR_PNP_ ff2 (.C(C), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DFFSR_NPP_ ff3 (.C(C), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+module dffsre(input C, R, S, E, D, output [4:0] Q);
+$_DFFSRE_PPPP_ ff0 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[0]));
+$_DFFSRE_PPPN_ ff1 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[1]));
+$_DFFSRE_PPNP_ ff2 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[2]));
+$_DFFSRE_PNPP_ ff3 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[3]));
+$_DFFSRE_NPPP_ ff4 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[4]));
+endmodule
+
+module top(input C, E, R, S, D, output [8:0] Q);
+dffsr dffsr_(.C(C), .R(R), .S(S), .D(D), .Q(Q[3:0]));
+dffsre dffsre_(.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[8:4]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ x -cell $_SR_PP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ x -cell $_SR_PP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ x
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ x -cell $_SR_PP_ x
+
+select -assert-count 14 dffsr/t:$_NOT_
+select -assert-count 16 dffsre/t:$_NOT_
+select -assert-count 4 dffsr/t:$_MUX_
+select -assert-count 10 dffsre/t:$_MUX_
+select -assert-count 8 dffsr/t:$_DFF_PP0_
+select -assert-count 10 dffsre/t:$_DFF_PP0_
+select -assert-count 4 dffsr/t:$_SR_PP_
+select -assert-count 5 dffsre/t:$_SR_PP_
+select -assert-none t:$_DFF_PP0_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ x -cell $_SR_PP_ x
+
+select -assert-count 14 dffsr/t:$_NOT_
+select -assert-count 18 dffsre/t:$_NOT_
+select -assert-count 4 dffsr/t:$_MUX_
+select -assert-count 5 dffsre/t:$_MUX_
+select -assert-count 8 dffsr/t:$_DFFE_PP0P_
+select -assert-count 10 dffsre/t:$_DFFE_PP0P_
+select -assert-count 4 dffsr/t:$_SR_PP_
+select -assert-count 5 dffsre/t:$_SR_PP_
+select -assert-none t:$_DFFE_PP0P_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ x
+
+select -assert-count 3 dffsr/t:$_NOT_
+select -assert-count 3 dffsre/t:$_NOT_
+select -assert-count 0 dffsr/t:$_MUX_
+select -assert-count 5 dffsre/t:$_MUX_
+select -assert-count 4 dffsr/t:$_DFFSR_PPP_
+select -assert-count 5 dffsre/t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ x
+
+select -assert-count 3 dffsr/t:$_NOT_
+select -assert-count 4 dffsre/t:$_NOT_
+select -assert-count 4 dffsr/t:$_DFFSRE_PPPP_
+select -assert-count 5 dffsre/t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dffsr_init.ys b/tests/techmap/dfflegalize_dffsr_init.ys
new file mode 100644
index 000000000..ce5a32f76
--- /dev/null
+++ b/tests/techmap/dfflegalize_dffsr_init.ys
@@ -0,0 +1,379 @@
+read_verilog -icells <<EOT
+
+module dffsr0(input C, R, S, D, (* init = 4'h0 *) output [3:0] Q);
+$_DFFSR_PPP_ ff0 (.C(C), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DFFSR_PPN_ ff1 (.C(C), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DFFSR_PNP_ ff2 (.C(C), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DFFSR_NPP_ ff3 (.C(C), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+module dffsr1(input C, R, S, D, (* init = 4'hf *) output [3:0] Q);
+$_DFFSR_PPP_ ff0 (.C(C), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DFFSR_PPN_ ff1 (.C(C), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DFFSR_PNP_ ff2 (.C(C), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DFFSR_NPP_ ff3 (.C(C), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+module dffsre0(input C, R, S, E, D, (* init = 5'h0 *) output [4:0] Q);
+$_DFFSRE_PPPP_ ff0 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[0]));
+$_DFFSRE_PPPN_ ff1 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[1]));
+$_DFFSRE_PPNP_ ff2 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[2]));
+$_DFFSRE_PNPP_ ff3 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[3]));
+$_DFFSRE_NPPP_ ff4 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[4]));
+endmodule
+
+module dffsre1(input C, R, S, E, D, (* init = 5'h1f *) output [4:0] Q);
+$_DFFSRE_PPPP_ ff0 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[0]));
+$_DFFSRE_PPPN_ ff1 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[1]));
+$_DFFSRE_PPNP_ ff2 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[2]));
+$_DFFSRE_PNPP_ ff3 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[3]));
+$_DFFSRE_NPPP_ ff4 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[4]));
+endmodule
+
+module top(input C, E, R, S, D, output [17:0] Q);
+dffsr0 dffsr0_(.C(C), .R(R), .S(S), .D(D), .Q(Q[3:0]));
+dffsr1 dffsr1_(.C(C), .R(R), .S(S), .D(D), .Q(Q[7:4]));
+dffsre0 dffsre0_(.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[12:8]));
+dffsre1 dffsre1_(.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[17:13]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 0 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 1 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 0 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP1_ 1 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 0 -cell $_SR_PP_ 0
+
+select -assert-count 14 dffsr0/t:$_NOT_
+select -assert-count 18 dffsr1/t:$_NOT_
+select -assert-count 16 dffsre0/t:$_NOT_
+select -assert-count 21 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 10 dffsre0/t:$_MUX_
+select -assert-count 10 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFF_PP0_
+select -assert-count 8 dffsr1/t:$_DFF_PP0_
+select -assert-count 10 dffsre0/t:$_DFF_PP0_
+select -assert-count 10 dffsre1/t:$_DFF_PP0_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFF_PP0_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 1 -cell $_SR_PP_ 0
+
+select -assert-count 18 dffsr0/t:$_NOT_
+select -assert-count 14 dffsr1/t:$_NOT_
+select -assert-count 21 dffsre0/t:$_NOT_
+select -assert-count 16 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 10 dffsre0/t:$_MUX_
+select -assert-count 10 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFF_PP0_
+select -assert-count 8 dffsr1/t:$_DFF_PP0_
+select -assert-count 10 dffsre0/t:$_DFF_PP0_
+select -assert-count 10 dffsre1/t:$_DFF_PP0_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFF_PP0_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 0 -cell $_SR_PP_ 0
+
+select -assert-count 18 dffsr0/t:$_NOT_
+select -assert-count 14 dffsr1/t:$_NOT_
+select -assert-count 21 dffsre0/t:$_NOT_
+select -assert-count 16 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 10 dffsre0/t:$_MUX_
+select -assert-count 10 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFF_PP1_
+select -assert-count 8 dffsr1/t:$_DFF_PP1_
+select -assert-count 10 dffsre0/t:$_DFF_PP1_
+select -assert-count 10 dffsre1/t:$_DFF_PP1_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFF_PP1_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP1_ 1 -cell $_SR_PP_ 0
+
+select -assert-count 14 dffsr0/t:$_NOT_
+select -assert-count 18 dffsr1/t:$_NOT_
+select -assert-count 16 dffsre0/t:$_NOT_
+select -assert-count 21 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 10 dffsre0/t:$_MUX_
+select -assert-count 10 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFF_PP1_
+select -assert-count 8 dffsr1/t:$_DFF_PP1_
+select -assert-count 10 dffsre0/t:$_DFF_PP1_
+select -assert-count 10 dffsre1/t:$_DFF_PP1_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFF_PP1_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+
+# Convert everything to ADFFEs.
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 0 -cell $_SR_PP_ 1
+
+select -assert-count 18 dffsr0/t:$_NOT_
+select -assert-count 14 dffsr1/t:$_NOT_
+select -assert-count 23 dffsre0/t:$_NOT_
+select -assert-count 18 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFFE_PP0P_
+select -assert-count 8 dffsr1/t:$_DFFE_PP0P_
+select -assert-count 10 dffsre0/t:$_DFFE_PP0P_
+select -assert-count 10 dffsre1/t:$_DFFE_PP0P_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFFE_PP0P_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_SR_PP_ 1
+
+select -assert-count 14 dffsr0/t:$_NOT_
+select -assert-count 18 dffsr1/t:$_NOT_
+select -assert-count 18 dffsre0/t:$_NOT_
+select -assert-count 23 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFFE_PP0P_
+select -assert-count 8 dffsr1/t:$_DFFE_PP0P_
+select -assert-count 10 dffsre0/t:$_DFFE_PP0P_
+select -assert-count 10 dffsre1/t:$_DFFE_PP0P_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFFE_PP0P_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_SR_PP_ 1
+
+select -assert-count 14 dffsr0/t:$_NOT_
+select -assert-count 18 dffsr1/t:$_NOT_
+select -assert-count 18 dffsre0/t:$_NOT_
+select -assert-count 23 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFFE_PP1P_
+select -assert-count 8 dffsr1/t:$_DFFE_PP1P_
+select -assert-count 10 dffsre0/t:$_DFFE_PP1P_
+select -assert-count 10 dffsre1/t:$_DFFE_PP1P_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFFE_PP1P_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_SR_PP_ 1
+
+select -assert-count 18 dffsr0/t:$_NOT_
+select -assert-count 14 dffsr1/t:$_NOT_
+select -assert-count 23 dffsre0/t:$_NOT_
+select -assert-count 18 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_MUX_
+select -assert-count 4 dffsr1/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 8 dffsr0/t:$_DFFE_PP1P_
+select -assert-count 8 dffsr1/t:$_DFFE_PP1P_
+select -assert-count 10 dffsre0/t:$_DFFE_PP1P_
+select -assert-count 10 dffsre1/t:$_DFFE_PP1P_
+select -assert-count 4 dffsr0/t:$_SR_PP_
+select -assert-count 4 dffsr1/t:$_SR_PP_
+select -assert-count 5 dffsre0/t:$_SR_PP_
+select -assert-count 5 dffsre1/t:$_SR_PP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFFE_PP1P_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 0
+
+select -assert-count 3 dffsr0/t:$_NOT_
+select -assert-count 11 dffsr1/t:$_NOT_
+select -assert-count 3 dffsre0/t:$_NOT_
+select -assert-count 13 dffsre1/t:$_NOT_
+select -assert-count 0 dffsr0/t:$_MUX_
+select -assert-count 0 dffsr1/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 4 dffsr0/t:$_DFFSR_PPP_
+select -assert-count 4 dffsr1/t:$_DFFSR_PPP_
+select -assert-count 5 dffsre0/t:$_DFFSR_PPP_
+select -assert-count 5 dffsre1/t:$_DFFSR_PPP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 1
+
+select -assert-count 11 dffsr0/t:$_NOT_
+select -assert-count 3 dffsr1/t:$_NOT_
+select -assert-count 13 dffsre0/t:$_NOT_
+select -assert-count 3 dffsre1/t:$_NOT_
+select -assert-count 0 dffsr0/t:$_MUX_
+select -assert-count 0 dffsr1j/t:$_MUX_
+select -assert-count 5 dffsre0/t:$_MUX_
+select -assert-count 5 dffsre1/t:$_MUX_
+select -assert-count 4 dffsr0/t:$_DFFSR_PPP_
+select -assert-count 4 dffsr1/t:$_DFFSR_PPP_
+select -assert-count 5 dffsre0/t:$_DFFSR_PPP_
+select -assert-count 5 dffsre1/t:$_DFFSR_PPP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFFSR_PPP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 0
+
+select -assert-count 3 dffsr0/t:$_NOT_
+select -assert-count 11 dffsr1/t:$_NOT_
+select -assert-count 4 dffsre0/t:$_NOT_
+select -assert-count 14 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_DFFSRE_PPPP_
+select -assert-count 4 dffsr1/t:$_DFFSRE_PPPP_
+select -assert-count 5 dffsre0/t:$_DFFSRE_PPPP_
+select -assert-count 5 dffsre1/t:$_DFFSRE_PPPP_
+select -assert-count 1 dffsr1/t:$_AND_
+select -assert-count 2 dffsr1/t:$_ANDNOT_
+select -assert-count 1 dffsr1/t:$_OR_
+select -assert-count 1 dffsre1/t:$_AND_
+select -assert-count 3 dffsre1/t:$_ANDNOT_
+select -assert-count 1 dffsre1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr1/* dffsre1/* %u %n %i
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+select -assert-count 11 dffsr0/t:$_NOT_
+select -assert-count 3 dffsr1/t:$_NOT_
+select -assert-count 14 dffsre0/t:$_NOT_
+select -assert-count 4 dffsre1/t:$_NOT_
+select -assert-count 4 dffsr0/t:$_DFFSRE_PPPP_
+select -assert-count 4 dffsr1/t:$_DFFSRE_PPPP_
+select -assert-count 5 dffsre0/t:$_DFFSRE_PPPP_
+select -assert-count 5 dffsre1/t:$_DFFSRE_PPPP_
+select -assert-count 1 dffsr0/t:$_AND_
+select -assert-count 2 dffsr0/t:$_ANDNOT_
+select -assert-count 1 dffsr0/t:$_OR_
+select -assert-count 1 dffsre0/t:$_AND_
+select -assert-count 3 dffsre0/t:$_ANDNOT_
+select -assert-count 1 dffsre0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dffsr0/* dffsre0/* %u %n %i
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatch.ys b/tests/techmap/dfflegalize_dlatch.ys
new file mode 100644
index 000000000..b68ea741e
--- /dev/null
+++ b/tests/techmap/dfflegalize_dlatch.ys
@@ -0,0 +1,42 @@
+read_verilog -icells <<EOT
+
+module dlatch(input E, D, output [1:0] Q);
+$_DLATCH_P_ ff0 (.E(E), .D(D), .Q(Q[0]));
+$_DLATCH_N_ ff1 (.E(E), .D(D), .Q(Q[1]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_P_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ x
+
+# Convert everything to DFFs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_P_ x
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_P_
+select -assert-none t:$_DLATCH_P_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ x
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ x
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatch_const.ys b/tests/techmap/dfflegalize_dlatch_const.ys
new file mode 100644
index 000000000..f30a534fd
--- /dev/null
+++ b/tests/techmap/dfflegalize_dlatch_const.ys
@@ -0,0 +1,53 @@
+read_verilog -icells <<EOT
+
+module dlatch(input E, D, (* init = 8'hf0 *) output [7:0] Q);
+$_DLATCH_P_ ff0 (.E(E), .D(1'b0), .Q(Q[0]));
+$_DLATCH_N_ ff1 (.E(E), .D(1'b0), .Q(Q[1]));
+$_DLATCH_P_ ff2 (.E(E), .D(1'b1), .Q(Q[2]));
+$_DLATCH_N_ ff3 (.E(E), .D(1'b1), .Q(Q[3]));
+$_DLATCH_P_ ff4 (.E(E), .D(1'b0), .Q(Q[4]));
+$_DLATCH_N_ ff5 (.E(E), .D(1'b0), .Q(Q[5]));
+$_DLATCH_P_ ff6 (.E(E), .D(1'b1), .Q(Q[6]));
+$_DLATCH_N_ ff7 (.E(E), .D(1'b1), .Q(Q[7]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP0_ 01
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_PP?_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+# Convert everything to ADFFs.
+
+design -load orig
+dfflegalize -cell $_DFF_PP0_ 01
+
+select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_DFF_PP0_
+select -assert-none t:$_DFF_PP0_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFF_PP?_ 0
+
+select -assert-count 12 t:$_NOT_
+select -assert-count 4 t:$_DFF_PP0_
+select -assert-count 4 t:$_DFF_PP1_
+select -assert-none t:$_DFF_PP0_ t:$_DFF_PP1_ t:$_NOT_ %% %n t:* %i
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 0
+
+select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+select -assert-count 12 t:$_NOT_
+select -assert-count 8 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatch_init.ys b/tests/techmap/dfflegalize_dlatch_init.ys
new file mode 100644
index 000000000..ccc9e41d7
--- /dev/null
+++ b/tests/techmap/dfflegalize_dlatch_init.ys
@@ -0,0 +1,82 @@
+read_verilog -icells <<EOT
+
+module dlatch(input E, D, (* init = 2'h0 *) output [1:0] Q);
+$_DLATCH_P_ ff0 (.E(E), .D(D), .Q(Q[0]));
+$_DLATCH_N_ ff1 (.E(E), .D(D), .Q(Q[1]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_P_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_P_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 1
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 0
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+# Convert everything to DFFs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_P_ 0
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_P_
+select -assert-none t:$_DLATCH_P_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_P_ 1
+
+select -assert-count 5 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_P_
+select -assert-none t:$_DLATCH_P_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 0
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 1
+
+select -assert-count 5 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 0
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_PP1_
+select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 1
+
+select -assert-count 5 t:$_NOT_
+select -assert-count 2 t:$_DLATCH_PP1_
+select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 0
+
+select -assert-count 1 t:$_NOT_
+select -assert-count 2 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+select -assert-count 5 t:$_NOT_
+select -assert-count 2 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatchsr.ys b/tests/techmap/dfflegalize_dlatchsr.ys
new file mode 100644
index 000000000..53d910723
--- /dev/null
+++ b/tests/techmap/dfflegalize_dlatchsr.ys
@@ -0,0 +1,37 @@
+read_verilog -icells <<EOT
+
+module dlatchsr(input E, R, S, D, output [3:0] Q);
+$_DLATCHSR_PPP_ ff0 (.E(E), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DLATCHSR_PPN_ ff1 (.E(E), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DLATCHSR_PNP_ ff2 (.E(E), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DLATCHSR_NPP_ ff3 (.E(E), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ x -cell $_SR_PP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ x
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ x -cell $_SR_PP_ x
+
+select -assert-count 14 t:$_NOT_
+select -assert-count 4 t:$_MUX_
+select -assert-count 8 t:$_DLATCH_PP0_
+select -assert-count 4 t:$_SR_PP_
+select -assert-none t:$_DLATCH_PP0_ t:$_SR_PP_ t:$_MUX_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ x
+
+select -assert-count 3 t:$_NOT_
+select -assert-count 0 t:$_MUX_
+select -assert-count 4 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_dlatchsr_init.ys b/tests/techmap/dfflegalize_dlatchsr_init.ys
new file mode 100644
index 000000000..2d33634d1
--- /dev/null
+++ b/tests/techmap/dfflegalize_dlatchsr_init.ys
@@ -0,0 +1,127 @@
+read_verilog -icells <<EOT
+
+module dlatchsr0(input E, R, S, D, (* init = 4'h0 *) output [3:0] Q);
+$_DLATCHSR_PPP_ ff0 (.E(E), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DLATCHSR_PPN_ ff1 (.E(E), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DLATCHSR_PNP_ ff2 (.E(E), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DLATCHSR_NPP_ ff3 (.E(E), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+module dlatchsr1(input E, R, S, D, (* init = 4'hf *) output [3:0] Q);
+$_DLATCHSR_PPP_ ff0 (.E(E), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DLATCHSR_PPN_ ff1 (.E(E), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DLATCHSR_PNP_ ff2 (.E(E), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DLATCHSR_NPP_ ff3 (.E(E), .R(R), .S(S), .D(D), .Q(Q[3]));
+endmodule
+
+module top(input C, E, R, S, D, output [17:0] Q);
+dlatchsr0 dlatchsr0_(.E(E), .R(R), .S(S), .D(D), .Q(Q[3:0]));
+dlatchsr1 dlatchsr1_(.E(E), .R(R), .S(S), .D(D), .Q(Q[7:4]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 0
+
+select -assert-count 14 dlatchsr0/t:$_NOT_
+select -assert-count 18 dlatchsr1/t:$_NOT_
+select -assert-count 4 dlatchsr0/t:$_MUX_
+select -assert-count 4 dlatchsr1/t:$_MUX_
+select -assert-count 12 dlatchsr0/t:$_DLATCH_PP0_
+select -assert-count 12 dlatchsr1/t:$_DLATCH_PP0_
+select -assert-count 1 dlatchsr1/t:$_AND_
+select -assert-count 2 dlatchsr1/t:$_ANDNOT_
+select -assert-count 1 dlatchsr1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr1/* %n %i
+select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 1
+
+select -assert-count 14 dlatchsr0/t:$_NOT_
+select -assert-count 18 dlatchsr1/t:$_NOT_
+select -assert-count 4 dlatchsr0/t:$_MUX_
+select -assert-count 4 dlatchsr1/t:$_MUX_
+select -assert-count 12 dlatchsr0/t:$_DLATCH_PP0_
+select -assert-count 12 dlatchsr1/t:$_DLATCH_PP0_
+select -assert-count 1 dlatchsr1/t:$_AND_
+select -assert-count 2 dlatchsr1/t:$_ANDNOT_
+select -assert-count 1 dlatchsr1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr1/* %n %i
+select -assert-none t:$_DLATCH_PP0_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 0
+
+select -assert-count 22 dlatchsr0/t:$_NOT_
+select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 4 dlatchsr0/t:$_MUX_
+select -assert-count 4 dlatchsr1/t:$_MUX_
+select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
+select -assert-count 12 dlatchsr1/t:$_DLATCH_PP1_
+select -assert-count 1 dlatchsr1/t:$_AND_
+select -assert-count 2 dlatchsr1/t:$_ANDNOT_
+select -assert-count 1 dlatchsr1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr1/* %n %i
+select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 1
+
+select -assert-count 22 dlatchsr0/t:$_NOT_
+select -assert-count 26 dlatchsr1/t:$_NOT_
+select -assert-count 4 dlatchsr0/t:$_MUX_
+select -assert-count 4 dlatchsr1/t:$_MUX_
+select -assert-count 12 dlatchsr0/t:$_DLATCH_PP1_
+select -assert-count 12 dlatchsr1/t:$_DLATCH_PP1_
+select -assert-count 1 dlatchsr1/t:$_AND_
+select -assert-count 2 dlatchsr1/t:$_ANDNOT_
+select -assert-count 1 dlatchsr1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr1/* %n %i
+select -assert-none t:$_DLATCH_PP1_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 0
+
+select -assert-count 3 dlatchsr0/t:$_NOT_
+select -assert-count 11 dlatchsr1/t:$_NOT_
+select -assert-count 0 dlatchsr0/t:$_MUX_
+select -assert-count 0 dlatchsr1/t:$_MUX_
+select -assert-count 4 dlatchsr0/t:$_DLATCHSR_PPP_
+select -assert-count 4 dlatchsr1/t:$_DLATCHSR_PPP_
+select -assert-count 1 dlatchsr1/t:$_AND_
+select -assert-count 2 dlatchsr1/t:$_ANDNOT_
+select -assert-count 1 dlatchsr1/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr1/* %n %i
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+select -assert-count 11 dlatchsr0/t:$_NOT_
+select -assert-count 3 dlatchsr1/t:$_NOT_
+select -assert-count 0 dlatchsr0/t:$_MUX_
+select -assert-count 0 dlatchsr1j/t:$_MUX_
+select -assert-count 4 dlatchsr0/t:$_DLATCHSR_PPP_
+select -assert-count 4 dlatchsr1/t:$_DLATCHSR_PPP_
+select -assert-count 1 dlatchsr0/t:$_AND_
+select -assert-count 2 dlatchsr0/t:$_ANDNOT_
+select -assert-count 1 dlatchsr0/t:$_OR_
+select -assert-count 0 t:$_AND_ t:$_OR_ t:$_ANDNOT_ %% dlatchsr0/* %n %i
+select -assert-none t:$_DLATCHSR_PPP_ t:$_MUX_ t:$_NOT_ t:$_AND_ t:$_ANDNOT_ t:$_OR_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_inv.ys b/tests/techmap/dfflegalize_inv.ys
new file mode 100644
index 000000000..cb42e01a8
--- /dev/null
+++ b/tests/techmap/dfflegalize_inv.ys
@@ -0,0 +1,178 @@
+# Base test: make sure inverters are applied correctly.
+
+read_verilog -icells <<EOT
+
+module top(input C, E, R, S, D, output [64:0] Q);
+
+$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
+$_DFF_N_ ff1 (.C(C), .D(D), .Q(Q[1]));
+
+$_DFFE_PP_ ff2 (.C(C), .E(E), .D(D), .Q(Q[2]));
+$_DFFE_PN_ ff3 (.C(C), .E(E), .D(D), .Q(Q[3]));
+$_DFFE_NP_ ff4 (.C(C), .E(E), .D(D), .Q(Q[4]));
+
+$_DFF_PP0_ ff5 (.C(C), .R(R), .D(D), .Q(Q[5]));
+$_DFF_PN0_ ff6 (.C(C), .R(R), .D(D), .Q(Q[6]));
+$_DFF_NP0_ ff7 (.C(C), .R(R), .D(D), .Q(Q[7]));
+
+$_DFF_PP1_ ff8 (.C(C), .R(R), .D(D), .Q(Q[8]));
+$_DFF_PN1_ ff9 (.C(C), .R(R), .D(D), .Q(Q[9]));
+$_DFF_NP1_ ff10 (.C(C), .R(R), .D(D), .Q(Q[10]));
+
+$_DFFE_PP0P_ ff11 (.C(C), .R(R), .E(E), .D(D), .Q(Q[11]));
+$_DFFE_PP0N_ ff12 (.C(C), .R(R), .E(E), .D(D), .Q(Q[12]));
+$_DFFE_PN0P_ ff13 (.C(C), .R(R), .E(E), .D(D), .Q(Q[13]));
+$_DFFE_NP0P_ ff14 (.C(C), .R(R), .E(E), .D(D), .Q(Q[14]));
+
+$_DFFE_PP1P_ ff15 (.C(C), .R(R), .E(E), .D(D), .Q(Q[15]));
+$_DFFE_PP1N_ ff16 (.C(C), .R(R), .E(E), .D(D), .Q(Q[16]));
+$_DFFE_PN1P_ ff17 (.C(C), .R(R), .E(E), .D(D), .Q(Q[17]));
+$_DFFE_NP1P_ ff18 (.C(C), .R(R), .E(E), .D(D), .Q(Q[18]));
+
+$_DFFSR_PPP_ ff19 (.C(C), .R(R), .S(S), .D(D), .Q(Q[19]));
+$_DFFSR_PPN_ ff20 (.C(C), .R(R), .S(S), .D(D), .Q(Q[20]));
+$_DFFSR_PNP_ ff21 (.C(C), .R(R), .S(S), .D(D), .Q(Q[21]));
+$_DFFSR_NPP_ ff22 (.C(C), .R(R), .S(S), .D(D), .Q(Q[22]));
+
+$_DFFSRE_PPPP_ ff23 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[23]));
+$_DFFSRE_PPPN_ ff24 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[24]));
+$_DFFSRE_PPNP_ ff25 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[25]));
+$_DFFSRE_PNPP_ ff26 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[26]));
+$_DFFSRE_NPPP_ ff27 (.C(C), .R(R), .S(S), .E(E), .D(D), .Q(Q[27]));
+
+$_SDFF_PP0_ ff28 (.C(C), .R(R), .D(D), .Q(Q[28]));
+$_SDFF_PN0_ ff29 (.C(C), .R(R), .D(D), .Q(Q[29]));
+$_SDFF_NP0_ ff30 (.C(C), .R(R), .D(D), .Q(Q[30]));
+
+$_SDFF_PP1_ ff31 (.C(C), .R(R), .D(D), .Q(Q[31]));
+$_SDFF_PN1_ ff32 (.C(C), .R(R), .D(D), .Q(Q[32]));
+$_SDFF_NP1_ ff33 (.C(C), .R(R), .D(D), .Q(Q[33]));
+
+$_SDFFE_PP0P_ ff34 (.C(C), .R(R), .E(E), .D(D), .Q(Q[34]));
+$_SDFFE_PP0N_ ff35 (.C(C), .R(R), .E(E), .D(D), .Q(Q[35]));
+$_SDFFE_PN0P_ ff36 (.C(C), .R(R), .E(E), .D(D), .Q(Q[36]));
+$_SDFFE_NP0P_ ff37 (.C(C), .R(R), .E(E), .D(D), .Q(Q[37]));
+
+$_SDFFE_PP1P_ ff38 (.C(C), .R(R), .E(E), .D(D), .Q(Q[38]));
+$_SDFFE_PP1N_ ff39 (.C(C), .R(R), .E(E), .D(D), .Q(Q[39]));
+$_SDFFE_PN1P_ ff40 (.C(C), .R(R), .E(E), .D(D), .Q(Q[40]));
+$_SDFFE_NP1P_ ff41 (.C(C), .R(R), .E(E), .D(D), .Q(Q[41]));
+
+$_SDFFCE_PP0P_ ff42 (.C(C), .R(R), .E(E), .D(D), .Q(Q[42]));
+$_SDFFCE_PP0N_ ff43 (.C(C), .R(R), .E(E), .D(D), .Q(Q[43]));
+$_SDFFCE_PN0P_ ff44 (.C(C), .R(R), .E(E), .D(D), .Q(Q[44]));
+$_SDFFCE_NP0P_ ff45 (.C(C), .R(R), .E(E), .D(D), .Q(Q[45]));
+
+$_SDFFCE_PP1P_ ff46 (.C(C), .R(R), .E(E), .D(D), .Q(Q[46]));
+$_SDFFCE_PP1N_ ff47 (.C(C), .R(R), .E(E), .D(D), .Q(Q[47]));
+$_SDFFCE_PN1P_ ff48 (.C(C), .R(R), .E(E), .D(D), .Q(Q[48]));
+$_SDFFCE_NP1P_ ff49 (.C(C), .R(R), .E(E), .D(D), .Q(Q[49]));
+
+$_DLATCH_P_ ff50 (.E(E), .D(D), .Q(Q[50]));
+$_DLATCH_N_ ff51 (.E(E), .D(D), .Q(Q[51]));
+
+$_DLATCH_PP0_ ff52 (.E(E), .R(R), .D(D), .Q(Q[52]));
+$_DLATCH_PN0_ ff53 (.E(E), .R(R), .D(D), .Q(Q[53]));
+$_DLATCH_NP0_ ff54 (.E(E), .R(R), .D(D), .Q(Q[54]));
+
+$_DLATCH_PP1_ ff55 (.E(E), .R(R), .D(D), .Q(Q[55]));
+$_DLATCH_PN1_ ff56 (.E(E), .R(R), .D(D), .Q(Q[56]));
+$_DLATCH_NP1_ ff57 (.E(E), .R(R), .D(D), .Q(Q[57]));
+
+$_DLATCHSR_PPP_ ff58 (.E(E), .R(R), .S(S), .D(D), .Q(Q[58]));
+$_DLATCHSR_PPN_ ff59 (.E(E), .R(R), .S(S), .D(D), .Q(Q[59]));
+$_DLATCHSR_PNP_ ff60 (.E(E), .R(R), .S(S), .D(D), .Q(Q[60]));
+$_DLATCHSR_NPP_ ff61 (.E(E), .R(R), .S(S), .D(D), .Q(Q[61]));
+
+$_SR_PP_ ff62 (.R(R), .S(S), .Q(Q[62]));
+$_SR_PN_ ff63 (.R(R), .S(S), .Q(Q[63]));
+$_SR_NP_ ff64 (.R(R), .S(S), .Q(Q[64]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_P_ x -cell $_DFFE_PP_ x -cell $_DFF_PP?_ x -cell $_DFFE_PP?P_ x -cell $_DFFSR_PPP_ x -cell $_DFFSRE_PPPP_ x -cell $_SDFF_PP?_ x -cell $_SDFFE_PP?P_ x -cell $_SDFFCE_PP?P_ x -cell $_DLATCH_P_ x -cell $_DLATCH_PP?_ x -cell $_DLATCHSR_PPP_ x -cell $_SR_PP_ x
+design -load postopt
+
+select -assert-count 46 t:$_NOT_
+select -assert-count 2 t:$_DFF_P_
+select -assert-count 3 t:$_DFFE_PP_
+select -assert-count 3 t:$_DFF_PP0_
+select -assert-count 3 t:$_DFF_PP1_
+select -assert-count 4 t:$_DFFE_PP0P_
+select -assert-count 4 t:$_DFFE_PP1P_
+select -assert-count 4 t:$_DFFSR_PPP_
+select -assert-count 5 t:$_DFFSRE_PPPP_
+select -assert-count 3 t:$_SDFF_PP0_
+select -assert-count 3 t:$_SDFF_PP1_
+select -assert-count 4 t:$_SDFFE_PP0P_
+select -assert-count 4 t:$_SDFFE_PP1P_
+select -assert-count 4 t:$_SDFFCE_PP0P_
+select -assert-count 4 t:$_SDFFCE_PP1P_
+select -assert-count 2 t:$_DLATCH_P_
+select -assert-count 3 t:$_DLATCH_PP0_
+select -assert-count 3 t:$_DLATCH_PP1_
+select -assert-count 4 t:$_DLATCHSR_PPP_
+select -assert-count 3 t:$_SR_PP_
+select -assert-none t:$_DFF_P_ t:$_DFFE_PP_ t:$_DFF_PP?_ t:$_DFFE_PP?P_ t:$_DFFSR_PPP_ t:$_DFFSRE_PPPP_ t:$_SDFF_PP?_ t:$_SDFFE_PP?P_ t:$_SDFFCE_PP?P_ t:$_DLATCH_P_ t:$_DLATCH_PP?_ t:$_DLATCHSR_PPP_ t:$_SR_PP_ t:$_NOT_ %% %n t:* %i
+
+# Now try it again, targetting the opposite cells.
+
+design -load orig
+
+equiv_opt -assert -multiclock dfflegalize -cell $_DFF_N_ x -cell $_DFFE_NN_ x -cell $_DFF_NN?_ x -cell $_DFFE_NN?N_ x -cell $_DFFSR_NNN_ x -cell $_DFFSRE_NNNN_ x -cell $_SDFF_NN?_ x -cell $_SDFFE_NN?N_ x -cell $_SDFFCE_NN?N_ x -cell $_DLATCH_N_ x -cell $_DLATCH_NN?_ x -cell $_DLATCHSR_NNN_ x -cell $_SR_NN_ x
+design -load postopt
+
+select -assert-count 122 t:$_NOT_
+select -assert-count 2 t:$_DFF_N_
+select -assert-count 3 t:$_DFFE_NN_
+select -assert-count 3 t:$_DFF_NN0_
+select -assert-count 3 t:$_DFF_NN1_
+select -assert-count 4 t:$_DFFE_NN0N_
+select -assert-count 4 t:$_DFFE_NN1N_
+select -assert-count 4 t:$_DFFSR_NNN_
+select -assert-count 5 t:$_DFFSRE_NNNN_
+select -assert-count 3 t:$_SDFF_NN0_
+select -assert-count 3 t:$_SDFF_NN1_
+select -assert-count 4 t:$_SDFFE_NN0N_
+select -assert-count 4 t:$_SDFFE_NN1N_
+select -assert-count 4 t:$_SDFFCE_NN0N_
+select -assert-count 4 t:$_SDFFCE_NN1N_
+select -assert-count 2 t:$_DLATCH_N_
+select -assert-count 3 t:$_DLATCH_NN0_
+select -assert-count 3 t:$_DLATCH_NN1_
+select -assert-count 4 t:$_DLATCHSR_NNN_
+select -assert-count 3 t:$_SR_NN_
+select -assert-none t:$_DFF_N_ t:$_DFFE_NN_ t:$_DFF_NN?_ t:$_DFFE_NN?N_ t:$_DFFSR_NNN_ t:$_DFFSRE_NNNN_ t:$_SDFF_NN?_ t:$_SDFFE_NN?N_ t:$_SDFFCE_NN?N_ t:$_DLATCH_N_ t:$_DLATCH_NN?_ t:$_DLATCHSR_NNN_ t:$_SR_NN_ t:$_NOT_ %% %n t:* %i
+
+
+# Second test: make sure set/reset/enable are inverted before clock.
+
+design -reset
+
+read_verilog -icells <<EOT
+
+module top(input C, E, R, S, D, output [3:0] Q);
+
+$_DFFSRE_PPPP_ ff0 (.C(C), .E(E), .R(R), .S(S), .D(D), .Q(Q[0]));
+$_DFFSRE_NPPP_ ff1 (.C(C), .E(E), .R(R), .S(S), .D(D), .Q(Q[1]));
+$_DFFSRE_PNNN_ ff2 (.C(C), .E(E), .R(R), .S(S), .D(D), .Q(Q[2]));
+$_DFFSRE_NNNN_ ff3 (.C(C), .E(E), .R(R), .S(S), .D(D), .Q(Q[3]));
+
+endmodule
+
+EOT
+
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_NNNN_ x -cell $_DFFSRE_PPPP_ x
+design -load postopt
+
+select -assert-count 6 t:$_NOT_
+select -assert-count 2 t:$_DFFSRE_PPPP_
+select -assert-count 2 t:$_DFFSRE_NNNN_
+select -assert-count 1 t:$_DFFSRE_PPPP_ n:ff0 %i
+select -assert-count 1 t:$_DFFSRE_NNNN_ n:ff1 %i
+select -assert-count 1 t:$_DFFSRE_PPPP_ n:ff2 %i
+select -assert-count 1 t:$_DFFSRE_NNNN_ n:ff3 %i
diff --git a/tests/techmap/dfflegalize_mince.ys b/tests/techmap/dfflegalize_mince.ys
new file mode 100644
index 000000000..31c8d04fc
--- /dev/null
+++ b/tests/techmap/dfflegalize_mince.ys
@@ -0,0 +1,53 @@
+read_verilog -icells <<EOT
+
+module top(input D, C, R, S, input [4:0] E, output [15:0] Q);
+$_DFFE_PP_ ff0(.D(D), .C(C), .E(E[0]), .Q(Q[0]));
+$_DFFE_PP0P_ ff1(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[1]));
+$_DFFE_PP1P_ ff2(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[2]));
+$_SDFFE_PP0P_ ff3(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[3]));
+$_SDFFE_PP1P_ ff4(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[4]));
+$_SDFFCE_PP0P_ ff5(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[5]));
+$_SDFFCE_PP1P_ ff6(.D(D), .C(C), .E(E[0]), .R(R), .Q(Q[6]));
+$_DFFSRE_PPPP_ ff7(.D(D), .C(C), .E(E[0]), .R(R), .S(S), .Q(Q[7]));
+$_DFFE_PP_ ff8(.D(D), .C(C), .E(E[1]), .Q(Q[8]));
+$_DFFE_PP0P_ ff9(.D(D), .C(C), .E(E[1]), .R(R), .Q(Q[9]));
+$_DFFE_PP1P_ ff10(.D(D), .C(C), .E(E[2]), .R(R), .Q(Q[10]));
+$_SDFFE_PP0P_ ff11(.D(D), .C(C), .E(E[2]), .R(R), .Q(Q[11]));
+$_SDFFE_PP1P_ ff12(.D(D), .C(C), .E(E[3]), .R(R), .Q(Q[12]));
+$_SDFFCE_PP0P_ ff13(.D(D), .C(C), .E(E[3]), .R(R), .Q(Q[13]));
+$_SDFFCE_PP1P_ ff14(.D(D), .C(C), .E(E[4]), .R(R), .Q(Q[14]));
+$_DFFSRE_PPPP_ ff15(.D(D), .C(C), .E(E[4]), .R(R), .S(S), .Q(Q[15]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFE_PP_ x -cell $_DFFE_PP?P_ x -cell $_DFFSRE_PPPP_ x -cell $_SDFFE_PP?P_ x -cell $_SDFFCE_PP?P_ x -mince 3
+design -load postopt
+
+select -assert-count 4 t:$_DFFE_PP_
+select -assert-count 2 t:$_DFFE_PP0P_
+select -assert-count 2 t:$_DFFE_PP1P_
+select -assert-count 2 t:$_SDFFE_PP0P_
+select -assert-count 2 t:$_SDFFE_PP1P_
+select -assert-count 1 t:$_SDFFCE_PP0P_
+select -assert-count 1 t:$_SDFFCE_PP1P_
+select -assert-count 2 t:$_DFFSRE_PPPP_
+select -assert-count 10 t:$_MUX_
+select -assert-count 0 n:ff0 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff1 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff2 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff3 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff4 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff5 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff6 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff7 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff8 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff9 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff10 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff11 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff12 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff13 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff14 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff15 %ci %ci t:$_MUX_ %i
+select -assert-none n:ff* t:$_MUX_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_minsrst.ys b/tests/techmap/dfflegalize_minsrst.ys
new file mode 100644
index 000000000..0fc40dc08
--- /dev/null
+++ b/tests/techmap/dfflegalize_minsrst.ys
@@ -0,0 +1,43 @@
+read_verilog -icells <<EOT
+
+module top(input D, C, E, input [3:0] R, output [11:0] Q);
+$_SDFF_PP0_ ff0(.D(D), .C(C), .R(R[0]), .Q(Q[0]));
+$_SDFF_PP1_ ff1(.D(D), .C(C), .R(R[0]), .Q(Q[1]));
+$_SDFFE_PP0P_ ff2(.D(D), .C(C), .R(R[0]), .E(E), .Q(Q[2]));
+$_SDFFE_PP1P_ ff3(.D(D), .C(C), .R(R[0]), .E(E), .Q(Q[3]));
+$_SDFFCE_PP0P_ ff4(.D(D), .C(C), .R(R[0]), .E(E), .Q(Q[4]));
+$_SDFFCE_PP1P_ ff5(.D(D), .C(C), .R(R[0]), .E(E), .Q(Q[5]));
+$_SDFF_PP0_ ff6(.D(D), .C(C), .R(R[1]), .Q(Q[6]));
+$_SDFF_PP1_ ff7(.D(D), .C(C), .R(R[1]), .Q(Q[7]));
+$_SDFFE_PP0P_ ff8(.D(D), .C(C), .R(R[2]), .E(E), .Q(Q[8]));
+$_SDFFE_PP1P_ ff9(.D(D), .C(C), .R(R[2]), .E(E), .Q(Q[9]));
+$_SDFFCE_PP0P_ ff10(.D(D), .C(C), .R(R[3]), .E(E), .Q(Q[10]));
+$_SDFFCE_PP1P_ ff11(.D(D), .C(C), .R(R[3]), .E(E), .Q(Q[11]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_SDFF_PP?_ x -cell $_SDFFE_PP?P_ x -cell $_SDFFCE_PP?P_ x -minsrst 3
+design -load postopt
+
+select -assert-count 5 t:$_SDFF_PP0_
+select -assert-count 1 t:$_SDFF_PP1_
+select -assert-count 3 t:$_SDFFE_PP0P_
+select -assert-count 1 t:$_SDFFE_PP1P_
+select -assert-count 1 t:$_SDFFCE_PP0P_
+select -assert-count 1 t:$_SDFFCE_PP1P_
+select -assert-count 8 t:$_MUX_
+select -assert-count 0 n:ff0 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff1 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff2 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff3 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff4 %ci %ci t:$_MUX_ %i
+select -assert-count 0 n:ff5 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff6 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff7 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff8 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff9 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff10 %ci %ci t:$_MUX_ %i
+select -assert-count 1 n:ff11 %ci %ci t:$_MUX_ %i
+select -assert-none n:ff* t:$_MUX_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_sr.ys b/tests/techmap/dfflegalize_sr.ys
new file mode 100644
index 000000000..27e83be91
--- /dev/null
+++ b/tests/techmap/dfflegalize_sr.ys
@@ -0,0 +1,74 @@
+read_verilog -icells <<EOT
+
+module sr(input R, S, output [2:0] Q);
+$_SR_PP_ ff0 (.R(R), .S(S), .Q(Q[0]));
+$_SR_PN_ ff1 (.R(R), .S(S), .Q(Q[1]));
+$_SR_NP_ ff2 (.R(R), .S(S), .Q(Q[2]));
+endmodule
+
+EOT
+
+design -save orig
+equiv_opt -assert -multiclock dfflegalize -cell $_SR_PP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ x
+equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ x
+
+
+# Convert everything to SRs.
+
+design -load orig
+dfflegalize -cell $_SR_PP_ x
+
+select -assert-count 2 t:$_NOT_
+select -assert-count 3 t:$_SR_PP_
+select -assert-none t:$_SR_PP_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ x
+
+select -assert-count 2 t:$_NOT_
+select -assert-count 3 t:$_DLATCH_PP0_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ x
+
+select -assert-count 8 t:$_NOT_
+select -assert-count 3 t:$_DLATCH_PP1_
+select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ x
+
+select -assert-count 2 t:$_NOT_
+select -assert-count 3 t:$_DLATCHSR_PPP_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ x
+
+select -assert-count 2 t:$_NOT_
+select -assert-count 3 t:$_DFFSR_PPP_
+select -assert-none t:$_DFFSR_PPP_ t:$_NOT_ %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ x
+
+select -assert-count 2 t:$_NOT_
+select -assert-count 3 t:$_DFFSRE_PPPP_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dfflegalize_sr_init.ys b/tests/techmap/dfflegalize_sr_init.ys
new file mode 100644
index 000000000..52b797b9e
--- /dev/null
+++ b/tests/techmap/dfflegalize_sr_init.ys
@@ -0,0 +1,230 @@
+read_verilog -icells <<EOT
+
+module sr0(input R, S, (* init = 3'h0 *) output [2:0] Q);
+$_SR_PP_ ff0 (.R(R), .S(S), .Q(Q[0]));
+$_SR_PN_ ff1 (.R(R), .S(S), .Q(Q[1]));
+$_SR_NP_ ff2 (.R(R), .S(S), .Q(Q[2]));
+endmodule
+
+module sr1(input R, S, (* init = 3'h7 *) output [2:0] Q);
+$_SR_PP_ ff0 (.R(R), .S(S), .Q(Q[0]));
+$_SR_PN_ ff1 (.R(R), .S(S), .Q(Q[1]));
+$_SR_NP_ ff2 (.R(R), .S(S), .Q(Q[2]));
+endmodule
+
+module top(input C, E, R, D, output [5:0] Q);
+sr0 sr0_(.S(S), .R(R), .Q(Q[2:0]));
+sr1 sr1_(.S(S), .R(R), .Q(Q[5:3]));
+endmodule
+
+EOT
+
+design -save orig
+flatten
+#equiv_opt -assert -multiclock dfflegalize -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_SR_PP_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP0_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCH_PP1_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DLATCHSR_PPP_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSR_PPP_ 1
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 0
+#equiv_opt -assert -multiclock dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+
+# Convert everything to SRs.
+
+design -load orig
+dfflegalize -cell $_SR_PP_ 0
+
+select -assert-count 2 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_SR_PP_
+select -assert-count 3 sr1/t:$_SR_PP_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_SR_PP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_SR_PP_ 1
+
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 2 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_SR_PP_
+select -assert-count 3 sr1/t:$_SR_PP_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_SR_PP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+
+# Convert everything to ADLATCHs.
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 0
+
+select -assert-count 2 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCH_PP0_
+select -assert-count 3 sr1/t:$_DLATCH_PP0_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP0_ 1
+
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 2 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCH_PP0_
+select -assert-count 3 sr1/t:$_DLATCH_PP0_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_DLATCH_PP0_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 0
+
+select -assert-count 11 sr0/t:$_NOT_
+select -assert-count 8 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCH_PP1_
+select -assert-count 3 sr1/t:$_DLATCH_PP1_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCH_PP1_ 1
+
+select -assert-count 8 sr0/t:$_NOT_
+select -assert-count 11 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCH_PP1_
+select -assert-count 3 sr1/t:$_DLATCH_PP1_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_DLATCH_PP1_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+
+# Convert everything to DLATCHSRs.
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 0
+
+select -assert-count 2 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCHSR_PPP_
+select -assert-count 3 sr1/t:$_DLATCHSR_PPP_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DLATCHSR_PPP_ 1
+
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 2 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DLATCHSR_PPP_
+select -assert-count 3 sr1/t:$_DLATCHSR_PPP_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_DLATCHSR_PPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSRs.
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 0
+
+select -assert-count 2 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DFFSR_PPP_
+select -assert-count 3 sr1/t:$_DFFSR_PPP_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_DFFSR_PPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSR_PPP_ 1
+
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 2 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DFFSR_PPP_
+select -assert-count 3 sr1/t:$_DFFSR_PPP_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_DFFSR_PPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+
+# Convert everything to DFFSREs.
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 0
+
+select -assert-count 2 sr0/t:$_NOT_
+select -assert-count 5 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DFFSRE_PPPP_
+select -assert-count 3 sr1/t:$_DFFSRE_PPPP_
+select -assert-count 0 sr0/t:$_ANDNOT_
+select -assert-count 1 sr1/t:$_ANDNOT_
+select -assert-count 0 sr0/t:$_AND_
+select -assert-count 1 sr1/t:$_AND_
+select -assert-count 0 sr0/t:$_OR_
+select -assert-count 1 sr1/t:$_OR_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
+
+design -load orig
+dfflegalize -cell $_DFFSRE_PPPP_ 1
+
+select -assert-count 5 sr0/t:$_NOT_
+select -assert-count 2 sr1/t:$_NOT_
+select -assert-count 3 sr0/t:$_DFFSRE_PPPP_
+select -assert-count 3 sr1/t:$_DFFSRE_PPPP_
+select -assert-count 1 sr0/t:$_ANDNOT_
+select -assert-count 0 sr1/t:$_ANDNOT_
+select -assert-count 1 sr0/t:$_AND_
+select -assert-count 0 sr1/t:$_AND_
+select -assert-count 1 sr0/t:$_OR_
+select -assert-count 0 sr1/t:$_OR_
+select -assert-none t:$_DFFSRE_PPPP_ t:$_NOT_ t:$_ANDNOT_ t:$_OR_ t:$_AND_ top/* %% %n t:* %i
diff --git a/tests/techmap/dfflibmap-sim.v b/tests/techmap/dfflibmap-sim.v
new file mode 100644
index 000000000..1788a683b
--- /dev/null
+++ b/tests/techmap/dfflibmap-sim.v
@@ -0,0 +1,22 @@
+module dffn(input CLK, D, output reg Q, output QN);
+
+always @(negedge CLK)
+ Q <= D;
+
+assign QN = ~Q;
+
+endmodule
+
+module dffsr(input CLK, D, CLEAR, PRESET, output reg Q, output QN);
+
+always @(posedge CLK, posedge CLEAR, posedge PRESET)
+ if (CLEAR)
+ Q <= 0;
+ else if (PRESET)
+ Q <= 1;
+ else
+ Q <= D;
+
+assign QN = ~Q;
+
+endmodule
diff --git a/tests/techmap/dfflibmap.lib b/tests/techmap/dfflibmap.lib
new file mode 100644
index 000000000..ce460877e
--- /dev/null
+++ b/tests/techmap/dfflibmap.lib
@@ -0,0 +1,55 @@
+library(test) {
+ /* D-type flip-flop with asynchronous reset and preset */
+ cell (dffn) {
+ area : 6;
+ ff("IQ", "IQN") {
+ next_state : "D";
+ clocked_on : "!CLK";
+ }
+ pin(D) {
+ direction : input;
+ }
+ pin(CLK) {
+ direction : input;
+ }
+ pin(Q) {
+ direction: output;
+ function : "IQ";
+ }
+ pin(QN) {
+ direction: output;
+ function : "IQN";
+ }
+ }
+ cell (dffsr) {
+ area : 6;
+ ff("IQ", "IQN") {
+ next_state : "D";
+ clocked_on : "CLK";
+ clear : "CLEAR";
+ preset : "PRESET";
+ clear_preset_var1 : L;
+ clear_preset_var2 : L;
+ }
+ pin(D) {
+ direction : input;
+ }
+ pin(CLK) {
+ direction : input;
+ }
+ pin(CLEAR) {
+ direction : input;
+ }
+ pin(PRESET) {
+ direction : input;
+ }
+ pin(Q) {
+ direction: output;
+ function : "IQ";
+ }
+ pin(QN) {
+ direction: output;
+ function : "IQN";
+ }
+ }
+}
diff --git a/tests/techmap/dfflibmap.ys b/tests/techmap/dfflibmap.ys
new file mode 100644
index 000000000..04477eb14
--- /dev/null
+++ b/tests/techmap/dfflibmap.ys
@@ -0,0 +1,58 @@
+read_verilog -icells <<EOT
+
+module top(input C, D, S, R, output [9:0] Q);
+
+$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
+$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
+$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));
+$_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3]));
+$_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(R), .S(S), .Q(Q[4]));
+
+assign Q[9:5] = ~Q[4:0];
+
+endmodule
+
+EOT
+
+simplemap
+
+design -save orig
+
+#equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -liberty dfflibmap.lib
+#equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -prepare -liberty dfflibmap.lib
+dfflibmap -prepare -liberty dfflibmap.lib
+equiv_opt -map dfflibmap-sim.v -assert -multiclock dfflibmap -map-only -liberty dfflibmap.lib
+
+design -load orig
+dfflibmap -liberty dfflibmap.lib
+clean
+
+select -assert-count 4 t:$_NOT_
+select -assert-count 1 t:dffn
+select -assert-count 4 t:dffsr
+select -assert-none t:dffn t:dffsr t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflibmap -prepare -liberty dfflibmap.lib
+
+select -assert-count 9 t:$_NOT_
+select -assert-count 1 t:$_DFF_N_
+select -assert-count 4 t:$_DFFSR_PPP_
+select -assert-none t:$_DFF_N_ t:$_DFFSR_PPP_ t:$_NOT_ %% %n t:* %i
+
+design -load orig
+dfflibmap -map-only -liberty dfflibmap.lib
+
+select -assert-count 5 t:$_NOT_
+select -assert-count 0 t:dffn
+select -assert-count 1 t:dffsr
+
+design -load orig
+dfflibmap -prepare -liberty dfflibmap.lib
+dfflibmap -map-only -liberty dfflibmap.lib
+clean
+
+select -assert-count 4 t:$_NOT_
+select -assert-count 1 t:dffn
+select -assert-count 4 t:dffsr
+select -assert-none t:dffn t:dffsr t:$_NOT_ %% %n t:* %i
diff --git a/tests/techmap/dffunmap.ys b/tests/techmap/dffunmap.ys
new file mode 100644
index 000000000..b813078ee
--- /dev/null
+++ b/tests/techmap/dffunmap.ys
@@ -0,0 +1,100 @@
+read_verilog -icells << EOT
+
+module top(...);
+
+input C, R, E, S;
+input [1:0] D;
+output [20:0] Q;
+
+$dff #(.CLK_POLARITY(1'b0), .WIDTH(2)) ff0 (.CLK(C), .D(D), .Q(Q[1:0]));
+$dffe #(.CLK_POLARITY(1'b0), .EN_POLARITY(1'b0), .WIDTH(2)) ff1 (.CLK(C), .EN(E), .D(D), .Q(Q[3:2]));
+$sdff #(.CLK_POLARITY(1'b0), .WIDTH(2), .SRST_POLARITY(1'b0), .SRST_VALUE(2'h2)) ff2 (.CLK(C), .SRST(R), .D(D), .Q(Q[5:4]));
+$sdffe #(.CLK_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(2), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2)) ff3 (.CLK(C), .EN(E), .SRST(R), .D(D), .Q(Q[7:6]));
+$sdffce #(.CLK_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(2), .SRST_POLARITY(1'b1), .SRST_VALUE(2'h2)) ff4 (.CLK(C), .EN(E), .SRST(R), .D(D), .Q(Q[9:8]));
+$adff #(.CLK_POLARITY(1'b0), .WIDTH(2), .ARST_POLARITY(1'b0), .ARST_VALUE(2'h2)) ff5 (.CLK(C), .ARST(R), .D(D), .Q(Q[11:10]));
+$adffe #(.CLK_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(2), .ARST_POLARITY(1'b1), .ARST_VALUE(2'h2)) ff6 (.CLK(C), .EN(E), .ARST(R), .D(D), .Q(Q[13:12]));
+$dffsr #(.CLK_POLARITY(1'b0), .WIDTH(2), .CLR_POLARITY(1'b0), .SET_POLARITY(1'b1)) ff7 (.CLK(C), .CLR({R, S}), .SET({S, R}), .D(D), .Q(Q[15:14]));
+$dffsre #(.CLK_POLARITY(1'b0), .EN_POLARITY(1'b1), .WIDTH(2), .CLR_POLARITY(1'b1), .SET_POLARITY(1'b0)) ff8 (.CLK(C), .EN(E), .CLR({R, R}), .SET({S, S}), .D(D), .Q(Q[17:16]));
+
+endmodule
+
+EOT
+
+design -save orig
+
+equiv_opt -assert -async2sync dffunmap
+design -load postopt
+select -assert-none t:$sdff t:$dffe t:$adffe t:$sdffe t:$sdffce t:$dffsre
+select -assert-count 5 t:$dff
+select -assert-count 2 t:$adff
+select -assert-count 2 t:$dffsr
+
+design -load orig
+
+equiv_opt -assert -async2sync dffunmap -ce-only
+design -load postopt
+select -assert-none t:$dffe t:$adffe t:$sdffe t:$sdffce t:$dffsre
+select -assert-count 3 t:$dff
+select -assert-count 2 t:$sdff
+select -assert-count 2 t:$adff
+select -assert-count 2 t:$dffsr
+
+design -load orig
+
+equiv_opt -assert -async2sync dffunmap -srst-only
+design -load postopt
+select -assert-none t:$sdff t:$sdffe t:$sdffce
+select -assert-count 3 t:$dff
+select -assert-count 2 t:$dffe
+select -assert-count 1 t:$adff
+select -assert-count 1 t:$adffe
+select -assert-count 1 t:$dffsr
+select -assert-count 1 t:$dffsre
+
+design -load orig
+simplemap
+
+equiv_opt -assert -async2sync dffunmap
+design -load postopt
+select -assert-none t:$_SDFF* t:$_DFFE_* t:$_DFFSRE_*
+select -assert-count 10 t:$_DFF_N_
+select -assert-count 1 t:$_DFF_NP0_
+select -assert-count 1 t:$_DFF_NN0_
+select -assert-count 1 t:$_DFF_NP1_
+select -assert-count 1 t:$_DFF_NN1_
+select -assert-count 2 t:$_DFFSR_NPN_
+select -assert-count 2 t:$_DFFSR_NNP_
+
+design -load orig
+simplemap
+
+equiv_opt -assert -async2sync dffunmap -ce-only
+design -load postopt
+select -assert-none t:$_SDFFE_* t:$_SDFFCE_* t:$_DFFE_* t:$_DFFSRE_*
+select -assert-count 6 t:$_DFF_N_
+select -assert-count 1 t:$_SDFF_NP0_
+select -assert-count 1 t:$_SDFF_NN0_
+select -assert-count 1 t:$_SDFF_NP1_
+select -assert-count 1 t:$_SDFF_NN1_
+select -assert-count 1 t:$_DFF_NP0_
+select -assert-count 1 t:$_DFF_NN0_
+select -assert-count 1 t:$_DFF_NP1_
+select -assert-count 1 t:$_DFF_NN1_
+select -assert-count 2 t:$_DFFSR_NPN_
+select -assert-count 2 t:$_DFFSR_NNP_
+
+design -load orig
+simplemap
+
+equiv_opt -assert -async2sync dffunmap -srst-only
+design -load postopt
+select -assert-none t:$sdff t:$sdffe t:$sdffce
+select -assert-count 6 t:$_DFF_N_
+select -assert-count 2 t:$_DFFE_NP_
+select -assert-count 2 t:$_DFFE_NN_
+select -assert-count 1 t:$_DFF_NN0_
+select -assert-count 1 t:$_DFF_NN1_
+select -assert-count 1 t:$_DFFE_NP0P_
+select -assert-count 1 t:$_DFFE_NP1P_
+select -assert-count 2 t:$_DFFSR_NPN_
+select -assert-count 2 t:$_DFFSRE_NNPP_
diff --git a/tests/techmap/mem_simple_4x1_runtest.sh b/tests/techmap/mem_simple_4x1_runtest.sh
index e2c6303da..9c41fa56a 100644
--- a/tests/techmap/mem_simple_4x1_runtest.sh
+++ b/tests/techmap/mem_simple_4x1_runtest.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-set -ev
+set -e
../../yosys -b 'verilog -noattr' -o mem_simple_4x1_synth.v -p 'proc; opt; memory -nomap; techmap -map mem_simple_4x1_map.v;; techmap; opt; abc;; stat' mem_simple_4x1_uut.v
diff --git a/tests/techmap/recursive_runtest.sh b/tests/techmap/recursive_runtest.sh
index 30c79bf03..0725ccf40 100644
--- a/tests/techmap/recursive_runtest.sh
+++ b/tests/techmap/recursive_runtest.sh
@@ -1,3 +1,3 @@
-set -ev
+set -e
../../yosys -p 'hierarchy -top top; techmap -map recursive_map.v -max_iter 1; select -assert-count 2 t:sub; select -assert-count 2 t:bar' recursive.v
diff --git a/tests/techmap/run-test.sh b/tests/techmap/run-test.sh
index c16f204d9..581847ab0 100755
--- a/tests/techmap/run-test.sh
+++ b/tests/techmap/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../yosys -ql ${x%.ys}.log -e 'select out of bounds' $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s > ${s%.sh}.log 2>&1"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash --yosys-args "-e 'select out of bounds'"
diff --git a/tests/techmap/shiftx2mux.ys b/tests/techmap/shiftx2mux.ys
index eb29680f6..f749e79b2 100644
--- a/tests/techmap/shiftx2mux.ys
+++ b/tests/techmap/shiftx2mux.ys
@@ -74,12 +74,6 @@ design -save gold
design -load gold
-techmap -D NO_LSB_FIRST_SHIFT_SHIFTX
-abc -lut 6
-select -assert-min 17 t:$lut
-
-
-design -load gold
techmap
abc -lut 6
select -assert-count 16 t:$lut
@@ -92,12 +86,6 @@ sat -verify -prove-asserts -show-ports miter
design -load gold
-techmap -D NO_LSB_FIRST_SHIFT_SHIFTX
-abc9 -lut 6
-select -assert-min 17 t:$lut
-
-
-design -load gold
techmap
abc9 -lut 6
select -assert-count 16 t:$lut
diff --git a/tests/techmap/zinit.ys b/tests/techmap/zinit.ys
index d0e41b4d2..1670573dd 100644
--- a/tests/techmap/zinit.ys
+++ b/tests/techmap/zinit.ys
@@ -61,32 +61,32 @@ design -reset
read_verilog -icells <<EOT
module top(input C, R, D, E, (* init = {24{1'b1}} *) output [23:0] Q);
-$__DFFE_NN0 dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
-$__DFFE_NN1 dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
-$__DFFE_NP0 dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
-$__DFFE_NP1 dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
-$__DFFE_PN0 dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
-$__DFFE_PN1 dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
-$__DFFE_PP0 dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
-$__DFFE_PP1 dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
-
-$__DFFS_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
-$__DFFS_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
-$__DFFS_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
-$__DFFS_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
-$__DFFS_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
-$__DFFS_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
-$__DFFS_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
-$__DFFS_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
-
-$__DFFSE_NN0 dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
-$__DFFSE_NN1 dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
-$__DFFSE_NP0 dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
-$__DFFSE_NP1 dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
-$__DFFSE_PN0 dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
-$__DFFSE_PN1 dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
-$__DFFSE_PP0 dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
-$__DFFSE_PP1 dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
+$_DFFE_NN0P_ dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
+$_DFFE_NN1P_ dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
+$_DFFE_NP0P_ dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
+$_DFFE_NP1P_ dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
+$_DFFE_PN0P_ dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
+$_DFFE_PN1P_ dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
+$_DFFE_PP0P_ dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
+$_DFFE_PP1P_ dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
+
+$_SDFF_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
+$_SDFF_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
+$_SDFF_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
+$_SDFF_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
+$_SDFF_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
+$_SDFF_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
+$_SDFF_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
+$_SDFF_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
+
+$_SDFFE_NN0P_ dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
+$_SDFFE_NN1P_ dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
+$_SDFFE_NP0P_ dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
+$_SDFFE_NP1P_ dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
+$_SDFFE_PN0P_ dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
+$_SDFFE_PN1P_ dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
+$_SDFFE_PP0P_ dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
+$_SDFFE_PP1P_ dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
endmodule
EOT
@@ -95,45 +95,45 @@ EOT
zinit
select -assert-count 48 t:$_NOT_
-select -assert-count 1 w:Q a:init=24'bx %i
-select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$__DFFE_??1 %i
-select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$__DFFE_??0 %i
-select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$__DFFS_??1_ %i
-select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$__DFFS_??0_ %i
-select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$__DFFSE_??1 %i
-select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$__DFFSE_??0 %i
+select -assert-count 0 w:Q a:init %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFFE_??1P_ %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFFE_??0P_ %i
+select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$_SDFF_??1_ %i
+select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$_SDFF_??0_ %i
+select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$_SDFFE_??1P_ %i
+select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$_SDFFE_??0P_ %i
design -reset
read_verilog -icells <<EOT
module top(input C, R, D, E, (* init = {24{1'b0}} *) output [23:0] Q);
-$__DFFE_NN0 dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
-$__DFFE_NN1 dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
-$__DFFE_NP0 dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
-$__DFFE_NP1 dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
-$__DFFE_PN0 dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
-$__DFFE_PN1 dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
-$__DFFE_PP0 dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
-$__DFFE_PP1 dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
-
-$__DFFS_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
-$__DFFS_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
-$__DFFS_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
-$__DFFS_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
-$__DFFS_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
-$__DFFS_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
-$__DFFS_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
-$__DFFS_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
-
-$__DFFSE_NN0 dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
-$__DFFSE_NN1 dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
-$__DFFSE_NP0 dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
-$__DFFSE_NP1 dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
-$__DFFSE_PN0 dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
-$__DFFSE_PN1 dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
-$__DFFSE_PP0 dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
-$__DFFSE_PP1 dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
+$_DFFE_NN0P_ dff0 (.C(C), .D(D), .E(E), .R(R), .Q(Q[0]));
+$_DFFE_NN1P_ dff1 (.C(C), .D(D), .E(E), .R(R), .Q(Q[1]));
+$_DFFE_NP0P_ dff2 (.C(C), .D(D), .E(E), .R(R), .Q(Q[2]));
+$_DFFE_NP1P_ dff3 (.C(C), .D(D), .E(E), .R(R), .Q(Q[3]));
+$_DFFE_PN0P_ dff4 (.C(C), .D(D), .E(E), .R(R), .Q(Q[4]));
+$_DFFE_PN1P_ dff5 (.C(C), .D(D), .E(E), .R(R), .Q(Q[5]));
+$_DFFE_PP0P_ dff6 (.C(C), .D(D), .E(E), .R(R), .Q(Q[6]));
+$_DFFE_PP1P_ dff7 (.C(C), .D(D), .E(E), .R(R), .Q(Q[7]));
+
+$_SDFF_NN0_ dff8 (.C(C), .D(D[0]), .R(R), .Q(Q[8]));
+$_SDFF_NN1_ dff9 (.C(C), .D(D[0]), .R(R), .Q(Q[9]));
+$_SDFF_NP0_ dff10(.C(C), .D(D[0]), .R(R), .Q(Q[10]));
+$_SDFF_NP1_ dff11(.C(C), .D(D[0]), .R(R), .Q(Q[11]));
+$_SDFF_PN0_ dff12(.C(C), .D(D[0]), .R(R), .Q(Q[12]));
+$_SDFF_PN1_ dff13(.C(C), .D(D[0]), .R(R), .Q(Q[13]));
+$_SDFF_PP0_ dff14(.C(C), .D(D[0]), .R(R), .Q(Q[14]));
+$_SDFF_PP1_ dff15(.C(C), .D(D[0]), .R(R), .Q(Q[15]));
+
+$_SDFFE_NN0P_ dff16(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[16]));
+$_SDFFE_NN1P_ dff17(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[17]));
+$_SDFFE_NP0P_ dff18(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[18]));
+$_SDFFE_NP1P_ dff19(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[19]));
+$_SDFFE_PN0P_ dff20(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[20]));
+$_SDFFE_PN1P_ dff21(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[21]));
+$_SDFFE_PP0P_ dff22(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[22]));
+$_SDFFE_PP1P_ dff23(.C(C), .D(D[0]),.E(E), .R(R), .Q(Q[23]));
endmodule
EOT
@@ -142,10 +142,10 @@ EOT
zinit
select -assert-count 0 t:$_NOT_
-select -assert-count 1 w:Q a:init=24'bx %i
-select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$__DFFE_??0 %i
-select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$__DFFE_??1 %i
-select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$__DFFS_??0_ %i
-select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$__DFFS_??1_ %i
-select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$__DFFSE_??0 %i
-select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$__DFFSE_??1 %i
+select -assert-count 0 w:Q a:init %i
+select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFFE_??0P_ %i
+select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFFE_??1P_ %i
+select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$_SDFF_??0_ %i
+select -assert-count 4 c:dff9 c:dff11 c:dff13 c:dff15 %% t:$_SDFF_??1_ %i
+select -assert-count 4 c:dff16 c:dff18 c:dff20 c:dff22 %% t:$_SDFFE_??0P_ %i
+select -assert-count 4 c:dff17 c:dff19 c:dff21 c:dff23 %% t:$_SDFFE_??1P_ %i
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index 4d3478628..72a3d51eb 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -193,13 +193,13 @@ do
elif [ "$frontend" = "verific_gates" ]; then
test_passes -p "verific -vlog2k ${bn}_ref.${refext}; verific -import -gates -all; opt; memory;;"
else
- test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.${refext}
+ test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt -nodffe -nosdff; fsm; opt; memory; opt -full -fine" ${bn}_ref.${refext}
test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.${refext}
if [ -n "$firrtl2verilog" ]; then
if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then
- "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.${refext}
+ "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt -nodffe -nosdff; fsm; opt; memory; opt -full -fine; pmuxtree" ${bn}_ref.${refext}
$firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v
- test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v
+ test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt -nodffe -nosdff; fsm; opt; memory; opt -full -fine" ${bn}_ref.fir.v
fi
fi
fi
diff --git a/tests/various/const_arg_loop.v b/tests/various/const_arg_loop.v
new file mode 100644
index 000000000..3bfff4acd
--- /dev/null
+++ b/tests/various/const_arg_loop.v
@@ -0,0 +1,64 @@
+module top;
+ function automatic [31:0] operation1;
+ input [4:0] rounds;
+ input integer num;
+ integer i;
+ begin
+ begin : shadow
+ integer rounds;
+ rounds = 0;
+ end
+ for (i = 0; i < rounds; i = i + 1)
+ num = num * 2;
+ operation1 = num;
+ end
+ endfunction
+
+ function automatic [31:0] operation2;
+ input [4:0] var;
+ input integer num;
+ begin
+ var[0] = var[0] ^ 1;
+ operation2 = num * var;
+ end
+ endfunction
+
+ function automatic [31:0] operation3;
+ input [4:0] rounds;
+ input integer num;
+ reg [4:0] rounds;
+ integer i;
+ begin
+ begin : shadow
+ integer rounds;
+ rounds = 0;
+ end
+ for (i = 0; i < rounds; i = i + 1)
+ num = num * 2;
+ operation3 = num;
+ end
+ endfunction
+
+ wire [31:0] a;
+ assign a = 2;
+
+ parameter A = 3;
+
+ wire [31:0] x1;
+ assign x1 = operation1(A, a);
+
+ wire [31:0] x2;
+ assign x2 = operation2(A, a);
+
+ wire [31:0] x3;
+ assign x3 = operation3(A, a);
+
+// `define VERIFY
+`ifdef VERIFY
+ assert property (a == 2);
+ assert property (A == 3);
+ assert property (x1 == 16);
+ assert property (x2 == 4);
+ assert property (x3 == 16);
+`endif
+endmodule
diff --git a/tests/various/const_arg_loop.ys b/tests/various/const_arg_loop.ys
new file mode 100644
index 000000000..b039bda10
--- /dev/null
+++ b/tests/various/const_arg_loop.ys
@@ -0,0 +1 @@
+read_verilog const_arg_loop.v
diff --git a/tests/various/const_func.v b/tests/various/const_func.v
new file mode 100644
index 000000000..541e63b19
--- /dev/null
+++ b/tests/various/const_func.v
@@ -0,0 +1,87 @@
+module Example(outA, outB, outC, outD);
+ parameter OUTPUT = "FOO";
+ output wire [23:0] outA;
+ output wire [23:0] outB;
+ output reg outC, outD;
+ function automatic [23:0] flip;
+ input [23:0] inp;
+ flip = ~inp;
+ endfunction
+
+ generate
+ if (flip(OUTPUT) == flip("BAR"))
+ assign outA = OUTPUT;
+ else
+ assign outA = 0;
+
+ case (flip(OUTPUT))
+ flip("FOO"): assign outB = OUTPUT;
+ flip("BAR"): assign outB = 0;
+ flip("BAZ"): assign outB = "HI";
+ endcase
+
+ genvar i;
+ initial outC = 0;
+ for (i = 0; i != flip(flip(OUTPUT[15:8])); i = i + 1)
+ if (i + 1 == flip(flip("O")))
+ initial outC = 1;
+ endgenerate
+
+ integer j;
+ initial begin
+ outD = 1;
+ for (j = 0; j != flip(flip(OUTPUT[15:8])); j = j + 1)
+ if (j + 1 == flip(flip("O")))
+ outD = 0;
+ end
+endmodule
+
+module top(out);
+ wire [23:0] a1, a2, a3, a4;
+ wire [23:0] b1, b2, b3, b4;
+ wire c1, c2, c3, c4;
+ wire d1, d2, d3, d4;
+ Example e1(a1, b1, c1, d1);
+ Example #("FOO") e2(a2, b2, c2, d2);
+ Example #("BAR") e3(a3, b3, c3, d3);
+ Example #("BAZ") e4(a4, b4, c4, d4);
+
+ output wire [24 * 8 - 1 + 4 :0] out;
+ assign out = {
+ a1, a2, a3, a4,
+ b1, b2, b3, b4,
+ c1, c2, c3, c4,
+ d1, d2, d3, d4};
+
+ function signed [31:0] negate;
+ input integer inp;
+ negate = ~inp;
+ endfunction
+ parameter W = 10;
+ parameter X = 3;
+ localparam signed Y = $floor(W / X);
+ localparam signed Z = negate($floor(W / X));
+
+// `define VERIFY
+`ifdef VERIFY
+ assert property (a1 == 0);
+ assert property (a2 == 0);
+ assert property (a3 == "BAR");
+ assert property (a4 == 0);
+ assert property (b1 == "FOO");
+ assert property (b2 == "FOO");
+ assert property (b3 == 0);
+ assert property (b4 == "HI");
+ assert property (c1 == 1);
+ assert property (c2 == 1);
+ assert property (c3 == 0);
+ assert property (c4 == 0);
+ assert property (d1 == 0);
+ assert property (d2 == 0);
+ assert property (d3 == 1);
+ assert property (d4 == 1);
+
+ assert property (Y == 3);
+ assert property (Z == ~3);
+`endif
+endmodule
diff --git a/tests/various/const_func.ys b/tests/various/const_func.ys
new file mode 100644
index 000000000..5e3c04105
--- /dev/null
+++ b/tests/various/const_func.ys
@@ -0,0 +1 @@
+read_verilog const_func.v
diff --git a/tests/various/const_func_block_var.v b/tests/various/const_func_block_var.v
new file mode 100644
index 000000000..cb60844ab
--- /dev/null
+++ b/tests/various/const_func_block_var.v
@@ -0,0 +1,26 @@
+module top(out);
+ function integer operation;
+ input integer num;
+ localparam incr = 1;
+ localparam mult = 1;
+ begin
+ operation = 0;
+ begin : op_i
+ integer i;
+ for (i = 0; i * mult < 2; i = i + incr)
+ begin : op_j
+ integer j;
+ localparam other_mult = 2;
+ for (j = i; j < i * other_mult; j = j + incr)
+ num = num + incr;
+ end
+ num = num * 2;
+ end
+ operation = num;
+ end
+ endfunction
+
+ localparam res = operation(4);
+ output wire [31:0] out;
+ assign out = res;
+endmodule
diff --git a/tests/various/const_func_block_var.ys b/tests/various/const_func_block_var.ys
new file mode 100644
index 000000000..7c2e85c64
--- /dev/null
+++ b/tests/various/const_func_block_var.ys
@@ -0,0 +1 @@
+read_verilog const_func_block_var.v
diff --git a/tests/various/equiv_opt_undef.ys b/tests/various/equiv_opt_undef.ys
new file mode 100644
index 000000000..5d2c60d0a
--- /dev/null
+++ b/tests/various/equiv_opt_undef.ys
@@ -0,0 +1,35 @@
+read_ilang << EOT
+
+module \top
+ wire $a
+ wire $b
+ wire input 1 \D
+ wire input 2 \EN
+ wire output 3 \Q
+ cell $mux $x
+ parameter \WIDTH 1
+ connect \A \Q
+ connect \B \D
+ connect \S \EN
+ connect \Y $a
+ end
+ cell $ff $y
+ parameter \WIDTH 1
+ connect \D $a
+ connect \Q $b
+ end
+ cell $and $z
+ parameter \A_SIGNED 0
+ parameter \A_WIDTH 1
+ parameter \B_SIGNED 0
+ parameter \B_WIDTH 1
+ parameter \Y_WIDTH 1
+ connect \A $b
+ connect \B 1'x
+ connect \Y \Q
+ end
+end
+
+EOT
+
+equiv_opt -assert -undef ls
diff --git a/tests/various/integer_range_bad_syntax.ys b/tests/various/integer_range_bad_syntax.ys
new file mode 100644
index 000000000..4f427211f
--- /dev/null
+++ b/tests/various/integer_range_bad_syntax.ys
@@ -0,0 +1,6 @@
+logger -expect error "syntax error, unexpected" 1
+read_verilog -sv <<EOT
+module test_integer_range();
+parameter integer [31:0] a = 0;
+endmodule
+EOT
diff --git a/tests/various/integer_real_bad_syntax.ys b/tests/various/integer_real_bad_syntax.ys
new file mode 100644
index 000000000..942d8de77
--- /dev/null
+++ b/tests/various/integer_real_bad_syntax.ys
@@ -0,0 +1,6 @@
+logger -expect error "syntax error, unexpected TOK_REAL" 1
+read_verilog -sv <<EOT
+module test_integer_real();
+parameter integer real a = 0;
+endmodule
+EOT
diff --git a/tests/various/logic_param_simple.ys b/tests/various/logic_param_simple.ys
new file mode 100644
index 000000000..968564080
--- /dev/null
+++ b/tests/various/logic_param_simple.ys
@@ -0,0 +1,9 @@
+read_verilog -sv <<EOT
+module test_logic_param();
+parameter logic a = 0;
+parameter logic [31:0] e = 0;
+parameter logic signed b = 0;
+parameter logic unsigned c = 0;
+parameter logic unsigned [31:0] d = 0;
+endmodule
+EOT
diff --git a/tests/various/peepopt.ys b/tests/various/peepopt.ys
index ee5ad8a1a..45e936a21 100644
--- a/tests/various/peepopt.ys
+++ b/tests/various/peepopt.ys
@@ -68,146 +68,3 @@ equiv_opt -assert peepopt
design -load postopt
clean
select -assert-count 0 t:*
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o);
- always @(posedge clk) if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-clean
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o);
- always @(posedge clk) if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-clean
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-###################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o);
- always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 1 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-###################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o);
- always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz};
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-select -assert-count 1 t:$dff r:WIDTH=4 %i
-select -assert-count 1 t:$mux r:WIDTH=4 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o);
- always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i;
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-wreduce
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
- always @(posedge clk) begin
- if (ce) o <= i;
- if (!rstn) o <= 4'b1111;
- end
-endmodule
-EOT
-
-proc
-equiv_opt -assert peepopt
-design -load postopt
-wreduce
-select -assert-count 1 t:$dff r:WIDTH=2 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=2 %i
-select -assert-count 0 t:$logic_not t:$dff t:$mux %% t:* %D
-
-####################
-
-design -reset
-read_verilog <<EOT
-module peepopt_dffmuxext_signed_rst_init(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o);
- initial o <= 4'b0010;
- always @(posedge clk) begin
- if (ce) o <= i;
- if (!rstn) o <= 4'b1111;
- end
-endmodule
-EOT
-
-proc
-# NB: equiv_opt uses equiv_induct which covers
-# only the induction half of temporal induction
-# --- missing the base-case half
-# This makes it akin to `sat -tempinduct-inductonly`
-# instead of `sat -tempinduct-baseonly` or
-# `sat -tempinduct` which is necessary for this
-# testcase
-#equiv_opt -assert peepopt
-
-design -save gold
-peepopt
-wreduce
-design -stash gate
-design -import gold -as gold
-design -import gate -as gate
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -tempinduct -verify -prove-asserts -show-ports miter
-
-design -load gate
-select -assert-count 1 t:$dff r:WIDTH=4 %i
-select -assert-count 2 t:$mux
-select -assert-count 2 t:$mux r:WIDTH=4 %i
-select -assert-count 0 t:$logic_not t:$dff t:$mux %% t:* %D
diff --git a/tests/various/plugin.cc b/tests/various/plugin.cc
index be305fbda..451484c50 100644
--- a/tests/various/plugin.cc
+++ b/tests/various/plugin.cc
@@ -4,7 +4,7 @@ YOSYS_NAMESPACE_BEGIN
struct TestPass : public Pass {
TestPass() : Pass("test", "test") { }
- void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
size_t argidx = 1;
extra_args(args, argidx, design);
diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh
index ea56b70f0..2f91cf0fd 100755
--- a/tests/various/run-test.sh
+++ b/tests/various/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../yosys -ql ${x%.ys}.log $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash
diff --git a/tests/various/signed.ys b/tests/various/signed.ys
new file mode 100644
index 000000000..2319a5da1
--- /dev/null
+++ b/tests/various/signed.ys
@@ -0,0 +1,28 @@
+# SV LRM A2.2.1
+
+read_verilog -sv <<EOT
+module test_signed();
+parameter integer signed a = 0;
+parameter integer unsigned b = 0;
+
+endmodule
+EOT
+
+design -reset
+read_verilog -sv <<EOT
+module test_signed();
+parameter logic signed [7:0] a = 0;
+parameter logic unsigned [7:0] b = 0;
+
+endmodule
+EOT
+
+design -reset
+logger -expect error "syntax error, unexpected TOK_INTEGER" 1
+read_verilog -sv <<EOT
+module test_signed();
+parameter signed integer a = 0;
+parameter unsigned integer b = 0;
+
+endmodule
+EOT
diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore
index b48f808a1..34da23437 100644
--- a/tests/verilog/.gitignore
+++ b/tests/verilog/.gitignore
@@ -1,3 +1,5 @@
/*.log
/*.out
/run-test.mk
+/const_arst.v
+/const_sr.v
diff --git a/tests/verilog/const_arst.ys b/tests/verilog/const_arst.ys
new file mode 100644
index 000000000..df720575c
--- /dev/null
+++ b/tests/verilog/const_arst.ys
@@ -0,0 +1,24 @@
+read_verilog <<EOT
+module test (
+ input clk, d,
+ output reg q
+);
+wire nop = 1'h0;
+always @(posedge clk, posedge nop) begin
+ if (nop) q <= 1'b0;
+ else q <= d;
+end
+endmodule
+EOT
+prep -top test
+write_verilog const_arst.v
+design -stash gold
+read_verilog const_arst.v
+prep -top test
+design -stash gate
+design -copy-from gold -as gold A:top
+design -copy-from gate -as gate A:top
+miter -equiv -flatten -make_assert gold gate miter
+prep -top miter
+clk2fflogic
+sat -set-init-zero -tempinduct -prove-asserts -verify
diff --git a/tests/verilog/const_sr.ys b/tests/verilog/const_sr.ys
new file mode 100644
index 000000000..c1406b0a0
--- /dev/null
+++ b/tests/verilog/const_sr.ys
@@ -0,0 +1,25 @@
+read_verilog <<EOT
+module test (
+ input clk, rst, d,
+ output reg q
+);
+wire nop = 1'h0;
+always @(posedge clk, posedge nop, posedge rst) begin
+ if (rst) q <= 1'b0;
+ else if (nop) q <= 1'b1;
+ else q <= d;
+end
+endmodule
+EOT
+prep -top test
+write_verilog const_sr.v
+design -stash gold
+read_verilog const_sr.v
+prep -top test
+design -stash gate
+design -copy-from gold -as gold A:top
+design -copy-from gate -as gate A:top
+miter -equiv -flatten -make_assert gold gate miter
+prep -top miter
+clk2fflogic
+sat -set-init-zero -tempinduct -prove-asserts -verify
diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh
index ea56b70f0..2f91cf0fd 100755
--- a/tests/verilog/run-test.sh
+++ b/tests/verilog/run-test.sh
@@ -1,20 +1,4 @@
#!/usr/bin/env bash
-set -e
-{
-echo "all::"
-for x in *.ys; do
- echo "all:: run-$x"
- echo "run-$x:"
- echo " @echo 'Running $x..'"
- echo " @../../yosys -ql ${x%.ys}.log $x"
-done
-for s in *.sh; do
- if [ "$s" != "run-test.sh" ]; then
- echo "all:: run-$s"
- echo "run-$s:"
- echo " @echo 'Running $s..'"
- echo " @bash $s"
- fi
-done
-} > run-test.mk
-exec ${MAKE:-make} -f run-test.mk
+set -eu
+source ../gen-tests-makefile.sh
+run_tests --yosys-scripts --bash