Merge branch 'main' of github.com:davidharrishmc/riscv-wally into main

This commit is contained in:
Thomas Fleming 2021-04-29 16:30:00 -04:00
commit 6e5fc107d9
14 changed files with 691 additions and 195 deletions

View File

@ -1,11 +1,14 @@
# check for warnings in Verilog code
# The verilator lint tool is faster and better than Modelsim so it is best to run this first.
echo "rv64ic linting..."
verilator --lint-only "$@" --top-module wallypipelinedsoc -Iconfig/rv64ic src/*/*.sv
echo "rv32ic linting..."
verilator --lint-only "$@" --top-module wallypipelinedsoc -Iconfig/rv32ic src/*/*.sv
#verilator --lint-only --top-module wallypipelinedsoc -Iconfig/rv64ic src/*/*.sv src/*/div/*.sv
for config in rv64ic rv32ic; do
echo "$config linting..."
if !(verilator --lint-only "$@" --top-module wallypipelinedsoc "-Iconfig/$config" src/*/*.sv); then
echo "Exiting after $config lint due to errors or warnings"
exit 1
fi
done
echo "All lints run with no errors or warnings"
# --lint-only just runs lint rather than trying to compile and simulate
# -I points to the include directory where files such as `include wally-config.vh are found

View File

@ -30,34 +30,43 @@ vlib work
# default to config/rv64ic, but allow this to be overridden at the command line. For example:
# do wally-pipelined.do ../config/rv32ic
switch $argc {
0 {vlog +incdir+../config/rv64ic ../testbench/testbench-privileged.sv ../src/*/*.sv -suppress 2583}
1 {vlog +incdir+$1 ../testbench/testbench-privileged.sv ../testbench/function_radix.sv ../src/*/*.sv -suppress 2583}
0 {vlog +incdir+../config/rv64ic ../testbench/testbench-imperas.sv ../src/*/*.sv -suppress 2583}
1 {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 +acc work.testbench -o workopt
vsim workopt
view wave
-- display input and output signals as hexidecimal values
do ./wave-dos/default-waves.do
-- Set Wave Output Items
onerror {resume}
add wave -noupdate /testbench/clk
add wave -noupdate /testbench/reset
add wave -noupdate -expand -group {Execution Stage} /testbench/dut/hart/ifu/PCE
quietly WaveActivateNextPane {} 0
TreeUpdate [SetDefaultTree]
WaveRestoreZoom {0 ps} {100 ps}
WaveRestoreCursors {{Cursor 2} {12215488 ns} 0} {{Cursor 4} {22127 ns} 0}
quietly wave cursor active 2
configure wave -namecolwidth 250
configure wave -valuecolwidth 140
configure wave -valuecolwidth 513
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
set DefaultRadix hexadecimal
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {21993 ns} {22181 ns}
-- Run the Simulation
#run 4100
#run 5000
run -all
#quit
noview ../testbench/testbench-imperas.sv
view wave

View File

@ -63,4 +63,4 @@ configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
set DefaultRadix hexadecimal
set DefaultRadix hexadecimal

View File

@ -41,13 +41,13 @@ module globalHistoryPredictor
input logic [1:0] UpdatePrediction
);
logic [k-1:0] GHRF, GHRD, GHRE, GHRENext;
assign GHRENext = {PCSrcE, GHRE[k-1:1]};
logic [k-1:0] GHRF, GHRFNext;
assign GHRFNext = {PCSrcE, GHRF[k-1:1]};
flopenr #(k) GlobalHistoryRegister(.clk(clk),
.reset(reset),
.en(UpdateEN),
.d(GHRENext),
.d(GHRFNext),
.q(GHRF));
@ -65,7 +65,7 @@ module globalHistoryPredictor
.RA1(GHRF),
.RD1(PredictionMemory),
.REN1(~StallF),
.WA1(GHRENext),
.WA1(GHRFNext),
.WD1(UpdatePrediction),
.WEN1(UpdateEN),
.BitWEN1(2'b11));
@ -73,7 +73,7 @@ module globalHistoryPredictor
// need to forward when updating to the same address as reading.
// first we compare to see if the update and lookup addreses are the same
assign DoForwarding = GHRF == GHRE;
assign DoForwarding = GHRF == GHRFNext;
// register the update value and the forwarding signal into the Fetch stage
// TODO: add stall logic ***
@ -90,7 +90,7 @@ module globalHistoryPredictor
assign Prediction = DoForwardingF ? UpdatePredictionF : PredictionMemory;
//pipeline for GHR
flopenrc #(k) GHRDReg(.clk(clk),
/*flopenrc #(k) GHRDReg(.clk(clk),
.reset(reset),
.en(~StallD),
.clear(FlushD),
@ -103,5 +103,5 @@ module globalHistoryPredictor
.clear(FlushE),
.d(GHRD),
.q(GHRE));
*/
endmodule

View File

@ -42,24 +42,24 @@ module gsharePredictor
);
logic [k-1:0] GHRF, GHRD, GHRE, GHRENext;
logic [k-1:0] GHRF, GHRFNext;
//logic [k-1:0] LookUpPCIndexD, LookUpPCIndexE;
logic [k-1:0] LookUpPCIndex, UpdatePCIndex;
logic [1:0] PredictionMemory;
logic DoForwarding, DoForwardingF;
logic [1:0] UpdatePredictionF;
assign GHRENext = {PCSrcE, GHRE[k-1:1]};
assign GHRFNext = {PCSrcE, GHRF[k-1:1]};
flopenr #(k) GlobalHistoryRegister(.clk(clk),
.reset(reset),
.en(UpdateEN),
.d(GHRENext),
.d(GHRFNext),
.q(GHRF));
// for gshare xor the PC with the GHR
assign UpdatePCIndex = GHRENext ^ UpdatePC[k:1];
assign UpdatePCIndex = GHRFNext ^ UpdatePC[k:1];
assign LookUpPCIndex = GHRF ^ LookUpPC[k:1];
// Make Prediction by reading the correct address in the PHT and also update the new address in the PHT
// GHR referes to the address that the past k branches points to in the prediction stage
@ -110,7 +110,7 @@ module gsharePredictor
.q(LookUpPCIndexE));
-----/\----- EXCLUDED -----/\----- */
flopenrc #(k) GHRRegD(.clk(clk),
/* flopenrc #(k) GHRRegD(.clk(clk),
.reset(reset),
.en(~StallD),
.clear(FlushD),
@ -124,5 +124,5 @@ module gsharePredictor
.d(GHRD),
.q(GHRE));
*/
endmodule

