From b2faf3c8888464484ab5e77f70137c133b56a183 Mon Sep 17 00:00:00 2001 From: Domenico Ottolia Date: Tue, 16 Mar 2021 16:11:20 -0400 Subject: [PATCH 01/10] Add privileged tests folder --- .../testgen/privileged/testgen-CAUSE.py | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 wally-pipelined/testgen/privileged/testgen-CAUSE.py diff --git a/wally-pipelined/testgen/privileged/testgen-CAUSE.py b/wally-pipelined/testgen/privileged/testgen-CAUSE.py new file mode 100644 index 00000000..c4b331ac --- /dev/null +++ b/wally-pipelined/testgen/privileged/testgen-CAUSE.py @@ -0,0 +1,154 @@ +#!/usr/bin/python3 +################################## +# testgen-CAUSE.py +# +# dottolia@hmc.edu 16 Mar 2021 +# +# Generate directed and random test vectors for RISC-V Design Validation. +################################## + +################################## +# libraries +################################## +from datetime import datetime +from random import randint +from random import seed +from enum import Enum +from random import getrandbits + +################################## +# functions +################################## + +# def computeExpected(a, b, test): +# if (test == "ADD"): +# return a + b +# elif (test == "SUB"): +# return a - b +# else: +# die("bad test name ", test) +# # exit(1) + +def randRegs(): + reg1 = randint(1,31) + reg2 = randint(1,31) + reg3 = randint(1,31) + if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): + return randRegs() + else: + return reg1, reg2, reg3 + +def writeVectors(storecmd): + reg1, reg2, reg3 = randRegs() + + lines = f""" + li x{reg1}, 0 + """ + + write(lines, storecmd, reg1, 0) + +def write(lines, storecmd, reg, expected): + global testnum + + lines = f""" + # Testcase {testnum} + {lines} + + {storecmd} x{reg}, {str(wordsize*testnum)}(x6) + #RVTEST_IO_ASSERT_GPR_EQ(x0, 0, {formatstr.format(expected)}) + """ + f.write(lines) + + if (xlen == 32): + line = formatrefstr.format(expected)+"\n" + else: + line = formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32) + "\n" + r.write(line) + testnum = testnum+1 + +################################## +# main body +################################## + +# name: (interrupt?, code) +tests = { + 'User software interrupt': (1, '0'), + 'Supervisor software interrupt': (1, '1'), + 'Machine software interrupt': (1, '3'), + 'User timer interrupt': (1, '4'), + 'Supervisor timer interrupt': (1, '5'), + 'Machine timer interrupt': (1, '7'), + 'User external interrupt': (1, '8'), + 'Supervisor external interrupt': (1, '9'), + 'Machine external interrupt': (1, '11'), + 'Instruction address misaligned': (0, '0'), + 'Instruction access fault': (0, '1'), + 'Illegal instruction': (0, '2'), + 'Breakpoint': (0, '3'), + 'Load address misaligned': (0, '4'), + 'Load access fault': (0, '5'), + 'Store/AMO address misaligned': (0, '6'), + 'Store/AMO access fault': (0, '7'), + 'Environment call from U-mode': (0, '8'), + 'Environment call from S-mode': (0, '9'), + 'Environment call from M-mode': (0, '11'), + 'Instruction page fault': (0, '12'), + 'Load page fault': (0, '13'), + 'Store/AMO page fault': (0, '15'), +} +author = "dottolia@hmc.edu" +xlens = [32, 64] +numrand = 60; + +# setup +seed(0xC395DDEB9173AD42) # make tests reproducible + +# generate files for each test +for xlen in xlens: + formatstrlen = str(int(xlen/4)) + formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number + formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x + if (xlen == 32): + storecmd = "sw" + wordsize = 4 + else: + storecmd = "sd" + wordsize = 8 + + imperaspath = "../../../imperas-riscv-tests/riscv-test-suite/privileged/" + basename = "WALLY-CAUSE-" + str(xlen) + fname = imperaspath + "src/" + basename + ".S" + refname = imperaspath + "references/" + basename + ".reference_output" + testnum = 0 + + # print custom header part + f = open(fname, "w") + r = open(refname, "w") + line = "///////////////////////////////////////////\n" + f.write(line) + lines="// "+fname+ "\n// " + author + "\n" + f.write(lines) + line ="// Created " + str(datetime.now()) + f.write(line) + + # insert generic header + h = open("../testgen_header.S", "r") + for line in h: + f.write(line) + + # print directed and random test vectors + writeVectors(storecmd) + + + # print footer + h = open("../testgen_footer.S", "r") + for line in h: + f.write(line) + + # Finish + lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + f.write(lines) + f.close() + r.close() + From f6cbe44cbd1b31535f8fe48071fad5ec54f8ca2c Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Tue, 16 Mar 2021 17:43:39 -0400 Subject: [PATCH 02/10] Change busybear to only check that first 100k instructions load --- wally-pipelined/regression/regression-wally.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wally-pipelined/regression/regression-wally.py b/wally-pipelined/regression/regression-wally.py index 6f89e56f..96a755b7 100755 --- a/wally-pipelined/regression/regression-wally.py +++ b/wally-pipelined/regression/regression-wally.py @@ -27,7 +27,7 @@ def test_config(config, print_res=True): cmd = "echo 'quit' | vsim -do wally-busybear.do -c >" + logname os.system(cmd) # check for success. grep returns 0 if found, 1 if not found - passed = search_log_for_text("no more .* to read", logname) + passed = search_log_for_text("# loaded 100000 instructions", logname) else: cmd = "vsim -c >" + logname +" < Date: Tue, 16 Mar 2021 18:15:13 -0400 Subject: [PATCH 03/10] Condense the parallel and non-parallel wally-pipelined-batch.do files into one --- .../regression/regression-wally.py | 4 +- .../wally-pipelined-batch-parallel.do | 38 ------------------- .../regression/wally-pipelined-batch.do | 13 ++++--- 3 files changed, 9 insertions(+), 46 deletions(-) delete mode 100644 wally-pipelined/regression/wally-pipelined-batch-parallel.do diff --git a/wally-pipelined/regression/regression-wally.py b/wally-pipelined/regression/regression-wally.py index 96a755b7..167ee57b 100755 --- a/wally-pipelined/regression/regression-wally.py +++ b/wally-pipelined/regression/regression-wally.py @@ -27,9 +27,9 @@ def test_config(config, print_res=True): cmd = "echo 'quit' | vsim -do wally-busybear.do -c >" + logname os.system(cmd) # check for success. grep returns 0 if found, 1 if not found - passed = search_log_for_text("# loaded 100000 instructions", logname) + passed = True# search_log_for_text("# loaded 100000 instructions", logname) else: - cmd = "vsim -c >" + logname +" <" + logname +" <" prompt: -# do wally-pipelined.do ../config/rv64ic -# or, to run from a shell, type the following at the shell prompt: -# vsim -c -do wally-pipelined.do ../config/rv64ic -# (omit the "-c" to see the GUI while running from the shell) - -onbreak {resume} - -# create library -if [file exists work$2] { - vdel -lib work$2 -all -} -vlib work$2 - -# compile source files -# suppress spurious warnngs about -# "Extra checking for conflicts with always_comb done at vopt time" -# because vsim will run vopt -vlog +incdir+$1 ../testbench/testbench-imperas.sv ../testbench/function_radix.sv ../src/*/*.sv -suppress 2583 - -# start and run simulation -# remove +acc flag for faster sim during regressions if there is no need to access internal signals -vopt work.testbench -o workopt -vsim workopt - -run -all -quit diff --git a/wally-pipelined/regression/wally-pipelined-batch.do b/wally-pipelined/regression/wally-pipelined-batch.do index 040c03c5..ad4c7507 100644 --- a/wally-pipelined/regression/wally-pipelined-batch.do +++ b/wally-pipelined/regression/wally-pipelined-batch.do @@ -17,10 +17,10 @@ onbreak {resume} # create library -if [file exists work] { - vdel -all +if [file exists work_$2] { + vdel -lib work_$2 -all } -vlib work +vlib work_$2 # compile source files # suppress spurious warnngs about @@ -28,15 +28,16 @@ vlib work # because vsim will run vopt # default to config/rv64ic, but allow this to be overridden at the command line. For example: -# do wally-pipelined-batch.do ../config/rv32ic +# do wally-pipelined-batch.do ../config/rv32ic rv32ic switch $argc { 0 {vlog +incdir+../config/rv64ic ../testbench/testbench-imperas.sv ../src/*/*.sv -suppress 2583} 1 {vlog +incdir+$1 ../testbench/testbench-imperas.sv ../src/*/*.sv -suppress 2583} + 2 {vlog -work work_$2 +incdir+$1 ../testbench/testbench-imperas.sv ../src/*/*.sv -suppress 2583} } # start and run simulation # remove +acc flag for faster sim during regressions if there is no need to access internal signals -vopt work.testbench -o workopt -vsim workopt +vopt work_$2.testbench -work work_$2 -o workopt_$2 +vsim -lib work_$2 workopt_$2 run -all quit From 152ffd16e2ed994b7ce46867abe87247cf310180 Mon Sep 17 00:00:00 2001 From: Jarred Allen Date: Tue, 16 Mar 2021 18:16:00 -0400 Subject: [PATCH 04/10] Undo accidental change --- wally-pipelined/regression/regression-wally.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wally-pipelined/regression/regression-wally.py b/wally-pipelined/regression/regression-wally.py index 167ee57b..68957cae 100755 --- a/wally-pipelined/regression/regression-wally.py +++ b/wally-pipelined/regression/regression-wally.py @@ -27,7 +27,7 @@ def test_config(config, print_res=True): cmd = "echo 'quit' | vsim -do wally-busybear.do -c >" + logname os.system(cmd) # check for success. grep returns 0 if found, 1 if not found - passed = True# search_log_for_text("# loaded 100000 instructions", logname) + passed = search_log_for_text("# loaded 100000 instructions", logname) else: cmd = "vsim -c >" + logname +" < Date: Tue, 16 Mar 2021 19:22:36 -0400 Subject: [PATCH 06/10] Add privileged tests for mcause --- .../testgen/privileged/testgen-CAUSE.py | 200 ++++++++++++++---- 1 file changed, 158 insertions(+), 42 deletions(-) diff --git a/wally-pipelined/testgen/privileged/testgen-CAUSE.py b/wally-pipelined/testgen/privileged/testgen-CAUSE.py index c4b331ac..7cc9fa54 100644 --- a/wally-pipelined/testgen/privileged/testgen-CAUSE.py +++ b/wally-pipelined/testgen/privileged/testgen-CAUSE.py @@ -30,33 +30,149 @@ from random import getrandbits # # exit(1) def randRegs(): - reg1 = randint(1,31) - reg2 = randint(1,31) - reg3 = randint(1,31) + reg1 = randint(1,30) + reg2 = randint(1,30) + reg3 = randint(1,30) if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2): return randRegs() else: return reg1, reg2, reg3 def writeVectors(storecmd): + global testnum reg1, reg2, reg3 = randRegs() + # t5 gets written with mtvec? + + # lines = f""" + + # li x{reg1}, 0 + # csrwi mtvec, 80002000 + # .data 00000000 + # j _done{testnum} + + # _trap{testnum}: + # csrrs x{reg1}, mcause, x0 + # ecall + + # _done{testnum}: + # add x0, x0, x0 + # """ + + #lines = + lines = f""" - li x{reg1}, 0 + j _setup + csrrs x31, mcause, x0 + ecall + + _setup: + li x2, 0x80000004 + csrrw x0, mtvec, x2 + """ + f.write(lines) - write(lines, storecmd, reg1, 0) + # User Software Interrupt + write(f""" + li x3, 0x8000000 + {storecmd} x2, 0(x3) + """, storecmd, True, 0, "u") -def write(lines, storecmd, reg, expected): + # Supervisor Software Interrupt + write(f""" + li x3, 0x8000000 + {storecmd} x2, 0(x3) + """, storecmd, True, 0, "s") + + # Machine Software Interrupt + write(f""" + li x3, 0x8000000 + {storecmd} x2, 0(x3) + """, storecmd, True, 3) + + # User Timer Interrupt + #write(f""" + # lw x2, mtimecmp + # {storecmd} x2, mtimecmp + #""", storecmd, True, 4, "u") + + # # Supervisor Timer Interrupt + #write(f""" + # lw x2, mtimecmp + # {storecmd} x2, mtimecmp + #""", storecmd, True, 5, "s") + + # Machine Timer Interrupt + #write(f""" + # lw x2, mtimecmp + # {storecmd} x2, mtimecmp + #""", storecmd, True, 6) + + # User external interrupt True, 8 + # Supervisor external interrupt True, 9 + + # Instr Addr Misalign + write(f""" + li x2, 0x00000000 + lw x3, 11(x2) + """, storecmd, False, 0) + + # Instr Access Fault False, 1 + # Not possible in machine mode, because we can access all memory + + # Illegal Instruction + write(f""" + .data 00000000 + """, storecmd, False, 2) + + # Breakpoint + write(f""" + ebreak + """, storecmd, False, 3) + + # Load Addr Misalign + write(f""" + li x2, 0x00000000 + lw x3, 11(x2) + """, storecmd, False, 4) + + # Load Access Fault False, 5 + # Not possible in machine mode, because we can access all memory + + + # Store/AMO address misaligned + write(f""" + li x2, 0x00000000 + {storecmd} x3, 11(x2) + """, storecmd, False, 6) + + # Store/AMO access fault False, 7 + # Not possible in machine mode, because we can access all memory + + # Environment call from U-mode + # Environment call from S-mode + +def write(lines, storecmd, interrupt, code, mode = "m"): global testnum + # generate expected interrupt code + expected = (0 if not interrupt else (2**31 if xlen == 32 else 2**63)) + code + lines = f""" # Testcase {testnum} + li x31, 0 {lines} - {storecmd} x{reg}, {str(wordsize*testnum)}(x6) - #RVTEST_IO_ASSERT_GPR_EQ(x0, 0, {formatstr.format(expected)}) + {storecmd} x31, {str(wordsize*testnum)}(x6) + # RVTEST_IO_ASSERT_GPR_EQ(x0, 0, {formatstr.format(expected)}) """ + + #if mode == "s": + # go to supervisor mode + #elif mode == "u": + # go to user mode + f.write(lines) if (xlen == 32): @@ -71,31 +187,31 @@ def write(lines, storecmd, reg, expected): ################################## # name: (interrupt?, code) -tests = { - 'User software interrupt': (1, '0'), - 'Supervisor software interrupt': (1, '1'), - 'Machine software interrupt': (1, '3'), - 'User timer interrupt': (1, '4'), - 'Supervisor timer interrupt': (1, '5'), - 'Machine timer interrupt': (1, '7'), - 'User external interrupt': (1, '8'), - 'Supervisor external interrupt': (1, '9'), - 'Machine external interrupt': (1, '11'), - 'Instruction address misaligned': (0, '0'), - 'Instruction access fault': (0, '1'), - 'Illegal instruction': (0, '2'), - 'Breakpoint': (0, '3'), - 'Load address misaligned': (0, '4'), - 'Load access fault': (0, '5'), - 'Store/AMO address misaligned': (0, '6'), - 'Store/AMO access fault': (0, '7'), - 'Environment call from U-mode': (0, '8'), - 'Environment call from S-mode': (0, '9'), - 'Environment call from M-mode': (0, '11'), - 'Instruction page fault': (0, '12'), - 'Load page fault': (0, '13'), - 'Store/AMO page fault': (0, '15'), -} +# tests = { +# 'User software interrupt': (1, '0'), +# 'Supervisor software interrupt': (1, '1'), +# 'Machine software interrupt': (1, '3'), +# 'User timer interrupt': (1, '4'), +# 'Supervisor timer interrupt': (1, '5'), +# 'Machine timer interrupt': (1, '7'), +# 'User external interrupt': (1, '8'), +# 'Supervisor external interrupt': (1, '9'), +# 'Machine external interrupt': (1, '11'), +# 'Instruction address misaligned': (0, '0'), +# 'Instruction access fault': (0, '1'), +# 'Illegal instruction': (0, '2'), +# 'Breakpoint': (0, '3'), +# 'Load address misaligned': (0, '4'), +# 'Load access fault': (0, '5'), +# 'Store/AMO address misaligned': (0, '6'), +# 'Store/AMO access fault': (0, '7'), +# 'Environment call from U-mode': (0, '8'), +# 'Environment call from S-mode': (0, '9'), +# 'Environment call from M-mode': (0, '11'), +# 'Instruction page fault': (0, '12'), +# 'Load page fault': (0, '13'), +# 'Store/AMO page fault': (0, '15'), +# } author = "dottolia@hmc.edu" xlens = [32, 64] numrand = 60; @@ -132,23 +248,23 @@ for xlen in xlens: f.write(line) # insert generic header - h = open("../testgen_header.S", "r") - for line in h: - f.write(line) + # h = open("../testgen_header.S", "r") + # for line in h: + # f.write(line) # print directed and random test vectors writeVectors(storecmd) # print footer - h = open("../testgen_footer.S", "r") - for line in h: - f.write(line) + # h = open("../testgen_footer.S", "r") + # for line in h: + # f.write(line) # Finish - lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" - lines = lines + "\nRV_COMPLIANCE_DATA_END\n" - f.write(lines) + # lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n" + # lines = lines + "\nRV_COMPLIANCE_DATA_END\n" + # f.write(lines) f.close() r.close() From d354cbd37d70ed3b14a5d13b214ae422f833949f Mon Sep 17 00:00:00 2001 From: Domenico Ottolia Date: Tue, 16 Mar 2021 20:28:38 -0400 Subject: [PATCH 07/10] Add privileged testbench --- .../testbench/testbench-privileged.sv | 305 ++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 wally-pipelined/testbench/testbench-privileged.sv diff --git a/wally-pipelined/testbench/testbench-privileged.sv b/wally-pipelined/testbench/testbench-privileged.sv new file mode 100644 index 00000000..410dd62e --- /dev/null +++ b/wally-pipelined/testbench/testbench-privileged.sv @@ -0,0 +1,305 @@ +/////////////////////////////////////////// +// testbench-privileged.sv +// +// Written: Ben Bracker (bbracker@hmc.edu) 11 Feb. 2021, Tiny Modifications: Domenico Ottolia (dottolia@hmc.edu) 16 Mar. 2021 +// Based on: testbench-imperas.sv by David Harris +// +// Purpose: Wally Testbench and helper modules +// Applies test programs meant to test peripherals +// These tests assume the processor itself is already working! +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +`include "wally-config.vh" + +module testbench(); + logic clk; + logic reset; + + int test, i, errors, totalerrors; + logic [31:0] sig32[0:10000]; + logic [`XLEN-1:0] signature[0:10000]; + logic [`XLEN-1:0] testadr; + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + logic [`XLEN-1:0] meminit; + + string tests[] = '{ + "privileged/WALLY-CAUSE-64", "0" + }; + + logic [`AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic [31:0] HADDR; + logic [`AHBW-1:0] HWDATA; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic HCLK, HRESETn; + + + // pick tests based on modes supported + // *** actually I no longer support this + // would need to put this back in if you wanted to test anything other than rv64i + + string signame, memfilename; + + logic [31:0] GPIOPinsIn, GPIOPinsOut, GPIOPinsEn; + logic UARTSin, UARTSout; + + // instantiate device to be tested + assign GPIOPinsIn = 0; + assign UARTSin = 1; + assign HREADYEXT = 1; + assign HRESPEXT = 0; + assign HRDATAEXT = 0; + + wallypipelinedsoc dut(.*); + + // Track names of instructions + instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE, + dut.hart.ifu.InstrD, dut.hart.ifu.InstrE, + dut.hart.ifu.InstrM, InstrW, + InstrDName, InstrEName, InstrMName, InstrWName); + + // initialize tests + initial + begin + test = 0; + totalerrors = 0; + testadr = 0; + // fill memory with defined values to reduce Xs in simulation + if (`XLEN == 32) meminit = 32'hFEDC0123; + else meminit = 64'hFEDCBA9876543210; + for (i=0; i<=65535; i = i+1) begin + //dut.imem.RAM[i] = meminit; + // dut.uncore.RAM[i] = meminit; + end + // read test vectors into memory + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + reset = 1; # 22; reset = 0; + end + + // generate clock to sequence tests + always + begin + clk = 1; # 5; clk = 0; # 5; + end + + // check results + always @(negedge clk) + begin + if (dut.hart.priv.EcallFaultM && + (dut.hart.ieu.dp.regf.rf[3] == 1 || (dut.hart.ieu.dp.regf.we3 && dut.hart.ieu.dp.regf.a3 == 3 && dut.hart.ieu.dp.regf.wd3 == 1))) begin + $display("Code ended with ecall with gp = 1"); + #60; // give time for instructions in pipeline to finish + // clear signature to prevent contamination from previous tests + for(i=0; i<10000; i=i+1) begin + sig32[i] = 'bx; + end + + // read signature, reformat in 64 bits if necessary + signame = {"../../imperas-riscv-tests/work/", tests[test], ".signature.output"}; + $readmemh(signame, sig32); + i = 0; + while (i < 10000) begin + if (`XLEN == 32) begin + signature[i] = sig32[i]; + i = i+1; + end else begin + signature[i/2] = {sig32[i+1], sig32[i]}; + i = i + 2; + end + end + + // Check errors + i = 0; + errors = 0; + if (`XLEN == 32) + testadr = (`TIMBASE+tests[test+1].atohex())/4; + else + testadr = (`TIMBASE+tests[test+1].atohex())/8; + /* verilator lint_off INFINITELOOP */ + while (signature[i] !== 'bx) begin + //$display("signature[%h] = %h", i, signature[i]); + if (signature[i] !== dut.uncore.dtim.RAM[testadr+i]) begin + if (signature[i+4] !== 'bx || signature[i] !== 32'hFFFFFFFF) begin + // report errors unless they are garbage at the end of the sim + // kind of hacky test for garbage right now + errors = errors+1; + $display(" Error on test %s result %d: adr = %h sim = %h, signature = %h", + tests[test], i, (testadr+i)*`XLEN/8, dut.uncore.dtim.RAM[testadr+i], signature[i]); + end + end + i = i + 1; + end + /* verilator lint_on INFINITELOOP */ + if (errors == 0) $display("%s succeeded. Brilliant!!!", tests[test]); + else begin + $display("%s failed with %d errors. :(", tests[test], errors); + totalerrors = totalerrors+1; + end + test = test + 2; + if (test == tests.size()) begin + if (totalerrors == 0) $display("SUCCESS! All tests ran without failures."); + else $display("FAIL: %d test programs had errors", totalerrors); + $stop; + end + else begin + memfilename = {"../../imperas-riscv-tests/work/", tests[test], ".elf.memfile"}; + $readmemh(memfilename, dut.imem.RAM); + $readmemh(memfilename, dut.uncore.dtim.RAM); + $display("Read memfile %s", memfilename); + reset = 1; # 17; reset = 0; + end + end + end +endmodule + +/* verilator lint_on STMTDLY */ +/* verilator lint_on WIDTH */ + +module instrTrackerTB( + input logic clk, reset, FlushE, + input logic [31:0] InstrD, + input logic [31:0] InstrE, InstrM, + output logic [31:0] InstrW, + output string InstrDName, InstrEName, InstrMName, InstrWName); + + // stage Instr to Writeback for visualization + flopr #(32) InstrWReg(clk, reset, InstrM, InstrW); + + instrNameDecTB ddec(InstrD, InstrDName); + instrNameDecTB edec(InstrE, InstrEName); + instrNameDecTB mdec(InstrM, InstrMName); + instrNameDecTB wdec(InstrW, InstrWName); +endmodule + +// decode the instruction name, to help the test bench +module instrNameDecTB( + input logic [31:0] instr, + output string name); + + logic [6:0] op; + logic [2:0] funct3; + logic [6:0] funct7; + logic [11:0] imm; + + assign op = instr[6:0]; + assign funct3 = instr[14:12]; + assign funct7 = instr[31:25]; + assign imm = instr[31:20]; + + // it would be nice to add the operands to the name + // create another variable called decoded + + always_comb + casez({op, funct3}) + 10'b0000000_000: name = "BAD"; + 10'b0000011_000: name = "LB"; + 10'b0000011_001: name = "LH"; + 10'b0000011_010: name = "LW"; + 10'b0000011_011: name = "LD"; + 10'b0000011_100: name = "LBU"; + 10'b0000011_101: name = "LHU"; + 10'b0000011_110: name = "LWU"; + 10'b0010011_000: if (instr[31:15] == 0 && instr[11:7] ==0) name = "NOP/FLUSH"; + else name = "ADDI"; + 10'b0010011_001: if (funct7[6:1] == 6'b000000) name = "SLLI"; + else name = "ILLEGAL"; + 10'b0010011_010: name = "SLTI"; + 10'b0010011_011: name = "SLTIU"; + 10'b0010011_100: name = "XORI"; + 10'b0010011_101: if (funct7[6:1] == 6'b000000) name = "SRLI"; + else if (funct7[6:1] == 6'b010000) name = "SRAI"; + else name = "ILLEGAL"; + 10'b0010011_110: name = "ORI"; + 10'b0010011_111: name = "ANDI"; + 10'b0010111_???: name = "AUIPC"; + 10'b0100011_000: name = "SB"; + 10'b0100011_001: name = "SH"; + 10'b0100011_010: name = "SW"; + 10'b0100011_011: name = "SD"; + 10'b0011011_000: name = "ADDIW"; + 10'b0011011_001: name = "SLLIW"; + 10'b0011011_101: if (funct7 == 7'b0000000) name = "SRLIW"; + else if (funct7 == 7'b0100000) name = "SRAIW"; + else name = "ILLEGAL"; + 10'b0111011_000: if (funct7 == 7'b0000000) name = "ADDW"; + else if (funct7 == 7'b0100000) name = "SUBW"; + else name = "ILLEGAL"; + 10'b0111011_001: name = "SLLW"; + 10'b0111011_101: if (funct7 == 7'b0000000) name = "SRLW"; + else if (funct7 == 7'b0100000) name = "SRAW"; + else name = "ILLEGAL"; + 10'b0110011_000: if (funct7 == 7'b0000000) name = "ADD"; + else if (funct7 == 7'b0000001) name = "MUL"; + else if (funct7 == 7'b0100000) name = "SUB"; + else name = "ILLEGAL"; + 10'b0110011_001: if (funct7 == 7'b0000000) name = "SLL"; + else if (funct7 == 7'b0000001) name = "MULH"; + else name = "ILLEGAL"; + 10'b0110011_010: if (funct7 == 7'b0000000) name = "SLT"; + else if (funct7 == 7'b0000001) name = "MULHSU"; + else name = "ILLEGAL"; + 10'b0110011_011: if (funct7 == 7'b0000000) name = "SLTU"; + else if (funct7 == 7'b0000001) name = "DIV"; + else name = "ILLEGAL"; + 10'b0110011_100: if (funct7 == 7'b0000000) name = "XOR"; + else if (funct7 == 7'b0000001) name = "MUL"; + else name = "ILLEGAL"; + 10'b0110011_101: if (funct7 == 7'b0000000) name = "SRL"; + else if (funct7 == 7'b0000001) name = "DIVU"; + else if (funct7 == 7'b0100000) name = "SRA"; + else name = "ILLEGAL"; + 10'b0110011_110: if (funct7 == 7'b0000000) name = "OR"; + else if (funct7 == 7'b0000001) name = "REM"; + else name = "ILLEGAL"; + 10'b0110011_111: if (funct7 == 7'b0000000) name = "AND"; + else if (funct7 == 7'b0000001) name = "REMU"; + else name = "ILLEGAL"; + 10'b0110111_???: name = "LUI"; + 10'b1100011_000: name = "BEQ"; + 10'b1100011_001: name = "BNE"; + 10'b1100011_100: name = "BLT"; + 10'b1100011_101: name = "BGE"; + 10'b1100011_110: name = "BLTU"; + 10'b1100011_111: name = "BGEU"; + 10'b1100111_000: name = "JALR"; + 10'b1101111_???: name = "JAL"; + 10'b1110011_000: if (imm == 0) name = "ECALL"; + else if (imm == 1) name = "EBREAK"; + else if (imm == 2) name = "URET"; + else if (imm == 258) name = "SRET"; + else if (imm == 770) name = "MRET"; + else name = "ILLEGAL"; + 10'b1110011_001: name = "CSRRW"; + 10'b1110011_010: name = "CSRRS"; + 10'b1110011_011: name = "CSRRC"; + 10'b1110011_101: name = "CSRRWI"; + 10'b1110011_110: name = "CSRRSI"; + 10'b1110011_111: name = "CSRRCI"; + 10'b0001111_???: name = "FENCE"; + default: name = "ILLEGAL"; + endcase +endmodule From e7fae21eb895a43c8835b618a8032fe58f9d09c8 Mon Sep 17 00:00:00 2001 From: Noah Boorstin Date: Tue, 16 Mar 2021 21:08:47 -0400 Subject: [PATCH 08/10] busybear: add COUNTERS define --- wally-pipelined/config/busybear/wally-config.vh | 1 + 1 file changed, 1 insertion(+) diff --git a/wally-pipelined/config/busybear/wally-config.vh b/wally-pipelined/config/busybear/wally-config.vh index dc4d6451..5a07bf55 100644 --- a/wally-pipelined/config/busybear/wally-config.vh +++ b/wally-pipelined/config/busybear/wally-config.vh @@ -38,6 +38,7 @@ `define U_SUPPORTED ((`MISA >> 20) % 2 == 1) `define ZCSR_SUPPORTED 1 `define ZCOUNTERS_SUPPORTED 1 +`define COUNTERS 31 // N-mode user-level interrupts are depricated per Andrew Waterman 1/13/21 //`define N_SUPPORTED ((MISA >> 13) % 2 == 1) `define N_SUPPORTED 0 From bfa7aedd3591a8a71a514d7bd093550f4800b15f Mon Sep 17 00:00:00 2001 From: Noah Boorstin Date: Tue, 16 Mar 2021 21:42:26 -0400 Subject: [PATCH 09/10] busybear: add seperate message on bad memory access becasue its confusing --- wally-pipelined/testbench/testbench-busybear.sv | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/wally-pipelined/testbench/testbench-busybear.sv b/wally-pipelined/testbench/testbench-busybear.sv index abd830b8..e9d0621c 100644 --- a/wally-pipelined/testbench/testbench-busybear.sv +++ b/wally-pipelined/testbench/testbench-busybear.sv @@ -106,6 +106,7 @@ module testbench_busybear(); end integer warningCount = 0; + integer instrs; //logic[63:0] adrTranslation[4:0]; //string translationType[4:0] = {"rf", "writeAdr", "PCW", "PC", "readAdr"}; @@ -249,6 +250,15 @@ module testbench_busybear(); end end + always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin + if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 5 && instrs != 0) begin + $display("!!!!!!illegal (physical) memory access !!!!!!!!!!"); + $display("(as a reminder, MCAUSE and MEPC are set by this)"); + $display("at %0t ps, instr %0d, HADDR %x", $time, instrs, HADDR); + `ERROR + end + end + `define CHECK_CSR2(CSR, PATH) \ string CSR; \ logic [63:0] expected``CSR``; \ @@ -340,7 +350,6 @@ module testbench_busybear(); end string PCtext, PCtext2; - integer instrs; initial begin instrs = 0; end From 748372dc45376a5e8a7d4f3af08490534a04b1aa Mon Sep 17 00:00:00 2001 From: Domenico Ottolia Date: Tue, 16 Mar 2021 23:26:59 -0400 Subject: [PATCH 10/10] Add test runner for privileged --- wally-pipelined/testgen/privileged/run.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 wally-pipelined/testgen/privileged/run.sh diff --git a/wally-pipelined/testgen/privileged/run.sh b/wally-pipelined/testgen/privileged/run.sh new file mode 100644 index 00000000..13c7c2b0 --- /dev/null +++ b/wally-pipelined/testgen/privileged/run.sh @@ -0,0 +1,22 @@ +clear +printf "\n\n#####\nStarting tests for $1\n#####\n\n" + +if [[ "$2" != "-simonly" ]] +then + cd ~/riscv-wally/wally-pipelined/testgen/privileged + python3 "testgen-$1.py" + printf "\n\n#####\nRan testgen-$1.py Making...\n#####\n\n\n" + + cd ~/riscv-wally/imperas-riscv-tests + make privileged +fi + +if [[ "$2" == "-sim" || "$2" == "-simonly" ]] +then + printf "\n\n\n#####\nSimulating!\n#####\n\n" + cd ~/riscv-wally/wally-pipelined/regression + vsim -do wally-privileged.do -c +fi + +cd ~/riscv-wally +printf "\n\n\n#####\nDone!\n#####\n\n" \ No newline at end of file