cvw/testbench/testbench.sv

1035 lines
44 KiB
Systemverilog
Raw Normal View History

///////////////////////////////////////////
// testbench.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
2024-09-29 17:18:04 +00:00
// Modified:
//
// Purpose: Wally Testbench and helper modules
2024-09-29 17:18:04 +00:00
// Applies test programs from the riscv-arch-test and other custom tests
//
// A component of the Wally configurable RISC-V project.
2024-09-29 17:18:04 +00:00
//
// 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
//
2024-09-29 17:18:04 +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
2023-02-04 16:19:20 +00:00
// may obtain a copy of the License at
//
2023-02-04 16:19:20 +00:00
// https://solderpad.org/licenses/SHL-2.1/
//
2024-09-29 17:18:04 +00:00
// 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
2023-02-04 16:19:20 +00:00
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
`include "config.vh"
`include "tests.vh"
`include "BranchPredictorType.vh"
`ifdef USE_IMPERAS_DV
`include "idv/idv.svh"
`endif
import cvw::*;
module testbench;
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off WIDTHEXPAND */
parameter DEBUG=0;
parameter PrintHPMCounters=0;
2023-12-20 20:55:37 +00:00
parameter BPRED_LOGGER=0;
parameter I_CACHE_ADDR_LOGGER=0;
parameter D_CACHE_ADDR_LOGGER=0;
parameter RVVI_SYNTH_SUPPORTED=0;
2024-12-02 21:52:44 +00:00
parameter MAKE_VCD=0;
2024-09-29 17:18:04 +00:00
2024-12-19 22:09:42 +00:00
// TREK Requires a license for the Breker tool. See tests/breker/README.md for details
2024-11-27 08:13:17 +00:00
`ifdef USE_TREK_DV
event trek_start;
always @(testbench.trek_start) begin
trek_uvm_pkg::trek_uvm_events::do_backdoor_init();
end
`endif
`ifdef USE_IMPERAS_DV
import idvPkg::*;
import rvviApiPkg::*;
import idvApiPkg::*;
`endif
2024-04-21 15:38:13 +00:00
`ifdef VERILATOR
import "DPI-C" function string getenvval(input string env_name);
2024-07-23 08:58:19 +00:00
string RISCV_DIR = getenvval("RISCV");
string WALLY_DIR = getenvval("WALLY"); // ~/cvw typical
`elsif VCS
2024-05-08 11:25:03 +00:00
import "DPI-C" function string getenv(input string env_name);
2024-07-23 08:58:19 +00:00
string RISCV_DIR = getenv("RISCV");
2024-09-29 17:18:04 +00:00
string WALLY_DIR = getenv("WALLY");
2024-04-21 15:38:13 +00:00
`else
2024-07-23 08:58:19 +00:00
string RISCV_DIR = "$RISCV";
string WALLY_DIR = "$WALLY";
2024-04-21 15:38:13 +00:00
`endif
`include "parameter-defs.vh"
logic clk;
2021-10-25 17:05:41 +00:00
logic reset_ext, reset;
2023-06-12 19:06:17 +00:00
logic ResetMem;
2024-04-06 18:11:22 +00:00
// Variables that can be overwritten with $value$plusargs at start of simulation
string TEST, ElfFile;
2024-04-06 18:11:22 +00:00
integer INSTR_LIMIT;
// DUT signals
logic [P.AHBW-1:0] HRDATAEXT;
2024-09-29 17:18:04 +00:00
logic HREADYEXT, HRESPEXT;
logic [P.PA_BITS-1:0] HADDR;
logic [P.AHBW-1:0] HWDATA;
logic [P.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 [31:0] GPIOIN, GPIOOUT, GPIOEN;
logic UARTSin, UARTSout;
2023-11-01 17:14:15 +00:00
logic SPIIn, SPIOut;
logic [3:0] SPICS;
logic SPICLK;
logic SDCCmd;
logic SDCIn;
logic [3:0] SDCCS;
2024-09-29 17:18:04 +00:00
logic SDCCLK;
logic HREADY;
logic HSELEXT;
2024-09-29 17:18:04 +00:00
2023-04-14 02:06:09 +00:00
string ProgramAddrMapFile, ProgramLabelMapFile;
integer ProgramAddrLabelArray [string];
2023-04-14 02:06:09 +00:00
int test, i, errors, totalerrors;
string outputfile;
integer outputFilePointer;
2023-04-14 02:06:09 +00:00
string tests[];
2023-04-14 02:06:09 +00:00
logic DCacheFlushDone, DCacheFlushStart;
2024-09-29 17:18:04 +00:00
logic riscofTest;
2023-06-14 17:11:55 +00:00
logic Validate;
logic SelectTest;
logic TestComplete;
logic PrevPCZero;
logic RVVIStall;
initial begin
2024-04-06 18:11:22 +00:00
// look for arguments passed to simulation, or use defaults
if (!$value$plusargs("TEST=%s", TEST))
TEST = "none";
if (!$value$plusargs("ElfFile=%s", ElfFile))
ElfFile = "none";
2024-04-06 18:11:22 +00:00
if (!$value$plusargs("INSTR_LIMIT=%d", INSTR_LIMIT))
INSTR_LIMIT = 0;
//$display("TEST = %s ElfFile = %s", TEST, ElfFile);
2024-09-29 17:18:04 +00:00
2024-04-06 18:11:22 +00:00
// pick tests based on modes supported
2021-12-30 00:53:39 +00:00
//tests = '{};
if (P.XLEN == 64) begin // RV64
case (TEST)
"arch64i": tests = arch64i;
"arch64priv": tests = arch64priv;
2024-09-29 17:18:04 +00:00
"arch64c": if (P.ZCA_SUPPORTED)
if (P.ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv};
else tests = {arch64c};
"arch64m": if (P.M_SUPPORTED) tests = arch64m;
"arch64a_amo": if (P.ZAAMO_SUPPORTED) tests = arch64a_amo;
"arch64f": if (P.F_SUPPORTED) tests = arch64f;
2024-09-29 17:18:04 +00:00
"arch64d": if (P.D_SUPPORTED) tests = arch64d;
2023-12-19 21:24:11 +00:00
"arch64f_fma": if (P.F_SUPPORTED) tests = arch64f_fma;
2024-09-29 17:18:04 +00:00
"arch64d_fma": if (P.D_SUPPORTED) tests = arch64d_fma;
"arch64f_divsqrt": if (P.F_SUPPORTED) tests = arch64f_divsqrt;
2024-09-29 17:18:04 +00:00
"arch64d_divsqrt": if (P.D_SUPPORTED) tests = arch64d_divsqrt;
2023-12-19 21:24:11 +00:00
"arch64zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch64zifencei;
2024-01-11 15:37:15 +00:00
"arch64zicond": if (P.ZICOND_SUPPORTED) tests = arch64zicond;
"wally64q": if (P.Q_SUPPORTED) tests = wally64q;
"wally64a_lrsc": if (P.ZALRSC_SUPPORTED) tests = wally64a_lrsc;
"custom": tests = custom;
"wally64priv": tests = wally64priv;
"wally64periph": tests = wally64periph;
"coremark": tests = coremark;
"fpga": tests = fpga;
"ahb64" : tests = ahb64;
"coverage64gc" : tests = coverage64gc;
"arch64zba": if (P.ZBA_SUPPORTED) tests = arch64zba;
"arch64zbb": if (P.ZBB_SUPPORTED) tests = arch64zbb;
"arch64zbc": if (P.ZBC_SUPPORTED) tests = arch64zbc;
"arch64zbs": if (P.ZBS_SUPPORTED) tests = arch64zbs;
2023-12-19 21:24:11 +00:00
"arch64zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch64zicboz;
"arch64zcb": if (P.ZCB_SUPPORTED) tests = arch64zcb;
"arch64zfh": if (P.ZFH_SUPPORTED) tests = arch64zfh;
2024-09-29 17:18:04 +00:00
"arch64zfh_fma": if (P.ZFH_SUPPORTED) tests = arch64zfh_fma;
"arch64zfh_divsqrt": if (P.ZFH_SUPPORTED) tests = arch64zfh_divsqrt;
2024-01-17 01:27:40 +00:00
"arch64zfaf": if (P.ZFA_SUPPORTED) tests = arch64zfaf;
"arch64zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch64zfad;
"buildroot": tests = buildroot;
2024-02-28 23:05:08 +00:00
"arch64zbkb": if (P.ZBKB_SUPPORTED) tests = arch64zbkb;
"arch64zbkc": if (P.ZBKC_SUPPORTED) tests = arch64zbkc;
"arch64zbkx": if (P.ZBKX_SUPPORTED) tests = arch64zbkx;
"arch64zknd": if (P.ZKND_SUPPORTED) tests = arch64zknd;
"arch64zkne": if (P.ZKNE_SUPPORTED) tests = arch64zkne;
"arch64zknh": if (P.ZKNH_SUPPORTED) tests = arch64zknh;
"arch64pmp": if (P.PMP_ENTRIES > 0) tests = arch64pmp;
2024-09-29 17:18:04 +00:00
endcase
end else begin // RV32
case (TEST)
2024-09-29 17:18:04 +00:00
"arch32e": tests = arch32e;
"arch32i": tests = arch32i;
"arch32priv": tests = arch32priv;
2024-09-29 17:18:04 +00:00
"arch32c": if (P.C_SUPPORTED)
if (P.ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv};
else tests = {arch32c};
"arch32m": if (P.M_SUPPORTED) tests = arch32m;
2024-09-29 17:18:04 +00:00
"arch32a_amo": if (P.ZAAMO_SUPPORTED) tests = arch32a_amo;
"arch32f": if (P.F_SUPPORTED) tests = arch32f;
"arch32d": if (P.D_SUPPORTED) tests = arch32d;
2023-12-19 21:24:11 +00:00
"arch32f_fma": if (P.F_SUPPORTED) tests = arch32f_fma;
"arch32d_fma": if (P.D_SUPPORTED) tests = arch32d_fma;
"arch32f_divsqrt": if (P.F_SUPPORTED) tests = arch32f_divsqrt;
2024-09-29 17:18:04 +00:00
"arch32d_divsqrt": if (P.D_SUPPORTED) tests = arch32d_divsqrt;
2023-12-19 21:24:11 +00:00
"arch32zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch32zifencei;
2024-01-11 15:37:15 +00:00
"arch32zicond": if (P.ZICOND_SUPPORTED) tests = arch32zicond;
2024-09-29 17:18:04 +00:00
"wally32a_lrsc": if (P.ZALRSC_SUPPORTED) tests = wally32a_lrsc;
"wally32priv": tests = wally32priv;
"wally32periph": tests = wally32periph;
"ahb32" : tests = ahb32;
"embench": tests = embench;
"coremark": tests = coremark;
"arch32zba": if (P.ZBA_SUPPORTED) tests = arch32zba;
"arch32zbb": if (P.ZBB_SUPPORTED) tests = arch32zbb;
"arch32zbc": if (P.ZBC_SUPPORTED) tests = arch32zbc;
"arch32zbs": if (P.ZBS_SUPPORTED) tests = arch32zbs;
2023-12-19 21:24:11 +00:00
"arch32zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch32zicboz;
"arch32zcb": if (P.ZCB_SUPPORTED) tests = arch32zcb;
"arch32zfh": if (P.ZFH_SUPPORTED) tests = arch32zfh;
2024-09-29 17:18:04 +00:00
"arch32zfh_fma": if (P.ZFH_SUPPORTED) tests = arch32zfh_fma;
"arch32zfh_divsqrt": if (P.ZFH_SUPPORTED) tests = arch32zfh_divsqrt;
"arch32zfaf": if (P.ZFA_SUPPORTED) tests = arch32zfaf;
2024-01-17 01:27:40 +00:00
"arch32zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch32zfad;
2024-02-28 23:05:08 +00:00
"arch32zbkb": if (P.ZBKB_SUPPORTED) tests = arch32zbkb;
"arch32zbkc": if (P.ZBKC_SUPPORTED) tests = arch32zbkc;
"arch32zbkx": if (P.ZBKX_SUPPORTED) tests = arch32zbkx;
"arch32zknd": if (P.ZKND_SUPPORTED) tests = arch32zknd;
"arch32zkne": if (P.ZKNE_SUPPORTED) tests = arch32zkne;
"arch32zknh": if (P.ZKNH_SUPPORTED) tests = arch32zknh;
"arch32pmp": if (P.PMP_ENTRIES > 0) tests = arch32pmp;
"arch32vm_sv32": if (P.VIRTMEM_SUPPORTED) tests = arch32vm_sv32;
endcase
end
if (tests.size() == 0 & ElfFile == "none") begin
if (tests.size() == 0) begin
$display("TEST %s not supported in this configuration", TEST);
end else if(ElfFile == "none") begin
$display("ElfFile %s not found", ElfFile);
end
2024-02-05 02:56:40 +00:00
$finish;
end
2024-12-02 21:52:44 +00:00
if (MAKE_VCD) begin
$dumpfile("testbench.vcd");
$dumpvars;
end
2023-06-12 19:06:17 +00:00
end // initial begin
// Model the testbench as an fsm.
// Do this in parts so it easier to verify
// part 1: build a version which echos the same behavior as the below code, but does not drive anything
// part 2: drive some of the controls
// part 3: drive all logic and remove old inital and always @ negedge clk block
typedef enum logic [3:0]{STATE_TESTBENCH_RESET,
STATE_INIT_TEST,
2023-06-12 19:06:17 +00:00
STATE_RESET_MEMORIES,
STATE_RESET_MEMORIES2,
2023-06-12 19:06:17 +00:00
STATE_LOAD_MEMORIES,
STATE_RESET_TEST,
STATE_RUN_TEST,
STATE_COPY_RAM,
STATE_CHECK_TEST,
STATE_CHECK_TEST_WAIT,
STATE_VALIDATE,
STATE_INCR_TEST} statetype;
2023-06-12 19:06:17 +00:00
statetype CurrState, NextState;
logic TestBenchReset;
logic [2:0] ResetCount, ResetThreshold;
logic LoadMem;
logic ResetCntEn;
logic ResetCntRst;
2023-12-20 19:16:32 +00:00
logic CopyRAM;
2024-05-16 20:29:12 +00:00
string signame, elffilename, memfilename, bootmemfilename, uartoutfilename, pathname;
2023-12-20 20:55:37 +00:00
integer begin_signature_addr, end_signature_addr, signature_size;
integer uartoutfile;
2023-06-12 19:06:17 +00:00
assign ResetThreshold = 3'd5;
initial begin
2024-04-21 05:52:08 +00:00
TestBenchReset = 1'b1;
2023-06-12 19:06:17 +00:00
# 100;
2024-04-21 05:52:08 +00:00
TestBenchReset = 1'b0;
end
2023-06-14 17:11:55 +00:00
always_ff @(posedge clk)
if (TestBenchReset) CurrState <= STATE_TESTBENCH_RESET;
2024-09-29 17:18:04 +00:00
else CurrState <= NextState;
2023-06-15 19:57:05 +00:00
// fsm next state logic
2023-06-12 19:06:17 +00:00
always_comb begin
2024-09-29 17:18:04 +00:00
// riscof tests have a different signature, tests[0] == "0" refers to RiscvArchTests
// and tests[0] == "1" refers to WallyRiscvArchTests
riscofTest = tests[0] == "0" | tests[0] == "1";
pathname = tvpaths[tests[0].atoi()];
case(CurrState)
2023-06-15 19:57:05 +00:00
STATE_TESTBENCH_RESET: NextState = STATE_INIT_TEST;
STATE_INIT_TEST: NextState = STATE_RESET_MEMORIES;
STATE_RESET_MEMORIES: NextState = STATE_RESET_MEMORIES2;
STATE_RESET_MEMORIES2: NextState = STATE_LOAD_MEMORIES; // Give the reset enough time to ensure the bus is reset before loading the memories.
STATE_LOAD_MEMORIES: NextState = STATE_RESET_TEST;
STATE_RESET_TEST: if(ResetCount < ResetThreshold) NextState = STATE_RESET_TEST;
else NextState = STATE_RUN_TEST;
STATE_RUN_TEST: if(TestComplete) NextState = STATE_COPY_RAM;
2023-06-15 19:57:05 +00:00
else NextState = STATE_RUN_TEST;
STATE_COPY_RAM: NextState = STATE_CHECK_TEST;
2023-06-15 19:57:05 +00:00
STATE_CHECK_TEST: if (DCacheFlushDone) NextState = STATE_VALIDATE;
else NextState = STATE_CHECK_TEST_WAIT;
STATE_CHECK_TEST_WAIT: if(DCacheFlushDone) NextState = STATE_VALIDATE;
else NextState = STATE_CHECK_TEST_WAIT;
STATE_VALIDATE: NextState = STATE_INIT_TEST;
STATE_INCR_TEST: NextState = STATE_INIT_TEST;
default: NextState = STATE_TESTBENCH_RESET;
2023-06-12 19:06:17 +00:00
endcase
end // always_comb
2024-09-29 17:18:04 +00:00
// fsm output control logic
assign reset_ext = CurrState == STATE_TESTBENCH_RESET | CurrState == STATE_INIT_TEST |
CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2 |
2023-06-15 19:57:05 +00:00
CurrState == STATE_LOAD_MEMORIES | CurrState ==STATE_RESET_TEST;
2024-09-29 17:18:04 +00:00
// this initialization is very expensive, only do it for coremark.
2023-06-15 19:57:05 +00:00
assign ResetMem = (CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2) & TEST == "coremark";
assign LoadMem = CurrState == STATE_LOAD_MEMORIES;
assign ResetCntRst = CurrState == STATE_INIT_TEST;
assign ResetCntEn = CurrState == STATE_RESET_TEST;
assign Validate = CurrState == STATE_VALIDATE;
assign SelectTest = CurrState == STATE_INIT_TEST;
assign CopyRAM = TestComplete & CurrState == STATE_RUN_TEST;
assign DCacheFlushStart = CurrState == STATE_COPY_RAM;
2023-06-15 19:57:05 +00:00
// fsm reset counter
counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCount);
2023-06-12 19:06:17 +00:00
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Find the test vector files and populate the PC to function label converter
////////////////////////////////////////////////////////////////////////////////
logic [P.XLEN-1:0] testadr;
2024-05-07 17:41:02 +00:00
//VCS ignores the dynamic types while processing the implicit sensitivity lists of always @*, always_comb, and always_latch
//procedural blocks. VCS supports the dynamic types in the implicit sensitivity list of always @* block as specified in the Section 9.2 of the IEEE Standard SystemVerilog Specification 1800-2012.
//To support memory load and dump task verbosity: flag : -diag sys_task_mem
always @(*) begin
2024-04-03 17:39:02 +00:00
begin_signature_addr = ProgramAddrLabelArray["begin_signature"];
2024-05-07 17:41:02 +00:00
end_signature_addr = ProgramAddrLabelArray["sig_end_canary"];
2024-04-03 17:39:02 +00:00
signature_size = end_signature_addr - begin_signature_addr;
end
logic EcallFaultM;
if (P.ZICSR_SUPPORTED)
assign EcallFaultM = dut.core.priv.priv.EcallFaultM;
else
assign EcallFaultM = 0;
2024-09-29 17:18:04 +00:00
2023-06-14 17:11:55 +00:00
always @(posedge clk) begin
////////////////////////////////////////////////////////////////////////////////
// Verify the test ran correctly by checking the memory against a known signature.
////////////////////////////////////////////////////////////////////////////////
if(TestBenchReset) test = 1;
if (P.ZICSR_SUPPORTED & TEST == "coremark")
if (EcallFaultM) begin
$display("Benchmark: coremark is done.");
$stop;
end
2023-06-14 17:11:55 +00:00
if(SelectTest) begin
2024-09-29 17:18:04 +00:00
if (riscofTest) begin
memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"};
2024-05-16 20:29:12 +00:00
elffilename = {pathname, tests[test], "ref/ref.elf"};
ProgramAddrMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.addr"};
ProgramLabelMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.lab"};
2024-09-29 17:18:04 +00:00
end else if(TEST == "buildroot") begin
memfilename = {RISCV_DIR, "/linux-testvectors/ram.bin"};
2024-05-16 20:29:12 +00:00
elffilename = "buildroot";
bootmemfilename = {RISCV_DIR, "/linux-testvectors/bootmem.bin"};
uartoutfilename = {"logs/", TEST, "_uart.out"};
uartoutfile = $fopen(uartoutfilename, "w"); // delete UART output file
ProgramAddrMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.addr"};
ProgramLabelMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.lab"};
end else if(TEST == "fpga") begin
bootmemfilename = {WALLY_DIR, "/fpga/src/boot.mem"};
memfilename = {WALLY_DIR, "/fpga/src/data.mem"};
ProgramAddrMapFile = {WALLY_DIR, "/fpga/zsbl/bin/boot.objdump.addr"};
ProgramLabelMapFile = {WALLY_DIR, "/fpga/zsbl/bin/boot.objdump.lab"};
end else if(ElfFile != "none") begin
2024-05-16 20:29:12 +00:00
elffilename = ElfFile;
memfilename = {ElfFile, ".memfile"};
ProgramAddrMapFile = {ElfFile, ".objdump.addr"};
ProgramLabelMapFile = {ElfFile, ".objdump.lab"};
2023-06-14 17:11:55 +00:00
end else begin
2024-05-16 20:29:12 +00:00
elffilename = {pathname, tests[test], ".elf"};
memfilename = {pathname, tests[test], ".elf.memfile"};
2023-06-14 17:11:55 +00:00
ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"};
ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"};
end
2024-09-29 17:18:04 +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
2023-06-14 17:11:55 +00:00
// and initialize them to zero (also initilaize them to zero at the start of the next test)
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, memfilename, WALLY_DIR, ProgramAddrLabelArray);
2023-06-14 17:11:55 +00:00
end
if(Validate) begin
if (PrevPCZero) totalerrors = totalerrors + 1; // error if PC is stuck at zero
if (TEST == "buildroot")
$fclose(uartoutfile);
2023-06-15 19:57:05 +00:00
if (TEST == "embench") begin
2023-06-14 17:23:26 +00:00
// Writes contents of begin_signature to .sim.output file
2024-09-29 17:18:04 +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,
2023-06-14 17:23:26 +00:00
// which will be read by the python script for error checking
$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, "w");
i = 0;
testadr = ($unsigned(begin_signature_addr))/(P.XLEN/8);
while ($unsigned(i) < $unsigned(5'd5)) begin
$fdisplayh(outputFilePointer, DCacheFlushFSM.ShadowRAM[testadr+i]);
i = i + 1;
end
2023-06-14 17:23:26 +00:00
$fclose(outputFilePointer);
$display("Embench Benchmark: created output file: %s", outputfile);
end else if (TEST == "coverage64gc") begin
$display("%s ran. Coverage tests don't get checked", tests[test]);
end else if (ElfFile != "none") begin
2024-12-11 19:54:39 +00:00
`ifdef USE_TREK_DV
$display("Breker test is done.");
`else
$display("Single Elf file tests are not signatured verified.");
`endif
2024-06-27 04:18:40 +00:00
`ifdef QUESTA
$stop; // if this is changed to $finish for Questa, wally-batch.do does not go to the next step to run coverage, and wally.do terminates without allowing GUI debug
`else
2024-06-27 04:18:40 +00:00
$finish;
`endif
2024-09-29 17:18:04 +00:00
end else begin
2023-06-14 17:23:26 +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
if (!begin_signature_addr)
$display("begin_signature addr not found in %s", ProgramLabelMapFile);
2024-09-29 17:18:04 +00:00
else if (TEST != "embench") begin
2024-05-07 17:41:02 +00:00
CheckSignature(pathname, tests[test], riscofTest, begin_signature_addr, errors);
if(errors > 0) totalerrors = totalerrors + 1;
end
2023-06-14 17:23:26 +00:00
end
2024-09-29 17:18:04 +00:00
test = test + 1;
2023-06-14 17:11:55 +00:00
if (test == tests.size()) begin
if (totalerrors == 0) $display("SUCCESS! All tests ran without failures.");
else $display("FAIL: %d test programs had errors", totalerrors);
2024-06-27 04:18:40 +00:00
`ifdef QUESTA
$stop; // if this is changed to $finish for Questa, wally-batch.do does not go to the next step to run coverage, and wally.do terminates without allowing GUI debug
`else
2024-06-27 04:18:40 +00:00
$finish;
`endif
2023-06-14 17:11:55 +00:00
end
end
2024-06-27 05:39:43 +00:00
end
2023-06-14 17:11:55 +00:00
2023-06-12 19:06:17 +00:00
////////////////////////////////////////////////////////////////////////////////
// load memories with program image
////////////////////////////////////////////////////////////////////////////////
2023-12-20 20:55:37 +00:00
integer ShadowIndex;
integer LogXLEN;
integer StartIndex;
integer EndIndex;
integer BaseIndex;
2024-07-08 19:48:52 +00:00
integer memFile, uncoreMemFile;
integer readResult;
if (P.SDC_SUPPORTED) begin
always @(posedge clk) begin
if (LoadMem) begin
string romfilename, sdcfilename;
romfilename = {"../tests/custom/fpga-test-sdc/bin/fpga-test-sdc.memfile"};
2024-09-29 17:18:04 +00:00
sdcfilename = {"../testbench/sdc/ramdisk2.hex"};
//$readmemh(romfilename, dut.uncoregen.uncore.bootrom.bootrom.memory.ROM);
2023-10-13 19:08:17 +00:00
//$readmemh(sdcfilename, sdcard.sdcard.FLASHmem);
// shorten sdc timers for simulation
//dut.uncoregen.uncore.sdc.SDC.LimitTimers = 1;
end
end
end else if (P.IROM_SUPPORTED) begin
always @(posedge clk) begin
if (LoadMem) begin
$readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
end
end
2023-12-20 20:55:37 +00:00
end else if (P.BUS_SUPPORTED) begin : bus_supported
always @(posedge clk) begin
if (LoadMem) begin
if (TEST == "buildroot") begin
memFile = $fopen(bootmemfilename, "rb");
2024-06-14 16:50:07 +00:00
if (memFile == 0) begin
$display("Error: Could not open file %s", memfilename);
$finish;
end
2024-07-05 16:13:18 +00:00
if (P.BOOTROM_SUPPORTED)
readResult = $fread(dut.uncoregen.uncore.bootrom.bootrom.memory.ROM, memFile);
else begin
$display("Buildroot test requires BOOTROM_SUPPORTED");
$finish;
end
$fclose(memFile);
memFile = $fopen(memfilename, "rb");
2024-06-14 16:50:07 +00:00
if (memFile == 0) begin
$display("Error: Could not open file %s", memfilename);
$finish;
end
2024-06-14 10:35:05 +00:00
readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.ram.RAM, memFile);
$fclose(memFile);
end else if (TEST == "fpga") begin
memFile = $fopen(bootmemfilename, "rb");
if (memFile == 0) begin
$display("Error: Could not open file %s", memfilename);
$finish;
end
if (P.BOOTROM_SUPPORTED) begin
readResult = $fread(dut.uncoregen.uncore.bootrom.bootrom.memory.ROM, memFile);
end
$fclose(memFile);
memFile = $fopen(memfilename, "rb");
if (memFile == 0) begin
$display("Error: Could not open file %s", memfilename);
$finish;
end
readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.ram.RAM, memFile);
$fclose(memFile);
2024-07-08 19:48:52 +00:00
end else begin
uncoreMemFile = $fopen(memfilename, "r"); // Is there a better way to test if a file exists?
if (uncoreMemFile == 0) begin
$display("Error: Could not open file %s", memfilename);
$finish;
end else begin
$fclose(uncoreMemFile);
$readmemh(memfilename, dut.uncoregen.uncore.ram.ram.memory.ram.RAM);
2024-11-27 08:13:17 +00:00
`ifdef USE_TREK_DV
-> trek_start;
$display("starting Trek....");
`endif
2024-07-08 19:48:52 +00:00
end
end
if (TEST == "embench") $display("Read memfile %s", memfilename);
end
if (CopyRAM) begin
2023-12-20 20:55:37 +00:00
LogXLEN = (1 + P.XLEN/32); // 2 for rv32 and 3 for rv64
StartIndex = begin_signature_addr >> LogXLEN;
EndIndex = (end_signature_addr >> LogXLEN) + 8;
BaseIndex = P.UNCORE_RAM_BASE >> LogXLEN;
for(ShadowIndex = StartIndex; ShadowIndex <= EndIndex; ShadowIndex++) begin
2024-06-14 10:35:05 +00:00
testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.uncoregen.uncore.ram.ram.memory.ram.RAM[ShadowIndex - BaseIndex];
end
end
end
2024-09-29 17:18:04 +00:00
end
if (P.DTIM_SUPPORTED) begin
always @(posedge clk) begin
if (LoadMem) begin
2024-06-14 10:35:05 +00:00
$readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.ram.RAM);
end
if (CopyRAM) begin
2023-12-20 20:55:37 +00:00
LogXLEN = (1 + P.XLEN/32); // 2 for rv32 and 3 for rv64
StartIndex = begin_signature_addr >> LogXLEN;
EndIndex = (end_signature_addr >> LogXLEN) + 8;
BaseIndex = P.UNCORE_RAM_BASE >> LogXLEN;
for(ShadowIndex = StartIndex; ShadowIndex <= EndIndex; ShadowIndex++) begin
2024-06-14 10:35:05 +00:00
testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.core.lsu.dtim.dtim.ram.ram.RAM[ShadowIndex - BaseIndex];
end
end
end
end
integer adrindex;
if (P.UNCORE_RAM_SUPPORTED)
2024-09-29 17:18:04 +00:00
always @(posedge clk)
if (ResetMem) // program memory is sometimes reset (e.g. for CoreMark, which needs zeroed memory)
2024-09-29 17:18:04 +00:00
for (adrindex=0; adrindex<(P.UNCORE_RAM_RANGE>>1+(P.XLEN/32)); adrindex = adrindex+1)
2024-06-14 10:35:05 +00:00
dut.uncoregen.uncore.ram.ram.memory.ram.RAM[adrindex] = '0;
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Actual hardware
////////////////////////////////////////////////////////////////////////////////
// instantiate device to be tested
2024-04-21 00:22:31 +00:00
assign GPIOIN = '0;
assign UARTSin = 1'b1;
assign SPIIn = 1'b0;
if(P.EXT_MEM_SUPPORTED) begin
2024-11-16 20:53:10 +00:00
ram_ahb #(.P(P), .RANGE(P.EXT_MEM_RANGE))
2024-09-29 17:18:04 +00:00
ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT),
2023-06-15 19:57:05 +00:00
.HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY, .HWSTRB);
2024-09-29 17:18:04 +00:00
end else begin
2024-04-21 00:22:31 +00:00
assign HREADYEXT = 1'b1;
assign {HRESPEXT, HRDATAEXT} = '0;
end
2023-10-13 19:08:17 +00:00
if(P.SDC_SUPPORTED) begin : sdcard
2024-06-19 20:51:37 +00:00
// JP: Add back sd card when sd card AHB implementation done
/* -----\/----- EXCLUDED -----\/-----
sdModel sdcard
(.sdClk(SDCCLK),
2024-09-29 17:18:04 +00:00
.cmd(SDCCmd),
.dat(SDCDat));
assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz;
assign SDCCmdIn = SDCCmd;
2023-10-17 19:13:18 +00:00
assign SDCDat = sd_dat_reg_t ? sd_dat_reg_o : sd_dat_i;
assign SDCDatIn = SDCDat;
2024-06-19 20:51:37 +00:00
-----/\----- EXCLUDED -----/\----- */
end else begin
assign SDCIn = 1'b1;
2024-09-29 17:18:04 +00:00
end
2024-09-29 17:18:04 +00:00
wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .ExternalStall(RVVIStall),
.HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT,
2023-06-15 19:57:05 +00:00
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN,
2024-09-29 17:18:04 +00:00
.UARTSin, .UARTSout, .SPIIn, .SPIOut, .SPICS, .SPICLK, .SDCIn, .SDCCmd, .SDCCS, .SDCCLK);
// generate clock to sequence tests
2023-06-15 19:57:05 +00:00
always begin
2024-04-21 05:52:08 +00:00
clk = 1'b1; # 5; clk = 1'b0; # 5;
end
if(RVVI_SYNTH_SUPPORTED) begin : rvvi_synth
localparam MAX_CSRS = 5;
localparam logic [31:0] RVVI_INIT_TIME_OUT = 32'd4;
localparam logic [31:0] RVVI_PACKET_DELAY = 32'd2;
logic [3:0] mii_txd;
logic mii_tx_en, mii_tx_er;
2024-09-29 17:18:04 +00:00
rvvitbwrapper #(P, MAX_CSRS, RVVI_INIT_TIME_OUT, RVVI_PACKET_DELAY)
rvvitbwrapper(.clk, .reset, .RVVIStall, .mii_tx_clk(clk), .mii_txd, .mii_tx_en, .mii_tx_er,
.mii_rx_clk(clk), .mii_rxd('0), .mii_rx_dv('0), .mii_rx_er('0));
end else begin
assign RVVIStall = '0;
end
2024-09-29 17:18:04 +00:00
/*
// Print key info each cycle for debugging
2024-09-29 17:18:04 +00:00
always @(posedge clk) begin
#2;
$display("PCM: %x InstrM: %x (%5s) WriteDataM: %x IEUResultM: %x",
dut.core.PCM, dut.core.InstrM, InstrMName, dut.core.WriteDataM, dut.core.ieu.dp.IEUResultM);
end
*/
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Support logic
////////////////////////////////////////////////////////////////////////////////
// Duplicate copy of pipeline registers that are optimized out of some configurations
logic [31:0] NextInstrE, InstrM;
mux2 #(32) FlushInstrMMux(dut.core.ifu.InstrE, dut.core.ifu.nop, dut.core.ifu.FlushM, NextInstrE);
flopenr #(32) InstrMReg(clk, reset, ~dut.core.ifu.StallM, NextInstrE, InstrM);
// Track names of instructions
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
logic [31:0] InstrW;
flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW);
instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE,
dut.core.ifu.InstrRawF[31:0],
dut.core.ifu.InstrD, dut.core.ifu.InstrE,
InstrM, InstrW,
InstrFName, InstrDName, InstrEName, InstrMName, InstrWName);
// watch for problems such as lockup, reading unitialized memory, bad configs
watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset, .TEST); // check if PCW is stuck
2024-09-29 17:18:04 +00:00
ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM,
dut.core.ifu.PCM, InstrM, dut.core.lsu.IEUAdrM, InstrMName);
2023-06-15 19:57:05 +00:00
riscvassertions #(P) riscvassertions(); // check assertions for a legal configuration
loggers #(P, PrintHPMCounters, I_CACHE_ADDR_LOGGER, D_CACHE_ADDR_LOGGER, BPRED_LOGGER)
loggers (clk, reset, DCacheFlushStart, DCacheFlushDone, memfilename, TEST);
// track the current function or global label
if (DEBUG > 0 | ((PrintHPMCounters | BPRED_LOGGER) & P.ZICNTR_SUPPORTED)) begin : FunctionName
FunctionName #(P) FunctionName(.reset(reset_ext | TestBenchReset),
.clk(clk), .ProgramAddrMapFile(ProgramAddrMapFile), .ProgramLabelMapFile(ProgramLabelMapFile));
end
// Append UART output to file for tests
if (P.UART_SUPPORTED) begin: uart_logger
always @(posedge clk) begin
if (TEST == "buildroot") begin
if (~dut.uncoregen.uncore.uartgen.uart.MEMWb & dut.uncoregen.uncore.uartgen.uart.uartPC.A == 3'b000 & ~dut.uncoregen.uncore.uartgen.uart.uartPC.DLAB) begin
$fwrite(uartoutfile, "%c", dut.uncoregen.uncore.uartgen.uart.uartPC.Din); // append characters one at a time so we see a consistent log appearing during the run
$fflush(uartoutfile);
end
end
end
end
// Termination condition
2024-09-29 17:18:04 +00:00
// Terminate on
2024-06-19 20:51:37 +00:00
// 1. jump to self loop (0x0000006f)
// 2. a store word writes to the address "tohost"
// 3. or PC is stuck at 0
always @(posedge clk) begin
// if (reset) PrevPCZero <= 0;
// else if (dut.core.InstrValidM) PrevPCZero <= (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0);
TestComplete <= ((InstrM == 32'h6f) & dut.core.InstrValidM ) |
((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"] & dut.core.lsu.IEUAdrM != 0) & InstrMName == "SW"); // |
// (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero));
// if (FunctionName.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.InstrValidM & PrevPCZero)
// $error("Program fetched illegal instruction 0x00000000 from address 0x00000000 twice in a row. Usually due to fault with no fault handler.");
2024-09-29 17:18:04 +00:00
end
2024-04-21 00:22:31 +00:00
DCacheFlushFSM #(P) DCacheFlushFSM(.clk, .start(DCacheFlushStart), .done(DCacheFlushDone));
2024-04-06 18:11:22 +00:00
if(P.ZICSR_SUPPORTED) begin
logic [P.XLEN-1:0] Minstret;
2024-09-29 17:18:04 +00:00
assign Minstret = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2];
always @(negedge clk) begin
2024-04-06 18:11:22 +00:00
if (INSTR_LIMIT > 0) begin
if((Minstret != 0) & (Minstret % 'd100000 == 0)) $display("Reached %d instructions", Minstret);
if((Minstret == INSTR_LIMIT) & (INSTR_LIMIT!=0)) begin $finish; end
2024-04-06 18:11:22 +00:00
end
end
end
////////////////////////////////////////////////////////////////////////////////
// ImperasDV Co-simulator hooks
////////////////////////////////////////////////////////////////////////////////
`ifdef USE_IMPERAS_DV
rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi();
wallyTracer #(P) wallyTracer(rvvi);
trace2log idv_trace2log(rvvi);
trace2cov idv_trace2cov(rvvi);
// enabling of comparison types
trace2api #(.CMP_PC (1),
.CMP_INS (1),
.CMP_GPR (1),
.CMP_FPR (1),
.CMP_VR (0),
.CMP_CSR (1)
) idv_trace2api(rvvi);
2024-05-16 20:29:12 +00:00
string filename;
initial begin
// imperasDV requires the elffile be defined at the begining of the simulation.
int iter;
longint x64;
int x32[2];
longint index;
string memfilenameImperasDV, bootmemfilenameImperasDV;
#1;
IDV_MAX_ERRORS = 3;
elffilename = ElfFile;
// Initialize REF (do this before initializing the DUT)
if (!rvviVersionCheck(RVVI_API_VERSION)) begin
$display($sformatf("%m @ t=%0t: Expecting RVVI API version %0d.", $time, RVVI_API_VERSION));
$fatal;
end
2024-09-29 17:18:04 +00:00
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org"));
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv"));
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GCK"));
void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, XLEN==64 ? 56 : 34));
void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6));
2024-09-29 17:18:04 +00:00
if(elffilename == "buildroot") filename = "";
2024-05-16 20:29:12 +00:00
else filename = elffilename;
// use the ImperasDV rvviRefInit to load the reference model with an elf file
if(elffilename != "none") begin
if (!rvviRefInit(filename)) begin
$display($sformatf("%m @ t=%0t: rvviRefInit failed", $time));
$fatal;
end
2024-06-14 16:50:07 +00:00
end else begin // for buildroot use the binary instead to load the reference model.
if (!rvviRefInit("")) begin // still have to call with nothing
$display($sformatf("%m @ t=%0t: rvviRefInit failed", $time));
$fatal;
2024-09-29 17:18:04 +00:00
end
memfilenameImperasDV = {RISCV_DIR, "/linux-testvectors/ram.bin"};
bootmemfilenameImperasDV = {RISCV_DIR, "/linux-testvectors/bootmem.bin"};
$display("RVVI Loading bootmem.bin");
memFile = $fopen(bootmemfilenameImperasDV, "rb");
index = 'h1000 - 8;
while(!$feof(memFile)) begin
index+=8;
readResult = $fread(x64, memFile);
if (x64 == 0) continue;
x32[0] = x64 & 'hffffffff;
x32[1] = x64 >> 32;
rvviRefMemoryWrite(0, index+0, x32[0], 4);
rvviRefMemoryWrite(0, index+4, x32[1], 4);
//$display("boot %08X x32[0]=%08X x32[1]=%08X", index, x32[0], x32[1]);
end
$fclose(memFile);
2024-09-29 17:18:04 +00:00
$display("RVVI Loading ram.bin");
memFile = $fopen(memfilenameImperasDV, "rb");
index = 'h80000000 - 8;
while(!$feof(memFile)) begin
index+=8;
readResult = $fread(x64, memFile);
if (x64 == 0) continue;
x32[0] = x64 & 'hffffffff;
x32[1] = x64 >> 32;
rvviRefMemoryWrite(0, index+0, x32[0], 4);
rvviRefMemoryWrite(0, index+4, x32[1], 4);
//$display("ram %08X x32[0]=%08X x32[1]=%08X", index, x32[0], x32[1]);
end
$fclose(memFile);
2024-09-29 17:18:04 +00:00
$display("RVVI Loading Complete");
2024-09-29 17:18:04 +00:00
void'(rvviRefPcSet(0, P.RESET_VECTOR)); // set BOOTROM address
end
// Volatile CSRs
void'(rvviRefCsrSetVolatile(0, 32'hC00)); // CYCLE
void'(rvviRefCsrSetVolatile(0, 32'hB00)); // MCYCLE
void'(rvviRefCsrSetVolatile(0, 32'hC02)); // INSTRET
void'(rvviRefCsrSetVolatile(0, 32'hB02)); // MINSTRET
void'(rvviRefCsrSetVolatile(0, 32'hC01)); // TIME
if (P.XLEN == 32) begin
void'(rvviRefCsrSetVolatile(0, 32'hC80)); // CYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hB80)); // MCYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hC82)); // INSTRETH
void'(rvviRefCsrSetVolatile(0, 32'hB82)); // MINSTRETH
2024-09-29 17:18:04 +00:00
void'(rvviRefCsrSetVolatile(0, 32'hC81)); // TIMEH
end
// User HPMCOUNTER3 - HPMCOUNTER31
for (iter='hC03; iter<='hC1F; iter++) begin
void'(rvviRefCsrSetVolatile(0, iter)); // HPMCOUNTERx
2024-09-29 17:18:04 +00:00
if (P.XLEN == 32)
void'(rvviRefCsrSetVolatile(0, iter+128)); // HPMCOUNTERxH
2024-09-29 17:18:04 +00:00
end
// Machine MHPMCOUNTER3 - MHPMCOUNTER31
for (iter='hB03; iter<='hB1F; iter++) begin
void'(rvviRefCsrSetVolatile(0, iter)); // MHPMCOUNTERx
2024-09-29 17:18:04 +00:00
if (P.XLEN == 32)
void'(rvviRefCsrSetVolatile(0, iter+128)); // MHPMCOUNTERxH
2024-09-29 17:18:04 +00:00
end
// cannot predict this register due to latency between
// pending and taken
void'(rvviRefCsrSetVolatile(0, 32'h344)); // MIP
void'(rvviRefCsrSetVolatile(0, 32'h144)); // SIP
// Privileges for PMA are set in the imperas.ic
// volatile (IO) regions are defined here
// only real ROM/RAM areas are BOOTROM and UNCORE_RAM
if (P.CLINT_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.CLINT_BASE, (P.CLINT_BASE + P.CLINT_RANGE)));
end
if (P.GPIO_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.GPIO_BASE, (P.GPIO_BASE + P.GPIO_RANGE)));
end
if (P.UART_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.UART_BASE, (P.UART_BASE + P.UART_RANGE)));
end
if (P.PLIC_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.PLIC_BASE, (P.PLIC_BASE + P.PLIC_RANGE)));
end
if (P.SDC_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.SDC_BASE, (P.SDC_BASE + P.SDC_RANGE)));
end
if (P.SPI_SUPPORTED) begin
void'(rvviRefMemorySetVolatile(P.SPI_BASE, (P.SPI_BASE + P.SPI_RANGE)));
end
if(P.XLEN==32) begin
void'(rvviRefCsrSetVolatile(0, 32'hC80)); // CYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hB80)); // MCYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hC82)); // INSTRETH
void'(rvviRefCsrSetVolatile(0, 32'hB82)); // MINSTRETH
end
void'(rvviRefCsrSetVolatile(0, 32'h104)); // SIE - Temporary!!!!
2024-09-29 17:18:04 +00:00
end
if (P.ZICSR_SUPPORTED) begin
always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));
always @(dut.core.priv.priv.csr.csri.MIP_REGW[11]) void'(rvvi.net_push("MExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[11]));
always @(dut.core.priv.priv.csr.csri.MIP_REGW[9]) void'(rvvi.net_push("SExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[9]));
always @(dut.core.priv.priv.csr.csri.MIP_REGW[3]) void'(rvvi.net_push("MSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[3]));
always @(dut.core.priv.priv.csr.csri.MIP_REGW[1]) void'(rvvi.net_push("SSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[1]));
always @(dut.core.priv.priv.csr.csri.MIP_REGW[5]) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[5]));
end
final begin
void'(rvviRefShutdown());
end
`endif
////////////////////////////////////////////////////////////////////////////////
// END of ImperasDV Co-simulator hooks
////////////////////////////////////////////////////////////////////////////////
2023-06-14 22:02:49 +00:00
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.
2024-09-29 17:18:04 +00:00
2023-06-14 22:02:49 +00:00
input string pathname;
input string TestName;
input logic riscofTest;
input integer begin_signature_addr;
output integer errors;
int fd, code;
string line;
int siglines, sigentries;
2023-06-14 22:02:49 +00:00
localparam SIGNATURESIZE = 5000000;
integer i;
logic [31:0] sig32[0:SIGNATURESIZE];
logic [31:0] parsed;
2023-06-14 22:02:49 +00:00
logic [P.XLEN-1:0] signature[0:SIGNATURESIZE];
string signame;
2023-06-14 22:02:49 +00:00
logic [P.XLEN-1:0] testadr, testadrNoBase;
2024-09-29 17:18:04 +00:00
//$display("Invoking CheckSignature %s %s %0t", pathname, TestName, $time);
// read .signature.output file and compare to check for errors
2023-06-14 22:02:49 +00:00
if (riscofTest) signame = {pathname, TestName, "/ref/Reference-sail_c_simulator.signature"};
else signame = {pathname, TestName, ".signature.output"};
// read signature file from memory and count lines. Can't use readmemh because we need the line count
// $readmemh(signame, sig32);
fd = $fopen(signame, "r");
siglines = 0;
if (fd == 0) $display("Unable to read %s", signame);
else begin
while (!$feof(fd)) begin
code = $fgets(line, fd);
if (code != 0) begin
int errno;
string errstr;
errno = $ferror(fd, errstr);
if (errno != 0) $display("Error %d (code %d) reading line %d of %s: %s", errno, code, siglines, signame, errstr);
if (line.len() > 1) begin // skip blank lines
if ($sscanf(line, "%x", parsed) != 0) begin
sig32[siglines] = parsed;
siglines = siglines + 1; // increment if line is not blank
end
end
end
2023-04-14 02:06:09 +00:00
end
$fclose(fd);
2023-03-27 23:36:02 +00:00
end
// Check valid number of lines were read
2024-09-29 17:18:04 +00:00
if (siglines == 0) begin
errors = 1;
$display("Error: empty test file %s", signame);
end else if (P.XLEN == 64 & (siglines % 2)) begin
errors = 1;
$display("Error: RV64 signature has odd number of lines %s", signame);
end else errors = 0;
// copy lines into signature, converting to XLEN if necessary
sigentries = (P.XLEN == 32) ? siglines : siglines/2; // number of signature entries
for (i=0; i<sigentries; i++) begin
signature[i] = (P.XLEN == 32) ? sig32[i] : {sig32[i*2+1], sig32[i*2]};
//$display("XLEN = %d signature[%d] = %x", P.XLEN, i, signature[i]);
end
2023-06-14 22:02:49 +00:00
// Check errors
testadr = ($unsigned(begin_signature_addr))/(P.XLEN/8);
testadrNoBase = (begin_signature_addr - P.UNCORE_RAM_BASE)/(P.XLEN/8);
for (i=0; i<sigentries; i++) begin
2024-09-29 17:18:04 +00:00
if (signature[i] !== testbench.DCacheFlushFSM.ShadowRAM[testadr+i]) begin
2023-06-14 22:02:49 +00:00
errors = errors+1;
2024-09-29 17:18:04 +00:00
$display(" Error on test %s result %d: adr = %h sim (D$) %h signature = %h",
TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], signature[i]);
$stop; // if this is changed to $finish, wally-batch.do does not get to the next step to run coverage
2023-04-14 02:06:09 +00:00
end
2022-05-17 01:03:09 +00:00
end
if (errors) $display("%s failed with %d errors. :(", TestName, errors);
else $display("%s succeeded. Brilliant!!!", TestName);
endtask
2024-09-29 17:18:04 +00:00
2024-05-02 18:53:04 +00:00
`ifdef PMP_COVERAGE
test_pmp_coverage #(P) pmp_inst(clk);
`endif
/* verilator lint_on WIDTHTRUNC */
/* verilator lint_on WIDTHEXPAND */
endmodule
/* verilator lint_on STMTDLY */
/* verilator lint_on WIDTH */
2022-06-17 22:07:16 +00:00
task automatic updateProgramAddrLabelArray;
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off WIDTHEXPAND */
input string ProgramAddrMapFile, ProgramLabelMapFile, memfilename, WALLY_DIR;
2022-06-17 22:07:16 +00:00
inout integer ProgramAddrLabelArray [string];
// Gets the memory location of begin_signature
integer ProgramLabelMapFP, ProgramAddrMapFP;
string cmd;
// if memfile, label, or addr files are out of date or don't exist, generate them
cmd = {"make -s -f ", WALLY_DIR, "/testbench/Makefile ", memfilename, " ", ProgramAddrMapFile};
$system(cmd);
2023-12-20 20:55:37 +00:00
2022-06-17 22:07:16 +00:00
ProgramLabelMapFP = $fopen(ProgramLabelMapFile, "r");
ProgramAddrMapFP = $fopen(ProgramAddrMapFile, "r");
2022-06-17 22:07:16 +00:00
if (ProgramLabelMapFP & ProgramAddrMapFP) begin // check we found both files
ProgramAddrLabelArray["begin_signature"] = 0;
ProgramAddrLabelArray["tohost"] = 0;
2023-12-20 20:55:37 +00:00
ProgramAddrLabelArray["sig_end_canary"] = 0;
2022-06-17 22:07:16 +00:00
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
2024-09-29 17:18:04 +00:00
end
2023-12-20 20:55:37 +00:00
// if(ProgramAddrLabelArray["begin_signature"] == 0) $display("Couldn't find begin_signature in %s", ProgramLabelMapFile);
// if(ProgramAddrLabelArray["sig_end_canary"] == 0) $display("Couldn't find sig_end_canary in %s", ProgramLabelMapFile);
2023-12-20 20:55:37 +00:00
2022-06-17 22:07:16 +00:00
$fclose(ProgramLabelMapFP);
$fclose(ProgramAddrMapFP);
/* verilator lint_on WIDTHTRUNC */
/* verilator lint_on WIDTHEXPAND */
endtask
2023-01-12 16:09:34 +00:00