mirror of
https://github.com/openhwgroup/cvw
synced 2025-01-23 13:04:28 +00:00
295 lines
12 KiB
Systemverilog
295 lines
12 KiB
Systemverilog
///////////////////////////////////////////
|
|
// loggers.sv
|
|
//
|
|
// Written: Rose Thompson rose@rosethompson.net
|
|
// 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;
|
|
logic [P.XLEN-1:0] InitialHPMCOUNTERH[P.COUNTERS-1:0];
|
|
logic EndSampleDelayed;
|
|
|
|
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;
|
|
EndSampleFirst = '0;
|
|
end
|
|
|
|
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
|
always_comb
|
|
if (TEST == "embench" | TEST == "coremark") begin
|
|
EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
|
end else begin
|
|
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;
|
|
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" :
|
|
dut.core.lsu.bus.dcache.dcache.CMOpM == 4'b1000 ? "Z" : // cbo.zero
|
|
dut.core.lsu.bus.dcache.dcache.CMOpM == 4'b0001 ? "V" : // cbo.inval should just clear the valid and dirty bits
|
|
dut.core.lsu.bus.dcache.dcache.CMOpM == 4'b0010 ? "C" : // cbo.clean should act like a read in terms of the lru, but clears the dirty bit
|
|
dut.core.lsu.bus.dcache.dcache.CMOpM == 4'b0100 ? "L" : // cbo.flush should just clear and the valid and drity bits
|
|
"NULL";
|
|
end
|
|
|
|
assign Enabled = (dut.core.lsu.bus.dcache.dcache.cachefsm.LRUWriteEn |
|
|
// don't include cbo.zero as it uses LRUWriteEn to update the LRU and would be double counted.
|
|
((AccessTypeString == "C" | AccessTypeString == "L" | AccessTypeString == "V") & ~dut.core.lsu.bus.dcache.dcache.cachefsm.CacheStall)) &
|
|
~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 Rose's research analysis scripts
|
|
CFILogFile = "cfi.log"; // will break some of Rose'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.IClassM[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.IClassM) & ~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
|