mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-02 09:45:18 +00:00
Significant refactoring of testbench.
This commit is contained in:
parent
4d2bb0ea83
commit
301d54fea8
26
testbench/common/checksignature.sv
Normal file
26
testbench/common/checksignature.sv
Normal file
@ -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.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -1,6 +1,8 @@
|
|||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
// functionName.sv
|
// functionName.sv
|
||||||
//
|
//
|
||||||
|
// Written: Ross Thompson ross1728@gmail.com
|
||||||
|
//
|
||||||
// Purpose: decode name of function
|
// Purpose: decode name of function
|
||||||
//
|
//
|
||||||
// A component of the Wally configurable RISC-V project.
|
// 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) 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);
|
flopenr #(P.XLEN) PCMOldReg(clk, reset, InstrValidM, PCM_temp, PCMOld);
|
||||||
assign PCM = InstrValidM ? PCM_temp : PCMOld;
|
assign PCM = InstrValidM ? PCM_temp : PCMOld;
|
||||||
|
|
||||||
|
|
||||||
task automatic bin_search_min;
|
task automatic bin_search_min;
|
||||||
input logic [P.XLEN-1:0] pc;
|
input logic [P.XLEN-1:0] pc;
|
||||||
@ -169,7 +170,6 @@ module FunctionName import cvw::*; #(parameter cvw_t P) (
|
|||||||
initial ProgramAddrIndex = '0;
|
initial ProgramAddrIndex = '0;
|
||||||
|
|
||||||
assign FunctionName = AnyUnknown ? "Unknown!" : ProgramLabelMapMemory[ProgramAddrIndex];
|
assign FunctionName = AnyUnknown ? "Unknown!" : ProgramLabelMapMemory[ProgramAddrIndex];
|
||||||
|
|
||||||
|
|
||||||
endmodule // function_radix
|
endmodule // function_radix
|
||||||
|
|
||||||
|
234
testbench/common/loggers.sv
Normal file
234
testbench/common/loggers.sv
Normal file
@ -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
|
139
testbench/common/shadowmem.sv
Normal file
139
testbench/common/shadowmem.sv
Normal file
@ -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
|
52
testbench/common/watchdog.sv
Normal file
52
testbench/common/watchdog.sv
Normal file
@ -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
|
@ -25,7 +25,6 @@
|
|||||||
// and limitations under the License.
|
// and limitations under the License.
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
`include "wally-config.vh"
|
|
||||||
`include "config.vh"
|
`include "config.vh"
|
||||||
`include "tests.vh"
|
`include "tests.vh"
|
||||||
|
|
||||||
@ -85,7 +84,6 @@ module testbench;
|
|||||||
string tests[];
|
string tests[];
|
||||||
logic DCacheFlushDone, DCacheFlushStart;
|
logic DCacheFlushDone, DCacheFlushStart;
|
||||||
logic riscofTest;
|
logic riscofTest;
|
||||||
logic StartSample, EndSample;
|
|
||||||
logic Validate;
|
logic Validate;
|
||||||
logic SelectTest;
|
logic SelectTest;
|
||||||
|
|
||||||
@ -396,11 +394,8 @@ module testbench;
|
|||||||
$display("Read memfile %s", memfilename);
|
$display("Read memfile %s", memfilename);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logic BeginSample;
|
|
||||||
|
|
||||||
// instantiate device to be tested
|
// instantiate device to be tested
|
||||||
assign GPIOIN = 0;
|
assign GPIOIN = 0;
|
||||||
assign UARTSin = 1;
|
assign UARTSin = 1;
|
||||||
@ -451,89 +446,7 @@ module testbench;
|
|||||||
clk = 1; # 5; clk = 0; # 5;
|
clk = 1; # 5; clk = 0; # 5;
|
||||||
// if ($time % 100000 == 0) $display("Time is %0t", $time);
|
// if ($time % 100000 == 0) $display("Time is %0t", $time);
|
||||||
end
|
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
|
// track the current function or global label
|
||||||
if (DEBUG == 1 | (PrintHPMCounters & P.ZICOUNTERS_SUPPORTED)) begin : FunctionName
|
if (DEBUG == 1 | (PrintHPMCounters & P.ZICOUNTERS_SUPPORTED)) begin : FunctionName
|
||||||
@ -564,120 +477,87 @@ module testbench;
|
|||||||
.start(DCacheFlushStart),
|
.start(DCacheFlushStart),
|
||||||
.done(DCacheFlushDone));
|
.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);
|
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<SIGNATURESIZE; i=i+1) begin
|
||||||
|
sig32[i] = 'bx;
|
||||||
|
end
|
||||||
|
if (riscofTest) signame = {pathname, TestName, "/ref/Reference-sail_c_simulator.signature"};
|
||||||
|
else signame = {pathname, TestName, ".signature.output"};
|
||||||
|
// read signature, reformat in 64 bits if necessary
|
||||||
|
$readmemh(signame, sig32);
|
||||||
|
i = 0;
|
||||||
|
while (i < SIGNATURESIZE) begin
|
||||||
|
if (P.XLEN == 32) begin
|
||||||
|
signature[i] = sig32[i];
|
||||||
|
i = i+1;
|
||||||
|
end else begin
|
||||||
|
signature[i/2] = {sig32[i+1], sig32[i]};
|
||||||
|
i = i + 2;
|
||||||
|
end
|
||||||
|
if (i >= 4 & sig32[i-4] === 'bx) begin
|
||||||
|
if (i == 4) begin
|
||||||
|
i = SIGNATURESIZE+1; // flag empty file
|
||||||
|
$display(" Error: empty test file");
|
||||||
|
end else i = SIGNATURESIZE; // skip over the rest of the x's for efficiency
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Check errors
|
||||||
|
errors = (i == SIGNATURESIZE+1); // error if file is empty
|
||||||
|
i = 0;
|
||||||
|
testadr = ($unsigned(begin_signature_addr))/(P.XLEN/8);
|
||||||
|
testadrNoBase = (begin_signature_addr - P.UNCORE_RAM_BASE)/(P.XLEN/8);
|
||||||
|
/* verilator lint_off INFINITELOOP */
|
||||||
|
while (signature[i] !== 'bx) begin
|
||||||
|
logic [P.XLEN-1:0] sig;
|
||||||
|
if (P.DTIM_SUPPORTED) sig = testbench.dut.core.lsu.dtim.dtim.ram.RAM[testadrNoBase+i];
|
||||||
|
else if (P.UNCORE_RAM_SUPPORTED) sig = testbench.dut.uncore.uncore.ram.ram.memory.RAM[testadrNoBase+i];
|
||||||
|
//$display("signature[%h] = %h sig = %h", i, signature[i], sig);
|
||||||
|
if (signature[i] !== sig & (signature[i] !== testbench.DCacheFlushFSM.ShadowRAM[testadr+i])) begin
|
||||||
|
errors = errors+1;
|
||||||
|
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
|
||||||
|
TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
|
||||||
|
$stop; //***debug
|
||||||
|
end
|
||||||
|
i = i + 1;
|
||||||
|
end
|
||||||
|
/* verilator lint_on INFINITELOOP */
|
||||||
|
if (errors == 0) begin
|
||||||
|
$display("%s succeeded. Brilliant!!!", TestName);
|
||||||
|
end else begin
|
||||||
|
$display("%s failed with %d errors. :(", TestName, errors);
|
||||||
|
//totalerrors = totalerrors+1;
|
||||||
|
end
|
||||||
|
|
||||||
|
endtask //
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
/* verilator lint_on STMTDLY */
|
/* verilator lint_on STMTDLY */
|
||||||
/* verilator lint_on WIDTH */
|
/* verilator lint_on WIDTH */
|
||||||
|
|
||||||
|
|
||||||
task automatic updateProgramAddrLabelArray;
|
task automatic updateProgramAddrLabelArray;
|
||||||
input string ProgramAddrMapFile, ProgramLabelMapFile;
|
input string ProgramAddrMapFile, ProgramLabelMapFile;
|
||||||
inout integer ProgramAddrLabelArray [string];
|
inout integer ProgramAddrLabelArray [string];
|
||||||
@ -703,73 +583,3 @@ task automatic updateProgramAddrLabelArray;
|
|||||||
$fclose(ProgramAddrMapFP);
|
$fclose(ProgramAddrMapFP);
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
|
||||||
task automatic CheckSignature;
|
|
||||||
|
|
||||||
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 [`XLEN-1:0] signature[0:SIGNATURESIZE];
|
|
||||||
string signame, pathname;
|
|
||||||
logic [`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<SIGNATURESIZE; i=i+1) begin
|
|
||||||
sig32[i] = 'bx;
|
|
||||||
end
|
|
||||||
if (riscofTest) signame = {pathname, TestName, "/ref/Reference-sail_c_simulator.signature"};
|
|
||||||
else signame = {pathname, TestName, ".signature.output"};
|
|
||||||
// read signature, reformat in 64 bits if necessary
|
|
||||||
$readmemh(signame, sig32);
|
|
||||||
i = 0;
|
|
||||||
while (i < SIGNATURESIZE) begin
|
|
||||||
if (`XLEN == 32) begin
|
|
||||||
signature[i] = sig32[i];
|
|
||||||
i = i+1;
|
|
||||||
end else begin
|
|
||||||
signature[i/2] = {sig32[i+1], sig32[i]};
|
|
||||||
i = i + 2;
|
|
||||||
end
|
|
||||||
if (i >= 4 & sig32[i-4] === 'bx) begin
|
|
||||||
if (i == 4) begin
|
|
||||||
i = SIGNATURESIZE+1; // flag empty file
|
|
||||||
$display(" Error: empty test file");
|
|
||||||
end else i = SIGNATURESIZE; // skip over the rest of the x's for efficiency
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// Check errors
|
|
||||||
errors = (i == SIGNATURESIZE+1); // error if file is empty
|
|
||||||
i = 0;
|
|
||||||
testadr = ($unsigned(begin_signature_addr))/(`XLEN/8);
|
|
||||||
testadrNoBase = (begin_signature_addr - `UNCORE_RAM_BASE)/(`XLEN/8);
|
|
||||||
/* verilator lint_off INFINITELOOP */
|
|
||||||
while (signature[i] !== 'bx) begin
|
|
||||||
logic [`XLEN-1:0] sig;
|
|
||||||
if (`DTIM_SUPPORTED) sig = testbench.dut.core.lsu.dtim.dtim.ram.RAM[testadrNoBase+i];
|
|
||||||
else if (`UNCORE_RAM_SUPPORTED) sig = testbench.dut.uncore.uncore.ram.ram.memory.RAM[testadrNoBase+i];
|
|
||||||
//$display("signature[%h] = %h sig = %h", i, signature[i], sig);
|
|
||||||
if (signature[i] !== sig & (signature[i] !== testbench.DCacheFlushFSM.ShadowRAM[testadr+i])) begin
|
|
||||||
errors = errors+1;
|
|
||||||
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
|
|
||||||
TestName, i, (testadr+i)*(`XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
|
|
||||||
$stop; //***debug
|
|
||||||
end
|
|
||||||
i = i + 1;
|
|
||||||
end
|
|
||||||
/* verilator lint_on INFINITELOOP */
|
|
||||||
if (errors == 0) begin
|
|
||||||
$display("%s succeeded. Brilliant!!!", TestName);
|
|
||||||
end else begin
|
|
||||||
$display("%s failed with %d errors. :(", TestName, errors);
|
|
||||||
//totalerrors = totalerrors+1;
|
|
||||||
end
|
|
||||||
|
|
||||||
endtask //
|
|
||||||
|
Loading…
Reference in New Issue
Block a user