From 08601d727006171a3e0211c9e49465fe4118c6da Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Thu, 16 May 2024 13:59:15 -0500 Subject: [PATCH 01/12] Added functionallity to testbench.sv for single elf files. --- testbench/testbench.sv | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/testbench/testbench.sv b/testbench/testbench.sv index ef1809e9e..c1ff01599 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -68,7 +68,7 @@ module testbench; logic ResetMem; // Variables that can be overwritten with $value$plusargs at start of simulation - string TEST; + string TEST, ElfFile; integer INSTR_LIMIT; // DUT signals @@ -115,6 +115,10 @@ module testbench; // 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"; + else begin + end if (!$value$plusargs("INSTR_LIMIT=%d", INSTR_LIMIT)) INSTR_LIMIT = 0; @@ -221,8 +225,12 @@ module testbench; "arch32zknh": if (P.ZKNH_SUPPORTED) tests = arch32zknh; endcase end - if (tests.size() == 0) begin - $display("TEST %s not supported in this configuration", TEST); + 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 $finish; end `ifdef MAKEVCD @@ -356,21 +364,23 @@ module testbench; //end // added //always @(posedge SelectTest) // added if(SelectTest) begin - if (riscofTest) memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"}; - else if(TEST == "buildroot") begin + if (riscofTest) begin + memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"}; + ProgramAddrMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.addr"}; + ProgramLabelMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.lab"}; + end else if(TEST == "buildroot") begin memfilename = {RISCV_DIR, "/linux-testvectors/ram.bin"}; bootmemfilename = {RISCV_DIR, "/linux-testvectors/bootmem.bin"}; uartoutfilename = {"logs/", TEST, "_uart.out"}; uartoutfile = $fopen(uartoutfilename, "w"); // delete UART output file - end - else memfilename = {pathname, tests[test], ".elf.memfile"}; - if (riscofTest) begin - ProgramAddrMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.addr"}; - ProgramLabelMapFile = {pathname, tests[test], "/ref/ref.elf.objdump.lab"}; - end else if (TEST == "buildroot") begin ProgramAddrMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.addr"}; ProgramLabelMapFile = {RISCV_DIR, "/buildroot/output/images/disassembly/vmlinux.objdump.lab"}; + end else if(ElfFile != "none") begin + memfilename = {ElfFile, ".memfile"}; + ProgramAddrMapFile = {ElfFile, ".objdump.addr"}; + ProgramLabelMapFile = {ElfFile, ".objdump.lab"}; end else begin + memfilename = {pathname, tests[test], ".elf.memfile"}; ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"}; ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"}; end @@ -410,6 +420,15 @@ module testbench; $display("Embench Benchmark: created output file: %s", outputfile); end else if (TEST == "coverage64gc") begin $display("Coverage tests don't get checked"); + end else if (ElfFile != "none") begin + $display("Single Elf file tests don't get signatured checked."); +`ifdef VERILATOR // this macro is defined when verilator is used + $finish; // Simulator Verilator needs $finish to terminate simulation. +`elsif SIM_VCS // this macro is defined when vcs is used + $finish; // Simulator VCS needs $finish to terminate simulation. +`else + $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 +`endif end else begin // 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 From 3fdfa0f70589b78967211edf1e8427db2fe67120 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Thu, 16 May 2024 15:14:49 -0500 Subject: [PATCH 02/12] wsim now simulates a single elffile. --- bin/wsim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/wsim b/bin/wsim index 9c4cce68f..531c6825c 100755 --- a/bin/wsim +++ b/bin/wsim @@ -18,6 +18,7 @@ import os parser = argparse.ArgumentParser() parser.add_argument("config", help="Configuration file") parser.add_argument("testsuite", help="Test suite or ELF file") +parser.add_argument("--elf", "-e", help="Elf file", action="store_true") parser.add_argument("--sim", "-s", help="Simulator", choices=["questa", "verilator", "vcs"], default="questa") parser.add_argument("--tb", "-t", help="Testbench", choices=["testbench", "testbench_fp"], default="testbench") parser.add_argument("--gui", "-g", help="Simulate with GUI", action="store_true") @@ -26,6 +27,10 @@ parser.add_argument("--args", "-a", help="Optional arguments passed to simulator parser.add_argument("--vcd", "-v", help="Generate testbench.vcd", action="store_true") args = parser.parse_args() print("Config=" + args.config + " tests=" + args.testsuite + " sim=" + args.sim + " gui=" + str(args.gui) + " args='" + args.args + "'") +ElfFile="" +if(args.elf): + ElfFile = "+ElfFile=" + args.testsuite + args.testsuite = "none" # Validate arguments if (args.gui): @@ -55,7 +60,7 @@ cd = "cd $WALLY/sim/" +args.sim if (args.sim == "questa"): if (args.tb == "testbench_fp"): args.args = " -GTEST=\"" + args.testsuite + "\" " + args.args - cmd = "do wally.do " + args.config + " " + args.testsuite + " " + args.tb + " " + args.args + cmd = "do wally.do " + args.config + " " + args.testsuite + " " + args.tb + " " + args.args + " " + ElfFile if (args.coverage): cmd += " --coverage" if (args.gui): # launch Questa with GUI; add +acc to keep variables accessible From 8391b8b821c09c33b28f4adcdabd662b0b6c2c90 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Thu, 16 May 2024 15:29:12 -0500 Subject: [PATCH 03/12] Progress towards unified regression. --- testbench/testbench.sv | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/testbench/testbench.sv b/testbench/testbench.sv index c1ff01599..846ef9e6a 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -265,7 +265,7 @@ module testbench; logic ResetCntRst; logic CopyRAM; - string signame, memfilename, bootmemfilename, uartoutfilename, pathname; + string signame, elffilename, memfilename, bootmemfilename, uartoutfilename, pathname; integer begin_signature_addr, end_signature_addr, signature_size; integer uartoutfile; @@ -366,20 +366,24 @@ module testbench; if(SelectTest) begin if (riscofTest) begin memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"}; + 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"}; end else if(TEST == "buildroot") begin memfilename = {RISCV_DIR, "/linux-testvectors/ram.bin"}; + 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(ElfFile != "none") begin + elffilename = ElfFile; memfilename = {ElfFile, ".memfile"}; ProgramAddrMapFile = {ElfFile, ".objdump.addr"}; ProgramLabelMapFile = {ElfFile, ".objdump.lab"}; end else begin + elffilename = {pathname, tests[test], ".elf"}; memfilename = {pathname, tests[test], ".elf.memfile"}; ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"}; ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"}; @@ -421,7 +425,7 @@ module testbench; end else if (TEST == "coverage64gc") begin $display("Coverage tests don't get checked"); end else if (ElfFile != "none") begin - $display("Single Elf file tests don't get signatured checked."); + $display("Single Elf file tests are not signatured verified."); `ifdef VERILATOR // this macro is defined when verilator is used $finish; // Simulator Verilator needs $finish to terminate simulation. `elsif SIM_VCS // this macro is defined when vcs is used @@ -688,6 +692,7 @@ end .CMP_CSR (1) ) idv_trace2api(rvvi); + string filename; initial begin int iter; #1; @@ -705,7 +710,10 @@ end void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 56)); void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); - if (!rvviRefInit("")) begin + if(elffilename == "buildroot") filename = ""; + else filename = elffilename; + + if (!rvviRefInit(filename)) begin $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); $fatal; end From 62eaca0e6ec72e9d39dd1eb9f8825bb4eb4f4a47 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Thu, 16 May 2024 17:01:25 -0500 Subject: [PATCH 04/12] Almost working ImperasDV with testbench.sv and wally.do. For some reason IDV is saying the instructions are mismatching. --- testbench/testbench.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 846ef9e6a..63bbf7d00 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -775,7 +775,7 @@ end // *** RT: This section can probably be moved into the same chunk of code which // loads the memories. However I'm not sure that ImperasDV supports reloading // the memories without relaunching the simulator. - begin + if(elffilename == "buildroot") begin longint x64; int x32[2]; longint index; From bd8450734bf403785c537204cee6cd77cfde78cb Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 10:39:00 -0500 Subject: [PATCH 05/12] Fixed more bugs with wally.do. --- sim/questa/wally.do | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim/questa/wally.do b/sim/questa/wally.do index 0e717f730..4f626851e 100644 --- a/sim/questa/wally.do +++ b/sim/questa/wally.do @@ -143,7 +143,7 @@ vlog -lint -work ${WKDIR} +incdir+${CONFIG}/${CFG} +incdir+${CONFIG}/deriv/${CF # start and run simulation # remove +acc flag for faster sim during regressions if there is no need to access internal signals -vopt $accFlag wkdir/${CFG}_${TESTSUITE}.${TESTBENCH} -work ${WKDIR} ${lst} -o testbenchopt ${CoverageVoptArg} +vopt $accFlag wkdir/${CFG}_${TESTSUITE}.${TESTBENCH} -work ${WKDIR} ${ParamArgs} -o testbenchopt ${CoverageVoptArg} vsim -lib ${WKDIR} testbenchopt +TEST=${TESTSUITE} ${PlusArgs} -fatal 7 ${SVLib} ${SVLibPath} ${OtherFlags} -suppress 3829 ${CoverageVsimArg} From a885240fbde05e345145f084a252ae20e7472079 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 12:36:00 -0500 Subject: [PATCH 06/12] temporary commit to help debug merging testbench.sv with testbench-imperas.sv --- sim/questa/run-imperas-linux.sh | 2 +- testbench/testbench-imperas.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sim/questa/run-imperas-linux.sh b/sim/questa/run-imperas-linux.sh index d0f3981c4..aebf6b9d0 100755 --- a/sim/questa/run-imperas-linux.sh +++ b/sim/questa/run-imperas-linux.sh @@ -7,4 +7,4 @@ export OTHERFLAGS="+TRACE2LOG_ENABLE=1 +TRACE2LOG_AFTER=100" #export OTHERFLAGS="+TRACE2LOG_ENABLE=1 +TRACE2LOG_AFTER=10500000" #export OTHERFLAGS="" -vsim -c -do "do wally.do buildroot buildroot testbench --lockstep" +vsim -do "do wally.do buildroot buildroot testbench --lockstep +acc -GDEBUG=1" diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index c315272a6..877422fc5 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -97,7 +97,7 @@ module testbench; initial begin ResetCount = 0; - ResetThreshold = 2; + ResetThreshold = 21; InReset = 1; testadr = 0; testadrNoBase = 0; From d9807bb9094e2e8ea12d8c192ba5497df9b62c47 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 14:45:37 -0500 Subject: [PATCH 07/12] This is crazy. I'm merging testbench.sv into testbench-imperas.sv to find the point when it stops working. But each logical point where it would stop working it keeps working. For example moving readmemh from initial to always block. --- testbench/testbench-imperas.sv | 633 +++++++++++++++++++++++++++------ 1 file changed, 515 insertions(+), 118 deletions(-) diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index 877422fc5..478474749 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -26,59 +26,66 @@ //////////////////////////////////////////////////////////////////////////////////////////////// `include "config.vh" - - -// This is set from the command line script -// `define USE_IMPERAS_DV +`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; + parameter BPRED_LOGGER=0; + parameter I_CACHE_ADDR_LOGGER=0; + parameter D_CACHE_ADDR_LOGGER=0; -`ifdef USE_IMPERAS_DV - import idvPkg::*; - import rvviApiPkg::*; - import idvApiPkg::*; -`endif + `ifdef USE_IMPERAS_DV + import idvPkg::*; + import rvviApiPkg::*; + import idvApiPkg::*; + `endif + + `ifdef VERILATOR + import "DPI-C" function string getenvval(input string env_name); + string RISCV_DIR = getenvval("RISCV"); // "/opt/riscv"; + `elsif SIM_VCS + import "DPI-C" function string getenv(input string env_name); + string RISCV_DIR = getenv("RISCV"); // "/opt/riscv"; + `else + string RISCV_DIR = "$RISCV"; // "/opt/riscv"; + `endif `include "parameter-defs.vh" logic clk; logic reset_ext, reset; + logic ResetMem; + // Variables that can be overwritten with $value$plusargs at start of simulation + string TEST; + string ElfFile; + integer INSTR_LIMIT; - logic [P.XLEN-1:0] testadr, testadrNoBase; - string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; - logic [31:0] InstrW; - - logic [3:0] dummy; - - logic [P.AHBW-1:0] HRDATAEXT; - logic HREADYEXT, HRESPEXT; - logic HSELEXTSDC; + // DUT signals + logic [P.AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic HSELEXTSDC; 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 [P.XLEN-1:0] PCW; - logic [31:0] NextInstrE, InstrM; - - string ProgramAddrMapFile, ProgramLabelMapFile; - integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 }; - logic DCacheFlushDone, DCacheFlushStart; - string testName; - string memfilename, testDir, adrstr, elffilename; + 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; @@ -88,10 +95,275 @@ module testbench; logic HREADY; logic HSELEXT; + + string ProgramAddrMapFile, ProgramLabelMapFile; + integer ProgramAddrLabelArray [string]; + + int test, i, errors, totalerrors; + + string outputfile; + integer outputFilePointer; + + string tests[]; + logic DCacheFlushDone, DCacheFlushStart; + logic riscofTest; + logic Validate; + logic SelectTest; + logic TestComplete; + + initial begin + // 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"; + else begin + end + if (!$value$plusargs("INSTR_LIMIT=%d", INSTR_LIMIT)) + INSTR_LIMIT = 0; + ElfFile = "/home/rose/repos/active/cvw2/cvw/tests/riscof/work/riscv-arch-test/rv64i_m/I/src/add-01.S/ref/ref.elf"; + + // pick tests based on modes supported + //tests = '{}; + if (P.XLEN == 64) begin // RV64 + case (TEST) + "arch64i": tests = arch64i; + "arch64priv": tests = arch64priv; + "arch64c": if (P.C_SUPPORTED) + if (P.ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv}; + else tests = {arch64c}; + "arch64m": if (P.M_SUPPORTED) tests = arch64m; + "arch64a_amo": if (P.A_SUPPORTED | P.ZAAMO_SUPPORTED) tests = arch64a_amo; + "arch64f": if (P.F_SUPPORTED) tests = arch64f; + "arch64d": if (P.D_SUPPORTED) tests = arch64d; + "arch64f_fma": if (P.F_SUPPORTED) tests = arch64f_fma; + "arch64d_fma": if (P.D_SUPPORTED) tests = arch64d_fma; + "arch64f_divsqrt": if (P.F_SUPPORTED) tests = arch64f_divsqrt; + "arch64d_divsqrt": if (P.D_SUPPORTED) tests = arch64d_divsqrt; + "arch64zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch64zifencei; + "arch64zicond": if (P.ZICOND_SUPPORTED) tests = arch64zicond; + "imperas64i": tests = imperas64i; + "imperas64f": if (P.F_SUPPORTED) tests = imperas64f; + "imperas64d": if (P.D_SUPPORTED) tests = imperas64d; + "imperas64m": if (P.M_SUPPORTED) tests = imperas64m; + "wally64q": if (P.Q_SUPPORTED) tests = wally64q; + "wally64a_lrsc": if (P.A_SUPPORTED | P.ZALRSC_SUPPORTED) tests = wally64a_lrsc; + "imperas64c": if (P.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; + "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; + "arch64zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch64zicboz; + "arch64zcb": if (P.ZCB_SUPPORTED) tests = arch64zcb; + "arch64zfh": if (P.ZFH_SUPPORTED) tests = arch64zfh; + "arch64zfh_fma": if (P.ZFH_SUPPORTED) tests = arch64zfh_fma; + "arch64zfh_divsqrt": if (P.ZFH_SUPPORTED) tests = arch64zfh_divsqrt; + "arch64zfaf": if (P.ZFA_SUPPORTED) tests = arch64zfaf; + "arch64zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch64zfad; + "buildroot": tests = buildroot; + "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; + endcase + end else begin // RV32 + case (TEST) + "arch32e": tests = arch32e; + "arch32i": tests = arch32i; + "arch32priv": tests = arch32priv; + "arch32c": if (P.C_SUPPORTED) + if (P.ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv}; + else tests = {arch32c}; + "arch32m": if (P.M_SUPPORTED) tests = arch32m; + "arch32a_amo": if (P.A_SUPPORTED | P.ZAAMO_SUPPORTED) tests = arch32a_amo; + "arch32f": if (P.F_SUPPORTED) tests = arch32f; + "arch32d": if (P.D_SUPPORTED) tests = arch32d; + "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; + "arch32d_divsqrt": if (P.D_SUPPORTED) tests = arch32d_divsqrt; + "arch32zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch32zifencei; + "arch32zicond": if (P.ZICOND_SUPPORTED) tests = arch32zicond; + "imperas32i": tests = imperas32i; + "imperas32f": if (P.F_SUPPORTED) tests = imperas32f; + "imperas32m": if (P.M_SUPPORTED) tests = imperas32m; + "wally32a_lrsc": if (P.A_SUPPORTED | P.ZALRSC_SUPPORTED) tests = wally32a_lrsc; + "imperas32c": if (P.C_SUPPORTED) tests = imperas32c; + else tests = imperas32iNOc; + "wally32i": tests = wally32i; + "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; + "arch32zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch32zicboz; + "arch32zcb": if (P.ZCB_SUPPORTED) tests = arch32zcb; + "arch32zfh": if (P.ZFH_SUPPORTED) tests = arch32zfh; + "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; + "arch32zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch32zfad; + "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; + 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 + $finish; + end +`ifdef MAKEVCD + $dumpfile("testbench.vcd"); + $dumpvars; +`endif + end // initial begin + + typedef enum logic [3:0]{STATE_TESTBENCH_RESET, + STATE_INIT_TEST, + STATE_RESET_MEMORIES, + STATE_RESET_MEMORIES2, + 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; + statetype CurrState, NextState; + logic TestBenchReset; + logic [2:0] ResetCountNew, ResetThresholdNew; + logic LoadMem; + logic ResetCntEn; + logic ResetCntRst; + logic CopyRAM; + + string signame, bootmemfilename, uartoutfilename, pathname; + integer begin_signature_addr, end_signature_addr, signature_size; + integer uartoutfile; + logic reset_extNew; + logic DCacheFlushStartNew; + + logic [P.XLEN-1:0] testadr, testadrNoBase; + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + + + + logic [P.XLEN-1:0] PCW; + logic [31:0] NextInstrE, InstrM; + + string testName; + string memfilename, testDir, adrstr, elffilename; + + logic InitializingMemories; integer ResetCount, ResetThreshold; logic InReset; + integer memFile; + integer readResult; + + + + //////////////////////////////////////////////////////////////////////////////// + // load memories with program image + //////////////////////////////////////////////////////////////////////////////// + + integer ShadowIndex; + integer LogXLEN; + integer StartIndex; + integer EndIndex; + integer BaseIndex; + 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"}; + sdcfilename = {"../testbench/sdc/ramdisk2.hex"}; + //$readmemh(romfilename, dut.uncoregen.uncore.bootrom.bootrom.memory.ROM); + //$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 + end else if (P.BUS_SUPPORTED) begin : bus_supported + always @(posedge clk) begin + if (LoadMem) begin + if (TEST == "buildroot") begin + memFile = $fopen(bootmemfilename, "rb"); + readResult = $fread(dut.uncoregen.uncore.bootrom.bootrom.memory.ROM, memFile); + $fclose(memFile); + memFile = $fopen(memfilename, "rb"); + readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.RAM, memFile); + $fclose(memFile); + end else + $readmemh(memfilename, dut.uncoregen.uncore.ram.ram.memory.RAM); + if (TEST == "embench") $display("Read memfile %s", memfilename); + end + if (CopyRAM) begin + 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 + testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.uncoregen.uncore.ram.ram.memory.RAM[ShadowIndex - BaseIndex]; + end + end + end + end + if (P.DTIM_SUPPORTED) begin + always @(posedge clk) begin + if (LoadMem) begin + $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM); + $display("Read memfile %s", memfilename); + end + if (CopyRAM) begin + 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 + testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.core.lsu.dtim.dtim.ram.RAM[ShadowIndex - BaseIndex]; + end + end + end + end + + integer adrindex; + if (P.UNCORE_RAM_SUPPORTED) + always @(posedge clk) + if (ResetMem) // program memory is sometimes reset (e.g. for CoreMark, which needs zeroed memory) + for (adrindex=0; adrindex<(P.UNCORE_RAM_RANGE>>1+(P.XLEN/32)); adrindex = adrindex+1) + dut.uncoregen.uncore.ram.ram.memory.RAM[adrindex] = '0; // Imperas look here. initial @@ -110,8 +382,7 @@ module testbench; $error("Must specify test directory using plusarg testDir"); end - if (P.BUS_SUPPORTED) $readmemh(memfilename, dut.uncoregen.uncore.ram.ram.memory.RAM); - else $error("Imperas test bench requires BUS."); + #130; ProgramAddrMapFile = {testDir, "/ref/ref.elf.objdump.addr"}; ProgramLabelMapFile = {testDir, "/ref/ref.elf.objdump.lab"}; @@ -123,98 +394,224 @@ module testbench; end + // 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 + + + assign ResetThresholdNew = 3'd5; + + initial begin + TestBenchReset = 1'b1; + # 100; + TestBenchReset = 1'b0; + end + + always_ff @(posedge clk) + if (TestBenchReset) CurrState <= STATE_TESTBENCH_RESET; + else CurrState <= NextState; + + // fsm next state logic + always_comb begin + // riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests + // and tests[0] == "2" refers to WallyRiscvArchTests + //pathname = tvpaths[tests[0].atoi()]; + + case(CurrState) + 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(ResetCountNew < ResetThresholdNew) NextState = STATE_RESET_TEST; + else NextState = STATE_RUN_TEST; + STATE_RUN_TEST: if(TestComplete) NextState = STATE_COPY_RAM; + else NextState = STATE_RUN_TEST; + STATE_COPY_RAM: NextState = STATE_CHECK_TEST; + 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; + endcase + end // always_comb + // fsm output control logic + assign reset_extNew = CurrState == STATE_TESTBENCH_RESET | CurrState == STATE_INIT_TEST | + CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2 | + CurrState == STATE_LOAD_MEMORIES | CurrState ==STATE_RESET_TEST; + // this initialization is very expensive, only do it for coremark. + assign ResetMem = (CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2); + 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 DCacheFlushStartNew = CurrState == STATE_COPY_RAM; + + // fsm reset counter + counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCountNew); + + `ifdef USE_IMPERAS_DV - rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); - wallyTracer #(P) wallyTracer(rvvi); + rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); + wallyTracer #(P) wallyTracer(rvvi); - trace2log idv_trace2log(rvvi); - trace2cov idv_trace2cov(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); + // 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); - initial begin - - IDV_MAX_ERRORS = 3; + string filename; + initial begin + int iter; + #1; + IDV_MAX_ERRORS = 3; - // 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 - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org")); - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv")); - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GC")); - void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 39)); - void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); + // 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 + + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org")); + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv")); + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GC")); + void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 56)); + void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); - if (!rvviRefInit(elffilename)) begin - $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); - $fatal; - 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 - - // 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!!!! - + if(elffilename == "buildroot") filename = ""; + else filename = elffilename; + + if (!rvviRefInit(filename)) begin + $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); + $fatal; end - 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])); + // 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 + + // User HPMCOUNTER3 - HPMCOUNTER31 + for (iter='hC03; iter<='hC1F; iter++) begin + void'(rvviRefCsrSetVolatile(0, iter)); // HPMCOUNTERx + end + + // Machine MHPMCOUNTER3 - MHPMCOUNTER31 + for (iter='hB03; iter<='hB1F; iter++) begin + void'(rvviRefCsrSetVolatile(0, iter)); // MHPMCOUNTERx + end + + // cannot predict this register due to latency between + // pending and taken + void'(rvviRefCsrSetVolatile(0, 32'h344)); // MIP + void'(rvviRefCsrSetVolatile(0, 32'h144)); // SIP - final begin - void'(rvviRefShutdown()); + // 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!!!! + + // Load memory + // *** RT: This section can probably be moved into the same chunk of code which + // loads the memories. However I'm not sure that ImperasDV supports reloading + // the memories without relaunching the simulator. + if(elffilename == "buildroot") begin + longint x64; + int x32[2]; + longint index; + string memfilenameImperasDV, bootmemfilenameImperasDV; + + 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); + + $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); + + $display("RVVI Loading Complete"); + + void'(rvviRefPcSet(0, P.RESET_VECTOR)); // set BOOTROM address + end + end + + 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])); + + final begin + void'(rvviRefShutdown()); + end `endif From e6902eb4d29f4e4eab28c783ce109a695e0ca232 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 16:08:14 -0500 Subject: [PATCH 08/12] Ok. How does it still work? testbench-imperas.sv the same as testbench.sv now. --- testbench/testbench-imperas.sv | 619 ++++++++++++++++++++++----------- 1 file changed, 421 insertions(+), 198 deletions(-) diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index 478474749..c8ff90893 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -240,6 +240,12 @@ module testbench; `endif 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, STATE_RESET_MEMORIES, @@ -260,33 +266,204 @@ module testbench; logic ResetCntRst; logic CopyRAM; - string signame, bootmemfilename, uartoutfilename, pathname; + string signame, elffilename, memfilename, bootmemfilename, uartoutfilename, pathname; integer begin_signature_addr, end_signature_addr, signature_size; integer uartoutfile; + logic reset_extNew; logic DCacheFlushStartNew; + assign ResetThresholdNew = 3'd5; + + initial begin + TestBenchReset = 1'b1; + # 100; + TestBenchReset = 1'b0; + end + + always_ff @(posedge clk) + if (TestBenchReset) CurrState <= STATE_TESTBENCH_RESET; + else CurrState <= NextState; + + // fsm next state logic + always_comb begin + // riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests + // and tests[0] == "2" refers to WallyRiscvArchTests + //pathname = tvpaths[tests[0].atoi()]; + + case(CurrState) + 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(ResetCountNew < ResetThresholdNew) NextState = STATE_RESET_TEST; + else NextState = STATE_RUN_TEST; + STATE_RUN_TEST: if(TestComplete) NextState = STATE_COPY_RAM; + else NextState = STATE_RUN_TEST; + STATE_COPY_RAM: NextState = STATE_CHECK_TEST; + 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; + endcase + end // always_comb + // fsm output control logic + assign reset_ext = CurrState == STATE_TESTBENCH_RESET | CurrState == STATE_INIT_TEST | + CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2 | + CurrState == STATE_LOAD_MEMORIES | CurrState ==STATE_RESET_TEST; + // this initialization is very expensive, only do it for coremark. + assign ResetMem = (CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2); + 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 DCacheFlushStartNew = CurrState == STATE_COPY_RAM; + + // fsm reset counter + counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCountNew); - logic [P.XLEN-1:0] testadr, testadrNoBase; - string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; - logic [31:0] InstrW; - - - - logic [P.XLEN-1:0] PCW; - logic [31:0] NextInstrE, InstrM; - - string testName; - string memfilename, testDir, adrstr, elffilename; - - - logic InitializingMemories; - integer ResetCount, ResetThreshold; - logic InReset; - integer memFile; - integer readResult; + //////////////////////////////////////////////////////////////////////////////// + // Find the test vector files and populate the PC to function label converter + //////////////////////////////////////////////////////////////////////////////// + logic [P.XLEN-1:0] testadr; + //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 + begin_signature_addr = ProgramAddrLabelArray["begin_signature"]; + end_signature_addr = ProgramAddrLabelArray["sig_end_canary"]; + 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; + 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 + if (P.ZICSR_SUPPORTED & dut.core.ifu.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.ieu.InstrValidM) begin + $display("Program fetched illegal instruction 0x00000000 from address 0x00000000. Might be fault with no fault handler."); + //$stop; // presently wally32/64priv tests trigger this for reasons not yet understood. + end + // modifications 4/3/24 kunlin & harris to speed up Verilator + // For some reason, Verilator runs ~100x slower when these SelectTest and Validate codes are in the posedge clk block + //end // added + //always @(posedge SelectTest) // added + if(SelectTest) begin + if (riscofTest) begin + memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"}; + 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"}; + end else if(TEST == "buildroot") begin + memfilename = {RISCV_DIR, "/linux-testvectors/ram.bin"}; + 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(ElfFile != "none") begin + elffilename = ElfFile; + memfilename = {ElfFile, ".memfile"}; + ProgramAddrMapFile = {ElfFile, ".objdump.addr"}; + ProgramLabelMapFile = {ElfFile, ".objdump.lab"}; + end else begin + elffilename = {pathname, tests[test], ".elf"}; + memfilename = {pathname, tests[test], ".elf.memfile"}; + ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"}; + ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"}; + end + // 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) + updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray); + end +`ifdef VERILATOR // this macro is defined when verilator is used + // Simulator Verilator has an issue that the validate logic below slows runtime 110x if it is + // in the posedge clk block rather than a separate posedge Validate block. + // Until it is fixed, provide a silly posedge Validate block to keep Verilator happy. + // https://github.com/verilator/verilator/issues/4967 + end // restored + always @(posedge Validate) // added +`endif + if(Validate) begin + if (TEST == "buildroot") + $fclose(uartoutfile); + if (TEST == "embench") begin + // Writes contents of begin_signature to .sim.output file + // 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 + $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 + $fclose(outputFilePointer); + $display("Embench Benchmark: created output file: %s", outputfile); + end else if (TEST == "coverage64gc") begin + $display("Coverage tests don't get checked"); + end else if (ElfFile != "none") begin + $display("Single Elf file tests are not signatured verified."); +`ifdef VERILATOR // this macro is defined when verilator is used + $finish; // Simulator Verilator needs $finish to terminate simulation. +`elsif SIM_VCS // this macro is defined when vcs is used + $finish; // Simulator VCS needs $finish to terminate simulation. +`else + $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 +`endif + end else begin + // 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); + else if (TEST != "embench") begin // *** quick hack for embench. need a better long term solution + CheckSignature(pathname, tests[test], riscofTest, begin_signature_addr, errors); + if(errors > 0) totalerrors = totalerrors + 1; + end + end + test = test + 1; // *** this probably needs to be moved. + if (test == tests.size()) begin + if (totalerrors == 0) $display("SUCCESS! All tests ran without failures."); + else $display("FAIL: %d test programs had errors", totalerrors); +`ifdef VERILATOR // this macro is defined when verilator is used + $finish; // Simulator Verilator needs $finish to terminate simulation. +`elsif SIM_VCS // this macro is defined when vcs is used + $finish; // Simulator VCS needs $finish to terminate simulation. +`else + $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 +`endif + end + end +`ifndef VERILATOR + // Remove this when issue 4967 is resolved and the posedge Validate logic above is removed + end +`endif + + //////////////////////////////////////////////////////////////////////////////// // load memories with program image @@ -297,6 +474,8 @@ module testbench; integer StartIndex; integer EndIndex; integer BaseIndex; + integer memFile; + integer readResult; if (P.SDC_SUPPORTED) begin always @(posedge clk) begin if (LoadMem) begin @@ -365,6 +544,155 @@ module testbench; for (adrindex=0; adrindex<(P.UNCORE_RAM_RANGE>>1+(P.XLEN/32)); adrindex = adrindex+1) dut.uncoregen.uncore.ram.ram.memory.RAM[adrindex] = '0; + //////////////////////////////////////////////////////////////////////////////// + // Actual hardware + //////////////////////////////////////////////////////////////////////////////// + + // instantiate device to be tested + assign GPIOIN = '0; + assign UARTSin = 1'b1; + assign SPIIn = 1'b0; + + if(P.EXT_MEM_SUPPORTED) begin + ram_ahb #(.P(P), .BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) + ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT), + .HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY, .HWSTRB); + end else begin + assign HREADYEXT = 1'b1; + assign {HRESPEXT, HRDATAEXT} = '0; + end + + if(P.SDC_SUPPORTED) begin : sdcard + // *** fix later +/* -----\/----- EXCLUDED -----\/----- + sdModel sdcard + (.sdClk(SDCCLK), + .cmd(SDCCmd), + .dat(SDCDat)); + + assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; + assign SDCCmdIn = SDCCmd; + assign SDCDat = sd_dat_reg_t ? sd_dat_reg_o : sd_dat_i; + assign SDCDatIn = SDCDat; + -----/\----- EXCLUDED -----/\----- */ + assign SDCIntr = 1'b0; + end else begin + assign SDCIntr = 1'b0; + end + + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCIntr, .SPIIn, .SPIOut, .SPICS); + + // generate clock to sequence tests + always begin + clk = 1'b1; # 5; clk = 1'b0; # 5; + end + + /* + // Print key info each cycle for debugging + 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 + */ + + //////////////////////////////////////////////////////////////////////////////// + // 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); // check if PCW is stuck + 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); + 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 + // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed + // or sw gp,-56(t0) for new Imperas tests + // or sd gp, -56(t0) + // or on a jump to self infinite loop (6f) for RISC-V Arch tests + logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls + if (P.ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM; + else assign ecf = 0; + always_comb begin + TestComplete = ecf & + (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)) | + ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"] & dut.core.lsu.IEUAdrM != 0) & InstrMName == "SW" ); + end + + DCacheFlushFSM #(P) DCacheFlushFSM(.clk, .start(DCacheFlushStart), .done(DCacheFlushDone)); + + if(P.ZICSR_SUPPORTED) begin + logic [P.XLEN-1:0] Minstret; + assign Minstret = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2]; + always @(negedge clk) begin + 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 + end + end +end + + + + + + + + + logic [P.XLEN-1:0] testadrNoBase; + + + string testName; + string testDir, adrstr; + + + logic InitializingMemories; + integer ResetCount, ResetThreshold; + logic InReset; + // Imperas look here. initial begin @@ -394,67 +722,8 @@ module testbench; end - // 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 - assign ResetThresholdNew = 3'd5; - - initial begin - TestBenchReset = 1'b1; - # 100; - TestBenchReset = 1'b0; - end - - always_ff @(posedge clk) - if (TestBenchReset) CurrState <= STATE_TESTBENCH_RESET; - else CurrState <= NextState; - - // fsm next state logic - always_comb begin - // riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests - // and tests[0] == "2" refers to WallyRiscvArchTests - //pathname = tvpaths[tests[0].atoi()]; - - case(CurrState) - 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(ResetCountNew < ResetThresholdNew) NextState = STATE_RESET_TEST; - else NextState = STATE_RUN_TEST; - STATE_RUN_TEST: if(TestComplete) NextState = STATE_COPY_RAM; - else NextState = STATE_RUN_TEST; - STATE_COPY_RAM: NextState = STATE_CHECK_TEST; - 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; - endcase - end // always_comb - // fsm output control logic - assign reset_extNew = CurrState == STATE_TESTBENCH_RESET | CurrState == STATE_INIT_TEST | - CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2 | - CurrState == STATE_LOAD_MEMORIES | CurrState ==STATE_RESET_TEST; - // this initialization is very expensive, only do it for coremark. - assign ResetMem = (CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2); - 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 DCacheFlushStartNew = CurrState == STATE_COPY_RAM; - - // fsm reset counter - counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCountNew); `ifdef USE_IMPERAS_DV @@ -615,134 +884,88 @@ module testbench; `endif - flopenr #(P.XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); - flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); + 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; + int fd, code; + string line; + int siglines, sigentries; - // check assertions for a legal configuration - riscvassertions #(P) riscvassertions(); + localparam SIGNATURESIZE = 5000000; + integer i; + logic [31:0] sig32[0:SIGNATURESIZE]; + logic [31:0] parsed; + logic [P.XLEN-1:0] signature[0:SIGNATURESIZE]; + string signame; + logic [P.XLEN-1:0] testadr, testadrNoBase; + //$display("Invoking CheckSignature %s %s %0t", pathname, TestName, $time); + + // read .signature.output file and compare to check for errors + if (riscofTest) signame = {pathname, TestName, "/ref/Reference-sail_c_simulator.signature"}; + else signame = {pathname, TestName, ".signature.output"}; - // instantiate device to be tested - assign GPIOIN = 0; - assign UARTSin = 1; - - if(P.EXT_MEM_SUPPORTED) begin - ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) - 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 - - if(P.SDC_SUPPORTED) begin : sdcard - // *** fix later -/* -----\/----- EXCLUDED -----\/----- - sdModel sdcard - (.sdClk(SDCCLK), - .cmd(SDCCmd), - .dat(SDCDat)); - - assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; - assign SDCCmdIn = SDCCmd; - assign SDCDatIn = SDCDat; - -----/\----- EXCLUDED -----/\----- */ - assign SDCIntr = 0; - end else begin - assign SDCIntr = 0; - end - - wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, - .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); - - // Track names of instructions - 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); - - // initialize tests - - // generate clock to sequence tests - always - begin - clk = 1; # 5; clk = 0; # 5; - // if ($time % 100000 == 0) $display("Time is %0t", $time); - end - - // check results - assign reset_ext = InReset; - - always @(negedge clk) - begin - 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. - InReset = 0; - ResetCount = 0; - end - end - end // always @ (negedge clk) - - - // track the current function or global label - if (DEBUG == 1) begin : FunctionName - FunctionName #(P) FunctionName(.reset(reset), - .clk(clk), - .ProgramAddrMapFile(ProgramAddrMapFile), - .ProgramLabelMapFile(ProgramLabelMapFile)); - end - - // Duplicate copy of pipeline registers that are optimized out of some configurations - 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); - - // Termination condition - // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed - // or sw gp,-56(t0) for new Imperas tests - // or sd gp, -56(t0) - // or on a jump to self infinite loop (6f) for RISC-V Arch tests - logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls - if (P.ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM; - else assign ecf = 0; - assign DCacheFlushStart = ecf & - (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)) | - ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | - ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); - - DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), - .start(DCacheFlushStart), - .done(DCacheFlushDone)); - - // initialize the branch predictor - if (P.BPRED_SUPPORTED == 1) - begin - genvar adrindex; - - // Initializing all zeroes into the branch predictor memory. - for(adrindex = 0; adrindex < 1024; adrindex++) begin - initial begin - force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0; - force dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0; - #1; - release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex]; - release dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex]; + // 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 end + $fclose(fd); end - watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck + // Check valid number of lines were read + 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 Date: Fri, 17 May 2024 16:45:01 -0500 Subject: [PATCH 09/12] Yay. Finally found the issue with the integrated testbench.sv and imperasDV. The function which loads the elf file rvviRefInit must be called during an initial block using a valid file name. Because of how the testbench was organized the elffile was not defined until several cycles later so the call to rvviRefInit did not have a valid elf. Waiting several cycles does not work. rvviRefInit requires being called in an initial block so it is not possible to run back to back imperasDV simulations in the same run. --- testbench/testbench.sv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 63bbf7d00..1bd41627a 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -694,9 +694,11 @@ end string filename; initial begin + // imperasDV requires the elffile be defined at the begining of the simulation. int iter; #1; IDV_MAX_ERRORS = 3; + elffilename = ElfFile; // Initialize REF (do this before initializing the DUT) if (!rvviVersionCheck(RVVI_API_VERSION)) begin From 0ed75a3ff511212ec92a764eb1f4f7d2d8816277 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 16:48:29 -0500 Subject: [PATCH 10/12] Reverted testbench-imperas.sv incase someone wants this. --- testbench/testbench-imperas.sv | 1088 +++++++------------------------- 1 file changed, 234 insertions(+), 854 deletions(-) diff --git a/testbench/testbench-imperas.sv b/testbench/testbench-imperas.sv index c8ff90893..c315272a6 100644 --- a/testbench/testbench-imperas.sv +++ b/testbench/testbench-imperas.sv @@ -26,66 +26,59 @@ //////////////////////////////////////////////////////////////////////////////////////////////// `include "config.vh" -`include "tests.vh" -`include "BranchPredictorType.vh" + + +// This is set from the command line script +// `define USE_IMPERAS_DV `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; - parameter BPRED_LOGGER=0; - parameter I_CACHE_ADDR_LOGGER=0; - parameter D_CACHE_ADDR_LOGGER=0; - `ifdef USE_IMPERAS_DV - import idvPkg::*; - import rvviApiPkg::*; - import idvApiPkg::*; - `endif - - `ifdef VERILATOR - import "DPI-C" function string getenvval(input string env_name); - string RISCV_DIR = getenvval("RISCV"); // "/opt/riscv"; - `elsif SIM_VCS - import "DPI-C" function string getenv(input string env_name); - string RISCV_DIR = getenv("RISCV"); // "/opt/riscv"; - `else - string RISCV_DIR = "$RISCV"; // "/opt/riscv"; - `endif +`ifdef USE_IMPERAS_DV + import idvPkg::*; + import rvviApiPkg::*; + import idvApiPkg::*; +`endif `include "parameter-defs.vh" logic clk; logic reset_ext, reset; - logic ResetMem; - // Variables that can be overwritten with $value$plusargs at start of simulation - string TEST; - string ElfFile; - integer INSTR_LIMIT; - // DUT signals - logic [P.AHBW-1:0] HRDATAEXT; - logic HREADYEXT, HRESPEXT; - logic HSELEXTSDC; + logic [P.XLEN-1:0] testadr, testadrNoBase; + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + + logic [3:0] dummy; + + logic [P.AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic HSELEXTSDC; 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 [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 [P.XLEN-1:0] PCW; + logic [31:0] NextInstrE, InstrM; + + string ProgramAddrMapFile, ProgramLabelMapFile; + integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 }; + logic DCacheFlushDone, DCacheFlushStart; + string testName; + string memfilename, testDir, adrstr, elffilename; logic [31:0] GPIOIN, GPIOOUT, GPIOEN; logic UARTSin, UARTSout; @@ -95,600 +88,7 @@ module testbench; logic HREADY; logic HSELEXT; - - string ProgramAddrMapFile, ProgramLabelMapFile; - integer ProgramAddrLabelArray [string]; - - int test, i, errors, totalerrors; - - string outputfile; - integer outputFilePointer; - - string tests[]; - logic DCacheFlushDone, DCacheFlushStart; - logic riscofTest; - logic Validate; - logic SelectTest; - logic TestComplete; - - initial begin - // 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"; - else begin - end - if (!$value$plusargs("INSTR_LIMIT=%d", INSTR_LIMIT)) - INSTR_LIMIT = 0; - ElfFile = "/home/rose/repos/active/cvw2/cvw/tests/riscof/work/riscv-arch-test/rv64i_m/I/src/add-01.S/ref/ref.elf"; - - // pick tests based on modes supported - //tests = '{}; - if (P.XLEN == 64) begin // RV64 - case (TEST) - "arch64i": tests = arch64i; - "arch64priv": tests = arch64priv; - "arch64c": if (P.C_SUPPORTED) - if (P.ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv}; - else tests = {arch64c}; - "arch64m": if (P.M_SUPPORTED) tests = arch64m; - "arch64a_amo": if (P.A_SUPPORTED | P.ZAAMO_SUPPORTED) tests = arch64a_amo; - "arch64f": if (P.F_SUPPORTED) tests = arch64f; - "arch64d": if (P.D_SUPPORTED) tests = arch64d; - "arch64f_fma": if (P.F_SUPPORTED) tests = arch64f_fma; - "arch64d_fma": if (P.D_SUPPORTED) tests = arch64d_fma; - "arch64f_divsqrt": if (P.F_SUPPORTED) tests = arch64f_divsqrt; - "arch64d_divsqrt": if (P.D_SUPPORTED) tests = arch64d_divsqrt; - "arch64zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch64zifencei; - "arch64zicond": if (P.ZICOND_SUPPORTED) tests = arch64zicond; - "imperas64i": tests = imperas64i; - "imperas64f": if (P.F_SUPPORTED) tests = imperas64f; - "imperas64d": if (P.D_SUPPORTED) tests = imperas64d; - "imperas64m": if (P.M_SUPPORTED) tests = imperas64m; - "wally64q": if (P.Q_SUPPORTED) tests = wally64q; - "wally64a_lrsc": if (P.A_SUPPORTED | P.ZALRSC_SUPPORTED) tests = wally64a_lrsc; - "imperas64c": if (P.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; - "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; - "arch64zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch64zicboz; - "arch64zcb": if (P.ZCB_SUPPORTED) tests = arch64zcb; - "arch64zfh": if (P.ZFH_SUPPORTED) tests = arch64zfh; - "arch64zfh_fma": if (P.ZFH_SUPPORTED) tests = arch64zfh_fma; - "arch64zfh_divsqrt": if (P.ZFH_SUPPORTED) tests = arch64zfh_divsqrt; - "arch64zfaf": if (P.ZFA_SUPPORTED) tests = arch64zfaf; - "arch64zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch64zfad; - "buildroot": tests = buildroot; - "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; - endcase - end else begin // RV32 - case (TEST) - "arch32e": tests = arch32e; - "arch32i": tests = arch32i; - "arch32priv": tests = arch32priv; - "arch32c": if (P.C_SUPPORTED) - if (P.ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv}; - else tests = {arch32c}; - "arch32m": if (P.M_SUPPORTED) tests = arch32m; - "arch32a_amo": if (P.A_SUPPORTED | P.ZAAMO_SUPPORTED) tests = arch32a_amo; - "arch32f": if (P.F_SUPPORTED) tests = arch32f; - "arch32d": if (P.D_SUPPORTED) tests = arch32d; - "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; - "arch32d_divsqrt": if (P.D_SUPPORTED) tests = arch32d_divsqrt; - "arch32zifencei": if (P.ZIFENCEI_SUPPORTED) tests = arch32zifencei; - "arch32zicond": if (P.ZICOND_SUPPORTED) tests = arch32zicond; - "imperas32i": tests = imperas32i; - "imperas32f": if (P.F_SUPPORTED) tests = imperas32f; - "imperas32m": if (P.M_SUPPORTED) tests = imperas32m; - "wally32a_lrsc": if (P.A_SUPPORTED | P.ZALRSC_SUPPORTED) tests = wally32a_lrsc; - "imperas32c": if (P.C_SUPPORTED) tests = imperas32c; - else tests = imperas32iNOc; - "wally32i": tests = wally32i; - "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; - "arch32zicboz": if (P.ZICBOZ_SUPPORTED) tests = arch32zicboz; - "arch32zcb": if (P.ZCB_SUPPORTED) tests = arch32zcb; - "arch32zfh": if (P.ZFH_SUPPORTED) tests = arch32zfh; - "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; - "arch32zfad": if (P.ZFA_SUPPORTED & P.D_SUPPORTED) tests = arch32zfad; - "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; - 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 - $finish; - end -`ifdef MAKEVCD - $dumpfile("testbench.vcd"); - $dumpvars; -`endif - 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, - STATE_RESET_MEMORIES, - STATE_RESET_MEMORIES2, - 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; - statetype CurrState, NextState; - logic TestBenchReset; - logic [2:0] ResetCountNew, ResetThresholdNew; - logic LoadMem; - logic ResetCntEn; - logic ResetCntRst; - logic CopyRAM; - - string signame, elffilename, memfilename, bootmemfilename, uartoutfilename, pathname; - integer begin_signature_addr, end_signature_addr, signature_size; - integer uartoutfile; - - logic reset_extNew; - logic DCacheFlushStartNew; - - assign ResetThresholdNew = 3'd5; - - initial begin - TestBenchReset = 1'b1; - # 100; - TestBenchReset = 1'b0; - end - - always_ff @(posedge clk) - if (TestBenchReset) CurrState <= STATE_TESTBENCH_RESET; - else CurrState <= NextState; - - // fsm next state logic - always_comb begin - // riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests - // and tests[0] == "2" refers to WallyRiscvArchTests - //pathname = tvpaths[tests[0].atoi()]; - - case(CurrState) - 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(ResetCountNew < ResetThresholdNew) NextState = STATE_RESET_TEST; - else NextState = STATE_RUN_TEST; - STATE_RUN_TEST: if(TestComplete) NextState = STATE_COPY_RAM; - else NextState = STATE_RUN_TEST; - STATE_COPY_RAM: NextState = STATE_CHECK_TEST; - 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; - endcase - end // always_comb - // fsm output control logic - assign reset_ext = CurrState == STATE_TESTBENCH_RESET | CurrState == STATE_INIT_TEST | - CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2 | - CurrState == STATE_LOAD_MEMORIES | CurrState ==STATE_RESET_TEST; - // this initialization is very expensive, only do it for coremark. - assign ResetMem = (CurrState == STATE_RESET_MEMORIES | CurrState == STATE_RESET_MEMORIES2); - 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 DCacheFlushStartNew = CurrState == STATE_COPY_RAM; - - // fsm reset counter - counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCountNew); - //////////////////////////////////////////////////////////////////////////////// - // Find the test vector files and populate the PC to function label converter - //////////////////////////////////////////////////////////////////////////////// - logic [P.XLEN-1:0] testadr; - - //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 - begin_signature_addr = ProgramAddrLabelArray["begin_signature"]; - end_signature_addr = ProgramAddrLabelArray["sig_end_canary"]; - 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; - - 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 - if (P.ZICSR_SUPPORTED & dut.core.ifu.PCM == 0 & dut.core.ifu.InstrM == 0 & dut.core.ieu.InstrValidM) begin - $display("Program fetched illegal instruction 0x00000000 from address 0x00000000. Might be fault with no fault handler."); - //$stop; // presently wally32/64priv tests trigger this for reasons not yet understood. - end - // modifications 4/3/24 kunlin & harris to speed up Verilator - // For some reason, Verilator runs ~100x slower when these SelectTest and Validate codes are in the posedge clk block - //end // added - //always @(posedge SelectTest) // added - if(SelectTest) begin - if (riscofTest) begin - memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"}; - 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"}; - end else if(TEST == "buildroot") begin - memfilename = {RISCV_DIR, "/linux-testvectors/ram.bin"}; - 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(ElfFile != "none") begin - elffilename = ElfFile; - memfilename = {ElfFile, ".memfile"}; - ProgramAddrMapFile = {ElfFile, ".objdump.addr"}; - ProgramLabelMapFile = {ElfFile, ".objdump.lab"}; - end else begin - elffilename = {pathname, tests[test], ".elf"}; - memfilename = {pathname, tests[test], ".elf.memfile"}; - ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"}; - ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"}; - end - // 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) - updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray); - end -`ifdef VERILATOR // this macro is defined when verilator is used - // Simulator Verilator has an issue that the validate logic below slows runtime 110x if it is - // in the posedge clk block rather than a separate posedge Validate block. - // Until it is fixed, provide a silly posedge Validate block to keep Verilator happy. - // https://github.com/verilator/verilator/issues/4967 - end // restored - always @(posedge Validate) // added -`endif - if(Validate) begin - if (TEST == "buildroot") - $fclose(uartoutfile); - if (TEST == "embench") begin - // Writes contents of begin_signature to .sim.output file - // 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 - $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 - $fclose(outputFilePointer); - $display("Embench Benchmark: created output file: %s", outputfile); - end else if (TEST == "coverage64gc") begin - $display("Coverage tests don't get checked"); - end else if (ElfFile != "none") begin - $display("Single Elf file tests are not signatured verified."); -`ifdef VERILATOR // this macro is defined when verilator is used - $finish; // Simulator Verilator needs $finish to terminate simulation. -`elsif SIM_VCS // this macro is defined when vcs is used - $finish; // Simulator VCS needs $finish to terminate simulation. -`else - $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 -`endif - end else begin - // 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); - else if (TEST != "embench") begin // *** quick hack for embench. need a better long term solution - CheckSignature(pathname, tests[test], riscofTest, begin_signature_addr, errors); - if(errors > 0) totalerrors = totalerrors + 1; - end - end - test = test + 1; // *** this probably needs to be moved. - if (test == tests.size()) begin - if (totalerrors == 0) $display("SUCCESS! All tests ran without failures."); - else $display("FAIL: %d test programs had errors", totalerrors); -`ifdef VERILATOR // this macro is defined when verilator is used - $finish; // Simulator Verilator needs $finish to terminate simulation. -`elsif SIM_VCS // this macro is defined when vcs is used - $finish; // Simulator VCS needs $finish to terminate simulation. -`else - $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 -`endif - end - end -`ifndef VERILATOR - // Remove this when issue 4967 is resolved and the posedge Validate logic above is removed - end -`endif - - - - //////////////////////////////////////////////////////////////////////////////// - // load memories with program image - //////////////////////////////////////////////////////////////////////////////// - - integer ShadowIndex; - integer LogXLEN; - integer StartIndex; - integer EndIndex; - integer BaseIndex; - integer memFile; - 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"}; - sdcfilename = {"../testbench/sdc/ramdisk2.hex"}; - //$readmemh(romfilename, dut.uncoregen.uncore.bootrom.bootrom.memory.ROM); - //$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 - end else if (P.BUS_SUPPORTED) begin : bus_supported - always @(posedge clk) begin - if (LoadMem) begin - if (TEST == "buildroot") begin - memFile = $fopen(bootmemfilename, "rb"); - readResult = $fread(dut.uncoregen.uncore.bootrom.bootrom.memory.ROM, memFile); - $fclose(memFile); - memFile = $fopen(memfilename, "rb"); - readResult = $fread(dut.uncoregen.uncore.ram.ram.memory.RAM, memFile); - $fclose(memFile); - end else - $readmemh(memfilename, dut.uncoregen.uncore.ram.ram.memory.RAM); - if (TEST == "embench") $display("Read memfile %s", memfilename); - end - if (CopyRAM) begin - 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 - testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.uncoregen.uncore.ram.ram.memory.RAM[ShadowIndex - BaseIndex]; - end - end - end - end - if (P.DTIM_SUPPORTED) begin - always @(posedge clk) begin - if (LoadMem) begin - $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM); - $display("Read memfile %s", memfilename); - end - if (CopyRAM) begin - 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 - testbench.DCacheFlushFSM.ShadowRAM[ShadowIndex] = dut.core.lsu.dtim.dtim.ram.RAM[ShadowIndex - BaseIndex]; - end - end - end - end - - integer adrindex; - if (P.UNCORE_RAM_SUPPORTED) - always @(posedge clk) - if (ResetMem) // program memory is sometimes reset (e.g. for CoreMark, which needs zeroed memory) - for (adrindex=0; adrindex<(P.UNCORE_RAM_RANGE>>1+(P.XLEN/32)); adrindex = adrindex+1) - dut.uncoregen.uncore.ram.ram.memory.RAM[adrindex] = '0; - - //////////////////////////////////////////////////////////////////////////////// - // Actual hardware - //////////////////////////////////////////////////////////////////////////////// - - // instantiate device to be tested - assign GPIOIN = '0; - assign UARTSin = 1'b1; - assign SPIIn = 1'b0; - - if(P.EXT_MEM_SUPPORTED) begin - ram_ahb #(.P(P), .BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) - ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT), - .HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY, .HWSTRB); - end else begin - assign HREADYEXT = 1'b1; - assign {HRESPEXT, HRDATAEXT} = '0; - end - - if(P.SDC_SUPPORTED) begin : sdcard - // *** fix later -/* -----\/----- EXCLUDED -----\/----- - sdModel sdcard - (.sdClk(SDCCLK), - .cmd(SDCCmd), - .dat(SDCDat)); - - assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; - assign SDCCmdIn = SDCCmd; - assign SDCDat = sd_dat_reg_t ? sd_dat_reg_o : sd_dat_i; - assign SDCDatIn = SDCDat; - -----/\----- EXCLUDED -----/\----- */ - assign SDCIntr = 1'b0; - end else begin - assign SDCIntr = 1'b0; - end - - wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, - .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, - .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, - .UARTSin, .UARTSout, .SDCIntr, .SPIIn, .SPIOut, .SPICS); - - // generate clock to sequence tests - always begin - clk = 1'b1; # 5; clk = 1'b0; # 5; - end - - /* - // Print key info each cycle for debugging - 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 - */ - - //////////////////////////////////////////////////////////////////////////////// - // 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); // check if PCW is stuck - 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); - 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 - // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed - // or sw gp,-56(t0) for new Imperas tests - // or sd gp, -56(t0) - // or on a jump to self infinite loop (6f) for RISC-V Arch tests - logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls - if (P.ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM; - else assign ecf = 0; - always_comb begin - TestComplete = ecf & - (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)) | - ((InstrM == 32'h6f | InstrM == 32'hfc32a423 | InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | - ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"] & dut.core.lsu.IEUAdrM != 0) & InstrMName == "SW" ); - end - - DCacheFlushFSM #(P) DCacheFlushFSM(.clk, .start(DCacheFlushStart), .done(DCacheFlushDone)); - - if(P.ZICSR_SUPPORTED) begin - logic [P.XLEN-1:0] Minstret; - assign Minstret = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2]; - always @(negedge clk) begin - 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 - end - end -end - - - - - - - - - logic [P.XLEN-1:0] testadrNoBase; - - - string testName; - string testDir, adrstr; - - logic InitializingMemories; integer ResetCount, ResetThreshold; logic InReset; @@ -697,7 +97,7 @@ end initial begin ResetCount = 0; - ResetThreshold = 21; + ResetThreshold = 2; InReset = 1; testadr = 0; testadrNoBase = 0; @@ -710,7 +110,8 @@ end $error("Must specify test directory using plusarg testDir"); end - #130; + if (P.BUS_SUPPORTED) $readmemh(memfilename, dut.uncoregen.uncore.ram.ram.memory.RAM); + else $error("Imperas test bench requires BUS."); ProgramAddrMapFile = {testDir, "/ref/ref.elf.objdump.addr"}; ProgramLabelMapFile = {testDir, "/ref/ref.elf.objdump.lab"}; @@ -722,250 +123,229 @@ end end - - - - `ifdef USE_IMPERAS_DV - rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); - wallyTracer #(P) wallyTracer(rvvi); + rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); + wallyTracer #(P) wallyTracer(rvvi); - trace2log idv_trace2log(rvvi); - // trace2cov idv_trace2cov(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); + // 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); - string filename; - initial begin - int iter; - #1; - IDV_MAX_ERRORS = 3; - - // 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 - - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org")); - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv")); - void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GC")); - void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 56)); - void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); - - if(elffilename == "buildroot") filename = ""; - else filename = elffilename; - - if (!rvviRefInit(filename)) begin - $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); - $fatal; - 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 - - // User HPMCOUNTER3 - HPMCOUNTER31 - for (iter='hC03; iter<='hC1F; iter++) begin - void'(rvviRefCsrSetVolatile(0, iter)); // HPMCOUNTERx - end - - // Machine MHPMCOUNTER3 - MHPMCOUNTER31 - for (iter='hB03; iter<='hB1F; iter++) begin - void'(rvviRefCsrSetVolatile(0, iter)); // MHPMCOUNTERx - 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!!!! - - // Load memory - // *** RT: This section can probably be moved into the same chunk of code which - // loads the memories. However I'm not sure that ImperasDV supports reloading - // the memories without relaunching the simulator. - if(elffilename == "buildroot") begin - longint x64; - int x32[2]; - longint index; - string memfilenameImperasDV, bootmemfilenameImperasDV; + initial begin - memfilenameImperasDV = {RISCV_DIR, "/linux-testvectors/ram.bin"}; - bootmemfilenameImperasDV = {RISCV_DIR, "/linux-testvectors/bootmem.bin"}; + IDV_MAX_ERRORS = 3; - $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]); + // 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 - $fclose(memFile); - - $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]); + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org")); + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv")); + void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GC")); + void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 39)); + void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); + + if (!rvviRefInit(elffilename)) begin + $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); + $fatal; end - $fclose(memFile); + + // 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 - $display("RVVI Loading Complete"); + // 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!!!! - void'(rvviRefPcSet(0, P.RESET_VECTOR)); // set BOOTROM address end - end - 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])); + 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])); - final begin - void'(rvviRefShutdown()); - end + final begin + void'(rvviRefShutdown()); + end `endif - 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; - int fd, code; - string line; - int siglines, sigentries; + flopenr #(P.XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, InstrM, InstrW); - localparam SIGNATURESIZE = 5000000; - integer i; - logic [31:0] sig32[0:SIGNATURESIZE]; - logic [31:0] parsed; - logic [P.XLEN-1:0] signature[0:SIGNATURESIZE]; - string signame; - logic [P.XLEN-1:0] testadr, testadrNoBase; + // check assertions for a legal configuration + riscvassertions #(P) riscvassertions(); - //$display("Invoking CheckSignature %s %s %0t", pathname, TestName, $time); - - // read .signature.output file and compare to check for errors - 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 + // instantiate device to be tested + assign GPIOIN = 0; + assign UARTSin = 1; + + if(P.EXT_MEM_SUPPORTED) begin + ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) + 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 + + if(P.SDC_SUPPORTED) begin : sdcard + // *** fix later +/* -----\/----- EXCLUDED -----\/----- + sdModel sdcard + (.sdClk(SDCCLK), + .cmd(SDCCmd), + .dat(SDCDat)); + + assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; + assign SDCCmdIn = SDCCmd; + assign SDCDatIn = SDCDat; + -----/\----- EXCLUDED -----/\----- */ + assign SDCIntr = 0; + end else begin + assign SDCIntr = 0; + end + + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCIntr, .SPICS, .SPIOut, .SPIIn); + + // Track names of instructions + 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); + + // initialize tests + + // generate clock to sequence tests + always + begin + clk = 1; # 5; clk = 0; # 5; + // if ($time % 100000 == 0) $display("Time is %0t", $time); + end + + // check results + assign reset_ext = InReset; + + always @(negedge clk) + begin + 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. + InReset = 0; + ResetCount = 0; end end - $fclose(fd); - end + end // always @ (negedge clk) - // Check valid number of lines were read - 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 Date: Fri, 17 May 2024 17:10:15 -0500 Subject: [PATCH 11/12] wsim now supports lockstep and single elf example wsim rv64gc ../../tests/riscof/work/riscv-arch-test/rv64i_m/I/src/add-01.S/ref/ref.elf --elf --lockstep --- bin/wsim | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/bin/wsim b/bin/wsim index 531c6825c..4a4103242 100755 --- a/bin/wsim +++ b/bin/wsim @@ -25,9 +25,12 @@ parser.add_argument("--gui", "-g", help="Simulate with GUI", action="store_true" parser.add_argument("--coverage", "-c", help="Code & Functional Coverage", action="store_true") parser.add_argument("--args", "-a", help="Optional arguments passed to simulator via $value$plusargs", default="") parser.add_argument("--vcd", "-v", help="Generate testbench.vcd", action="store_true") +parser.add_argument("--lockstep", "-l", help="Run ImperasDV lock, step, and compare.", action="store_true") +parser.add_argument("--locksteplog", "-b", help="Retired instruction number to be begin logging.", default=0) args = parser.parse_args() print("Config=" + args.config + " tests=" + args.testsuite + " sim=" + args.sim + " gui=" + str(args.gui) + " args='" + args.args + "'") ElfFile="" + if(args.elf): ElfFile = "+ElfFile=" + args.testsuite args.testsuite = "none" @@ -55,21 +58,29 @@ for d in ["logs", "wkdir", "cov"]: except: pass + # Launch selected simulator cd = "cd $WALLY/sim/" +args.sim if (args.sim == "questa"): + if (args.lockstep): + Instret = str(args.locksteplog) + prefix ="IMPERAS_TOOLS=" + WALLY + "/sim/imperas.ic OTHERFLAGS=\"+IDV_TRACE2LOG=" + Instret + " +IDV_TRACE2COV=" + Instret + "\" "; + suffix = "--lockstep" + else: + prefix = "" + suffix = "" if (args.tb == "testbench_fp"): args.args = " -GTEST=\"" + args.testsuite + "\" " + args.args - cmd = "do wally.do " + args.config + " " + args.testsuite + " " + args.tb + " " + args.args + " " + ElfFile + cmd = "do wally.do " + args.config + " " + args.testsuite + " " + args.tb + " " + args.args + " " + ElfFile + " " + suffix if (args.coverage): cmd += " --coverage" if (args.gui): # launch Questa with GUI; add +acc to keep variables accessible if(args.tb == "testbench"): - cmd = cd + "; vsim -do \"" + cmd + " +acc -GDEBUG=1\"" + cmd = cd + "; " + prefix + " vsim -do \"" + cmd + " +acc -GDEBUG=1\"" elif(args.tb == "testbench_fp"): - cmd = cd + "; vsim -do \"" + cmd + " +acc\"" + cmd = cd + "; " + prefix + " vsim -do \"" + cmd + " +acc\"" else: # launch Questa in batch mode - cmd = cd + "; vsim -c -do \"" + cmd + "\"" + cmd = cd + "; " + prefix + " vsim -c -do \"" + cmd + "\"" print("Running Questa with command: " + cmd) os.system(cmd) elif (args.sim == "verilator"): From 6e3ccbb9c18a7961612713443aa64055e65f0119 Mon Sep 17 00:00:00 2001 From: Rose Thompson Date: Fri, 17 May 2024 17:34:29 -0500 Subject: [PATCH 12/12] Almost have it working for both buildroot and single elfs. --- testbench/testbench.sv | 104 +++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/testbench/testbench.sv b/testbench/testbench.sv index e32fdd9a8..71aaa8126 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -696,6 +696,10 @@ end 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; @@ -714,10 +718,55 @@ end if(elffilename == "buildroot") filename = ""; else filename = elffilename; - - if (!rvviRefInit(filename)) begin - $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); - $fatal; + + // 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 + end else begin // for buildroot use the binary instead to load teh reference model. + if (!rvviRefInit("")) begin // still have to call with nothing + $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); + $fatal; + 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); + + $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); + + $display("RVVI Loading Complete"); + + void'(rvviRefPcSet(0, P.RESET_VECTOR)); // set BOOTROM address end // Volatile CSRs @@ -773,53 +822,6 @@ end void'(rvviRefCsrSetVolatile(0, 32'h104)); // SIE - Temporary!!!! - // Load memory - // *** RT: This section can probably be moved into the same chunk of code which - // loads the memories. However I'm not sure that ImperasDV supports reloading - // the memories without relaunching the simulator. - if(elffilename == "buildroot") begin - longint x64; - int x32[2]; - longint index; - string memfilenameImperasDV, bootmemfilenameImperasDV; - - 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); - - $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); - - $display("RVVI Loading Complete"); - - void'(rvviRefPcSet(0, P.RESET_VECTOR)); // set BOOTROM address - end end always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));