From 95a97faf3fc480793cc0dcca1ef01c2eea3e1b62 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Mon, 29 Jan 2024 16:46:34 -0600 Subject: [PATCH] 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 --- testbench/testbench-fp.sv | 204 +++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 112 deletions(-) diff --git a/testbench/testbench-fp.sv b/testbench/testbench-fp.sv index b19542d62..46f261c0a 100644 --- a/testbench/testbench-fp.sv +++ b/testbench/testbench-fp.sv @@ -83,7 +83,7 @@ module testbenchfp; logic [P.LOGCVTLEN-1:0] CvtShiftAmtE; // how much to shift by logic [P.DIVb:0] Quot; logic CvtResSubnormUfE; - logic DivStart; + logic DivStart=0; logic FDivBusyE; logic OldFDivBusyE; logic reset = 1'b0; @@ -120,7 +120,11 @@ module testbenchfp; logic ResMatch; // Check if result match logic FlagMatch; // Check if IEEE flags match 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, .Xs, .Ys, .Zs, .Unit(UnitVal), .Xe, .Ye, .Ze, .TestNum, .OpCtrl(OpCtrlVal), - .Xm, .Ym, .Zm, .DivStart, + .Xm, .Ym, .Zm, .XNaN, .YNaN, .ZNaN, .XSNaN, .YSNaN, .ZSNaN, .XSubnorm, .ZSubnorm, @@ -748,16 +752,6 @@ module testbenchfp; clk = 1; #5; clk = 0; #5; 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 - /////////////////////////////////////////////////////////////////////////////////////////////// // ||||| ||| |||||||||| ||||| ||| @@ -835,45 +829,64 @@ module testbenchfp; `CMPUNIT: ResFlg = CmpFlg; `CVTINTUNIT: ResFlg = Flg; `CVTFPUNIT: ResFlg = Flg; - endcase - end + 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 + + // 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) OldFDivBusyE = FDivDoneE; - // For FP division this adds extra clock cycles to make sure the - // computation completes. + // state machine to handle timing for testing due + // various cycle counts for different fp/int operations + // Adds vector at start of clock always @(posedge clk) begin - // Add extra clock cycles in beginning for fdivsqrt to adequate reset state - if (~(FDivBusyE|DivStart)|(UnitVal != `DIVUNIT)) begin - // This allows specific number of clocks to allow each vector - // to complete for division or square root. It is an - // arbitrary value and can be changed, if needed. - case (FmtVal) - // QP - 2'b11: begin - repeat (20) - @(posedge clk); - 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 + + // state machine element for testing + if (reset) + state <= S0; + else + state <= nextstate; + + // Increment the vector when Done with each test + if (state == Done) + VectorNum += 1; // increment the vector + end // 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]})) | (ZNaN&(Res[P.H_LEN-2:0] === {Z[P.H_LEN-2:P.H_NF],1'b1,Z[P.H_NF-2:0]}))); 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]) 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}}})) | @@ -941,29 +954,22 @@ module testbenchfp; /////////////////////////////////////////////////////////////////////////////////////////////// // 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 FlagMatch = ((ResFlg === AnsFlg) | (AnsFlg === 5'bx)); assign divsqrtop = (OpCtrlVal == `SQRT_OPCTRL) | (OpCtrlVal == `DIV_OPCTRL); assign FMAop = (OpCtrlVal == `FMAUNIT); assign DivDone = OldFDivBusyE & ~FDivBusyE; - - // Maybe change OpCtrl but for now just look at TEST for fma test - assign CheckNow = ((DivDone | ~divsqrtop) | (TEST == "add" | TEST == "fma" | TEST == "sub")) & (UnitVal !== `CVTINTUNIT) & (UnitVal !== `CMPUNIT); - if (~(ResMatch & FlagMatch) & CheckNow) begin + assign CheckNow = ((DivDone | ~divsqrtop) | + (TEST == "all" | TEST == "add" | TEST == "fma" | TEST == "sub")) + & (UnitVal !== `CVTINTUNIT) & (UnitVal !== `CMPUNIT); + + if (~(ResMatch & FlagMatch) & CheckNow & (Ans[0] !== 1'bx)) begin 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 Expected: %h %h", X, Y, Z, SrcA, Res, ResFlg, Ans, AnsFlg); $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 // increment the test @@ -979,11 +985,12 @@ module testbenchfp; // increment the rounding mode or loop back to rne if (FrmNum < 4) FrmNum += 1; else begin - FrmNum = 0; + FrmNum = 0; // Add some time as a buffer between tests at the end of each test - repeat (10) - @(posedge clk); - end + // (to be removed) + repeat (10) + @(posedge clk); + end // if no more Tests - finish if (Tests[TestNum] === "") begin $display("\nAll Tests completed with %d errors\n", errors); @@ -996,28 +1003,27 @@ endmodule module readvectors import cvw::*; #(parameter cvw_t P) ( - input logic clk, - input logic [P.FLEN*4+7:0] TestVector, + input logic clk, + input logic [P.FLEN*4+7:0] TestVector, input logic [P.FMTBITS-1:0] ModFmt, - input logic [1:0] Fmt, - input logic [2:0] Unit, - input logic [31:0] VectorNum, - input logic [31:0] TestNum, - input logic [2:0] OpCtrl, - output logic [P.FLEN-1:0] Ans, - output logic [P.XLEN-1:0] SrcA, - output logic [4:0] AnsFlg, - 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.NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision) - output logic XNaN, YNaN, ZNaN, // is XYZ a NaN - output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN - output logic XSubnorm, ZSubnorm, // is XYZ denormalized - output logic XZero, YZero, ZZero, // is XYZ zero - output logic XInf, YInf, ZInf, // is XYZ infinity - output logic XExpMax, - output logic DivStart, - output logic [P.FLEN-1:0] X, Y, Z, XPostBox + input logic [1:0] Fmt, + input logic [2:0] Unit, + input logic [31:0] VectorNum, + input logic [31:0] TestNum, + input logic [2:0] OpCtrl, + output logic [P.FLEN-1:0] Ans, + output logic [P.XLEN-1:0] SrcA, + output logic [4:0] AnsFlg, + 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.NF:0] Xm, Ym, Zm, // mantissas of XYZ (converted to largest supported precision) + output logic XNaN, YNaN, ZNaN, // is XYZ a NaN + output logic XSNaN, YSNaN, ZSNaN, // is XYZ a signaling NaN + output logic XSubnorm, ZSubnorm, // is XYZ denormalized + output logic XZero, YZero, ZZero, // is XYZ zero + output logic XInf, YInf, ZInf, // is XYZ infinity + output logic XExpMax, + output logic [P.FLEN-1:0] X, Y, Z, XPostBox ); 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 // Format of vectors Inputs(1/2/3)_AnsFlg always @(VectorNum) begin - DivStart = 1'b0; - #1; AnsFlg = TestVector[4:0]; case (Unit) `FMAUNIT: @@ -1101,30 +1105,18 @@ module readvectors import cvw::*; #(parameter cvw_t P) ( 2'b11: begin // quad X = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)]; Ans = TestVector[8+(P.Q_LEN-1):8]; - if (~clk) #5; - DivStart = 1'b1; #10 // one clk cycle - DivStart = 1'b0; end 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)]}; 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 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)]}; 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 2'b10: begin // half 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]}; - if (~clk) #5; - DivStart = 1'b1; #10 - DivStart = 1'b0; end endcase 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)]; Y = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)]; Ans = TestVector[8+(P.Q_LEN-1):8]; - if (~clk) #5; - DivStart = 1'b1; #10 // one clk cycle - DivStart = 1'b0; end 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)]}; 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]}; - if (~clk) #5; - DivStart = 1'b1; #10 - DivStart = 1'b0; end 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)]}; 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]}; - if (~clk) #5; - DivStart = 1'b1; #10 - DivStart = 1'b0; end 2'b10: begin // half 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)]}; 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 endcase `CMPUNIT: