/////////////////////////////////////////// // // Written: me@KatherineParry.com // Modified: 7/5/2022 // Modified: 4/2/2023 // // Purpose: Testbench for Testfloat // // A component of the Wally configurable RISC-V project. // // Copyright (C) 2021 Harvey Mudd College & Oklahoma State University // // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 // // Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file // except in compliance with the License, or, at your option, the Apache License version 2.0. You // may obtain a copy of the License at // // https://solderpad.org/licenses/SHL-2.1/ // // Unless required by applicable law or agreed to in writing, any work distributed under the // License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific language governing permissions // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// `include "wally-config.vh" `include "tests-fp.vh" module testbenchfp; parameter TEST="none"; string Tests[]; // list of tests to be run logic [2:0] OpCtrl[]; // list of op controls logic [2:0] Unit[]; // list of units being tested logic WriteInt[]; // Is being written to integer resgiter logic [2:0] Frm[4:0] = {3'b100, 3'b010, 3'b011, 3'b001, 3'b000}; // rounding modes: rne-000, rz-001, ru-011, rd-010, rnm-100 logic [1:0] Fmt[]; // list of formats for the other units logic clk=0; logic [31:0] TestNum=0; // index for the test logic [31:0] OpCtrlNum=0; // index for OpCtrl logic [31:0] errors=0; // how many errors logic [31:0] VectorNum=0; // index for test vector logic [31:0] FrmNum=0; // index for rounding mode logic [`FLEN*4+7:0] TestVectors[8388609:0]; // list of test vectors logic [1:0] FmtVal; // value of the current Fmt logic [2:0] UnitVal, OpCtrlVal, FrmVal; // value of the currnet Unit/OpCtrl/FrmVal logic WriteIntVal; // value of the current WriteInt logic [`FLEN-1:0] X, Y, Z; // inputs read from TestFloat logic [`FLEN-1:0] XPostBox; // inputs read from TestFloat logic [`XLEN-1:0] SrcA; // integer input logic [`FLEN-1:0] Ans; // correct answer from TestFloat logic [`FLEN-1:0] Res; // result from other units logic [4:0] AnsFlg; // correct flags read from testfloat logic [4:0] ResFlg, Flg; // Result flags logic [`FMTBITS-1:0] ModFmt; // format - 10 = half, 00 = single, 01 = double, 11 = quad logic [`FLEN-1:0] FpRes, FpCmpRes; // Results from each unit logic [`XLEN-1:0] IntRes, CmpRes; // Results from each unit logic [4:0] FmaFlg, CvtFlg, DivFlg, CmpFlg; // Outputed flags logic AnsNaN, ResNaN, NaNGood; logic Xs, Ys, Zs; // sign of the inputs logic [`NE-1:0] Xe, Ye, Ze; // exponent of the inputs logic [`NF:0] Xm, Ym, Zm; // mantissas of the inputs logic XNaN, YNaN, ZNaN; // is the input NaN logic XSNaN, YSNaN, ZSNaN; // is the input a signaling NaN logic XSubnorm, ZSubnorm; // is the input denormalized logic XInf, YInf, ZInf; // is the input infinity logic XZero, YZero, ZZero; // is the input zero logic XExpMax, YExpMax, ZExpMax; // is the input's exponent all ones logic [`CVTLEN-1:0] CvtLzcInE; // input to the Leading Zero Counter (priority encoder) logic IntZero; logic CvtResSgnE; logic [`NE:0] CvtCalcExpE; // the calculated expoent logic [`LOGCVTLEN-1:0] CvtShiftAmtE; // how much to shift by logic [`DIVb:0] Quot; logic CvtResSubnormUfE; logic DivStart, FDivBusyE, OldFDivBusyE; logic reset = 1'b0; logic [$clog2(`NF+2)-1:0] XZeroCnt, YZeroCnt; logic [`DURLEN-1:0] Dur; // in-between FMA signals logic Mult; logic Ss; logic [`NE+1:0] Pe; logic [`NE+1:0] Se; logic ASticky; logic KillProd; logic [$clog2(3*`NF+5)-1:0] SCnt; logic [3*`NF+3:0] Sm; logic InvA; logic NegSum; logic As; logic Ps; logic DivSticky; logic DivDone; logic DivNegSticky; logic [`NE+1:0] DivCalcExp; logic divsqrtop; // Missing logic vectors fdivsqrt logic [2:0] Funct3E; logic [2:0] Funct3M; logic FlushE; logic IFDivStartE, FDivDoneE; logic [`NE+1:0] QeM; logic [`DIVb:0] QmM; logic [`XLEN-1:0] FIntDivResultM; /////////////////////////////////////////////////////////////////////////////////////////////// // ||||||||| |||||||| ||||||| ||||||||| ||||||| |||||||| ||| // ||| ||| ||| ||| ||| ||| ||| // ||| |||||||| ||||||| ||| ||||||| |||||||| ||| // ||| ||| ||| ||| ||| ||| ||| // ||| |||||||| ||||||| ||| ||||||| |||||||| ||||||||| /////////////////////////////////////////////////////////////////////////////////////////////// // select tests relevent to the specified configuration // cvtint - test integer conversion unit (fcvtint) // cvtfp - test floating-point conversion unit (fcvtfp) // cmp - test comparison unit's LT, LE, EQ opperations (fcmp) // add - test addition // sub - test subtraction // div - test division // sqrt - test square root // all - test all of the above initial begin $display("TEST is %s", TEST); if (`Q_SUPPORTED) begin // if Quad percision is supported if (TEST === "cvtint"| TEST === "all") begin // if testing integer conversion // add the 128-bit cvtint tests to the to-be-tested list Tests = {Tests, f128rv32cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UI_OPCTRL, `FROM_I_OPCTRL, `TO_UI_OPCTRL, `TO_I_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b11}; end if (`XLEN == 64) begin // if 64-bit integers are supported add their conversions Tests = {Tests, f128rv64cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UL_OPCTRL, `FROM_L_OPCTRL, `TO_UL_OPCTRL, `TO_L_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b11}; end end end // if the floating-point conversions are being tested if (TEST === "cvtfp" | TEST === "all") begin if(`D_SUPPORTED) begin // if double precision is supported // add the 128 <-> 64 bit conversions to the to-be-tested list Tests = {Tests, f128f64cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b01, 3'b11}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b11}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b01}; end end if(`F_SUPPORTED) begin // if single precision is supported // add the 128 <-> 32 bit conversions to the to-be-tested list Tests = {Tests, f128f32cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b00, 3'b11}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b11}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b00}; end end if(`ZFH_SUPPORTED) begin // if half precision is supported // add the 128 <-> 16 bit conversions to the to-be-tested list Tests = {Tests, f128f16cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b10, 3'b11}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b11}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b10}; end end end if (TEST === "cmp" | TEST === "all") begin// if comparisons are being tested // add the compare tests/op-ctrls/unit/fmt Tests = {Tests, f128cmp}; OpCtrl = {OpCtrl, `EQ_OPCTRL, `LE_OPCTRL, `LT_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b0}; for(int i = 0; i<15; i++) begin Unit = {Unit, `CMPUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "add" | TEST === "all") begin // if addition is being tested // add the addition tests/op-ctrls/unit/fmt Tests = {Tests, f128add}; OpCtrl = {OpCtrl, `ADD_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "sub" | TEST === "all") begin // if subtraction is being tested // add the subtraction tests/op-ctrls/unit/fmt Tests = {Tests, f128sub}; OpCtrl = {OpCtrl, `SUB_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "mul" | TEST === "all") begin // if multiplication is being tested // add the multiply tests/op-ctrls/unit/fmt Tests = {Tests, f128mul}; OpCtrl = {OpCtrl, `MUL_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "div" | TEST === "all") begin // if division is being tested // add the divide tests/op-ctrls/unit/fmt Tests = {Tests, f128div}; OpCtrl = {OpCtrl, `DIV_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "sqrt" | TEST === "all") begin // if square-root is being tested // add the square-root tests/op-ctrls/unit/fmt Tests = {Tests, f128sqrt}; OpCtrl = {OpCtrl, `SQRT_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b11}; end end if (TEST === "fma" | TEST === "all") begin // if fused-mutliply-add is being tested Tests = {Tests, f128fma}; OpCtrl = {OpCtrl, `FMA_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b11}; end end end if (`D_SUPPORTED) begin // if double precision is supported if (TEST === "cvtint"| TEST === "all") begin // if integer conversion is being tested Tests = {Tests, f64rv32cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UI_OPCTRL, `FROM_I_OPCTRL, `TO_UI_OPCTRL, `TO_I_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b01}; end if (`XLEN == 64) begin // if 64-bit integers are being supported Tests = {Tests, f64rv64cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UL_OPCTRL, `FROM_L_OPCTRL, `TO_UL_OPCTRL, `TO_L_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b01}; end end end if (TEST === "cvtfp" | TEST === "all") begin // if floating point conversions are being tested if(`F_SUPPORTED) begin // if single precision is supported // add the 64 <-> 32 bit conversions to the to-be-tested list Tests = {Tests, f64f32cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b00, 3'b01}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b01}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b00}; end end if(`ZFH_SUPPORTED) begin // if half precision is supported // add the 64 <-> 16 bit conversions to the to-be-tested list Tests = {Tests, f64f16cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b10, 3'b01}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b01}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b10}; end end end if (TEST === "cmp" | TEST === "all") begin // if comparisions are being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64cmp}; OpCtrl = {OpCtrl, `EQ_OPCTRL, `LE_OPCTRL, `LT_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b0}; for(int i = 0; i<15; i++) begin Unit = {Unit, `CMPUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "add" | TEST === "all") begin // if addition is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64add}; OpCtrl = {OpCtrl, `ADD_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "sub" | TEST === "all") begin // if subtration is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64sub}; OpCtrl = {OpCtrl, `SUB_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "mul" | TEST === "all") begin // if multiplication is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64mul}; OpCtrl = {OpCtrl, `MUL_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "div" | TEST === "all") begin // if division is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64div}; OpCtrl = {OpCtrl, `DIV_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "sqrt" | TEST === "all") begin // if square-root is being tessted // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f64sqrt}; OpCtrl = {OpCtrl, `SQRT_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b01}; end end if (TEST === "fma" | TEST === "all") begin // if the fused multiply add is being tested Tests = {Tests, f64fma}; OpCtrl = {OpCtrl, `FMA_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b01}; end end end if (`F_SUPPORTED) begin // if single precision being supported if (TEST === "cvtint"| TEST === "all") begin // if integer conversion is being tested Tests = {Tests, f32rv32cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UI_OPCTRL, `FROM_I_OPCTRL, `TO_UI_OPCTRL, `TO_I_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b00}; end if (`XLEN == 64) begin // if 64-bit integers are supported Tests = {Tests, f32rv64cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UL_OPCTRL, `FROM_L_OPCTRL, `TO_UL_OPCTRL, `TO_L_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b00}; end end end if (TEST === "cvtfp" | TEST === "all") begin // if floating point conversion is being tested if(`ZFH_SUPPORTED) begin // add the 32 <-> 16 bit conversions to the to-be-tested list Tests = {Tests, f32f16cvt}; // add the op-ctrls (i.e. the format of the result) OpCtrl = {OpCtrl, 3'b10, 3'b00}; WriteInt = {WriteInt, 1'b0, 1'b0}; // add the unit being tested and fmt (input format) for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b00}; end for(int i = 0; i<5; i++) begin Unit = {Unit, `CVTFPUNIT}; Fmt = {Fmt, 2'b10}; end end end if (TEST === "cmp" | TEST === "all") begin // if comparision is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32cmp}; OpCtrl = {OpCtrl, `EQ_OPCTRL, `LE_OPCTRL, `LT_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b0}; for(int i = 0; i<15; i++) begin Unit = {Unit, `CMPUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "add" | TEST === "all") begin // if addition is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32add}; OpCtrl = {OpCtrl, `ADD_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "sub" | TEST === "all") begin // if subtration is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32sub}; OpCtrl = {OpCtrl, `SUB_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "mul" | TEST === "all") begin // if multiply is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32mul}; OpCtrl = {OpCtrl, `MUL_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "div" | TEST === "all") begin // if division is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32div}; OpCtrl = {OpCtrl, `DIV_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "sqrt" | TEST === "all") begin // if sqrt is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f32sqrt}; OpCtrl = {OpCtrl, `SQRT_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b00}; end end if (TEST === "fma" | TEST === "all") begin // if fma is being tested Tests = {Tests, f32fma}; OpCtrl = {OpCtrl, `FMA_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b00}; end end end if (`ZFH_SUPPORTED) begin // if half precision supported if (TEST === "cvtint"| TEST === "all") begin // if in conversions are being tested Tests = {Tests, f16rv32cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UI_OPCTRL, `FROM_I_OPCTRL, `TO_UI_OPCTRL, `TO_I_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b10}; end if (`XLEN == 64) begin // if 64-bit integers are supported Tests = {Tests, f16rv64cvtint}; // add the op-codes for these tests to the op-code list OpCtrl = {OpCtrl, `FROM_UL_OPCTRL, `FROM_L_OPCTRL, `TO_UL_OPCTRL, `TO_L_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b1, 1'b1}; // add what unit is used and the fmt to their lists (one for each test) for(int i = 0; i<20; i++) begin Unit = {Unit, `CVTINTUNIT}; Fmt = {Fmt, 2'b10}; end end end if (TEST === "cmp" | TEST === "all") begin // if comparisions are being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16cmp}; OpCtrl = {OpCtrl, `EQ_OPCTRL, `LE_OPCTRL, `LT_OPCTRL}; WriteInt = {WriteInt, 1'b0, 1'b0, 1'b0}; for(int i = 0; i<15; i++) begin Unit = {Unit, `CMPUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "add" | TEST === "all") begin // if addition is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16add}; OpCtrl = {OpCtrl, `ADD_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "sub" | TEST === "all") begin // if subtraction is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16sub}; OpCtrl = {OpCtrl, `SUB_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "mul" | TEST === "all") begin // if multiplication is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16mul}; OpCtrl = {OpCtrl, `MUL_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "div" | TEST === "all") begin // if division is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16div}; OpCtrl = {OpCtrl, `DIV_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "sqrt" | TEST === "all") begin // if sqrt is being tested // add the correct tests/op-ctrls/unit/fmt to their lists Tests = {Tests, f16sqrt}; OpCtrl = {OpCtrl, `SQRT_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `DIVUNIT}; Fmt = {Fmt, 2'b10}; end end if (TEST === "fma" | TEST === "all") begin // if fma is being tested Tests = {Tests, f16fma}; OpCtrl = {OpCtrl, `FMA_OPCTRL}; WriteInt = {WriteInt, 1'b0}; for(int i = 0; i<5; i++) begin Unit = {Unit, `FMAUNIT}; Fmt = {Fmt, 2'b10}; end end end // check if nothing is being tested if (Tests.size() == 0) begin $display("TEST %s not supported in this configuration", TEST); $stop; end end /////////////////////////////////////////////////////////////////////////////////////////////// // ||||||||| |||||||| ||||||||| ||||||| ||||||||| |||||||| ||||||| ||||||||| // ||| ||| ||| ||| ||| || || ||| ||| ||| ||| // |||||||| |||||||| ||||||||| || || ||| |||||||| ||||||| ||| // ||| || ||| ||| ||| || || ||| ||| ||| ||| // ||| ||| |||||||| ||| ||| ||||||| ||| |||||||| ||||||| ||| /////////////////////////////////////////////////////////////////////////////////////////////// // Read the first test initial begin $display("\n\nRunning %s vectors", Tests[TestNum]); $readmemh({`PATH, Tests[TestNum]}, TestVectors); // set the test index to 0 TestNum = 0; end // set a the signals for all tests always_comb UnitVal = Unit[TestNum]; always_comb FmtVal = Fmt[TestNum]; always_comb OpCtrlVal = OpCtrl[OpCtrlNum]; always_comb WriteIntVal = WriteInt[OpCtrlNum]; always_comb FrmVal = Frm[FrmNum]; // modify the format signal if only 2 percisions supported // - 1 for the larger precision // - 0 for the smaller precision always_comb begin if(`FMTBITS == 1) ModFmt = FmtVal == `FMT; else ModFmt = FmtVal; end // extract the inputs (X, Y, Z, SrcA) and the output (Ans, AnsFlg) from the current test vector readvectors readvectors (.clk, .Fmt(FmtVal), .ModFmt, .TestVector(TestVectors[VectorNum]), .VectorNum, .Ans(Ans), .AnsFlg(AnsFlg), .SrcA, .Xs, .Ys, .Zs, .Unit(UnitVal), .Xe, .Ye, .Ze, .TestNum, .OpCtrl(OpCtrlVal), .Xm, .Ym, .Zm, .DivStart, .XNaN, .YNaN, .ZNaN, .XSNaN, .YSNaN, .ZSNaN, .XSubnorm, .ZSubnorm, .XZero, .YZero, .ZZero, .XInf, .YInf, .ZInf, .XExpMax, .X, .Y, .Z, .XPostBox); /////////////////////////////////////////////////////////////////////////////////////////////// // ||||||| ||| ||| ||||||||| // ||| ||| ||| ||| ||| // ||| ||| ||| ||| ||| // ||| ||| ||| ||| ||| // ||||||| ||||||||| ||| /////////////////////////////////////////////////////////////////////////////////////////////// // instantiate devices under test if (TEST === "fma"| TEST === "mul" | TEST === "add" | TEST === "sub" | TEST === "all") begin : fma fma fma(.Xs(Xs), .Ys(Ys), .Zs(Zs), .Xe(Xe), .Ye(Ye), .Ze(Ze), .Xm(Xm), .Ym(Ym), .Zm(Zm), .XZero, .YZero, .ZZero, .Ss, .Se, .OpCtrl(OpCtrlVal), .Sm, .InvA, .SCnt, .As, .Ps, .ASticky); end postprocess postprocess(.Xs(Xs), .Ys(Ys), .PostProcSel(UnitVal[1:0]), .OpCtrl(OpCtrlVal), .DivQm(Quot), .DivQe(DivCalcExp), .Xm(Xm), .Ym(Ym), .Zm(Zm), .CvtCe(CvtCalcExpE), .DivSticky(DivSticky), .FmaSs(Ss), .XNaN(XNaN), .YNaN(YNaN), .ZNaN(ZNaN), .CvtResSubnormUf(CvtResSubnormUfE), .XZero(XZero), .YZero(YZero), .CvtShiftAmt(CvtShiftAmtE), .XInf(XInf), .YInf(YInf), .ZInf(ZInf), .CvtCs(CvtResSgnE), .ToInt(WriteIntVal), .XSNaN(XSNaN), .YSNaN(YSNaN), .ZSNaN(ZSNaN), .CvtLzcIn(CvtLzcInE), .IntZero, .FmaASticky(ASticky), .FmaSe(Se), .FmaSm(Sm), .FmaSCnt(SCnt), .FmaAs(As), .FmaPs(Ps), .Fmt(ModFmt), .Frm(FrmVal), .PostProcFlg(Flg), .PostProcRes(FpRes), .FCvtIntRes(IntRes)); if (TEST === "cvtfp" | TEST === "cvtint" | TEST === "all") begin : fcvt fcvt fcvt (.Xs(Xs), .Xe(Xe), .Xm(Xm), .Int(SrcA), .ToInt(WriteIntVal), .XZero(XZero), .OpCtrl(OpCtrlVal), .IntZero, .Fmt(ModFmt), .Ce(CvtCalcExpE), .ShiftAmt(CvtShiftAmtE), .ResSubnormUf(CvtResSubnormUfE), .Cs(CvtResSgnE), .LzcIn(CvtLzcInE)); end if (TEST === "cmp" | TEST === "all") begin: fcmp fcmp fcmp (.Fmt(ModFmt), .OpCtrl(OpCtrlVal), .Xs, .Ys, .Xe, .Ye, .Xm, .Ym, .XZero, .YZero, .CmpIntRes(CmpRes), .XNaN, .YNaN, .XSNaN, .YSNaN, .X, .Y, .CmpNV(CmpFlg[4]), .CmpFpRes(FpCmpRes)); end if (TEST === "div" | TEST === "sqrt" | TEST === "all") begin: fdivsqrt fdivsqrt fdivsqrt(.clk, .reset, .XsE(Xs), .FmtE(ModFmt), .XmE(Xm), .YmE(Ym), .XeE(Xe), .YeE(Ye), .SqrtE(OpCtrlVal[0]), .SqrtM(OpCtrlVal[0]), .XInfE(XInf), .YInfE(YInf), .XZeroE(XZero), .YZeroE(YZero), .XNaNE(XNaN), .YNaNE(YNaN), .FDivStartE(DivStart), .IDivStartE(1'b0), .W64E(1'b0), .StallM(1'b0), .DivStickyM(DivSticky), .FDivBusyE, .QeM(DivCalcExp), .QmM(Quot), .FlushE(1'b0), .ForwardedSrcAE('0), .ForwardedSrcBE('0), .Funct3M(Funct3M), .Funct3E(Funct3E), .IntDivE(1'b0), .FIntDivResultM(FIntDivResultM), .FDivDoneE(FDivDoneE), .IFDivStartE(IFDivStartE)); end assign CmpFlg[3:0] = 0; // produce clock always begin 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 /////////////////////////////////////////////////////////////////////////////////////////////// // ||||| ||| |||||||||| ||||| ||| // ||||||| ||| ||| ||| ||||||| ||| // |||| ||| ||| |||||||||| |||| ||| ||| // |||| ||| ||| ||| ||| |||| ||| ||| // |||| ||| ||| ||| ||| |||| ||| ||| // |||| |||||| ||| ||| |||| |||||| /////////////////////////////////////////////////////////////////////////////////////////////// // Check if the correct answer and result is a NaN always_comb begin if(UnitVal === `CVTINTUNIT | UnitVal === `CMPUNIT) begin // an integer output can't be a NaN AnsNaN = 1'b0; ResNaN = 1'b0; end else if (UnitVal === `CVTFPUNIT) begin case (OpCtrlVal[1:0]) 4'b11: begin // quad AnsNaN = &Ans[`Q_LEN-2:`NF]&(|Ans[`Q_NF-1:0]); ResNaN = &Res[`Q_LEN-2:`NF]&(|Res[`Q_NF-1:0]); end 4'b01: begin // double AnsNaN = &Ans[`D_LEN-2:`D_NF]&(|Ans[`D_NF-1:0]); ResNaN = &Res[`D_LEN-2:`D_NF]&(|Res[`D_NF-1:0]); end 4'b00: begin // single AnsNaN = &Ans[`S_LEN-2:`S_NF]&(|Ans[`S_NF-1:0]); ResNaN = &Res[`S_LEN-2:`S_NF]&(|Res[`S_NF-1:0]); end 4'b10: begin // half AnsNaN = &Ans[`H_LEN-2:`H_NF]&(|Ans[`H_NF-1:0]); ResNaN = &Res[`H_LEN-2:`H_NF]&(|Res[`H_NF-1:0]); end endcase end else begin case (FmtVal) 4'b11: begin // quad AnsNaN = &Ans[`Q_LEN-2:`Q_NF]&(|Ans[`Q_NF-1:0]); ResNaN = &Res[`Q_LEN-2:`Q_NF]&(|Res[`Q_NF-1:0]); end 4'b01: begin // double AnsNaN = &Ans[`D_LEN-2:`D_NF]&(|Ans[`D_NF-1:0]); ResNaN = &Res[`D_LEN-2:`D_NF]&(|Res[`D_NF-1:0]); end 4'b00: begin // single AnsNaN = &Ans[`S_LEN-2:`S_NF]&(|Ans[`S_NF-1:0]); ResNaN = &Res[`S_LEN-2:`S_NF]&(|Res[`S_NF-1:0]); end 4'b10: begin // half AnsNaN = &Ans[`H_LEN-2:`H_NF]&(|Ans[`H_NF-1:0]); ResNaN = &Res[`H_LEN-2:`H_NF]&(|Res[`H_NF-1:0]); end endcase end end always_comb begin // select the result to check case (UnitVal) `FMAUNIT: Res = FpRes; `DIVUNIT: Res = FpRes; `CMPUNIT: Res = CmpRes; `CVTINTUNIT: if(WriteIntVal) Res = IntRes; else Res = FpRes; `CVTFPUNIT: Res = FpRes; endcase // select the flag to check case (UnitVal) `FMAUNIT: ResFlg = Flg; `DIVUNIT: ResFlg = Flg; `CMPUNIT: ResFlg = CmpFlg; `CVTINTUNIT: ResFlg = Flg; `CVTFPUNIT: ResFlg = Flg; endcase end logic ResMatch, FlagMatch, CheckNow; always @(posedge clk) OldFDivBusyE = FDivDoneE; // check results on falling edge of clk always @(negedge clk) begin // check if the NaN value is good. IEEE754-2019 sections 6.3 and 6.2.3 specify: // - the sign of the NaN does not matter for the opperations being tested // - when 2 or more NaNs are inputed the NaN that is propigated doesn't matter if (UnitVal !== `CVTFPUNIT & UnitVal !== `CVTINTUNIT) case (FmtVal) 4'b11: NaNGood = (((`IEEE754==0)&AnsNaN&(Res === {1'b0, {`Q_NE+1{1'b1}}, {`Q_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`Q_LEN-2:0] === {{`Q_NE+1{1'b1}}, {`Q_NF-1{1'b0}}})) | (XNaN&(Res[`Q_LEN-2:0] === {X[`Q_LEN-2:`Q_NF],1'b1,X[`Q_NF-2:0]})) | (YNaN&(Res[`Q_LEN-2:0] === {Y[`Q_LEN-2:`Q_NF],1'b1,Y[`Q_NF-2:0]})) | (ZNaN&(Res[`Q_LEN-2:0] === {Z[`Q_LEN-2:`Q_NF],1'b1,Z[`Q_NF-2:0]}))); 4'b01: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`D_LEN-1:0] === {1'b0, {`D_NE+1{1'b1}}, {`D_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`D_LEN-2:0] === {{`D_NE+1{1'b1}}, {`D_NF-1{1'b0}}})) | (XNaN&(Res[`D_LEN-2:0] === {X[`D_LEN-2:`D_NF],1'b1,X[`D_NF-2:0]})) | (YNaN&(Res[`D_LEN-2:0] === {Y[`D_LEN-2:`D_NF],1'b1,Y[`D_NF-2:0]})) | (ZNaN&(Res[`D_LEN-2:0] === {Z[`D_LEN-2:`D_NF],1'b1,Z[`D_NF-2:0]}))); 4'b00: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`S_LEN-1:0] === {1'b0, {`S_NE+1{1'b1}}, {`S_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`S_LEN-2:0] === {{`S_NE+1{1'b1}}, {`S_NF-1{1'b0}}})) | (XNaN&(Res[`S_LEN-2:0] === {X[`S_LEN-2:`S_NF],1'b1,X[`S_NF-2:0]})) | (YNaN&(Res[`S_LEN-2:0] === {Y[`S_LEN-2:`S_NF],1'b1,Y[`S_NF-2:0]})) | (ZNaN&(Res[`S_LEN-2:0] === {Z[`S_LEN-2:`S_NF],1'b1,Z[`S_NF-2:0]}))); 4'b10: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`H_LEN-1:0] === {1'b0, {`H_NE+1{1'b1}}, {`H_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`H_LEN-2:0] === {{`H_NE+1{1'b1}}, {`H_NF-1{1'b0}}})) | (XNaN&(Res[`H_LEN-2:0] === {X[`H_LEN-2:`H_NF],1'b1,X[`H_NF-2:0]})) | (YNaN&(Res[`H_LEN-2:0] === {Y[`H_LEN-2:`H_NF],1'b1,Y[`H_NF-2:0]})) | (ZNaN&(Res[`H_LEN-2:0] === {Z[`H_LEN-2:`H_NF],1'b1,Z[`H_NF-2:0]}))); endcase else if (UnitVal === `CVTFPUNIT) // if converting from floating point to floating point OpCtrl contains the final FP format case (OpCtrlVal[1:0]) 2'b11: NaNGood = (((`IEEE754==0)&AnsNaN&(Res === {1'b0, {`Q_NE+1{1'b1}}, {`Q_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`Q_LEN-2:0] === {{`Q_NE+1{1'b1}}, {`Q_NF-1{1'b0}}})) | (AnsNaN&(Res[`Q_LEN-2:0] === Ans[`Q_LEN-2:0])) | (XNaN&(Res[`Q_LEN-2:0] === {X[`Q_LEN-2:`Q_NF],1'b1,X[`Q_NF-2:0]})) | (YNaN&(Res[`Q_LEN-2:0] === {Y[`Q_LEN-2:`Q_NF],1'b1,Y[`Q_NF-2:0]}))); 2'b01: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`D_LEN-1:0] === {1'b0, {`D_NE+1{1'b1}}, {`D_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`D_LEN-2:0] === {{`D_NE+1{1'b1}}, {`D_NF-1{1'b0}}})) | (AnsNaN&(Res[`D_LEN-2:0] === Ans[`D_LEN-2:0])) | (XNaN&(Res[`D_LEN-2:0] === {X[`D_LEN-2:`D_NF],1'b1,X[`D_NF-2:0]})) | (YNaN&(Res[`D_LEN-2:0] === {Y[`D_LEN-2:`D_NF],1'b1,Y[`D_NF-2:0]}))); 2'b00: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`S_LEN-1:0] === {1'b0, {`S_NE+1{1'b1}}, {`S_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`S_LEN-2:0] === {{`S_NE+1{1'b1}}, {`S_NF-1{1'b0}}})) | (AnsNaN&(Res[`S_LEN-2:0] === Ans[`S_LEN-2:0])) | (XNaN&(Res[`S_LEN-2:0] === {X[`S_LEN-2:`S_NF],1'b1,X[`S_NF-2:0]})) | (YNaN&(Res[`S_LEN-2:0] === {Y[`S_LEN-2:`S_NF],1'b1,Y[`S_NF-2:0]}))); 2'b10: NaNGood = (((`IEEE754==0)&AnsNaN&(Res[`H_LEN-1:0] === {1'b0, {`H_NE+1{1'b1}}, {`H_NF-1{1'b0}}})) | (AnsFlg[4]&(Res[`H_LEN-2:0] === {{`H_NE+1{1'b1}}, {`H_NF-1{1'b0}}})) | (AnsNaN&(Res[`H_LEN-2:0] === Ans[`H_LEN-2:0])) | (XNaN&(Res[`H_LEN-2:0] === {X[`H_LEN-2:`H_NF],1'b1,X[`H_NF-2:0]})) | (YNaN&(Res[`H_LEN-2:0] === {Y[`H_LEN-2:`H_NF],1'b1,Y[`H_NF-2:0]}))); endcase else NaNGood = 1'b0; // integers can't be NaNs /////////////////////////////////////////////////////////////////////////////////////////////// // ||||||| ||| ||| ||||||| ||||||| ||| ||| // ||| ||| ||| ||| ||| ||| ||| // ||| |||||||||| ||||||| ||| |||||| // ||| ||| ||| ||| ||| ||| ||| // ||||||| ||| ||| ||||||| ||||||| ||| ||| /////////////////////////////////////////////////////////////////////////////////////////////// // 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) // if(~((Res === Ans | NaNGood | NaNGood === 1'bx) & (ResFlg === AnsFlg | AnsFlg === 5'bx))&~((FDivBusyE===1'b1)|DivStart)&(UnitVal !== `CVTINTUNIT)&(UnitVal !== `CMPUNIT)) begin ResMatch = (Res === Ans | NaNGood | NaNGood === 1'bx); FlagMatch = (ResFlg === AnsFlg | AnsFlg === 5'bx); divsqrtop = OpCtrlVal == `SQRT_OPCTRL | OpCtrlVal == `DIV_OPCTRL; assign DivDone = OldFDivBusyE & ~FDivBusyE; //assign divsqrtop = OpCtrl[TestNum] == `SQRT_OPCTRL | OpCtrl[TestNum] == `DIV_OPCTRL; CheckNow = (DivDone | ~divsqrtop) & (UnitVal !== `CVTINTUNIT)&(UnitVal !== `CMPUNIT); if(~(ResMatch & FlagMatch) & CheckNow) begin // if(~((Res === Ans | NaNGood | NaNGood === 1'bx) & (ResFlg === AnsFlg | AnsFlg === 5'bx))&(DivDone | (TEST != "sqrt" & TEST != "div"))&(UnitVal !== `CVTINTUNIT)&(UnitVal !== `CMPUNIT)) begin errors += 1; $display("TestNum %d OpCtrl %d", TestNum, OpCtrl[TestNum]); $display("Error in %s", Tests[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 // TestFloat sets the result to all 1's when there is an invalid result, however in // http://www.jhauser.us/arithmetic/TestFloat-3/doc/TestFloat-general.html it says // for an unsigned integer result 0 is also okay // Testfloat outputs 800... for both the largest integer values for both positive and negitive numbers but // the riscv spec specifies 2^31-1 for positive values out of range and NaNs ie 7fff... else if ((UnitVal === `CVTINTUNIT) & ~(((WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&Xs&(Res[`XLEN-1:0] === (`XLEN)'(0))) | (WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~Xs|XNaN)&OpCtrlVal[1]&(Res[`XLEN-1:0] === {1'b0, {`XLEN-1{1'b1}}})) | (WriteIntVal&OpCtrlVal[0]&AnsFlg[4]&(~Xs|XNaN)&~OpCtrlVal[1]&(Res[`XLEN-1:0] === {{`XLEN-32{1'b0}}, 1'b0, {31{1'b1}}})) | (~(WriteIntVal&~OpCtrlVal[0]&AnsFlg[4]&Xs&~XNaN)&(Res === Ans | NaNGood | NaNGood === 1'bx))) & (ResFlg === AnsFlg | AnsFlg === 5'bx))) begin errors += 1; $display("There is an error in %s", Tests[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 // Add extra clock cycles in beginning for fdivsqrt to adequate reset state if(~(FDivBusyE|DivStart)|(UnitVal != `DIVUNIT)) begin repeat (12) @(posedge clk); if (reset != 1'b1) VectorNum += 1; // increment the vector end if (TestVectors[VectorNum][0] === 1'bx & Tests[TestNum] !== "") begin // if reached the eof // increment the test TestNum += 1; // clear the vectors for(int i=0; i<6133248; i++) TestVectors[i] = {`FLEN*4+8{1'bx}}; // read next files $readmemh({`PATH, Tests[TestNum]}, TestVectors); // set the vector index back to 0 VectorNum = 0; // incemet the operation if all the rounding modes have been tested if(FrmNum === 4) OpCtrlNum += 1; // increment the rounding mode or loop back to rne if(FrmNum < 4) FrmNum += 1; else FrmNum = 0; // if no more Tests - finish if(Tests[TestNum] === "") begin $display("\nAll Tests completed with %d errors\n", errors); $stop; end $display("Running %s vectors", Tests[TestNum]); end end endmodule module readvectors ( input logic clk, input logic [`FLEN*4+7:0] TestVector, input logic [`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 [`FLEN-1:0] Ans, output logic [`XLEN-1:0] SrcA, output logic [4:0] AnsFlg, output logic Xs, Ys, Zs, // sign bits of XYZ output logic [`NE-1:0] Xe, Ye, Ze, // exponents of XYZ (converted to largest supported precision) output logic [`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 [`FLEN-1:0] X, Y, Z, XPostBox ); logic XEn, YEn, ZEn; // apply test vectors on rising edge of clk // Format of vectors Inputs(1/2/3)_AnsFlg always @(VectorNum) begin #1; AnsFlg = TestVector[4:0]; DivStart = 1'b0; case (Unit) `FMAUNIT: case (Fmt) 2'b11: begin // quad if(OpCtrl === `FMA_OPCTRL) begin X = TestVector[8+4*(`Q_LEN)-1:8+3*(`Q_LEN)]; Y = TestVector[8+3*(`Q_LEN)-1:8+2*(`Q_LEN)]; Z = TestVector[8+2*(`Q_LEN)-1:8+`Q_LEN]; end else begin X = TestVector[8+3*(`Q_LEN)-1:8+2*(`Q_LEN)]; if(OpCtrl === `MUL_OPCTRL) Y = TestVector[8+2*(`Q_LEN)-1:8+(`Q_LEN)]; else Y = {2'b0, {`Q_NE-1{1'b1}}, (`Q_NF)'(0)}; if(OpCtrl === `MUL_OPCTRL) Z = 0; else Z = TestVector[8+2*(`Q_LEN)-1:8+(`Q_LEN)]; end Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: if (`D_SUPPORTED)begin // double if(OpCtrl === `FMA_OPCTRL) begin X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+4*(`D_LEN)-1:8+3*(`D_LEN)]}; Y = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+3*(`D_LEN)-1:8+2*(`D_LEN)]}; Z = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+2*(`D_LEN)-1:8+`D_LEN]}; end else begin X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+3*(`D_LEN)-1:8+2*(`D_LEN)]}; if(OpCtrl === `MUL_OPCTRL) Y = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+2*(`D_LEN)-1:8+(`D_LEN)]}; else Y = {{`FLEN-`D_LEN{1'b1}}, 2'b0, {`D_NE-1{1'b1}}, (`D_NF)'(0)}; if(OpCtrl === `MUL_OPCTRL) Z = {{`FLEN-`D_LEN{1'b1}}, {`D_LEN{1'b0}}}; else Z = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+2*(`D_LEN)-1:8+(`D_LEN)]}; end Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b00: if (`S_SUPPORTED)begin // single if(OpCtrl === `FMA_OPCTRL) begin X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+4*(`S_LEN)-1:8+3*(`S_LEN)]}; Y = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+3*(`S_LEN)-1:8+2*(`S_LEN)]}; Z = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+2*(`S_LEN)-1:8+`S_LEN]}; end else begin X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+3*(`S_LEN)-1:8+2*(`S_LEN)]}; if(OpCtrl === `MUL_OPCTRL) Y = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+2*(`S_LEN)-1:8+(`S_LEN)]}; else Y = {{`FLEN-`S_LEN{1'b1}}, 2'b0, {`S_NE-1{1'b1}}, (`S_NF)'(0)}; if(OpCtrl === `MUL_OPCTRL) Z = {{`FLEN-`S_LEN{1'b1}}, {`S_LEN{1'b0}}}; else Z = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+2*(`S_LEN)-1:8+(`S_LEN)]}; end Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // half if(OpCtrl === `FMA_OPCTRL) begin X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+4*(`H_LEN)-1:8+3*(`H_LEN)]}; Y = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+3*(`H_LEN)-1:8+2*(`H_LEN)]}; Z = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+2*(`H_LEN)-1:8+`H_LEN]}; end else begin X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+3*(`H_LEN)-1:8+2*(`H_LEN)]}; if(OpCtrl === `MUL_OPCTRL) Y = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+2*(`H_LEN)-1:8+(`H_LEN)]}; else Y = {{`FLEN-`H_LEN{1'b1}}, 2'b0, {`H_NE-1{1'b1}}, (`H_NF)'(0)}; if(OpCtrl === `MUL_OPCTRL) Z = {{`FLEN-`H_LEN{1'b1}}, {`H_LEN{1'b0}}}; else Z = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+2*(`H_LEN)-1:8+(`H_LEN)]}; end Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end endcase `DIVUNIT: if(OpCtrl[0]) case (Fmt) 2'b11: begin // quad X = TestVector[8+2*(`Q_LEN)-1:8+(`Q_LEN)]; Ans = TestVector[8+(`Q_LEN-1):8]; if (~clk) #5; DivStart = 1'b1; #10 // one clk cycle DivStart = 1'b0; end 2'b01: if (`D_SUPPORTED)begin // double X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+2*(`D_LEN)-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end 2'b00: if (`S_SUPPORTED)begin // single X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+2*(`S_LEN)-1:8+1*(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end 2'b10: begin // half X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+2*(`H_LEN)-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end endcase else case (Fmt) 2'b11: begin // quad X = TestVector[8+3*(`Q_LEN)-1:8+2*(`Q_LEN)]; Y = TestVector[8+2*(`Q_LEN)-1:8+(`Q_LEN)]; Ans = TestVector[8+(`Q_LEN-1):8]; if (~clk) #5; DivStart = 1'b1; #10 // one clk cycle DivStart = 1'b0; end 2'b01: if (`D_SUPPORTED)begin // double X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+3*(`D_LEN)-1:8+2*(`D_LEN)]}; Y = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+2*(`D_LEN)-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end 2'b00: if (`S_SUPPORTED)begin // single X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+3*(`S_LEN)-1:8+2*(`S_LEN)]}; Y = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+2*(`S_LEN)-1:8+1*(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end 2'b10: begin // half X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+3*(`H_LEN)-1:8+2*(`H_LEN)]}; Y = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+2*(`H_LEN)-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; if (~clk) #5; DivStart = 1'b1; #10 DivStart = 1'b0; end endcase `CMPUNIT: case (Fmt) 2'b11: begin // quad X = TestVector[12+2*(`Q_LEN)-1:12+(`Q_LEN)]; Y = TestVector[12+(`Q_LEN)-1:12]; Ans = TestVector[8]; end 2'b01: if (`D_SUPPORTED)begin // double X = {{`FLEN-`D_LEN{1'b1}}, TestVector[12+2*(`D_LEN)-1:12+(`D_LEN)]}; Y = {{`FLEN-`D_LEN{1'b1}}, TestVector[12+(`D_LEN)-1:12]}; Ans = TestVector[8]; end 2'b00: if (`S_SUPPORTED)begin // single X = {{`FLEN-`S_LEN{1'b1}}, TestVector[12+2*(`S_LEN)-1:12+(`S_LEN)]}; Y = {{`FLEN-`S_LEN{1'b1}}, TestVector[12+(`S_LEN)-1:12]}; Ans = TestVector[8]; end 2'b10: begin // half X = {{`FLEN-`H_LEN{1'b1}}, TestVector[12+2*(`H_LEN)-1:12+(`H_LEN)]}; Y = {{`FLEN-`H_LEN{1'b1}}, TestVector[12+(`H_LEN)-1:12]}; Ans = TestVector[8]; end endcase `CVTFPUNIT: case (Fmt) 2'b11: begin // quad case (OpCtrl[1:0]) 2'b11: begin // quad X = {TestVector[8+`Q_LEN+`Q_LEN-1:8+(`Q_LEN)]}; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: if (`D_SUPPORTED)begin // double X = {TestVector[8+`Q_LEN+`D_LEN-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b00: begin // single X = {TestVector[8+`Q_LEN+`S_LEN-1:8+(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // half X = {TestVector[8+`Q_LEN+`H_LEN-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end endcase end 2'b01: if (`D_SUPPORTED)begin // double case (OpCtrl[1:0]) 2'b11: begin // quad X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+`D_LEN+`Q_LEN-1:8+(`Q_LEN)]}; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: begin // double X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+`D_LEN+`D_LEN-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b00: begin // single X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+`D_LEN+`S_LEN-1:8+(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // half X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+`D_LEN+`H_LEN-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end endcase end 2'b00: if (`S_SUPPORTED)begin // single case (OpCtrl[1:0]) 2'b11: begin // quad X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+`S_LEN+`Q_LEN-1:8+(`Q_LEN)]}; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: if (`D_SUPPORTED)begin // double X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+`S_LEN+`D_LEN-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b00: begin // single X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+`S_LEN+`S_LEN-1:8+(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // half X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+`S_LEN+`H_LEN-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end endcase end 2'b10: begin // half case (OpCtrl[1:0]) 2'b11: begin // quad X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+`H_LEN+`Q_LEN-1:8+(`Q_LEN)]}; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: if (`D_SUPPORTED)begin // double X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+`H_LEN+`D_LEN-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b00: if (`S_SUPPORTED)begin // single X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+`H_LEN+`S_LEN-1:8+(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // half X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+`H_LEN+`H_LEN-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end endcase end endcase `CVTINTUNIT: case (Fmt) 2'b11: begin // quad // {is the integer a long, is the opperation to an integer} casex ({OpCtrl[2:1]}) 2'b11: begin // long -> quad X = {`FLEN{1'bx}}; SrcA = TestVector[8+`Q_LEN+`XLEN-1:8+(`Q_LEN)]; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b10: begin // int -> quad // correctly sign extend the integer depending on if it's a signed/unsigned test X = {`FLEN{1'bx}}; SrcA = {{`XLEN-32{TestVector[8+`Q_LEN+32-1]}}, TestVector[8+`Q_LEN+32-1:8+(`Q_LEN)]}; Ans = TestVector[8+(`Q_LEN-1):8]; end 2'b01: begin // quad -> long X = {TestVector[8+`XLEN+`Q_LEN-1:8+(`XLEN)]}; SrcA = {`XLEN{1'bx}}; Ans = {TestVector[8+(`XLEN-1):8]}; end 2'b00: begin // quad -> int X = {TestVector[8+32+`Q_LEN-1:8+(32)]}; SrcA = {`XLEN{1'bx}}; Ans = {{`XLEN-32{TestVector[8+32-1]}},TestVector[8+(32-1):8]}; end endcase end 2'b01: if (`D_SUPPORTED)begin // double // {Int->Fp?, is the integer a long} casex ({OpCtrl[2:1]}) 2'b11: begin // long -> double X = {`FLEN{1'bx}}; SrcA = TestVector[8+`D_LEN+`XLEN-1:8+(`D_LEN)]; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b10: begin // int -> double // correctly sign extend the integer depending on if it's a signed/unsigned test X = {`FLEN{1'bx}}; SrcA = {{`XLEN-32{TestVector[8+`D_LEN+32-1]}}, TestVector[8+`D_LEN+32-1:8+(`D_LEN)]}; Ans = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+(`D_LEN-1):8]}; end 2'b01: begin // double -> long X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+`XLEN+`D_LEN-1:8+(`XLEN)]}; SrcA = {`XLEN{1'bx}}; Ans = {TestVector[8+(`XLEN-1):8]}; end 2'b00: begin // double -> int X = {{`FLEN-`D_LEN{1'b1}}, TestVector[8+32+`D_LEN-1:8+(32)]}; SrcA = {`XLEN{1'bx}}; Ans = {{`XLEN-32{TestVector[8+32-1]}},TestVector[8+(32-1):8]}; end endcase end 2'b00: if (`S_SUPPORTED)begin // single // {is the integer a long, is the opperation to an integer} casex ({OpCtrl[2:1]}) 2'b11: begin // long -> single X = {`FLEN{1'bx}}; SrcA = TestVector[8+`S_LEN+`XLEN-1:8+(`S_LEN)]; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b10: begin // int -> single // correctly sign extend the integer depending on if it's a signed/unsigned test X = {`FLEN{1'bx}}; SrcA = {{`XLEN-32{TestVector[8+`S_LEN+32-1]}}, TestVector[8+`S_LEN+32-1:8+(`S_LEN)]}; Ans = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+(`S_LEN-1):8]}; end 2'b01: begin // single -> long X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+`XLEN+`S_LEN-1:8+(`XLEN)]}; SrcA = {`XLEN{1'bx}}; Ans = {TestVector[8+(`XLEN-1):8]}; end 2'b00: begin // single -> int X = {{`FLEN-`S_LEN{1'b1}}, TestVector[8+32+`S_LEN-1:8+(32)]}; SrcA = {`XLEN{1'bx}}; Ans = {{`XLEN-32{TestVector[8+32-1]}},TestVector[8+(32-1):8]}; end endcase end 2'b10: begin // half // {is the integer a long, is the opperation to an integer} casex ({OpCtrl[2:1]}) 2'b11: begin // long -> half X = {`FLEN{1'bx}}; SrcA = TestVector[8+`H_LEN+`XLEN-1:8+(`H_LEN)]; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end 2'b10: begin // int -> half // correctly sign extend the integer depending on if it's a signed/unsigned test X = {`FLEN{1'bx}}; SrcA = {{`XLEN-32{TestVector[8+`H_LEN+32-1]}}, TestVector[8+`H_LEN+32-1:8+(`H_LEN)]}; Ans = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+(`H_LEN-1):8]}; end 2'b01: begin // half -> long X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+`XLEN+`H_LEN-1:8+(`XLEN)]}; SrcA = {`XLEN{1'bx}}; Ans = {TestVector[8+(`XLEN-1):8]}; end 2'b00: begin // half -> int X = {{`FLEN-`H_LEN{1'b1}}, TestVector[8+32+`H_LEN-1:8+(32)]}; SrcA = {`XLEN{1'bx}}; Ans = {{`XLEN-32{TestVector[8+32-1]}}, TestVector[8+(32-1):8]}; end endcase end endcase endcase end assign XEn = ~((Unit == `CVTINTUNIT)&OpCtrl[2]); assign YEn = ~((Unit == `CVTINTUNIT)|(Unit == `CVTFPUNIT)|((Unit == `DIVUNIT)&OpCtrl[0])); assign ZEn = (Unit == `FMAUNIT); unpack unpack(.X, .Y, .Z, .Fmt(ModFmt), .Xs, .Ys, .Zs, .Xe, .Ye, .Ze, .Xm, .Ym, .Zm, .XNaN, .YNaN, .ZNaN, .XSNaN, .YSNaN, .ZSNaN, .XSubnorm, .XZero, .YZero, .ZZero, .XInf, .YInf, .ZInf, .XEn, .YEn, .ZEn, .XExpMax, .XPostBox); endmodule