///////////////////////////////////////////
// wallyTracer.sv
//
// A component of the Wally configurable RISC-V project.
// Implements a RISC-V Verification Interface (RVVI)
// to support functional coverage and lockstep simulation.
// 
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////


`define STD_LOG 0
`define PRINT_PC_INSTR 0
`define PRINT_MOST 0
`define PRINT_ALL 0
`define PRINT_CSRS 0

module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi);

  localparam NUM_REGS = P.E_SUPPORTED ? 16 : 32;
  localparam NUM_CSRS = 4096;
  
  // wally specific signals
  logic                  reset;
  logic                  clk;
  logic                  InstrValidD, InstrValidE;
  logic                  StallF, StallD;
  logic                  STATUS_SXL, STATUS_UXL;
  logic [P.XLEN-1:0]     PCNextF, PCF, PCD, PCE, PCM, PCW;
  logic [31:0]           InstrRawD, InstrRawE, InstrRawM, InstrRawW;
  logic                  InstrValidM, InstrValidW;
  logic                  StallE, StallM, StallW;
  logic                  GatedStallW;
  logic                  SelHPTW;
  logic                  FlushD, FlushE, FlushM, FlushW;
  logic                  TrapM, TrapW;
  logic                  HaltM, HaltW;
  logic [1:0]            PrivilegeModeW;
  logic [P.XLEN-1:0]     rf[NUM_REGS];
  logic [NUM_REGS-1:0]   rf_wb;
  logic [4:0]            rf_a3;
  logic                  rf_we3;
  logic [P.FLEN-1:0]     frf[32];
  logic [31:0]           frf_wb;
  logic [4:0]            frf_a4;
  logic                  frf_we4;
  logic [P.XLEN-1:0]     CSRArray [4095:0];
  logic [P.XLEN-1:0]     CSRArrayOld [4095:0];
  logic [NUM_CSRS-1:0]  CSR_W;
  logic                  CSRWriteM, CSRWriteW;
  logic [11:0]           CSRAdrM, CSRAdrW;
  logic                  wfiM;
  logic                  InterruptM, InterruptW;

  //For VM Verification
  logic [(P.XLEN-1):0]     IVAdrF,IVAdrD,IVAdrE,IVAdrM,IVAdrW,DVAdrM,DVAdrW;
  logic [(P.XLEN-1):0]     IPTEF,IPTED,IPTEE,IPTEM,IPTEW,DPTEM,DPTEW;
  logic [(P.PA_BITS-1):0]  IPAF,IPAD,IPAE,IPAM,IPAW,DPAM,DPAW;
  logic [(P.PPN_BITS-1):0] IPPNF,IPPND,IPPNE,IPPNM,IPPNW,DPPNM,DPPNW;
  logic [1:0]              IPageTypeF, IPageTypeD, IPageTypeE, IPageTypeM, IPageTypeW, DPageTypeM, DPageTypeW;
  logic ReadAccessM,WriteAccessM,ReadAccessW,WriteAccessW;
  logic ExecuteAccessF,ExecuteAccessD,ExecuteAccessE,ExecuteAccessM,ExecuteAccessW;

  assign clk = testbench.dut.clk;
  //  assign InstrValidF = testbench.dut.core.ieu.InstrValidF;  // not needed yet
  assign InstrValidD    = testbench.dut.core.ieu.c.InstrValidD;
  assign InstrValidE    = testbench.dut.core.ieu.c.InstrValidE;
  assign InstrValidM    = testbench.dut.core.ieu.InstrValidM;
  assign InstrRawD      = testbench.dut.core.ifu.InstrRawD;
  assign PCNextF        = testbench.dut.core.ifu.PCNextF;
  assign PCF            = testbench.dut.core.ifu.PCF;
  assign PCD            = testbench.dut.core.ifu.PCD;
  assign PCE            = testbench.dut.core.ifu.PCE;
  assign PCM            = testbench.dut.core.ifu.PCM;
  assign reset          = testbench.reset;
  assign StallF         = testbench.dut.core.StallF;
  assign StallD         = testbench.dut.core.StallD;
  assign StallE         = testbench.dut.core.StallE;
  assign StallM         = testbench.dut.core.StallM;
  assign StallW         = testbench.dut.core.StallW;
  assign GatedStallW    = testbench.dut.core.lsu.GatedStallW;
  assign SelHPTW        = testbench.dut.core.lsu.hptw.hptw.SelHPTW;
  assign FlushD         = testbench.dut.core.FlushD;
  assign FlushE         = testbench.dut.core.FlushE;
  assign FlushM         = testbench.dut.core.FlushM;
  assign FlushW         = testbench.dut.core.FlushW;
  assign TrapM          = testbench.dut.core.TrapM;
  assign HaltM          = testbench.DCacheFlushStart;
  if (P.ZICSR_SUPPORTED) begin
    assign PrivilegeModeW = testbench.dut.core.priv.priv.privmode.PrivilegeModeW;
    assign STATUS_SXL     = testbench.dut.core.priv.priv.csr.csrsr.STATUS_SXL;
    assign STATUS_UXL     = testbench.dut.core.priv.priv.csr.csrsr.STATUS_UXL;
    assign wfiM           = testbench.dut.core.priv.priv.wfiM;
    assign InterruptM     = testbench.dut.core.priv.priv.InterruptM;
  end else begin
    assign PrivilegeModeW = 2'b11;
    assign STATUS_SXL     = 0;
    assign STATUS_UXL     = 0;
    assign wfiM           = 0;
    assign InterruptM     = 0;
  end

  //For VM Verification
  assign IVAdrF         = testbench.dut.core.ifu.immu.immu.tlb.tlb.VAdr;
  assign DVAdrM         = testbench.dut.core.lsu.dmmu.dmmu.tlb.tlb.VAdr;
  assign IPAF           = testbench.dut.core.ifu.immu.immu.PhysicalAddress;
  assign DPAM           = testbench.dut.core.lsu.dmmu.dmmu.PhysicalAddress;
  assign ReadAccessM    = testbench.dut.core.lsu.dmmu.dmmu.ReadAccessM;
  assign WriteAccessM   = testbench.dut.core.lsu.dmmu.dmmu.WriteAccessM;
  assign ExecuteAccessF = testbench.dut.core.ifu.immu.immu.ExecuteAccessF;
  assign IPTEF         = testbench.dut.core.ifu.immu.immu.PTE;
  assign DPTEM         = testbench.dut.core.lsu.dmmu.dmmu.PTE;
  assign IPPNF         = testbench.dut.core.ifu.immu.immu.tlb.tlb.PPN;
  assign DPPNM         = testbench.dut.core.lsu.dmmu.dmmu.tlb.tlb.PPN; 
  assign IPageTypeF    = testbench.dut.core.ifu.immu.immu.PageTypeWriteVal;
  assign DPageTypeM    = testbench.dut.core.lsu.dmmu.dmmu.PageTypeWriteVal;

  logic valid;
  
  if (P.ZICSR_SUPPORTED) begin
    always_comb begin
      // Since we are detected the CSR change by comparing the old value we need to
      // ensure the CSR is detected when the pipeline's Writeback stage is not
      // stalled.  If it is stalled we want CSRArray to hold the old value.
      if(valid) begin 
        // PMPCFG CSRs (space is 0-15 3a0 - 3af)
        localparam inc = P.XLEN == 32 ? 4 : 8;
        int i, i4, i8, csrid;
        logic [P.XLEN-1:0] pmp;

        for (i=0; i<P.PMP_ENTRIES; i+=inc) begin
          i4 = i / 4;
          i8 = (i / inc) * inc;
          csrid = 12'h3A0 + i4;
          pmp = 0;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+0] << 0;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+1] << 8;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+2] << 16;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+3] << 24;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+4] << 32;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+5] << 40;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+6] << 48;
          pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+7] << 56;
          
          CSRArray[csrid] = pmp;
        end

        // PMPADDR CSRs (space is 0-63 3b0 - 3ef)
        for (i=0; i<P.PMP_ENTRIES; i++) begin
          csrid = 12'h3B0 + i;;
          pmp = testbench.dut.core.priv.priv.csr.csrm.PMPADDR_ARRAY_REGW[i];
          CSRArray[csrid] = pmp;
        end

        // M-mode trap CSRs
        CSRArray[12'h300] = testbench.dut.core.priv.priv.csr.csrm.MSTATUS_REGW;
        CSRArray[12'h302] = testbench.dut.core.priv.priv.csr.csrm.MEDELEG_REGW;
        CSRArray[12'h303] = testbench.dut.core.priv.priv.csr.csrm.MIDELEG_REGW;
        CSRArray[12'h304] = testbench.dut.core.priv.priv.csr.csrm.MIE_REGW;
        CSRArray[12'h305] = testbench.dut.core.priv.priv.csr.csrm.MTVEC_REGW;
        CSRArray[12'h340] = testbench.dut.core.priv.priv.csr.csrm.MSCRATCH_REGW;
        CSRArray[12'h341] = testbench.dut.core.priv.priv.csr.csrm.MEPC_REGW;
        CSRArray[12'h342] = testbench.dut.core.priv.priv.csr.csrm.MCAUSE_REGW;
        CSRArray[12'h343] = testbench.dut.core.priv.priv.csr.csrm.MTVAL_REGW;
        CSRArray[12'h344] = testbench.dut.core.priv.priv.csr.csrm.MIP_REGW;
        
        // S-mode trap CSRs
        CSRArray[12'h100] = testbench.dut.core.priv.priv.csr.csrs.csrs.SSTATUS_REGW;
        CSRArray[12'h104] = testbench.dut.core.priv.priv.csr.csrm.MIE_REGW & 12'h222;
        CSRArray[12'h105] = testbench.dut.core.priv.priv.csr.csrs.csrs.STVEC_REGW;
        CSRArray[12'h140] = testbench.dut.core.priv.priv.csr.csrs.csrs.SSCRATCH_REGW;
        CSRArray[12'h141] = testbench.dut.core.priv.priv.csr.csrs.csrs.SEPC_REGW;
        CSRArray[12'h142] = testbench.dut.core.priv.priv.csr.csrs.csrs.SCAUSE_REGW;
        CSRArray[12'h143] = testbench.dut.core.priv.priv.csr.csrs.csrs.STVAL_REGW;
        CSRArray[12'h144] = testbench.dut.core.priv.priv.csr.csrm.MIP_REGW & 12'h222 & testbench.dut.core.priv.priv.csr.csrm.MIDELEG_REGW;

        // Virtual Memory CSRs
        CSRArray[12'h180] = testbench.dut.core.priv.priv.csr.csrs.csrs.SATP_REGW;

        // Floating-Point CSRs
        CSRArray[12'h001] = testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW;
        CSRArray[12'h002] = testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW;
        CSRArray[12'h003] = {testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW, testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW};

        // Counters / Performance Monitoring CSRs
        CSRArray[12'h306] = testbench.dut.core.priv.priv.csr.csrm.MCOUNTEREN_REGW;
        CSRArray[12'h106] = testbench.dut.core.priv.priv.csr.csrs.csrs.SCOUNTEREN_REGW;
        CSRArray[12'h320] = testbench.dut.core.priv.priv.csr.csrm.MCOUNTINHIBIT_REGW;
        // mhpmevent3-31 not connected (232-33F)
        CSRArray[12'hB00] = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[0]; // MCYCLE
        CSRArray[12'hB02] = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2]; // MINSTRET
        // mhpmcounter3-31 not connected (B03-B1F)
        // cycle, time, instret not connected (C00-C02)
        // hpmcounter3-31 not connected (C03-C1F)

        // Machine Information Registers and Configuration CSRs
        CSRArray[12'h301] = testbench.dut.core.priv.priv.csr.csrm.MISA_REGW;
        CSRArray[12'h30A] = testbench.dut.core.priv.priv.csr.csrm.MENVCFG_REGW;
        CSRArray[12'h10A] = testbench.dut.core.priv.priv.csr.csrs.csrs.SENVCFG_REGW;
        CSRArray[12'h747] = 0; // mseccfg
        CSRArray[12'hF11] = 0; //mvendorid
        CSRArray[12'hF12] = 0; // marchid
        CSRArray[12'hF13] = {{P.XLEN-12{1'b0}}, 12'h100}; // mimpid
        CSRArray[12'hF14] = testbench.dut.core.priv.priv.csr.csrm.MHARTID_REGW;
        CSRArray[12'hF15] = 0; //mconfigptr

        // Sstc CSRs
        CSRArray[12'h14D] = testbench.dut.core.priv.priv.csr.csrs.csrs.STIMECMP_REGW[P.XLEN-1:0];
        
        // Zkr CSRs
        // seed not connected (015)

        // extra CSRs for RV32
        if (P.XLEN == 32) begin
          CSRArray[12'h310] = testbench.dut.core.priv.priv.csr.csrsr.MSTATUSH_REGW;
          CSRArray[12'h31A] = testbench.dut.core.priv.priv.csr.csrm.MENVCFGH_REGW;
          CSRArray[12'h757] = 0; // mseccfgh
          CSRArray[12'h15D] = testbench.dut.core.priv.priv.csr.csrs.csrs.STIMECMP_REGW[63:32];
        end
      end else begin // hold the old value if the pipeline is stalled.
        // PMP CFG 3A0 to 3AF
        int csrid;
        for(csrid='h3A0; csrid<='h3AF; csrid++)
          CSRArray[csrid] = CSRArrayOld[csrid];
        
        // PMP ADDR 3B0 to 3EF
        for(csrid='h3B0; csrid<='h3EF; csrid++)
          CSRArray[csrid] = CSRArrayOld[csrid];

        // M-mode trap CSRs
        CSRArray[12'h300] = CSRArrayOld[12'h300];
        CSRArray[12'h302] = CSRArrayOld[12'h302];
        CSRArray[12'h303] = CSRArrayOld[12'h303];
        CSRArray[12'h304] = CSRArrayOld[12'h304];
        CSRArray[12'h305] = CSRArrayOld[12'h305];
        CSRArray[12'h340] = CSRArrayOld[12'h340];
        CSRArray[12'h341] = CSRArrayOld[12'h341];
        CSRArray[12'h342] = CSRArrayOld[12'h342];
        CSRArray[12'h343] = CSRArrayOld[12'h343];
        CSRArray[12'h344] = CSRArrayOld[12'h344];

        // S-mode trap CSRs
        CSRArray[12'h100] = CSRArrayOld[12'h100];
        CSRArray[12'h104] = CSRArrayOld[12'h104];
        CSRArray[12'h105] = CSRArrayOld[12'h105];
        CSRArray[12'h140] = CSRArrayOld[12'h140];
        CSRArray[12'h141] = CSRArrayOld[12'h141];
        CSRArray[12'h142] = CSRArrayOld[12'h142];
        CSRArray[12'h143] = CSRArrayOld[12'h143];
        CSRArray[12'h144] = CSRArrayOld[12'h144];

        // Virtual Memory CSRs
        CSRArray[12'h180] = CSRArrayOld[12'h180] ;

        // Floating-Point CSRs
        CSRArray[12'h001] = CSRArrayOld[12'h001];
        CSRArray[12'h002] = CSRArrayOld[12'h002];
        CSRArray[12'h003] = CSRArrayOld[12'h003];

        // Counters / Performance Monitoring CSRs
        CSRArray[12'h306] = CSRArrayOld[12'h306];
        CSRArray[12'h106] = CSRArrayOld[12'h106];
        CSRArray[12'h320] = CSRArrayOld[12'h320];
        // mhpmevent3-31 not connected (232-33F)
        CSRArray[12'hB00] = CSRArrayOld[12'hB00];
        CSRArray[12'hB02] = CSRArrayOld[12'hB02];
        // mhpmcounter3-31 not connected (B03-B1F)
        // cycle, time, instret not connected (C00-C02)
        // hpmcounter3-31 not connected (C03-C1F)

        // Machine Information Registers and Configuration CSRs
        CSRArray[12'h301] = CSRArrayOld[12'h301];
        CSRArray[12'h30A] = CSRArrayOld[12'h30A];
        CSRArray[12'h10A] = CSRArrayOld[12'h10A];
        CSRArray[12'h747] = CSRArrayOld[12'h747];
        CSRArray[12'hF11] = CSRArrayOld[12'hF11];
        CSRArray[12'hF12] = CSRArrayOld[12'hF12];
        CSRArray[12'hF13] = CSRArrayOld[12'hF13];
        CSRArray[12'hF14] = CSRArrayOld[12'hF14];
        CSRArray[12'hF15] = CSRArrayOld[12'hF15];

        // Sstc CSRs
        CSRArray[12'h14D] = CSRArrayOld[12'h14D];
        
        // Zkr CSRs
        // seed not connected (015)

        // extra CSRs for RV32
        if (P.XLEN == 32) begin
          CSRArray[12'h310] = CSRArrayOld[12'h310];
          CSRArray[12'h31A] = CSRArrayOld[12'h31A];
          CSRArray[12'h757] = CSRArrayOld[12'h757];
          CSRArray[12'h15D] = CSRArrayOld[12'h15D];
        end
      end    
    end
  end else begin
    // no CSRArray
  end

  genvar index;
  assign rf[0] = 0;
  for(index = 1; index < NUM_REGS; index += 1) 
    assign rf[index] = testbench.dut.core.ieu.dp.regf.rf[index];

  assign rf_a3  = testbench.dut.core.ieu.dp.regf.a3;
  assign rf_we3 = testbench.dut.core.ieu.dp.regf.we3;
  
  always_comb begin
    rf_wb <= 0;
    if(rf_we3)
      rf_wb[rf_a3] <= 1'b1;
  end

  if (P.F_SUPPORTED) begin
    assign frf_a4  = testbench.dut.core.fpu.fpu.fregfile.a4;
    assign frf_we4 = testbench.dut.core.fpu.fpu.fregfile.we4;
    for(index = 0; index < 32; index += 1) 
      assign frf[index] = testbench.dut.core.fpu.fpu.fregfile.rf[index];
  end else begin
    assign frf_a4  = '0;
    assign frf_we4 = 0;
    for(index = 0; index < 32; index += 1) 
      assign frf[index] = '0;
  end
  
  
  always_comb begin
    frf_wb <= 0;
    if(frf_we4)
      frf_wb[frf_a4] <= 1'b1;
  end

  assign CSRAdrM  = testbench.dut.core.priv.priv.csr.CSRAdrM;
  assign CSRWriteM = testbench.dut.core.priv.priv.csr.CSRWriteM;
  
  // pipeline to writeback stage
  flopenrc #(32)    InstrRawEReg (clk, reset, FlushE, ~StallE, InstrRawD, InstrRawE);
  flopenrc #(32)    InstrRawMReg (clk, reset, FlushM, ~StallM, InstrRawE, InstrRawM);
  flopenrc #(32)    InstrRawWReg (clk, reset, FlushW & ~TrapM, ~StallW, InstrRawM, InstrRawW);
  flopenrc #(P.XLEN)PCWReg       (clk, reset, FlushW & ~TrapM, ~StallW, PCM, PCW);
  flopenrc #(1)     InstrValidMReg (clk, reset, FlushW & ~TrapM, ~StallW, InstrValidM, InstrValidW);
  flopenrc #(1)     TrapWReg (clk, reset, 1'b0, ~StallW, TrapM, TrapW);
  flopenrc #(1)     InterruptWReg (clk, reset, 1'b0, ~StallW, InterruptM, InterruptW);
  flopenrc #(1)     HaltWReg (clk, reset, 1'b0, ~StallW, HaltM, HaltW);

  flopenrc #(12)    CSRAdrWReg (clk, reset, FlushW, ~StallW, CSRAdrM, CSRAdrW);
  flopenrc #(1)     CSRWriteWReg (clk, reset, FlushW, ~StallW, CSRWriteM, CSRWriteW);

  //for VM Verification
  flopenrc #(P.XLEN)     IVAdrDReg (clk, reset, 1'b0, SelHPTW, IVAdrF, IVAdrD); //Virtual Address for IMMU // *** RT: possible bug SelHPTW probably should be ~StallD
  flopenrc #(P.XLEN)     IVAdrEReg (clk, reset, 1'b0, ~StallE, IVAdrD, IVAdrE); //Virtual Address for IMMU
  flopenrc #(P.XLEN)     IVAdrMReg (clk, reset, 1'b0, ~(StallM & ~SelHPTW), IVAdrE, IVAdrM); //Virtual Address for IMMU
  flopenrc #(P.XLEN)     IVAdrWReg (clk, reset, 1'b0, SelHPTW, IVAdrM, IVAdrW); //Virtual Address for IMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW
  flopenrc #(P.XLEN)     DVAdrWReg (clk, reset, 1'b0, SelHPTW, DVAdrM, DVAdrW); //Virtual Address for DMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW

  flopenrc #(P.PA_BITS)  IPADReg (clk, reset, 1'b0, SelHPTW, IPAF, IPAD); //Physical Address for IMMU // *** RT: possible bug SelHPTW probably should be ~StallD
  flopenrc #(P.PA_BITS)  IPAEReg (clk, reset, 1'b0, ~StallE, IPAD, IPAE); //Physical Address for IMMU
  flopenrc #(P.PA_BITS)  IPAMReg (clk, reset, 1'b0, ~(StallM & ~SelHPTW), IPAE, IPAM); //Physical Address for IMMU
  flopenrc #(P.PA_BITS)  IPAWReg (clk, reset, 1'b0, SelHPTW, IPAM, IPAW); //Physical Address for IMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW
  flopenrc #(P.PA_BITS)  DPAWReg (clk, reset, 1'b0, SelHPTW, DPAM, DPAW); //Physical Address for DMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW

  flopenrc #(P.XLEN)     IPTEDReg (clk, reset, 1'b0, SelHPTW, IPTEF, IPTED); //PTE for IMMU // *** RT: possible bug SelHPTW probably should be ~StallD
  flopenrc #(P.XLEN)     IPTEEReg (clk, reset, 1'b0, ~StallE, IPTED, IPTEE); //PTE for IMMU
  flopenrc #(P.XLEN)     IPTEMReg (clk, reset, 1'b0, ~(StallM & ~SelHPTW), IPTEE, IPTEM); //PTE for IMMU
  flopenrc #(P.XLEN)     IPTEWReg (clk, reset, 1'b0, SelHPTW, IPTEM, IPTEW); //PTE for IMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW
  flopenrc #(P.XLEN)     DPTEWReg (clk, reset, 1'b0, SelHPTW, DPTEM, DPTEW); //PTE for DMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW

  flopenrc #(2)     IPageTypeDReg (clk, reset, 1'b0, SelHPTW, IPageTypeF, IPageTypeD); //PageType (kilo, mega, giga, tera) from IMMU // *** RT: possible bug SelHPTW probably should be ~StallD
  flopenrc #(2)     IPageTypeEReg (clk, reset, 1'b0, ~StallE, IPageTypeD, IPageTypeE); //PageType (kilo, mega, giga, tera) from IMMU
  flopenrc #(2)     IPageTypeMReg (clk, reset, 1'b0, ~(StallM & ~SelHPTW), IPageTypeE, IPageTypeM); //PageType (kilo, mega, giga, tera) from IMMU
  flopenrc #(2)     IPageTypeWReg (clk, reset, 1'b0, SelHPTW, IPageTypeM, IPageTypeW); //PageType (kilo, mega, giga, tera) from IMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW
  flopenrc #(2)     DPageTypeWReg (clk, reset, 1'b0, SelHPTW, DPageTypeM, DPageTypeW); //PageType (kilo, mega, giga, tera) from DMMU // *** RT: possible bug SelHPTW probably should be ~GatedStallW

  flopenrc #(P.PPN_BITS) IPPNDReg (clk, reset, 1'b0, ~StallD, IPPNF, IPPND); //Physical Page Number for IMMU
  flopenrc #(P.PPN_BITS) IPPNEReg (clk, reset, 1'b0, ~StallE, IPPND, IPPNE); //Physical Page Number for IMMU
  flopenrc #(P.PPN_BITS) IPPNMReg (clk, reset, 1'b0, ~StallM, IPPNE, IPPNM); //Physical Page Number for IMMU
  flopenrc #(P.PPN_BITS) IPPNWReg (clk, reset, 1'b0, ~StallW, IPPNM, IPPNW); //Physical Page Number for IMMU
  flopenrc #(P.PPN_BITS) DPPNWReg (clk, reset, 1'b0, ~StallW, DPPNM, DPPNW); //Physical Page Number for DMMU

  flopenrc #(1)  ReadAccessWReg    (clk, reset, 1'b0, ~GatedStallW, ReadAccessM, ReadAccessW);   //LoadAccess
  flopenrc #(1)  WriteAccessWReg   (clk, reset, 1'b0, ~GatedStallW, WriteAccessM, WriteAccessW); //StoreAccess

  flopenrc #(1)  ExecuteAccessDReg (clk, reset, 1'b0, ~StallD, ExecuteAccessF, ExecuteAccessD); //Instruction Fetch Access
  flopenrc #(1)  ExecuteAccessEReg (clk, reset, 1'b0, ~StallE, ExecuteAccessD, ExecuteAccessE); //Instruction Fetch Access
  flopenrc #(1)  ExecuteAccessMReg (clk, reset, 1'b0, ~StallM, ExecuteAccessE, ExecuteAccessM); //Instruction Fetch Access
  flopenrc #(1)  ExecuteAccessWReg (clk, reset, 1'b0, ~StallW, ExecuteAccessM, ExecuteAccessW); //Instruction Fetch Access

  // Initially connecting the writeback stage signals, but may need to use M stage
  // and gate on ~FlushW.

  assign valid  = ((InstrValidW | TrapW) & ~StallW) & ~reset;
  assign rvvi.clk = clk;
  assign rvvi.valid[0][0]    = valid;
  assign rvvi.order[0][0]    = CSRArray[12'hB02];  // TODO: IMPERAS Should be event order
  assign rvvi.insn[0][0]     = InstrRawW;
  assign rvvi.pc_rdata[0][0] = PCW;
  assign rvvi.trap[0][0]     = TrapW;
  assign rvvi.halt[0][0]     = HaltW;
  assign rvvi.intr[0][0]     = InterruptW;
  assign rvvi.mode[0][0]     = PrivilegeModeW;
  assign rvvi.ixl[0][0]      = PrivilegeModeW == 2'b11 ? 2'b10 :
                               PrivilegeModeW == 2'b01 ? STATUS_SXL : STATUS_UXL;
  assign rvvi.pc_wdata[0][0] = ~FlushW ? PCM :
                               ~FlushM ? PCE :
                               ~FlushE ? PCD :
                               ~FlushD ? PCF : PCNextF;

  for(index = 0; index < NUM_REGS; index += 1) begin
    assign rvvi.x_wdata[0][0][index] = rf[index];
    assign rvvi.x_wb[0][0][index]    = rf_wb[index];
  end
  for(index = 0; index < 32; index += 1) begin
    assign rvvi.f_wdata[0][0][index] = frf[index];
    assign rvvi.f_wb[0][0][index]    = frf_wb[index];
  end

  // record previous csr value.
  integer index4;
  always_ff @(posedge clk) begin
    int csrid;
    // PMP CFG 3A0 to 3AF
    for(csrid='h3A0; csrid<='h3AF; csrid++)
      CSRArrayOld[csrid] = CSRArray[csrid];
    
    // PMP ADDR 3B0 to 3EF
    for(csrid='h3B0; csrid<='h3EF; csrid++)
      CSRArrayOld[csrid] = CSRArray[csrid];

    // M-mode trap CSRs
    CSRArrayOld[12'h300] = CSRArray[12'h300];
    CSRArrayOld[12'h302] = CSRArray[12'h302];
    CSRArrayOld[12'h303] = CSRArray[12'h303];
    CSRArrayOld[12'h304] = CSRArray[12'h304];
    CSRArrayOld[12'h305] = CSRArray[12'h305];
    CSRArrayOld[12'h340] = CSRArray[12'h340];
    CSRArrayOld[12'h341] = CSRArray[12'h341];
    CSRArrayOld[12'h342] = CSRArray[12'h342];
    CSRArrayOld[12'h343] = CSRArray[12'h343];
    CSRArrayOld[12'h344] = CSRArray[12'h344];

    // S-mode trap CSRs
    CSRArrayOld[12'h100] = CSRArray[12'h100];
    CSRArrayOld[12'h104] = CSRArray[12'h104];
    CSRArrayOld[12'h105] = CSRArray[12'h105];
    CSRArrayOld[12'h140] = CSRArray[12'h140];
    CSRArrayOld[12'h141] = CSRArray[12'h141];
    CSRArrayOld[12'h142] = CSRArray[12'h142];
    CSRArrayOld[12'h143] = CSRArray[12'h143];
    CSRArrayOld[12'h144] = CSRArray[12'h144];

    // Virtual Memory CSRs
    CSRArrayOld[12'h180] = CSRArray[12'h180] ;

    // Floating-Point CSRs
    CSRArrayOld[12'h001] = CSRArray[12'h001];
    CSRArrayOld[12'h002] = CSRArray[12'h002];
    CSRArrayOld[12'h003] = CSRArray[12'h003];

    // Counters / Performance Monitoring CSRs
    CSRArrayOld[12'h306] = CSRArray[12'h306];
    CSRArrayOld[12'h106] = CSRArray[12'h106];
    CSRArrayOld[12'h320] = CSRArray[12'h320];
    // mhpmevent3-31 not connected (232-33F)
    CSRArrayOld[12'hB00] = CSRArray[12'hB00];
    CSRArrayOld[12'hB02] = CSRArray[12'hB02];
    // mhpmcounter3-31 not connected (B03-B1F)
    // cycle, time, instret not connected (C00-C02)
    // hpmcounter3-31 not connected (C03-C1F)

    // Machine Information Registers and Configuration CSRs
    CSRArrayOld[12'h301] = CSRArray[12'h301];
    CSRArrayOld[12'h30A] = CSRArray[12'h30A];
    CSRArrayOld[12'h10A] = CSRArray[12'h10A];
    CSRArrayOld[12'h747] = CSRArray[12'h747];
    CSRArrayOld[12'hF11] = CSRArray[12'hF11];
    CSRArrayOld[12'hF12] = CSRArray[12'hF12];
    CSRArrayOld[12'hF13] = CSRArray[12'hF13];
    CSRArrayOld[12'hF14] = CSRArray[12'hF14];
    CSRArrayOld[12'hF15] = CSRArray[12'hF15];

    // Sstc CSRs
    CSRArrayOld[12'h14D] = CSRArray[12'h14D];
    
    // Zkr CSRs
    // seed not connected (015)

    // extra CSRs for RV32
    if (P.XLEN == 32) begin
      CSRArrayOld[12'h310] = CSRArray[12'h310];
      CSRArrayOld[12'h31A] = CSRArray[12'h31A];
      CSRArrayOld[12'h757] = CSRArray[12'h757];
      CSRArrayOld[12'h15D] = CSRArray[12'h15D];
    end
  end
  
  // check for csr value change.
  // M-mode trap CSRs
  assign CSR_W[12'h300] = (CSRArrayOld[12'h300] != CSRArray[12'h300]) ? 1 : 0;
  assign CSR_W[12'h302] = (CSRArrayOld[12'h302] != CSRArray[12'h302]) ? 1 : 0;
  assign CSR_W[12'h303] = (CSRArrayOld[12'h303] != CSRArray[12'h303]) ? 1 : 0;
  assign CSR_W[12'h304] = (CSRArrayOld[12'h304] != CSRArray[12'h304]) ? 1 : 0;
  assign CSR_W[12'h305] = (CSRArrayOld[12'h305] != CSRArray[12'h305]) ? 1 : 0;
  assign CSR_W[12'h340] = (CSRArrayOld[12'h340] != CSRArray[12'h340]) ? 1 : 0;
  assign CSR_W[12'h341] = (CSRArrayOld[12'h341] != CSRArray[12'h341]) ? 1 : 0;
  assign CSR_W[12'h342] = (CSRArrayOld[12'h342] != CSRArray[12'h342]) ? 1 : 0;
  assign CSR_W[12'h343] = (CSRArrayOld[12'h343] != CSRArray[12'h343]) ? 1 : 0;
  assign CSR_W[12'h344] = (CSRArrayOld[12'h344] != CSRArray[12'h344]) ? 1 : 0;

  // S-mode trap CSRs
  assign CSR_W[12'h100] = (CSRArrayOld[12'h100] != CSRArray[12'h100]) ? 1 : 0;
  assign CSR_W[12'h104] = (CSRArrayOld[12'h104] != CSRArray[12'h104]) ? 1 : 0;
  assign CSR_W[12'h105] = (CSRArrayOld[12'h105] != CSRArray[12'h105]) ? 1 : 0;
  assign CSR_W[12'h140] = (CSRArrayOld[12'h140] != CSRArray[12'h140]) ? 1 : 0;
  assign CSR_W[12'h141] = (CSRArrayOld[12'h141] != CSRArray[12'h141]) ? 1 : 0;
  assign CSR_W[12'h142] = (CSRArrayOld[12'h142] != CSRArray[12'h142]) ? 1 : 0;
  assign CSR_W[12'h143] = (CSRArrayOld[12'h143] != CSRArray[12'h143]) ? 1 : 0;
  assign CSR_W[12'h144] = (CSRArrayOld[12'h144] != CSRArray[12'h144]) ? 1 : 0;

  // Virtual Memory CSRs
  assign CSR_W[12'h180] = (CSRArrayOld[12'h180] != CSRArray[12'h180]) ? 1 : 0;

  // Floating-Point CSRs
  assign CSR_W[12'h001] = (CSRArrayOld[12'h001] != CSRArray[12'h001]) ? 1 : 0;
  assign CSR_W[12'h002] = (CSRArrayOld[12'h002] != CSRArray[12'h002]) ? 1 : 0;
  assign CSR_W[12'h003] = (CSRArrayOld[12'h003] != CSRArray[12'h003]) ? 1 : 0;

  // Counters / Performance Monitoring CSRs
  assign CSR_W[12'h306] = (CSRArrayOld[12'h306] != CSRArray[12'h306]) ? 1 : 0;
  assign CSR_W[12'h106] = (CSRArrayOld[12'h106] != CSRArray[12'h106]) ? 1 : 0;
  assign CSR_W[12'h320] = (CSRArrayOld[12'h320] != CSRArray[12'h320]) ? 1 : 0;
  // mhpmevent3-31 not connected (232-33F)
  assign CSR_W[12'hB00] = (CSRArrayOld[12'hB00] != CSRArray[12'hB00]) ? 1 : 0;
  assign CSR_W[12'hB02] = (CSRArrayOld[12'hB02] != CSRArray[12'hB02]) ? 1 : 0;
  // mhpmcounter3-31 not connected (B03-B1F)
  // cycle, time, instret not connected (C00-C02)
  // hpmcounter3-31 not connected (C03-C1F)

  // Machine Information Registers and Configuration CSRs
  assign CSR_W[12'h301] = (CSRArrayOld[12'h301] != CSRArray[12'h301]) ? 1 : 0;
  assign CSR_W[12'h30A] = (CSRArrayOld[12'h30A] != CSRArray[12'h30A]) ? 1 : 0;
  assign CSR_W[12'h10A] = (CSRArrayOld[12'h10A] != CSRArray[12'h10A]) ? 1 : 0;
  assign CSR_W[12'h747] = (CSRArrayOld[12'h747] != CSRArray[12'h747]) ? 1 : 0;
  assign CSR_W[12'hF11] = (CSRArrayOld[12'hF11] != CSRArray[12'hF11]) ? 1 : 0;
  assign CSR_W[12'hF12] = (CSRArrayOld[12'hF12] != CSRArray[12'hF12]) ? 1 : 0;
  assign CSR_W[12'hF13] = (CSRArrayOld[12'hF13] != CSRArray[12'hF13]) ? 1 : 0;
  assign CSR_W[12'hF14] = (CSRArrayOld[12'hF14] != CSRArray[12'hF14]) ? 1 : 0;
  assign CSR_W[12'hF15] = (CSRArrayOld[12'hF15] != CSRArray[12'hF15]) ? 1 : 0;

  // Sstc CSRs
  assign CSR_W[12'h14D] = (CSRArrayOld[12'h14D] != CSRArray[12'h14D]) ? 1 : 0;
  
  // Zkr CSRs
  // seed not connected (015)

  // extra CSRs for RV32
  if (P.XLEN == 32) begin
    assign CSR_W[12'h310] = (CSRArrayOld[12'h310] != CSRArray[12'h310]) ? 1 : 0;
    assign CSR_W[12'h31A] = (CSRArrayOld[12'h31A] != CSRArray[12'h31A]) ? 1 : 0;
    assign CSR_W[12'h757] = (CSRArrayOld[12'h757] != CSRArray[12'h757]) ? 1 : 0;
    assign CSR_W[12'h15D] = (CSRArrayOld[12'h15D] != CSRArray[12'h15D]) ? 1 : 0;
  end



  // M-mode trap CSRs
  assign rvvi.csr_wb[0][0][12'h300] = CSR_W[12'h300];
  assign rvvi.csr_wb[0][0][12'h302] = CSR_W[12'h302];
  assign rvvi.csr_wb[0][0][12'h303] = CSR_W[12'h303];
  assign rvvi.csr_wb[0][0][12'h304] = CSR_W[12'h304];
  assign rvvi.csr_wb[0][0][12'h305] = CSR_W[12'h305];
  assign rvvi.csr_wb[0][0][12'h340] = CSR_W[12'h340];
  assign rvvi.csr_wb[0][0][12'h341] = CSR_W[12'h341];
  assign rvvi.csr_wb[0][0][12'h342] = CSR_W[12'h342];
  assign rvvi.csr_wb[0][0][12'h343] = CSR_W[12'h343];
  assign rvvi.csr_wb[0][0][12'h344] = CSR_W[12'h344];

  // S-mode trap CSRs
  assign rvvi.csr_wb[0][0][12'h100] = CSR_W[12'h100];
  assign rvvi.csr_wb[0][0][12'h104] = CSR_W[12'h104];
  assign rvvi.csr_wb[0][0][12'h105] = CSR_W[12'h105];
  assign rvvi.csr_wb[0][0][12'h140] = CSR_W[12'h140];
  assign rvvi.csr_wb[0][0][12'h141] = CSR_W[12'h141];
  assign rvvi.csr_wb[0][0][12'h142] = CSR_W[12'h142];
  assign rvvi.csr_wb[0][0][12'h143] = CSR_W[12'h143];
  assign rvvi.csr_wb[0][0][12'h144] = CSR_W[12'h144];

  // Virtual Memory CSRs
  assign rvvi.csr_wb[0][0][12'h180] = CSR_W[12'h180];

  // Floating-Point CSRs
  assign rvvi.csr_wb[0][0][12'h001] = CSR_W[12'h001];
  assign rvvi.csr_wb[0][0][12'h002] = CSR_W[12'h002];
  assign rvvi.csr_wb[0][0][12'h003] = CSR_W[12'h003];

  // Counters / Performance Monitoring CSRs
  assign rvvi.csr_wb[0][0][12'h306] = CSR_W[12'h306];
  assign rvvi.csr_wb[0][0][12'h106] = CSR_W[12'h106];
  assign rvvi.csr_wb[0][0][12'h320] = CSR_W[12'h320];
  // mhpmevent3-31 not connected (232-33F)
  assign rvvi.csr_wb[0][0][12'hB00] = CSR_W[12'hB00];
  assign rvvi.csr_wb[0][0][12'hB02] = CSR_W[12'hB02];
  // mhpmcounter3-31 not connected (B03-B1F)
  // cycle, time, instret not connected (C00-C02)
  // hpmcounter3-31 not connected (C03-C1F)

  // Machine Information Registers and Configuration CSRs
  assign rvvi.csr_wb[0][0][12'h301] = CSR_W[12'h301];
  assign rvvi.csr_wb[0][0][12'h30A] = CSR_W[12'h30A];
  assign rvvi.csr_wb[0][0][12'h10A] = CSR_W[12'h10A];
  assign rvvi.csr_wb[0][0][12'h747] = CSR_W[12'h747];
  assign rvvi.csr_wb[0][0][12'hF11] = CSR_W[12'hF11];
  assign rvvi.csr_wb[0][0][12'hF12] = CSR_W[12'hF12];
  assign rvvi.csr_wb[0][0][12'hF13] = CSR_W[12'hF13];
  assign rvvi.csr_wb[0][0][12'hF14] = CSR_W[12'hF14];
  assign rvvi.csr_wb[0][0][12'hF15] = CSR_W[12'hF15];

  // Sstc CSRs
  assign rvvi.csr_wb[0][0][12'h14D] = CSR_W[12'h14D];
  
  // Zkr CSRs
  // seed not connected (015)

  // extra CSRs for RV32
  if (P.XLEN == 32) begin
    assign rvvi.csr_wb[0][0][12'h310] = CSR_W[12'h310];
    assign rvvi.csr_wb[0][0][12'h31A] = CSR_W[12'h31A];
    assign rvvi.csr_wb[0][0][12'h757] = CSR_W[12'h757];
    assign rvvi.csr_wb[0][0][12'h15D] = CSR_W[12'h15D];
  end



// M-mode trap CSRs
  assign rvvi.csr[0][0][12'h300] = CSRArray[12'h300];
  assign rvvi.csr[0][0][12'h302] = CSRArray[12'h302];
  assign rvvi.csr[0][0][12'h303] = CSRArray[12'h303];
  assign rvvi.csr[0][0][12'h304] = CSRArray[12'h304];
  assign rvvi.csr[0][0][12'h305] = CSRArray[12'h305];
  assign rvvi.csr[0][0][12'h340] = CSRArray[12'h340];
  assign rvvi.csr[0][0][12'h341] = CSRArray[12'h341];
  assign rvvi.csr[0][0][12'h342] = CSRArray[12'h342];
  assign rvvi.csr[0][0][12'h343] = CSRArray[12'h343];
  assign rvvi.csr[0][0][12'h344] = CSRArray[12'h344];

  // S-mode trap CSRs
  assign rvvi.csr[0][0][12'h100] = CSRArray[12'h100];
  assign rvvi.csr[0][0][12'h104] = CSRArray[12'h104];
  assign rvvi.csr[0][0][12'h105] = CSRArray[12'h105];
  assign rvvi.csr[0][0][12'h140] = CSRArray[12'h140];
  assign rvvi.csr[0][0][12'h141] = CSRArray[12'h141];
  assign rvvi.csr[0][0][12'h142] = CSRArray[12'h142];
  assign rvvi.csr[0][0][12'h143] = CSRArray[12'h143];
  assign rvvi.csr[0][0][12'h144] = CSRArray[12'h144];

  // Virtual Memory CSRs
  assign rvvi.csr[0][0][12'h180] = CSRArray[12'h180];

  // Floating-Point CSRs
  assign rvvi.csr[0][0][12'h001] = CSRArray[12'h001];
  assign rvvi.csr[0][0][12'h002] = CSRArray[12'h002];
  assign rvvi.csr[0][0][12'h003] = CSRArray[12'h003];

  // Counters / Performance Monitoring CSRs
  assign rvvi.csr[0][0][12'h306] = CSRArray[12'h306];
  assign rvvi.csr[0][0][12'h106] = CSRArray[12'h106];
  assign rvvi.csr[0][0][12'h320] = CSRArray[12'h320];
  // mhpmevent3-31 not connected (232-33F)
  assign rvvi.csr[0][0][12'hB00] = CSRArray[12'hB00];
  assign rvvi.csr[0][0][12'hB02] = CSRArray[12'hB02];
  // mhpmcounter3-31 not connected (B03-B1F)
  // cycle, time, instret not connected (C00-C02)
  // hpmcounter3-31 not connected (C03-C1F)

  // Machine Information Registers and Configuration CSRs
  assign rvvi.csr[0][0][12'h301] = CSRArray[12'h301];
  assign rvvi.csr[0][0][12'h30A] = CSRArray[12'h30A];
  assign rvvi.csr[0][0][12'h10A] = CSRArray[12'h10A];
  assign rvvi.csr[0][0][12'h747] = CSRArray[12'h747];
  assign rvvi.csr[0][0][12'hF11] = CSRArray[12'hF11];
  assign rvvi.csr[0][0][12'hF12] = CSRArray[12'hF12];
  assign rvvi.csr[0][0][12'hF13] = CSRArray[12'hF13];
  assign rvvi.csr[0][0][12'hF14] = CSRArray[12'hF14];
  assign rvvi.csr[0][0][12'hF15] = CSRArray[12'hF15];

  // Sstc CSRs
  assign rvvi.csr[0][0][12'h14D] = CSRArray[12'h14D];
  
  // Zkr CSRs
  // seed not connected (015)

  // extra CSRs for RV32
  if (P.XLEN == 32) begin
    assign rvvi.csr[0][0][12'h310] = CSRArray[12'h310];
    assign rvvi.csr[0][0][12'h31A] = CSRArray[12'h31A];
    assign rvvi.csr[0][0][12'h757] = CSRArray[12'h757];
    assign rvvi.csr[0][0][12'h15D] = CSRArray[12'h15D];
  end


  // PMP CFG 3A0 to 3AF
  for(index='h3A0; index<='h3AF; index++) begin
    assign CSR_W[index] = (CSRArrayOld[index] != CSRArray[index]) ? 1 : 0;
    assign rvvi.csr_wb[0][0][index] = CSR_W[index];
    assign rvvi.csr[0][0][index] = CSRArray[index];  
  end

  // PMP ADDR 3B0 to 3EF
  for(index='h3B0; index<='h3EF; index++) begin
    assign CSR_W[index] = (CSRArrayOld[index] != CSRArray[index]) ? 1 : 0;
    assign rvvi.csr_wb[0][0][index] = CSR_W[index];
    assign rvvi.csr[0][0][index] = CSRArray[index];  
  end

  // *** implementation only cancel? so sc does not clear?
  assign rvvi.lrsc_cancel[0][0] = 0;

  integer index2;

  string  instrWName;
  int     file;
  string  LogFile;
  if(`STD_LOG) begin
    instrNameDecTB #(P.XLEN) NameDecoder(rvvi.insn[0][0], instrWName);
    initial begin
      LogFile = "logs/boottrace.log";
      file = $fopen(LogFile, "w");
    end
  end
  
  always_ff @(posedge clk) begin
	if(valid) begin
      if(`STD_LOG) begin
        $fwrite(file, "%016x, %08x, %s\t\t", rvvi.pc_rdata[0][0], rvvi.insn[0][0], instrWName);
        for(index2 = 0; index2 < NUM_REGS; index2 += 1) begin
          if(rvvi.x_wb[0][0][index2]) begin
            $fwrite(file, "rf[%02d] = %016x ", index2, rvvi.x_wdata[0][0][index2]);
          end
        end
      end
      for(index2 = 0; index2 < 32; index2 += 1) begin
        if(rvvi.f_wb[0][0][index2]) begin
          $fwrite(file, "frf[%02d] = %016x ", index2, rvvi.f_wdata[0][0][index2]);
        end
      end
      for(index2 = 0; index2 < NUM_CSRS; index2 += 1) begin
        if(rvvi.csr_wb[0][0][index2]) begin
          $fwrite(file, "csr[%03x] = %016x ", index2, rvvi.csr[0][0][index2]);
        end
      end
      $fwrite(file, "\n");
      if(`PRINT_PC_INSTR & !(`PRINT_ALL | `PRINT_MOST))
        $display("order = %08d, PC = %08x, insn = %08x", rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0]);
      else if(`PRINT_MOST & !`PRINT_ALL)
        $display("order = %08d, PC = %010x, insn = %08x, trap = %1d, halt = %1d, intr = %1d, mode = %1x, ixl = %1x, pc_wdata = %010x, x%02d = %016x, f%02d = %016x, csr%03x = %016x", 
                 rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0], rvvi.trap[0][0], rvvi.halt[0][0], rvvi.intr[0][0], rvvi.mode[0][0], rvvi.ixl[0][0], rvvi.pc_wdata[0][0], rf_a3, rvvi.x_wdata[0][0][rf_a3], frf_a4, rvvi.f_wdata[0][0][frf_a4], CSRAdrW, rvvi.csr[0][0][CSRAdrW]);
      else if(`PRINT_ALL) begin
        $display("order = %08d, PC = %08x, insn = %08x, trap = %1d, halt = %1d, intr = %1d, mode = %1x, ixl = %1x, pc_wdata = %08x", 
                 rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0], rvvi.trap[0][0], rvvi.halt[0][0], rvvi.intr[0][0], rvvi.mode[0][0], rvvi.ixl[0][0], rvvi.pc_wdata[0][0]);
        for(index2 = 0; index2 < NUM_REGS; index2 += 1) begin
          $display("x%02d = %08x", index2, rvvi.x_wdata[0][0][index2]);
        end
        for(index2 = 0; index2 < 32; index2 += 1) begin
          $display("f%02d = %08x", index2, rvvi.f_wdata[0][0][index2]);
        end
      end
      if (`PRINT_CSRS) begin
        for(index2 = 0; index2 < NUM_CSRS; index2 += 1) begin
          if(CSR_W[index2]) begin
            $display("%t: CSR %03x = %x", $time(), index2, CSRArray[index2]);
          end
        end
      end
    end
    if(HaltW) $finish;
  end
endmodule

