diff options
Diffstat (limited to 'techlibs')
-rw-r--r-- | techlibs/ecp5/cells_map.v | 132 | ||||
-rw-r--r-- | techlibs/ice40/cells_map.v | 13 | ||||
-rw-r--r-- | techlibs/ice40/ice40_opt.cc | 4 | ||||
-rw-r--r-- | techlibs/intel/synth_intel.cc | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 230 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.py | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.v | 43 | ||||
-rw-r--r-- | techlibs/xilinx/lut_map.v | 99 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 14 | ||||
-rw-r--r-- | techlibs/xilinx/tests/.gitignore | 3 | ||||
-rw-r--r-- | techlibs/xilinx/tests/test_dsp48_model.sh | 14 | ||||
-rw-r--r-- | techlibs/xilinx/tests/test_dsp48_model.v | 287 |
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 |