diff options
Diffstat (limited to 'techlibs')
-rw-r--r-- | techlibs/common/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/common/mul2dsp.v | 232 | ||||
-rw-r--r-- | techlibs/ecp5/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/ecp5/dsp_map.v | 10 | ||||
-rw-r--r-- | techlibs/ecp5/synth_ecp5.cc | 33 | ||||
-rw-r--r-- | techlibs/ice40/synth_ice40.cc | 4 | ||||
-rw-r--r-- | techlibs/xilinx/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 147 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.v | 82 | ||||
-rw-r--r-- | techlibs/xilinx/dsp_map.v | 40 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 24 |
11 files changed, 487 insertions, 88 deletions
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 0e05620bc..e6d1c2f29 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -28,3 +28,4 @@ $(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)) +$(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v new file mode 100644 index 000000000..391b395ff --- /dev/null +++ b/techlibs/common/mul2dsp.v @@ -0,0 +1,232 @@ +// From Eddie Hung
+// extracted from: https://github.com/eddiehung/vtr-with-yosys/blob/vtr7-with-yosys/vtr_flow/misc/yosys_models.v#L220
+// revised by Andre DeHon
+// further revised by David Shah
+`ifndef DSP_A_MAXWIDTH
+$error("Macro DSP_A_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_B_MAXWIDTH
+$error("Macro DSP_B_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_SIGNEDONLY
+`define DSP_SIGNEDONLY 0
+`endif
+
+`ifndef DSP_NAME
+$error("Macro DSP_NAME must be defined");
+`endif
+
+`define MAX(a,b) (a > b ? a : b)
+`define MIN(a,b) (a < b ? a : b)
+
+module \$mul (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ generate
+ if (A_SIGNED != B_SIGNED)
+ wire _TECHMAP_FAIL_ = 1;
+ else if (`DSP_SIGNEDONLY && !A_SIGNED) begin
+ wire [1:0] dummy;
+ \$mul #(
+ .A_SIGNED(1),
+ .B_SIGNED(1),
+ .A_WIDTH(A_WIDTH + 1),
+ .B_WIDTH(B_WIDTH + 1),
+ .Y_WIDTH(Y_WIDTH + 2)
+ ) _TECHMAP_REPLACE_ (
+ .A({1'b0, A}),
+ .B({1'b0, B}),
+ .Y({dummy, Y})
+ );
+ end
+ // NB: A_SIGNED == B_SIGNED == 0 from here
+ else if (A_WIDTH >= B_WIDTH)
+ \$__mul_gen #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .B(B),
+ .Y(Y)
+ );
+ else
+ \$__mul_gen #(
+ .A_SIGNED(B_SIGNED),
+ .B_SIGNED(A_SIGNED),
+ .A_WIDTH(B_WIDTH),
+ .B_WIDTH(A_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(B),
+ .B(A),
+ .Y(Y)
+ );
+ endgenerate
+endmodule
+
+module \$__mul_gen (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+
+`ifdef DSP_SIGNEDONLY
+ localparam sign_headroom = 1;
+`else
+ localparam sign_headroom = 0;
+`endif
+
+ genvar i;
+ generate
+ if (A_WIDTH > `DSP_A_MAXWIDTH) begin
+ localparam n = (A_WIDTH+`DSP_A_MAXWIDTH-sign_headroom-1) / (`DSP_A_MAXWIDTH-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH);
+ if (A_SIGNED && B_SIGNED) begin
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
+ end
+ else begin
+ wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire [Y_WIDTH-1:0] partial_sum [n-1:0];
+ end
+
+ \$__mul_gen #(
+ .A_SIGNED(0),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul_slice_first (
+ .A({{sign_headroom{1'b0}}, A[`DSP_A_MAXWIDTH-sign_headroom-1 : 0]}),
+ .B(B),
+ .Y(partial[0])
+ );
+ assign partial_sum[0] = partial[0];
+
+ for (i = 1; i < n-1; i=i+1) begin:slice
+ \$__mul_gen #(
+ .A_SIGNED(0),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul_slice (
+ .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH-sign_headroom) +: `DSP_A_MAXWIDTH-sign_headroom]}),
+ .B(B),
+ .Y(partial[i])
+ );
+ assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
+ end
+
+ \$__mul_gen #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom)),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul_slice_last (
+ .A(A[A_WIDTH-1 : (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)]),
+ .B(B),
+ .Y(partial[n-1])
+ );
+ assign partial_sum[n-1] = (partial[n-1] << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
+ assign Y = partial_sum[n-1];
+ end
+ else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
+ localparam n = (B_WIDTH+`DSP_B_MAXWIDTH-sign_headroom-1) / (`DSP_B_MAXWIDTH-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH);
+ if (A_SIGNED && B_SIGNED) begin
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
+ end
+ else begin
+ wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ wire [Y_WIDTH-1:0] partial_sum [n-1:0];
+ end
+
+ \$__mul_gen #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(0),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul_first (
+ .A(A),
+ .B({{sign_headroom{1'b0}}, B[`DSP_B_MAXWIDTH-sign_headroom-1 : 0]}),
+ .Y(partial[0])
+ );
+ assign partial_sum[0] = partial[0];
+
+ for (i = 1; i < n-1; i=i+1) begin:slice
+ \$__mul_gen #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(0),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul (
+ .A(A),
+ .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH-sign_headroom) +: `DSP_B_MAXWIDTH-sign_headroom]}),
+ .Y(partial[i])
+ );
+ assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
+ end
+
+ \$__mul_gen #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom)),
+ .Y_WIDTH(partial_Y_WIDTH)
+ ) mul_last (
+ .A(A),
+ .B(B[B_WIDTH-1 : (n-1)*(`DSP_B_MAXWIDTH-sign_headroom)]),
+ .Y(partial[n-1])
+ );
+ assign partial_sum[n-1] = (partial[n-1] << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
+ assign Y = partial_sum[n-1];
+ end
+ else begin
+ if (A_SIGNED)
+ wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
+ else
+ wire [`DSP_A_MAXWIDTH-1:0] Aext = A;
+ if (B_SIGNED)
+ wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B);
+ else
+ wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
+
+ `DSP_NAME #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH),
+ .Y_WIDTH(`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH),
+ ) _TECHMAP_REPLACE_ (
+ .A(Aext),
+ .B(Bext),
+ .Y(Y)
+ );
+ end
+ endgenerate
+endmodule
+
+
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 73e18112f..c7d6eee02 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -10,6 +10,7 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) diff --git a/techlibs/ecp5/dsp_map.v b/techlibs/ecp5/dsp_map.v new file mode 100644 index 000000000..24e28869e --- /dev/null +++ b/techlibs/ecp5/dsp_map.v @@ -0,0 +1,10 @@ +module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); + MULT18X18D _TECHMAP_REPLACE_ ( + .A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]), + .B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]), + .C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0), + .SIGNEDA(1'b0), .SIGNEDB(1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0), + + .P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35]) + ); +endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 143d1f95c..3129ba929 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -89,6 +89,9 @@ struct SynthEcp5Pass : public ScriptPass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); + log(" -dsp\n"); + log(" map multipliers to MULT18X18D (EXPERIMENTAL)\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -96,7 +99,7 @@ struct SynthEcp5Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, vpr; + bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, dsp, vpr; void clear_flags() YS_OVERRIDE { @@ -114,6 +117,7 @@ struct SynthEcp5Pass : public ScriptPass abc2 = false; vpr = false; abc9 = false; + dsp = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -192,6 +196,10 @@ struct SynthEcp5Pass : public ScriptPass abc9 = true; continue; } + if (args[argidx] == "-dsp") { + dsp = true; + continue; + } break; } extra_args(args, argidx, design); @@ -228,7 +236,28 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("coarse")) { - run("synth -run coarse"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); + run("opt_expr"); + run("opt_clean"); + if (dsp) { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_NAME=$__MUL18X18"); + run("clean"); + run("techmap -map +/ecp5/dsp_map.v"); + } + run("alumacc"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } if (!nobram && check_label("map_bram", "(skip if -nobram)")) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index be60a0071..5053e445d 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -265,8 +265,10 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("opt_expr"); run("opt_clean"); - if (help_mode || dsp) + if (help_mode || dsp) { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 -D DSP_NAME=$__MUL16X16"); run("ice40_dsp", "(if -dsp)"); + } run("alumacc"); run("opt"); run("fsm"); diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 2c6e7432e..b0251d621 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -38,6 +38,7 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut)) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 05e46b4e7..33b2a8f62 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -378,3 +378,150 @@ module SRLC32E ( always @(posedge CLK) if (CE) r <= { r[30:0], D }; endgenerate endmodule + +module DSP48E1 ( + output [29:0] ACOUT, + output [17:0] BCOUT, + output CARRYCASCOUT, + output [3:0] CARRYOUT, + output MULTSIGNOUT, + output OVERFLOW, + output reg signed [47:0] P, + output PATTERNBDETECT, + output PATTERNDETECT, + output [47:0] PCOUT, + output UNDERFLOW, + input signed [29:0] A, + input [29:0] ACIN, + input [3:0] ALUMODE, + input signed [17:0] B, + input [17:0] BCIN, + input [47:0] C, + input CARRYCASCIN, + input CARRYIN, + input [2:0] CARRYINSEL, + input CEA1, + input CEA2, + input CEAD, + input CEALUMODE, + input CEB1, + input CEB2, + input CEC, + input CECARRYIN, + input CECTRL, + input CED, + input CEINMODE, + input CEM, + input CEP, + input CLK, + input [24:0] D, + input [4:0] INMODE, + input MULTSIGNIN, + input [6:0] OPMODE, + input [47:0] PCIN, + input RSTA, + input RSTALLCARRYIN, + input RSTALUMODE, + input RSTB, + input RSTC, + input RSTCTRL, + input RSTD, + input RSTINMODE, + input RSTM, + input RSTP +); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_DPORT = "FALSE"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter [47:0] PATTERN = 48'h000000000000; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b0; + parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + + initial begin +`ifdef __ICARUS__ + if (ACASCREG != 0) $fatal(1, "Unsupported ACASCREG value"); + if (ADREG != 0) $fatal(1, "Unsupported ADREG value"); + if (ALUMODEREG != 0) $fatal(1, "Unsupported ALUMODEREG value"); + if (AREG == 2) $fatal(1, "Unsupported AREG value"); + if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value"); + if (A_INPUT != "DIRECT") $fatal(1, "Unsupported A_INPUT value"); + if (BCASCREG != 0) $fatal(1, "Unsupported BCASCREG value"); + if (BREG == 2) $fatal(1, "Unsupported BREG value"); + if (B_INPUT != "DIRECT") $fatal(1, "Unsupported B_INPUT value"); + if (CARRYINREG != 0) $fatal(1, "Unsupported CARRYINREG value"); + if (CARRYINSELREG != 0) $fatal(1, "Unsupported CARRYINSELREG value"); + if (CREG != 0) $fatal(1, "Unsupported CREG value"); + if (DREG != 0) $fatal(1, "Unsupported DREG value"); + if (INMODEREG != 0) $fatal(1, "Unsupported INMODEREG value"); + if (MREG != 0) $fatal(1, "Unsupported MREG value"); + if (OPMODEREG != 0) $fatal(1, "Unsupported OPMODEREG value"); + //if (PREG != 0) $fatal(1, "Unsupported PREG value"); + if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value"); + if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value"); + if (USE_DPORT != "FALSE") $fatal(1, "Unsupported USE_DPORT value"); + if (USE_MULT != "MULTIPLY") $fatal(1, "Unsupported USE_MULT value"); + if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value"); + if (USE_SIMD != "ONE48") $fatal(1, "Unsupported USE_SIMD value"); + if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value"); + if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value"); + if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value"); + if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value"); + if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value"); +`endif + end + + reg signed [29:0] Ar; + reg signed [17:0] Br; + reg signed [47:0] Pr; + generate + if (AREG == 1) begin always @(posedge CLK) if (CEA2) Ar <= A; end + else always @* Ar <= A; + if (BREG == 1) begin always @(posedge CLK) if (CEB2) Br <= B; end + else always @* Br <= B; + endgenerate + + always @* begin + Pr <= {48{1'bx}}; +`ifdef __ICARUS__ + if (INMODE != 4'b0000) $fatal(1, "Unsupported INMODE value"); + if (ALUMODE != 4'b0000) $fatal(1, "Unsupported ALUMODE value"); + if (OPMODE != 7'b000101) $fatal(1, "Unsupported OPMODE value"); + if (CARRYINSEL != 3'b000) $fatal(1, "Unsupported CARRYINSEL value"); + if (ACIN != 30'b0) $fatal(1, "Unsupported ACIN value"); + if (BCIN != 18'b0) $fatal(1, "Unsupported BCIN value"); + if (PCIN != 48'b0) $fatal(1, "Unsupported PCIN value"); + if (CARRYIN != 1'b0) $fatal(1, "Unsupported CARRYIN value"); +`endif + Pr[42:0] <= $signed(Ar[24:0]) * Br; + end + + generate + if (PREG == 1) begin always @(posedge CLK) if (CEP) P <= Pr; end + else always @* P <= Pr; + endgenerate + +endmodule diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 15fa1b63a..d79349225 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -111,88 +111,6 @@ module DNA_PORT (...); input CLK, DIN, READ, SHIFT; endmodule -module DSP48E1 (...); - parameter integer ACASCREG = 1; - parameter integer ADREG = 1; - parameter integer ALUMODEREG = 1; - parameter integer AREG = 1; - parameter AUTORESET_PATDET = "NO_RESET"; - parameter A_INPUT = "DIRECT"; - parameter integer BCASCREG = 1; - parameter integer BREG = 1; - parameter B_INPUT = "DIRECT"; - parameter integer CARRYINREG = 1; - parameter integer CARRYINSELREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer INMODEREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter SEL_MASK = "MASK"; - parameter SEL_PATTERN = "PATTERN"; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - parameter USE_PATTERN_DETECT = "NO_PATDET"; - parameter USE_SIMD = "ONE48"; - parameter [47:0] MASK = 48'h3FFFFFFFFFFF; - parameter [47:0] PATTERN = 48'h000000000000; - parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; - parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - parameter [4:0] IS_INMODE_INVERTED = 5'b0; - parameter [6:0] IS_OPMODE_INVERTED = 7'b0; - output [29:0] ACOUT; - output [17:0] BCOUT; - output CARRYCASCOUT; - output [3:0] CARRYOUT; - output MULTSIGNOUT; - output OVERFLOW; - output [47:0] P; - output PATTERNBDETECT; - output PATTERNDETECT; - output [47:0] PCOUT; - output UNDERFLOW; - input [29:0] A; - input [29:0] ACIN; - input [3:0] ALUMODE; - input [17:0] B; - input [17:0] BCIN; - input [47:0] C; - input CARRYCASCIN; - input CARRYIN; - input [2:0] CARRYINSEL; - input CEA1; - input CEA2; - input CEAD; - input CEALUMODE; - input CEB1; - input CEB2; - input CEC; - input CECARRYIN; - input CECTRL; - input CED; - input CEINMODE; - input CEM; - input CEP; - input CLK; - input [24:0] D; - input [4:0] INMODE; - input MULTSIGNIN; - input [6:0] OPMODE; - input [47:0] PCIN; - input RSTA; - input RSTALLCARRYIN; - input RSTALUMODE; - input RSTB; - input RSTC; - input RSTCTRL; - input RSTD; - input RSTINMODE; - input RSTM; - input RSTP; -endmodule - module EFUSE_USR (...); parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; output [31:0] EFUSEUSR; diff --git a/techlibs/xilinx/dsp_map.v b/techlibs/xilinx/dsp_map.v new file mode 100644 index 000000000..32f570935 --- /dev/null +++ b/techlibs/xilinx/dsp_map.v @@ -0,0 +1,40 @@ +module \$__MUL25X18 (input signed [24:0] A, input signed [17:0] B, output signed [42:0] Y); + wire [47:0] P_48; + DSP48E1 #( + // Disable all registers + .ACASCREG(0), + .ADREG(0), + .A_INPUT("DIRECT"), + .ALUMODEREG(0), + .AREG(0), + .BCASCREG(0), + .B_INPUT("DIRECT"), + .BREG(0), + .CARRYINREG(0), + .CARRYINSELREG(0), + .CREG(0), + .DREG(0), + .INMODEREG(0), + .MREG(0), + .OPMODEREG(0), + .PREG(0) + ) _TECHMAP_REPLACE_ ( + //Data path + .A({{5{A[24]}}, A}), + .B(B), + .C(48'b0), + .D(24'b0), + .P(P_48), + + .INMODE(4'b0000), + .ALUMODE(4'b0000), + .OPMODE(7'b000101), + .CARRYINSEL(3'b000), + + .ACIN(30'b0), + .BCIN(18'b0), + .PCIN(48'b0), + .CARRYIN(1'b0) + ); + assign Y = P_48; +endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b672a0d4f..e5a27015a 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -78,6 +78,9 @@ struct SynthXilinxPass : public ScriptPass log(" -nowidelut\n"); log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); log("\n"); + log(" -nodsp\n"); + log(" do not use DSP48E1s to implement multipliers and associated logic\n"); + log("\n"); log(" -widemux <int>\n"); log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n"); log(" above this number of inputs (minimum value 2, recommended value >= 5).\n"); @@ -104,7 +107,7 @@ struct SynthXilinxPass : public ScriptPass } std::string top_opt, edif_file, blif_file, family; - bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9; + bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, nodsp, abc9; int widemux; void clear_flags() YS_OVERRIDE @@ -122,6 +125,7 @@ struct SynthXilinxPass : public ScriptPass nosrl = false; nocarry = false; nowidelut = false; + nodsp = false; abc9 = false; widemux = 0; } @@ -202,6 +206,10 @@ struct SynthXilinxPass : public ScriptPass abc9 = true; continue; } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } break; } extra_args(args, argidx, design); @@ -249,8 +257,8 @@ struct SynthXilinxPass : public ScriptPass if (check_label("coarse")) { run("proc"); - if (help_mode || flatten) - run("flatten", "(if -flatten)"); + if (flatten || help_mode) + run("flatten", "(with '-flatten')"); run("opt_expr"); run("opt_clean"); run("check"); @@ -275,6 +283,12 @@ struct SynthXilinxPass : public ScriptPass } run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + + if (!nodsp || help_mode) { + // NB: Xilinx multipliers are signed only + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18"); + } + run("alumacc"); run("share"); run("opt"); @@ -317,6 +331,10 @@ struct SynthXilinxPass : public ScriptPass run("memory_map"); run("dffsr2dff"); run("dff2dffe"); + if (help_mode || !nodsp) { + run("techmap -map +/xilinx/dsp_map.v", "(skip if '-nodsp')"); + run("xilinx_dsp", " (skip if '-nodsp')"); + } if (help_mode) { run("simplemap t:$mux", " ('-widemux' only)"); run("muxcover <internal options>, ('-widemux' only)"); |