[wip] sim model testing

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2019-08-08 09:31:34 +01:00
parent fe95807f16
commit ccfb4ff2a9
3 changed files with 361 additions and 41 deletions

View File

@ -463,27 +463,10 @@ module DSP48E1 (
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");
@ -505,14 +488,14 @@ module DSP48E1 (
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
@ -594,7 +577,7 @@ module DSP48E1 (
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
@ -610,7 +593,7 @@ module DSP48E1 (
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
@ -625,14 +608,16 @@ module DSP48E1 (
// 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
@ -640,10 +625,11 @@ module DSP48E1 (
// 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;
@ -653,26 +639,54 @@ module DSP48E1 (
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
// 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
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 alu_cin = 1'b0; // FIXME*
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);
@ -730,16 +744,11 @@ module DSP48E1 (
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)

View File

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

View File

@ -0,0 +1,310 @@
`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