aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs')
-rw-r--r--techlibs/ecp5/cells_map.v132
-rw-r--r--techlibs/ice40/cells_map.v13
-rw-r--r--techlibs/ice40/ice40_opt.cc4
-rw-r--r--techlibs/intel/synth_intel.cc2
-rw-r--r--techlibs/xilinx/cells_sim.v230
-rw-r--r--techlibs/xilinx/cells_xtra.py2
-rw-r--r--techlibs/xilinx/cells_xtra.v43
-rw-r--r--techlibs/xilinx/lut_map.v99
-rw-r--r--techlibs/xilinx/synth_xilinx.cc14
-rw-r--r--techlibs/xilinx/tests/.gitignore3
-rw-r--r--techlibs/xilinx/tests/test_dsp48_model.sh14
-rw-r--r--techlibs/xilinx/tests/test_dsp48_model.v287
12 files changed, 643 insertions, 200 deletions
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index 10e89a3e0..c031703a9 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -73,102 +73,80 @@ module \$lut (A, Y);
input [WIDTH-1:0] A;
output Y;
- // Need to swap input ordering, and fix init accordingly,
- // to match ABC's expectation of LUT inputs in non-decreasing
- // delay order
- localparam P_WIDTH = WIDTH < 4 ? 4 : WIDTH;
- function [P_WIDTH-1:0] permute_index;
- input [P_WIDTH-1:0] i;
- integer j;
- begin
- permute_index = 0;
- for (j = 0; j < P_WIDTH; j = j + 1)
- permute_index[P_WIDTH-1 - j] = i[j];
- end
- endfunction
-
- function [2**P_WIDTH-1:0] permute_init;
- integer i;
- begin
- permute_init = 0;
- for (i = 0; i < 2**P_WIDTH; i = i + 1)
- permute_init[i] = LUT[permute_index(i)];
- end
- endfunction
-
- parameter [2**P_WIDTH-1:0] P_LUT = permute_init();
-
generate
if (WIDTH == 1) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}};
+ LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
.A(1'b0), .B(1'b0), .C(1'b0), .D(A[0]));
end else
if (WIDTH == 2) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0]));
+ localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}};
+ LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(1'b0), .B(1'b0), .C(A[0]), .D(A[1]));
end else
if (WIDTH == 3) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0]));
+ localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}};
+ LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(1'b0), .B(A[0]), .C(A[1]), .D(A[2]));
end else
if (WIDTH == 4) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y),
- .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0]));
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
`ifndef NO_PFUMUX
end else
if (WIDTH == 5) begin
wire f0, f1;
- LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
- .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
- LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
- .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1]));
- PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y));
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y));
end else
if (WIDTH == 6) begin
wire f0, f1, f2, f3, g0, g1;
- LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
- .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
- LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
- .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
-
- LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
- .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
- LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
- .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2]));
-
- PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0));
- PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1));
- L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y));
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
end else
if (WIDTH == 7) begin
wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
- LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
- LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
-
- LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
- LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
-
- LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
- LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
-
- LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
- LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7),
- .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3]));
-
- PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0));
- PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1));
- PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2));
- PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3));
- L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0));
- L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1));
- L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y));
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2));
+ PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3));
+ L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
+ L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
+ L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
`endif
end else begin
wire _TECHMAP_FAIL_ = 1;
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index 759549e30..d5362eb83 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -42,19 +42,18 @@ module \$lut (A, Y);
.I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0]));
end else
if (WIDTH == 2) begin
- localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}};
+ localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}};
SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0]));
+ .I0(1'b0), .I1(1'b0), .I2(A[0]), .I3(A[1]));
end else
if (WIDTH == 3) begin
- localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}};
+ localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}};
SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0]));
+ .I0(1'b0), .I1(A[0]), .I2(A[1]), .I3(A[2]));
end else
if (WIDTH == 4) begin
- localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]};
- SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0]));
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index df10a2842..925ab31bb 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -139,8 +139,8 @@ static void run_ice40_opts(Module *module)
log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n",
log_id(module), log_id(cell), log_signal(replacement_output));
cell->type = "$lut";
- auto I3 = cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3));
- cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], I3 });
+ auto I3 = get_bit_or_zero(cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3)));
+ cell->setPort("\\A", { I3, inbit[1], inbit[0], get_bit_or_zero(cell->getPort("\\I0")) });
cell->setPort("\\Y", cell->getPort("\\O"));
cell->unsetPort("\\B");
cell->unsetPort("\\CI");
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index 2ebb8bf50..3689df70e 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SynthIntelPass : public ScriptPass {
- SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}
+ SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { experimental(); }
void help() YS_OVERRIDE
{
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 22dca3c47..eb145593e 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -2155,7 +2155,235 @@ assign PCOUT = P;
endmodule
-// TODO: DSP48 (Virtex 4).
+module DSP48 (
+ input signed [17:0] A,
+ input signed [17:0] B,
+ input signed [47:0] C,
+ input signed [17:0] BCIN,
+ input signed [47:0] PCIN,
+ input CARRYIN,
+ input [6:0] OPMODE,
+ input SUBTRACT,
+ input [1:0] CARRYINSEL,
+ output signed [47:0] P,
+ output signed [17:0] BCOUT,
+ output signed [47:0] PCOUT,
+ (* clkbuf_sink *)
+ input CLK,
+ input CEA,
+ input CEB,
+ input CEC,
+ input CEM,
+ input CECARRYIN,
+ input CECINSUB,
+ input CECTRL,
+ input CEP,
+ input RSTA,
+ input RSTB,
+ input RSTC,
+ input RSTM,
+ input RSTCARRYIN,
+ input RSTCTRL,
+ input RSTP
+);
+
+parameter integer AREG = 1;
+parameter integer BREG = 1;
+parameter integer CREG = 1;
+parameter integer MREG = 1;
+parameter integer PREG = 1;
+parameter integer CARRYINREG = 1;
+parameter integer CARRYINSELREG = 1;
+parameter integer OPMODEREG = 1;
+parameter integer SUBTRACTREG = 1;
+parameter B_INPUT = "DIRECT";
+parameter LEGACY_MODE = "MULT18X18S";
+
+wire signed [17:0] A_OUT;
+wire signed [17:0] B_OUT;
+wire signed [47:0] C_OUT;
+wire signed [35:0] M_MULT;
+wire signed [35:0] M_OUT;
+wire signed [47:0] P_IN;
+wire [6:0] OPMODE_OUT;
+wire [1:0] CARRYINSEL_OUT;
+wire CARRYIN_OUT;
+wire SUBTRACT_OUT;
+reg INT_CARRYIN_XY;
+reg INT_CARRYIN_Z;
+reg signed [47:0] XMUX;
+reg signed [47:0] YMUX;
+wire signed [47:0] XYMUX;
+reg signed [47:0] ZMUX;
+reg CIN;
+
+// The B input multiplexer.
+wire signed [17:0] B_MUX;
+assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN;
+
+// The cascade output.
+assign BCOUT = B_OUT;
+assign PCOUT = P;
+
+// The registers.
+reg signed [17:0] A0_REG;
+reg signed [17:0] A1_REG;
+reg signed [17:0] B0_REG;
+reg signed [17:0] B1_REG;
+reg signed [47:0] C_REG;
+reg signed [35:0] M_REG;
+reg signed [47:0] P_REG;
+reg [6:0] OPMODE_REG;
+reg [1:0] CARRYINSEL_REG;
+reg SUBTRACT_REG;
+reg CARRYIN_REG;
+reg INT_CARRYIN_XY_REG;
+
+initial begin
+ A0_REG = 0;
+ A1_REG = 0;
+ B0_REG = 0;
+ B1_REG = 0;
+ C_REG = 0;
+ M_REG = 0;
+ P_REG = 0;
+ OPMODE_REG = 0;
+ CARRYINSEL_REG = 0;
+ SUBTRACT_REG = 0;
+ CARRYIN_REG = 0;
+ INT_CARRYIN_XY_REG = 0;
+end
+
+always @(posedge CLK) begin
+ if (RSTA) begin
+ A0_REG <= 0;
+ A1_REG <= 0;
+ end else if (CEA) begin
+ A0_REG <= A;
+ A1_REG <= A0_REG;
+ end
+ if (RSTB) begin
+ B0_REG <= 0;
+ B1_REG <= 0;
+ end else if (CEB) begin
+ B0_REG <= B_MUX;
+ B1_REG <= B0_REG;
+ end
+ if (RSTC) begin
+ C_REG <= 0;
+ end else if (CEC) begin
+ C_REG <= C;
+ end
+ if (RSTM) begin
+ M_REG <= 0;
+ end else if (CEM) begin
+ M_REG <= M_MULT;
+ end
+ if (RSTP) begin
+ P_REG <= 0;
+ end else if (CEP) begin
+ P_REG <= P_IN;
+ end
+ if (RSTCTRL) begin
+ OPMODE_REG <= 0;
+ CARRYINSEL_REG <= 0;
+ SUBTRACT_REG <= 0;
+ end else begin
+ if (CECTRL) begin
+ OPMODE_REG <= OPMODE;
+ CARRYINSEL_REG <= CARRYINSEL;
+ end
+ if (CECINSUB)
+ SUBTRACT_REG <= SUBTRACT;
+ end
+ if (RSTCARRYIN) begin
+ CARRYIN_REG <= 0;
+ INT_CARRYIN_XY_REG <= 0;
+ end else begin
+ if (CECINSUB)
+ CARRYIN_REG <= CARRYIN;
+ if (CECARRYIN)
+ INT_CARRYIN_XY_REG <= INT_CARRYIN_XY;
+ end
+end
+
+// The register enables.
+assign A_OUT = (AREG == 2) ? A1_REG : (AREG == 1) ? A0_REG : A;
+assign B_OUT = (BREG == 2) ? B1_REG : (BREG == 1) ? B0_REG : B_MUX;
+assign C_OUT = (CREG == 1) ? C_REG : C;
+assign M_OUT = (MREG == 1) ? M_REG : M_MULT;
+assign P = (PREG == 1) ? P_REG : P_IN;
+assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE;
+assign SUBTRACT_OUT = (SUBTRACTREG == 1) ? SUBTRACT_REG : SUBTRACT;
+assign CARRYINSEL_OUT = (CARRYINSELREG == 1) ? CARRYINSEL_REG : CARRYINSEL;
+assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN;
+
+// The multiplier.
+assign M_MULT = A_OUT * B_OUT;
+
+// The post-adder inputs.
+always @* begin
+ case (OPMODE_OUT[1:0])
+ 2'b00: XMUX <= 0;
+ 2'b10: XMUX <= P;
+ 2'b11: XMUX <= {{12{A_OUT[17]}}, A_OUT, B_OUT};
+ default: XMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+ case (OPMODE_OUT[1:0])
+ 2'b01: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
+ 2'b11: INT_CARRYIN_XY <= ~A_OUT[17];
+ // TODO: not tested in hardware.
+ default: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
+ endcase
+end
+
+always @* begin
+ case (OPMODE_OUT[3:2])
+ 2'b00: YMUX <= 0;
+ 2'b11: YMUX <= C_OUT;
+ default: YMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+end
+
+assign XYMUX = (OPMODE_OUT[3:0] == 4'b0101) ? M_OUT : (XMUX + YMUX);
+
+always @* begin
+ case (OPMODE_OUT[6:4])
+ 3'b000: ZMUX <= 0;
+ 3'b001: ZMUX <= PCIN;
+ 3'b010: ZMUX <= P;
+ 3'b011: ZMUX <= C_OUT;
+ 3'b101: ZMUX <= {{17{PCIN[47]}}, PCIN[47:17]};
+ 3'b110: ZMUX <= {{17{P[47]}}, P[47:17]};
+ default: ZMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+ // TODO: check how all this works on actual hw.
+ if (OPMODE_OUT[1:0] == 2'b10)
+ INT_CARRYIN_Z <= ~P[47];
+ else
+ case (OPMODE_OUT[6:4])
+ 3'b001: INT_CARRYIN_Z <= ~PCIN[47];
+ 3'b010: INT_CARRYIN_Z <= ~P[47];
+ 3'b101: INT_CARRYIN_Z <= ~PCIN[47];
+ 3'b110: INT_CARRYIN_Z <= ~P[47];
+ default: INT_CARRYIN_Z <= 1'bx;
+ endcase
+end
+
+always @* begin
+ case (CARRYINSEL_OUT)
+ 2'b00: CIN <= CARRYIN_OUT;
+ 2'b01: CIN <= INT_CARRYIN_Z;
+ 2'b10: CIN <= INT_CARRYIN_XY;
+ 2'b11: CIN <= INT_CARRYIN_XY_REG;
+ default: CIN <= 1'bx;
+ endcase
+end
+
+// The post-adder.
+assign P_IN = SUBTRACT_OUT ? (ZMUX - (XYMUX + CIN)) : (ZMUX + XYMUX + CIN);
+
+endmodule
// TODO: DSP48E (Virtex 5).
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index d5c58c5d7..06e982a0e 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -209,7 +209,7 @@ CELLS = [
# Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E
# Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP
# Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6
- Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
+ # Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5
#Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7
Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index c3e5c72f9..54e48f1a6 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -5476,49 +5476,6 @@ module URAM288_BASE (...);
input SLEEP;
endmodule
-module DSP48 (...);
- parameter integer AREG = 1;
- parameter integer BREG = 1;
- parameter B_INPUT = "DIRECT";
- parameter integer CARRYINREG = 1;
- parameter integer CARRYINSELREG = 1;
- parameter integer CREG = 1;
- parameter LEGACY_MODE = "MULT18X18S";
- parameter integer MREG = 1;
- parameter integer OPMODEREG = 1;
- parameter integer PREG = 1;
- parameter integer SUBTRACTREG = 1;
- output [17:0] BCOUT;
- output [47:0] P;
- output [47:0] PCOUT;
- input [17:0] A;
- input [17:0] B;
- input [17:0] BCIN;
- input [47:0] C;
- input CARRYIN;
- input [1:0] CARRYINSEL;
- input CEA;
- input CEB;
- input CEC;
- input CECARRYIN;
- input CECINSUB;
- input CECTRL;
- input CEM;
- input CEP;
- (* clkbuf_sink *)
- input CLK;
- input [6:0] OPMODE;
- input [47:0] PCIN;
- input RSTA;
- input RSTB;
- input RSTC;
- input RSTCARRYIN;
- input RSTCTRL;
- input RSTM;
- input RSTP;
- input SUBTRACT;
-endmodule
-
module DSP48E (...);
parameter SIM_MODE = "SAFE";
parameter integer ACASCREG = 1;
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
index 62d501632..718ec42f1 100644
--- a/techlibs/xilinx/lut_map.v
+++ b/techlibs/xilinx/lut_map.v
@@ -29,90 +29,65 @@ module \$lut (A, Y);
input [WIDTH-1:0] A;
output Y;
- // Need to swap input ordering, and fix init accordingly,
- // to match ABC's expectation of LUT inputs in non-decreasing
- // delay order
- function [WIDTH-1:0] permute_index;
- input [WIDTH-1:0] i;
- integer j;
- begin
- permute_index = 0;
- for (j = 0; j < WIDTH; j = j + 1)
- permute_index[WIDTH-1 - j] = i[j];
- end
- endfunction
-
- function [2**WIDTH-1:0] permute_init;
- input [2**WIDTH-1:0] orig;
- integer i;
- begin
- permute_init = 0;
- for (i = 0; i < 2**WIDTH; i = i + 1)
- permute_init[i] = orig[permute_index(i)];
- end
- endfunction
-
- parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT);
-
generate
if (WIDTH == 1) begin
- if (P_LUT == 2'b01) begin
+ if (LUT == 2'b01) begin
INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0]));
end else begin
- LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end
end else
if (WIDTH == 2) begin
- LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[1]), .I1(A[0]));
+ LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]));
end else
if (WIDTH == 3) begin
- LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[2]), .I1(A[1]), .I2(A[0]));
+ LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]));
end else
if (WIDTH == 4) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[3]), .I1(A[2]), .I2(A[1]),
- .I3(A[0]));
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]));
end else
if (WIDTH == 5) begin
- LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[4]), .I1(A[3]), .I2(A[2]),
- .I3(A[1]), .I4(A[0]));
+ LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]));
end else
if (WIDTH == 6) begin
- LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[5]), .I1(A[4]), .I2(A[3]),
- .I3(A[2]), .I4(A[1]), .I5(A[0]));
+ LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
end else
if (WIDTH == 7) begin
wire T0, T1;
- LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[6]), .I1(A[5]), .I2(A[4]),
- .I3(A[3]), .I4(A[2]), .I5(A[1]));
- LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[6]), .I1(A[5]), .I2(A[4]),
- .I3(A[3]), .I4(A[2]), .I5(A[1]));
- MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
+ LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
end else
if (WIDTH == 8) begin
wire T0, T1, T2, T3, T4, T5;
- LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1]));
- MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1]));
- MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
+ LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
+ MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
+ MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
+ MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 5c3b5179d..8119d307c 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -316,7 +316,11 @@ struct SynthXilinxPass : public ScriptPass
run("proc");
if (flatten || help_mode)
run("flatten", "(with '-flatten')");
+ if (active_design)
+ active_design->scratchpad_unset("tribuf.added_something");
run("tribuf -logic");
+ if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
+ log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
run("deminout");
run("opt_expr");
run("opt_clean");
@@ -526,7 +530,7 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("map_cells")) {
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
if (help_mode || !noiopad)
- run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if not '-noiopad')");
+ run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(skip if '-noiopad')");
std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
if (widemux > 0)
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
@@ -589,17 +593,15 @@ struct SynthXilinxPass : public ScriptPass
if (!nosrl || help_mode)
run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
- if (help_mode)
- techmap_args += stringf("[-map %s]", ff_map_file.c_str());
- else if (!abc9)
+ if (help_mode || !abc9)
techmap_args += stringf(" -map %s", ff_map_file.c_str());
- run("techmap " + techmap_args, "(only if '-abc9')");
+ run("techmap " + techmap_args);
run("xilinx_dffopt");
}
if (check_label("finalize")) {
if (help_mode || !noclkbuf)
- run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')");
+ run("clkbufmap -buf BUFG O:I", "(skip if '-noclkbuf')");
if (help_mode || ise)
run("extractinv -inv INV O:I", "(only if '-ise')");
run("clean");
diff --git a/techlibs/xilinx/tests/.gitignore b/techlibs/xilinx/tests/.gitignore
index 848f88d53..0d9c28fde 100644
--- a/techlibs/xilinx/tests/.gitignore
+++ b/techlibs/xilinx/tests/.gitignore
@@ -12,4 +12,7 @@ test_dsp48a_model_ref.v
test_dsp48a1_model_ref.v
test_dsp48a1_model_uut.v
test_dsp48a1_model
+test_dsp48_model_ref.v
+test_dsp48_model_uut.v
+test_dsp48_model
*.vcd
diff --git a/techlibs/xilinx/tests/test_dsp48_model.sh b/techlibs/xilinx/tests/test_dsp48_model.sh
new file mode 100644
index 000000000..9a73f9b0c
--- /dev/null
+++ b/techlibs/xilinx/tests/test_dsp48_model.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -ex
+if [ -z $ISE_DIR ]; then
+ ISE_DIR=/opt/Xilinx/ISE/14.7
+fi
+sed 's/DSP48 /DSP48_UUT /; /DSP48_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48_model_uut.v
+if [ ! -f "test_dsp48_model_ref.v" ]; then
+ cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48.v test_dsp48_model_ref.v
+fi
+for tb in mult_allreg mult_noreg mult_inreg
+do
+ iverilog -s $tb -s glbl -o test_dsp48_model test_dsp48_model.v test_dsp48_model_uut.v test_dsp48_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v
+ vvp -N ./test_dsp48_model
+done
diff --git a/techlibs/xilinx/tests/test_dsp48_model.v b/techlibs/xilinx/tests/test_dsp48_model.v
new file mode 100644
index 000000000..d69c00e93
--- /dev/null
+++ b/techlibs/xilinx/tests/test_dsp48_model.v
@@ -0,0 +1,287 @@
+`timescale 1ns / 1ps
+
+module testbench;
+ parameter integer AREG = 1;
+ parameter integer BREG = 1;
+ parameter integer CREG = 1;
+ parameter integer MREG = 1;
+ parameter integer PREG = 1;
+ parameter integer CARRYINREG = 1;
+ parameter integer CARRYINSELREG = 1;
+ parameter integer OPMODEREG = 1;
+ parameter integer SUBTRACTREG = 1;
+ parameter B_INPUT = "DIRECT";
+ parameter LEGACY_MODE = "NONE";
+
+ reg CLK;
+ reg CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL;
+ reg RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL;
+ reg [17:0] A;
+ reg [17:0] B;
+ reg [47:0] C;
+ reg [17:0] BCIN;
+ reg [47:0] PCIN;
+ reg CARRYIN;
+ reg [6:0] OPMODE;
+ reg SUBTRACT;
+ reg [1:0] CARRYINSEL;
+
+ output [47:0] P, REF_P;
+ output [17:0] BCOUT, REF_BCOUT;
+ output [47:0] PCOUT, REF_PCOUT;
+
+ integer errcount = 0;
+
+ reg ERROR_FLAG = 0;
+
+ task clkcycle;
+ begin
+ #5;
+ CLK = ~CLK;
+ #10;
+ CLK = ~CLK;
+ #2;
+ ERROR_FLAG = 0;
+ if (REF_BCOUT !== BCOUT) begin
+ $display("ERROR at %1t: REF_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
+ errcount = errcount + 1;
+ ERROR_FLAG = 1;
+ end
+ 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_PCOUT !== PCOUT) begin
+ $display("ERROR at %1t: REF_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
+ errcount = errcount + 1;
+ ERROR_FLAG = 1;
+ end
+ #3;
+ end
+ endtask
+
+ reg config_valid = 0;
+ task drc;
+ begin
+ config_valid = 1;
+
+ if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
+ if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b10) config_valid = 0;
+ if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b10) config_valid = 0;
+ if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b11) config_valid = 0;
+ if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b11) config_valid = 0;
+ if (OPMODE[3:2] == 2'b10) 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) config_valid = 0;
+ if (OPMODE[6:4] == 3'b111) config_valid = 0;
+ if (OPMODE[6:4] == 3'b000 && CARRYINSEL == 2'b01) config_valid = 0;
+ if (OPMODE[6:4] == 3'b011 && CARRYINSEL == 2'b01) config_valid = 0;
+
+ // Xilinx models consider these combinations invalid for an unknown reason.
+ if (CARRYINSEL == 2'b01 && OPMODE[3:2] == 2'b00) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000011) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000101) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0100011) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0111111) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b1100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0011111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0010011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0101111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0110011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0111111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1010011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1011111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1101111) config_valid = 0;
+
+ if (CARRYINSEL == 2'b10 && OPMODE[3:0] == 4'b0101 && MREG == 1) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE[3:0] == 4'b0101 && MREG == 0) config_valid = 0;
+ end
+ endtask
+
+ initial begin
+ $dumpfile("test_dsp48_model.vcd");
+ $dumpvars(0, testbench);
+
+ #2;
+ CLK = 1'b0;
+ {CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = 8'b11111111;
+ {A, B, C, PCIN, OPMODE, SUBTRACT, CARRYIN, CARRYINSEL} = 0;
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 7'b1111111;
+ repeat (10) begin
+ #10;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0;
+ #10;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0;
+ end
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 0;
+
+ repeat (100000) begin
+ clkcycle;
+ config_valid = 0;
+ while (!config_valid) begin
+ A = $urandom;
+ B = $urandom;
+ C = {$urandom, $urandom};
+ BCIN = $urandom;
+ PCIN = {$urandom, $urandom};
+
+ {CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = $urandom | $urandom | $urandom;
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
+ {CARRYIN, CARRYINSEL, OPMODE, SUBTRACT} = $urandom;
+
+ drc;
+ end
+ end
+
+ if (errcount == 0) begin
+ $display("All tests passed.");
+ $finish;
+ end else begin
+ $display("Caught %1d errors.", errcount);
+ $stop;
+ end
+ end
+
+ DSP48 #(
+ .AREG (AREG),
+ .BREG (BREG),
+ .CREG (CREG),
+ .MREG (MREG),
+ .PREG (PREG),
+ .CARRYINREG (CARRYINREG),
+ .CARRYINSELREG (CARRYINSELREG),
+ .OPMODEREG (OPMODEREG),
+ .SUBTRACTREG (SUBTRACTREG),
+ .B_INPUT (B_INPUT),
+ .LEGACY_MODE (LEGACY_MODE)
+ ) ref (
+ .A (A),
+ .B (B),
+ .C (C),
+ .BCIN (BCIN),
+ .PCIN (PCIN),
+ .CARRYIN (CARRYIN),
+ .OPMODE (OPMODE),
+ .SUBTRACT (SUBTRACT),
+ .CARRYINSEL (CARRYINSEL),
+ .BCOUT (REF_BCOUT),
+ .P (REF_P),
+ .PCOUT (REF_PCOUT),
+ .CEA (CEA),
+ .CEB (CEB),
+ .CEC (CEC),
+ .CEM (CEM),
+ .CEP (CEP),
+ .CECARRYIN (CECARRYIN),
+ .CECINSUB (CECINSUB),
+ .CECTRL (CECTRL),
+ .CLK (CLK),
+ .RSTA (RSTA),
+ .RSTB (RSTB),
+ .RSTC (RSTC),
+ .RSTM (RSTM),
+ .RSTP (RSTP),
+ .RSTCARRYIN (RSTCARRYIN),
+ .RSTCTRL (RSTCTRL)
+ );
+
+ DSP48_UUT #(
+ .AREG (AREG),
+ .BREG (BREG),
+ .CREG (CREG),
+ .MREG (MREG),
+ .PREG (PREG),
+ .CARRYINREG (CARRYINREG),
+ .CARRYINSELREG (CARRYINSELREG),
+ .OPMODEREG (OPMODEREG),
+ .SUBTRACTREG (SUBTRACTREG),
+ .B_INPUT (B_INPUT),
+ .LEGACY_MODE (LEGACY_MODE)
+ ) uut (
+ .A (A),
+ .B (B),
+ .C (C),
+ .BCIN (BCIN),
+ .PCIN (PCIN),
+ .CARRYIN (CARRYIN),
+ .OPMODE (OPMODE),
+ .SUBTRACT (SUBTRACT),
+ .CARRYINSEL (CARRYINSEL),
+ .BCOUT (BCOUT),
+ .P (P),
+ .PCOUT (PCOUT),
+ .CEA (CEA),
+ .CEB (CEB),
+ .CEC (CEC),
+ .CEM (CEM),
+ .CEP (CEP),
+ .CECARRYIN (CECARRYIN),
+ .CECINSUB (CECINSUB),
+ .CECTRL (CECTRL),
+ .CLK (CLK),
+ .RSTA (RSTA),
+ .RSTB (RSTB),
+ .RSTC (RSTC),
+ .RSTM (RSTM),
+ .RSTP (RSTP),
+ .RSTCARRYIN (RSTCARRYIN),
+ .RSTCTRL (RSTCTRL)
+ );
+endmodule
+
+module mult_noreg;
+ testbench #(
+ .AREG (0),
+ .BREG (0),
+ .CREG (0),
+ .MREG (0),
+ .PREG (0),
+ .CARRYINREG (0),
+ .CARRYINSELREG (0),
+ .OPMODEREG (0),
+ .SUBTRACTREG (0),
+ .B_INPUT ("DIRECT")
+ ) testbench ();
+endmodule
+
+module mult_allreg;
+ testbench #(
+ .AREG (1),
+ .BREG (1),
+ .CREG (1),
+ .MREG (1),
+ .PREG (1),
+ .CARRYINREG (1),
+ .CARRYINSELREG (1),
+ .OPMODEREG (1),
+ .SUBTRACTREG (1),
+ .B_INPUT ("CASCADE")
+ ) testbench ();
+endmodule
+
+module mult_inreg;
+ testbench #(
+ .AREG (1),
+ .BREG (1),
+ .CREG (1),
+ .MREG (0),
+ .PREG (0),
+ .CARRYINREG (1),
+ .CARRYINSELREG (0),
+ .OPMODEREG (0),
+ .SUBTRACTREG (0),
+ .B_INPUT ("DIRECT")
+ ) testbench ();
+endmodule