From fec8b3c81ffcf1f8a27e79250c05b6ea91571bbe Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 18 Dec 2018 15:37:43 +0800 Subject: [PATCH 01/10] Add "dffinit -strinit high low" On some platforms the string to initialize DFF might not be "high" and "low", e.g. with Anlogic TD it's "SET" and "RESET". Add a "-strinit" parameter for dffinit to allow specify the strings used for high and low. Signed-off-by: Icenowy Zheng --- passes/techmap/dffinit.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index a8eecc970..4fa15a35b 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -43,6 +43,11 @@ struct DffinitPass : public Pass { log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); log(" mode.)\n"); log("\n"); + log(" -strinit \n"); + log(" use string values in the command line to represent a single-bit\n"); + log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); + log(" mode.)\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -50,11 +55,20 @@ struct DffinitPass : public Pass { dict> ff_types; bool highlow_mode = false; + std::string high_string, low_string; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-highlow") { highlow_mode = true; + high_string = "high"; + low_string = "low"; + continue; + } + if (args[argidx] == "-strinit" && argidx+2 < args.size()) { + highlow_mode = true; + high_string = args[++argidx]; + low_string = args[++argidx]; continue; } if (args[argidx] == "-ff" && argidx+3 < args.size()) { @@ -121,9 +135,9 @@ struct DffinitPass : public Pass { log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n", log_id(module), log_id(cell), log_id(it.second)); if (value[0] == State::S1) - value = Const("high"); + value = Const(high_string); else - value = Const("low"); + value = Const(low_string); } log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second), From 256fb8c95c3b974fb636f515297191a6fc70b356 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 18 Dec 2018 23:10:40 +0800 Subject: [PATCH 02/10] Add "dffinit -noreinit" parameter Sometimes the FF cell might be initialized during the map process, e.g. some FPGA platforms (Anlogic Eagle and Lattice ECP5 for example) has only a "SR" pin for a FF for async reset, that resets the FF to the initial value, which means the async reset value should be set as the initial value. In this case the DFFINIT pass shouldn't reinitialize it to a different value, which will lead to error. Add a "-noreinit" parameter for the safeguard. If a FF is not technically initialized before DFFINIT pass, the default value should be set to x. Signed-off-by: Icenowy Zheng --- passes/techmap/dffinit.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 4fa15a35b..48390488e 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -48,13 +48,18 @@ struct DffinitPass : public Pass { log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); log(" mode.)\n"); log("\n"); + log(" -noreinit\n"); + log(" fail if the FF cell has already a defined initial value set in other\n"); + log(" passes and the initial value of the net it drives is not equal to\n"); + log(" the already defined initial value.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n"); dict> ff_types; - bool highlow_mode = false; + bool highlow_mode = false, noreinit = false; std::string high_string, low_string; size_t argidx; @@ -78,6 +83,10 @@ struct DffinitPass : public Pass { ff_types[cell_name][output_port] = init_param; continue; } + if (args[argidx] == "-noreinit") { + noreinit = true; + continue; + } break; } extra_args(args, argidx, design); @@ -126,6 +135,10 @@ struct DffinitPass : public Pass { continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) + log_error("Trying to assign a different init value for %s.%s.%s which technically " + "have a conflicted init value.\n", + log_id(module), log_id(cell), log_id(it.second)); value.bits[i] = init_bits.at(sig[i]); cleanup_bits.insert(sig[i]); } From 4bf8ac728cbebabf2333f2a15b9e52c6af8b806a Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 18 Dec 2018 15:39:02 +0800 Subject: [PATCH 03/10] anlogic: set the init value of DFFs As dffinit has already supported for different initialization strings for DFFs and check for re-initialization, initialization of Anlogic DFFs are now ready to go. Support for set the init values of Anlogic DFFs. Signed-off-by: Icenowy Zheng --- techlibs/anlogic/cells_map.v | 28 ++++++++++++++-------------- techlibs/anlogic/synth_anlogic.cc | 1 + 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 36b920ef0..98b8d46ef 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -1,19 +1,19 @@ -module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule -module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule `ifndef NO_LUT module \$lut (A, Y); diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index a4eafeddf..492a830b9 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -170,6 +170,7 @@ struct SynthAnlogicPass : public ScriptPass { run("dffsr2dff"); run("techmap -D NO_LUT -map +/anlogic/cells_map.v"); + run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); run("simplemap"); } From a91892bba422bbe8de080a105a6fb4b44f96df1a Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 07:53:31 +0000 Subject: [PATCH 04/10] cmp2lut: new techmap pass. --- techlibs/common/Makefile.inc | 2 +- techlibs/common/cmp2lut.v | 105 +++++++++++++++++++++++++++++++++++ tests/lut/check_map.ys | 6 +- tests/lut/map_cmp.v | 29 ++++++++++ tests/lut/run-test.sh | 0 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 techlibs/common/cmp2lut.v create mode 100644 tests/lut/map_cmp.v mode change 100644 => 100755 tests/lut/run-test.sh diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 70074f653..0e05620bc 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -26,5 +26,5 @@ $(eval $(call add_share_file,share,techlibs/common/pmux2mux.v)) $(eval $(call add_share_file,share,techlibs/common/adff2dff.v)) $(eval $(call add_share_file,share,techlibs/common/dff2ff.v)) $(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) +$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) - diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v new file mode 100644 index 000000000..8aa1eb957 --- /dev/null +++ b/techlibs/common/cmp2lut.v @@ -0,0 +1,105 @@ +// Certain arithmetic operations between a signal of width n and a constant can be directly mapped +// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process +// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often +// cannot be optimized further. +// +// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells +// with n <= k inputs should be techmapped in this way, because this shortens the critical path +// from n to 1 by avoiding carry chains. + +(* techmap_celltype = "$eq $ne $lt $le $gt $ge" *) +module _90_lut_cmp_ (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +parameter _TECHMAP_CELLTYPE_ = ""; + +parameter _TECHMAP_CONSTMSK_A_ = 0; +parameter _TECHMAP_CONSTVAL_A_ = 0; +parameter _TECHMAP_CONSTMSK_B_ = 0; +parameter _TECHMAP_CONSTVAL_B_ = 0; + +function automatic integer gen_lut; + input integer width; + input integer operation; + input integer swap; + input integer sign; + input integer operand; + integer n, i_var, i_cst, lhs, rhs, o_bit; + begin + gen_lut = width'b0; + for (n = 0; n < (1 << width); n++) begin + if (sign) + i_var = n[width-1:0]; + else + i_var = n; + i_cst = operand; + if (swap) begin + lhs = i_cst; + rhs = i_var; + end else begin + lhs = i_var; + rhs = i_cst; + end + if (operation == 0) + o_bit = (lhs < rhs); + if (operation == 1) + o_bit = (lhs <= rhs); + if (operation == 2) + o_bit = (lhs > rhs); + if (operation == 3) + o_bit = (lhs >= rhs); + if (operation == 4) + o_bit = (lhs == rhs); + if (operation == 5) + o_bit = (lhs != rhs); + gen_lut = gen_lut | (o_bit << n); + end + end +endfunction + +generate + if (_TECHMAP_CELLTYPE_ == "$lt") + localparam operation = 0; + if (_TECHMAP_CELLTYPE_ == "$le") + localparam operation = 1; + if (_TECHMAP_CELLTYPE_ == "$gt") + localparam operation = 2; + if (_TECHMAP_CELLTYPE_ == "$ge") + localparam operation = 3; + if (_TECHMAP_CELLTYPE_ == "$eq") + localparam operation = 4; + if (_TECHMAP_CELLTYPE_ == "$ne") + localparam operation = 5; + + if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) + wire _TECHMAP_FAIL_ = 1; + else if (&_TECHMAP_CONSTMSK_B_) + \$lut #( + .WIDTH(A_WIDTH), + .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) }) + ) _TECHMAP_REPLACE_ ( + .A(A), + .Y(Y) + ); + else if (&_TECHMAP_CONSTMSK_A_) + \$lut #( + .WIDTH(B_WIDTH), + .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) }) + ) _TECHMAP_REPLACE_ ( + .A(B), + .Y(Y) + ); + else + wire _TECHMAP_FAIL_ = 1; +endgenerate + +endmodule diff --git a/tests/lut/check_map.ys b/tests/lut/check_map.ys index dc0aaffc2..46854e82e 100644 --- a/tests/lut/check_map.ys +++ b/tests/lut/check_map.ys @@ -1,4 +1,6 @@ simplemap -equiv_opt -assert techmap -map +/gate2lut.v -D LUT_WIDTH=4 +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/cmp2lut.v design -load postopt -select -assert-count 1 t:$lut +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/gate2lut.v +design -load postopt +select -assert-count 0 t:* t:$lut %d diff --git a/tests/lut/map_cmp.v b/tests/lut/map_cmp.v new file mode 100644 index 000000000..5e413f894 --- /dev/null +++ b/tests/lut/map_cmp.v @@ -0,0 +1,29 @@ +module top(...); + input [3:0] a; + + output o1_1 = 4'b1010 <= a; + output o1_2 = 4'b1010 < a; + output o1_3 = 4'b1010 >= a; + output o1_4 = 4'b1010 > a; + output o1_5 = 4'b1010 == a; + output o1_6 = 4'b1010 != a; + + output o2_1 = a <= 4'b1010; + output o2_2 = a < 4'b1010; + output o2_3 = a >= 4'b1010; + output o2_4 = a > 4'b1010; + output o2_5 = a == 4'b1010; + output o2_6 = a != 4'b1010; + + output o3_1 = 4'sb0101 <= $signed(a); + output o3_2 = 4'sb0101 < $signed(a); + output o3_3 = 4'sb0101 >= $signed(a); + output o3_4 = 4'sb0101 > $signed(a); + output o3_5 = 4'sb0101 == $signed(a); + output o3_6 = 4'sb0101 != $signed(a); + + output o4_1 = $signed(a) <= 4'sb0000; + output o4_2 = $signed(a) < 4'sb0000; + output o4_3 = $signed(a) >= 4'sb0000; + output o4_4 = $signed(a) > 4'sb0000; +endmodule diff --git a/tests/lut/run-test.sh b/tests/lut/run-test.sh old mode 100644 new mode 100755 From fdff32dd731d92c854aef73ea9fad89635e82c0f Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 08:05:44 +0000 Subject: [PATCH 05/10] synth: improve script documentation. NFC. --- techlibs/common/synth.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index efb214759..5cadbba7a 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -186,19 +186,19 @@ struct SynthPass : public ScriptPass { run("proc"); if (help_mode || flatten) - run("flatten", "(if -flatten)"); + run("flatten", " (if -flatten)"); run("opt_expr"); run("opt_clean"); run("check"); run("opt"); run("wreduce"); if (!noalumacc) - run("alumacc"); + run("alumacc", " (unless -noalumacc)"); if (!noshare) - run("share"); + run("share", " (unless -noshare)"); run("opt"); if (!nofsm) - run("fsm" + fsm_opts); + run("fsm" + fsm_opts, " (unless -nofsm)"); run("opt -fast"); run("memory -nomap" + memory_opts); run("opt_clean"); @@ -214,8 +214,8 @@ struct SynthPass : public ScriptPass if (!noabc) { #ifdef YOSYS_ENABLE_ABC - run("abc -fast"); - run("opt -fast"); + run("abc -fast", "(unless -noabc)"); + run("opt -fast", "(unless -noabc)"); #endif } } From 18174202a957cb20137e13893ad002ac1b52b61b Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 08:25:03 +0000 Subject: [PATCH 06/10] synth: add k-LUT mode. --- techlibs/common/synth.cc | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 5cadbba7a..5ff813d18 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -51,6 +51,9 @@ struct SynthPass : public ScriptPass log(" -encfile \n"); log(" passed to 'fsm_recode' via 'fsm'\n"); log("\n"); + log(" -lut \n"); + log(" perform synthesis for a k-LUT architecture.\n"); + log("\n"); log(" -nofsm\n"); log(" do not run FSM optimization\n"); log("\n"); @@ -80,6 +83,7 @@ struct SynthPass : public ScriptPass string top_module, fsm_opts, memory_opts; bool autotop, flatten, noalumacc, nofsm, noabc, noshare; + int lut; void clear_flags() YS_OVERRIDE { @@ -89,6 +93,7 @@ struct SynthPass : public ScriptPass autotop = false; flatten = false; + lut = 0; noalumacc = false; nofsm = false; noabc = false; @@ -130,6 +135,10 @@ struct SynthPass : public ScriptPass flatten = true; continue; } + if (args[argidx] == "-lut") { + lut = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-nofsm") { nofsm = true; continue; @@ -192,6 +201,10 @@ struct SynthPass : public ScriptPass run("check"); run("opt"); run("wreduce"); + if (help_mode) + run("techmap -map +/cmp2lut.v", " (if -lut)"); + else + run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut)); if (!noalumacc) run("alumacc", " (unless -noalumacc)"); if (!noshare) @@ -210,12 +223,33 @@ struct SynthPass : public ScriptPass run("memory_map"); run("opt -full"); run("techmap"); + if (help_mode) + { + run("techmap -map +/gate2lut.v", "(if -noabc and -lut)"); + run("clean; opt_lut", " (if -noabc and -lut)"); + } + else if (noabc && lut) + { + run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut)); + run("clean; opt_lut"); + } run("opt -fast"); if (!noabc) { #ifdef YOSYS_ENABLE_ABC - run("abc -fast", "(unless -noabc)"); - run("opt -fast", "(unless -noabc)"); + if (help_mode) + { + run("abc -fast", " (unless -noabc, unless -lut)"); + run("abc -fast -lut k", "(unless -noabc, if -lut)"); + } + else + { + if (lut) + run(stringf("abc -fast -lut %d", lut)); + else + run("abc -fast"); + } + run("opt -fast", " (unless -noabc)"); #endif } } From 17b283135658b84a0dfeec8b35f7d2bfe782be19 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 08:25:55 +0000 Subject: [PATCH 07/10] synth_ice40: use 4-LUT coarse synthesis mode. --- techlibs/ice40/synth_ice40.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index c2aed873b..4c4fdf7be 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -226,7 +226,7 @@ struct SynthIce40Pass : public ScriptPass if (check_label("coarse")) { - run("synth -run coarse"); + run("synth -lut 4 -run coarse"); } if (!nobram && check_label("bram", "(skip if -nobram)")) From f7363ac5086ccb8bdb97dcdbfed890c54e1ed153 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 08:40:01 +0000 Subject: [PATCH 08/10] opt_lut: count eliminated cells, and set opt.did_something for them. --- passes/opt/opt_lut.cc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index 261af538f..8c564b0ed 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -36,7 +36,7 @@ struct OptLutWorker dict> luts_dlogics; dict> luts_dlogic_inputs; - int combined_count = 0; + int eliminated_count = 0, combined_count = 0; bool evaluate_lut(RTLIL::Cell *lut, dict inputs) { @@ -191,6 +191,12 @@ struct OptLutWorker log("Eliminating LUTs.\n"); for (auto lut : luts) { + if (limit == 0) + { + log("Limit reached.\n"); + break; + } + SigSpec lut_input = sigmap(lut->getPort("\\A")); pool &lut_dlogic_inputs = luts_dlogic_inputs[lut]; @@ -263,6 +269,10 @@ struct OptLutWorker luts_arity.erase(lut); luts_dlogics.erase(lut); luts_dlogic_inputs.erase(lut); + + eliminated_count++; + if (limit > 0) + limit--; } } } @@ -568,16 +578,20 @@ struct OptLutPass : public Pass { } extra_args(args, argidx, design); - int total_count = 0; + int eliminated_count = 0, combined_count = 0; for (auto module : design->selected_modules()) { - OptLutWorker worker(dlogic, module, limit - total_count); - total_count += worker.combined_count; + OptLutWorker worker(dlogic, module, limit - eliminated_count - combined_count); + eliminated_count += worker.eliminated_count; + combined_count += worker.combined_count; } - if (total_count) + if (eliminated_count) + design->scratchpad_set_bool("opt.did_something", true); + if (combined_count) design->scratchpad_set_bool("opt.did_something", true); log("\n"); - log("Combined %d LUTs.\n", total_count); + log("Eliminated %d LUTs.\n", eliminated_count); + log("Combined %d LUTs.\n", combined_count); } } OptLutPass; From 06143ab33f4064677586be2a2b0d763f0818e856 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 09:36:32 +0000 Subject: [PATCH 09/10] opt_lut: use a worklist, and revisit cells affected by elimination. --- passes/opt/opt_lut.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index 8c564b0ed..a79a9a2da 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -189,7 +189,8 @@ struct OptLutWorker log("\n"); log("Eliminating LUTs.\n"); - for (auto lut : luts) + pool worklist = luts; + while (worklist.size()) { if (limit == 0) { @@ -197,6 +198,7 @@ struct OptLutWorker break; } + auto lut = worklist.pop(); SigSpec lut_input = sigmap(lut->getPort("\\A")); pool &lut_dlogic_inputs = luts_dlogic_inputs[lut]; @@ -262,8 +264,13 @@ struct OptLutWorker else { SigSpec lut_output = lut->getPort("\\Y"); - module->connect(lut_output, value); + for (auto &port : index.query_ports(lut_output)) + { + if (port.cell != lut && luts.count(port.cell)) + worklist.insert(port.cell); + } + module->connect(lut_output, value); module->remove(lut); luts.erase(lut); luts_arity.erase(lut); @@ -280,7 +287,7 @@ struct OptLutWorker log("\n"); log("Combining LUTs.\n"); - pool worklist = luts; + worklist = luts; while (worklist.size()) { if (limit == 0) From c55dfb83693c6707ecb1d7dce7824a61e87eb44d Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 2 Jan 2019 10:21:58 +0000 Subject: [PATCH 10/10] opt_lut: reflect changes in sigmap. Otherwise, some LUTs will be missed during elimination. --- passes/opt/opt_lut.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index a79a9a2da..b9a1ce7a7 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -271,6 +271,8 @@ struct OptLutWorker } module->connect(lut_output, value); + sigmap.add(lut_output, value); + module->remove(lut); luts.erase(lut); luts_arity.erase(lut);