2021-04-29 19:02:36 +00:00
#!/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
2021-05-05 00:20:22 +00:00
writeTest ( storecmd , f , r , " timer-interrupt " , True , - 1 ) # code determined inside of writeTest
2021-04-29 19:02:36 +00:00
# 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
2021-04-29 19:32:13 +00:00
writeTest ( storecmd , f , r , f """
. fill 1 , 4 , 0
""" , False, 2)
2021-04-29 19:02:36 +00:00
# Breakpoint
writeTest ( storecmd , f , r , " ebreak " , False , 3 )
# Load Address Misaligned
2021-04-29 19:32:13 +00:00
writeTest ( storecmd , f , r , f """
lw x0 , 11 ( x0 )
""" , False, 4)
2021-04-29 19:02:36 +00:00
# # Load Access fault: False, 5
2021-04-29 19:32:13 +00:00
# TODO: THIS NEEDS TO BE IMPLEMENTED
2021-04-29 19:02:36 +00:00
# # Store/AMO address misaligned
2021-04-29 19:32:13 +00:00
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
2021-04-29 19:02:36 +00:00
#writeTest(storecmd, f, r, "ecall", False, 11, "m")
2021-04-29 19:32:13 +00:00
def writeTest ( storecmd , f , r , test , interrupt , code , resetHander = " " ) :
2021-04-29 19:02:36 +00:00
global testnum
global testMode
global isInterrupts
2021-05-05 00:20:22 +00:00
beforeTest = " "
2021-04-29 19:02:36 +00:00
if interrupt != isInterrupts :
return
2021-05-05 00:20:22 +00:00
isTimerInterruptTest = test == " timer-interrupt "
2021-04-29 19:02:36 +00:00
delegateType = " i " if interrupt else " e "
for mode in ( [ " m " , " s " , " u " ] if testMode == " m " else [ " s " , " u " ] ) :
2021-05-05 00:20:22 +00:00
if isTimerInterruptTest :
clintAddr = " 0x2004000 "
2021-04-29 19:32:13 +00:00
2021-05-05 00:20:22 +00:00
if mode == " m " :
code = 7
test = f """
la x18 , { clintAddr }
{ storecmd } x0 , 0 ( x18 )
"""
elif mode == " s " :
code = 5
test = " "
else :
code = 4
test = " "
ieMask = 1 << code
statusMask = 0b1010
beforeTest = f """
li x1 , { statusMask }
csrrs x0 , mstatus , x1
li x1 , 0b0010
csrrs x0 , sstatus , x1
la x18 , { clintAddr }
lw x11 , 0 ( x18 )
li x1 , 0x7fffffffffffffff
{ storecmd } x1 , 0 ( x18 )
li x1 , { ieMask }
csrrs x0 , mie , x1
li x1 , { ieMask }
csrrs x0 , sie , x1
"""
resetHander = f """
#li x1, 0x80
#csrrc x0, sie, x1
li x1 , { ieMask }
csrrc x0 , mie , x1
li x1 , { ieMask }
csrrc x0 , sie , x1
li x1 , { statusMask }
csrrc x0 , mstatus , x1
li x1 , 0b0010
csrrc x0 , sstatus , x1
la x18 , { clintAddr }
{ storecmd } x11 , 0 ( x18 )
"""
if mode == " s " :
beforeTest + = f """
li x1 , { ieMask }
csrrs x0 , sip , x1
"""
resetHander + = f """
li x1 , { ieMask }
csrrc x0 , sip , x1
"""
elif test == " ecall " :
2021-04-29 19:32:13 +00:00
if mode == " m " :
code = 11
elif mode == " s " :
code = 9
else :
code = 8
mask = 1 << code
2021-04-29 19:02:36 +00:00
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 } :
2021-05-05 00:20:22 +00:00
{ resetHander }
2021-04-29 19:02:36 +00:00
li x25 , 3
csrr x1 , mepc
addi x1 , x1 , 4
csrrw x0 , mepc , x1
bnez x30 , _j_finished_ { labelSuffix }
mret
_j_s_trap_ { labelSuffix } :
2021-05-05 00:20:22 +00:00
{ resetHander }
2021-04-29 19:02:36 +00:00
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
"""
if mode != " m " :
lines = f """
{ original }
2021-05-05 00:20:22 +00:00
{ beforeTest }
2021-04-29 19:02:36 +00:00
li x1 , 0b110000000000
2021-06-11 17:39:28 +00:00
csrrc x31 , { testMode } status , x1
2021-04-29 19:02:36 +00:00
li x1 , 0 b { " 01 " if mode == " s " else " 00 " } 00000000000
2021-06-11 17:39:28 +00:00
csrrs x31 , { testMode } status , x1
2021-04-29 19:02:36 +00:00
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 :
2021-05-05 00:20:22 +00:00
lines = f """
{ original }
{ beforeTest }
{ test }
"""
2021-04-29 19:02:36 +00:00
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 + " \n RV_COMPLIANCE_DATA_END \n "
f . write ( lines )
f . close ( )
r . close ( )