View File

@ -44,13 +44,13 @@ module localHistoryPredictor
);
logic [2**m-1:0][k-1:0] LHRNextF;
logic [k-1:0] LHRF, LHRD, LHRE, LHRENext, ForwardLHRNext;
logic [k-1:0] LHRF, ForwardLHRNext;
logic [m-1:0] LookUpPCIndex, UpdatePCIndex;
logic [1:0] PredictionMemory;
logic DoForwarding, DoForwardingF, DoForwardingPHT, DoForwardingPHTF;
logic [1:0] UpdatePredictionF;
assign LHRENext = {PCSrcE, LHRE[k-1:1]};
assign LHRFNext = {PCSrcE, LHRF[k-1:1]};
assign UpdatePCIndex = {UpdatePC[m+1] ^ UpdatePC[1], UpdatePC[m:2]};
assign LookUpPCIndex = {LookUpPC[m+1] ^ LookUpPC[1], LookUpPC[m:2]};
@ -72,7 +72,7 @@ generate
flopenr #(k) LocalHistoryRegister(.clk(clk),
.reset(reset),
.en(UpdateEN && (index == UpdatePCIndex)),
.d(LHRENext),
.d(LHRFNext),
.q(LHRNextF[index]));
end
endgenerate
@ -80,7 +80,7 @@ endgenerate
// need to forward when updating to the same address as reading.
// first we compare to see if the update and lookup addreses are the same
assign DoForwarding = LookUpPCIndex == UpdatePCIndex;
assign ForwardLHRNext = DoForwarding ? LHRENext :LHRNextF[LookUpPCIndex];
assign ForwardLHRNext = DoForwarding ? LHRFNext :LHRNextF[LookUpPCIndex];
// Make Prediction by reading the correct address in the PHT and also update the new address in the PHT
// LHR referes to the address that the past k branches points to in the prediction stage
@ -90,14 +90,14 @@ assign ForwardLHRNext = DoForwarding ? LHRENext :LHRNextF[LookUpPCIndex];
.RA1(ForwardLHRNext),
.RD1(PredictionMemory),
.REN1(~StallF),
.WA1(LHRENext),
.WA1(LHRFNext),
.WD1(UpdatePrediction),
.WEN1(UpdateEN),
.BitWEN1(2'b11));
assign DoForwardingPHT = LHRENext == ForwardLHRNext;
assign DoForwardingPHT = LHRFNext == ForwardLHRNext;
// register the update value and the forwarding signal into the Fetch stage
// TODO: add stall logic ***
@ -120,7 +120,7 @@ assign DoForwardingPHT = LHRENext == ForwardLHRNext;
.clear(FlushF),
.d(ForwardLHRNext),
.q(LHRF));
/*
flopenrc #(k) LHRDReg(.clk(clk),
.reset(reset),
.en(~StallD),
@ -134,5 +134,5 @@ assign DoForwardingPHT = LHRENext == ForwardLHRNext;
.clear(FlushE),
.d(LHRD),
.q(LHRE));
*/
endmodule

View File

@ -36,6 +36,7 @@ module csr #(parameter
input logic FlushW, StallD, StallE, StallM, StallW,
input logic [31:0] InstrM,
input logic [`XLEN-1:0] PCM, SrcAM,
input logic InterruptM,
input logic CSRReadM, CSRWriteM, TrapM, MTrapM, STrapM, UTrapM, mretM, sretM, uretM,
input logic TimerIntM, ExtIntM, SwIntM,
input logic InstrValidW, FloatRegWriteW, LoadStallD,
@ -71,7 +72,14 @@ module csr #(parameter
logic WriteMSTATUSM, WriteSSTATUSM, WriteUSTATUSM;
logic CSRMWriteM, CSRSWriteM, CSRUWriteM;
logic [`XLEN-1:0] UnalignedNextEPCM, NextEPCM, NextCauseM, NextMtvalM;
logic [`XLEN-1:0] UnalignedNextEPCM, NextEPCM, preservedPCM, readPCM, NextCauseM, NextMtvalM;
always_ff @(posedge clk) begin
preservedPCM <= PCM;
end
mux2 #(`XLEN) pcmux(PCM, preservedPCM, InterruptM, readPCM);
//flop #(`XLEN) CSRReadPCMreg(clk, reset, PCM, readPCM);
logic [11:0] CSRAdrM;
logic [11:0] SIP_REGW, SIE_REGW;
@ -100,7 +108,7 @@ module csr #(parameter
// write CSRs
assign CSRAdrM = InstrM[31:20];
assign UnalignedNextEPCM = TrapM ? PCM : CSRWriteValM;
assign UnalignedNextEPCM = TrapM ? readPCM : CSRWriteValM;
assign NextEPCM = `C_SUPPORTED ? {UnalignedNextEPCM[`XLEN-1:1], 1'b0} : {UnalignedNextEPCM[`XLEN-1:2], 2'b00}; // 3.1.15 alignment
assign NextCauseM = TrapM ? CauseM : CSRWriteValM;
assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM;

