diff --git a/sim/imperas.ic b/sim/imperas.ic index 3744a426..82aedf1c 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -1,5 +1,7 @@ -#--showoverrides -#--showcommands +#--mpdconsole refRoot +#--gdbconsole +--showoverrides +--showcommands # Core settings --override cpu/unaligned=F @@ -9,7 +11,14 @@ --override cpu/misa_Extensions_mask=0x0 # THIS NEEDS FIXING to 16 ---override cpu/PMP_registers=0 +--override cpu/PMP_registers=16 +--override cpu/PMP_undefined=T + +# Illegal instruction should not contain the bit pattern +# illegal pmp read contained this +# --override cpu/tval_ii_code=F + +--registerset cpu/SCOUNTEREN=0x1 # PMA Settings # 'r': read access allowed @@ -24,16 +33,16 @@ # '8': 8-byte accesses allowed # '-', space: ignored (use for input string formatting). # -# SV39 Memory 0x0000000000 0x7FFFFFFFFF +# SVxx Memory 0x0000000000 0x7FFFFFFFFF # ---callcommand refRoot/cpu/setPMA -lo 0x0000000000 -hi 0x7FFFFFFFFF -attributes " ------ ---- "; # INITIAL ---callcommand refRoot/cpu/setPMA -lo 0x0000001000 -hi 0x0000001FFF -attributes " r-x-A- 1248 "; # BOOTROM ---callcommand refRoot/cpu/setPMA -lo 0x0000012100 -hi 0x000001211F -attributes " rw--A- --48 "; # SDC ---callcommand refRoot/cpu/setPMA -lo 0x0002000000 -hi 0x000200FFFF -attributes " rw--A- 1248 "; # CLINT ---callcommand refRoot/cpu/setPMA -lo 0x000C000000 -hi 0x000FFFFFFF -attributes " rw--A- --4- "; # PLIC ---callcommand refRoot/cpu/setPMA -lo 0x0010000000 -hi 0x0010000007 -attributes " rw--A- 1--- "; # UART0 error - 0x10000000 - 0x100000FF ---callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- "; # GPIO error - 0x10006000 - 0x100060FF ---callcommand refRoot/cpu/setPMA -lo 0x0080000000 -hi 0x008FFFFFFF -attributes " rwx--- 1248 "; # UNCORE_RAM +--callcommand refRoot/cpu/setPMA -lo 0x0000000000 -hi 0x7FFFFFFFFF -attributes " ------ ---- " # INITIAL +--callcommand refRoot/cpu/setPMA -lo 0x0000001000 -hi 0x0000001FFF -attributes " r-x-A- 1248 " # BOOTROM +--callcommand refRoot/cpu/setPMA -lo 0x0000012100 -hi 0x000001211F -attributes " rw--A- --48 " # SDC +--callcommand refRoot/cpu/setPMA -lo 0x0002000000 -hi 0x000200FFFF -attributes " rw--A- 1248 " # CLINT +--callcommand refRoot/cpu/setPMA -lo 0x000C000000 -hi 0x000FFFFFFF -attributes " rw--A- --4- " # PLIC +--callcommand refRoot/cpu/setPMA -lo 0x0010000000 -hi 0x0010000007 -attributes " rw--A- 1--- " # UART0 error - 0x10000000 - 0x100000FF +--callcommand refRoot/cpu/setPMA -lo 0x0010060000 -hi 0x00100600FF -attributes " rw--A- --4- " # GPIO error - 0x10006000 - 0x100060FF +--callcommand refRoot/cpu/setPMA -lo 0x0080000000 -hi 0x008FFFFFFF -attributes " rwx--- 1248 " # UNCORE_RAM # Enable the Imperas instruction coverage #-extlib refRoot/cpu/cv=imperas.com/intercept/riscvInstructionCoverage/1.0 @@ -42,7 +51,7 @@ # Add Imperas simulator application instruction tracing --override cpu/show_c_prefix=T ---trace --tracechange --traceshowicount --tracemode -tracemem ASX --monitornetschange +--trace --tracechange --traceshowicount --tracemode -tracemem ASX --monitornetschange --traceafter 10000000 # Exceptions and pagetables debug --override cpu/debugflags=6 diff --git a/sim/run-imperas-linux.sh b/sim/run-imperas-linux.sh new file mode 100755 index 00000000..5a21b0eb --- /dev/null +++ b/sim/run-imperas-linux.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export RISCV=/scratch/moore/RISCV + +export IMPERAS_TOOLS=$(pwd)/imperas.ic +export OTHERFLAGS="+TRACE2LOG_ENABLE=1" +export OTHERFLAGS="+TRACE2LOG_ENABLE=1 +TRACE2LOG_AFTER=10000000" + +vsim -c -do "do wally-linux-imperas.do buildroot buildroot-no-trace $::env(RISCV) 0 0 0" diff --git a/sim/wally-imperas-cov.do b/sim/wally-imperas-cov.do index dc9e28db..567ef6b1 100644 --- a/sim/wally-imperas-cov.do +++ b/sim/wally-imperas-cov.do @@ -51,7 +51,7 @@ vlog +incdir+../config/$1 \ -suppress 7063 \ +acc vopt +acc work.testbench -G DEBUG=1 -o workopt -vsim workopt +nowarn3829 -fatal 7 \ +eval vsim workopt +nowarn3829 -fatal 7 \ -sv_lib $env(IMPERAS_HOME)/lib/Linux64/ImperasLib/imperas.com/verification/riscv/1.0/model \ +testDir=$env(TESTDIR) $env(OTHERFLAGS) +TRACE2COV_ENABLE=1 \ -do "coverage save -onexit ./riscv.ucdb" diff --git a/sim/wally-imperas-no-idv.do b/sim/wally-imperas-no-idv.do index 5f300250..6050211b 100644 --- a/sim/wally-imperas-no-idv.do +++ b/sim/wally-imperas-no-idv.do @@ -34,7 +34,7 @@ vlog +incdir+../config/$1 \ -suppress 2583 \ -suppress 7063 vopt +acc work.testbench -G DEBUG=1 -o workopt -vsim workopt +nowarn3829 -fatal 7 \ +eval vsim workopt +nowarn3829 -fatal 7 \ +testDir=$env(TESTDIR) $env(OTHERFLAGS) view wave #-- display input and output signals as hexidecimal values diff --git a/sim/wally-imperas.do b/sim/wally-imperas.do index 2de97be2..14634c61 100644 --- a/sim/wally-imperas.do +++ b/sim/wally-imperas.do @@ -45,7 +45,7 @@ vlog +incdir+../config/$1 \ -suppress 7063 vopt +acc work.testbench -G DEBUG=1 -o workopt -vsim workopt +nowarn3829 -fatal 7 \ +eval vsim workopt +nowarn3829 -fatal 7 \ -sv_lib $env(IMPERAS_HOME)/lib/Linux64/ImperasLib/imperas.com/verification/riscv/1.0/model \ +testDir=$env(TESTDIR) $env(OTHERFLAGS) view wave diff --git a/sim/wally-linux-imperas.do b/sim/wally-linux-imperas.do new file mode 100644 index 00000000..a95dc51a --- /dev/null +++ b/sim/wally-linux-imperas.do @@ -0,0 +1,150 @@ +# wally.do +# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +# +# Modification by Oklahoma State University & Harvey Mudd College +# Use with Testbench +# James Stine, 2008; David Harris 2021 +# Go Cowboys!!!!!! +# +# Takes 1:10 to run RV64IC tests using gui + +# run with vsim -do "do wally-pipelined.do rv64ic riscvarchtest-64m" + +# Use this wally-pipelined.do file to run this example. +# Either bring up ModelSim and type the following at the "ModelSim>" prompt: +# do wally.do +# or, to run from a shell, type the following at the shell prompt: +# vsim -do wally.do -c +# (omit the "-c" to see the GUI while running from the shell) + +onbreak {resume} + +# create library +if [file exists work] { + vdel -all +} +vlib work + +# compile source files +# suppress spurious warnngs about +# "Extra checking for conflicts with always_comb done at vopt time" +# because vsim will run vopt + +# start and run simulation +# remove +acc flag for faster sim during regressions if there is no need to access internal signals +if {$2 eq "buildroot" || $2 eq "buildroot-checkpoint"} { + vlog -lint -work work_${1}_${2} +incdir+../config/$1 +incdir+../config/shared ../testbench/testbench-linux.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv -suppress 2583 + # start and run simulation + vopt +acc work_${1}_${2}.testbench -work work_${1}_${2} -G RISCV_DIR=$3 -G INSTR_LIMIT=$4 -G INSTR_WAVEON=$5 -G CHECKPOINT=$6 -G NO_SPOOFING=0 -o testbenchopt + vsim -lib work_${1}_${2} testbenchopt -suppress 8852,12070,3084,3829,13286 -fatal 7 + + #-- Run the Simulation + #run -all + add log -recursive /* + do linux-wave.do + run -all + + exec ./slack-notifier/slack-notifier.py + +} elseif {$2 eq "buildroot-no-trace"} { + vlog -lint -work work_${1}_${2} \ + +define+USE_IMPERAS_DV \ + +incdir+../config/$1 \ + +incdir+../config/shared \ + +incdir+$env(IMPERAS_HOME)/ImpPublic/include/host \ + +incdir+$env(IMPERAS_HOME)/ImpProprietary/include/host \ + $env(IMPERAS_HOME)/ImpPublic/source/host/rvvi/rvvi-api-pkg.sv \ + $env(IMPERAS_HOME)/ImpPublic/source/host/rvvi/rvvi-trace.sv \ + $env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/rvvi-pkg.sv \ + $env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/imperasDV-api-pkg.sv \ + $env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/trace2api.sv \ + $env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/trace2log.sv \ + $env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/trace2cov.sv \ + ../testbench/testbench-linux-imperas.sv \ + ../testbench/common/*.sv ../src/*/*.sv \ + ../src/*/*/*.sv -suppress 2583 + + # + # start and run simulation + # for profiling add + # vopt -fprofile + # vsim -fprofile+perf + # visualizer -fprofile+perf+dir=fprofile + # + eval vopt +acc work_${1}_${2}.testbench -work work_${1}_${2} -G RISCV_DIR=$3 \ + -G INSTR_LIMIT=0 -G INSTR_WAVEON=0 -G CHECKPOINT=0 -G NO_SPOOFING=1 -o testbenchopt + eval vsim -lib work_${1}_${2} testbenchopt -suppress 8852,12070,3084,3829,13286 -fatal 7 \ + -sv_lib $env(IMPERAS_HOME)/lib/Linux64/ImperasLib/imperas.com/verification/riscv/1.0/model \ + $env(OTHERFLAGS) + + #-- Run the Simulation + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + echo "Don't forget to change DEBUG_LEVEL = 0." + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + #run 100 ns + #force -deposit testbench/dut/core/priv/priv/csr/csri/IE_REGW 16'h2aa + #force -deposit testbench/dut/uncore/uncore/clint/clint/MTIMECMP 64'h1000 + run 14000 ms + #add log -recursive /* + #do linux-wave.do + #run -all + + exec ./slack-notifier/slack-notifier.py + +} elseif {$2 eq "fpga"} { + echo "hello" + vlog -work work +incdir+../config/fpga +incdir+../config/shared ../testbench/testbench.sv ../testbench/sdc/*.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv ../../fpga/sim/*.sv -suppress 8852,12070,3084,3829,2583,7063,13286 + vopt +acc work.testbench -G TEST=$2 -G DEBUG=0 -o workopt + vsim workopt +nowarn3829 -fatal 7 + + do fpga-wave.do + add log -r /* + run 20 ms + +} else { + if {$2 eq "ahb"} { + vlog +incdir+../config/$1 +incdir+../config/shared ../testbench/testbench.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv -suppress 2583,13286 -suppress 7063 +define+RAM_LATENCY=$3 +define+BURST_EN=$4 + } else { + # *** modelsim won't take `PA_BITS, but will take other defines for the lengths of DTIM_RANGE and IROM_LEN. For now just live with the warnings. + vlog +incdir+../config/$1 +incdir+../config/shared ../testbench/testbench.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv -suppress 2583,13286 -suppress 7063 + } + vopt +acc work.testbench -G TEST=$2 -G DEBUG=1 -o workopt + + vsim workopt +nowarn3829 -fatal 7 + + view wave + #-- display input and output signals as hexidecimal values + #do ./wave-dos/peripheral-waves.do + add log -recursive /* + do wave.do + #do wave-bus.do + + # power add generates the logging necessary for saif generation. + #power add -r /dut/core/* + #-- Run the Simulation + + run -all + #power off -r /dut/core/* + #power report -all -bsaif power.saif + noview ../testbench/testbench.sv + view wave +} + + + +#elseif {$2 eq "buildroot-no-trace""} { +# vlog -lint -work work_${1}_${2} +incdir+../config/$1 +incdir+../config/shared ../testbench/testbench-linux.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv -suppress 2583 + # start and run simulation +# vopt +acc work_${1}_${2}.testbench -work work_${1}_${2} -G RISCV_DIR=$3 -G INSTR_LIMIT=470350800 -G INSTR_WAVEON=470350800 -G CHECKPOINT=470350800 -G DEBUG_TRACE=0 -o testbenchopt +# vsim -lib work_${1}_${2} testbenchopt -suppress 8852,12070,3084,3829 + + #-- Run the Simulation +# run 100 ns +# force -deposit testbench/dut/core/priv/priv/csr/csri/IE_REGW 16'h2aa +# force -deposit testbench/dut/uncore/uncore/clint/clint/MTIMECMP 64'h1000 +# add log -recursive /* +# do linux-wave.do +# run -all + +# exec ./slack-notifier/slack-notifier.py +#} diff --git a/src/privileged/csrsr.sv b/src/privileged/csrsr.sv index a92aca3b..1b8386f4 100644 --- a/src/privileged/csrsr.sv +++ b/src/privileged/csrsr.sv @@ -52,6 +52,8 @@ module csrsr ( logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS_INT, STATUS_MPP_NEXT; logic STATUS_MPIE, STATUS_SPIE, STATUS_UBE, STATUS_SBE, STATUS_MBE; logic nextMBE, nextSBE; + + initial $monitor("QEMU=%0d STATUS_SXL=%0d STATUS_UXL=%0d", `QEMU, STATUS_SXL, STATUS_UXL); // STATUS REGISTER FIELD // See Privileged Spec Section 3.1.6 diff --git a/testbench/common/wallyTracer.sv b/testbench/common/wallyTracer.sv index bfe5c4b3..4df1956a 100644 --- a/testbench/common/wallyTracer.sv +++ b/testbench/common/wallyTracer.sv @@ -90,6 +90,7 @@ module wallyTracer(rvviTrace rvvi); assign STATUS_UXL = testbench.dut.core.priv.priv.csr.csrsr.STATUS_UXL; logic valid; + int csrid; always_comb begin // Since we are detected the CSR change by comparing the old value we need to @@ -116,7 +117,6 @@ module wallyTracer(rvviTrace rvvi); pmp |= testbench.dut.core.priv.priv.csr.csrm.PMPCFG_ARRAY_REGW[i8+7] << 56; csrid = 12'h3A0 + i4; - //if (CSRArray[csrid] != pmp) $display("Info: %m pmpcfg%0d [%03X] %016X -> %016X", i4, csrid, CSRArray[csrid], pmp); CSRArray[csrid] = pmp; end @@ -125,7 +125,6 @@ module wallyTracer(rvviTrace rvvi); pmp = testbench.dut.core.priv.priv.csr.csrm.PMPADDR_ARRAY_REGW[i]; csrid = 12'h3B0 + i; - //if (CSRArray[csrid] != pmp) $display("Info: %m Change pmpaddr%0d [%03X] %016X -> %016X", i, csrid, CSRArray[csrid], pmp); CSRArray[csrid] = pmp; end @@ -167,7 +166,17 @@ module wallyTracer(rvviTrace rvvi); CSRArray[12'h001] = testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW; CSRArray[12'h002] = testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW; CSRArray[12'h003] = {testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW, testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW}; + end else begin // hold the old value if the pipeline is stalled. + + // PMP CFG 3A0 to 3AF + for(csrid='h3A0; csrid<='h3AF; csrid++) + CSRArray[csrid] = CSRArrayOld[csrid]; + + // PMP ADDR 3B0 to 3EF + for(csrid='h3B0; csrid<='h3EF; csrid++) + CSRArray[csrid] = CSRArrayOld[csrid]; + CSRArray[12'h300] = CSRArrayOld[12'h300]; CSRArray[12'h310] = CSRArrayOld[12'h310]; CSRArray[12'h305] = CSRArrayOld[12'h305]; @@ -209,7 +218,7 @@ module wallyTracer(rvviTrace rvvi); end end - genvar index; + genvar index; assign rf[0] = '0; for(index = 1; index < NUMREGS; index += 1) assign rf[index] = testbench.dut.core.ieu.dp.regf.rf[index]; @@ -286,27 +295,177 @@ module wallyTracer(rvviTrace rvvi); // record previous csr value. integer index4; always_ff @(posedge clk) begin - for (index4 = 0; index4 < `NUM_CSRS; index4 += 1) begin -// IMPERAS - //CSR_W[index4] = (CSRArrayOld[index4] != CSRArray[index4]) ? 1 : 0; - CSRArrayOld[index4] = CSRArray[index4]; - end + CSRArrayOld[12'h300] = CSRArray[12'h300]; + CSRArrayOld[12'h310] = CSRArray[12'h310]; + CSRArrayOld[12'h305] = CSRArray[12'h305]; + CSRArrayOld[12'h341] = CSRArray[12'h341]; + CSRArrayOld[12'h306] = CSRArray[12'h306]; + CSRArrayOld[12'h320] = CSRArray[12'h320]; + CSRArrayOld[12'h302] = CSRArray[12'h302]; + CSRArrayOld[12'h303] = CSRArray[12'h303]; + CSRArrayOld[12'h344] = CSRArray[12'h344]; + CSRArrayOld[12'h304] = CSRArray[12'h304]; + CSRArrayOld[12'h301] = CSRArray[12'h301]; + CSRArrayOld[12'hF14] = CSRArray[12'hF14]; + CSRArrayOld[12'h340] = CSRArray[12'h340]; + CSRArrayOld[12'h342] = CSRArray[12'h342]; + CSRArrayOld[12'h343] = CSRArray[12'h343]; + CSRArrayOld[12'hF11] = CSRArray[12'hF11]; + CSRArrayOld[12'hF12] = CSRArray[12'hF12]; + CSRArrayOld[12'hF13] = CSRArray[12'hF13]; + CSRArrayOld[12'hF15] = CSRArray[12'hF15]; + CSRArrayOld[12'h34A] = CSRArray[12'h34A]; + // MCYCLE and MINSTRET + CSRArrayOld[12'hB00] = CSRArray[12'hB00]; + CSRArrayOld[12'hB02] = CSRArray[12'hB02]; + // supervisor CSRs + CSRArrayOld[12'h100] = CSRArray[12'h100]; + CSRArrayOld[12'h104] = CSRArray[12'h104]; + CSRArrayOld[12'h105] = CSRArray[12'h105]; + CSRArrayOld[12'h141] = CSRArray[12'h141]; + CSRArrayOld[12'h106] = CSRArray[12'h106]; + CSRArrayOld[12'h180] = CSRArray[12'h180]; + CSRArrayOld[12'h140] = CSRArray[12'h140]; + CSRArrayOld[12'h143] = CSRArray[12'h143]; + CSRArrayOld[12'h142] = CSRArray[12'h142]; + CSRArrayOld[12'h144] = CSRArray[12'h144]; + // user CSRs + CSRArrayOld[12'h001] = CSRArray[12'h001]; + CSRArrayOld[12'h002] = CSRArray[12'h002]; + CSRArrayOld[12'h003] = CSRArray[12'h003]; + + // PMP CFG 3A0 to 3AF + for(index4='h3A0; index4<='h3AF; index4++) + CSRArrayOld[index4] = CSRArray[index4]; + + // PMP ADDR 3B0 to 3EF + for(index4='h3B0; index4<='h3EF; index4++) + CSRArrayOld[index4] = CSRArray[index4]; end // check for csr value change. - genvar index5; - for(index5 = 0; index5 < `NUM_CSRS; index5 += 1) begin - // CSR_W should only indicate the change when the Writeback stage is not stalled and valid. - assign #2 CSR_W[index5] = (CSRArrayOld[index5] != CSRArray[index5]) ? 1 : 0; - assign rvvi.csr_wb[0][0][index5] = CSR_W[index5]; - assign rvvi.csr[0][0][index5] = CSRArray[index5]; + assign #2 CSR_W[12'h300] = (CSRArrayOld[12'h300] != CSRArray[12'h300]) ? 1 : 0; + assign #2 CSR_W[12'h310] = (CSRArrayOld[12'h310] != CSRArray[12'h310]) ? 1 : 0; + assign #2 CSR_W[12'h305] = (CSRArrayOld[12'h305] != CSRArray[12'h305]) ? 1 : 0; + assign #2 CSR_W[12'h341] = (CSRArrayOld[12'h341] != CSRArray[12'h341]) ? 1 : 0; + assign #2 CSR_W[12'h306] = (CSRArrayOld[12'h306] != CSRArray[12'h306]) ? 1 : 0; + assign #2 CSR_W[12'h320] = (CSRArrayOld[12'h320] != CSRArray[12'h320]) ? 1 : 0; + assign #2 CSR_W[12'h302] = (CSRArrayOld[12'h302] != CSRArray[12'h302]) ? 1 : 0; + assign #2 CSR_W[12'h303] = (CSRArrayOld[12'h303] != CSRArray[12'h303]) ? 1 : 0; + assign #2 CSR_W[12'h344] = (CSRArrayOld[12'h344] != CSRArray[12'h344]) ? 1 : 0; + assign #2 CSR_W[12'h304] = (CSRArrayOld[12'h304] != CSRArray[12'h304]) ? 1 : 0; + assign #2 CSR_W[12'h301] = (CSRArrayOld[12'h301] != CSRArray[12'h301]) ? 1 : 0; + assign #2 CSR_W[12'hF14] = (CSRArrayOld[12'hF14] != CSRArray[12'hF14]) ? 1 : 0; + assign #2 CSR_W[12'h340] = (CSRArrayOld[12'h340] != CSRArray[12'h340]) ? 1 : 0; + assign #2 CSR_W[12'h342] = (CSRArrayOld[12'h342] != CSRArray[12'h342]) ? 1 : 0; + assign #2 CSR_W[12'h343] = (CSRArrayOld[12'h343] != CSRArray[12'h343]) ? 1 : 0; + assign #2 CSR_W[12'hF11] = (CSRArrayOld[12'hF11] != CSRArray[12'hF11]) ? 1 : 0; + assign #2 CSR_W[12'hF12] = (CSRArrayOld[12'hF12] != CSRArray[12'hF12]) ? 1 : 0; + assign #2 CSR_W[12'hF13] = (CSRArrayOld[12'hF13] != CSRArray[12'hF13]) ? 1 : 0; + assign #2 CSR_W[12'hF15] = (CSRArrayOld[12'hF15] != CSRArray[12'hF15]) ? 1 : 0; + assign #2 CSR_W[12'h34A] = (CSRArrayOld[12'h34A] != CSRArray[12'h34A]) ? 1 : 0; + assign #2 CSR_W[12'hB00] = (CSRArrayOld[12'hB00] != CSRArray[12'hB00]) ? 1 : 0; + assign #2 CSR_W[12'hB02] = (CSRArrayOld[12'hB02] != CSRArray[12'hB02]) ? 1 : 0; + assign #2 CSR_W[12'h100] = (CSRArrayOld[12'h100] != CSRArray[12'h100]) ? 1 : 0; + assign #2 CSR_W[12'h104] = (CSRArrayOld[12'h104] != CSRArray[12'h104]) ? 1 : 0; + assign #2 CSR_W[12'h105] = (CSRArrayOld[12'h105] != CSRArray[12'h105]) ? 1 : 0; + assign #2 CSR_W[12'h141] = (CSRArrayOld[12'h141] != CSRArray[12'h141]) ? 1 : 0; + assign #2 CSR_W[12'h106] = (CSRArrayOld[12'h106] != CSRArray[12'h106]) ? 1 : 0; + assign #2 CSR_W[12'h180] = (CSRArrayOld[12'h180] != CSRArray[12'h180]) ? 1 : 0; + assign #2 CSR_W[12'h140] = (CSRArrayOld[12'h140] != CSRArray[12'h140]) ? 1 : 0; + assign #2 CSR_W[12'h143] = (CSRArrayOld[12'h143] != CSRArray[12'h143]) ? 1 : 0; + assign #2 CSR_W[12'h142] = (CSRArrayOld[12'h142] != CSRArray[12'h142]) ? 1 : 0; + assign #2 CSR_W[12'h144] = (CSRArrayOld[12'h144] != CSRArray[12'h144]) ? 1 : 0; + assign #2 CSR_W[12'h001] = (CSRArrayOld[12'h001] != CSRArray[12'h001]) ? 1 : 0; + assign #2 CSR_W[12'h002] = (CSRArrayOld[12'h002] != CSRArray[12'h002]) ? 1 : 0; + assign #2 CSR_W[12'h003] = (CSRArrayOld[12'h003] != CSRArray[12'h003]) ? 1 : 0; + + assign rvvi.csr_wb[0][0][12'h300] = CSR_W[12'h300]; + assign rvvi.csr_wb[0][0][12'h310] = CSR_W[12'h310]; + assign rvvi.csr_wb[0][0][12'h305] = CSR_W[12'h305]; + assign rvvi.csr_wb[0][0][12'h341] = CSR_W[12'h341]; + assign rvvi.csr_wb[0][0][12'h306] = CSR_W[12'h306]; + assign rvvi.csr_wb[0][0][12'h320] = CSR_W[12'h320]; + assign rvvi.csr_wb[0][0][12'h302] = CSR_W[12'h302]; + assign rvvi.csr_wb[0][0][12'h303] = CSR_W[12'h303]; + assign rvvi.csr_wb[0][0][12'h344] = CSR_W[12'h344]; + assign rvvi.csr_wb[0][0][12'h304] = CSR_W[12'h304]; + assign rvvi.csr_wb[0][0][12'h301] = CSR_W[12'h301]; + assign rvvi.csr_wb[0][0][12'hF14] = CSR_W[12'hF14]; + assign rvvi.csr_wb[0][0][12'h340] = CSR_W[12'h340]; + assign rvvi.csr_wb[0][0][12'h342] = CSR_W[12'h342]; + assign rvvi.csr_wb[0][0][12'h343] = CSR_W[12'h343]; + assign rvvi.csr_wb[0][0][12'hF11] = CSR_W[12'hF11]; + assign rvvi.csr_wb[0][0][12'hF12] = CSR_W[12'hF12]; + assign rvvi.csr_wb[0][0][12'hF13] = CSR_W[12'hF13]; + assign rvvi.csr_wb[0][0][12'hF15] = CSR_W[12'hF15]; + assign rvvi.csr_wb[0][0][12'h34A] = CSR_W[12'h34A]; + assign rvvi.csr_wb[0][0][12'hB00] = CSR_W[12'hB00]; + assign rvvi.csr_wb[0][0][12'hB02] = CSR_W[12'hB02]; + assign rvvi.csr_wb[0][0][12'h100] = CSR_W[12'h100]; + assign rvvi.csr_wb[0][0][12'h104] = CSR_W[12'h104]; + assign rvvi.csr_wb[0][0][12'h105] = CSR_W[12'h105]; + assign rvvi.csr_wb[0][0][12'h141] = CSR_W[12'h141]; + assign rvvi.csr_wb[0][0][12'h106] = CSR_W[12'h106]; + assign rvvi.csr_wb[0][0][12'h180] = CSR_W[12'h180]; + assign rvvi.csr_wb[0][0][12'h140] = CSR_W[12'h140]; + assign rvvi.csr_wb[0][0][12'h143] = CSR_W[12'h143]; + assign rvvi.csr_wb[0][0][12'h142] = CSR_W[12'h142]; + assign rvvi.csr_wb[0][0][12'h144] = CSR_W[12'h144]; + assign rvvi.csr_wb[0][0][12'h001] = CSR_W[12'h001]; + assign rvvi.csr_wb[0][0][12'h002] = CSR_W[12'h002]; + assign rvvi.csr_wb[0][0][12'h003] = CSR_W[12'h003]; + + assign rvvi.csr[0][0][12'h300] = CSRArray[12'h300]; + assign rvvi.csr[0][0][12'h310] = CSRArray[12'h310]; + assign rvvi.csr[0][0][12'h305] = CSRArray[12'h305]; + assign rvvi.csr[0][0][12'h341] = CSRArray[12'h341]; + assign rvvi.csr[0][0][12'h306] = CSRArray[12'h306]; + assign rvvi.csr[0][0][12'h320] = CSRArray[12'h320]; + assign rvvi.csr[0][0][12'h302] = CSRArray[12'h302]; + assign rvvi.csr[0][0][12'h303] = CSRArray[12'h303]; + assign rvvi.csr[0][0][12'h344] = CSRArray[12'h344]; + assign rvvi.csr[0][0][12'h304] = CSRArray[12'h304]; + assign rvvi.csr[0][0][12'h301] = CSRArray[12'h301]; + assign rvvi.csr[0][0][12'hF14] = CSRArray[12'hF14]; + assign rvvi.csr[0][0][12'h340] = CSRArray[12'h340]; + assign rvvi.csr[0][0][12'h342] = CSRArray[12'h342]; + assign rvvi.csr[0][0][12'h343] = CSRArray[12'h343]; + assign rvvi.csr[0][0][12'hF11] = CSRArray[12'hF11]; + assign rvvi.csr[0][0][12'hF12] = CSRArray[12'hF12]; + assign rvvi.csr[0][0][12'hF13] = CSRArray[12'hF13]; + assign rvvi.csr[0][0][12'hF15] = CSRArray[12'hF15]; + assign rvvi.csr[0][0][12'h34A] = CSRArray[12'h34A]; + assign rvvi.csr[0][0][12'hB00] = CSRArray[12'hB00]; + assign rvvi.csr[0][0][12'hB02] = CSRArray[12'hB02]; + assign rvvi.csr[0][0][12'h100] = CSRArray[12'h100]; + assign rvvi.csr[0][0][12'h104] = CSRArray[12'h104]; + assign rvvi.csr[0][0][12'h105] = CSRArray[12'h105]; + assign rvvi.csr[0][0][12'h141] = CSRArray[12'h141]; + assign rvvi.csr[0][0][12'h106] = CSRArray[12'h106]; + assign rvvi.csr[0][0][12'h180] = CSRArray[12'h180]; + assign rvvi.csr[0][0][12'h140] = CSRArray[12'h140]; + assign rvvi.csr[0][0][12'h143] = CSRArray[12'h143]; + assign rvvi.csr[0][0][12'h142] = CSRArray[12'h142]; + assign rvvi.csr[0][0][12'h144] = CSRArray[12'h144]; + assign rvvi.csr[0][0][12'h001] = CSRArray[12'h001]; + assign rvvi.csr[0][0][12'h002] = CSRArray[12'h002]; + assign rvvi.csr[0][0][12'h003] = CSRArray[12'h003]; + + // PMP CFG 3A0 to 3AF + for(index='h3A0; index<='h3AF; index++) begin + assign #2 CSR_W[index] = (CSRArrayOld[index] != CSRArray[index]) ? 1 : 0; + assign rvvi.csr_wb[0][0][index] = CSR_W[index]; + assign rvvi.csr[0][0][index] = CSRArray[index]; end - -// always @rvvi.clk $display("%t @rvvi.clk=%X", $time, rvvi.clk); -// always @rvvi.csr[0][0]['h300] $display("%t rvvi.csr[0][0]['h300]=%X", $time, rvvi.csr[0][0]['h300]); -// always @rvvi.csr_wb[0][0]['h300] $display("%t rvvi.csr_wb[0][0]['h300]=%X", $time, rvvi.csr_wb[0][0]['h300]); -// always @rvvi.valid[0][0] $display("%t rvvi.valid[0][0]=%X", $time, rvvi.valid[0][0]); - + + // PMP ADDR 3B0 to 3EF + for(index='h3B0; index<='h3EF; index++) begin + assign #2 CSR_W[index] = (CSRArrayOld[index] != CSRArray[index]) ? 1 : 0; + assign rvvi.csr_wb[0][0][index] = CSR_W[index]; + assign rvvi.csr[0][0][index] = CSRArray[index]; + end + // *** implementation only cancel? so sc does not clear? assign rvvi.lrsc_cancel[0][0] = '0; diff --git a/testbench/testbench-linux-imperas.sv b/testbench/testbench-linux-imperas.sv new file mode 100644 index 00000000..64f745e4 --- /dev/null +++ b/testbench/testbench-linux-imperas.sv @@ -0,0 +1,1033 @@ +/////////////////////////////////////////// +// testbench-linux.sv +// +// Written: nboorstin@g.hmc.edu 2021 +// Modified: +// +// Purpose: Testbench for Buildroot Linux +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file +// except in compliance with the License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work distributed under the +// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +//////////////////////////////////////////////////////////////////////////////////////////////// + +`include "wally-config.vh" + +// This is set from the command line script +// `define USE_IMPERAS_DV + +`ifdef USE_IMPERAS_DV + `include "rvvi/imperasDV.svh" +`endif + +`define DEBUG_TRACE 0 +// Debug Levels +// 0: don't check against QEMU +// 1: print disagreements with QEMU, but only halt on PCW disagreements +// 2: halt on any disagreement with QEMU except CSRs +// 3: halt on all disagreements with QEMU +// 4: print memory accesses whenever they happen +// 5: print everything + +module testbench; + /////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////// CONFIG //////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + // Recommend setting all of these in 'do' script using -G option + parameter INSTR_LIMIT = 0; // # of instructions at which to stop + parameter INSTR_WAVEON = 0; // # of instructions at which to turn on waves in graphical sim + parameter CHECKPOINT = 0; + parameter RISCV_DIR = "/opt/riscv"; + parameter NO_SPOOFING = 0; + + + `ifdef USE_IMPERAS_DV + import rvviPkg::*; + import rvviApiPkg::*; + import idvApiPkg::*; + `endif + + + + + + + + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////// SIGNAL / VAR / MACRO DECLARATIONS ///////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + // ========== Testbench Core ========== + integer warningCount = 0; + integer errorCount = 0; + integer fault; + string ProgramAddrMapFile, ProgramLabelMapFile; + // ========== Initialization ========== + string testvectorDir; + string linuxImageDir; + integer memFile; + integer readResult; + // ========== Checkpointing ========== + string checkpointDir; + logic [1:0] initPriv; + // ========== Trace parsing & checking ========== + integer garbageInt; + string garbageString; + `define DECLARE_TRACE_SCANNER_SIGNALS(STAGE) \ + integer traceFile``STAGE; \ + integer matchCount``STAGE; \ + string line``STAGE; \ + string token``STAGE; \ + string ExpectedTokens``STAGE [31:0]; \ + integer index``STAGE; \ + integer StartIndex``STAGE, EndIndex``STAGE; \ + integer TokenIndex``STAGE; \ + integer MarkerIndex``STAGE; \ + integer NumCSR``STAGE; \ + logic [`XLEN-1:0] ExpectedPC``STAGE; \ + logic [31:0] ExpectedInstr``STAGE; \ + string text``STAGE; \ + string MemOp``STAGE; \ + string RegWrite``STAGE; \ + integer ExpectedRegAdr``STAGE; \ + logic [`XLEN-1:0] ExpectedRegValue``STAGE; \ + logic [`XLEN-1:0] ExpectedIEUAdr``STAGE, ExpectedMemReadData``STAGE, ExpectedMemWriteData``STAGE; \ + string ExpectedCSRArray``STAGE[10:0]; \ + logic [`XLEN-1:0] ExpectedCSRArrayValue``STAGE[10:0]; // *** might be redundant? + `DECLARE_TRACE_SCANNER_SIGNALS(E) + `DECLARE_TRACE_SCANNER_SIGNALS(M) + // M-stage expected values + logic checkInstrM; + integer MIPexpected, SIPexpected; + string name; + logic [`AHBW-1:0] readDataExpected; + // W-stage expected values + logic checkInstrW; + logic [`XLEN-1:0] ExpectedPCW; + logic [31:0] ExpectedInstrW; + string textW; + string RegWriteW; + integer ExpectedRegAdrW; + logic [`XLEN-1:0] ExpectedRegValueW; + string MemOpW; + logic [`XLEN-1:0] ExpectedIEUAdrW, ExpectedMemReadDataW, ExpectedMemWriteDataW; + integer NumCSRW; + string ExpectedCSRArrayW[10:0]; + logic [`XLEN-1:0] ExpectedCSRArrayValueW[10:0]; + logic [`XLEN-1:0] ExpectedIntType; + integer NumCSRWIndex; + integer NumCSRPostWIndex; + logic [`XLEN-1:0] InstrCountW; + // ========== Interrupt parsing & spoofing ========== + string interrupt; + string interruptLine; + integer interruptFile; + integer interruptInstrCount; + integer interruptHartVal; + integer interruptAsyncVal; + longint interruptCauseVal; + longint interruptEpcVal; + longint interruptTVal; + string interruptDesc; + integer NextMIPexpected, NextSIPexpected; + integer NextMepcExpected; + logic [`XLEN-1:0] AttemptedInstructionCount; + // ========== Misc Aliases ========== + `define RF dut.core.ieu.dp.regf.rf + `define PC dut.core.ifu.pcreg.q + `define PRIV_BASE dut.core.priv.priv + `define PRIV `PRIV_BASE.privmode.privmode.privmodereg.q + `define CSR_BASE `PRIV_BASE.csr + `define MEIP `PRIV_BASE.MExtInt + `define SEIP `PRIV_BASE.SExtInt + `define MTIP `PRIV_BASE.MTimerInt + `define HPMCOUNTER `CSR_BASE.counters.counters.HPMCOUNTER_REGW + `define MEDELEG `CSR_BASE.csrm.deleg.MEDELEGreg.q + `define MIDELEG `CSR_BASE.csrm.deleg.MIDELEGreg.q + `define MIE `CSR_BASE.csri.MIE_REGW + `define MIP `CSR_BASE.csri.MIP_REGW_writeable + `define MCAUSE `CSR_BASE.csrm.MCAUSEreg.q + `define SCAUSE `CSR_BASE.csrs.csrs.SCAUSEreg.q + `define MEPC `CSR_BASE.csrm.MEPCreg.q + `define SEPC `CSR_BASE.csrs.csrs.SEPCreg.q + `define MCOUNTEREN `CSR_BASE.csrm.mcounteren.MCOUNTERENreg.q + `define SCOUNTEREN `CSR_BASE.csrs.csrs.SCOUNTERENreg.q + `define MSCRATCH `CSR_BASE.csrm.MSCRATCHreg.q + `define SSCRATCH `CSR_BASE.csrs.csrs.SSCRATCHreg.q + `define MTVEC `CSR_BASE.csrm.MTVECreg.q + `define STVEC `CSR_BASE.csrs.csrs.STVECreg.q + `define SATP `CSR_BASE.csrs.csrs.genblk1.SATPreg.q + `define INSTRET `CSR_BASE.counters.counters.HPMCOUNTER_REGW[2] + `define MSTATUS `CSR_BASE.csrsr.MSTATUS_REGW + `define SSTATUS `CSR_BASE.csrsr.SSTATUS_REGW + `define STATUS_TSR `CSR_BASE.csrsr.STATUS_TSR_INT + `define STATUS_TW `CSR_BASE.csrsr.STATUS_TW_INT + `define STATUS_TVM `CSR_BASE.csrsr.STATUS_TVM_INT + `define STATUS_MXR `CSR_BASE.csrsr.STATUS_MXR_INT + `define STATUS_SUM `CSR_BASE.csrsr.STATUS_SUM_INT + `define STATUS_MPRV `CSR_BASE.csrsr.STATUS_MPRV_INT + `define STATUS_FS `CSR_BASE.csrsr.STATUS_FS_INT + `define STATUS_MPP `CSR_BASE.csrsr.STATUS_MPP + `define STATUS_SPP `CSR_BASE.csrsr.STATUS_SPP + `define STATUS_MPIE `CSR_BASE.csrsr.STATUS_MPIE + `define STATUS_SPIE `CSR_BASE.csrsr.STATUS_SPIE + `define STATUS_MIE `CSR_BASE.csrsr.STATUS_MIE + `define STATUS_SIE `CSR_BASE.csrsr.STATUS_SIE + `define UART dut.uncore.uncore.uart.uart.u + `define UART_IER `UART.IER + `define UART_LCR `UART.LCR + `define UART_MCR `UART.MCR + `define UART_SCR `UART.SCR + `define UART_IP `UART.INTR + `define PLIC dut.uncore.uncore.plic.plic + `define PLIC_INT_PRIORITY `PLIC.intPriority + `define PLIC_INT_ENABLE `PLIC.intEn + `define PLIC_THRESHOLD `PLIC.intThreshold + `define PCM dut.core.ifu.PCM + // ========== COMMON MACROS ========== + // Needed for initialization and core + `define SCAN_NEW_INTERRUPT \ + begin \ + $fgets(interruptLine, interruptFile); \ + //$display("Time %t, interruptLine %x", $time, interruptLine); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%d", interruptInstrCount); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%d", interruptHartVal); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%d", interruptAsyncVal); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%x", interruptCauseVal); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%x", interruptEpcVal); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%x", interruptTVal); \ + $fgets(interruptLine, interruptFile); \ + $sscanf(interruptLine, "%s", interruptDesc); \ + end + + + + + + + + /////////////////////////////////////////////////////////////////////////////// + /////////////////////////////// Cache Issue /////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + logic probe; + if (NO_SPOOFING) + assign probe = testbench.dut.core.PCM == 64'hffffffff80200c8c + & testbench.dut.core.InstrM != 32'h14021273 + & testbench.dut.core.InstrValidM; + + + + + + + + + /////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// HARDWARE /////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + // Clock and Reset + logic clk, reset_ext; + logic reset; + initial begin reset_ext <= 1; # 22; reset_ext <= 0; end + always begin clk <= 1; # 5; clk <= 0; # 5; end + // Wally Interface + logic [`AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic HCLK, HRESETn; + logic HREADY; + logic HSELEXT; + logic [`PA_BITS-1:0] HADDR; + logic [`AHBW-1:0] HWDATA; + logic [`XLEN/8-1:0] HWSTRB; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic [31:0] GPIOPinsIn; + logic [31:0] GPIOPinsOut, GPIOPinsEn; + logic UARTSin, UARTSout; + + // FPGA-specific Stuff + logic SDCCLK; + logic SDCCmdIn; + logic SDCCmdOut; + logic SDCCmdOE; + logic [3:0] SDCDatIn; + + // Hardwire UART, GPIO pins + assign GPIOPinsIn = 0; + assign UARTSin = 1; + + + + `ifdef USE_IMPERAS_DV + + logic DCacheFlushDone, DCacheFlushStart; + + rvviTrace #(.XLEN(`XLEN), .FLEN(`FLEN)) rvvi(); + wallyTracer wallyTracer(rvvi); + + trace2log idv_trace2log(rvvi); +// trace2cov idv_trace2cov(rvvi); + + // enabling of comparison types + trace2api #(.CMP_PC (1), + .CMP_INS (1), + .CMP_GPR (1), + .CMP_FPR (1), + .CMP_VR (0), + .CMP_CSR (1) + ) idv_trace2api(rvvi); + + initial begin + int iter; + #1; + MAX_ERRS = 3; + + // Initialize REF (do this before initializing the DUT) + if (!rvviVersionCheck(RVVI_API_VERSION)) begin + msgfatal($sformatf("%m @ t=%0t: Expecting RVVI API version %0d.", $time, RVVI_API_VERSION)); + 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("")) begin + msgfatal($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); + 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 + + // ERROR Temporary as it powers up as 0x1 + void'(rvviRefCsrSet(0, 32'h106, 1)); // RTL sets SCOUNTEREN to 1 for some reason + + // 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 (`CLINT_SUPPORTED) begin + void'(rvviRefMemorySetVolatile(`CLINT_BASE, (`CLINT_BASE + `CLINT_RANGE))); + end + if (`GPIO_SUPPORTED) begin + void'(rvviRefMemorySetVolatile(`GPIO_BASE, (`GPIO_BASE + `GPIO_RANGE))); + end + if (`UART_SUPPORTED) begin + void'(rvviRefMemorySetVolatile(`UART_BASE, (`UART_BASE + `UART_RANGE))); + end + if (`PLIC_SUPPORTED) begin + void'(rvviRefMemorySetVolatile(`PLIC_BASE, (`PLIC_BASE + `PLIC_RANGE))); + end + if (`SDC_SUPPORTED) begin + void'(rvviRefMemorySetVolatile(`SDC_BASE, (`SDC_BASE + `SDC_RANGE))); + end + + if(`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 + begin + longint x64; + int x32[2]; + longint index; + + $sformat(testvectorDir,"%s/linux-testvectors/",RISCV_DIR); + + $display("RVVI Loading bootmem.bin"); + memFile = $fopen({testvectorDir,"bootmem.bin"}, "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({testvectorDir,"ram.bin"}, "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, 'h1000)); // set BOOTROM address + end + end + + always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt)); + always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt)); + always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt)); + always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt)); + + final begin + void'(rvviRefShutdown()); + end + + `endif + + + // Wally + wallypipelinedsoc dut(.clk, .reset, .reset_ext, + .HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HRESPEXT, .HCLK, + .HRESETn, .HADDR, .HWDATA, .HWRITE, .HWSTRB, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, + .TIMECLK('0), .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn, + .UARTSin, .UARTSout, + .SDCCLK, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn); + + // W-stage hardware not needed by Wally itself + parameter nop = 'h13; + logic [`XLEN-1:0] PCW; + logic [31:0] InstrW; + logic InstrValidW; + logic [`XLEN-1:0] IEUAdrW, WriteDataW; + logic TrapW; + `define FLUSHW dut.core.FlushW + `define STALLW dut.core.StallW + flopenrc #(`XLEN) PCWReg(clk, reset, `FLUSHW, ~`STALLW, `PCM, PCW); + flopenr #(32) InstrWReg(clk, reset, ~`STALLW, `FLUSHW ? nop : dut.core.ifu.InstrM, InstrW); + flopenrc #(1) controlregW(clk, reset, `FLUSHW, ~`STALLW, dut.core.ieu.c.InstrValidM, InstrValidW); + flopenrc #(`XLEN) IEUAdrWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.IEUAdrM, IEUAdrW); + flopenrc #(`XLEN) WriteDataWReg(clk, reset, `FLUSHW, ~`STALLW, dut.core.lsu.WriteDataM, WriteDataW); + flopenr #(1) TrapWReg(clk, reset, ~`STALLW, dut.core.hzu.TrapM, TrapW); + + + + + + + + + + + /////////////////////////////////////////////////////////////////////////////// + /////////////////////////////// INITIALIZATION //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + // ========== CHECKPOINTING ========== + `define MAKE_CHECKPOINT_INIT_SIGNAL(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \ + logic DIM init``SIGNAL[ARRAY_MAX:ARRAY_MIN]; \ + initial begin \ + #1; \ + if (CHECKPOINT!=0) $readmemh({checkpointDir,"checkpoint-",`"SIGNAL`"}, init``SIGNAL); \ + end + + `define INIT_CHECKPOINT_SIMPLE_ARRAY(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \ + `MAKE_CHECKPOINT_INIT_SIGNAL(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \ + initial begin \ + if (CHECKPOINT!=0) begin \ + force `SIGNAL = init``SIGNAL[ARRAY_MAX:ARRAY_MIN]; \ + while (reset!==1) #1; \ + while (reset!==0) #1; \ + #1; \ + release `SIGNAL; \ + end \ + end + + `define INIT_CHECKPOINT_PACKED_ARRAY(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \ + `MAKE_CHECKPOINT_INIT_SIGNAL(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \ + for (i=ARRAY_MIN; i= 2)) fault = 1; \ + end + + `define checkCSR(CSR) \ + begin \ + if (CSR != ExpectedCSRArrayValueW[NumCSRPostWIndex]) begin \ + $display("%tns, %d instrs: CSR %s = %016x, does not equal expected value %016x", $time, AttemptedInstructionCount, ExpectedCSRArrayW[NumCSRPostWIndex], CSR, ExpectedCSRArrayValueW[NumCSRPostWIndex]); \ + if(`DEBUG_TRACE >= 3) fault = 1; \ + end \ + end + + // =========== CORE =========== + assign checkInstrM = dut.core.ieu.InstrValidM & ~dut.core.priv.priv.trap.InstrPageFaultM & ~dut.core.priv.priv.trap.InterruptM & ~dut.core.StallM; + always @(negedge clk) begin + `SCAN_NEW_INSTR_FROM_TRACE(E) + `SCAN_NEW_INSTR_FROM_TRACE(M) + end + + // step 1: register expected state into the write back stage. + always @(posedge clk) begin + if (reset) begin + ExpectedPCW <= '0; + ExpectedInstrW <= '0; + textW <= ""; + RegWriteW <= ""; + ExpectedRegAdrW <= '0; + ExpectedRegValueW <= '0; + ExpectedIEUAdrW <= '0; + MemOpW <= ""; + ExpectedMemWriteDataW <= '0; + ExpectedMemReadDataW <= '0; + NumCSRW <= '0; + end else if(~dut.core.StallW) begin + if(dut.core.FlushW) begin + ExpectedPCW <= '0; + ExpectedInstrW <= '0; + textW <= ""; + RegWriteW <= ""; + ExpectedRegAdrW <= '0; + ExpectedRegValueW <= '0; + ExpectedIEUAdrW <= '0; + MemOpW <= ""; + ExpectedMemWriteDataW <= '0; + ExpectedMemReadDataW <= '0; + NumCSRW <= '0; + end else if (dut.core.ieu.c.InstrValidM) begin + ExpectedPCW <= ExpectedPCM; + ExpectedInstrW <= ExpectedInstrM; + textW <= textM; + RegWriteW <= RegWriteM; + ExpectedRegAdrW <= ExpectedRegAdrM; + ExpectedRegValueW <= ExpectedRegValueM; + ExpectedIEUAdrW <= ExpectedIEUAdrM; + MemOpW <= MemOpM; + ExpectedMemWriteDataW <= ExpectedMemWriteDataM; + ExpectedMemReadDataW <= ExpectedMemReadDataM; + NumCSRW <= NumCSRM; + for(NumCSRWIndex = 0; NumCSRWIndex < NumCSRM; NumCSRWIndex++) begin + ExpectedCSRArrayW[NumCSRWIndex] = ExpectedCSRArrayM[NumCSRWIndex]; + ExpectedCSRArrayValueW[NumCSRWIndex] = ExpectedCSRArrayValueM[NumCSRWIndex]; + end + end + #1; + // override on special conditions + if(~dut.core.StallW) begin + if(textW.substr(0,5) == "rdtime") begin + //$display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, AttemptedInstructionCount); + if(!NO_SPOOFING) + release dut.uncore.uncore.clint.clint.MTIME; + end + //if (ExpectedIEUAdrM == 'h10000005) begin + //$display("%tns, %d instrs: releasing force of ReadDataM.", $time, AttemptedInstructionCount); + //release dut.core.ieu.dp.ReadDataM; + //end + end + end + end + + // step2: make all checks in the write back stage. + assign checkInstrW = InstrValidW & ~dut.core.StallW; // trapW will already be invalid in there was an InstrPageFault in the previous instruction. + always @(negedge clk) begin + #1; // small delay allows interrupt spoofing to happen first + // always check PC, instruction bits + if (checkInstrW) begin + InstrCountW += 1; + // print progress message + if (AttemptedInstructionCount % 'd100000 == 0) $display("Reached %d instructions", AttemptedInstructionCount); + // turn on waves + if (AttemptedInstructionCount == INSTR_WAVEON) $stop; + // end sim + if ((AttemptedInstructionCount == INSTR_LIMIT) & (INSTR_LIMIT!=0)) begin $stop; $stop; end + fault = 0; + if (`DEBUG_TRACE >= 1) begin + `checkEQ("PCW",PCW,ExpectedPCW) + //`checkEQ("InstrW",InstrW,ExpectedInstrW) <-- not viable because of + // compressed to uncompressed conversion + `checkEQ("Instr Count",dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2],InstrCountW) + #2; // delay 2 ns. + if(`DEBUG_TRACE >= 5) begin + $display("%tns, %d instrs: Reg Write Address %02d ? expected value: %02d", $time, AttemptedInstructionCount, dut.core.ieu.dp.regf.a3, ExpectedRegAdrW); + $display("%tns, %d instrs: RF[%02d] %016x ? expected value: %016x", $time, AttemptedInstructionCount, ExpectedRegAdrW, dut.core.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW); + end + if (RegWriteW == "GPR") begin + `checkEQ("Reg Write Address",dut.core.ieu.dp.regf.a3,ExpectedRegAdrW) + $sformat(name,"RF[%02d]",ExpectedRegAdrW); + `checkEQ(name, dut.core.ieu.dp.regf.rf[ExpectedRegAdrW], ExpectedRegValueW) + end + if (MemOpW.substr(0,2) == "Mem") begin + if(`DEBUG_TRACE >= 4) $display("\tIEUAdrW: %016x ? expected: %016x", IEUAdrW, ExpectedIEUAdrW); + `checkEQ("IEUAdrW",IEUAdrW,ExpectedIEUAdrW) + if(MemOpW == "MemR" | MemOpW == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tReadDataW: %016x ? expected: %016x", dut.core.ieu.dp.ReadDataW, ExpectedMemReadDataW); + `checkEQ("ReadDataW",dut.core.ieu.dp.ReadDataW,ExpectedMemReadDataW) + end else if(MemOpW == "MemW" | MemOpW == "MemRW") begin + if(`DEBUG_TRACE >= 4) $display("\tWriteDataW: %016x ? expected: %016x", WriteDataW, ExpectedMemWriteDataW); + `checkEQ("WriteDataW",ExpectedMemWriteDataW,ExpectedMemWriteDataW) + end + end + // check csr + for(NumCSRPostWIndex = 0; NumCSRPostWIndex < NumCSRW; NumCSRPostWIndex++) begin + case(ExpectedCSRArrayW[NumCSRPostWIndex]) + "mhartid": `checkCSR(`CSR_BASE.csrm.MHARTID_REGW) + "mstatus": `checkCSR(`CSR_BASE.csrm.MSTATUS_REGW) + "sstatus": `checkCSR(`CSR_BASE.csrs.csrs.SSTATUS_REGW) + "mtvec": `checkCSR(`CSR_BASE.csrm.MTVEC_REGW) + "mie": `checkCSR(`CSR_BASE.csrm.MIE_REGW) + "mideleg": `checkCSR(`CSR_BASE.csrm.MIDELEG_REGW) + "medeleg": `checkCSR(`CSR_BASE.csrm.MEDELEG_REGW) + "mepc": `checkCSR(`CSR_BASE.csrm.MEPC_REGW) + "mtval": `checkCSR(`CSR_BASE.csrm.MTVAL_REGW) + "sepc": `checkCSR(`CSR_BASE.csrs.csrs.SEPC_REGW) + "scause": `checkCSR(`CSR_BASE.csrs.csrs.SCAUSE_REGW) + "stvec": `checkCSR(`CSR_BASE.csrs.csrs.STVEC_REGW) + "stval": `checkCSR(`CSR_BASE.csrs.csrs.STVAL_REGW) + "mip": begin + `checkCSR(`CSR_BASE.csrm.MIP_REGW) + if(!NO_SPOOFING) begin + if ((ExpectedCSRArrayValueW[NumCSRPostWIndex] & 1<<11) == 0) + force `MEIP = 0; + if ((ExpectedCSRArrayValueW[NumCSRPostWIndex] & 1<<09) == 0) + force `SEIP = 0; + if ((ExpectedCSRArrayValueW[NumCSRPostWIndex] & ((1<<11) | (1<<09))) == 0) + force `UART_IP = 0; + if ((ExpectedCSRArrayValueW[NumCSRPostWIndex] & 1<<07) == 0) + force `MTIP = 0; + end + end + endcase + end + if (fault == 1) begin + errorCount +=1; + $display("processed %0d instructions with %0d warnings", AttemptedInstructionCount, warningCount); + $stop; $stop; + end + end // if (`DEBUG_TRACE >= 1) + end // if (checkInstrW) + end // always @ (negedge clk) + + + // New IP spoofing + logic globalIntsBecomeEnabled; + assign globalIntsBecomeEnabled = (`CSR_BASE.csrm.WriteMSTATUSM || `CSR_BASE.csrs.csrs.WriteSSTATUSM) && (|(`CSR_BASE.CSRWriteValM & (~`CSR_BASE.csrm.MSTATUS_REGW) & 32'h22)); + logic checkInterruptM; + assign checkInterruptM = dut.core.ieu.InstrValidM & ~dut.core.priv.priv.trap.InstrPageFaultM & ~dut.core.priv.priv.trap.InterruptM; + + always @(negedge clk) begin + if(checkInterruptM) begin + if((interruptInstrCount+1) == AttemptedInstructionCount) begin + if(!NO_SPOOFING) begin + case (interruptCauseVal) + 11: begin + force `MEIP = 1; + force `UART_IP = 1; + end + 09: begin + force `SEIP = 1; + force `UART_IP = 1; + end + 07: force `MTIP = 1; + default: $display("Unsupported interrupt in interrupts.txt. cause = %0d",interruptCauseVal); + endcase + $display("Forcing interrupt."); + end + `SCAN_NEW_INTERRUPT + if (globalIntsBecomeEnabled) begin + $display("Enabled global interrupts"); + // The idea here is if a CSR instruction causes an interrupt by + // enabling interrupts, that CSR instruction will commit. + end else begin + // Other instructions, however, will get interrupted and not + // commit, so we don't want our W-stage checker to look for them + // and get confused when it doesn't find them. + garbageInt = $fgets(garbageString,traceFileE); + garbageInt = $fgets(garbageString,traceFileM); + AttemptedInstructionCount += 1; + end + end + end + end + + + + + + + + + + + /////////////////////////////////////////////////////////////////////////////// + //////////////////////////////// Extra Features /////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + // Function Tracking + FunctionName FunctionName(.reset(reset), + .clk(clk), + .ProgramAddrMapFile(ProgramAddrMapFile), + .ProgramLabelMapFile(ProgramLabelMapFile)); + + // Instr Opcode Tracking + // For waveview convenience + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, + dut.core.ifu.InstrRawF[31:0], + dut.core.ifu.InstrD, dut.core.ifu.InstrE, + dut.core.ifu.InstrM, InstrW, + InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); + + // ------------------ + // Address Translator + // ------------------ + /** + * Walk the page table stored in ram according to sv39 logic and translate a + * virtual address to a physical address. + * + * See section 4.3.2 of the RISC-V Privileged specification for a full + * explanation of the below algorithm. + */ + logic SvMode, PTE_R, PTE_X; + logic [`XLEN-1:0] SATP, PTE; + logic [55:0] BaseAdr, PAdr; + logic [8:0] VPN [2:0]; + logic [11:0] Offset; + function logic [`XLEN-1:0] adrTranslator( + input logic [`XLEN-1:0] adrIn); + begin + int i; + // Grab the SATP register from privileged unit + SATP = dut.core.priv.priv.csr.SATP_REGW; + // Split the virtual address into page number segments and offset + VPN[2] = adrIn[38:30]; + VPN[1] = adrIn[29:21]; + VPN[0] = adrIn[20:12]; + Offset = adrIn[11:0]; + // We do not support sv48; only sv39 + SvMode = SATP[63]; + // Only perform translation if translation is on and the processor is not + // in machine mode + if (SvMode & (dut.core.priv.priv.PrivilegeModeW != `M_MODE)) begin + BaseAdr = SATP[43:0] << 12; + for (i = 2; i >= 0; i--) begin + PAdr = BaseAdr + (VPN[i] << 3); + // ram.memory.RAM is 64-bit addressed. PAdr specifies a byte. We right shift + // by 3 (the PTE size) to get the requested 64-bit PTE. + PTE = dut.uncore.uncore.ram.ram.memory.RAM[PAdr >> 3]; + PTE_R = PTE[1]; + PTE_X = PTE[3]; + if (PTE_R | PTE_X) begin + // Leaf page found + break; + end else begin + // Go to next level of table + BaseAdr = PTE[53:10] << 12; + end + end + // Determine which parts of the PTE page number to use based on the + // level of the page table we reached. + if (i == 2) begin + // Gigapage + assign adrTranslator = {8'b0, PTE[53:28], VPN[1], VPN[0], Offset}; + end else if (i == 1) begin + // Megapage + assign adrTranslator = {8'b0, PTE[53:19], VPN[0], Offset}; + end else begin + // Kilopage + assign adrTranslator = {8'b0, PTE[53:10], Offset}; + end + end else begin + // Direct translation if address translation is not on + assign adrTranslator = adrIn; + end + end + endfunction +endmodule