aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--techlibs/nexus/Makefile.inc1
-rw-r--r--techlibs/nexus/dsp_map.v79
-rw-r--r--techlibs/nexus/synth_nexus.cc38
-rw-r--r--tests/arch/nexus/mul.ys46
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