View File

@ -85,7 +85,8 @@ module privileged (
logic IllegalInstrFaultM;
logic BreakpointFaultM, EcallFaultM;
logic MTrapM, STrapM, UTrapM;
logic MTrapM, STrapM, UTrapM;
logic InterruptM;
logic [1:0] STATUS_MPP;
logic STATUS_SPP, STATUS_TSR;

View File

@ -41,13 +41,14 @@ module trap (
input logic [`XLEN-1:0] InstrMisalignedAdrM, MemAdrM,
input logic [31:0] InstrM,
output logic TrapM, MTrapM, STrapM, UTrapM, RetM,
output logic InterruptM,
output logic [`XLEN-1:0] PrivilegedNextPCM, CauseM, NextFaultMtvalM
// output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW,
// input logic WriteMIPM, WriteSIPM, WriteUIPM, WriteMIEM, WriteSIEM, WriteUIEM
);
logic [11:0] MIntGlobalEnM, SIntGlobalEnM, PendingIntsM;
logic InterruptM;
//logic InterruptM;
logic [`XLEN-1:0] PrivilegedTrapVector, PrivilegedVectoredTrapVector;
// Determine pending enabled interrupts

View File

@ -354,7 +354,9 @@ module testbench();
"rv64p/WALLY-MARCHID", "4000",
"rv64p/WALLY-MIMPID", "4000",
"rv64p/WALLY-MHARTID", "4000",
"rv64p/WALLY-MVENDORID", "4000"
"rv64p/WALLY-MVENDORID", "4000",
"rv64p/WALLY-MIE", "3000",
"rv64p/WALLY-MEDELEG", "4000"
};
string tests32p[] = '{
@ -368,6 +370,7 @@ module testbench();
"rv32p/WALLY-MIMPID", "4000",
"rv32p/WALLY-MHARTID", "4000",
"rv32p/WALLY-MVENDORID", "4000"
//"rv32p/WALLY-MEDELEG", "4000" // all 32 bit tests are currently failing, so haven't been able to confirm this test works yet. It should, though.
};
string tests64periph[] = '{

View File

@ -58,8 +58,44 @@ def writeVectors(storecmd, returningInstruction):
# """)
# User Timer Interrupt: True, 4
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Supervior timer interrupt: True, 5
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Machine timer interrupt: True, 7
# TODO: THIS NEEDS TO BE IMPLEMENTED
# if fromMode == "m":
# clintAddr = "0x2004000"
# writeTest(storecmd, f, r, f"""
# li x1, 0x8
# csrrs x0, {fromMode}status, x1
# la x18, {clintAddr}
# lw x11, 0(x18)
# li x1, 1
# # {storecmd} x1, 0(x18)
# li x1, 0x80
# csrrs x0, {fromMode}ie, x1
# nop
# nop
# nop
# nop
# nop
# nop
# nop
# """, True, 4, f"""
# li x1, 0x80
# # csrrc x0, {fromMode}ie, x1
# li x1, 0x8
# # csrrc x0, {fromMode}status, x1
# la x18, {clintAddr}
# {storecmd} x11, 0(x18)
# """)
# writeTest(storecmd, f, r, f"""
# li x10, MASK_XLEN(0x8)
@ -121,10 +157,17 @@ def writeVectors(storecmd, returningInstruction):
# """)
# User external input: True, 8
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Supervisor external input: True, 9
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Machine externa input: True, 11
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Instruction address misaligned: False, 0
# TODO: THIS NEEDS TO BE IMPLEMENTED
# looks like this is giving us an infinite loop for wally
# BUG: jumping to a misaligned instruction address doesn't cause an exception: we actually jump...
# Either that, or somehow at the end we always end up at 0x80004002
@ -135,6 +178,7 @@ def writeVectors(storecmd, returningInstruction):
# """, False, 0)
# Instruction access fault: False, 1
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Illegal Instruction
writeTest(storecmd, f, r, f"""
@ -153,16 +197,14 @@ def writeVectors(storecmd, returningInstruction):
""", False, 4)
# Load Access fault: False, 5
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Store/AMO address misaligned
writeTest(storecmd, f, r, f"""
sw x0, 11(x0)
""", False, 6)
# Environment call from u-mode: only for when only M and U mode enabled?
# writeTest(storecmd, f, r, f"""
# ecall
# """, False, 8, "u")
# Environment call
if returningInstruction != "ecall":
if fromMode == "u":
writeTest(storecmd, f, r, f"""
@ -182,8 +224,13 @@ def writeVectors(storecmd, returningInstruction):
""", False, 11, "m")
# Instruction page fault: 12
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Load page fault: 13
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Store/AMO page fault: 15
# TODO: THIS NEEDS TO BE IMPLEMENTED
@ -194,7 +241,7 @@ def writeTest(storecmd, f, r, test, interrupt, code, mode = "m", resetHander = "
expected = code
if(interrupt):
expected+=(1 << (wordsize - 1))
expected+=(1 << (xlen - 1))
trapEnd = ""
@ -316,6 +363,8 @@ for xlen in xlens:
csrs sedeleg, x9
"""
clintAddr = "0x2004000"
lines += f"""
li x30, 0
@ -328,6 +377,32 @@ for xlen in xlens:
j _j_t_begin_{returningInstruction}
_j_m_trap_{returningInstruction}:
#li x1, 0x20
#csrrw x0, mie, x1
li x11, 0x3fffffffffffffff
la x18, {clintAddr}
{storecmd} x11, 0(x18)
li x1, 0x8
csrrc x0, mstatus, x1
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
sub x1, x2, x3
csrrs x1, mepc, x0
{"csrr x25, mcause" if testMode == "m" else "li x25, 0xBAD00003"}

View File

@ -0,0 +1,291 @@
#!/usr/bin/python3
##################################
# testgen-CAUSE.py
#
# dottolia@hmc.edu 27 Apr 2021
#
# Generate directed and random test vectors for RISC-V Design Validation.
#
#
##################################
# DOCUMENTATION:
# Most of the comments explaining what everything
# does can be found in testgen-TVAL.py
###################################
##################################
# libraries
##################################
from datetime import datetime
from random import randint
from random import seed
from random import getrandbits
##################################
# functions
##################################
#For instruction-fetch access or page-fault exceptions on systems with variable-length instructions, mtval will contain the virtual address of the portion of the instruction that caused the fault while mepc will point to the beginning of the instruction.
def randRegs():
reg1 = randint(1,20)
reg2 = randint(1,20)
reg3 = randint(1,20)
if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2):
return randRegs()
else:
return str(reg1), str(reg2), str(reg3)
def writeVectors(storecmd):
global testnum
# User Software Interrupt: True, 0
# Supervisor Software Interrupt: True, 1
# Machine Software Interrupt: True, 2
# User external input: True, 8
# Supervisor external input: True, 9
# Machine externa input: True, 11
# Instruction address misaligned: False, 0
# Instruction access fault: False, 1
# Illegal Instruction
#writeTest(storecmd, f, r, "ecall", False, 11)
writeTest(storecmd, f, r, f"""
.fill 1, 4, 0
""", False, 2)
# Breakpoint
writeTest(storecmd, f, r, "ebreak", False, 3)
# Load Address Misaligned
writeTest(storecmd, f, r, f"""
lw x0, 11(x0)
""", False, 4)
# # Load Access fault: False, 5
# TODO: THIS NEEDS TO BE IMPLEMENTED
# # Store/AMO address misaligned
writeTest(storecmd, f, r, f"""
sw x0, 11(x0)
""", False, 6)
# Breakpoint: codes 8, 9, 11
writeTest(storecmd, f, r, "ecall", False, -1) # code determined inside of writeTest
# Instruction page fault: 12
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Load page fault: 13
# TODO: THIS NEEDS TO BE IMPLEMENTED
# Store/AMO page fault: 15
# TODO: THIS NEEDS TO BE IMPLEMENTED
#writeTest(storecmd, f, r, "ecall", False, 11, "m")
def writeTest(storecmd, f, r, test, interrupt, code, resetHander = ""):
global testnum
global testMode
global isInterrupts
if interrupt != isInterrupts:
return
delegateType = "i" if interrupt else "e"
for mode in (["m", "s", "u"] if testMode == "m" else ["s", "u"]):
if test == "ecall":
if mode == "m":
code = 11
elif mode == "s":
code = 9
else:
code = 8
mask = 1 << code
for delegated in [True, False]:
labelSuffix = testnum
f.write(f"""
_start_{labelSuffix}:
la x1, _j_m_trap_{labelSuffix}
csrw mtvec, x1
la x1, _j_s_trap_{labelSuffix}
csrw stvec, x1
j _j_test_{labelSuffix}
_j_m_trap_{labelSuffix}:
li x25, 3
csrr x1, mepc
addi x1, x1, 4
csrrw x0, mepc, x1
bnez x30, _j_finished_{labelSuffix}
mret
_j_s_trap_{labelSuffix}:
li x25, 1
csrr x1, sepc
addi x1, x1, 4
csrrw x0, sepc, x1
bnez x30, _j_goto_machine_mode_{labelSuffix}
sret
_j_goto_machine_mode_{labelSuffix}:
li x30, 1
{"ebreak" if test is not "ebreak" else "ecall"}
_j_test_{labelSuffix}:
""")
original = f"""
li x1, {mask if delegated else 0}
csrw m{delegateType}deleg, x1
"""
lines = original + "\n" + test
if mode != "m":
lines = f"""
{original}
li x1, 0b110000000000
csrrc x28, {testMode}status, x1
li x1, 0b{"01" if mode == "s" else "00"}00000000000
csrrs x28, {testMode}status, x1
auipc x1, 0
addi x1, x1, 16 # x1 is now right after the ret instruction
csrrw x27, {testMode}epc, x1
{testMode}ret
# From {testMode}, we're now in {mode} mode...
{test}
"""
writeTestInner(storecmd, f, r, lines, 1 if delegated else 3)
f.write(f"""
j _j_goto_machine_mode_{labelSuffix}
""")
else:
writeTestInner(storecmd, f, r, lines, 3)
f.write(f"""
_j_finished_{labelSuffix}:
li x30, 0
""")
def writeTestInner(storecmd, f, r, lines, expected):
global testnum
lines = f"""
li x25, 0xDEADBEA7
{lines}
"""
lines += storecmd + " x25, " + str(testnum * wordsize) + "(x6)\n"
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
##################################
# change these to suite your tests
author = "dottolia@hmc.edu"
xlens = [32, 64]
numrand = 1;
# setup
seed(0xD0C0_D0C0_D0C0_D0C0) # 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
for testMode in ["m"]:
for isInterrupts in [True, False]:
imperaspath = "../../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "p/"
basename = "WALLY-" + testMode.upper() + ("I" if isInterrupts else "E") + "DELEG"
fname = imperaspath + "src/" + basename + ".S"
refname = imperaspath + "references/" + basename + ".reference_output"
# 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)
# All registers used:
# x19: mtvec old value
# x18: medeleg old value
# x17: mideleg old value
f.write(f"""
add x7, x6, x0
csrr x19, mtvec
csrr x18, medeleg
csrr x17, medeleg
""")
testnum = 0
for i in range(0, 2):
writeVectors(storecmd)
f.write(f"""
csrw mtvec, x19
csrw medeleg, x18
csrw mideleg, x17
""")
# if we're in supervisor mode, this leaves the ebreak instruction untested (we need a way to)
# get back to machine mode.
# 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()

View File

@ -20,84 +20,91 @@ from random import getrandbits
# functions
##################################
def writeTrapHandlers(storecmd):
def writeTrapHandlers(storecmd, mode):
global testnum
[reg1, reg2, reg3] = [30, 29, 28]
[reg4, reg5] = [27, 26]
lines = "\n# Trap Handler: Machine Timer Interupt\n"
lines += "_timerM_trap_handler:\n"
lines += "li x" + str(reg1) + ", MASK_XLEN(0x2A)\n"
lines += "la x" + str(reg2) + ", 0x2004000\n"
lines += str(storecmd) + " x" + str(reg1) + ", 0(x" + str(reg2) + ")\n"
lines += "csrrw x" + str(reg3) + ", mepc, x0\n"
lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
if mode == "M":
lines = "\n# Trap Handler: Machine Timer Interupt\n"
lines += "_timerM_trap_handler:\n"
lines += "li x" + str(reg1) + ", MASK_XLEN(0xFFFF)\n"
lines += "la x" + str(reg2) + ", 0x2004000\n"
lines += str(storecmd) + " x" + str(reg1) + ", 0(x" + str(reg2) + ")\n"
lines += "csrrc x" + str(reg3) + ", mepc, x0\n"
lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
lines += "csrrw x0, mepc, x" + str(reg3) + "\n"
# clear machine timer interupt enable bit in mie
lines += "li x" + str(reg4) + ", MASK_XLEN(" + str(0x80) + ")\n"
lines += "csrrc x0, mie, x" + str(reg4) + "\n"
lines += "mret\n"
elif mode == "S":
lines = "\n# Trap Handler: Supervisor Timer Interupt\n"
lines += "_timerS_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x20)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
lines += "\n# Trap Handler: Supervisor Timer Interupt\n"
lines += "_timerS_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x20)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
#lines += "\n# Trap Handler: User Timer Interupt\n"
#lines += "_timerU_trap_handler:\n"
#lines += "li x" + str(reg4) + ", MASK_XLEN(0x10)\n"
#lines += "csrrc x0, mip, x" + str(reg4) + "\n"
#lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
#lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
#lines += "mret\n"
lines += "\n# Trap Handler: User Timer Interupt\n"
lines += "_timerU_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x10)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
lines += "\n# Trap Handler: Machine Software Interupt\n"
lines += "_softwareM_trap_handler:\n"
lines += "li x" + str(reg1) + ", MASK_XLEN(0x0)\n" # clear MSIP bit in CLINT
lines += "la x" + str(reg2) + ", 0x2000000\n"
lines += str(storecmd) + " x" + str(reg1) + ", 0(x" + str(reg2) + ")\n"
lines += "csrrw x" + str(reg3) + ", mepc, x0\n"
lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
lines += "\n# Trap Handler: Supervisor Software Interupt\n"
lines += "_softwareS_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x2)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
lines += "\n# Trap Handler: User Software Interupt\n"
lines += "_softwareU_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x1)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
lines += "\n# Trap Handler: Machine External Interupt\n"
lines += "_externalM_trap_handler:\n"
#lines += "\n# Trap Handler: Machine Software Interupt\n"
#lines += "_softwareM_trap_handler:\n"
#lines += "li x" + str(reg1) + ", MASK_XLEN(0x0)\n" # clear MSIP bit in CLINT
#lines += "la x" + str(reg2) + ", 0x2000000\n"
#lines += str(storecmd) + " x" + str(reg1) + ", 0(x" + str(reg2) + ")\n"
lines += "csrrw x" + str(reg3) + ", mepc, x0\n"
lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
##lines += "csrrs x" + str(reg3) + ", mepc, x0\n"
#lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
#lines += "csrrw x0, mepc, x" + str(reg3) + "\n"
#lines += "mret\n"
lines += "\n# Trap Handler: Supervisor External Interupt\n"
lines += "_externalS_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x200)\n"
"""lines += "\n# Trap Handler: Supervisor Software Interupt\n"
lines += "_softwareS_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x2)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "csrrs x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "csrrw x0, mepc, x" + str(reg5) + "\n"
lines += "mret\n"
"""
#lines += "\n# Trap Handler: User Software Interupt\n"
#lines += "_softwareU_trap_handler:\n"
#lines += "li x" + str(reg4) + ", MASK_XLEN(0x1)\n"
#lines += "csrrc x0, mip, x" + str(reg4) + "\n"
#lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
#lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
#lines += "mret\n"
lines += "\n# Trap Handler: User External Interupt\n"
lines += "_externalU_trap_handler:\n"
lines += "li x" + str(reg4) + ", MASK_XLEN(0x100)\n"
lines += "csrrc x0, mip, x" + str(reg4) + "\n"
lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
lines += "mret\n"
#lines += "\n# Trap Handler: Machine External Interupt\n"
#lines += "_externalM_trap_handler:\n"
#lines += "li x" + str(reg1) + ", MASK_XLEN(0x0)\n" # clear MSIP bit in CLINT
#lines += "la x" + str(reg2) + ", 0x2000000\n"
#lines += str(storecmd) + " x" + str(reg1) + ", 0(x" + str(reg2) + ")\n"
#lines += "csrrw x" + str(reg3) + ", mepc, x0\n"
#lines += "addi x"+ str(reg3) + ", x" + str(reg3) + ", MASK_XLEN(0x4)\n"
#lines += "mret\n"
#lines += "\n# Trap Handler: Supervisor External Interupt\n"
#lines += "_externalS_trap_handler:\n"
#lines += "li x" + str(reg4) + ", MASK_XLEN(0x200)\n"
#lines += "csrrc x0, mip, x" + str(reg4) + "\n"
#lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
#lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
#lines += "mret\n"
#lines += "\n# Trap Handler: User External Interupt\n"
#lines += "_externalU_trap_handler:\n"
#lines += "li x" + str(reg4) + ", MASK_XLEN(0x100)\n"
#lines += "csrrc x0, mip, x" + str(reg4) + "\n"
#lines += "csrrw x" + str(reg5) + ", mepc, x0\n"
#lines += "addi x"+ str(reg5) + ", x" + str(reg5) + ", MASK_XLEN(0x4)\n"
#lines += "mret\n"
f.write(lines)
@ -156,26 +163,32 @@ def getMcause():
def writeVectors(a, xlen, storecmd):
global testnum
[reg1, reg2, reg3] = [1, 2, 3]
# Registers used:
# x13 ---> read mcause value
# x12 ---> save old value of mtvec
# x8 ---> holds mieE
# x5 ---> holds value of trap handler
# x3 ---> holds mstatusE
# remaining registers (not used by mode management) are free to be used by tests
[reg2, reg3] = [2, 3]
[reg5, reg8] = [5, 8]
[reg9, reg10, reg11, reg12] = [9, 10, 11, 12]
[reg10, reg11, reg12] = [10, 11, 12]
[reg13, reg14, reg15] = [13, 14, 15]
lines = f"\n# Testcase {testnum}: {test} Interupt\n"
# mcause code
expected = getMcause()
lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(expected) + ")\n"
if (testnum == 0): expected = 0
[mstatusE, mieE] = getInteruptEnableValues()
# set interupt enable bit in mstatus
lines += "li x" + str(reg3) + ", MASK_XLEN(" + str(mstatusE) + ")\n"
lines += "csrrs x0, mstatus, x" + str(reg3) + "\n"
# ensure interupt enable bit in mie is low
lines += "li x" + str(reg8) + ", MASK_XLEN(" + formatstr.format(mieE) + ")\n"
lines += "csrrc x0, mie, x" + str(reg8) + "\n"
# set timer interupt enable bit in mie
lines += "li x" + str(reg9) + ", MASK_XLEN(" + str(mieE) + ")\n"
lines += "csrrs x0, mie, x" + str(reg3) + "\n"
# set interupt enable bit in mstatus
lines += "li x" + str(reg3) + ", MASK_XLEN(" + formatstr.format(mstatusE) + ")\n"
lines += "csrrs x0, mstatus, x" + str(reg3) + "\n"
# Save and set trap handler address for interrupt
lines += "la x" + str(reg5) + ", _" + test + "_trap_handler\n"
@ -185,59 +198,50 @@ def writeVectors(a, xlen, storecmd):
# cause timer interupt
if test == "timerM":
lines += "li x" + str(reg8) + ", MASK_XLEN(0)\n"
lines += str(storecmd) + " x" + str(reg8) + ", " + str(wordsize*testnum)+ "(x6)\n"
lines += "la x" + str(reg8) + ", 0x2004000\n"
# load MTIMECMP register address
lines += "la x" + str(reg2) + ", 0x2004000\n"
lines += "li x" + str(reg3) + ", MASK_XLEN(0)\n"
# to be stored in MTIMECMP
lines += "li x" + str(reg10) + ", MASK_XLEN(0)\n"
# save old value of mtimecmp and then set mtimecmp to zero
lines += "lw x" + str(reg11) + ", 0(x" + str(reg8) + ")\n"
lines += str(storecmd) + " x" + str(reg3) + ", 0(x" + str(reg8) + ")\n"
if xlens == 64:
lines += "lw x" + str(reg11) + ", 0(x" + str(reg2) + ")\n"
lines += str(storecmd) + " x" + str(reg10) + ", 0(x" + str(reg2) + ")\n"
elif xlen == 32:
lines += "lw x" + str(reg11) + ", 0(x" + str(reg2) + ")\n"
lines += str(storecmd) + " x" + str(reg10) + ", 0(x" + str(reg2) + ")\n"
lines += str(storecmd) + " x" + str(reg10) + ", 4(x" + str(reg2) + ")\n"
elif test == "timerS":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x20)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
elif test == "timerU":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x10)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
# cause software interupt
if test == "softwareM":
lines += "la x" + str(reg8) + ", 0x2000000\n" # Write to the MSIP bit in CLINT
lines += "li x" + str(reg3) + ", MASK_XLEN(0x1)\n"
lines += str(storecmd) + " x" + str(reg3) + ", 0(x" + str(reg8) + ")\n"
lines += "li x" + str(reg11) + ", MASK_XLEN(0x1)\n"
lines += str(storecmd) + " x" + str(reg11) + ", 0(x" + str(reg8) + ")\n"
elif test == "softwareS":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x2)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
elif test == "softwareU":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x1)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
# cause external interupt
# Not sure how to cause an external machine interupt yet
# will writing to PLIC just cause it? (where is the ExtIntM located in PLIC)
#if test == "externalM":
#lines += "la x" + str(reg8) + ", 0x2000000\n" # Write to the MSIP bit in CLINT
#lines += "li x" + str(reg3) + ", MASK_XLEN(0x1)\n"
#lines += str(storecmd) + " x" + str(reg3) + ", 0(x" + str(reg8) + ")\n"
if test == "externalS":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x200)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
elif test == "externalU":
lines += "li x" + str(reg3) + ", MASK_XLEN(0x100)\n"
lines += "csrrs x0, mip, x" + str(reg3) + "\n"
#lines += "wfi\n" # wait for interupt to be taken
# set timer interupt enable bit in mie
lines += "csrrs x0, mie, x" + str(reg8) + "\n"
# wait for interupt to be taken
lines += "nop\nnop\n"
lines += "csrrw " + " x" + str(reg2) + ", mcause, x" + str(reg1) + "\n"
lines += "csrrs " + " x" + str(reg13) + ", mcause, x0\n"
# reset mtvec
lines += "csrrw x0, mtvec, x" + str(reg12) + "\n"
lines += storecmd + " x" + str(reg2) + ", " + str(wordsize*testnum) + "(x6)\n"
lines += "RVTEST_IO_ASSERT_GPR_EQ(x7, x" + str(reg2) +", "+formatstr.format(expected)+")\n"
lines += storecmd + " x" + str(reg13) + ", " + str(wordsize*testnum) + "(x6)\n"
lines += "RVTEST_IO_ASSERT_GPR_EQ(x7, x" + str(reg13) +", "+formatstr.format(expected)+")\n"
f.write(lines)
if (xlen == 32):
line = formatrefstr.format(expected)+"\n"
@ -251,9 +255,10 @@ def writeVectors(a, xlen, storecmd):
##################################
# change these to suite your tests
tests = ["timerM"] #, "timerS", "timerU", "softwareM", "softwareS", "softwareU"]
tests = ["timerM"] #, "timerM", "timerS", "softwareM", "softwareS"]
author = "ushakya@hmc.edu"
xlens = [64, 32]
xlens = [64] #, 32]
modes = ["M"]#, "S"]
numrand = 100;
# setup
@ -270,9 +275,9 @@ for xlen in xlens:
else:
storecmd = "sd"
wordsize = 8
for test in tests:
for mode in modes:
imperaspath = "../../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "p/"
basename = "WALLY-IE"
basename = "WALLY-" + mode + "IE"
fname = imperaspath + "src/" + basename + ".S"
refname = imperaspath + "references/" + basename + ".reference_output"
testnum = 0
@ -291,13 +296,99 @@ for xlen in xlens:
h = open("../testgen_header.S", "r")
for line in h:
f.write(line)
line = "\n"
# Registers used for dropping down to supervisor mode:
# x30 ---> set to 1 if we should return to & stay in machine mode after trap, 0 otherwise
# x20 ---> hold address of _j_all_end_{returningInstruction}
# x19 ---> save old value of mtvec
# x18 ---> save old value of medeleg
# x16 ---> save old value of mideleg
# x9 ---> bit mask for mideleg and medeleg
# x1 ---> used to go down to supervisor mode
# print directed and random test vectors
for i in range(0,numrand):
a = getrandbits(xlen)
writeVectors(a, xlen, storecmd)
# We need to leave at least one bit in medeleg unset so that we have a way to get
# back to machine mode when the tests are complete (otherwise we'll only ever be able
# to get up to supervisor mode).
#
# So, we define a returning instruction which will be used to cause the exception that
# brings us into machine mode. The bit for this returning instruction is NOT set in
# medeleg. However, this also means that we can't test that instruction. So, we have
# two different returning instructions.
#
# Current code is written to only support ebreak and ecall.
#
# For testgen-IE, we don't need to test ebreak, so we can use that as the sole
# returning instruction.
returningInstruction = "ebreak"
if mode == "S":
# need to move down to supervisor mode (based on code in testgen-TVAL)
lines += f"""
# Reset x30 to 0 so we can run the tests. We'll set this to 1 when tests are completed so we stay in machine mode
li x30, 0
"""
writeTrapHandlers(storecmd)
# We don't want to delegate our returning instruction. Otherwise, we'll have no way of getting
# back to machine mode at the end! (and we need to be in machine mode to complete the tests)
medelegMask = "0b1111111111110111" if returningInstruction == "ebreak" else "0b1111000011111111"
# Set medeleg and mideleg
lines += f"""
csrr x18, medeleg
li x9, {medelegMask if testMode == "s" or testMode == "u" else "0"}
csrw medeleg, x9
csrr x16, mideleg
li x9, {"0xffffffff" if testMode == "s" or testMode == "u" else "0"}
csrw mideleg, x9
"""
# bring down to supervisor mode
lines += f"""
li x1, 0b110000000000
csrrc x28, mstatus, x1
li x1, 0b0100000000000
csrrs x28, mstatus, x1
auipc x1, 0
addi x1, x1, 16 # x1 is now right after the mret instruction
csrw mepc, x1
mret
# We're now in supervisor mode...
"""
for test in tests:
# print directed and random test vectors
for i in range(0,numrand):
a = getrandbits(xlen)
writeVectors(a, xlen, storecmd)
if mode == "S":
# Bring us back up to machine mode!
# Creates a new trap handler that just jumps to _j_all_end_{returningInstruction}
#
# Get into the trap handler by running returningInstruction (in this case its ebreak)
f.write(f"""
li x30, 1 #may not need this
csrr x19, mtvec # save old value of mtvec
la x20 _j_all_end_{returningInstruction}
csrw mtvec, x20
{returningInstruction}
_returnMachineMode_handler:
j _j_all_end_{returningInstruction}
mret
_j_all_end_{returningInstruction}:
# Reset trap handling csrs to old values
csrw mtvec, x19
csrw medeleg, x18
csrw mideleg, x16
""")
f.write(lines)
# print footer
h = open("../testgen_footer.S", "r")
@ -308,5 +399,8 @@ for xlen in xlens:
lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n"
lines = lines + "\nRV_COMPLIANCE_DATA_END\n"
f.write(lines)
writeTrapHandlers(storecmd, mode)
f.close()
r.close()

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
##################################
# testgen-CAUSE.py (new)
# testgen-TVEC.py (new)
#
# dottolia@hmc.edu 1 Mar 2021
#
@ -25,6 +25,12 @@ from random import randint
from random import seed
from random import getrandbits
##################################
# setup
##################################
areVectoredTrapsSupported = True
##################################
# functions
##################################
@ -43,29 +49,6 @@ def randRegs():
def writeVectors(storecmd, returningInstruction):
global testnum
if fromMode == "m":
expectedCode = 7 if fromMode == "m" else 5
clintAddr = "0x2004000"
writeTest(storecmd, f, r, f"""
li x1, 0x8
csrrs x0, {fromMode}status, x1
la x18, {clintAddr}
lw x11, 0(x18)
li x1, 1
{storecmd} x1, 0(x18)
li x1, 0x80
csrrs x0, {fromMode}ie, x1
""", True, expectedCode, f"""
la x18, {clintAddr}
{storecmd} x11, 0(x18)
li x1, 0x80
csrrc x0, {fromMode}ie, x1
""")
# Illegal Instruction
writeTest(storecmd, f, r, f"""
@ -112,6 +95,35 @@ def writeVectors(storecmd, returningInstruction):
ecall
""", False, 0)
if fromMode == "m":
expectedCode = 7 if fromMode == "m" else 5
clintAddr = "0x2004000"
writeTest(storecmd, f, r, f"""
li x1, 0x8
csrrs x0, {fromMode}status, x1
la x18, {clintAddr}
lw x11, 0(x18)
li x1, 0x3fffffffffffffff
{storecmd} x1, 0(x18)
li x1, 0x80
csrrs x0, {fromMode}ie, x1
{storecmd} x0, 0(x18)
""", True, expectedCode, f"""
li x1, 0x80
csrrc x0, {fromMode}ie, x1
li x1, 0x8
csrrc x0, {fromMode}status, x1
la x18, {clintAddr}
{storecmd} x0, 0(x18)
""")
# Instruction page fault: 12
# Load page fault: 13
# Store/AMO page fault: 15
@ -144,14 +156,13 @@ def writeTest(storecmd, f, r, test, interrupt, code, resetHander = ""):
{test}
"""
# We expect x25 to be 0 always. This is because of the code we wrote at the begining
# of this function
# Store the expected value of x25 to memory and in the .reference_output file
lines += f"""
{storecmd} x25, {testnum * wordsize}(x6)
"""
if not areVectoredTrapsSupported:
expected = 0
f.write(lines)
if (xlen == 32):
line = formatrefstr.format(expected)+"\n"
@ -291,7 +302,7 @@ for xlen in xlens:
# Set up
la x1, _j_m_trap_{returningInstruction}
addi x1, 1
#addi x1, 1
csrw mtvec, x1
la x1, _j_s_trap_{returningInstruction}
csrw stvec, x1