From 301d54fea8e08275646ae342b317a3a563073e44 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Wed, 14 Jun 2023 17:02:49 -0500 Subject: [PATCH] Significant refactoring of testbench. --- testbench/common/checksignature.sv | 26 +++ testbench/common/functionName.sv | 4 +- testbench/common/loggers.sv | 234 ++++++++++++++++++++ testbench/common/shadowmem.sv | 139 ++++++++++++ testbench/common/watchdog.sv | 52 +++++ testbench/testbench.sv | 342 +++++++---------------------- 6 files changed, 529 insertions(+), 268 deletions(-) create mode 100644 testbench/common/checksignature.sv create mode 100644 testbench/common/loggers.sv create mode 100644 testbench/common/shadowmem.sv create mode 100644 testbench/common/watchdog.sv diff --git a/testbench/common/checksignature.sv b/testbench/common/checksignature.sv new file mode 100644 index 000000000..7fb589bb6 --- /dev/null +++ b/testbench/common/checksignature.sv @@ -0,0 +1,26 @@ +/////////////////////////////////////////// +// checksignature.sv +// +// Written: David Harris David_Harris@hmc.edu +// Modified: 14 June 2023 +// +// Purpose: Verifies the memory signature. +// +// 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. +//////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/testbench/common/functionName.sv b/testbench/common/functionName.sv index 6f01471b3..90157f255 100644 --- a/testbench/common/functionName.sv +++ b/testbench/common/functionName.sv @@ -1,6 +1,8 @@ /////////////////////////////////////////// // functionName.sv // +// Written: Ross Thompson ross1728@gmail.com +// // Purpose: decode name of function // // A component of the Wally configurable RISC-V project. @@ -56,7 +58,6 @@ module FunctionName import cvw::*; #(parameter cvw_t P) ( flopenr #(P.XLEN) PCMReg(clk, reset, ~StallM, FlushD & FlushE & FlushM ? PCF : FlushE & FlushM ? PCE : FlushM ? PCM : PCE, PCM_temp); flopenr #(P.XLEN) PCMOldReg(clk, reset, InstrValidM, PCM_temp, PCMOld); assign PCM = InstrValidM ? PCM_temp : PCMOld; - task automatic bin_search_min; input logic [P.XLEN-1:0] pc; @@ -169,7 +170,6 @@ module FunctionName import cvw::*; #(parameter cvw_t P) ( initial ProgramAddrIndex = '0; assign FunctionName = AnyUnknown ? "Unknown!" : ProgramLabelMapMemory[ProgramAddrIndex]; - endmodule // function_radix diff --git a/testbench/common/loggers.sv b/testbench/common/loggers.sv new file mode 100644 index 000000000..0ab692385 --- /dev/null +++ b/testbench/common/loggers.sv @@ -0,0 +1,234 @@ +/////////////////////////////////////////// +// 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 TEST, + 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 + ); + + // performance counter logging + logic BeginSample; + logic StartSample, EndSample; + if(PrintHPMCounters & P.ZICOUNTERS_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" + }; + + 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 + 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 & + ~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; + assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : + dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M"; + 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; + assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : + (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" : + dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E"; + assign AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" : + dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" : + "NULL"; + + 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 & + (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; + logic PCSrcM; + string LogFile; + logic resetD, resetEdge; + flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.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 + //LogFile = $psprintf("branch_%s%0d.log", P.BPRED_TYPE, P.BPRED_SIZE); + file = $fopen(LogFile, "w"); + end + always @(posedge clk) begin + if(resetEdge) $fwrite(file, "TRAIN\n"); + if(StartSample) $fwrite(file, "BEGIN %s\n", memfilename); + 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(EndSample) $fwrite(file, "END %s\n", memfilename); + end + end + end + +endmodule diff --git a/testbench/common/shadowmem.sv b/testbench/common/shadowmem.sv new file mode 100644 index 000000000..021d4b82f --- /dev/null +++ b/testbench/common/shadowmem.sv @@ -0,0 +1,139 @@ +/////////////////////////////////////////// +// shadowmem.sv +// +// Written: David Harris David_Harris@hmc.edu and Ross Thompson ross1728@gmail.com +// Modified: 14 June 2023 +// +// Purpose: The L1 data cache and any feature L2 or high cache will not necessary writeback all dirty +// line before the end of test. Signature based regression tests need to check the L1 data cache +// in addition to the main memory. These modules create a shadow memory with a projection of the +// D$ contents. +// +// 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 DCacheFlushFSM import cvw::*; #(parameter cvw_t P) + (input logic clk, + input logic reset, + input logic start, + output logic done); + + genvar adr; + + logic [P.XLEN-1:0] ShadowRAM[P.UNCORE_RAM_BASE>>(1+P.XLEN/32):(P.UNCORE_RAM_RANGE+P.UNCORE_RAM_BASE)>>1+(P.XLEN/32)]; + logic startD; + + if(P.DCACHE_SUPPORTED) begin + localparam numlines = testbench.dut.core.lsu.bus.dcache.dcache.NUMLINES; + localparam numways = testbench.dut.core.lsu.bus.dcache.dcache.NUMWAYS; + localparam linebytelen = testbench.dut.core.lsu.bus.dcache.dcache.LINEBYTELEN; + localparam linelen = testbench.dut.core.lsu.bus.dcache.dcache.LINELEN; + localparam sramlen = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].SRAMLEN; + localparam cachesramwords = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].NUMSRAM; + localparam numwords = sramlen/P.XLEN; + localparam lognumlines = $clog2(numlines); + localparam loglinebytelen = $clog2(linebytelen); + localparam lognumways = $clog2(numways); + localparam tagstart = lognumlines + loglinebytelen; + + genvar index, way, cacheWord; + logic [sramlen-1:0] CacheData [numways-1:0] [numlines-1:0] [cachesramwords-1:0]; + logic [sramlen-1:0] cacheline; + logic [P.XLEN-1:0] CacheTag [numways-1:0] [numlines-1:0] [cachesramwords-1:0]; + logic CacheValid [numways-1:0] [numlines-1:0] [cachesramwords-1:0]; + logic CacheDirty [numways-1:0] [numlines-1:0] [cachesramwords-1:0]; + logic [P.PA_BITS-1:0] CacheAdr [numways-1:0] [numlines-1:0] [cachesramwords-1:0]; + for(index = 0; index < numlines; index++) begin + for(way = 0; way < numways; way++) begin + for(cacheWord = 0; cacheWord < cachesramwords; cacheWord++) begin + copyShadow #(.P(P), .tagstart(tagstart), + .loglinebytelen(loglinebytelen), .sramlen(sramlen)) + copyShadow(.clk, + .start, + .tag(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][P.PA_BITS-1-tagstart:0]), + .valid(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].ValidBits[index]), + .dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].DirtyBits[index]), + // these dirty bit selections would be needed if dirty is moved inside the tag array. + //.dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].dirty.DirtyMem.RAM[index]), + //.dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][P.PA_BITS+tagstart]), + .data(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].word[cacheWord].wordram.CacheDataMem.RAM[index]), + .index(index), + .cacheWord(cacheWord), + .CacheData(CacheData[way][index][cacheWord]), + .CacheAdr(CacheAdr[way][index][cacheWord]), + .CacheTag(CacheTag[way][index][cacheWord]), + .CacheValid(CacheValid[way][index][cacheWord]), + .CacheDirty(CacheDirty[way][index][cacheWord])); + end + end + end + + integer i, j, k, l; + + always @(posedge clk) begin + if (startD) begin + for(i = 0; i < numlines; i++) begin + for(j = 0; j < numways; j++) begin + for(l = 0; l < cachesramwords; l++) begin + if (CacheValid[j][i][l] & CacheDirty[j][i][l]) begin + for(k = 0; k < numwords; k++) begin + //cacheline = CacheData[j][i][0]; + // does not work with modelsim + // # ** Error: ../testbench/testbench.sv(483): Range must be bounded by constant expressions. + // see https://verificationacademy.com/forums/systemverilog/range-must-be-bounded-constant-expressions + //ShadowRAM[CacheAdr[j][i][k] >> $clog2(P.XLEN/8)] = cacheline[P.XLEN*(k+1)-1:P.XLEN*k]; + ShadowRAM[(CacheAdr[j][i][l] >> $clog2(P.XLEN/8)) + k] = CacheData[j][i][l][P.XLEN*k +: P.XLEN]; + end + end + end + end + end + end + end + end + flop #(1) doneReg1(.clk, .d(start), .q(startD)); + flop #(1) doneReg2(.clk, .d(startD), .q(done)); +endmodule + +module copyShadow import cvw::*; #(parameter cvw_t P, + parameter tagstart, loglinebytelen, sramlen) + (input logic clk, + input logic start, + input logic [P.PA_BITS-1:tagstart] tag, + input logic valid, dirty, + input logic [sramlen-1:0] data, + input logic [32-1:0] index, + input logic [32-1:0] cacheWord, + output logic [sramlen-1:0] CacheData, + output logic [P.PA_BITS-1:0] CacheAdr, + output logic [P.XLEN-1:0] CacheTag, + output logic CacheValid, + output logic CacheDirty); + + + always_ff @(posedge clk) begin + if(start) begin + CacheTag = tag; + CacheValid = valid; + CacheDirty = dirty; + CacheData = data; + CacheAdr = (tag << tagstart) + (index << loglinebytelen) + (cacheWord << $clog2(sramlen/8)); + end + end + +endmodule diff --git a/testbench/common/watchdog.sv b/testbench/common/watchdog.sv new file mode 100644 index 000000000..51ed8c30f --- /dev/null +++ b/testbench/common/watchdog.sv @@ -0,0 +1,52 @@ +/////////////////////////////////////////// +// watchdog.sv +// +// Written: Ross Thompson ross1728@gmail.com +// Modified: 14 June 2023 +// +// Purpose: Detects if the processor is stuck and halts the simulation +// +// 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 watchdog #(parameter XLEN, WatchDogTimerThreshold) + (input clk, + input reset + ); + + // check for hang up. + logic [XLEN-1:0] PCW; + flopenr #(XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); + logic [XLEN-1:0] OldPCW; + integer WatchDogTimerCount; + logic WatchDogTimeOut; + always_ff @(posedge clk) begin + OldPCW <= PCW; + if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1; + else WatchDogTimerCount = '0; + end + + always_comb begin + WatchDogTimeOut = WatchDogTimerCount >= WatchDogTimerThreshold; + if(WatchDogTimeOut) begin + $display("FAILURE: Watch Dog Time Out triggered. PCW stuck at %x for more than %d cycles", PCW, WatchDogTimerCount); + $stop; + end + end + +endmodule diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 7dd256e11..04e41b158 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -25,7 +25,6 @@ // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// -`include "wally-config.vh" `include "config.vh" `include "tests.vh" @@ -85,7 +84,6 @@ module testbench; string tests[]; logic DCacheFlushDone, DCacheFlushStart; logic riscofTest; - logic StartSample, EndSample; logic Validate; logic SelectTest; @@ -396,11 +394,8 @@ module testbench; $display("Read memfile %s", memfilename); end end - - - logic BeginSample; - + // instantiate device to be tested assign GPIOIN = 0; assign UARTSin = 1; @@ -451,89 +446,7 @@ module testbench; clk = 1; # 5; clk = 0; # 5; // if ($time % 100000 == 0) $display("Time is %0t", $time); end - - if(PrintHPMCounters & P.ZICOUNTERS_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" - }; - - 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 - 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 + // track the current function or global label if (DEBUG == 1 | (PrintHPMCounters & P.ZICOUNTERS_SUPPORTED)) begin : FunctionName @@ -564,120 +477,87 @@ module testbench; .start(DCacheFlushStart), .done(DCacheFlushDone)); - - - - 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 & - ~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; - assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : - dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M"; - 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; - assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : - (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" : - dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E"; - assign AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" : - dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" : - dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : - dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" : - "NULL"; - - 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 & - (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; - logic PCSrcM; - string LogFile; - logic resetD, resetEdge; - flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.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 - //LogFile = $psprintf("branch_%s%0d.log", P.BPRED_TYPE, P.BPRED_SIZE); - file = $fopen(LogFile, "w"); - end - always @(posedge clk) begin - if(resetEdge) $fwrite(file, "TRAIN\n"); - if(StartSample) $fwrite(file, "BEGIN %s\n", memfilename); - 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(EndSample) $fwrite(file, "END %s\n", memfilename); - end - end - end - watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); + loggers #(P, TEST, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER) + loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename); + + task automatic CheckSignature; + // This task must be declared inside this module as it needs access to parameter P. There is + // no way to pass P to the task unless we convert it to a module. + + input string pathname; + input string TestName; + input logic riscofTest; + input integer begin_signature_addr; + output integer errors; + + localparam SIGNATURESIZE = 5000000; + integer i; + logic [31:0] sig32[0:SIGNATURESIZE]; + logic [P.XLEN-1:0] signature[0:SIGNATURESIZE]; + string signame, pathname; + logic [P.XLEN-1:0] testadr, testadrNoBase; + + // for tests with no self checking mechanism, read .signature.output file and compare to check for errors + // clear signature to prevent contamination from previous tests + for(i=0; i