///////////////////////////////////////////
//
// Written: me@KatherineParry.com, james.stine@okstate.edu
//
// Purpose: Testbench for UCB Testfloat on Wally
// 
// 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 "config.vh"
`include "tests_fp.vh"

import cvw::*;

module testbench_fp;
   // Two parameters TEST, TEST_SIZE used with testfloat.do in sim dir
   // to run specific precisions (e.g., quad or all)
   parameter string TEST="none"; // choices are cvtint, cvtfp, cmp, add, sub, mul, div, sqrt, fma; all does not check properly
   parameter string TEST_SIZE="all";

  `include "parameter-defs.vh"   

   parameter MAXVECTORS = 8388610;

   // FIXME: needs cleaning of unused variables (jes)
   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 [P.Q_LEN*4+7:0] 	TestVectors[MAXVECTORS-1: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 [P.Q_LEN-1:0] 		X, Y, Z;                    // inputs read from TestFloat
   logic [P.FLEN-1:0] 		XPostBox;                   // inputs read from TestFloat
   logic [P.XLEN-1:0] 		SrcA;                       // integer input
   logic [P.Q_LEN-1:0] 		Ans;                        // correct answer from TestFloat
   logic [P.Q_LEN-1:0] 		Res;                        // result from other units
   logic [4:0] 			AnsFlg;                     // correct flags read from testfloat
   logic [4:0] 			ResFlg, Flg;                // Result flags
   logic [P.FMTBITS-1:0] 	ModFmt;                     // format - 10 = half, 00 = single, 01 = double, 11 = quad
   logic [P.FLEN-1:0] 		FpRes, FpCmpRes;            // Results from each unit
   logic [P.XLEN-1:0] 		IntRes, CmpRes;             // Results from each unit
   logic [P.Q_LEN-1:0]     FpResExtended;              // FpRes extended to same length as Ans/Res
   logic [4:0] 			FmaFlg, CvtFlg, DivFlg;     // Outputed flags
   logic [4:0] 			CmpFlg;                     // Outputed flags
   logic                        AnsNaN, ResNaN, NaNGood;
   logic                        Xs, Ys, Zs;                 // sign of the inputs
   logic [P.NE-1:0] 		Xe, Ye, Ze;                 // exponent of the inputs
   logic [P.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 [P.CVTLEN-1:0] 	CvtLzcInE;                  // input to the Leading Zero Counter (priority encoder)
   logic                        IntZero;
   logic                        CvtResSgnE;
   logic [P.NE:0] 		CvtCalcExpE;                // the calculated exponent
   logic [P.LOGCVTLEN-1:0] 	CvtShiftAmtE;               // how much to shift by
   logic [P.DIVb:0] 		Quot;
   logic                        CvtResSubnormUfE;
   logic                        DivStart;
   logic 			FDivBusyE;
   logic 			OldFDivBusyE;
   logic                        reset = 1'b0;
   logic [$clog2(P.NF+2)-1:0] 	XZeroCnt, YZeroCnt;

   // in-between FMA signals
   logic                        Mult;
   logic                        Ss;
   logic [P.NE+1:0] 		Pe;
   logic [P.NE+1:0] 		Se;
   logic 			ASticky;
   logic 			KillProd; 
   logic [$clog2(P.FMALEN+1)-1:0] SCnt;
   logic [P.FMALEN-1:0] 		Sm;       
   logic 			InvA;
   logic 			NegSum;
   logic 			As;
   logic 			Ps;
   logic                        DivSticky;
   logic                        DivDone;
   logic                        DivNegSticky;
   logic [P.NE+1:0] 		DivCalcExp;
   logic                        divsqrtop;

   // Missing logic vectors fdivsqrt
   logic [2:0] 			Funct3E;
   logic [2:0] 			Funct3M;
   logic 			FlushE;
   logic 			IFDivStartE;
   logic 			FDivDoneE;
   logic [P.NE+1:0] 		UeM;
   logic [P.DIVb:0] 		UmM;
   logic [P.XLEN-1:0] 		FIntDivResultM;
   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 [P.NE-2:0]             BiasE;                              // Bias of exponent
   logic [P.LOGFLEN-1:0]        NfE;                                // Number of fractional bits

   // FSM for testing each item per clock
   typedef enum logic [2:0] {S0, Start, S2, Done} statetype;
   statetype state, nextstate;   
   
   ///////////////////////////////////////////////////////////////////////////////////////////////

   //     ||||||||| |||||||| ||||||| |||||||||   ||||||| |||||||| |||
   //        |||    |||      |||        |||      |||     |||      |||
   //        |||    |||||||| |||||||    |||      ||||||| |||||||| |||
   //        |||    |||          |||    |||          ||| |||      |||
   //        |||    |||||||| |||||||    |||      ||||||| |||||||| |||||||||

   ///////////////////////////////////////////////////////////////////////////////////////////////

   // 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 < doesn't report errors properly >
   
   initial begin
      // Information displayed for user on what is simulating
      // $display("\nThe start of simulation...");      
      // $display("This simulation for TEST is %s", TEST);
      // $display("This simulation for TEST is of the operand size of %s", TEST_SIZE);      

   if (P.Q_SUPPORTED & (TEST_SIZE == "QP" | TEST_SIZE == "all")) 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 (P.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 (P.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 (P.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 (P.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 (P.D_SUPPORTED & (TEST_SIZE == "DP" | TEST_SIZE == "all")) 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 (P.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 (P.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 (P.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 (P.F_SUPPORTED & (TEST_SIZE == "SP" | TEST_SIZE == "all")) 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 (P.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 (P.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 (P.ZFH_SUPPORTED & (TEST_SIZE == "HP" | TEST_SIZE == "all")) 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 (P.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
      //string testname = {`PATH, Tests[TestNum]}; 
      static string pp = `PATH;
      string testname;
      string tt0;
      tt0 = $sformatf("%s", Tests[TestNum]);
      testname = {pp, tt0};
      //$display("Here you are %s", testname);     
      $display("\n\nRunning %s vectors ", Tests[TestNum]);
      $readmemh(testname, TestVectors);
      // set the test index to 0
      TestNum = 0;
   end

   // set the signals for all tests
   always_ff @(posedge clk) begin
      UnitVal = Unit[TestNum];
      FmtVal = Fmt[TestNum];
      OpCtrlVal = OpCtrl[OpCtrlNum];
      WriteIntVal = WriteInt[OpCtrlNum];
      FrmVal = Frm[FrmNum];
   end

   // modify the format signal if only 2 precisions supported
   //    - 1 for the larger precision
   //    - 0 for the smaller precision
   always_comb begin
      if (P.FMTBITS == 1) ModFmt = {1'b0, FmtVal == P.FMT};
      else ModFmt = FmtVal;
   end

   // extract the inputs (X, Y, Z, SrcA) and the output (Ans, AnsFlg) from the current test vector
   readvectors #(P) 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, 
                                 .XNaN, .YNaN, .ZNaN,
                                 .XSNaN, .YSNaN, .ZSNaN, 
                                 .XSubnorm, .ZSubnorm, 
                                 .XZero, .YZero, .ZZero,
                                 .XInf, .YInf, .ZInf, .XExpMax,
                                 .X, .Y, .Z, .XPostBox, .NfE, .BiasE);

   ///////////////////////////////////////////////////////////////////////////////////////////////

   //     |||||||   |||   ||| ||||||||| 
   //     |||   ||| |||   |||    |||    
   //     |||   ||| |||   |||    |||    
   //     |||   ||| |||   |||    |||         
   //     |||||||   |||||||||    |||    

   ///////////////////////////////////////////////////////////////////////////////////////////////

   // instantiate devices under test
   if (TEST === "fma"| TEST === "mul" | TEST === "add" | TEST === "sub" | TEST === "all") begin : fma
      fma #(P) 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 #(P) postprocess(.Xs(Xs), .Ys(Ys), .PostProcSel(UnitVal[1:0]),
				.OpCtrl(OpCtrlVal), .DivUm(Quot), .DivUe(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), .Zfa(1'b0));
   
   if (TEST === "cvtfp" | TEST === "cvtint" | TEST === "all") begin : fcvt
      fcvt #(P) 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 #(P) fcmp (.Fmt(ModFmt), .OpCtrl(OpCtrlVal), .Zfa(1'b0), .Xs, .Ys, .Xe, .Ye, 
                   .Xm, .Ym, .XZero, .YZero, .CmpIntRes(CmpRes),
                   .XNaN, .YNaN, .XSNaN, .YSNaN, .X(X[P.FLEN-1:0]), .Y(Y[P.FLEN-1:0]), .CmpNV(CmpFlg[4]), .CmpFpRes(FpCmpRes));
   end
   
   if (TEST === "div" | TEST === "sqrt" | TEST === "all") begin: fdivsqrt
      fdivsqrt #(P) 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), .NfE, .BiasE,
			     .FDivStartE(DivStart), .IDivStartE(1'b0), .W64E(1'b0),
			     .StallM(1'b0), .DivStickyM(DivSticky), .FDivBusyE, .UeM(DivCalcExp),
			     .UmM(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

   ///////////////////////////////////////////////////////////////////////////////////////////////

   //          |||||      |||  ||||||||||  |||||      |||
   //          |||||||    |||  |||    |||  |||||||    |||
   //          |||| |||   |||  ||||||||||  |||| |||   |||
   //          ||||  |||  |||  |||    |||  ||||  |||  |||
   //          ||||   ||| |||  |||    |||  ||||   ||| |||
   //          ||||    ||||||  |||    |||  ||||    ||||||

   ///////////////////////////////////////////////////////////////////////////////////////////////

   // 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])
           2'b11: begin // quad             
              AnsNaN = &Ans[P.Q_LEN-2:P.NF]&(|Ans[P.Q_NF-1:0]);
              ResNaN = &Res[P.Q_LEN-2:P.NF]&(|Res[P.Q_NF-1:0]);
           end
           2'b01: begin // double                 
              AnsNaN = &Ans[P.D_LEN-2:P.D_NF]&(|Ans[P.D_NF-1:0]);
              ResNaN = &Res[P.D_LEN-2:P.D_NF]&(|Res[P.D_NF-1:0]);
           end
           2'b00: begin // single
              AnsNaN = &Ans[P.S_LEN-2:P.S_NF]&(|Ans[P.S_NF-1:0]);
              ResNaN = &Res[P.S_LEN-2:P.S_NF]&(|Res[P.S_NF-1:0]);
           end
           2'b10: begin // half
              AnsNaN = &Ans[P.H_LEN-2:P.H_NF]&(|Ans[P.H_NF-1:0]);
              ResNaN = &Res[P.H_LEN-2:P.H_NF]&(|Res[P.H_NF-1:0]);
           end
	 endcase
      end
      else begin
	 case (FmtVal)
           2'b11: begin // quad             
              AnsNaN = &Ans[P.Q_LEN-2:P.Q_NF]&(|Ans[P.Q_NF-1:0]);
              ResNaN = &Res[P.Q_LEN-2:P.Q_NF]&(|Res[P.Q_NF-1:0]);
           end
           2'b01: begin // double                 
              AnsNaN = &Ans[P.D_LEN-2:P.D_NF]&(|Ans[P.D_NF-1:0]);
              ResNaN = &Res[P.D_LEN-2:P.D_NF]&(|Res[P.D_NF-1:0]);
           end
           2'b00: begin // single
              AnsNaN = &Ans[P.S_LEN-2:P.S_NF]&(|Ans[P.S_NF-1:0]);
              ResNaN = &Res[P.S_LEN-2:P.S_NF]&(|Res[P.S_NF-1:0]);
           end
           2'b10: begin // half
              AnsNaN = &Ans[P.H_LEN-2:P.H_NF]&(|Ans[P.H_NF-1:0]);
              ResNaN = &Res[P.H_LEN-2:P.H_NF]&(|Res[P.H_NF-1:0]);
           end
	 endcase
      end
   end 
   
   always_comb begin
      FpResExtended = {{(P.Q_LEN-P.FLEN){1'b1}}, FpRes};
      // select the result to check
      case (UnitVal)
	`FMAUNIT: Res = FpResExtended;
	`DIVUNIT: Res = FpResExtended;
	`CMPUNIT: Res = {{(Q_LEN-XLEN){1'b0}}, CmpRes};
	`CVTINTUNIT: if (WriteIntVal) Res = {{(Q_LEN-XLEN){1'b0}}, IntRes}; else Res = FpResExtended;
	`CVTFPUNIT: Res = FpResExtended;
      endcase

      // select the flag to check
      case (UnitVal)
	`FMAUNIT: ResFlg = Flg;
	`DIVUNIT: ResFlg = Flg;
	`CMPUNIT: ResFlg = CmpFlg;
	`CVTINTUNIT: ResFlg = Flg;
	`CVTFPUNIT: ResFlg = Flg;
      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)&(UnitVal == `DIVUNIT))
	     nextstate = S2;
	   else
	     nextstate = Done;
	end
	Done: begin
	   DivStart = 1'b0;
	   nextstate = S0;
	end	
   default: 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;

   // 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

      // 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
   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)
            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}}})) |
                              (XNaN&(Res[P.Q_LEN-2:0] === {X[P.Q_LEN-2:P.Q_NF],1'b1,X[P.Q_NF-2:0]})) | 
                              (YNaN&(Res[P.Q_LEN-2:0] === {Y[P.Q_LEN-2:P.Q_NF],1'b1,Y[P.Q_NF-2:0]})) |
                              (ZNaN&(Res[P.Q_LEN-2:0] === {Z[P.Q_LEN-2:P.Q_NF],1'b1,Z[P.Q_NF-2:0]})));
            2'b01: NaNGood =  (((P.IEEE754==0)&AnsNaN&(Res[P.D_LEN-1:0] === {1'b0, {P.D_NE+1{1'b1}}, {P.D_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.D_LEN-2:0] === {{P.D_NE+1{1'b1}}, {P.D_NF-1{1'b0}}})) |
                              (XNaN&(Res[P.D_LEN-2:0] === {X[P.D_LEN-2:P.D_NF],1'b1,X[P.D_NF-2:0]})) | 
                              (YNaN&(Res[P.D_LEN-2:0] === {Y[P.D_LEN-2:P.D_NF],1'b1,Y[P.D_NF-2:0]})) |
                              (ZNaN&(Res[P.D_LEN-2:0] === {Z[P.D_LEN-2:P.D_NF],1'b1,Z[P.D_NF-2:0]})));
            2'b00: NaNGood =  (((P.IEEE754==0)&AnsNaN&(Res[P.S_LEN-1:0] === {1'b0, {P.S_NE+1{1'b1}}, {P.S_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.S_LEN-2:0] === {{P.S_NE+1{1'b1}}, {P.S_NF-1{1'b0}}})) |
                              (XNaN&(Res[P.S_LEN-2:0] === {X[P.S_LEN-2:P.S_NF],1'b1,X[P.S_NF-2:0]})) | 
                              (YNaN&(Res[P.S_LEN-2:0] === {Y[P.S_LEN-2:P.S_NF],1'b1,Y[P.S_NF-2:0]})) |
                              (ZNaN&(Res[P.S_LEN-2:0] === {Z[P.S_LEN-2:P.S_NF],1'b1,Z[P.S_NF-2:0]})));
            2'b10: NaNGood =  (((P.IEEE754==0)&AnsNaN&(Res[P.H_LEN-1:0] === {1'b0, {P.H_NE+1{1'b1}}, {P.H_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.H_LEN-2:0] === {{P.H_NE+1{1'b1}}, {P.H_NF-1{1'b0}}})) |
                              (XNaN&(Res[P.H_LEN-2:0] === {X[P.H_LEN-2:P.H_NF],1'b1,X[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]})));
         endcase
      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}}})) |
                              (AnsNaN&(Res[P.Q_LEN-2:0] === Ans[P.Q_LEN-2:0])) | 
                              (XNaN&(Res[P.Q_LEN-2:0] === {X[P.Q_LEN-2:P.Q_NF],1'b1,X[P.Q_NF-2:0]})) | 
                              (YNaN&(Res[P.Q_LEN-2:0] === {Y[P.Q_LEN-2:P.Q_NF],1'b1,Y[P.Q_NF-2:0]})));
            2'b01: NaNGood = (((P.IEEE754==0)&AnsNaN&(Res[P.D_LEN-1:0] === {1'b0, {P.D_NE+1{1'b1}}, {P.D_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.D_LEN-2:0] === {{P.D_NE+1{1'b1}}, {P.D_NF-1{1'b0}}})) |
                              (AnsNaN&(Res[P.D_LEN-2:0] === Ans[P.D_LEN-2:0])) | 
                              (XNaN&(Res[P.D_LEN-2:0] === {X[P.D_LEN-2:P.D_NF],1'b1,X[P.D_NF-2:0]})) | 
                              (YNaN&(Res[P.D_LEN-2:0] === {Y[P.D_LEN-2:P.D_NF],1'b1,Y[P.D_NF-2:0]})));
            2'b00: NaNGood = (((P.IEEE754==0)&AnsNaN&(Res[P.S_LEN-1:0] === {1'b0, {P.S_NE+1{1'b1}}, {P.S_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.S_LEN-2:0] === {{P.S_NE+1{1'b1}}, {P.S_NF-1{1'b0}}})) |
                              (AnsNaN&(Res[P.S_LEN-2:0] === Ans[P.S_LEN-2:0])) | 
                              (XNaN&(Res[P.S_LEN-2:0] === {X[P.S_LEN-2:P.S_NF],1'b1,X[P.S_NF-2:0]})) | 
                              (YNaN&(Res[P.S_LEN-2:0] === {Y[P.S_LEN-2:P.S_NF],1'b1,Y[P.S_NF-2:0]})));
            2'b10: NaNGood = (((P.IEEE754==0)&AnsNaN&(Res[P.H_LEN-1:0] === {1'b0, {P.H_NE+1{1'b1}}, {P.H_NF-1{1'b0}}})) |
                              (AnsFlg[4]&(Res[P.H_LEN-2:0] === {{P.H_NE+1{1'b1}}, {P.H_NF-1{1'b0}}})) |
                              (AnsNaN&(Res[P.H_LEN-2:0] === Ans[P.H_LEN-2:0])) | 
                              (XNaN&(Res[P.H_LEN-2:0] === {X[P.H_LEN-2:P.H_NF],1'b1,X[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]})));
         endcase
      else NaNGood = 1'b0; // integers can't be NaNs

         
      ///////////////////////////////////////////////////////////////////////////////////////////////

      //     ||||||| |||    ||| ||||||| ||||||| |||   |||
      //     |||     |||    ||| |||     |||     |||  |||
      //     |||     |||||||||| ||||||| |||     ||||||
      //     |||     |||    ||| |||     |||     |||  |||
      //     ||||||| |||    ||| ||||||| ||||||| |||    |||

      ///////////////////////////////////////////////////////////////////////////////////////////////

      // check if result is correct
      assign ResMatch = ((Res[P.FLEN-1:0] === Ans[P.FLEN-1:0]) | 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;
      assign CheckNow = ((DivDone | ~divsqrtop) | 
			 (TEST == "add" | TEST == "fma" | TEST == "sub") |
			 ((TEST == "all") & (DivDone | ~divsqrtop)));
            
      if (~(ResMatch & FlagMatch) & CheckNow & (Ans[0] !== 1'bx)) begin
         errors += 1;
         $display("\nError in %s", Tests[TestNum]);
         $display("TestNum %d VectorNum %d OpCtrl %d", TestNum, VectorNum, OpCtrl[TestNum]);	 
         $display("inputs: %h %h %h\nSrcA: %h\n Res: %h %h\n Expected: %h %h", 
            X[P.FLEN-1:0], Y[P.FLEN-1:0], Z[P.FLEN-1:0], SrcA, Res[P.FLEN-1:0], ResFlg, Ans[P.FLEN-1:0], AnsFlg);
         $stop;
      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<MAXVECTORS; i++) TestVectors[i] = {P.Q_LEN*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 begin
	    FrmNum = 0;
            // Add some time as a buffer between tests at the end of each test
	    // (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);
                  $stop;
         end 
         $display("Running %s vectors", Tests[TestNum]);
      end
   end
endmodule


module readvectors import cvw::*; #(parameter cvw_t P) (
		    input logic 		clk,
		    input logic [P.Q_LEN*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.Q_LEN-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.Q_LEN-1:0] 	X, Y, Z,
          output logic [P.FLEN-1:0]  XPostBox,
	       output logic [P.NE-2:0] BiasE,                              // Bias of exponent
          output logic [P.LOGFLEN-1:0] NfE                           // Number of fractional bits
		    );

   localparam Q_LEN = 32'd128;
   
   logic 					XEn;
   logic 					YEn;
   logic 					ZEn;
   logic 					FPUActive;   

   // apply test vectors on rising edge of clk
   // Format of vectors Inputs(1/2/3)_AnsFlg
   always @(VectorNum) begin
      AnsFlg = TestVector[4:0];
      //$display("Entering readvectors with VectorNum=%d, TestVector=%x, Unit=%d, Fmt=%d, OpCtrl=%d", VectorNum, TestVector, Unit, Fmt, OpCtrl);
      case (Unit)
	`FMAUNIT:
          case (Fmt)
            2'b11: if (P.Q_SUPPORTED) begin // quad
               if (OpCtrl === `FMA_OPCTRL) begin
		  X = TestVector[8+4*(P.Q_LEN)-1:8+3*(P.Q_LEN)];
		  Y = TestVector[8+3*(P.Q_LEN)-1:8+2*(P.Q_LEN)];
		  Z = TestVector[8+2*(P.Q_LEN)-1:8+P.Q_LEN];
               end
               else begin
		  X = TestVector[8+3*(P.Q_LEN)-1:8+2*(P.Q_LEN)];
		  if (OpCtrl === `MUL_OPCTRL) Y = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)]; else Y = {2'b0, {P.Q_NE-1{1'b1}}, (P.Q_NF)'(0)};
		  if (OpCtrl === `MUL_OPCTRL) Z = 0; else Z = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)];
               end
               Ans = TestVector[8+(P.Q_LEN-1):8];
            end
            2'b01: if (P.D_SUPPORTED) begin // double
               if (OpCtrl === `FMA_OPCTRL) begin
		  X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+4*(P.D_LEN)-1:8+3*(P.D_LEN)]};
		  Y = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+3*(P.D_LEN)-1:8+2*(P.D_LEN)]};
		  Z = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+P.D_LEN]};
               $display("Read %x %x %x", X, Y, Z);
               end
               else begin
		  X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+3*(P.D_LEN)-1:8+2*(P.D_LEN)]};
		  if (OpCtrl === `MUL_OPCTRL) Y = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]}; 
		  else Y = {{P.Q_LEN-P.D_LEN{1'b1}}, 2'b0, {P.D_NE-1{1'b1}}, (P.D_NF)'(0)};
		  if (OpCtrl === `MUL_OPCTRL) Z = {{P.Q_LEN-P.D_LEN{1'b1}}, {P.D_LEN{1'b0}}}; 
		  else Z = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]};
               end
               Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
            end
            2'b00: if (P.F_SUPPORTED) begin // single
               if (OpCtrl === `FMA_OPCTRL) begin
		  X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+4*(P.S_LEN)-1:8+3*(P.S_LEN)]};
		  Y = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+3*(P.S_LEN)-1:8+2*(P.S_LEN)]};
		  Z = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+P.S_LEN]};
               end
               else begin
		  X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+3*(P.S_LEN)-1:8+2*(P.S_LEN)]};
		  if (OpCtrl === `MUL_OPCTRL) Y = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+(P.S_LEN)]}; 
		  else Y = {{P.Q_LEN-P.S_LEN{1'b1}}, 2'b0, {P.S_NE-1{1'b1}}, (P.S_NF)'(0)};
		  if (OpCtrl === `MUL_OPCTRL) Z = {{P.Q_LEN-P.S_LEN{1'b1}}, {P.S_LEN{1'b0}}}; 
		  else Z = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+(P.S_LEN)]};
               end
               Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
            end
            2'b10: begin // half
               if (OpCtrl === `FMA_OPCTRL) begin
		  X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+4*(P.H_LEN)-1:8+3*(P.H_LEN)]};
		  Y = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+3*(P.H_LEN)-1:8+2*(P.H_LEN)]};
		  Z = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+P.H_LEN]};
               end
               else begin
		  X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+3*(P.H_LEN)-1:8+2*(P.H_LEN)]};
		  if (OpCtrl === `MUL_OPCTRL) Y = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]}; 
		  else Y = {{P.Q_LEN-P.H_LEN{1'b1}}, 2'b0, {P.H_NE-1{1'b1}}, (P.H_NF)'(0)};
		  if (OpCtrl === `MUL_OPCTRL) Z = {{P.Q_LEN-P.H_LEN{1'b1}}, {P.H_LEN{1'b0}}}; 
		  else Z = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]};
               end
               Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
            end
          endcase
	`DIVUNIT:
          if (OpCtrl[0])
            case (Fmt)
              2'b11: begin // quad
		 X = TestVector[8+2*(P.Q_LEN)-1:8+(P.Q_LEN)];
		 Ans = TestVector[8+(P.Q_LEN-1):8];
              end
              2'b01: if (P.D_SUPPORTED) begin // double
		 X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]};
		 Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
              end
              2'b00: if (P.F_SUPPORTED) begin // single
		 X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]};
		 Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
              end
              2'b10: begin // half
		 X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]};
		 Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
              end
            endcase
          else
            case (Fmt)
              2'b11: begin // quad
		 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];
              end
              2'b01: if (P.D_SUPPORTED) begin // double
		 X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+3*(P.D_LEN)-1:8+2*(P.D_LEN)]};
		 Y = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+2*(P.D_LEN)-1:8+(P.D_LEN)]};
		 Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
              end
              2'b00: if (P.F_SUPPORTED) begin // single
		 X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+3*(P.S_LEN)-1:8+2*(P.S_LEN)]};
		 Y = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+2*(P.S_LEN)-1:8+1*(P.S_LEN)]};
		 Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
              end
              2'b10: begin // half
		 X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+3*(P.H_LEN)-1:8+2*(P.H_LEN)]};
		 Y = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+2*(P.H_LEN)-1:8+(P.H_LEN)]};
		 Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
              end
            endcase
	`CMPUNIT:
          case (Fmt)        
            2'b11: begin // quad
               X = TestVector[12+2*(P.Q_LEN)-1:12+(P.Q_LEN)];
               Y = TestVector[12+(P.Q_LEN)-1:12];
               Ans = {{P.Q_LEN-1{1'b0}}, TestVector[8]};
            end
            2'b01: if (P.D_SUPPORTED) begin // double
               X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[12+2*(P.D_LEN)-1:12+(P.D_LEN)]};
               Y = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[12+(P.D_LEN)-1:12]};
               Ans = {{P.Q_LEN-1{1'b0}}, TestVector[8]};
            end
            2'b00: if (P.F_SUPPORTED) begin // single
               X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[12+2*(P.S_LEN)-1:12+(P.S_LEN)]};
               Y = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[12+(P.S_LEN)-1:12]};
               Ans = {{P.Q_LEN-1{1'b0}}, TestVector[8]};
            end
            2'b10: begin // half
               X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[12+2*(P.H_LEN)-1:12+(P.H_LEN)]};
               Y = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[12+(P.H_LEN)-1:12]};
               Ans = {{P.Q_LEN-1{1'b0}}, TestVector[8]};
            end
          endcase
	`CVTFPUNIT:
          case (Fmt)
            2'b11: begin // quad
               case (OpCtrl[1:0])
		 2'b11: begin // quad
		    X = {TestVector[8+P.Q_LEN+P.Q_LEN-1:8+(P.Q_LEN)]};
		    Ans = TestVector[8+(P.Q_LEN-1):8];
		 end
		 2'b01:	if (P.D_SUPPORTED) begin // double
		    X = {TestVector[8+P.Q_LEN+P.D_LEN-1:8+(P.D_LEN)]};
		    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
		 end
		 2'b00:	begin // single
		    X = {TestVector[8+P.Q_LEN+P.S_LEN-1:8+(P.S_LEN)]};
		    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
		 end
		 2'b10:	begin // half
		    X = {TestVector[8+P.Q_LEN+P.H_LEN-1:8+(P.H_LEN)]};
		    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
		 end
               endcase
            end
            2'b01: if (P.D_SUPPORTED) begin // double
               case (OpCtrl[1:0])
		 2'b11: begin // quad
		    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+P.D_LEN+P.Q_LEN-1:8+(P.Q_LEN)]};
		    Ans = TestVector[8+(P.Q_LEN-1):8];
		 end
		 2'b01:	begin // double
		    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+P.D_LEN+P.D_LEN-1:8+(P.D_LEN)]};
		    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
		 end
		 2'b00:	begin // single
		    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+P.D_LEN+P.S_LEN-1:8+(P.S_LEN)]};
		    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
		 end
		 2'b10:	begin // half
		    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+P.D_LEN+P.H_LEN-1:8+(P.H_LEN)]};
		    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
		 end
               endcase
            end
            2'b00: if (P.F_SUPPORTED) begin // single
               case (OpCtrl[1:0])
		 2'b11: begin // quad
		    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+P.S_LEN+P.Q_LEN-1:8+(P.Q_LEN)]};
		    Ans = TestVector[8+(P.Q_LEN-1):8];
		 end
		 2'b01:	if (P.D_SUPPORTED) begin // double
		    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+P.S_LEN+P.D_LEN-1:8+(P.D_LEN)]};
		    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
		 end
		 2'b00:	begin // single
		    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+P.S_LEN+P.S_LEN-1:8+(P.S_LEN)]};
		    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
		 end
		 2'b10:	begin // half
		    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+P.S_LEN+P.H_LEN-1:8+(P.H_LEN)]};
		    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
		 end
               endcase
            end
            2'b10: begin // half
               case (OpCtrl[1:0])
		 2'b11: begin // quad
		    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+P.H_LEN+P.Q_LEN-1:8+(P.Q_LEN)]};
		    Ans = TestVector[8+(P.Q_LEN-1):8];
		 end
		 2'b01:	if (P.D_SUPPORTED) begin // double
		    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+P.H_LEN+P.D_LEN-1:8+(P.D_LEN)]};
		    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
		 end
		 2'b00:	if (P.F_SUPPORTED) begin // single
		    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+P.H_LEN+P.S_LEN-1:8+(P.S_LEN)]};
		    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
		 end
		 2'b10:	begin // half
		    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+P.H_LEN+P.H_LEN-1:8+(P.H_LEN)]};
		    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.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}
               casez ({OpCtrl[2:1]})
		 2'b11: begin // long -> quad
                    X = {P.Q_LEN{1'bx}};
                    SrcA = TestVector[8+P.Q_LEN+P.XLEN-1:8+(P.Q_LEN)];
                    Ans = TestVector[8+(P.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 = {P.Q_LEN{1'bx}};
                    SrcA = {{P.XLEN-32{TestVector[8+P.Q_LEN+32-1]}}, TestVector[8+P.Q_LEN+32-1:8+(P.Q_LEN)]};
                    Ans = TestVector[8+(P.Q_LEN-1):8];
		 end
		 2'b01:	begin // quad -> long
                    X = {TestVector[8+P.XLEN+P.Q_LEN-1:8+(P.XLEN)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-64){1'b0}}, TestVector[8+(64-1):8]};
		 end
		 2'b00:	begin // quad -> int
                    X = {TestVector[8+32+P.Q_LEN-1:8+(32)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-32){TestVector[8+32-1]}},TestVector[8+(32-1):8]};
		 end
               endcase
            end
            2'b01: if (P.D_SUPPORTED) begin // double
               // {Int->Fp?, is the integer a long}
               casez ({OpCtrl[2:1]})
		 2'b11: begin // long -> double
                    X = {P.Q_LEN{1'bx}};
                    SrcA = TestVector[8+P.D_LEN+P.XLEN-1:8+(P.D_LEN)];
                    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.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 = {P.Q_LEN{1'bx}};
                    SrcA = {{P.XLEN-32{TestVector[8+P.D_LEN+32-1]}}, TestVector[8+P.D_LEN+32-1:8+(P.D_LEN)]};
                    Ans = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+(P.D_LEN-1):8]};
		 end
		 2'b01:	begin // double -> long
                    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+P.XLEN+P.D_LEN-1:8+(P.XLEN)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-64){1'b0}}, TestVector[8+(64-1):8]};
		 end
		 2'b00:	begin // double -> int
                    X = {{P.Q_LEN-P.D_LEN{1'b1}}, TestVector[8+32+P.D_LEN-1:8+(32)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{P.Q_LEN-32{TestVector[8+32-1]}},TestVector[8+(32-1):8]};
		 end
               endcase
            end
            2'b00: if (P.F_SUPPORTED) begin // single
               // {is the integer a long, is the opperation to an integer}
               casez ({OpCtrl[2:1]})
		 2'b11: begin // long -> single
                    X = {P.Q_LEN{1'bx}};
                    SrcA = TestVector[8+P.S_LEN+P.XLEN-1:8+(P.S_LEN)];
                    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.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 = {P.Q_LEN{1'bx}};
                    SrcA = {{P.XLEN-32{TestVector[8+P.S_LEN+32-1]}}, TestVector[8+P.S_LEN+32-1:8+(P.S_LEN)]};
                    Ans = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+(P.S_LEN-1):8]};
		 end
		 2'b01:	begin // single -> long
                    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+P.XLEN+P.S_LEN-1:8+(P.XLEN)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-64){1'b0}}, TestVector[8+(64-1):8]};
		 end
		 2'b00:	begin // single -> int
                    X = {{P.Q_LEN-P.S_LEN{1'b1}}, TestVector[8+32+P.S_LEN-1:8+(32)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-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}
               casez ({OpCtrl[2:1]})
		 2'b11: begin // long -> half
                    X = {P.Q_LEN{1'bx}};
                    SrcA = TestVector[8+P.H_LEN+P.XLEN-1:8+(P.H_LEN)];
                    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.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 = {P.Q_LEN{1'bx}};
                    SrcA = {{P.XLEN-32{TestVector[8+P.H_LEN+32-1]}}, TestVector[8+P.H_LEN+32-1:8+(P.H_LEN)]};
                    Ans = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+(P.H_LEN-1):8]};
		 end
		 2'b01:	begin // half -> long
                    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+P.XLEN+P.H_LEN-1:8+(P.XLEN)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-64){1'b0}}, TestVector[8+(64-1):8]};
		 end
		 2'b00:	begin // half -> int
                    X = {{P.Q_LEN-P.H_LEN{1'b1}}, TestVector[8+32+P.H_LEN-1:8+(32)]};
                    SrcA = {P.XLEN{1'bx}};
                    Ans = {{(P.Q_LEN-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);
   assign FPUActive = 1'b1;
   
   unpack #(P) unpack(.X(X[P.FLEN-1:0]), .Y(Y[P.FLEN-1:0]), .Z(Z[P.FLEN-1:0]), .Fmt(ModFmt), .FPUActive, .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, .Bias(BiasE), .Nf(NfE));

endmodule