diff options
-rw-r--r-- | techlibs/nexus/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/nexus/dsp_map.v | 79 | ||||
-rw-r--r-- | techlibs/nexus/synth_nexus.cc | 38 | ||||
-rw-r--r-- | tests/arch/nexus/mul.ys | 46 |
4 files changed, 151 insertions, 13 deletions
diff --git a/techlibs/nexus/Makefile.inc b/techlibs/nexus/Makefile.inc index e0ff40e15..c9a9ad4ff 100644 --- a/techlibs/nexus/Makefile.inc +++ b/techlibs/nexus/Makefile.inc @@ -11,4 +11,5 @@ $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams_map.v)) $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams.txt)) $(eval $(call add_share_file,share/nexus,techlibs/nexus/arith_map.v)) $(eval $(call add_share_file,share/nexus,techlibs/nexus/latches_map.v)) +$(eval $(call add_share_file,share/nexus,techlibs/nexus/dsp_map.v)) diff --git a/techlibs/nexus/dsp_map.v b/techlibs/nexus/dsp_map.v new file mode 100644 index 000000000..b12528309 --- /dev/null +++ b/techlibs/nexus/dsp_map.v @@ -0,0 +1,79 @@ +module \$__NX_MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y); + + parameter A_WIDTH = 36; + parameter B_WIDTH = 36; + parameter Y_WIDTH = 72; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT36X36 #( + .REGINPUTA("BYPASS"), + .REGINPUTB("BYPASS"), + .REGOUTPUT("BYPASS") + ) _TECHMAP_REPLACE_ ( + .A(A), .B(B), + .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); + + parameter A_WIDTH = 36; + parameter B_WIDTH = 18; + parameter Y_WIDTH = 54; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT18X36 #( + .REGINPUTA("BYPASS"), + .REGINPUTB("BYPASS"), + .REGOUTPUT("BYPASS") + ) _TECHMAP_REPLACE_ ( + .A(B), .B(A), + .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); + + parameter A_WIDTH = 18; + parameter B_WIDTH = 18; + parameter Y_WIDTH = 36; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT18X18 #( + .REGINPUTA("BYPASS"), + .REGINPUTB("BYPASS"), + .REGOUTPUT("BYPASS") + ) _TECHMAP_REPLACE_ ( + .A(A), .B(B), + .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), + .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), + .Z(Y) + ); +endmodule + +module \$__NX_MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y); + + parameter A_WIDTH = 9; + parameter B_WIDTH = 9; + parameter Y_WIDTH = 18; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT9X9 #( + .REGINPUTA("BYPASS"), + .REGINPUTB("BYPASS"), + .REGOUTPUT("BYPASS") + ) _TECHMAP_REPLACE_ ( + .A(A), .B(B), + .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), + .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), + .Z(Y) + ); +endmodule diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc index 7e2185ab6..9eabbace7 100644 --- a/techlibs/nexus/synth_nexus.cc +++ b/techlibs/nexus/synth_nexus.cc @@ -89,6 +89,9 @@ struct SynthNexusPass : public ScriptPass log(" -noiopad\n"); log(" do not insert IO buffers\n"); log("\n"); + log(" -nodsp\n"); + log(" do not infer DSP multipliers\n"); + log("\n"); log(" -abc9\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); @@ -98,7 +101,7 @@ struct SynthNexusPass : public ScriptPass } string top_opt, json_file, vm_file, family; - bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, flatten, dff, retime, abc9; + bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, nodsp, flatten, dff, retime, abc9; void clear_flags() override { @@ -112,6 +115,7 @@ struct SynthNexusPass : public ScriptPass nolutram = false; nowidelut = false; noiopad = false; + nodsp = false; flatten = true; dff = false; retime = false; @@ -161,6 +165,10 @@ struct SynthNexusPass : public ScriptPass dff = true; continue; } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } if (args[argidx] == "-retime") { retime = true; continue; @@ -211,6 +219,22 @@ struct SynthNexusPass : public ScriptPass log_pop(); } + struct DSPRule { + int a_maxwidth; + int b_maxwidth; + int a_minwidth; + int b_minwidth; + std::string prim; + }; + + const std::vector<DSPRule> dsp_rules = { + {36, 36, 22, 22, "$__NX_MUL36X36"}, + {36, 18, 22, 10, "$__NX_MUL36X18"}, + {18, 18, 10, 4, "$__NX_MUL18X18"}, + {18, 18, 4, 10, "$__NX_MUL18X18"}, + { 9, 9, 4, 4, "$__NX_MUL9X9"}, + }; + void script() override { @@ -244,6 +268,18 @@ struct SynthNexusPass : public ScriptPass run("opt_expr"); run("opt_clean"); + if (help_mode) { + run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); + run("techmap -map +/nexus/dsp_map.v", "(unless -nodsp)"); + } else if (!nodsp) { + for (const auto &rule : dsp_rules) { + run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", + rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim.c_str())); + run("chtype -set $mul t:$__soft_mul"); + } + run("techmap -map +/nexus/dsp_map.v"); + } + run("alumacc"); run("opt"); run("memory -nomap"); diff --git a/tests/arch/nexus/mul.ys b/tests/arch/nexus/mul.ys index 27ea3e04e..65a2fd8c3 100644 --- a/tests/arch/nexus/mul.ys +++ b/tests/arch/nexus/mul.ys @@ -1,4 +1,5 @@ read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 hierarchy -top top proc @@ -7,22 +8,43 @@ 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 7 t:CCU2 -select -assert-max 5 t:WIDEFN9 -select -assert-max 62 t:LUT4 +select -assert-count 1 t:MULT9X9 -select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:CCU2 t:WIDEFN9 %% t:* %D +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT9X9 %% t:* %D -design -load read -equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus -abc9 -design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +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 -stat -select -assert-count 7 t:CCU2 -select -assert-max 12 t:WIDEFN9 -select -assert-max 58 t:LUT4 +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:LUT4 t:CCU2 t:WIDEFN9 %% t:* %D +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT36X36 %% t:* %D |