2021-10-10 22:07:51 +00:00
|
|
|
///////////////////////////////////////////
|
|
|
|
// testbench.sv
|
|
|
|
//
|
|
|
|
// Written: David_Harris@hmc.edu 9 January 2021
|
|
|
|
// Modified:
|
|
|
|
//
|
|
|
|
// Purpose: Wally Testbench and helper modules
|
|
|
|
// Applies test programs from the riscv-arch-test and Imperas suites
|
|
|
|
//
|
|
|
|
// A component of the Wally configurable RISC-V project.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
|
|
|
//
|
2023-02-04 16:19:20 +00:00
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
2021-10-10 22:07:51 +00:00
|
|
|
//
|
2023-02-04 16:19:20 +00:00
|
|
|
// 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
|
2021-10-10 22:07:51 +00:00
|
|
|
//
|
2023-02-04 16:19:20 +00:00
|
|
|
// 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.
|
2022-01-07 12:58:40 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
`include "wally-config.vh"
|
|
|
|
`include "tests.vh"
|
|
|
|
|
2023-03-29 04:28:56 +00:00
|
|
|
`define PrintHPMCounters 0
|
2023-03-28 21:20:45 +00:00
|
|
|
`define BPRED_LOGGER 0
|
2023-04-05 09:43:02 +00:00
|
|
|
`define I_CACHE_ADDR_LOGGER 0
|
|
|
|
`define D_CACHE_ADDR_LOGGER 0
|
2023-01-06 00:00:11 +00:00
|
|
|
|
2021-10-23 13:15:26 +00:00
|
|
|
module testbench;
|
2021-10-10 22:07:51 +00:00
|
|
|
parameter DEBUG=0;
|
|
|
|
parameter TEST="none";
|
|
|
|
|
|
|
|
logic clk;
|
2021-10-25 17:05:41 +00:00
|
|
|
logic reset_ext, reset;
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
parameter SIGNATURESIZE = 5000000;
|
|
|
|
|
|
|
|
int test, i, errors, totalerrors;
|
|
|
|
logic [31:0] sig32[0:SIGNATURESIZE];
|
|
|
|
logic [`XLEN-1:0] signature[0:SIGNATURESIZE];
|
2022-03-30 04:48:19 +00:00
|
|
|
logic [`XLEN-1:0] testadr, testadrNoBase;
|
2021-10-10 22:07:51 +00:00
|
|
|
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
|
|
|
|
logic [31:0] InstrW;
|
|
|
|
|
2023-04-13 23:53:36 +00:00
|
|
|
string tests[];
|
|
|
|
logic [3:0] dummy;
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
logic [`AHBW-1:0] HRDATAEXT;
|
|
|
|
logic HREADYEXT, HRESPEXT;
|
2022-08-25 20:11:36 +00:00
|
|
|
logic [`PA_BITS-1:0] HADDR;
|
2023-04-14 02:06:09 +00:00
|
|
|
logic [`AHBW-1:0] HWDATA;
|
|
|
|
logic [`XLEN/8-1:0] HWSTRB;
|
|
|
|
logic HWRITE;
|
|
|
|
logic [2:0] HSIZE;
|
|
|
|
logic [2:0] HBURST;
|
|
|
|
logic [3:0] HPROT;
|
|
|
|
logic [1:0] HTRANS;
|
|
|
|
logic HMASTLOCK;
|
|
|
|
logic HCLK, HRESETn;
|
|
|
|
logic [`XLEN-1:0] PCW;
|
|
|
|
|
|
|
|
string ProgramAddrMapFile, ProgramLabelMapFile;
|
|
|
|
integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 };
|
|
|
|
|
|
|
|
logic DCacheFlushDone, DCacheFlushStart;
|
2022-06-29 19:23:40 +00:00
|
|
|
logic riscofTest;
|
2023-03-12 22:15:56 +00:00
|
|
|
logic StartSample, EndSample;
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2022-01-20 16:02:08 +00:00
|
|
|
flopenr #(`XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW);
|
2023-04-14 02:06:09 +00:00
|
|
|
flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW);
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
// check assertions for a legal configuration
|
|
|
|
riscvassertions riscvassertions();
|
|
|
|
|
|
|
|
// pick tests based on modes supported
|
|
|
|
initial begin
|
|
|
|
$display("TEST is %s", TEST);
|
2021-12-30 00:53:39 +00:00
|
|
|
//tests = '{};
|
2021-10-10 22:07:51 +00:00
|
|
|
if (`XLEN == 64) begin // RV64
|
|
|
|
case (TEST)
|
2023-04-14 02:18:26 +00:00
|
|
|
"arch64i": tests = arch64i;
|
|
|
|
"arch64priv": tests = arch64priv;
|
2021-12-30 02:25:46 +00:00
|
|
|
"arch64c": if (`C_SUPPORTED)
|
2023-04-14 02:18:26 +00:00
|
|
|
if (`ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv};
|
|
|
|
else tests = {arch64c};
|
|
|
|
"arch64m": if (`M_SUPPORTED) tests = arch64m;
|
|
|
|
"arch64f": if (`F_SUPPORTED) tests = arch64f;
|
|
|
|
"arch64d": if (`D_SUPPORTED) tests = arch64d;
|
2023-01-20 16:34:49 +00:00
|
|
|
"arch64zi": if (`ZIFENCEI_SUPPORTED) tests = arch64zi;
|
2023-04-14 02:18:26 +00:00
|
|
|
"imperas64i": tests = imperas64i;
|
|
|
|
"imperas64f": if (`F_SUPPORTED) tests = imperas64f;
|
|
|
|
"imperas64d": if (`D_SUPPORTED) tests = imperas64d;
|
|
|
|
"imperas64m": if (`M_SUPPORTED) tests = imperas64m;
|
|
|
|
"wally64a": if (`A_SUPPORTED) tests = wally64a;
|
|
|
|
"imperas64c": if (`C_SUPPORTED) tests = imperas64c;
|
|
|
|
else tests = imperas64iNOc;
|
|
|
|
"custom": tests = custom;
|
|
|
|
"wally64i": tests = wally64i;
|
|
|
|
"wally64priv": tests = wally64priv;
|
|
|
|
"wally64periph": tests = wally64periph;
|
|
|
|
"coremark": tests = coremark;
|
|
|
|
"fpga": tests = fpga;
|
|
|
|
"ahb" : tests = ahb;
|
|
|
|
"coverage64gc" : tests = coverage64gc;
|
|
|
|
"arch64zba": if (`ZBA_SUPPORTED) tests = arch64zba;
|
|
|
|
"arch64zbb": if (`ZBB_SUPPORTED) tests = arch64zbb;
|
|
|
|
"arch64zbc": if (`ZBC_SUPPORTED) tests = arch64zbc;
|
|
|
|
"arch64zbs": if (`ZBS_SUPPORTED) tests = arch64zbs;
|
2021-10-10 22:07:51 +00:00
|
|
|
endcase
|
|
|
|
end else begin // RV32
|
|
|
|
case (TEST)
|
2023-04-14 02:18:26 +00:00
|
|
|
"arch32i": tests = arch32i;
|
|
|
|
"arch32priv": tests = arch32priv;
|
2021-12-30 02:25:46 +00:00
|
|
|
"arch32c": if (`C_SUPPORTED)
|
2023-04-14 02:18:26 +00:00
|
|
|
if (`ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv};
|
|
|
|
else tests = {arch32c};
|
|
|
|
"arch32m": if (`M_SUPPORTED) tests = arch32m;
|
|
|
|
"arch32f": if (`F_SUPPORTED) tests = arch32f;
|
|
|
|
"arch32d": if (`D_SUPPORTED) tests = arch32d;
|
2023-01-20 16:34:49 +00:00
|
|
|
"arch32zi": if (`ZIFENCEI_SUPPORTED) tests = arch32zi;
|
2023-04-14 02:18:26 +00:00
|
|
|
"imperas32i": tests = imperas32i;
|
|
|
|
"imperas32f": if (`F_SUPPORTED) tests = imperas32f;
|
|
|
|
"imperas32m": if (`M_SUPPORTED) tests = imperas32m;
|
|
|
|
"wally32a": if (`A_SUPPORTED) tests = wally32a;
|
|
|
|
"imperas32c": if (`C_SUPPORTED) tests = imperas32c;
|
|
|
|
else tests = imperas32iNOc;
|
|
|
|
"wally32i": tests = wally32i;
|
|
|
|
"wally32e": tests = wally32e;
|
|
|
|
"wally32priv": tests = wally32priv;
|
|
|
|
"wally32periph": tests = wally32periph;
|
|
|
|
"embench": tests = embench;
|
|
|
|
"coremark": tests = coremark;
|
|
|
|
"arch32zba": if (`ZBA_SUPPORTED) tests = arch32zba;
|
|
|
|
"arch32zbb": if (`ZBB_SUPPORTED) tests = arch32zbb;
|
|
|
|
"arch32zbc": if (`ZBC_SUPPORTED) tests = arch32zbc;
|
|
|
|
"arch32zbs": if (`ZBS_SUPPORTED) tests = arch32zbs;
|
2021-10-10 22:07:51 +00:00
|
|
|
endcase
|
|
|
|
end
|
2021-12-29 00:28:51 +00:00
|
|
|
if (tests.size() == 0) begin
|
2021-10-10 22:07:51 +00:00
|
|
|
$display("TEST %s not supported in this configuration", TEST);
|
|
|
|
$stop;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
string signame, memfilename, pathname, objdumpfilename, adrstr, outputfile;
|
2022-06-17 22:07:16 +00:00
|
|
|
integer outputFilePointer;
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2023-03-24 23:55:43 +00:00
|
|
|
logic [31:0] GPIOIN, GPIOOUT, GPIOEN;
|
2022-08-24 18:27:18 +00:00
|
|
|
logic UARTSin, UARTSout;
|
|
|
|
|
|
|
|
logic SDCCLK;
|
|
|
|
logic SDCCmdIn;
|
|
|
|
logic SDCCmdOut;
|
|
|
|
logic SDCCmdOE;
|
|
|
|
logic [3:0] SDCDatIn;
|
2023-04-14 02:06:09 +00:00
|
|
|
tri1 [3:0] SDCDat;
|
2022-08-24 18:27:18 +00:00
|
|
|
tri1 SDCCmd;
|
|
|
|
|
|
|
|
logic HREADY;
|
|
|
|
logic HSELEXT;
|
2021-12-02 23:47:46 +00:00
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
logic InitializingMemories;
|
2023-04-14 02:07:43 +00:00
|
|
|
integer ResetCount, ResetThreshold;
|
2023-04-14 02:06:09 +00:00
|
|
|
logic InReset;
|
|
|
|
logic BeginSample;
|
2023-03-28 21:15:05 +00:00
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
// instantiate device to be tested
|
2023-03-24 23:55:43 +00:00
|
|
|
assign GPIOIN = 0;
|
2021-10-10 22:07:51 +00:00
|
|
|
assign UARTSin = 1;
|
2022-08-24 18:27:18 +00:00
|
|
|
|
|
|
|
if(`EXT_MEM_SUPPORTED) begin
|
2022-12-18 22:24:26 +00:00
|
|
|
ram_ahb #(.BASE(`EXT_MEM_BASE), .RANGE(`EXT_MEM_RANGE))
|
2022-08-24 18:27:18 +00:00
|
|
|
ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT),
|
|
|
|
.HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY,
|
|
|
|
.HWSTRB);
|
|
|
|
end else begin
|
|
|
|
assign HREADYEXT = 1;
|
|
|
|
assign HRESPEXT = 0;
|
|
|
|
assign HRDATAEXT = 0;
|
|
|
|
end
|
|
|
|
|
2022-08-24 22:49:38 +00:00
|
|
|
if(`FPGA) begin : sdcard
|
2022-08-24 18:27:18 +00:00
|
|
|
sdModel sdcard
|
|
|
|
(.sdClk(SDCCLK),
|
|
|
|
.cmd(SDCCmd),
|
|
|
|
.dat(SDCDat));
|
|
|
|
|
|
|
|
assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz;
|
|
|
|
assign SDCCmdIn = SDCCmd;
|
|
|
|
assign SDCDatIn = SDCDat;
|
|
|
|
end else begin
|
|
|
|
assign SDCCmd = '0;
|
2022-08-24 22:49:38 +00:00
|
|
|
assign SDCDat = '0;
|
2022-08-24 18:27:18 +00:00
|
|
|
end
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2021-12-14 21:43:06 +00:00
|
|
|
wallypipelinedsoc dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT,
|
2022-07-07 21:57:10 +00:00
|
|
|
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT,
|
2023-03-24 23:55:43 +00:00
|
|
|
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN,
|
2021-12-13 01:53:26 +00:00
|
|
|
.UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK);
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
// Track names of instructions
|
2022-01-20 16:02:08 +00:00
|
|
|
instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE,
|
2023-01-20 18:09:21 +00:00
|
|
|
dut.core.ifu.InstrRawF[31:0],
|
2022-01-20 16:02:08 +00:00
|
|
|
dut.core.ifu.InstrD, dut.core.ifu.InstrE,
|
|
|
|
dut.core.ifu.InstrM, InstrW,
|
2021-10-10 22:07:51 +00:00
|
|
|
InstrFName, InstrDName, InstrEName, InstrMName, InstrWName);
|
|
|
|
|
|
|
|
// initialize tests
|
2023-01-27 22:40:06 +00:00
|
|
|
localparam MemStartAddr = 0;
|
|
|
|
localparam MemEndAddr = `UNCORE_RAM_RANGE>>1+(`XLEN/32);
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
initial
|
|
|
|
begin
|
2022-12-23 02:19:09 +00:00
|
|
|
ResetCount = 0;
|
|
|
|
ResetThreshold = 2;
|
|
|
|
InReset = 1;
|
2021-10-10 22:07:51 +00:00
|
|
|
test = 1;
|
|
|
|
totalerrors = 0;
|
|
|
|
testadr = 0;
|
2022-03-30 04:48:19 +00:00
|
|
|
testadrNoBase = 0;
|
2023-04-14 02:06:09 +00:00
|
|
|
// riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests
|
|
|
|
// and tests[0] == "2" refers to WallyRiscvArchTests
|
2022-07-22 18:14:04 +00:00
|
|
|
riscofTest = tests[0] == "1" | tests[0] == "2";
|
2021-10-10 22:07:51 +00:00
|
|
|
// fill memory with defined values to reduce Xs in simulation
|
|
|
|
// Quick note the memory will need to be initialized. The C library does not
|
2023-04-14 02:06:09 +00:00
|
|
|
// guarantee the initialized reads. For example a strcmp can read 6 byte
|
|
|
|
// strings, but uses a load double to read them in. If the last 2 bytes are
|
|
|
|
// not initialized the compare results in an 'x' which propagates through
|
2021-10-10 22:07:51 +00:00
|
|
|
// the design.
|
2022-02-08 12:18:13 +00:00
|
|
|
if (TEST == "coremark")
|
|
|
|
for (i=MemStartAddr; i<MemEndAddr; i = i+1)
|
2022-08-25 15:35:24 +00:00
|
|
|
dut.uncore.uncore.ram.ram.memory.RAM[i] = 64'h0;
|
2022-02-08 12:18:13 +00:00
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
// read test vectors into memory
|
2021-11-01 15:48:46 +00:00
|
|
|
pathname = tvpaths[tests[0].atoi()];
|
2022-05-26 19:04:21 +00:00
|
|
|
/* if (tests[0] == `IMPERASTEST)
|
2023-03-03 16:42:52 +00:00
|
|
|
pathname = tvpaths[0];
|
2022-08-24 22:49:38 +00:00
|
|
|
else pathname = tvpaths[1]; */
|
2022-07-22 18:14:04 +00:00
|
|
|
if (riscofTest) memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"};
|
2023-04-14 02:06:09 +00:00
|
|
|
else memfilename = {pathname, tests[test], ".elf.memfile"};
|
2022-08-25 19:42:08 +00:00
|
|
|
if (`FPGA) begin
|
2022-08-24 22:49:38 +00:00
|
|
|
string romfilename, sdcfilename;
|
2023-02-02 22:14:11 +00:00
|
|
|
romfilename = {"../tests/custom/fpga-test-sdc/bin/fpga-test-sdc.memfile"};
|
2022-12-18 22:24:26 +00:00
|
|
|
sdcfilename = {"../testbench/sdc/ramdisk2.hex"};
|
|
|
|
$readmemh(romfilename, dut.uncore.uncore.bootrom.bootrom.memory.ROM);
|
2022-08-24 22:49:38 +00:00
|
|
|
$readmemh(sdcfilename, sdcard.sdcard.FLASHmem);
|
|
|
|
// force sdc timers
|
2022-08-25 15:35:24 +00:00
|
|
|
force dut.uncore.uncore.sdc.SDC.LimitTimers = 1;
|
2022-08-24 22:49:38 +00:00
|
|
|
end else begin
|
2023-04-14 02:06:09 +00:00
|
|
|
if (`IROM_SUPPORTED) $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
|
2023-01-29 02:35:53 +00:00
|
|
|
else if (`BUS_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
2023-04-14 02:06:09 +00:00
|
|
|
if (`DTIM_SUPPORTED) $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM);
|
2022-08-24 22:49:38 +00:00
|
|
|
end
|
2022-02-08 12:18:13 +00:00
|
|
|
|
2022-07-22 18:14:04 +00:00
|
|
|
if (riscofTest) begin
|
|
|
|
ProgramAddrMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.addr"};
|
|
|
|
ProgramLabelMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.lab"};
|
|
|
|
end else begin
|
|
|
|
ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"};
|
|
|
|
ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"};
|
|
|
|
end
|
2023-04-14 02:06:09 +00:00
|
|
|
// declare memory labels that interest us, the updateProgramAddrLabelArray task will find
|
|
|
|
// the addr of each label and fill the array. To expand, add more elements to this array
|
|
|
|
// and initialize them to zero (also initilaize them to zero at the start of the next test)
|
2022-08-24 22:49:38 +00:00
|
|
|
if(!`FPGA) begin
|
|
|
|
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray);
|
|
|
|
$display("Read memfile %s", memfilename);
|
|
|
|
end
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
// generate clock to sequence tests
|
|
|
|
always
|
|
|
|
begin
|
|
|
|
clk = 1; # 5; clk = 0; # 5;
|
2022-01-07 17:02:16 +00:00
|
|
|
// if ($time % 100000 == 0) $display("Time is %0t", $time);
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
// check results
|
2022-12-23 02:19:09 +00:00
|
|
|
assign reset_ext = InReset;
|
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
always @(negedge clk)
|
|
|
|
begin
|
2022-12-23 02:19:09 +00:00
|
|
|
InitializingMemories = 0;
|
|
|
|
if(InReset == 1) begin
|
|
|
|
// once the test inidicates it's done we need to immediately hold reset for a number of cycles.
|
|
|
|
if(ResetCount < ResetThreshold) ResetCount = ResetCount + 1;
|
|
|
|
else begin // hit reset threshold so we remove reset.
|
2023-02-17 02:10:05 +00:00
|
|
|
InReset = 0;
|
2022-12-23 02:19:09 +00:00
|
|
|
ResetCount = 0;
|
|
|
|
end
|
|
|
|
end else begin
|
2023-04-14 02:06:09 +00:00
|
|
|
if (TEST == "coremark")
|
2023-03-03 16:42:52 +00:00
|
|
|
if (dut.core.priv.priv.EcallFaultM) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
$display("Benchmark: coremark is done.");
|
|
|
|
$stop;
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
2023-04-14 02:06:09 +00:00
|
|
|
// Termination condition (i.e. we finished running current test)
|
|
|
|
if (DCacheFlushDone) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
integer begin_signature_addr;
|
|
|
|
InReset = 1;
|
|
|
|
begin_signature_addr = ProgramAddrLabelArray["begin_signature"];
|
|
|
|
if (!begin_signature_addr)
|
2023-04-14 02:18:26 +00:00
|
|
|
$display("begin_signature addr not found in %s", ProgramLabelMapFile);
|
2023-03-03 16:42:52 +00:00
|
|
|
testadr = ($unsigned(begin_signature_addr))/(`XLEN/8);
|
|
|
|
testadrNoBase = (begin_signature_addr - `UNCORE_RAM_BASE)/(`XLEN/8);
|
|
|
|
#600; // give time for instructions in pipeline to finish
|
|
|
|
if (TEST == "embench") begin
|
2023-03-22 20:00:10 +00:00
|
|
|
// Writes contents of begin_signature to .sim.output file
|
2023-04-14 02:06:09 +00:00
|
|
|
// this contains instret and cycles for start and end of test run, used by embench
|
|
|
|
// python speed script to calculate embench speed score.
|
|
|
|
// also, begin_signature contains the results of the self checking mechanism,
|
|
|
|
// which will be read by the python script for error checking
|
2023-03-22 20:00:10 +00:00
|
|
|
$display("Embench Benchmark: %s is done.", tests[test]);
|
|
|
|
if (riscofTest) outputfile = {pathname, tests[test], "/ref/ref.sim.output"};
|
|
|
|
else outputfile = {pathname, tests[test], ".sim.output"};
|
|
|
|
outputFilePointer = $fopen(outputfile);
|
|
|
|
i = 0;
|
|
|
|
while ($unsigned(i) < $unsigned(5'd5)) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
$fdisplayh(outputFilePointer, DCacheFlushFSM.ShadowRAM[testadr+i]);
|
|
|
|
i = i + 1;
|
2023-03-22 20:00:10 +00:00
|
|
|
end
|
|
|
|
$fclose(outputFilePointer);
|
|
|
|
$display("Embench Benchmark: created output file: %s", outputfile);
|
|
|
|
end else if (TEST == "coverage64gc") begin
|
|
|
|
$display("Coverage tests don't get checked");
|
2023-03-03 16:42:52 +00:00
|
|
|
end else begin
|
2023-04-14 02:06:09 +00:00
|
|
|
// 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
|
2023-03-03 16:42:52 +00:00
|
|
|
sig32[i] = 'bx;
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
|
|
|
if (riscofTest) signame = {pathname, tests[test], "/ref/Reference-sail_c_simulator.signature"};
|
|
|
|
else signame = {pathname, tests[test], ".signature.output"};
|
|
|
|
// read signature, reformat in 64 bits if necessary
|
|
|
|
$readmemh(signame, sig32);
|
|
|
|
i = 0;
|
|
|
|
while (i < SIGNATURESIZE) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
if (`XLEN == 32) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
signature[i] = sig32[i];
|
|
|
|
i = i+1;
|
2023-03-03 16:42:52 +00:00
|
|
|
end else begin
|
2023-04-14 02:06:09 +00:00
|
|
|
signature[i/2] = {sig32[i+1], sig32[i]};
|
|
|
|
i = i + 2;
|
2023-03-03 16:42:52 +00:00
|
|
|
end
|
|
|
|
if (i >= 4 & sig32[i-4] === 'bx) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
if (i == 4) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
i = SIGNATURESIZE+1; // flag empty file
|
|
|
|
$display(" Error: empty test file");
|
2023-04-14 02:06:09 +00:00
|
|
|
end else i = SIGNATURESIZE; // skip over the rest of the x's for efficiency
|
2023-03-03 16:42:52 +00:00
|
|
|
end
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
2023-03-03 16:42:52 +00:00
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
// Check errors
|
|
|
|
errors = (i == SIGNATURESIZE+1); // error if file is empty
|
|
|
|
i = 0;
|
|
|
|
/* verilator lint_off INFINITELOOP */
|
|
|
|
while (signature[i] !== 'bx) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
logic [`XLEN-1:0] sig;
|
|
|
|
if (`DTIM_SUPPORTED) sig = dut.core.lsu.dtim.dtim.ram.RAM[testadrNoBase+i];
|
|
|
|
else if (`UNCORE_RAM_SUPPORTED) sig = 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] !== DCacheFlushFSM.ShadowRAM[testadr+i])) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
errors = errors+1;
|
|
|
|
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
|
|
|
|
tests[test], i, (testadr+i)*(`XLEN/8), DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
|
|
|
|
$stop; //***debug
|
2023-03-03 16:42:52 +00:00
|
|
|
end
|
|
|
|
i = i + 1;
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
|
|
|
/* verilator lint_on INFINITELOOP */
|
|
|
|
if (errors == 0) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
$display("%s succeeded. Brilliant!!!", tests[test]);
|
2023-04-14 02:06:09 +00:00
|
|
|
end else begin
|
2023-03-03 16:42:52 +00:00
|
|
|
$display("%s failed with %d errors. :(", tests[test], errors);
|
|
|
|
totalerrors = totalerrors+1;
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
2022-06-01 21:00:44 +00:00
|
|
|
end
|
2023-03-03 16:42:52 +00:00
|
|
|
// move onto the next test, check to see if we're done
|
|
|
|
test = test + 1;
|
|
|
|
if (test == tests.size()) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
if (totalerrors == 0) $display("SUCCESS! All tests ran without failures.");
|
|
|
|
else $display("FAIL: %d test programs had errors", totalerrors);
|
|
|
|
$stop;
|
|
|
|
end else begin
|
2022-12-23 02:19:09 +00:00
|
|
|
InitializingMemories = 1;
|
2022-06-01 21:00:44 +00:00
|
|
|
// If there are still additional tests to run, read in information for the next test
|
2021-10-10 22:07:51 +00:00
|
|
|
//pathname = tvpaths[tests[0]];
|
2022-07-22 18:14:04 +00:00
|
|
|
if (riscofTest) memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"};
|
|
|
|
else memfilename = {pathname, tests[test], ".elf.memfile"};
|
2022-08-25 15:35:24 +00:00
|
|
|
//$readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
2022-08-27 03:26:12 +00:00
|
|
|
if (`IROM_SUPPORTED) $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
|
2023-04-14 02:06:09 +00:00
|
|
|
else if (`UNCORE_RAM_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
2022-08-27 03:26:12 +00:00
|
|
|
if (`DTIM_SUPPORTED) $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM);
|
2022-02-08 12:18:13 +00:00
|
|
|
|
2022-07-22 18:14:04 +00:00
|
|
|
if (riscofTest) begin
|
|
|
|
ProgramAddrMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.addr"};
|
|
|
|
ProgramLabelMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.lab"};
|
|
|
|
end else begin
|
|
|
|
ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"};
|
|
|
|
ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"};
|
|
|
|
end
|
2022-06-18 03:53:15 +00:00
|
|
|
ProgramAddrLabelArray = '{ "begin_signature" : 0, "tohost" : 0 };
|
2023-04-14 02:06:09 +00:00
|
|
|
if(!`FPGA) begin
|
2023-03-03 16:42:52 +00:00
|
|
|
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray);
|
|
|
|
$display("Read memfile %s", memfilename);
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
2022-08-24 22:49:38 +00:00
|
|
|
end
|
2023-04-14 02:06:09 +00:00
|
|
|
end // if (DCacheFlushDone)
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
|
|
|
end // always @ (negedge clk)
|
|
|
|
|
2023-01-06 00:00:11 +00:00
|
|
|
|
2023-03-03 19:10:01 +00:00
|
|
|
if(`PrintHPMCounters & `ZICOUNTERS_SUPPORTED) begin : HPMCSample
|
2023-04-14 02:06:09 +00:00
|
|
|
integer HPMCindex;
|
|
|
|
logic StartSampleFirst;
|
|
|
|
logic StartSampleDelayed, BeginDelayed;
|
|
|
|
logic EndSampleFirst, EndSampleDelayed;
|
|
|
|
logic [`XLEN-1:0] InitialHPMCOUNTERH[`COUNTERS-1:0];
|
2023-03-03 19:10:01 +00:00
|
|
|
|
2023-01-06 00:00:11 +00:00
|
|
|
string HPMCnames[] = '{"Mcycle",
|
|
|
|
"------",
|
|
|
|
"InstRet",
|
|
|
|
"Br Count",
|
2023-03-03 19:10:01 +00:00
|
|
|
"Jump Not Return",
|
2023-03-03 16:42:52 +00:00
|
|
|
"Return",
|
2023-03-03 19:10:01 +00:00
|
|
|
"BP Wrong",
|
|
|
|
"BP Dir Wrong",
|
|
|
|
"BP Target Wrong",
|
2023-01-06 00:00:11 +00:00
|
|
|
"RAS Wrong",
|
|
|
|
"Instr Class Wrong",
|
2023-04-14 02:06:09 +00:00
|
|
|
"Load Stall",
|
|
|
|
"Store Stall",
|
2023-01-06 00:00:11 +00:00
|
|
|
"D Cache Access",
|
|
|
|
"D Cache Miss",
|
2023-03-03 16:42:52 +00:00
|
|
|
"D Cache Cycles",
|
2023-01-06 00:00:11 +00:00
|
|
|
"I Cache Access",
|
2023-01-28 23:50:46 +00:00
|
|
|
"I Cache Miss",
|
2023-03-03 16:42:52 +00:00
|
|
|
"I Cache Cycles",
|
|
|
|
"CSR Write",
|
|
|
|
"FenceI",
|
|
|
|
"SFenceVMA",
|
|
|
|
"Interrupt",
|
|
|
|
"Exception",
|
|
|
|
"Divide Cycles"
|
2023-04-14 02:06:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2023-04-14 02:18:26 +00:00
|
|
|
end else if(TEST == "coremark") begin
|
2023-04-14 02:06:09 +00:00
|
|
|
// 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 = InReset;
|
|
|
|
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
|
2023-01-06 00:00:11 +00:00
|
|
|
always @(negedge clk) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
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
|
2023-03-03 19:10:01 +00:00
|
|
|
if(EndSample) begin
|
2023-01-06 00:00:11 +00:00
|
|
|
for(HPMCindex = 0; HPMCindex < HPMCnames.size(); HPMCindex += 1) begin
|
|
|
|
// unlikely to have more than 10M in any counter.
|
2023-03-03 19:10:01 +00:00
|
|
|
$display("Cnt[%2d] = %7d %s", HPMCindex, dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex] - InitialHPMCOUNTERH[HPMCindex], HPMCnames[HPMCindex]);
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-01-06 00:00:11 +00:00
|
|
|
end
|
2023-03-03 19:10:01 +00:00
|
|
|
|
|
|
|
|
2023-01-06 00:00:11 +00:00
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
// track the current function or global label
|
2023-03-03 20:59:20 +00:00
|
|
|
if (DEBUG == 1 | (`PrintHPMCounters & `ZICOUNTERS_SUPPORTED)) begin : FunctionName
|
2021-10-10 22:07:51 +00:00
|
|
|
FunctionName FunctionName(.reset(reset),
|
|
|
|
.clk(clk),
|
|
|
|
.ProgramAddrMapFile(ProgramAddrMapFile),
|
|
|
|
.ProgramLabelMapFile(ProgramLabelMapFile));
|
|
|
|
end
|
|
|
|
|
|
|
|
// Termination condition
|
2022-01-07 17:02:16 +00:00
|
|
|
// terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed
|
2021-12-25 22:39:51 +00:00
|
|
|
// or sw gp,-56(t0) for new Imperas tests
|
2022-01-07 17:02:16 +00:00
|
|
|
// or sd gp, -56(t0)
|
2021-12-25 22:39:51 +00:00
|
|
|
// or on a jump to self infinite loop (6f) for RISC-V Arch tests
|
2021-12-30 00:53:39 +00:00
|
|
|
logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls
|
2022-01-20 16:02:08 +00:00
|
|
|
if (`ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM;
|
2022-01-05 16:41:17 +00:00
|
|
|
else assign ecf = 0;
|
2022-01-02 21:47:21 +00:00
|
|
|
assign DCacheFlushStart = ecf &
|
2022-01-20 16:02:08 +00:00
|
|
|
(dut.core.ieu.dp.regf.rf[3] == 1 |
|
|
|
|
(dut.core.ieu.dp.regf.we3 &
|
|
|
|
dut.core.ieu.dp.regf.a3 == 3 &
|
|
|
|
dut.core.ieu.dp.regf.wd3 == 1)) |
|
2022-06-17 22:07:16 +00:00
|
|
|
((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) |
|
|
|
|
((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" );
|
2021-12-30 04:24:37 +00:00
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
DCacheFlushFSM DCacheFlushFSM(.clk(clk),
|
2021-12-30 04:24:37 +00:00
|
|
|
.reset(reset),
|
|
|
|
.start(DCacheFlushStart),
|
|
|
|
.done(DCacheFlushDone));
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2023-02-20 05:48:16 +00:00
|
|
|
|
2022-01-05 16:41:17 +00:00
|
|
|
// initialize the branch predictor
|
2023-03-28 21:27:54 +00:00
|
|
|
if (`BPRED_SUPPORTED) begin
|
2023-02-20 05:48:16 +00:00
|
|
|
integer adrindex;
|
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
always @(*) begin
|
|
|
|
if(reset) begin
|
|
|
|
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
|
|
|
force dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0;
|
|
|
|
end
|
|
|
|
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
|
|
|
force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0;
|
|
|
|
end
|
|
|
|
#1;
|
|
|
|
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
|
|
|
release dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex];
|
|
|
|
end
|
|
|
|
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
|
|
|
release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex];
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-03-27 23:36:02 +00:00
|
|
|
|
|
|
|
|
2023-04-04 18:38:32 +00:00
|
|
|
if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin : ICacheLogger
|
2023-03-27 23:36:02 +00:00
|
|
|
int file;
|
2023-04-12 02:29:51 +00:00
|
|
|
string LogFile;
|
|
|
|
logic resetD, resetEdge;
|
2023-04-14 02:18:26 +00:00
|
|
|
logic Enable;
|
|
|
|
logic InvalDelayed, InvalEdge;
|
2023-04-05 06:49:35 +00:00
|
|
|
|
2023-04-12 02:29:51 +00:00
|
|
|
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;
|
2023-04-14 02:06:09 +00:00
|
|
|
flop #(1) ResetDReg(clk, reset, resetD);
|
|
|
|
assign resetEdge = ~reset & resetD;
|
2023-04-12 02:29:51 +00:00
|
|
|
|
|
|
|
flop #(1) InvalReg(clk, dut.core.ifu.InvalidateICacheM, InvalDelayed);
|
2023-04-14 02:06:09 +00:00
|
|
|
assign InvalEdge = dut.core.ifu.InvalidateICacheM & ~InvalDelayed;
|
2023-04-12 02:29:51 +00:00
|
|
|
|
2023-03-27 23:36:02 +00:00
|
|
|
initial begin
|
2023-04-14 02:06:09 +00:00
|
|
|
LogFile = $psprintf("ICache.log");
|
2023-03-27 23:36:02 +00:00
|
|
|
file = $fopen(LogFile, "w");
|
2023-04-14 02:06:09 +00:00
|
|
|
$fwrite(file, "BEGIN %s\n", memfilename);
|
|
|
|
end
|
2023-04-05 04:12:35 +00:00
|
|
|
string AccessTypeString, HitMissString;
|
|
|
|
assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" :
|
|
|
|
dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M";
|
2023-03-27 23:36:02 +00:00
|
|
|
always @(posedge clk) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
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
|
2023-04-12 02:29:51 +00:00
|
|
|
if(InvalEdge) $fwrite(file, "0 I X\n");
|
2023-04-14 02:06:09 +00:00
|
|
|
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
2023-03-28 04:44:50 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-04-05 09:43:02 +00:00
|
|
|
|
2023-04-05 04:12:35 +00:00
|
|
|
if (`DCACHE_SUPPORTED && `D_CACHE_ADDR_LOGGER) begin : DCacheLogger
|
2023-03-28 04:44:50 +00:00
|
|
|
int file;
|
2023-04-14 00:00:41 +00:00
|
|
|
string LogFile;
|
|
|
|
logic resetD, resetEdge;
|
2023-04-05 04:12:35 +00:00
|
|
|
logic Enabled;
|
|
|
|
string AccessTypeString, HitMissString;
|
|
|
|
|
2023-04-14 00:00:41 +00:00
|
|
|
flop #(1) ResetDReg(clk, reset, resetD);
|
|
|
|
assign resetEdge = ~reset & resetD;
|
2023-04-05 04:12:35 +00:00
|
|
|
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";
|
2023-04-13 23:53:36 +00:00
|
|
|
|
2023-04-05 09:43:02 +00:00
|
|
|
assign Enabled = dut.core.lsu.bus.dcache.dcache.cachefsm.LRUWriteEn &
|
|
|
|
~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage &
|
2023-04-12 02:29:51 +00:00
|
|
|
dut.core.lsu.dmmu.dmmu.pmachecker.Cacheable &
|
2023-04-05 09:43:02 +00:00
|
|
|
(AccessTypeString != "NULL");
|
2023-04-05 04:12:35 +00:00
|
|
|
|
2023-03-28 04:44:50 +00:00
|
|
|
initial begin
|
2023-04-14 02:06:09 +00:00
|
|
|
LogFile = $psprintf("DCache.log");
|
2023-03-28 04:44:50 +00:00
|
|
|
file = $fopen(LogFile, "w");
|
2023-04-14 02:06:09 +00:00
|
|
|
$fwrite(file, "BEGIN %s\n", memfilename);
|
|
|
|
end
|
2023-03-28 04:44:50 +00:00
|
|
|
always @(posedge clk) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
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);
|
2023-03-27 23:36:02 +00:00
|
|
|
end
|
2023-02-20 05:48:16 +00:00
|
|
|
end
|
|
|
|
|
2023-04-04 18:38:32 +00:00
|
|
|
if (`BPRED_SUPPORTED) begin : BranchLogger
|
2023-03-03 16:42:52 +00:00
|
|
|
if (`BPRED_LOGGER) begin
|
|
|
|
string direction;
|
|
|
|
int file;
|
2023-04-14 02:06:09 +00:00
|
|
|
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;
|
2023-03-03 16:42:52 +00:00
|
|
|
initial begin
|
2023-04-14 02:06:09 +00:00
|
|
|
LogFile = $psprintf("branch_%s%0d.log", `BPRED_TYPE, `BPRED_SIZE);
|
2023-03-12 22:58:36 +00:00
|
|
|
file = $fopen(LogFile, "w");
|
2023-04-14 02:06:09 +00:00
|
|
|
end
|
2023-03-03 16:42:52 +00:00
|
|
|
always @(posedge clk) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
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
|
2022-05-17 01:03:09 +00:00
|
|
|
end
|
2023-03-03 16:42:52 +00:00
|
|
|
end
|
2022-12-21 15:18:00 +00:00
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
// check for hang up.
|
2022-12-21 15:18:00 +00:00
|
|
|
logic [`XLEN-1:0] OldPCW;
|
2023-04-14 02:06:09 +00:00
|
|
|
integer WatchDogTimerCount;
|
|
|
|
localparam WatchDogTimerThreshold = 1000000;
|
|
|
|
logic WatchDogTimeOut;
|
2022-12-21 15:18:00 +00:00
|
|
|
always_ff @(posedge clk) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
OldPCW <= PCW;
|
|
|
|
if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1;
|
|
|
|
else WatchDogTimerCount = '0;
|
2022-12-21 15:18:00 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
always_comb begin
|
2023-04-14 02:06:09 +00:00
|
|
|
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
|
2022-12-21 15:18:00 +00:00
|
|
|
end
|
|
|
|
|
2021-10-10 22:07:51 +00:00
|
|
|
endmodule
|
|
|
|
|
|
|
|
/* verilator lint_on STMTDLY */
|
|
|
|
/* verilator lint_on WIDTH */
|
|
|
|
|
|
|
|
module DCacheFlushFSM
|
|
|
|
(input logic clk,
|
|
|
|
input logic reset,
|
|
|
|
input logic start,
|
|
|
|
output logic done);
|
|
|
|
|
|
|
|
genvar adr;
|
|
|
|
|
2022-08-24 23:09:07 +00:00
|
|
|
logic [`XLEN-1:0] ShadowRAM[`UNCORE_RAM_BASE>>(1+`XLEN/32):(`UNCORE_RAM_RANGE+`UNCORE_RAM_BASE)>>1+(`XLEN/32)];
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2023-04-14 02:06:09 +00:00
|
|
|
if(`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/`XLEN;
|
|
|
|
localparam lognumlines = $clog2(numlines);
|
|
|
|
localparam loglinebytelen = $clog2(linebytelen);
|
|
|
|
localparam lognumways = $clog2(numways);
|
|
|
|
localparam tagstart = lognumlines + loglinebytelen;
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-04-14 02:18:26 +00:00
|
|
|
genvar index, way, cacheWord;
|
|
|
|
logic [sramlen-1:0] CacheData [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
2023-04-14 02:06:09 +00:00
|
|
|
logic [sramlen-1:0] cacheline;
|
2023-04-14 02:18:26 +00:00
|
|
|
logic [`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 [`PA_BITS-1:0] CacheAdr [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
2022-05-26 19:04:21 +00:00
|
|
|
for(index = 0; index < numlines; index++) begin
|
2023-04-14 02:06:09 +00:00
|
|
|
for(way = 0; way < numways; way++) begin
|
|
|
|
for(cacheWord = 0; cacheWord < cachesramwords; cacheWord++) begin
|
|
|
|
copyShadow #(.tagstart(tagstart),
|
|
|
|
.loglinebytelen(loglinebytelen), .sramlen(sramlen))
|
|
|
|
copyShadow(.clk,
|
2022-05-26 19:04:21 +00:00
|
|
|
.start,
|
2022-11-30 16:40:48 +00:00
|
|
|
.tag(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][`PA_BITS-1-tagstart:0]),
|
2022-05-26 19:04:21 +00:00
|
|
|
.valid(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].ValidBits[index]),
|
2022-11-30 17:01:25 +00:00
|
|
|
.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]),
|
2022-11-30 16:40:48 +00:00
|
|
|
//.dirty(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][`PA_BITS+tagstart]),
|
2023-04-05 05:21:06 +00:00
|
|
|
.data(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].word[cacheWord].wordram.CacheDataMem.RAM[index]),
|
2022-05-26 19:04:21 +00:00
|
|
|
.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
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
2022-05-26 19:04:21 +00:00
|
|
|
end
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2022-07-18 02:05:31 +00:00
|
|
|
integer i, j, k, l;
|
2022-05-26 19:04:21 +00:00
|
|
|
|
|
|
|
always @(posedge clk) begin
|
|
|
|
if (start) begin #1
|
|
|
|
#1
|
|
|
|
for(i = 0; i < numlines; i++) begin
|
|
|
|
for(j = 0; j < numways; j++) begin
|
2022-07-18 02:05:31 +00:00
|
|
|
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(`XLEN/8)] = cacheline[`XLEN*(k+1)-1:`XLEN*k];
|
|
|
|
ShadowRAM[(CacheAdr[j][i][l] >> $clog2(`XLEN/8)) + k] = CacheData[j][i][l][`XLEN*k +: `XLEN];
|
|
|
|
end
|
|
|
|
end
|
2022-05-26 19:04:21 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-01-05 16:41:17 +00:00
|
|
|
flop #(1) doneReg(.clk, .d(start), .q(done));
|
2021-10-10 22:07:51 +00:00
|
|
|
endmodule
|
|
|
|
|
|
|
|
module copyShadow
|
2022-07-18 02:05:31 +00:00
|
|
|
#(parameter tagstart, loglinebytelen, sramlen)
|
2023-04-14 02:06:09 +00:00
|
|
|
(input logic clk,
|
|
|
|
input logic start,
|
|
|
|
input logic [`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 [`PA_BITS-1:0] CacheAdr,
|
|
|
|
output logic [`XLEN-1:0] CacheTag,
|
|
|
|
output logic CacheValid,
|
|
|
|
output logic CacheDirty);
|
2021-10-10 22:07:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
always_ff @(posedge clk) begin
|
|
|
|
if(start) begin
|
|
|
|
CacheTag = tag;
|
|
|
|
CacheValid = valid;
|
|
|
|
CacheDirty = dirty;
|
|
|
|
CacheData = data;
|
2022-07-18 02:05:31 +00:00
|
|
|
CacheAdr = (tag << tagstart) + (index << loglinebytelen) + (cacheWord << $clog2(sramlen/8));
|
2021-10-10 22:07:51 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-17 22:07:16 +00:00
|
|
|
endmodule
|
2021-10-10 22:07:51 +00:00
|
|
|
|
2022-06-17 22:07:16 +00:00
|
|
|
task automatic updateProgramAddrLabelArray;
|
|
|
|
input string ProgramAddrMapFile, ProgramLabelMapFile;
|
|
|
|
inout integer ProgramAddrLabelArray [string];
|
|
|
|
// Gets the memory location of begin_signature
|
|
|
|
integer ProgramLabelMapFP, ProgramAddrMapFP;
|
|
|
|
ProgramLabelMapFP = $fopen(ProgramLabelMapFile, "r");
|
|
|
|
ProgramAddrMapFP = $fopen(ProgramAddrMapFile, "r");
|
|
|
|
|
|
|
|
if (ProgramLabelMapFP & ProgramAddrMapFP) begin // check we found both files
|
|
|
|
while (!$feof(ProgramLabelMapFP)) begin
|
|
|
|
string label, adrstr;
|
|
|
|
integer returncode;
|
|
|
|
returncode = $fscanf(ProgramLabelMapFP, "%s\n", label);
|
|
|
|
returncode = $fscanf(ProgramAddrMapFP, "%s\n", adrstr);
|
2023-04-14 02:06:09 +00:00
|
|
|
if (ProgramAddrLabelArray.exists(label)) ProgramAddrLabelArray[label] = adrstr.atohex();
|
2022-06-17 22:07:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
$fclose(ProgramLabelMapFP);
|
|
|
|
$fclose(ProgramAddrMapFP);
|
2022-07-17 21:20:04 +00:00
|
|
|
endtask
|
2023-01-12 16:09:34 +00:00
|
|
|
|