initial begin
`ifdef __ICARUS__
- if (ACASCREG != 0) $fatal(1, "Unsupported ACASCREG value");
- if (ADREG != 0) $fatal(1, "Unsupported ADREG value");
- if (ALUMODEREG != 0) $fatal(1, "Unsupported ALUMODEREG value");
- if (AREG == 2) $fatal(1, "Unsupported AREG value");
if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
- if (A_INPUT != "DIRECT") $fatal(1, "Unsupported A_INPUT value");
- if (BCASCREG != 0) $fatal(1, "Unsupported BCASCREG value");
- if (BREG == 2) $fatal(1, "Unsupported BREG value");
- if (B_INPUT != "DIRECT") $fatal(1, "Unsupported B_INPUT value");
- if (CARRYINREG != 0) $fatal(1, "Unsupported CARRYINREG value");
- if (CARRYINSELREG != 0) $fatal(1, "Unsupported CARRYINSELREG value");
- if (CREG != 0) $fatal(1, "Unsupported CREG value");
- if (DREG != 0) $fatal(1, "Unsupported DREG value");
- if (INMODEREG != 0) $fatal(1, "Unsupported INMODEREG value");
- if (MREG != 0) $fatal(1, "Unsupported MREG value");
- if (OPMODEREG != 0) $fatal(1, "Unsupported OPMODEREG value");
//if (PREG != 0) $fatal(1, "Unsupported PREG value");
if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
- if (USE_DPORT != "FALSE") $fatal(1, "Unsupported USE_DPORT value");
- if (USE_MULT != "MULTIPLY") $fatal(1, "Unsupported USE_MULT value");
if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value");
if (USE_SIMD != "ONE48") $fatal(1, "Unsupported USE_SIMD value");
if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value");
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;
- reg [6:0] OPMODEr;
- reg [3:0] ALUMODEr;
- reg [2:0] CARRYINSELr;
+ reg signed [29:0] Ar1 = 30'b0, Ar2 = 30'b0;
+ reg signed [24:0] Dr = 25'b0;
+ reg signed [17:0] Br1 = 18'b0, Br2 = 18'b0;
+ reg signed [47:0] Cr = 48'b0;
+ 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
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;
+ reg signed [24:0] ADr = 25'b0;
generate
if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
endgenerate
wire signed [42:0] M = A_MULT * B_MULT;
- reg signed [42:0] Mr;
+ reg signed [42:0] Mr = 43'b0;
// Multiplier result register
generate
// X multiplexer
case (OPMODEr[1:0])
2'b00: X = 48'b0;
- 2'b01: X = $signed(M);
+ 2'b01: begin X = $signed(M);
`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
- 2'b10: X = P;
+ 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: Y = 48'b0; // FIXME: more accurate partial product modelling?
+ 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 = C;
default: Y = 48'bx;
case (OPMODEr[6:4])
3'b000: Z = 48'b0;
3'b001: Z = PCIN;
- 3'b010: Z = P;
+ 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 = C;
- 3'b100: Z = P;
+ 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
- // ALU core
+ // Carry in
+ wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
+ reg CARRYINr, A24_xnor_B17;
+ 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 (CECARRYIN) A24_xnor_B17 <= A24_xnor_B17d; end
+ else always @* A24_xnor_B17 = A24_xnor_B17d;
+ endgenerate
- wire alu_cin = 1'b0; // FIXME*
+ 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) | (X & Y);
endgenerate
wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
+ initial P = 48'b0;
wire [3:0] CARRYOUTd = (ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out;
wire CARRYCASCOUTd = ext_carry_out[3];
wire MULTSIGNOUTd = Mr[42];
- always @* begin
-`ifdef __ICARUS__
- if (CARRYINSEL != 3'b000) $fatal(1, "Unsupported CARRYINSEL value");
-`endif
- end
-
generate
if (PREG == 1) begin
always @(posedge CLK)
--- /dev/null
+`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, 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;
+
+ task clkcycle;
+ begin
+ #5;
+ CLK = ~CLK;
+ #10;
+ CLK = ~CLK;
+ #2;
+
+ 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;
+ end
+ if (REF_CARRYOUT !== CARRYOUT) begin
+ $display("ERROR at %1t: REF_CARRYOUT=%b UUT_CARRYOUT=%b", $time, REF_CARRYOUT, CARRYOUT);
+ errcount = errcount + 1;
+ end
+ #3;
+ end
+ endtask
+
+ reg config_valid = 0;
+ task drc;
+ config_valid = 1;
+ if (AREG != 2 && INMODE[0]) config_valid = 0;
+ if (BREG != 2 && INMODE[4]) 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) && PREG != 1) config_valid = 0;
+ if ((OPMODE[6:4] == 3'b010) && (PREG != 1 || OPMODE[3:0] != 4'b1000)) config_valid = 0;
+ 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, RSTD, RSTINMODE, RSTM, RSTP} = ~0;
+ #5;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0
+ #5;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0;
+ {RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTD, RSTINMODE, RSTM, RSTP} = 0;
+
+ repeat (300) begin
+ clkcycle;
+ do begin
+ A = $urandom;
+ ACIN = $urandom;
+ B = $urandom;
+ BCIN = $urandom;
+ C = {$urandom, $urandom};
+ D = $urandom;
+ PCIN = {$urandom, $urandom};
+
+ {RSTA, RSTALLCARRYIN, RSTALUMODE, RSTB, RSTC, RSTD, RSTINMODE, RSTM, RSTP} = $urandom & $urandom & $urandom;
+ {ALUMODE, CARRYINSEL, INMODE} = $urandom & $urandom & $urandom;
+ OPMODE = $urandom;
+ {CARRYCASCIN, CARRYIN, MULTSIGNIN} = $urandom;
+ drc;
+ end while (!config_valid);
+ 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),
+ .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),
+ .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