3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-24 01:25:33 +00:00

Merge pull request #1359 from YosysHQ/xc7dsp

DSP inference for Xilinx (improved for ice40, initial support for ecp5)
This commit is contained in:
Eddie Hung 2019-09-29 11:26:22 -07:00 committed by GitHub
commit 8474c5b366
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 6247 additions and 294 deletions

View file

@ -28,4 +28,5 @@ $(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))
$(eval $(call add_share_file,share,techlibs/common/dummy.box))

296
techlibs/common/mul2dsp.v Normal file
View file

@ -0,0 +1,296 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* 2019 Eddie Hung <eddie@fpgeh.com>
* 2019 David Shah <dave@ds0.me>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* Tech-mapping rules for decomposing arbitrarily-sized $mul cells
* into an equivalent collection of smaller `DSP_NAME cells (with the
* same interface as $mul) no larger than `DSP_[AB]_MAXWIDTH, attached
* to $shl and $add cells.
*
*/
`ifndef DSP_A_MAXWIDTH
$fatal(1, "Macro DSP_A_MAXWIDTH must be defined");
`endif
`ifndef DSP_B_MAXWIDTH
$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
`endif
`ifndef DSP_B_MAXWIDTH
$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
`endif
`ifndef DSP_A_MAXWIDTH_PARTIAL
`define DSP_A_MAXWIDTH_PARTIAL `DSP_A_MAXWIDTH
`endif
`ifndef DSP_B_MAXWIDTH_PARTIAL
`define DSP_B_MAXWIDTH_PARTIAL `DSP_B_MAXWIDTH
`endif
`ifndef DSP_NAME
$fatal(1, "Macro DSP_NAME must be defined");
`endif
`define MAX(a,b) (a > b ? a : b)
`define MIN(a,b) (a < b ? a : b)
(* techmap_celltype = "$mul $__mul" *)
module _80_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;
parameter _TECHMAP_CELLTYPE_ = "";
generate
if (0) begin end
`ifdef DSP_A_MINWIDTH
else if (A_WIDTH < `DSP_A_MINWIDTH)
wire _TECHMAP_FAIL_ = 1;
`endif
`ifdef DSP_B_MINWIDTH
else if (B_WIDTH < `DSP_B_MINWIDTH)
wire _TECHMAP_FAIL_ = 1;
`endif
`ifdef DSP_Y_MINWIDTH
else if (Y_WIDTH < `DSP_Y_MINWIDTH)
wire _TECHMAP_FAIL_ = 1;
`endif
`ifdef DSP_SIGNEDONLY
else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED && !B_SIGNED)
\$mul #(
.A_SIGNED(1),
.B_SIGNED(1),
.A_WIDTH(A_WIDTH + 1),
.B_WIDTH(B_WIDTH + 1),
.Y_WIDTH(Y_WIDTH)
) _TECHMAP_REPLACE_ (
.A({1'b0, A}),
.B({1'b0, B}),
.Y(Y)
);
`endif
else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH)
\$mul #(
.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)
);
else begin
wire [1023:0] _TECHMAP_DO_ = "proc; clean";
`ifdef DSP_SIGNEDONLY
localparam sign_headroom = 1;
`else
localparam sign_headroom = 0;
`endif
genvar i;
if (A_WIDTH > `DSP_A_MAXWIDTH) begin
localparam n = (A_WIDTH-`DSP_A_MAXWIDTH+`DSP_A_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH_PARTIAL);
localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
wire signed [last_Y_WIDTH-1:0] last_partial;
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
wire [last_Y_WIDTH-1:0] last_partial;
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
for (i = 0; i < n; i=i+1) begin:sliceA
\$__mul #(
.A_SIGNED(sign_headroom),
.B_SIGNED(B_SIGNED),
.A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(partial_Y_WIDTH)
) mul (
.A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}),
.B(B),
.Y(partial[i])
);
// TODO: Currently a 'cascade' approach to summing the partial
// products is taken here, but a more efficient 'binary
// reduction' approach also exists...
if (i == 0)
assign partial_sum[i] = partial[i];
else
assign partial_sum[i] = (partial[i] << (* mul2dsp *) i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[i-1];
end
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(last_A_WIDTH),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(last_Y_WIDTH)
) sliceA.last (
.A(A[A_WIDTH-1 -: last_A_WIDTH]),
.B(B),
.Y(last_partial)
);
assign partial_sum[n] = (last_partial << (* mul2dsp *) n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[n-1];
assign Y = partial_sum[n];
end
else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
localparam n = (B_WIDTH-`DSP_B_MAXWIDTH+`DSP_B_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH_PARTIAL);
localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
wire signed [last_Y_WIDTH-1:0] last_partial;
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
wire [last_Y_WIDTH-1:0] last_partial;
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
for (i = 0; i < n; i=i+1) begin:sliceB
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(sign_headroom),
.A_WIDTH(A_WIDTH),
.B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL),
.Y_WIDTH(partial_Y_WIDTH)
) mul (
.A(A),
.B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}),
.Y(partial[i])
);
// TODO: Currently a 'cascade' approach to summing the partial
// products is taken here, but a more efficient 'binary
// reduction' approach also exists...
if (i == 0)
assign partial_sum[i] = partial[i];
else
assign partial_sum[i] = (partial[i] << (* mul2dsp *) i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[i-1];
end
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
.B_WIDTH(last_B_WIDTH),
.Y_WIDTH(last_Y_WIDTH)
) mul_sliceB_last (
.A(A),
.B(B[B_WIDTH-1 -: last_B_WIDTH]),
.Y(last_partial)
);
assign partial_sum[n] = (last_partial << (* mul2dsp *) n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + (* mul2dsp *) partial_sum[n-1];
assign Y = partial_sum[n];
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(`MIN(Y_WIDTH,`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)),
) _TECHMAP_REPLACE_ (
.A(Aext),
.B(Bext),
.Y(Y)
);
end
end
endgenerate
endmodule
(* techmap_celltype = "$mul $__mul" *)
module _90_soft_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;
// Indirection necessary since mapping
// back to $mul will cause recursion
generate
if (A_SIGNED && !B_SIGNED)
\$__soft_mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(1),
.A_WIDTH(A_WIDTH),
.B_WIDTH(B_WIDTH+1),
.Y_WIDTH(Y_WIDTH)
) _TECHMAP_REPLACE_ (
.A(A),
.B({1'b0,B}),
.Y(Y)
);
else if (!A_SIGNED && B_SIGNED)
\$__soft_mul #(
.A_SIGNED(1),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH+1),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(Y_WIDTH)
) _TECHMAP_REPLACE_ (
.A({1'b0,A}),
.B(B),
.Y(Y)
);
else
\$__soft_mul #(
.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)
);
endgenerate
endmodule

View file

@ -13,6 +13,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_map.v))
$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_unmap.v))

17
techlibs/ecp5/dsp_map.v Normal file
View file

@ -0,0 +1,17 @@
module \$__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;
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(A_SIGNED), .SIGNEDB(B_SIGNED), .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

View file

@ -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(" -nodsp\n");
log(" do not map multipliers to MULT18X18D\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, nodsp, vpr;
void clear_flags() YS_OVERRIDE
{
@ -114,6 +117,7 @@ struct SynthEcp5Pass : public ScriptPass
abc2 = false;
vpr = false;
abc9 = false;
nodsp = 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] == "-nodsp") {
nodsp = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -218,17 +226,34 @@ struct SynthEcp5Pass : public ScriptPass
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
run("tribuf -logic");
run("deminout");
}
if (check_label("coarse"))
{
run("synth -run coarse");
run("proc");
if (flatten || help_mode)
run("flatten");
run("tribuf -logic");
run("deminout");
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 (!nodsp) {
run("techmap -map +/mul2dsp.v -map +/ecp5/dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=$__MUL18X18", "(unless -nodsp)");
run("chtype -set $mul t:$__soft_mul", "(unless -nodsp)");
}
run("alumacc");
run("opt");
run("fsm");
run("opt -fast");
run("memory -nomap");
run("opt_clean");
}
if (!nobram && check_label("map_bram", "(skip if -nobram)"))

View file

@ -27,6 +27,7 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/dsp_map.v))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut))
$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box))

34
techlibs/ice40/dsp_map.v Normal file
View file

@ -0,0 +1,34 @@
module \$__MUL16X16 (input [15:0] A, input [15:0] B, output [31:0] Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
SB_MAC16 #(
.NEG_TRIGGER(1'b0),
.C_REG(1'b0),
.A_REG(1'b0),
.B_REG(1'b0),
.D_REG(1'b0),
.TOP_8x8_MULT_REG(1'b0),
.BOT_8x8_MULT_REG(1'b0),
.PIPELINE_16x16_MULT_REG1(1'b0),
.PIPELINE_16x16_MULT_REG2(1'b0),
.TOPOUTPUT_SELECT(2'b11),
.TOPADDSUB_LOWERINPUT(2'b0),
.TOPADDSUB_UPPERINPUT(1'b0),
.TOPADDSUB_CARRYSELECT(2'b0),
.BOTOUTPUT_SELECT(2'b11),
.BOTADDSUB_LOWERINPUT(2'b0),
.BOTADDSUB_UPPERINPUT(1'b0),
.BOTADDSUB_CARRYSELECT(2'b0),
.MODE_8x8(1'b0),
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED)
) _TECHMAP_REPLACE_ (
.A(A),
.B(B),
.O(Y),
);
endmodule

View file

@ -272,8 +272,18 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
run("opt_expr");
run("opt_clean");
if (help_mode || dsp)
run("ice40_dsp", "(if -dsp)");
if (help_mode || dsp) {
run("techmap -map +/mul2dsp.v -map +/ice40/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 "
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 "
"-D DSP_NAME=$__MUL16X16", "(if -dsp)");
run("select a:mul2dsp", " (if -dsp)");
run("setattr -unset mul2dsp", " (if -dsp)");
run("opt_expr -fine", " (if -dsp)");
run("wreduce", " (if -dsp)");
run("select -clear", " (if -dsp)");
run("ice40_dsp", " (if -dsp)");
run("chtype -set $mul t:$__soft_mul", "(if -dsp)");
}
run("alumacc");
run("opt");
run("fsm");

View file

@ -42,6 +42,7 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_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_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_unmap.v))

View file

@ -22,11 +22,11 @@
module RAM32X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
(* techmap_autopurge *) input D,
(* techmap_autopurge *) input WCLK,
(* techmap_autopurge *) input WE,
(* techmap_autopurge *) input A0, A1, A2, A3, A4,
(* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
parameter INIT = 32'h0;
parameter IS_WCLK_INVERTED = 1'b0;
@ -45,11 +45,11 @@ endmodule
module RAM64X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
(* techmap_autopurge *) input D,
(* techmap_autopurge *) input WCLK,
(* techmap_autopurge *) input WE,
(* techmap_autopurge *) input A0, A1, A2, A3, A4, A5,
(* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
parameter INIT = 64'h0;
parameter IS_WCLK_INVERTED = 1'b0;
@ -68,10 +68,10 @@ endmodule
module RAM128X1D (
output DPO, SPO,
input D,
input WCLK,
input WE,
input [6:0] A, DPRA
(* techmap_autopurge *) input D,
(* techmap_autopurge *) input WCLK,
(* techmap_autopurge *) input WE,
(* techmap_autopurge *) input [6:0] A, DPRA
);
parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0;
@ -90,7 +90,7 @@ endmodule
module SRL16E (
output Q,
input A0, A1, A2, A3, CE, CLK, D
(* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
@ -107,8 +107,8 @@ endmodule
module SRLC32E (
output Q,
output Q31,
input [4:0] A,
input CE, CLK, D
(* techmap_autopurge *) input [4:0] A,
(* techmap_autopurge *) input CE, CLK, D
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
@ -121,3 +121,327 @@ module SRLC32E (
);
\$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q));
endmodule
module DSP48E1 (
(* techmap_autopurge *) output [29:0] ACOUT,
(* techmap_autopurge *) output [17:0] BCOUT,
(* techmap_autopurge *) output reg CARRYCASCOUT,
(* techmap_autopurge *) output reg [3:0] CARRYOUT,
(* techmap_autopurge *) output reg MULTSIGNOUT,
(* techmap_autopurge *) output OVERFLOW,
(* techmap_autopurge *) output reg signed [47:0] P,
(* techmap_autopurge *) output PATTERNBDETECT,
(* techmap_autopurge *) output PATTERNDETECT,
(* techmap_autopurge *) output [47:0] PCOUT,
(* techmap_autopurge *) output UNDERFLOW,
(* techmap_autopurge *) input signed [29:0] A,
(* techmap_autopurge *) input [29:0] ACIN,
(* techmap_autopurge *) input [3:0] ALUMODE,
(* techmap_autopurge *) input signed [17:0] B,
(* techmap_autopurge *) input [17:0] BCIN,
(* techmap_autopurge *) input [47:0] C,
(* techmap_autopurge *) input CARRYCASCIN,
(* techmap_autopurge *) input CARRYIN,
(* techmap_autopurge *) input [2:0] CARRYINSEL,
(* techmap_autopurge *) input CEA1,
(* techmap_autopurge *) input CEA2,
(* techmap_autopurge *) input CEAD,
(* techmap_autopurge *) input CEALUMODE,
(* techmap_autopurge *) input CEB1,
(* techmap_autopurge *) input CEB2,
(* techmap_autopurge *) input CEC,
(* techmap_autopurge *) input CECARRYIN,
(* techmap_autopurge *) input CECTRL,
(* techmap_autopurge *) input CED,
(* techmap_autopurge *) input CEINMODE,
(* techmap_autopurge *) input CEM,
(* techmap_autopurge *) input CEP,
(* techmap_autopurge *) input CLK,
(* techmap_autopurge *) input [24:0] D,
(* techmap_autopurge *) input [4:0] INMODE,
(* techmap_autopurge *) input MULTSIGNIN,
(* techmap_autopurge *) input [6:0] OPMODE,
(* techmap_autopurge *) input [47:0] PCIN,
(* techmap_autopurge *) input RSTA,
(* techmap_autopurge *) input RSTALLCARRYIN,
(* techmap_autopurge *) input RSTALUMODE,
(* techmap_autopurge *) input RSTB,
(* techmap_autopurge *) input RSTC,
(* techmap_autopurge *) input RSTCTRL,
(* techmap_autopurge *) input RSTD,
(* techmap_autopurge *) input RSTINMODE,
(* techmap_autopurge *) input RSTM,
(* techmap_autopurge *) 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;
parameter _TECHMAP_CELLTYPE_ = "";
localparam techmap_guard = (_TECHMAP_CELLTYPE_ != "");
`define DSP48E1_INST(__CELL__) """
__CELL__ #(
.ACASCREG(ACASCREG),
.ADREG(ADREG),
.ALUMODEREG(ALUMODEREG),
.AREG(AREG),
.AUTORESET_PATDET(AUTORESET_PATDET),
.A_INPUT(A_INPUT),
.BCASCREG(BCASCREG),
.BREG(BREG),
.B_INPUT(B_INPUT),
.CARRYINREG(CARRYINREG),
.CARRYINSELREG(CARRYINSELREG),
.CREG(CREG),
.DREG(DREG),
.INMODEREG(INMODEREG),
.MREG(MREG),
.OPMODEREG(OPMODEREG),
.PREG(PREG),
.SEL_MASK(SEL_MASK),
.SEL_PATTERN(SEL_PATTERN),
.USE_DPORT(USE_DPORT),
.USE_MULT(USE_MULT),
.USE_PATTERN_DETECT(USE_PATTERN_DETECT),
.USE_SIMD(USE_SIMD),
.MASK(MASK),
.PATTERN(PATTERN),
.IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
.IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
.IS_CLK_INVERTED(IS_CLK_INVERTED),
.IS_INMODE_INVERTED(IS_INMODE_INVERTED),
.IS_OPMODE_INVERTED(IS_OPMODE_INVERTED)
) _TECHMAP_REPLACE_ (
.ACOUT(ACOUT),
.BCOUT(BCOUT),
.CARRYCASCOUT(CARRYCASCOUT),
.CARRYOUT(CARRYOUT),
.MULTSIGNOUT(MULTSIGNOUT),
.OVERFLOW(OVERFLOW),
.P(oP),
.PATTERNBDETECT(PATTERNBDETECT),
.PATTERNDETECT(PATTERNDETECT),
.PCOUT(oPCOUT),
.UNDERFLOW(UNDERFLOW),
.A(iA),
.ACIN(ACIN),
.ALUMODE(ALUMODE),
.B(iB),
.BCIN(BCIN),
.C(iC),
.CARRYCASCIN(CARRYCASCIN),
.CARRYIN(CARRYIN),
.CARRYINSEL(CARRYINSEL),
.CEA1(CEA1),
.CEA2(CEA2),
.CEAD(CEAD),
.CEALUMODE(CEALUMODE),
.CEB1(CEB1),
.CEB2(CEB2),
.CEC(CEC),
.CECARRYIN(CECARRYIN),
.CECTRL(CECTRL),
.CED(CED),
.CEINMODE(CEINMODE),
.CEM(CEM),
.CEP(CEP),
.CLK(CLK),
.D(iD),
.INMODE(INMODE),
.MULTSIGNIN(MULTSIGNIN),
.OPMODE(OPMODE),
.PCIN(PCIN),
.RSTA(RSTA),
.RSTALLCARRYIN(RSTALLCARRYIN),
.RSTALUMODE(RSTALUMODE),
.RSTB(RSTB),
.RSTC(RSTC),
.RSTCTRL(RSTCTRL),
.RSTD(RSTD),
.RSTINMODE(RSTINMODE),
.RSTM(RSTM),
.RSTP(RSTP)
);
"""
wire [29:0] iA;
wire [17:0] iB;
wire [47:0] iC;
wire [24:0] iD;
wire pA, pB, pC, pD, pAD, pM, pP;
wire [47:0] oP, mP;
wire [47:0] oPCOUT, mPCOUT;
generate
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
// Disconnect the A-input if MREG is enabled, since
// combinatorial path is broken
if (AREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx;
else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx;
else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx;
else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0)
assign iD = D;
else if (techmap_guard)
$error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
assign pD = 1'bx;
if (ADREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
assign pAD = 1'bx;
if (PREG == 0) begin
if (MREG == 1)
\$__ABC_REG rM (.Q(pM));
else
assign pM = 1'bx;
assign pP = 1'bx;
end else begin
assign pM = 1'bx;
\$__ABC_REG rP (.Q(pP));
end
if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT;
else
assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_MULT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
);
\$__ABC_DSP48E1_MULT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
);
`DSP48E1_INST(\$__ABC_DSP48E1_MULT )
end
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
// Disconnect the A-input if MREG is enabled, since
// combinatorial path is broken
if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx;
else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx;
else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx;
else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0 && ADREG == 0)
assign iD = D, pD = 1'bx;
else
\$__ABC_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD));
if (PREG == 0) begin
if (MREG == 1) begin
assign pAD = 1'bx;
\$__ABC_REG rM (.Q(pM));
end else begin
if (ADREG == 1)
\$__ABC_REG rAD (.Q(pAD));
else
assign pAD = 1'bx;
assign pM = 1'bx;
end
assign pP = 1'bx;
end else begin
assign pAD = 1'bx, pM = 1'bx;
\$__ABC_REG rP (.Q(pP));
end
if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT;
else
assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_MULT_DPORT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
);
\$__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
);
`DSP48E1_INST(\$__ABC_DSP48E1_MULT_DPORT )
end
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
// Disconnect the A-input if MREG is enabled, since
// combinatorial path is broken
if (AREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx;
else
\$__ABC_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx;
else
\$__ABC_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx;
else
\$__ABC_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
assign pD = 1'bx;
if (ADREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
assign pAD = 1'bx;
if (MREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\"");
assign pM = 1'bx;
if (PREG == 1)
\$__ABC_REG rP (.Q(pP));
else
assign pP = 1'bx;
if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT;
else
assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC_DSP48E1_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
);
\$__ABC_DSP48E1_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
);
`DSP48E1_INST(\$__ABC_DSP48E1 )
end
else
$error("Invalid DSP48E1 configuration");
endgenerate
`undef DSP48E1_INST
endmodule

View file

@ -20,15 +20,171 @@
// ============================================================================
// Box containing MUXF7.[AB] + MUXF8,
// Necessary to make these an atomic unit so that
// ABC cannot optimise just one of the MUXF7 away
// and expect to save on its delay
(* abc_box_id = 3, lib_whitebox *)
module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
assign O = S1 ? (S0 ? I3 : I2)
: (S0 ? I1 : I0);
endmodule
// Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
// Necessary since RAMD* and SRL* have both combinatorial (i.e.
// same-cycle read operation) and sequential (write operation
// is only committed on the next clock edge).
// To model the combinatorial path, such cells have to be split
// into comb and seq parts, with this box modelling only the former.
(* abc_box_id=2000 *)
module \$__ABC_LUT6 (input A, input [5:0] S, output Y);
endmodule
// Box to emulate comb/seq behaviour of RAMD128
(* abc_box_id=2001 *)
module \$__ABC_LUT7 (input A, input [6:0] S, output Y);
endmodule
// Modules used to model the comb/seq behaviour of DSP48E1
// With abc_map.v responsible for splicing the below modules
// between the combinatorial DSP48E1 box (e.g. disconnecting
// A when AREG, MREG or PREG is enabled and splicing in the
// "$__ABC_DSP48E1_REG" blackbox as "REG" in the diagram below)
// this acts to first disables the combinatorial path (as there
// is no connectivity through REG), and secondly, since this is
// blackbox a new PI will be introduced with an arrival time of
// zero.
// Note: Since these "$__ABC_DSP48E1_REG" modules are of a
// sequential nature, they are not passed as a box to ABC and
// (desirably) represented as PO/PIs.
//
// At the DSP output, we place a blackbox mux ("M" in the diagram
// below) to capture the fact that the critical-path could come
// from any one of its inputs.
// In contrast to "REG", the "$__ABC_DSP48E1_*_MUX" modules are
// combinatorial blackboxes that do get passed to ABC.
// The propagation delay through this box (specified in the box
// file) captures the arrival time of the register (i.e.
// propagation from AREG to P after clock edge), or zero delay
// for the combinatorial path from the DSP.
//
// Doing so should means that ABC is able to analyse the
// worst-case delay through to P, regardless of if it was
// through any combinatorial paths (e.g. B, below) or an
// internal register (A2REG).
// However, the true value of being as complete as this is
// questionable since if AREG=1 and BREG=0 (as below)
// then the worse-case path would very likely be through B
// and very unlikely to be through AREG.Q...?
//
// In graphical form:
//
// +-----+
// +------>> REG >>----+
// | +-----+ |
// | |
// | +---------+ | __
// A >>-+X X-| | +--| \
// | DSP48E1 |P | M |--->> P
// | AREG=1 |-------|__/
// B >>------| |
// +---------+
//
`define ABC_DSP48E1_MUX(__NAME__) """
module __NAME__ (input Aq, ADq, Bq, Cq, Dq, input [47:0] I, input Mq, input [47:0] P, input Pq, output [47:0] O);
endmodule
"""
(* abc_box_id=2100 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_P_MUX )
(* abc_box_id=2101 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_PCOUT_MUX )
(* abc_box_id=2102 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_DPORT_P_MUX )
(* abc_box_id=2103 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX )
(* abc_box_id=2104 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_P_MUX )
(* abc_box_id=2105 *) `ABC_DSP48E1_MUX(\$__ABC_DSP48E1_PCOUT_MUX )
`define ABC_DSP48E1(__NAME__) """
module __NAME__ (
output [29:0] ACOUT,
output [17:0] BCOUT,
output reg CARRYCASCOUT,
output reg [3:0] CARRYOUT,
output reg 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;
endmodule
"""
(* abc_box_id=3000 *) `ABC_DSP48E1(\$__ABC_DSP48E1_MULT )
(* abc_box_id=3001 *) `ABC_DSP48E1(\$__ABC_DSP48E1_MULT_DPORT )
(* abc_box_id=3002 *) `ABC_DSP48E1(\$__ABC_DSP48E1 )

View file

@ -26,3 +26,186 @@ endmodule
module \$__ABC_LUT7 (input A, input [6:0] S, output Y);
assign Y = A;
endmodule
module \$__ABC_REG (input [WIDTH-1:0] I, output [WIDTH-1:0] O, output Q);
parameter WIDTH = 1;
assign O = I;
endmodule
(* techmap_celltype = "$__ABC_DSP48E1_MULT_P_MUX $__ABC_DSP48E1_MULT_PCOUT_MUX $__ABC_DSP48E1_MULT_DPORT_P_MUX $__ABC_DSP48E1_MULT_DPORT_PCOUT_MUX $__ABC_DSP48E1_P_MUX $__ABC_DSP48E1_PCOUT_MUX" *)
module \$__ABC_DSP48E1_MUX (
input Aq, Bq, Cq, Dq, ADq,
input [47:0] I,
input Mq,
input [47:0] P,
input Pq,
output [47:0] O
);
assign O = I;
endmodule
(* techmap_celltype = "$__ABC_DSP48E1_MULT $__ABC_DSP48E1_MULT_DPORT $__ABC_DSP48E1" *)
module \$__ABC_DSP48E1 (
(* techmap_autopurge *) output [29:0] ACOUT,
(* techmap_autopurge *) output [17:0] BCOUT,
(* techmap_autopurge *) output reg CARRYCASCOUT,
(* techmap_autopurge *) output reg [3:0] CARRYOUT,
(* techmap_autopurge *) output reg MULTSIGNOUT,
(* techmap_autopurge *) output OVERFLOW,
(* techmap_autopurge *) output reg signed [47:0] P,
(* techmap_autopurge *) output PATTERNBDETECT,
(* techmap_autopurge *) output PATTERNDETECT,
(* techmap_autopurge *) output [47:0] PCOUT,
(* techmap_autopurge *) output UNDERFLOW,
(* techmap_autopurge *) input signed [29:0] A,
(* techmap_autopurge *) input [29:0] ACIN,
(* techmap_autopurge *) input [3:0] ALUMODE,
(* techmap_autopurge *) input signed [17:0] B,
(* techmap_autopurge *) input [17:0] BCIN,
(* techmap_autopurge *) input [47:0] C,
(* techmap_autopurge *) input CARRYCASCIN,
(* techmap_autopurge *) input CARRYIN,
(* techmap_autopurge *) input [2:0] CARRYINSEL,
(* techmap_autopurge *) input CEA1,
(* techmap_autopurge *) input CEA2,
(* techmap_autopurge *) input CEAD,
(* techmap_autopurge *) input CEALUMODE,
(* techmap_autopurge *) input CEB1,
(* techmap_autopurge *) input CEB2,
(* techmap_autopurge *) input CEC,
(* techmap_autopurge *) input CECARRYIN,
(* techmap_autopurge *) input CECTRL,
(* techmap_autopurge *) input CED,
(* techmap_autopurge *) input CEINMODE,
(* techmap_autopurge *) input CEM,
(* techmap_autopurge *) input CEP,
(* techmap_autopurge *) input CLK,
(* techmap_autopurge *) input [24:0] D,
(* techmap_autopurge *) input [4:0] INMODE,
(* techmap_autopurge *) input MULTSIGNIN,
(* techmap_autopurge *) input [6:0] OPMODE,
(* techmap_autopurge *) input [47:0] PCIN,
(* techmap_autopurge *) input RSTA,
(* techmap_autopurge *) input RSTALLCARRYIN,
(* techmap_autopurge *) input RSTALUMODE,
(* techmap_autopurge *) input RSTB,
(* techmap_autopurge *) input RSTC,
(* techmap_autopurge *) input RSTCTRL,
(* techmap_autopurge *) input RSTD,
(* techmap_autopurge *) input RSTINMODE,
(* techmap_autopurge *) input RSTM,
(* techmap_autopurge *) 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;
DSP48E1 #(
.ACASCREG(ACASCREG),
.ADREG(ADREG),
.ALUMODEREG(ALUMODEREG),
.AREG(AREG),
.AUTORESET_PATDET(AUTORESET_PATDET),
.A_INPUT(A_INPUT),
.BCASCREG(BCASCREG),
.BREG(BREG),
.B_INPUT(B_INPUT),
.CARRYINREG(CARRYINREG),
.CARRYINSELREG(CARRYINSELREG),
.CREG(CREG),
.DREG(DREG),
.INMODEREG(INMODEREG),
.MREG(MREG),
.OPMODEREG(OPMODEREG),
.PREG(PREG),
.SEL_MASK(SEL_MASK),
.SEL_PATTERN(SEL_PATTERN),
.USE_DPORT(USE_DPORT),
.USE_MULT(USE_MULT),
.USE_PATTERN_DETECT(USE_PATTERN_DETECT),
.USE_SIMD(USE_SIMD),
.MASK(MASK),
.PATTERN(PATTERN),
.IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
.IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
.IS_CLK_INVERTED(IS_CLK_INVERTED),
.IS_INMODE_INVERTED(IS_INMODE_INVERTED),
.IS_OPMODE_INVERTED(IS_OPMODE_INVERTED)
) _TECHMAP_REPLACE_ (
.ACOUT(ACOUT),
.BCOUT(BCOUT),
.CARRYCASCOUT(CARRYCASCOUT),
.CARRYOUT(CARRYOUT),
.MULTSIGNOUT(MULTSIGNOUT),
.OVERFLOW(OVERFLOW),
.P(P),
.PATTERNBDETECT(PATTERNBDETECT),
.PATTERNDETECT(PATTERNDETECT),
.PCOUT(PCOUT),
.UNDERFLOW(UNDERFLOW),
.A(A),
.ACIN(ACIN),
.ALUMODE(ALUMODE),
.B(B),
.BCIN(BCIN),
.C(C),
.CARRYCASCIN(CARRYCASCIN),
.CARRYIN(CARRYIN),
.CARRYINSEL(CARRYINSEL),
.CEA1(CEA1),
.CEA2(CEA2),
.CEAD(CEAD),
.CEALUMODE(CEALUMODE),
.CEB1(CEB1),
.CEB2(CEB2),
.CEC(CEC),
.CECARRYIN(CECARRYIN),
.CECTRL(CECTRL),
.CED(CED),
.CEINMODE(CEINMODE),
.CEM(CEM),
.CEP(CEP),
.CLK(CLK),
.D(D),
.INMODE(INMODE),
.MULTSIGNIN(MULTSIGNIN),
.OPMODE(OPMODE),
.PCIN(PCIN),
.RSTA(RSTA),
.RSTALLCARRYIN(RSTALLCARRYIN),
.RSTALUMODE(RSTALUMODE),
.RSTB(RSTB),
.RSTC(RSTC),
.RSTCTRL(RSTCTRL),
.RSTD(RSTD),
.RSTINMODE(RSTINMODE),
.RSTM(RSTM),
.RSTP(RSTP)
);
endmodule

File diff suppressed because it is too large Load diff

View file

@ -525,3 +525,466 @@ 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 reg CARRYCASCOUT,
output reg [3:0] CARRYOUT,
output reg MULTSIGNOUT,
output OVERFLOW,
output reg signed [47:0] P,
output reg PATTERNBDETECT,
output reg 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,
(* clkbuf_sink *) 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 (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
if (USE_SIMD != "ONE48" && USE_SIMD != "TWO24" && USE_SIMD != "FOUR12") $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
wire signed [29:0] A_muxed;
wire signed [17:0] B_muxed;
generate
if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
else assign A_muxed = A;
if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
else assign B_muxed = B;
endgenerate
reg signed [29:0] Ar1, Ar2;
reg signed [24:0] Dr;
reg signed [17:0] Br1, Br2;
reg signed [47:0] Cr;
reg [4:0] INMODEr = 5'b0;
reg [6:0] OPMODEr = 7'b0;
reg [3:0] ALUMODEr = 4'b0;
reg [2:0] CARRYINSELr = 3'b0;
generate
// Configurable A register
if (AREG == 2) begin
initial Ar1 = 30'b0;
initial Ar2 = 30'b0;
always @(posedge CLK)
if (RSTA) begin
Ar1 <= 30'b0;
Ar2 <= 30'b0;
end else begin
if (CEA1) Ar1 <= A_muxed;
if (CEA2) Ar2 <= Ar1;
end
end else if (AREG == 1) begin
//initial Ar1 = 30'b0;
initial Ar2 = 30'b0;
always @(posedge CLK)
if (RSTA) begin
Ar1 <= 30'b0;
Ar2 <= 30'b0;
end else begin
if (CEA1) Ar1 <= A_muxed;
if (CEA2) Ar2 <= A_muxed;
end
end else begin
always @* Ar1 <= A_muxed;
always @* Ar2 <= A_muxed;
end
// Configurable B register
if (BREG == 2) begin
initial Br1 = 25'b0;
initial Br2 = 25'b0;
always @(posedge CLK)
if (RSTB) begin
Br1 <= 18'b0;
Br2 <= 18'b0;
end else begin
if (CEB1) Br1 <= B_muxed;
if (CEB2) Br2 <= Br1;
end
end else if (BREG == 1) begin
//initial Br1 = 25'b0;
initial Br2 = 25'b0;
always @(posedge CLK)
if (RSTB) begin
Br1 <= 18'b0;
Br2 <= 18'b0;
end else begin
if (CEB1) Br1 <= B_muxed;
if (CEB2) Br2 <= B_muxed;
end
end else begin
always @* Br1 <= B_muxed;
always @* Br2 <= B_muxed;
end
// C and D registers
if (CREG == 1) initial Cr = 48'b0;
if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= C; end
else always @* Cr <= C;
if (CREG == 1) initial Dr = 25'b0;
if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
else always @* Dr <= D;
// Control registers
if (INMODEREG == 1) initial INMODEr = 5'b0;
if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
else always @* INMODEr <= INMODE;
if (OPMODEREG == 1) initial OPMODEr = 7'b0;
if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
else always @* OPMODEr <= OPMODE;
if (ALUMODEREG == 1) initial ALUMODEr = 4'b0;
if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
else always @* ALUMODEr <= ALUMODE;
if (CARRYINSELREG == 1) initial CARRYINSELr = 3'b0;
if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
else always @* CARRYINSELr <= CARRYINSEL;
endgenerate
// A and B cascade
generate
if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
else assign ACOUT = Ar2;
if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
else assign BCOUT = Br2;
endgenerate
// A/D input selection and pre-adder
wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
wire signed [24:0] Dr_gated = INMODEr[2] ? Dr : 25'b0;
wire signed [24:0] AD_result = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated);
reg signed [24:0] ADr;
generate
if (ADREG == 1) initial ADr = 25'b0;
if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
else always @* ADr <= AD_result;
endgenerate
// 25x18 multiplier
wire signed [24:0] A_MULT;
wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
generate
if (USE_DPORT == "TRUE") assign A_MULT = ADr;
else assign A_MULT = Ar12_gated;
endgenerate
wire signed [42:0] M = A_MULT * B_MULT;
wire signed [42:0] Mx = (CARRYINSEL == 3'b010) ? 43'bx : M;
reg signed [42:0] Mr = 43'b0;
// Multiplier result register
generate
if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= Mx; end
else always @* Mr <= Mx;
endgenerate
wire signed [42:0] Mrx = (CARRYINSELr == 3'b010) ? 43'bx : Mr;
// X, Y and Z ALU inputs
reg signed [47:0] X, Y, Z;
always @* begin
// X multiplexer
case (OPMODEr[1:0])
2'b00: X = 48'b0;
2'b01: begin X = $signed(Mrx);
`ifdef __ICARUS__
if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
`endif
end
2'b10: begin X = P;
`ifdef __ICARUS__
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
`endif
end
2'b11: X = $signed({Ar2, Br2});
default: X = 48'bx;
endcase
// Y multiplexer
case (OPMODEr[3:2])
2'b00: Y = 48'b0;
2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
`ifdef __ICARUS__
if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
`endif
end
2'b10: Y = {48{1'b1}};
2'b11: Y = Cr;
default: Y = 48'bx;
endcase
// Z multiplexer
case (OPMODEr[6:4])
3'b000: Z = 48'b0;
3'b001: Z = PCIN;
3'b010: begin Z = P;
`ifdef __ICARUS__
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
`endif
end
3'b011: Z = Cr;
3'b100: begin Z = P;
`ifdef __ICARUS__
if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
`endif
end
3'b101: Z = $signed(PCIN[47:17]);
3'b110: Z = $signed(P[47:17]);
default: Z = 48'bx;
endcase
end
// Carry in
wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
generate
if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
else always @* CARRYINr = CARRYIN;
if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
else always @* A24_xnor_B17 = A24_xnor_B17d;
endgenerate
reg cin_muxed;
always @(*) begin
case (CARRYINSELr)
3'b000: cin_muxed = CARRYINr;
3'b001: cin_muxed = ~PCIN[47];
3'b010: cin_muxed = CARRYCASCIN;
3'b011: cin_muxed = PCIN[47];
3'b100: cin_muxed = CARRYCASCOUT;
3'b101: cin_muxed = ~P[47];
3'b110: cin_muxed = A24_xnor_B17;
3'b111: cin_muxed = P[47];
default: cin_muxed = 1'bx;
endcase
end
wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
// ALU core
wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 : maj_xyz;
wire [48:0] maj_xyz_simd_gated;
wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
wire [47:0] alu_sum;
assign int_carry_in[0] = 1'b0;
wire [3:0] carryout_reset;
generate
if (USE_SIMD == "FOUR12") begin
assign maj_xyz_simd_gated = {
maj_xyz_gated[47:36],
1'b0, maj_xyz_gated[34:24],
1'b0, maj_xyz_gated[22:12],
1'b0, maj_xyz_gated[10:0],
alu_cin
};
assign int_carry_in[3:1] = 3'b000;
assign ext_carry_out = {
int_carry_out[3],
maj_xyz_gated[35] ^ int_carry_out[2],
maj_xyz_gated[23] ^ int_carry_out[1],
maj_xyz_gated[11] ^ int_carry_out[0]
};
assign carryout_reset = 4'b0000;
end else if (USE_SIMD == "TWO24") begin
assign maj_xyz_simd_gated = {
maj_xyz_gated[47:24],
1'b0, maj_xyz_gated[22:0],
alu_cin
};
assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
assign ext_carry_out = {
int_carry_out[3],
1'bx,
maj_xyz_gated[23] ^ int_carry_out[1],
1'bx
};
assign carryout_reset = 4'b0x0x;
end else begin
assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
assign int_carry_in[3:1] = int_carry_out[2:0];
assign ext_carry_out = {
int_carry_out[3],
3'bxxx
};
assign carryout_reset = 4'b0xxx;
end
genvar i;
for (i = 0; i < 4; i = i + 1)
assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
+ xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
endgenerate
wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
wire CARRYCASCOUTd = ext_carry_out[3];
wire MULTSIGNOUTd = Mrx[42];
generate
if (PREG == 1) begin
initial P = 48'b0;
initial CARRYOUT = carryout_reset;
initial CARRYCASCOUT = 1'b0;
initial MULTSIGNOUT = 1'b0;
always @(posedge CLK)
if (RSTP) begin
P <= 48'b0;
CARRYOUT <= carryout_reset;
CARRYCASCOUT <= 1'b0;
MULTSIGNOUT <= 1'b0;
end else if (CEP) begin
P <= Pd;
CARRYOUT <= CARRYOUTd;
CARRYCASCOUT <= CARRYCASCOUTd;
MULTSIGNOUT <= MULTSIGNOUTd;
end
end else begin
always @* begin
P = Pd;
CARRYOUT = CARRYOUTd;
CARRYCASCOUT = CARRYCASCOUTd;
MULTSIGNOUT = MULTSIGNOUTd;
end
end
endgenerate
assign PCOUT = P;
generate
wire PATTERNDETECTd, PATTERNBDETECTd;
if (USE_PATTERN_DETECT == "PATDET") begin
// TODO: Support SEL_PATTERN != "PATTERN" and SEL_MASK != "MASK
assign PATTERNDETECTd = &(~(Pd ^ PATTERN) | MASK);
assign PATTERNBDETECTd = &((Pd ^ PATTERN) | MASK);
end else begin
assign PATTERNDETECTd = 1'b1;
assign PATTERNBDETECTd = 1'b1;
end
if (PREG == 1) begin
reg PATTERNDETECTPAST, PATTERNBDETECTPAST;
initial PATTERNDETECT = 1'b0;
initial PATTERNBDETECT = 1'b0;
initial PATTERNDETECTPAST = 1'b0;
initial PATTERNBDETECTPAST = 1'b0;
always @(posedge CLK)
if (RSTP) begin
PATTERNDETECT <= 1'b0;
PATTERNBDETECT <= 1'b0;
PATTERNDETECTPAST <= 1'b0;
PATTERNBDETECTPAST <= 1'b0;
end else if (CEP) begin
PATTERNDETECT <= PATTERNDETECTd;
PATTERNBDETECT <= PATTERNBDETECTd;
PATTERNDETECTPAST <= PATTERNDETECT;
PATTERNBDETECTPAST <= PATTERNBDETECT;
end
assign OVERFLOW = &{PATTERNDETECTPAST, ~PATTERNBDETECT, ~PATTERNDETECT};
assign UNDERFLOW = &{PATTERNBDETECTPAST, ~PATTERNBDETECT, ~PATTERNDETECT};
end else begin
always @* begin
PATTERNDETECT = PATTERNDETECTd;
PATTERNBDETECT = PATTERNBDETECTd;
end
assign OVERFLOW = 1'bx, UNDERFLOW = 1'bx;
end
endgenerate
endmodule

49
techlibs/xilinx/dsp_map.v Normal file
View file

@ -0,0 +1,49 @@
module \$__MUL25X18 (input [24:0] A, input [17:0] B, output [42:0] Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
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),
.USE_MULT("MULTIPLY"),
.USE_SIMD("ONE48"),
.USE_DPORT("FALSE")
) _TECHMAP_REPLACE_ (
//Data path
.A({{5{A[24]}}, A}),
.B(B),
.C(48'b0),
.D(25'b0),
.P(P_48),
.INMODE(5'b00000),
.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

View file

@ -81,6 +81,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(" -iopad\n");
log(" enable I/O buffer insertion (selected automatically by -ise)\n");
log("\n");
@ -116,7 +119,7 @@ struct SynthXilinxPass : public ScriptPass
}
std::string top_opt, edif_file, blif_file, family;
bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9;
bool flatten_before_abc;
int widemux;
@ -139,6 +142,7 @@ struct SynthXilinxPass : public ScriptPass
nosrl = false;
nocarry = false;
nowidelut = false;
nodsp = false;
abc9 = false;
flatten_before_abc = false;
widemux = 0;
@ -240,6 +244,10 @@ struct SynthXilinxPass : public ScriptPass
abc9 = true;
continue;
}
if (args[argidx] == "-nodsp") {
nodsp = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -302,10 +310,10 @@ struct SynthXilinxPass : public ScriptPass
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
if (check_label("coarse")) {
if (check_label("prepare")) {
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");
@ -329,6 +337,26 @@ struct SynthXilinxPass : public ScriptPass
}
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
}
if (check_label("map_dsp"), "(skip if '-nodsp')") {
if (!nodsp || help_mode) {
// NB: Xilinx multipliers are signed only
run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 "
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18");
run("select a:mul2dsp");
run("setattr -unset mul2dsp");
run("opt_expr -fine");
run("wreduce");
run("select -clear");
run("xilinx_dsp");
run("chtype -set $mul t:$__soft_mul");
}
}
if (check_label("coarse")) {
run("alumacc");
run("share");
run("opt");

View file

@ -4,3 +4,8 @@ bram1_[0-9]*/
bram2.log
bram2_syn.v
bram2_tb
dsp_work*/
test_dsp_model_ref.v
test_dsp_model_uut.v
test_dsp_model
*.vcd

View file

@ -0,0 +1,14 @@
#!/bin/bash
set -ex
sed 's/DSP48E1/DSP48E1_UUT/; /DSP48E1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
if [ ! -f "test_dsp_model_ref.v" ]; then
cat /opt/Xilinx/Vivado/2019.1/data/verilog/src/unisims/DSP48E1.v > test_dsp_model_ref.v
fi
for tb in macc_overflow_underflow \
simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \
mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \
mult_allreg_preadd_nocasc mult_noreg_preadd_nocasc mult_inreg_preadd_nocasc
do
iverilog -s $tb -s glbl -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v /opt/Xilinx/Vivado/2019.1/data/verilog/src/glbl.v
vvp -N ./test_dsp_model
done

View file

@ -0,0 +1,652 @@
`timescale 1ns / 1ps
module testbench;
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;
reg CLK;
reg CEA1, CEA2, CEAD, CEALUMODE, CEB1, CEB2, CEC, CECARRYIN, CECTRL;
reg CED, CEINMODE, CEM, CEP;
reg RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP;
reg [29:0] A, ACIN;
reg [17:0] B, BCIN;
reg [47:0] C;
reg [24:0] D;
reg [47:0] PCIN;
reg [3:0] ALUMODE;
reg [2:0] CARRYINSEL;
reg [4:0] INMODE;
reg [6:0] OPMODE;
reg CARRYCASCIN, CARRYIN, MULTSIGNIN;
output [29:0] ACOUT, REF_ACOUT;
output [17:0] BCOUT, REF_BCOUT;
output CARRYCASCOUT, REF_CARRYCASCOUT;
output [3:0] CARRYOUT, REF_CARRYOUT;
output MULTSIGNOUT, REF_MULTSIGNOUT;
output OVERFLOW, REF_OVERFLOW;
output [47:0] P, REF_P;
output PATTERNBDETECT, REF_PATTERNBDETECT;
output PATTERNDETECT, REF_PATTERNDETECT;
output [47:0] PCOUT, REF_PCOUT;
output UNDERFLOW, REF_UNDERFLOW;
integer errcount = 0;
reg ERROR_FLAG = 0;
task clkcycle;
begin
#5;
CLK = ~CLK;
#10;
CLK = ~CLK;
#2;
ERROR_FLAG = 0;
if (REF_P !== P) begin
$display("ERROR at %1t: REF_P=%b UUT_P=%b DIFF=%b", $time, REF_P, P, REF_P ^ P);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_CARRYOUT !== CARRYOUT) begin
$display("ERROR at %1t: REF_CARRYOUT=%b UUT_CARRYOUT=%b", $time, REF_CARRYOUT, CARRYOUT);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_PATTERNDETECT !== PATTERNDETECT) begin
$display("ERROR at %1t: REF_PATTERNDETECT=%b UUT_PATTERNDETECT=%b DIFF=%b REF_P=%b P=%b", $time, REF_PATTERNDETECT, PATTERNDETECT, REF_PATTERNDETECT ^ PATTERNDETECT, REF_P, P);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_PATTERNBDETECT !== PATTERNBDETECT) begin
$display("ERROR at %1t: REF_PATTERNBDETECT=%b UUT_PATTERNBDETECT=%b DIFF=%b", $time, REF_PATTERNBDETECT, PATTERNBDETECT, REF_PATTERNBDETECT ^ PATTERNBDETECT);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_OVERFLOW !== OVERFLOW) begin
$display("ERROR at %1t: REF_OVERFLOW=%b UUT_OVERFLOW=%b DIFF=%b", $time, REF_OVERFLOW, OVERFLOW, REF_OVERFLOW ^ OVERFLOW);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_UNDERFLOW !== UNDERFLOW) begin
$display("ERROR at %1t: REF_UNDERFLOW=%b UUT_UNDERFLOW=%b DIFF=%b", $time, REF_UNDERFLOW, UNDERFLOW, REF_UNDERFLOW ^ UNDERFLOW);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
#3;
end
endtask
reg config_valid = 0;
task drc;
begin
config_valid = 1;
if (AREG != 2 && INMODE[0]) config_valid = 0;
if (BREG != 2 && INMODE[4]) config_valid = 0;
if (USE_SIMD != "ONE48" && OPMODE[3:0] == 4'b0101) config_valid = 0;
if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
if ((OPMODE[3:2] == 2'b01) ^ (OPMODE[1:0] == 2'b01) == 1'b1) config_valid = 0;
if ((OPMODE[6:4] == 3'b010 || OPMODE[6:4] == 3'b110) && PREG != 1) config_valid = 0;
if ((OPMODE[6:4] == 3'b100) && (PREG != 1 || OPMODE[3:0] != 4'b1000 || ALUMODE[3:2] == 2'b01 || ALUMODE[3:2] == 2'b11)) config_valid = 0;
if ((CARRYINSEL == 3'b100 || CARRYINSEL == 3'b101 || CARRYINSEL == 3'b111) && (PREG != 1)) config_valid = 0;
if (OPMODE[6:4] == 3'b111) config_valid = 0;
if ((OPMODE[3:0] == 4'b0101) && CARRYINSEL == 3'b010) config_valid = 0;
if (CARRYINSEL == 3'b000 && OPMODE == 7'b1001000) config_valid = 0;
if ((ALUMODE[3:2] == 2'b01 || ALUMODE[3:2] == 2'b11) && OPMODE[3:2] != 2'b00 && OPMODE[3:2] != 2'b10) config_valid = 0;
end
endtask
initial begin
$dumpfile("test_dsp_model.vcd");
$dumpvars(0, testbench);
#2;
CLK = 1'b0;
{CEA1, CEA2, CEAD, CEALUMODE, CEB1, CEB2, CEC, CECARRYIN, CECTRL} = 9'b111111111;
{CED, CEINMODE, CEM, CEP} = 4'b1111;
{A, B, C, D} = 0;
{ACIN, BCIN, PCIN} = 0;
{ALUMODE, CARRYINSEL, INMODE} = 0;
{OPMODE, CARRYCASCIN, CARRYIN, MULTSIGNIN} = 0;
{RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP} = ~0;
repeat (10) begin
#10;
CLK = 1'b1;
#10;
CLK = 1'b0;
#10;
CLK = 1'b1;
#10;
CLK = 1'b0;
end
{RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP} = 0;
repeat (10000) begin
clkcycle;
config_valid = 0;
while (!config_valid) begin
A = $urandom;
ACIN = $urandom;
B = $urandom;
BCIN = $urandom;
C = {$urandom, $urandom};
D = $urandom;
PCIN = {$urandom, $urandom};
{CEA1, CEA2, CEAD, CEALUMODE, CEB1, CEB2, CEC, CECARRYIN, CECTRL} = $urandom | $urandom | $urandom;
{CED, CEINMODE, CEM, CEP} = $urandom | $urandom | $urandom | $urandom;
// Otherwise we can accidentally create illegal configs
CEINMODE = CECTRL;
CEALUMODE = CECTRL;
{RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
{ALUMODE, INMODE} = $urandom;
CARRYINSEL = $urandom & $urandom & $urandom;
OPMODE = $urandom;
if ($urandom & 1'b1)
OPMODE[3:0] = 4'b0101; // test multiply more than other modes
{CARRYCASCIN, CARRYIN, MULTSIGNIN} = $urandom;
// So few valid options in these modes, just force one valid option
if (CARRYINSEL == 3'b001) OPMODE = 7'b1010101;
if (CARRYINSEL == 3'b010) OPMODE = 7'b0001010;
if (CARRYINSEL == 3'b011) OPMODE = 7'b0011011;
if (CARRYINSEL == 3'b100) OPMODE = 7'b0110011;
if (CARRYINSEL == 3'b101) OPMODE = 7'b0011010;
if (CARRYINSEL == 3'b110) OPMODE = 7'b0010101;
if (CARRYINSEL == 3'b111) OPMODE = 7'b0100011;
drc;
end
end
if (errcount == 0) begin
$display("All tests passed.");
$finish;
end else begin
$display("Caught %1d errors.", errcount);
$stop;
end
end
DSP48E1 #(
.ACASCREG (ACASCREG),
.ADREG (ADREG),
.ALUMODEREG (ALUMODEREG),
.AREG (AREG),
.AUTORESET_PATDET (AUTORESET_PATDET),
.A_INPUT (A_INPUT),
.BCASCREG (BCASCREG),
.BREG (BREG),
.B_INPUT (B_INPUT),
.CARRYINREG (CARRYINREG),
.CARRYINSELREG (CARRYINSELREG),
.CREG (CREG),
.DREG (DREG),
.INMODEREG (INMODEREG),
.MREG (MREG),
.OPMODEREG (OPMODEREG),
.PREG (PREG),
.SEL_MASK (SEL_MASK),
.SEL_PATTERN (SEL_PATTERN),
.USE_DPORT (USE_DPORT),
.USE_MULT (USE_MULT),
.USE_PATTERN_DETECT (USE_PATTERN_DETECT),
.USE_SIMD (USE_SIMD),
.MASK (MASK),
.PATTERN (PATTERN),
.IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
.IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
.IS_CLK_INVERTED (IS_CLK_INVERTED),
.IS_INMODE_INVERTED (IS_INMODE_INVERTED),
.IS_OPMODE_INVERTED (IS_OPMODE_INVERTED)
) ref (
.ACOUT (REF_ACOUT),
.BCOUT (REF_BCOUT),
.CARRYCASCOUT (REF_CARRYCASCOUT),
.CARRYOUT (REF_CARRYOUT),
.MULTSIGNOUT (REF_MULTSIGNOUT),
.OVERFLOW (REF_OVERFLOW),
.P (REF_P),
.PATTERNBDETECT(REF_PATTERNBDETECT),
.PATTERNDETECT (REF_PATTERNDETECT),
.PCOUT (REF_PCOUT),
.UNDERFLOW (REF_UNDERFLOW),
.A (A),
.ACIN (ACIN),
.ALUMODE (ALUMODE),
.B (B),
.BCIN (BCIN),
.C (C),
.CARRYCASCIN (CARRYCASCIN),
.CARRYINSEL (CARRYINSEL),
.CEA1 (CEA1),
.CEA2 (CEA2),
.CEAD (CEAD),
.CEALUMODE (CEALUMODE),
.CEB1 (CEB1),
.CEB2 (CEB2),
.CEC (CEC),
.CECARRYIN (CECARRYIN),
.CECTRL (CECTRL),
.CED (CED),
.CEINMODE (CEINMODE),
.CEM (CEM),
.CEP (CEP),
.CLK (CLK),
.D (D),
.INMODE (INMODE),
.MULTSIGNIN (MULTSIGNIN),
.OPMODE (OPMODE),
.PCIN (PCIN),
.RSTA (RSTA),
.RSTALLCARRYIN (RSTALLCARRYIN),
.RSTALUMODE (RSTALUMODE),
.RSTB (RSTB),
.RSTC (RSTC),
.RSTCTRL (RSTCTRL),
.RSTD (RSTD),
.RSTINMODE (RSTINMODE),
.RSTM (RSTM),
.RSTP (RSTP)
);
DSP48E1_UUT #(
.ACASCREG (ACASCREG),
.ADREG (ADREG),
.ALUMODEREG (ALUMODEREG),
.AREG (AREG),
.AUTORESET_PATDET (AUTORESET_PATDET),
.A_INPUT (A_INPUT),
.BCASCREG (BCASCREG),
.BREG (BREG),
.B_INPUT (B_INPUT),
.CARRYINREG (CARRYINREG),
.CARRYINSELREG (CARRYINSELREG),
.CREG (CREG),
.DREG (DREG),
.INMODEREG (INMODEREG),
.MREG (MREG),
.OPMODEREG (OPMODEREG),
.PREG (PREG),
.SEL_MASK (SEL_MASK),
.SEL_PATTERN (SEL_PATTERN),
.USE_DPORT (USE_DPORT),
.USE_MULT (USE_MULT),
.USE_PATTERN_DETECT (USE_PATTERN_DETECT),
.USE_SIMD (USE_SIMD),
.MASK (MASK),
.PATTERN (PATTERN),
.IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
.IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
.IS_CLK_INVERTED (IS_CLK_INVERTED),
.IS_INMODE_INVERTED (IS_INMODE_INVERTED),
.IS_OPMODE_INVERTED (IS_OPMODE_INVERTED)
) uut (
.ACOUT (ACOUT),
.BCOUT (BCOUT),
.CARRYCASCOUT (CARRYCASCOUT),
.CARRYOUT (CARRYOUT),
.MULTSIGNOUT (MULTSIGNOUT),
.OVERFLOW (OVERFLOW),
.P (P),
.PATTERNBDETECT(PATTERNBDETECT),
.PATTERNDETECT (PATTERNDETECT),
.PCOUT (PCOUT),
.UNDERFLOW (UNDERFLOW),
.A (A),
.ACIN (ACIN),
.ALUMODE (ALUMODE),
.B (B),
.BCIN (BCIN),
.C (C),
.CARRYCASCIN (CARRYCASCIN),
.CARRYINSEL (CARRYINSEL),
.CEA1 (CEA1),
.CEA2 (CEA2),
.CEAD (CEAD),
.CEALUMODE (CEALUMODE),
.CEB1 (CEB1),
.CEB2 (CEB2),
.CEC (CEC),
.CECARRYIN (CECARRYIN),
.CECTRL (CECTRL),
.CED (CED),
.CEINMODE (CEINMODE),
.CEM (CEM),
.CEP (CEP),
.CLK (CLK),
.D (D),
.INMODE (INMODE),
.MULTSIGNIN (MULTSIGNIN),
.OPMODE (OPMODE),
.PCIN (PCIN),
.RSTA (RSTA),
.RSTALLCARRYIN (RSTALLCARRYIN),
.RSTALUMODE (RSTALUMODE),
.RSTB (RSTB),
.RSTC (RSTC),
.RSTCTRL (RSTCTRL),
.RSTD (RSTD),
.RSTINMODE (RSTINMODE),
.RSTM (RSTM),
.RSTP (RSTP)
);
endmodule
module mult_noreg_nopreadd_nocasc;
testbench #(
.ACASCREG (0),
.ADREG (0),
.ALUMODEREG (0),
.AREG (0),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (0),
.BREG (0),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (0),
.DREG (0),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (0),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("FALSE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module mult_allreg_nopreadd_nocasc;
testbench #(
.ACASCREG (1),
.ADREG (1),
.ALUMODEREG (1),
.AREG (2),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (2),
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (1),
.DREG (1),
.INMODEREG (1),
.MREG (1),
.OPMODEREG (1),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("FALSE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module mult_noreg_preadd_nocasc;
testbench #(
.ACASCREG (0),
.ADREG (0),
.ALUMODEREG (0),
.AREG (0),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (0),
.BREG (0),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (0),
.DREG (0),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (0),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module mult_allreg_preadd_nocasc;
testbench #(
.ACASCREG (1),
.ADREG (1),
.ALUMODEREG (1),
.AREG (2),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (2),
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (1),
.DREG (1),
.INMODEREG (1),
.MREG (1),
.OPMODEREG (1),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module mult_inreg_preadd_nocasc;
testbench #(
.ACASCREG (1),
.ADREG (0),
.ALUMODEREG (0),
.AREG (1),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (1),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (1),
.DREG (1),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (0),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module simd12_preadd_noreg_nocasc;
testbench #(
.ACASCREG (0),
.ADREG (0),
.ALUMODEREG (0),
.AREG (0),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (0),
.BREG (0),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (0),
.DREG (0),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (0),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("FOUR12"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module simd24_preadd_noreg_nocasc;
testbench #(
.ACASCREG (0),
.ADREG (0),
.ALUMODEREG (0),
.AREG (0),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (0),
.BREG (0),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (0),
.DREG (0),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (0),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("TWO24"),
.MASK (48'h3FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule
module macc_overflow_underflow;
testbench #(
.ACASCREG (0),
.ADREG (0),
.ALUMODEREG (0),
.AREG (0),
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (0),
.BREG (0),
.B_INPUT ("DIRECT"),
.CARRYINREG (0),
.CARRYINSELREG (0),
.CREG (0),
.DREG (0),
.INMODEREG (0),
.MREG (0),
.OPMODEREG (0),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("FALSE"),
.USE_MULT ("DYNAMIC"),
.USE_PATTERN_DETECT ("PATDET"),
.USE_SIMD ("ONE48"),
.MASK (48'h1FFFFFFFFFFF),
.PATTERN (48'h000000000000),
.IS_ALUMODE_INVERTED(4'b0),
.IS_CARRYIN_INVERTED(1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0)
) testbench ();
endmodule