From 3948e7f94c95709905f6edaab6a6c7235dc4152b Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 3 Jun 2026 12:46:26 +0200 Subject: [PATCH 1/2] Use Nexus DSP pipelined registers. --- techlibs/lattice/dsp_map_nexus.v | 53 +++++-- techlibs/lattice/lattice_dsp_nexus.cc | 5 +- techlibs/lattice/lattice_dsp_nexus.pmg | 207 ++++++++++++++++++++++++- tests/arch/nexus/pipe_mul.sv | 156 +++++++++++++++++++ tests/arch/nexus/pipe_mul.ys | 73 +++++++++ 5 files changed, 479 insertions(+), 15 deletions(-) create mode 100644 tests/arch/nexus/pipe_mul.sv create mode 100644 tests/arch/nexus/pipe_mul.ys diff --git a/techlibs/lattice/dsp_map_nexus.v b/techlibs/lattice/dsp_map_nexus.v index 61d2d96a8..73aec9cef 100644 --- a/techlibs/lattice/dsp_map_nexus.v +++ b/techlibs/lattice/dsp_map_nexus.v @@ -1,57 +1,84 @@ -module \$__NX_MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y); +module \$__NX_MUL36X36 (input [35:0] A, input [35:0] B, input CLK, input CEA, RSTA, CEB, RSTB, CEOUT, RSTOUT, output [71:0] Y); parameter A_WIDTH = 36; parameter B_WIDTH = 36; parameter Y_WIDTH = 72; parameter A_SIGNED = 0; parameter B_SIGNED = 0; + parameter REGINPUTA = "BYPASS"; + parameter REGINPUTB = "BYPASS"; + parameter REGOUTPUT = "BYPASS"; + parameter RESETMODE = "SYNC"; MULT36X36 #( - .REGINPUTA("BYPASS"), - .REGINPUTB("BYPASS"), - .REGOUTPUT("BYPASS") + .REGINPUTA(REGINPUTA), + .REGINPUTB(REGINPUTB), + .REGOUTPUT(REGOUTPUT), + .RESETMODE(RESETMODE) ) _TECHMAP_REPLACE_ ( .A(A), .B(B), + .CLK(CLK), + .CEA(CEA), .RSTA(RSTA), + .CEB(CEB), .RSTB(RSTB), + .CEOUT(CEOUT), .RSTOUT(RSTOUT), .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .Z(Y) ); endmodule -module \$__NX_MUL36X18 (input [35:0] A, input [17:0] B, output [53:0] Y); +module \$__NX_MUL36X18 (input [35:0] A, input [17:0] B, input CLK, input CEA, RSTA, CEB, RSTB, CEOUT, RSTOUT, output [53:0] Y); parameter A_WIDTH = 36; parameter B_WIDTH = 18; parameter Y_WIDTH = 54; parameter A_SIGNED = 0; parameter B_SIGNED = 0; + parameter REGINPUTA = "BYPASS"; + parameter REGINPUTB = "BYPASS"; + parameter REGOUTPUT = "BYPASS"; + parameter RESETMODE = "SYNC"; MULT18X36 #( - .REGINPUTA("BYPASS"), - .REGINPUTB("BYPASS"), - .REGOUTPUT("BYPASS") + .REGINPUTA(REGINPUTB), + .REGINPUTB(REGINPUTA), + .REGOUTPUT(REGOUTPUT), + .RESETMODE(RESETMODE) ) _TECHMAP_REPLACE_ ( .A(B), .B(A), + .CLK(CLK), + .CEA(CEB), .RSTA(RSTB), + .CEB(CEA), .RSTB(RSTA), + .CEOUT(CEOUT), .RSTOUT(RSTOUT), .SIGNEDA(B_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(A_SIGNED ? 1'b1 : 1'b0), .Z(Y) ); endmodule -module \$__NX_MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); +module \$__NX_MUL18X18 (input [17:0] A, input [17:0] B, input CLK, input CEA, RSTA, CEB, RSTB, CEOUT, RSTOUT, output [35:0] Y); parameter A_WIDTH = 18; parameter B_WIDTH = 18; parameter Y_WIDTH = 36; parameter A_SIGNED = 0; parameter B_SIGNED = 0; + parameter REGINPUTA = "BYPASS"; + parameter REGINPUTB = "BYPASS"; + parameter REGOUTPUT = "BYPASS"; + parameter RESETMODE = "SYNC"; MULT18X18 #( - .REGINPUTA("BYPASS"), - .REGINPUTB("BYPASS"), - .REGOUTPUT("BYPASS") + .REGINPUTA(REGINPUTA), + .REGINPUTB(REGINPUTB), + .REGOUTPUT(REGOUTPUT), + .RESETMODE(RESETMODE) ) _TECHMAP_REPLACE_ ( .A(A), .B(B), + .CLK(CLK), + .CEA(CEA), .RSTA(RSTA), + .CEB(CEB), .RSTB(RSTB), + .CEOUT(CEOUT), .RSTOUT(RSTOUT), .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .Z(Y) @@ -148,4 +175,4 @@ module \$__NX_MAC9X9WIDE_4LANE (input [8:0] A0, B0, A1, B1, A2, B2, A3, B3, outp .ADDSUB(4'b0000), .Z(Y) ); -endmodule +endmodule \ No newline at end of file diff --git a/techlibs/lattice/lattice_dsp_nexus.cc b/techlibs/lattice/lattice_dsp_nexus.cc index d072c552d..b0aaa5f17 100644 --- a/techlibs/lattice/lattice_dsp_nexus.cc +++ b/techlibs/lattice/lattice_dsp_nexus.cc @@ -15,7 +15,9 @@ struct LatticeDspNexusPass : public Pass { log(" lattice_dsp_nexus [options] [selection]\n"); log("\n"); log("Infer Lattice Nexus sysDSP macrocells (MULTADDSUB18X18, MULTPREADD18X18,\n"); - log("MULTADDSUB9X9WIDE) from MAC and dot-product patterns.\n"); + log("MULTADDSUB9X9WIDE) from MAC and dot-product patterns, and absorb the\n"); + log("pipeline flip-flops around bare MULT18X18 / MULT36X36 multipliers into\n"); + log("the hardened DSP input and output registers.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -29,6 +31,7 @@ struct LatticeDspNexusPass : public Pass { pm.run_nexus_mac9_4lane(); pm.run_nexus_mac18(); pm.run_nexus_preadd18(); + pm.run_nexus_mul_reg(); } } } LatticeDspNexusPass; diff --git a/techlibs/lattice/lattice_dsp_nexus.pmg b/techlibs/lattice/lattice_dsp_nexus.pmg index 5fb828bb9..45084ff1e 100644 --- a/techlibs/lattice/lattice_dsp_nexus.pmg +++ b/techlibs/lattice/lattice_dsp_nexus.pmg @@ -205,4 +205,209 @@ code } accept; -endcode \ No newline at end of file +endcode + +pattern nexus_mul_reg + +match mul + select mul->type.in($mul) + select GetSize(port(mul, \A)) <= 36 + select GetSize(port(mul, \B)) <= 36 + select GetSize(port(mul, \Y)) <= 72 +endmatch + +match ffA + select ffA->type.in($dff, $dffe, $sdff, $sdffe) + select param(ffA, \CLK_POLARITY).as_bool() + filter ffA->type.in($dff, $dffe) || param(ffA, \SRST_VALUE).is_fully_zero() + filter GetSize(port(ffA, \Q)) == GetSize(port(mul, \A)) + index port(ffA, \Q) === port(mul, \A) + optional +endmatch + +match ffB + select ffB->type.in($dff, $dffe, $sdff, $sdffe) + select param(ffB, \CLK_POLARITY).as_bool() + filter ffB->type.in($dff, $dffe) || param(ffB, \SRST_VALUE).is_fully_zero() + filter GetSize(port(ffB, \Q)) == GetSize(port(mul, \B)) + index port(ffB, \Q) === port(mul, \B) + optional +endmatch + +match ffY + select ffY->type.in($dff, $dffe, $sdff, $sdffe) + select param(ffY, \CLK_POLARITY).as_bool() + filter ffY->type.in($dff, $dffe) || param(ffY, \SRST_VALUE).is_fully_zero() + filter GetSize(port(ffY, \D)) == GetSize(port(mul, \Y)) + index port(ffY, \D) === port(mul, \Y) + optional +endmatch + +code + Cell *fa = ffA; + Cell *fb = ffB; + Cell *fy = ffY; + + if (!fa && !fb && !fy) + reject; + + { + // Drop any FF whose Q carries a non-zero power-up value, since the DSP reg powers up at 0 + auto bad_init = [&](Cell *ff) -> bool { + SigSpec q = port(ff, \Q); + + for (auto bit : sigmap(q)) { + if (!bit.wire) + continue; + + auto it = bit.wire->attributes.find(\init); + if (it == bit.wire->attributes.end()) + continue; + + Const init = it->second; + int off = bit.offset; + + if (off < GetSize(init)) { + State s = init[off]; + if (s != State::Sx && s != State::S0) + return true; + } + } + + return false; + }; + + if (fa && bad_init(fa)) fa = nullptr; + if (fb && bad_init(fb)) fb = nullptr; + if (fy && bad_init(fy)) fy = nullptr; + + // All absorbed FFs must share one clock domain + SigBit clk; + bool have_clk = false; + + { + Cell *ffs[3] = { fa, fb, fy }; + for (Cell *ff : ffs) { + if (!ff) continue; + + SigBit c = sigmap(port(ff, \CLK)[0]); + + if (!have_clk) { + clk = c; + have_clk = true; + continue; + } + + if (c != clk) { + if (ff == fa) fa = nullptr; + else if (ff == fb) fb = nullptr; + else fy = nullptr; + } + } + } + + // If every candidate was filtered out, don't build a DSP reg cell + if (fa || fb || fy) { + int aw = GetSize(port(mul, \A)); + int bw = GetSize(port(mul, \B)); + IdString prim; + int A_PINS; + int B_PINS; + + if (aw <= 18 && bw <= 18) { + prim = "$__NX_MUL18X18"; + A_PINS = 18; + B_PINS = 18; + } else if (aw <= 36 && bw <= 18) { + prim = "$__NX_MUL36X18"; + A_PINS = 36; + B_PINS = 18; + } else if (aw <= 18 && bw <= 36) { + prim = "$__NX_MUL36X18"; + A_PINS = 36; + B_PINS = 18; + } else { + prim = "$__NX_MUL36X36"; + A_PINS = 36; + B_PINS = 36; + } + + bool a_signed = mul->getParam(\A_SIGNED).as_bool(); + bool b_signed = mul->getParam(\B_SIGNED).as_bool(); + SigSpec sigA = port(mul, \A); + SigSpec sigB = port(mul, \B); + SigSpec sigY = fy ? port(fy, \Q) : port(mul, \Y); + + // 36X18 -> wide operand goes to A + Cell *ffA_use = fa; + Cell *ffB_use = fb; + if (prim == "$__NX_MUL36X18" && aw <= 18 && bw <= 36) { + std::swap(sigA, sigB); + std::swap(a_signed, b_signed); + std::swap(ffA_use, ffB_use); + } + + sigA.extend_u0(A_PINS, a_signed); + sigB.extend_u0(B_PINS, b_signed); + + Cell *cell = module->addCell(NEW_ID, prim); + cell->setPort(\A, sigA); + cell->setPort(\B, sigB); + cell->setPort(\Y, sigY); + cell->setParam(\A_WIDTH, A_PINS); + cell->setParam(\B_WIDTH, B_PINS); + cell->setParam(\Y_WIDTH, GetSize(sigY)); + cell->setParam(\A_SIGNED, a_signed ? State::S1 : State::S0); + cell->setParam(\B_SIGNED, b_signed ? State::S1 : State::S0); + cell->setParam(\RESETMODE, std::string("SYNC")); + + auto ce_of = [&](Cell *ff) -> SigBit { + if (!ff) return State::S0; + + if (ff->type.in($dffe, $sdffe)) { + SigBit e = port(ff, \EN)[0]; + if (!ff->getParam(\EN_POLARITY).as_bool()) + e = module->NotGate(NEW_ID, e); + + return e; + } + + return State::S1; // Always enabled + }; + + auto rst_of = [&](Cell *ff) -> SigBit { + if (!ff) return State::S0; + + if (ff->type.in($sdff, $sdffe)) { + SigBit r = port(ff, \SRST)[0]; + if (!ff->getParam(\SRST_POLARITY).as_bool()) + r = module->NotGate(NEW_ID, r); + + return r; + } + + return State::S0; // No reset + }; + + cell->setPort(\CLK, have_clk ? clk : State::S0); + cell->setPort(\CEA, ce_of(ffA_use)); + cell->setPort(\RSTA, rst_of(ffA_use)); + cell->setPort(\CEB, ce_of(ffB_use)); + cell->setPort(\RSTB, rst_of(ffB_use)); + cell->setPort(\CEOUT, ce_of(fy)); + cell->setPort(\RSTOUT, rst_of(fy)); + cell->setParam(\REGINPUTA, ffA_use ? std::string("REGISTER") : std::string("BYPASS")); + cell->setParam(\REGINPUTB, ffB_use ? std::string("REGISTER") : std::string("BYPASS")); + cell->setParam(\REGOUTPUT, fy ? std::string("REGISTER") : std::string("BYPASS")); + + if (ffA_use) autoremove(ffA_use); + if (ffB_use && ffB_use != ffA_use) autoremove(ffB_use); + if (fy) autoremove(fy); + autoremove(mul); + + accept; + } + } + + reject; +endcode diff --git a/tests/arch/nexus/pipe_mul.sv b/tests/arch/nexus/pipe_mul.sv new file mode 100644 index 000000000..75769a29c --- /dev/null +++ b/tests/arch/nexus/pipe_mul.sv @@ -0,0 +1,156 @@ +// https://github.com/YosysHQ/yosys/issues/5917 + +module mul18_pipe( + input logic clk, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(posedge clk) begin + a_r <= a; + b_r <= b; + y <= a_r * b_r; + end +endmodule + +module mul18_pipe_signed ( + input logic clk, + input logic signed [17:0] a, + input logic signed [17:0] b, + output logic signed [35:0] y +); + logic signed [17:0] a_r; + logic signed [17:0] b_r; + + always_ff @(posedge clk) begin + a_r <= a; + b_r <= b; + y <= a_r * b_r; + end +endmodule + + +module mul18_pipe_in_only ( + input logic clk, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(posedge clk) begin + a_r <= a; + b_r <= b; + end + + assign y = a_r * b_r; +endmodule + +module mul18_pipe_out_only ( + input logic clk, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + always_ff @(posedge clk) + y <= a * b; +endmodule + +module mul18_pipe_io_rst ( + input logic clk, + input logic rst, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(posedge clk) + if (rst) begin a_r <= 0; b_r <= 0; y <= 0; end + else begin a_r <= a; b_r <= b; y <= a_r * b_r; end +endmodule + +module mul24_io ( + input logic clk, + input logic [23:0] a, + input logic [23:0] b, + output logic [47:0] y +); + logic [23:0] a_r; + logic [23:0] b_r; + + always_ff @(posedge clk) begin + a_r <= a; + b_r <= b; + y <= a_r * b_r; + end +endmodule + +module mul32_io ( + input logic clk, + input logic [31:0] a, + input logic [31:0] b, + output logic [63:0] y +); + logic [31:0] a_r; + logic [31:0] b_r; + + always_ff @(posedge clk) begin + a_r <= a; + b_r <= b; + y <= a_r * b_r; + end +endmodule + +module mul18_negedge ( + input logic clk, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(negedge clk) begin + a_r <= a; + b_r <= b; + y <= a_r * b_r; + end +endmodule + +module mul18_rst_nonzero ( + input logic clk, + input logic rst, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(posedge clk) + if (rst) begin a_r <= 18'h3; b_r <= 18'h7; end + else begin a_r <= a; b_r <= b; end + always_ff @(posedge clk) + y <= a_r * b_r; +endmodule + +module mul18_two_clock ( + input logic clk0, + input logic clk1, + input logic [17:0] a, + input logic [17:0] b, + output logic [35:0] y +); + logic [17:0] a_r; + logic [17:0] b_r; + + always_ff @(posedge clk0) a_r <= a; + always_ff @(posedge clk1) b_r <= b; + assign y = a_r * b_r; +endmodule \ No newline at end of file diff --git a/tests/arch/nexus/pipe_mul.ys b/tests/arch/nexus/pipe_mul.ys new file mode 100644 index 000000000..d2c5a6282 --- /dev/null +++ b/tests/arch/nexus/pipe_mul.ys @@ -0,0 +1,73 @@ +read_verilog -sv pipe_mul.sv + +design -save pristine + +# 18x18 MULT +design -load pristine +hierarchy -top mul18_pipe +synth_nexus -family lifcl -top mul18_pipe +select -assert-count 1 t:MULT18X18 +select -assert-count 0 t:FD1P3* + +# 18x18 MULT (signed) +design -load pristine +hierarchy -top mul18_pipe_signed +synth_nexus -family lifcl -top mul18_pipe_signed +select -assert-count 1 t:MULT18X18 +select -assert-count 0 t:FD1P3* + +# 18x18 MULT (input only) +design -load pristine +hierarchy -top mul18_pipe_in_only +synth_nexus -family lifcl -top mul18_pipe_in_only +select -assert-count 1 t:MULT18X18 +select -assert-count 0 t:FD1P3* + +# 18x18 MULT (output only) +design -load pristine +hierarchy -top mul18_pipe_out_only +synth_nexus -family lifcl -top mul18_pipe_out_only +select -assert-count 1 t:MULT18X18 +select -assert-count 0 t:FD1P3* + +# 18x18 MULT (reset) +design -load pristine +hierarchy -top mul18_pipe_io_rst +synth_nexus -family lifcl -top mul18_pipe_io_rst +select -assert-count 1 t:MULT18X18 +select -assert-count 0 t:FD1P3* + +# 24x24 MUL -> pipelined 36X36 MULT +design -load pristine +hierarchy -top mul24_io +synth_nexus -family lifcl -top mul24_io +select -assert-count 1 t:MULT36X36 +select -assert-count 0 t:FD1P3* + +# 32x32 MUL -> pipelined 36X36 MULT +design -load pristine +hierarchy -top mul32_io +synth_nexus -family lifcl -top mul32_io +select -assert-count 1 t:MULT36X36 +select -assert-count 0 t:FD1P3* + +# DSP reg is rising-edge +design -load pristine +hierarchy -top mul18_negedge +synth_nexus -family lifcl -top mul18_negedge +select -assert-count 1 t:MULT18X18 +select -assert-min 1 t:FD1P3* + +# DSP reg only resets to 0 +design -load pristine +hierarchy -top mul18_rst_nonzero +synth_nexus -family lifcl -top mul18_rst_nonzero +select -assert-count 1 t:MULT18X18 +select -assert-min 1 t:FD1P3* + +# two clocks feeding input regs -> can't share one CLK pin +design -load pristine +hierarchy -top mul18_two_clock +synth_nexus -family lifcl -top mul18_two_clock +select -assert-count 1 t:MULT18X18 +select -assert-min 1 t:FD1P3* From 5328762fe584df10c9434e121f11e271f0730a38 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 3 Jun 2026 12:51:57 +0200 Subject: [PATCH 2/2] Add regtype checks to tests. --- tests/arch/nexus/pipe_mul.ys | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/arch/nexus/pipe_mul.ys b/tests/arch/nexus/pipe_mul.ys index d2c5a6282..c5e40b96e 100644 --- a/tests/arch/nexus/pipe_mul.ys +++ b/tests/arch/nexus/pipe_mul.ys @@ -6,68 +6,69 @@ design -save pristine design -load pristine hierarchy -top mul18_pipe synth_nexus -family lifcl -top mul18_pipe -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* # 18x18 MULT (signed) design -load pristine hierarchy -top mul18_pipe_signed synth_nexus -family lifcl -top mul18_pipe_signed -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* # 18x18 MULT (input only) design -load pristine hierarchy -top mul18_pipe_in_only synth_nexus -family lifcl -top mul18_pipe_in_only -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=BYPASS select -assert-count 0 t:FD1P3* # 18x18 MULT (output only) design -load pristine hierarchy -top mul18_pipe_out_only synth_nexus -family lifcl -top mul18_pipe_out_only -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=BYPASS r:REGINPUTB=BYPASS r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* # 18x18 MULT (reset) design -load pristine hierarchy -top mul18_pipe_io_rst synth_nexus -family lifcl -top mul18_pipe_io_rst -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* # 24x24 MUL -> pipelined 36X36 MULT design -load pristine hierarchy -top mul24_io synth_nexus -family lifcl -top mul24_io -select -assert-count 1 t:MULT36X36 +select -assert-count 1 t:MULT36X36 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* # 32x32 MUL -> pipelined 36X36 MULT design -load pristine hierarchy -top mul32_io synth_nexus -family lifcl -top mul32_io -select -assert-count 1 t:MULT36X36 +select -assert-count 1 t:MULT36X36 r:REGINPUTA=REGISTER r:REGINPUTB=REGISTER r:REGOUTPUT=REGISTER select -assert-count 0 t:FD1P3* +# reject # DSP reg is rising-edge design -load pristine hierarchy -top mul18_negedge synth_nexus -family lifcl -top mul18_negedge -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=BYPASS r:REGINPUTB=BYPASS r:REGOUTPUT=BYPASS select -assert-min 1 t:FD1P3* # DSP reg only resets to 0 design -load pristine hierarchy -top mul18_rst_nonzero synth_nexus -family lifcl -top mul18_rst_nonzero -select -assert-count 1 t:MULT18X18 +select -assert-count 1 t:MULT18X18 r:REGINPUTA=BYPASS r:REGINPUTB=BYPASS r:REGOUTPUT=BYPASS select -assert-min 1 t:FD1P3* # two clocks feeding input regs -> can't share one CLK pin design -load pristine hierarchy -top mul18_two_clock synth_nexus -family lifcl -top mul18_two_clock -select -assert-count 1 t:MULT18X18 -select -assert-min 1 t:FD1P3* +select -assert-count 1 t:MULT18X18 r:REGINPUTA=BYPASS r:REGINPUTB=BYPASS +select -assert-min 1 t:FD1P3* \ No newline at end of file