nexus: DSP inference support
authorDavid Shah <dave@ds0.me>
Fri, 20 Nov 2020 08:26:58 +0000 (08:26 +0000)
committerDavid Shah <dave@ds0.me>
Fri, 20 Nov 2020 08:45:55 +0000 (08:45 +0000)
Signed-off-by: David Shah <dave@ds0.me>
techlibs/nexus/Makefile.inc
techlibs/nexus/dsp_map.v [new file with mode: 0644]
techlibs/nexus/synth_nexus.cc
tests/arch/nexus/mul.ys

index e0ff40e15331f31df696597c97f7a724d6e16e26..c9a9ad4fff448969c5a03cdcca106551573d6886 100644 (file)
@@ -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 (file)
index 0000000..b125283
--- /dev/null
@@ -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
index 7e2185ab6bad5da0f2628f900c4d251195d20a53..9eabbace724e92f70c95a3a23a111c52f5183349 100644 (file)
@@ -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");
index 27ea3e04ee1bf77af522217362d2242754cddac4..65a2fd8c3eb453d8aceb12b456964096491d6d63 100644 (file)
@@ -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