diff --git a/bin/wsim b/bin/wsim index 9c4cce68f..4a4103242 100755 --- a/bin/wsim +++ b/bin/wsim @@ -18,14 +18,22 @@ 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") 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" # Validate arguments if (args.gui): @@ -50,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 + 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"): 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/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} diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 41238a9d0..71aaa8126 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 @@ -257,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; @@ -356,21 +364,27 @@ 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"}; + 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 - 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 + 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 @@ -410,6 +424,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 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 @@ -669,10 +692,17 @@ end .CMP_CSR (1) ) idv_trace2api(rvvi); + string filename; initial begin + // imperasDV requires the elffile be defined at the begining of the simulation. int iter; + longint x64; + int x32[2]; + longint index; + string memfilenameImperasDV, bootmemfilenameImperasDV; #1; IDV_MAX_ERRORS = 3; + elffilename = ElfFile; // Initialize REF (do this before initializing the DUT) if (!rvviVersionCheck(RVVI_API_VERSION)) begin @@ -686,9 +716,57 @@ end void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH, 56)); void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); - if (!rvviRefInit("")) begin - $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); - $fatal; + if(elffilename == "buildroot") filename = ""; + else filename = elffilename; + + // use the ImperasDV rvviRefInit to load the reference model with an elf file + if(elffilename != "none") begin + if (!rvviRefInit(filename)) begin + $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); + $fatal; + end + 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 @@ -744,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. - 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]));