Fixes testbench issues in testing against all vectors. Still a bug in ui32_to_f16_rz.sv - but will fix. Some things can be optimized. Overall, adds a FSM to test things more effectively. Actually is faster than previously as it assumed everything took the same number of cycles. Again, some things can be optimized

This commit is contained in:
James E. Stine 2024-01-29 16:46:34 -06:00
parent df8df0598d
commit 95a97faf3f

View File

@ -83,7 +83,7 @@ module testbenchfp;
logic [P.LOGCVTLEN-1:0] CvtShiftAmtE; // how much to shift by logic [P.LOGCVTLEN-1:0] CvtShiftAmtE; // how much to shift by
logic [P.DIVb:0] Quot; logic [P.DIVb:0] Quot;
logic CvtResSubnormUfE; logic CvtResSubnormUfE;
logic DivStart; logic DivStart=0;
logic FDivBusyE; logic FDivBusyE;
logic OldFDivBusyE; logic OldFDivBusyE;
logic reset = 1'b0; logic reset = 1'b0;
@ -122,6 +122,10 @@ module testbenchfp;
logic CheckNow; // Final check logic CheckNow; // Final check
logic FMAop; // Is this a FMA operation? logic FMAop; // Is this a FMA operation?
// FSM for testing each item per clock
typedef enum logic [2:0] {S0, Start, S2, Done} statetype;
statetype state, nextstate;
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// ||||||||| |||||||| ||||||| ||||||||| ||||||| |||||||| ||| // ||||||||| |||||||| ||||||| ||||||||| ||||||| |||||||| |||
@ -676,7 +680,7 @@ module testbenchfp;
.VectorNum, .Ans(Ans), .AnsFlg(AnsFlg), .SrcA, .VectorNum, .Ans(Ans), .AnsFlg(AnsFlg), .SrcA,
.Xs, .Ys, .Zs, .Unit(UnitVal), .Xs, .Ys, .Zs, .Unit(UnitVal),
.Xe, .Ye, .Ze, .TestNum, .OpCtrl(OpCtrlVal), .Xe, .Ye, .Ze, .TestNum, .OpCtrl(OpCtrlVal),
.Xm, .Ym, .Zm, .DivStart, .Xm, .Ym, .Zm,
.XNaN, .YNaN, .ZNaN, .XNaN, .YNaN, .ZNaN,
.XSNaN, .YSNaN, .ZSNaN, .XSNaN, .YSNaN, .ZSNaN,
.XSubnorm, .ZSubnorm, .XSubnorm, .ZSubnorm,
@ -748,16 +752,6 @@ module testbenchfp;
clk = 1; #5; clk = 0; #5; clk = 1; #5; clk = 0; #5;
end end
// Provide reset for divsqrt to reset state to IDLE
// Previous version did not initiate a divide due to missing state
// information. This starts the FSM by putting the fdivsqrt into
// the IDLE state.
initial
begin
#0 reset = 1'b1;
#25 reset = 1'b0;
end
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// ||||| ||| |||||||||| ||||| ||| // ||||| ||| |||||||||| ||||| |||
@ -836,44 +830,63 @@ module testbenchfp;
`CVTINTUNIT: ResFlg = Flg; `CVTINTUNIT: ResFlg = Flg;
`CVTFPUNIT: ResFlg = Flg; `CVTFPUNIT: ResFlg = Flg;
endcase endcase
// Use four state test sequence to handle div properly.
// Four states should allow other operations to finish
// properly and within time.
case (state)
S0: begin
DivStart = 1'b0;
nextstate = Start;
end
Start: begin
if (UnitVal == `DIVUNIT)
DivStart = 1'b1;
else
DivStart = 1'b0;
nextstate = S2;
end
S2: begin
DivStart = 1'b0;
if ((FDivBusyE)|(~DivDone))
nextstate = S2;
else
nextstate = Done;
end
Done: begin
DivStart = 1'b0;
nextstate = S0;
end
endcase // case (state)
end end
// Provide reset for divsqrt to reset state
initial
begin
#0 reset = 1'b1;
#25 reset = 1'b0;
end
// Left-over from before - will remove soon
always @(posedge clk) always @(posedge clk)
OldFDivBusyE = FDivDoneE; OldFDivBusyE = FDivDoneE;
// For FP division this adds extra clock cycles to make sure the // state machine to handle timing for testing due
// computation completes. // various cycle counts for different fp/int operations
// Adds vector at start of clock
always @(posedge clk) begin always @(posedge clk) begin
// Add extra clock cycles in beginning for fdivsqrt to adequate reset state
if (~(FDivBusyE|DivStart)|(UnitVal != `DIVUNIT)) begin // state machine element for testing
// This allows specific number of clocks to allow each vector if (reset)
// to complete for division or square root. It is an state <= S0;
// arbitrary value and can be changed, if needed. else
case (FmtVal) state <= nextstate;
// QP
2'b11: begin // Increment the vector when Done with each test
repeat (20) if (state == Done)
@(posedge clk); VectorNum += 1; // increment the vector
end
// HP
2'b10: begin
repeat (14)
@(posedge clk);
end
// DP
2'b01: begin
repeat (18)
@(posedge clk);
end
// SP
2'b00: begin
repeat (16)
@(posedge clk);
end
endcase // case (FmtVal)
if (reset != 1'b1)
VectorNum += 1; // increment the vector
end
end end
// check results on falling edge of clk // check results on falling edge of clk
@ -904,7 +917,7 @@ module testbenchfp;
(YNaN&(Res[P.H_LEN-2:0] === {Y[P.H_LEN-2:P.H_NF],1'b1,Y[P.H_NF-2:0]})) | (YNaN&(Res[P.H_LEN-2:0] === {Y[P.H_LEN-2:P.H_NF],1'b1,Y[P.H_NF-2:0]})) |
(ZNaN&(Res[P.H_LEN-2:0] === {Z[P.H_LEN-2:P.H_NF],1'b1,Z[P.H_NF-2:0]}))); (ZNaN&(Res[P.H_LEN-2:0] === {Z[P.H_LEN-2:P.H_NF],1'b1,Z[P.H_NF-2:0]})));
endcase endcase
else if (UnitVal === `CVTFPUNIT) // if converting from floating point to floating point OpCtrl contains the final FP format else if (UnitVal === `CVTFPUNIT) // if converting from FP to FP OpCtrl contains the final FP format
case (OpCtrlVal[1:0]) case (OpCtrlVal[1:0])
2'b11: NaNGood = (((P.IEEE754==0)&AnsNaN&(Res === {1'b0, {P.Q_NE+1{1'b1}}, {P.Q_NF-1{1'b0}}})) | 2'b11: NaNGood = (((P.IEEE754==0)&AnsNaN&(Res === {1'b0, {P.Q_NE+1{1'b1}}, {P.Q_NF-1{1'b0}}})) |
(AnsFlg[4]&(Res[P.Q_LEN-2:0] === {{P.Q_NE+1{1'b1}}, {P.Q_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[P.Q_LEN-2:0] === {{P.Q_NE+1{1'b1}}, {P.Q_NF-1{1'b0}}})) |
@ -941,28 +954,21 @@ module testbenchfp;
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// check if result is correct // check if result is correct
// wait till the division result is done or one extra cylcle for early termination (to simulate the EM pipline stage)
assign ResMatch = ((Res === Ans) | NaNGood | (NaNGood === 1'bx)); assign ResMatch = ((Res === Ans) | NaNGood | (NaNGood === 1'bx));
assign FlagMatch = ((ResFlg === AnsFlg) | (AnsFlg === 5'bx)); assign FlagMatch = ((ResFlg === AnsFlg) | (AnsFlg === 5'bx));
assign divsqrtop = (OpCtrlVal == `SQRT_OPCTRL) | (OpCtrlVal == `DIV_OPCTRL); assign divsqrtop = (OpCtrlVal == `SQRT_OPCTRL) | (OpCtrlVal == `DIV_OPCTRL);
assign FMAop = (OpCtrlVal == `FMAUNIT); assign FMAop = (OpCtrlVal == `FMAUNIT);
assign DivDone = OldFDivBusyE & ~FDivBusyE; assign DivDone = OldFDivBusyE & ~FDivBusyE;
assign CheckNow = ((DivDone | ~divsqrtop) |
(TEST == "all" | TEST == "add" | TEST == "fma" | TEST == "sub"))
& (UnitVal !== `CVTINTUNIT) & (UnitVal !== `CMPUNIT);
// Maybe change OpCtrl but for now just look at TEST for fma test if (~(ResMatch & FlagMatch) & CheckNow & (Ans[0] !== 1'bx)) begin
assign CheckNow = ((DivDone | ~divsqrtop) | (TEST == "add" | TEST == "fma" | TEST == "sub")) & (UnitVal !== `CVTINTUNIT) & (UnitVal !== `CMPUNIT);
if (~(ResMatch & FlagMatch) & CheckNow) begin
errors += 1; errors += 1;
$display("\nError in %s", Tests[TestNum]); $display("\nError in %s", Tests[TestNum]);
$display("TestNum %d OpCtrl %d", TestNum, OpCtrl[TestNum]); $display("TestNum %d OpCtrl %d", TestNum, OpCtrl[TestNum]);
$display("inputs: %h %h %h\nSrcA: %h\n Res: %h %h\n Expected: %h %h", X, Y, Z, SrcA, Res, ResFlg, Ans, AnsFlg); $display("inputs: %h %h %h\nSrcA: %h\n Res: %h %h\n Expected: %h %h", X, Y, Z, SrcA, Res, ResFlg, Ans, AnsFlg);
$stop; $stop;
end else if (((UnitVal === `CVTINTUNIT) | (UnitVal === `CMPUNIT)) &
~(ResMatch & FlagMatch) & (Ans[0] !== 1'bx)) begin // Check for conversion and comparisons
errors += 1;
$display("\nError in %s", Tests[TestNum]);
$display("TestNum %d OpCtrl %d", TestNum, OpCtrl[TestNum]);
$display("inputs: %h %h %h\nSrcA: %h\n Res: %h %h\n Ans: %h %h", X, Y, Z, SrcA, Res, ResFlg, Ans, AnsFlg);
$stop;
end end
if (TestVectors[VectorNum][0] === 1'bx & Tests[TestNum] !== "") begin // if reached the eof if (TestVectors[VectorNum][0] === 1'bx & Tests[TestNum] !== "") begin // if reached the eof
@ -979,11 +985,12 @@ module testbenchfp;
// increment the rounding mode or loop back to rne // increment the rounding mode or loop back to rne
if (FrmNum < 4) FrmNum += 1; if (FrmNum < 4) FrmNum += 1;
else begin else begin
FrmNum = 0; FrmNum = 0;
// Add some time as a buffer between tests at the end of each test // Add some time as a buffer between tests at the end of each test
repeat (10) // (to be removed)
@(posedge clk); repeat (10)
end @(posedge clk);
end
// if no more Tests - finish // if no more Tests - finish
if (Tests[TestNum] === "") begin if (Tests[TestNum] === "") begin
$display("\nAll Tests completed with %d errors\n", errors); $display("\nAll Tests completed with %d errors\n", errors);
@ -996,28 +1003,27 @@ endmodule
module readvectors import cvw::*; #(parameter cvw_t P) ( module readvectors import cvw::*; #(parameter cvw_t P) (
input logic clk, input logic clk,
input logic [P.FLEN*4+7:0] TestVector, input logic [P.FLEN*4+7:0] TestVector,
input logic [P.FMTBITS-1:0] ModFmt, input logic [P.FMTBITS-1:0] ModFmt,
input logic [1:0] Fmt, input logic [1:0] Fmt,
input logic [2:0] Unit, input logic [2:0] Unit,
input logic [31:0] VectorNum, input logic [31:0] VectorNum,
input logic [31:0] TestNum, input logic [31:0] TestNum,
input logic [2:0] OpCtrl, input logic [2:0] OpCtrl,
output logic [P.FLEN-1:0] Ans, output logic [P.FLEN-1:0] Ans,
output logic [P.XLEN-1:0] SrcA, output logic [P.XLEN-1:0] SrcA,
output logic [4:0] AnsFlg, output logic [4:0] AnsFlg,
output logic Xs, Ys, Zs, // sign bits of XYZ output logic Xs, Ys, Zs, // sign bits of XYZ
output logic [P.NE-1:0] Xe, Ye, Ze, // exponents of XYZ (converted to largest supported precision) output logic [P.NE-1:0] Xe, Ye, Ze, // exponents of XYZ (converted to largest supported precision)
output logic [P.NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision) output logic [P.NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision)
output logic XNaN, YNaN, ZNaN, // is XYZ a NaN output logic XNaN, YNaN, ZNaN, // is XYZ a NaN
output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN
output logic XSubnorm, ZSubnorm, // is XYZ denormalized output logic XSubnorm, ZSubnorm, // is XYZ denormalized
output logic XZero, YZero, ZZero, // is XYZ zero output logic XZero, YZero, ZZero, // is XYZ zero
output logic XInf, YInf, ZInf, // is XYZ infinity output logic XInf, YInf, ZInf, // is XYZ infinity
output logic XExpMax, output logic XExpMax,
output logic DivStart, output logic [P.FLEN-1:0] X, Y, Z, XPostBox
output logic [P.FLEN-1:0] X, Y, Z, XPostBox
); );
localparam Q_LEN = 32'd128; localparam Q_LEN = 32'd128;
@ -1030,8 +1036,6 @@ module readvectors import cvw::*; #(parameter cvw_t P) (
// apply test vectors on rising edge of clk // apply test vectors on rising edge of clk
// Format of vectors Inputs(1/2/3)_AnsFlg // Format of vectors Inputs(1/2/3)_AnsFlg
always @(VectorNum) begin always @(VectorNum) begin
DivStart = 1'b0;
#1;
AnsFlg = TestVector[4:0]; AnsFlg = TestVector[4:0];
case (Unit) case (Unit)
`FMAUNIT: `FMAUNIT:
@ -1101,30 +1105,18 @@ module readvectors import cvw::*; #(parameter cvw_t P) (
2'b11: begin // quad 2'b11: begin // quad
X = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)]; X = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)];
Ans = TestVector[8+(P.Q_LEN-1):8]; Ans = TestVector[8+(P.Q_LEN-1):8];
if (~clk) #5;
DivStart = 1'b1; #10 // one clk cycle
DivStart = 1'b0;
end end
2'b01: if (P.D_SUPPORTED) begin // double 2'b01: if (P.D_SUPPORTED) begin // double
X = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]}; X = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]};
Ans = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]}; Ans = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
2'b00: if (P.S_SUPPORTED) begin // single 2'b00: if (P.S_SUPPORTED) begin // single
X = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]}; X = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]};
Ans = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]}; Ans = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
2'b10: begin // half 2'b10: begin // half
X = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]}; X = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]};
Ans = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]}; Ans = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
endcase endcase
else else
@ -1133,33 +1125,21 @@ module readvectors import cvw::*; #(parameter cvw_t P) (
X = TestVector[8+3*(P.Q_LEN)-1:8+2*(P.Q_LEN)]; X = TestVector[8+3*(P.Q_LEN)-1:8+2*(P.Q_LEN)];
Y = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)]; Y = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)];
Ans = TestVector[8+(P.Q_LEN-1):8]; Ans = TestVector[8+(P.Q_LEN-1):8];
if (~clk) #5;
DivStart = 1'b1; #10 // one clk cycle
DivStart = 1'b0;
end end
2'b01: if (P.D_SUPPORTED) begin // double 2'b01: if (P.D_SUPPORTED) begin // double
X = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+3*(P.D_LEN)-1:8+2*(P.D_LEN)]}; X = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+3*(P.D_LEN)-1:8+2*(P.D_LEN)]};
Y = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]}; Y = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]};
Ans = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]}; Ans = {{P.FLEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
2'b00: if (P.S_SUPPORTED) begin // single 2'b00: if (P.S_SUPPORTED) begin // single
X = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+3*(P.S_LEN)-1:8+2*(P.S_LEN)]}; X = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+3*(P.S_LEN)-1:8+2*(P.S_LEN)]};
Y = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]}; Y = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]};
Ans = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]}; Ans = {{P.FLEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
2'b10: begin // half 2'b10: begin // half
X = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+3*(P.H_LEN)-1:8+2*(P.H_LEN)]}; X = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+3*(P.H_LEN)-1:8+2*(P.H_LEN)]};
Y = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]}; Y = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]};
Ans = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]}; Ans = {{P.FLEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
if (~clk) #5;
DivStart = 1'b1; #10
DivStart = 1'b0;
end end
endcase endcase
`CMPUNIT: `CMPUNIT: