mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			281 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Systemverilog
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Systemverilog
		
	
	
	
	
	
///////////////////////////////////////////
 | 
						|
// loggers.sv
 | 
						|
//
 | 
						|
// Written: Ross Thompson ross1728@gmail.com
 | 
						|
// Modified: 14 June 2023
 | 
						|
// 
 | 
						|
// Purpose: Log branch instructions, log instruction fetches,
 | 
						|
//          log I$ misses, log data memory accesses, log D$ misses, and
 | 
						|
//          log other related operations
 | 
						|
// 
 | 
						|
// 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.
 | 
						|
////////////////////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
module loggers import cvw::*; #(parameter cvw_t P,
 | 
						|
 | 
						|
                                parameter PrintHPMCounters,
 | 
						|
                                parameter I_CACHE_ADDR_LOGGER,
 | 
						|
                                parameter D_CACHE_ADDR_LOGGER,
 | 
						|
                                parameter BPRED_LOGGER) (
 | 
						|
  input logic  clk,
 | 
						|
  input logic  reset,
 | 
						|
  input logic  DCacheFlushStart,
 | 
						|
  input logic  DCacheFlushDone,                                                         
 | 
						|
//  input logic BeginSample,
 | 
						|
//  input logic StartSample,
 | 
						|
//  input logic EndSample,
 | 
						|
  input string memfilename,
 | 
						|
  input string TEST
 | 
						|
  );
 | 
						|
  
 | 
						|
  // performance counter logging 
 | 
						|
  logic        BeginSample;
 | 
						|
  logic StartSample, EndSample;
 | 
						|
  if((PrintHPMCounters | BPRED_LOGGER) & P.ZICNTR_SUPPORTED) begin : HPMCSample
 | 
						|
    integer           HPMCindex;
 | 
						|
    logic             StartSampleFirst;
 | 
						|
    logic             StartSampleDelayed, BeginDelayed;
 | 
						|
    logic             EndSampleFirst, EndSampleDelayed;
 | 
						|
    logic [P.XLEN-1:0] InitialHPMCOUNTERH[P.COUNTERS-1:0];
 | 
						|
 | 
						|
    string  HPMCnames[] = '{"Mcycle",
 | 
						|
                            "------",
 | 
						|
                            "InstRet",
 | 
						|
                            "Br Count",
 | 
						|
                            "Jump Not Return",
 | 
						|
                            "Return",
 | 
						|
                            "BP Wrong",
 | 
						|
                            "BP Dir Wrong",
 | 
						|
                            "BP Target Wrong",
 | 
						|
                            "RAS Wrong",
 | 
						|
                            "Instr Class Wrong",
 | 
						|
                            "Load Stall",
 | 
						|
                            "Store Stall",
 | 
						|
                            "D Cache Access",
 | 
						|
                            "D Cache Miss",
 | 
						|
                            "D Cache Cycles",
 | 
						|
                            "I Cache Access",
 | 
						|
                            "I Cache Miss",
 | 
						|
                            "I Cache Cycles",
 | 
						|
                            "CSR Write",
 | 
						|
                            "FenceI",
 | 
						|
                            "SFenceVMA",
 | 
						|
                            "Interrupt",
 | 
						|
                            "Exception",
 | 
						|
                            "Divide Cycles"
 | 
						|
                          };
 | 
						|
 | 
						|
    always_comb
 | 
						|
      if (TEST == "embench") begin  
 | 
						|
        StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
 | 
						|
        EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
 | 
						|
      end else if (TEST == "coremark") begin
 | 
						|
        StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
 | 
						|
        EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
 | 
						|
      end else begin
 | 
						|
        StartSampleFirst = reset;
 | 
						|
        EndSample = DCacheFlushStart & ~DCacheFlushDone;
 | 
						|
      end
 | 
						|
 | 
						|
  /*
 | 
						|
    if(TEST == "embench") begin
 | 
						|
      // embench runs warmup then runs start_trigger
 | 
						|
      // embench end with stop_trigger.
 | 
						|
      //assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
 | 
						|
      //flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
 | 
						|
      //assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
 | 
						|
 | 
						|
      //assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
 | 
						|
      flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
 | 
						|
      assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
 | 
						|
 | 
						|
    end else if(TEST == "coremark") begin
 | 
						|
      // embench runs warmup then runs start_trigger
 | 
						|
	    // embench end with stop_trigger.
 | 
						|
      //assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
 | 
						|
      //flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
 | 
						|
      //assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
 | 
						|
 | 
						|
      //assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
 | 
						|
      flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
 | 
						|
      assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
 | 
						|
 | 
						|
    end else begin
 | 
						|
      // default start condiction is reset
 | 
						|
      // default end condiction is end of test (DCacheFlushDone)
 | 
						|
      //assign StartSampleFirst = reset;
 | 
						|
      //flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
 | 
						|
      //assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
 | 
						|
      //assign EndSample = DCacheFlushStart & ~DCacheFlushDone;
 | 
						|
 | 
						|
      flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed);
 | 
						|
      assign BeginSample = StartSampleFirst & ~BeginDelayed;
 | 
						|
 | 
						|
    end
 | 
						|
 | 
						|
  */
 | 
						|
 | 
						|
    flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
 | 
						|
    assign StartSample = StartSampleFirst & ~StartSampleDelayed;
 | 
						|
    flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
 | 
						|
    assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
 | 
						|
    flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed); // ** is this redundant with StartSampleReg?
 | 
						|
    assign BeginSample = StartSampleFirst & ~BeginDelayed;
 | 
						|
 | 
						|
 | 
						|
    always @(negedge clk) begin
 | 
						|
      if(StartSample) begin
 | 
						|
        for(HPMCindex = 0; HPMCindex < 32; HPMCindex += 1) begin
 | 
						|
          InitialHPMCOUNTERH[HPMCindex] <= dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex];
 | 
						|
        end
 | 
						|
      end
 | 
						|
      if(EndSample) begin
 | 
						|
        for(HPMCindex = 0; HPMCindex < HPMCnames.size(); HPMCindex += 1) begin
 | 
						|
          // unlikely to have more than 10M in any counter.
 | 
						|
          $display("Cnt[%2d] = %7d %s", HPMCindex, dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex] - InitialHPMCOUNTERH[HPMCindex], HPMCnames[HPMCindex]);
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  if (P.ICACHE_SUPPORTED && I_CACHE_ADDR_LOGGER) begin : ICacheLogger
 | 
						|
    int    file;
 | 
						|
    string LogFile;
 | 
						|
    logic  resetD, resetEdge;
 | 
						|
    logic  Enable;
 | 
						|
    logic  InvalDelayed, InvalEdge;
 | 
						|
    
 | 
						|
    assign Enable = dut.core.ifu.bus.icache.icache.cachefsm.LRUWriteEn & 
 | 
						|
                    dut.core.ifu.immu.immu.pmachecker.Cacheable &
 | 
						|
                    ~dut.core.ifu.bus.icache.icache.cachefsm.FlushStage &
 | 
						|
                    dut.core.ifu.bus.icache.icache.cachefsm.CacheEn &
 | 
						|
                    ~reset;
 | 
						|
    flop #(1) ResetDReg(clk, reset, resetD);
 | 
						|
    assign resetEdge = ~reset & resetD;
 | 
						|
 | 
						|
    flop #(1) InvalReg(clk, dut.core.ifu.InvalidateICacheM, InvalDelayed);
 | 
						|
    assign InvalEdge = dut.core.ifu.InvalidateICacheM & ~InvalDelayed;
 | 
						|
 | 
						|
    initial begin
 | 
						|
      LogFile = "ICache.log";
 | 
						|
      file = $fopen(LogFile, "w");
 | 
						|
      $fwrite(file, "BEGIN %s\n", memfilename);
 | 
						|
    end
 | 
						|
    string AccessTypeString, HitMissString;
 | 
						|
    always @(*) begin
 | 
						|
      HitMissString = dut.core.ifu.bus.icache.icache.Hit ? "H" :
 | 
						|
                      dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M";
 | 
						|
    end
 | 
						|
    always @(posedge clk) begin
 | 
						|
    if(resetEdge) $fwrite(file, "TRAIN\n");
 | 
						|
    if(BeginSample) $fwrite(file, "BEGIN %s\n", memfilename);
 | 
						|
    if(Enable) begin  // only log i cache reads
 | 
						|
      $fwrite(file, "%h R %s\n", dut.core.ifu.PCPF, HitMissString);
 | 
						|
    end
 | 
						|
    if(InvalEdge) $fwrite(file, "0 I X\n");
 | 
						|
    if(EndSample) $fwrite(file, "END %s\n", memfilename);
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
 | 
						|
  if (P.DCACHE_SUPPORTED && D_CACHE_ADDR_LOGGER) begin : DCacheLogger
 | 
						|
    int    file;
 | 
						|
    string LogFile;
 | 
						|
    logic  resetD, resetEdge;
 | 
						|
    logic  Enabled;
 | 
						|
    string AccessTypeString, HitMissString;
 | 
						|
 | 
						|
    flop #(1) ResetDReg(clk, reset, resetD);
 | 
						|
    assign resetEdge = ~reset & resetD;
 | 
						|
    always @(*) begin
 | 
						|
      HitMissString = dut.core.lsu.bus.dcache.dcache.Hit ? "H" :
 | 
						|
                      (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" :
 | 
						|
                      dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E";
 | 
						|
      AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" :
 | 
						|
                         dut.core.lsu.LSUAtomicM[1] ? "A" :
 | 
						|
                         dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : 
 | 
						|
                         dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" :
 | 
						|
                         "NULL";
 | 
						|
    end
 | 
						|
 | 
						|
    assign Enabled = dut.core.lsu.bus.dcache.dcache.cachefsm.LRUWriteEn &
 | 
						|
                     ~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage &
 | 
						|
                     dut.core.lsu.dmmu.dmmu.pmachecker.Cacheable &
 | 
						|
                     dut.core.lsu.bus.dcache.dcache.cachefsm.CacheEn &
 | 
						|
                     (AccessTypeString != "NULL");
 | 
						|
 | 
						|
    initial begin
 | 
						|
      LogFile = "DCache.log";
 | 
						|
      file = $fopen(LogFile, "w");
 | 
						|
      $fwrite(file, "BEGIN %s\n", memfilename);
 | 
						|
    end
 | 
						|
    always @(posedge clk) begin
 | 
						|
      if(resetEdge) $fwrite(file, "TRAIN\n");
 | 
						|
      if(BeginSample) $fwrite(file, "BEGIN %s\n", memfilename);
 | 
						|
      if(Enabled) begin
 | 
						|
        $fwrite(file, "%h %s %s\n", dut.core.lsu.PAdrM, AccessTypeString, HitMissString);
 | 
						|
      end
 | 
						|
      if(dut.core.lsu.bus.dcache.dcache.cachefsm.FlushFlag) $fwrite(file, "0 F X\n");
 | 
						|
      if(EndSample) $fwrite(file, "END %s\n", memfilename);
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  if (P.BPRED_SUPPORTED) begin : BranchLogger
 | 
						|
    if (BPRED_LOGGER) begin
 | 
						|
      string direction;
 | 
						|
      int    file, CFIfile;
 | 
						|
      logic  PCSrcM;
 | 
						|
      string LogFile, CFILogFile;
 | 
						|
      logic  resetD, resetEdge;
 | 
						|
      flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.PCSrcE, PCSrcM);
 | 
						|
      flop #(1) ResetDReg(clk, reset, resetD);
 | 
						|
      assign resetEdge = ~reset & resetD;
 | 
						|
      initial begin
 | 
						|
        LogFile = "branch.log"; // will break some of Ross's research analysis scripts
 | 
						|
        CFILogFile = "cfi.log"; // will break some of Ross's research analysis scripts
 | 
						|
        //LogFile = $psprintf("branch_%s%0d.log", P.BPRED_TYPE, P.BPRED_SIZE);
 | 
						|
        file = $fopen(LogFile, "w");
 | 
						|
        CFIfile = $fopen(CFILogFile, "w");
 | 
						|
      end
 | 
						|
      always @(posedge clk) begin
 | 
						|
        if(resetEdge) begin 
 | 
						|
          $fwrite(file, "TRAIN\n");
 | 
						|
          $fwrite(CFIfile, "TRAIN\n");
 | 
						|
        end
 | 
						|
        if(StartSample) begin
 | 
						|
          $fwrite(file, "BEGIN %s\n", memfilename);
 | 
						|
          $fwrite(CFIfile, "BEGIN %s\n", memfilename);
 | 
						|
        end
 | 
						|
        if(dut.core.ifu.InstrClassM[0] & ~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin
 | 
						|
          direction = PCSrcM ? "t" : "n";
 | 
						|
          $fwrite(file, "%h %s\n", dut.core.PCM, direction);
 | 
						|
        end
 | 
						|
        if((|dut.core.ifu.InstrClassM) & ~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin
 | 
						|
          direction = PCSrcM ? "t" : "n";
 | 
						|
          $fwrite(CFIfile, "%h %s\n", dut.core.PCM, direction);
 | 
						|
        end
 | 
						|
        if(EndSample) begin
 | 
						|
          $fwrite(file, "END %s\n", memfilename);
 | 
						|
          $fwrite(CFIfile, "END %s\n", memfilename);
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
endmodule
 |