Merge conflict fixing

This commit is contained in:
ethan-falicov 2021-02-10 09:45:47 -05:00
commit 863796b3c1
5 changed files with 896 additions and 19 deletions

View File

@ -146,6 +146,13 @@ string tests64iNOc[] = {
"rv64i/WALLY-SLLI", "3000",
"rv64i/WALLY-SRLI", "3000",
"rv64i/WALLY-SRAI", "3000"
"rv64i/WALLY-LOAD", "11bf0",
"rv64i/WALLY-JAL", "4000",
"rv64i/WALLY-STORE", "3000",
"rv64i/WALLY-ADDIW", "3000",
"rv64i/WALLY-SLLIW", "3000",
"rv64i/WALLY-SRLIW", "3000",
"rv64i/WALLY-SRAIW", "3000"
};
string tests32ic[] = '{
// "rv32ic/WALLY-C-ADHOC-01", "2000",
@ -226,6 +233,7 @@ string tests32i[] = {
"rv32i/I-XOR-01","2000",
"rv32i/I-XORI-01","2000",
"rv32i/WALLY-ADD", "3000",
<<<<<<< HEAD
"rv32i/WALLY-SUB", "3000",
"rv32i/WALLY-ADDI", "2000",
"rv32i/WALLY-ANDI", "2000",
@ -236,6 +244,12 @@ string tests32i[] = {
"rv32i/WALLY-SLLI", "2000",
"rv32i/WALLY-SRLI", "2000",
"rv32i/WALLY-SRAI", "2000"
=======
"rv32i/WALLY-LOAD", "11c00",
"rv32i/WALLY-SUB", "3000",
"rv32i/WALLY-STORE", "2000",
"rv32i/WALLY-JAL", "3000"
>>>>>>> 88ccaff534d6bc14ccf767006b2d25505d0ce674
};
string tests[];

View File

@ -0,0 +1,182 @@
#!/usr/bin/python3
##################################
# testgen-ADDIW-SLLIW-SRLIW-SRAIW.py
#
# ehedenberg@hmc.edu 4 February 2021
# heavily influenced by Prof Harris Code
#
# Generate directed and random test vectors for RISC-V Design Validation.
##################################
##################################
# libraries
##################################
from datetime import datetime
from random import randint
from random import seed
from random import getrandbits
import sys
##################################
# functions
##################################
def logical_rshift(signed_integer, places):
unsigned_integer=signed_integer%(1<<32)
return unsigned_integer >> places
def toSigned12bit(n):
n=n & 0xfff
if (n&(1<<11)):
n=n|0xfffffffffffff000
return n
def toSigned32bit(n):
n=n & 0xffffffff
if (n&(1<<31)):
n=n|0xffffffff00000000
return n
def computeExpected(a, b, test):
if (test == "ADDIW"):
b=toSigned12bit(b)
return a + b
elif (test == "SLLIW"):
return (a << b)
elif (test == "SRLIW"):
return logical_rshift(a, b)
elif(test == "SRAIW"):
a= toSigned32bit(a)
return a >> b
else:
die("bad test name ", test)
# exit(1)
def randRegs():
reg1 = randint(1,31)
reg2 = randint(1,31)
reg3 = randint(1,31)
if (reg1 == 6 or reg2 == 6 or reg3 == 6 or reg1 == reg2):
return randRegs()
else:
return reg1, reg2, reg3
def writeVector(a, b, storecmd):
global testnum
expected = computeExpected(a, b, test)
expected = expected % 2**64 # drop carry if necessary
if (expected < 0): # take twos complement
expected = 2**64 + expected
#expected=expected+2^32<<32
if (expected >= (2**32)):
expected=expected%(2**32)
expected=toSigned32bit(expected)
reg1, reg2, reg3 = randRegs()
lines = "\n# Testcase " + str(testnum) + ": rs1:x" + str(reg1) + "(" + formatstr.format(a)
lines = lines + "), imm:"+formatstr.format(b)
lines = lines + ", result rd:x" + str(reg3) + "(" + formatstr.format(expected) +")\n"
lines = lines + "li x" + str(reg1) + ", MASK_XLEN(" + formatstr.format(a) + ")\n"
#lines = lines + "li x" + str(reg2) + ", MASK_XLEN(" + formatstr.format(b) + ")\n"
lines = lines + test + " x" + str(reg3) + ", x" + str(reg1) + ", SEXT_IMM(" + formatstr.format(b) + ")\n"
lines = lines + storecmd + " x" + str(reg3) + ", " + str(wordsize*testnum) + "(x6)\n"
lines = lines + "RVTEST_IO_ASSERT_GPR_EQ(x7, x" + str(reg3) +", "+formatstr.format(expected)+")\n"
#lines = lines + str(b)+"\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
tests = ["ADDIW", "SLLIW", "SRLIW", "SRAIW"]
author = "Eizabeth Hedenberg"
xlens = [64]
shiftlen=5
addlen=12
numrand = 100
# setup
seed(0) # make tests reproducible
# generate files for each test
for xlen in xlens:
formatstrlen = str(int(xlen/4))
#formatstrlen6=str(int())
formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number
#formatstr6 = "0x{:0" + "2" + "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 test in tests:
cornersa = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1,
2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1]
#test both confined to top 32 and not
cornersshift=[0, 1, 2, 2**(shiftlen)-1, 2**(shiftlen)-2, 0b00101, 0b01110]
#6 bits: 0, 1, 2, largest, largest -1, largest -2, 21, 46
cornersadd=[0, 1, 2, 2**(addlen-1), 2**(addlen-1)-1, 2**(addlen-1)-2, 2**(addlen-1)+1, 2**(addlen)-2, 2**(addlen)-1, 0b001010010101, 0b101011101111]
#12 bit, 0, 1, 2 argest positive, largest -1, largest -2, largest negative number, -2, -1, random
imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/"
basename = "WALLY-" + test
fname = imperaspath + "src/" + basename + ".S"
refname = imperaspath + "references/" + basename + ".reference_output"
testnum = 0
# print custom header part
f = open(fname, "w")
r = open(refname, "w")
line = "///////////////////////////////////////////\n"
f.write(line)
lines="// "+fname+ "\n// " + author + "\n"
f.write(lines)
line ="// Created " + str(datetime.now())
f.write(line)
# insert generic header
h = open("testgen_header.S", "r")
for line in h:
f.write(line)
# print directed and random test vectors
if test=="ADDIW":
for a in cornersa:
for b in cornersadd:
writeVector(a, b, storecmd)
for i in range(0,numrand):
a = getrandbits(xlen)
b = getrandbits(12)
writeVector(a, b, storecmd)
else:
for a in cornersa:
for b in cornersshift:
writeVector(a, b, storecmd)
for i in range(0,numrand):
a = getrandbits(xlen)
b = getrandbits(5)
writeVector(a, b, storecmd)
# print footer
h = open("testgen_footer.S", "r")
for line in h:
f.write(line)
# Finish
lines = ".fill " + str(testnum) + ", " + str(wordsize) + ", -1\n"
lines = lines + "\nRV_COMPLIANCE_DATA_END\n"
f.write(lines)
f.close()
r.close()

View File

@ -0,0 +1,260 @@
#!/usr/bin/python3
##################################
# testgen-JAL.py
#
# Ben Bracker (bbracker@hmc.edu) 19 January 2021
# Based on testgen-ADD-SUB.py by David Harris
#
# Generate directed and random test vectors for RISC-V Design Validation.
##################################
##################################
# libraries
##################################
from datetime import datetime
from random import randint
from random import choice
from random import seed
from random import getrandbits
from copy import deepcopy
##################################
# functions
##################################
def InitTestGroup():
global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg
TestGroup += 1
TestGroupSizes.append(0)
UnusedRegs = deepcopy(AllRegs)
oldStoreAdrReg = StoreAdrReg
while ((StoreAdrReg == oldStoreAdrReg) or (StoreAdrReg == 0) or (StoreAdrReg == 31)):
StoreAdrReg = choice(UnusedRegs)
UnusedRegs.remove(StoreAdrReg)
f.write("\n # ---------------------------------------------------------------------------------------------\n")
f.write(" # new register for address of test results\n")
addInst(" la x"+str(StoreAdrReg)+", test_1_res\n")
f.write(" # ---------------------------------------------------------------------------------------------\n")
def registerSelect():
# ensures that rd experiences all possible registers
# *** does not yet ensure that rs experiences all possible registers
# ensures that at least once rd = rs
global UnusedRegs
if len(UnusedRegs)==0:
InitTestGroup()
rd = choice(UnusedRegs)
rs = choice(UnusedRegs)
UnusedRegs.remove(rd)
OtherRegs = deepcopy(AllRegs)
OtherRegs.remove(StoreAdrReg)
OtherRegs.remove(rd)
try:
OtherRegs.remove(0)
except:
pass
try:
OtherRegs.remove(rs)
except:
pass
DataReg = choice(OtherRegs)
OtherRegs.remove(DataReg)
OtherRd = choice(OtherRegs)
return (rd,rs,DataReg,OtherRd)
def addInst(line):
global CurrAdr
f.write(line)
if ("li x" in line):
CurrAdr += 8 if (xlen == 32) else 20
elif ("la x" in line):
CurrAdr += 8
else:
CurrAdr += 4
def writeForwardsJumpVector(spacers):
global TestNum
rd, rs, DataReg, OtherRd = registerSelect()
if (xlen==64):
expected = int("fedbca9876540000",16)
unexpected = int("ffff0000ffff0000",16)
else:
expected = int("fedbca98",16)
unexpected = int("ff00ff00",16)
f.write("\n")
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+44)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
addInst(" JAL x"+str(rd)+", 1f\n")
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
for i in range(spacers):
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
f.write("1:\n")
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
writeExpectedToRef(LinkAdr)
writeExpectedToRef(expected)
TestNum = TestNum+1
def writeBackwardsJumpVector(spacers):
global TestNum
rd, rs, DataReg,OtherRd = registerSelect()
if (xlen==64):
expected = int("fedbca9876540000",16)
unexpected = int("ffff0000ffff0000",16)
else:
expected = int("fedbca98",16)
unexpected = int("ff00ff00",16)
f.write("\n")
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+20+8*spacers)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
addInst(" JAL x"+str(OtherRd)+", 2f\n")
f.write("1:\n")
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
addInst(" JAL x"+str(OtherRd)+", 3f\n")
f.write("2:\n")
for i in range(spacers):
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
addInst(" JAL x"+str(rd)+", 1b\n")
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
f.write("3:\n")
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
writeExpectedToRef(LinkAdr)
writeExpectedToRef(expected)
TestNum = TestNum+1
def writeChainVector(repetitions,spacers):
global TestNum
rd, rs, DataReg,OtherRd = registerSelect()
if (xlen==64):
expected = int("fedbca9876540000",16)
unexpected = int("ffff0000ffff0000",16)
else:
expected = int("fedbca98",16)
unexpected = int("ff00ff00",16)
f.write("\n")
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"(ugh; if you really wanted to, you could figure it out) data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
for i in range(repetitions):
addInst(" JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n")
if spacers:
for j in range(i):
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
f.write(str(3*i+1)+":\n")
addInst(" JAL x"+str(OtherRd)+", "+str(3*i+3)+"f\n")
if spacers:
for j in range(i):
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
f.write(str(3*i+2)+":\n")
addInst(" JAL x"+str(rd)+", "+str(3*i+1)+"b\n")
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
if spacers:
for j in range(i):
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
f.write(str(3*i+3)+":\n")
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
writeExpectedToRef(LinkAdr)
writeExpectedToRef(expected)
TestNum = TestNum+1
def writeExpectedToRef(expected):
global TestGroupSizes
TestGroupSizes[TestGroup-1] += 1
if (xlen == 32):
r.write(formatrefstr.format(expected)+"\n")
else:
r.write(formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32)+"\n")
##################################
# main body
##################################
# change these to suite your tests
tests = ["JAL"]
author = "Ben Bracker (bbracker@hmc.edu)"
xlens = [32,64]
numtests = 100;
# setup
seed(0) # make tests reproducible
# generate files for each test
for xlen in xlens:
CurrAdr = int("80000108",16)
TestNum = 0
TestGroup = 1
TestGroupSizes = [0]
AllRegs = list(range(0,32))
UnusedRegs = deepcopy(AllRegs)
StoreAdrReg = 6 # matches what's in header script
UnusedRegs.remove(6)
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 test in tests:
imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/"
basename = "WALLY-" + test
fname = imperaspath + "src/" + basename + ".S"
refname = imperaspath + "references/" + basename + ".reference_output"
# print custom header part
f = open(fname, "w")
r = open(refname, "w")
f.write("///////////////////////////////////////////\n")
f.write("// "+fname+ "\n")
f.write("//\n")
f.write("// This file can be used to test the RISC-V JAL instruction.\n")
f.write("// But be warned that altering the test environment may break this test!\n")
f.write("// In order to work, this test expects that the first instruction (la)\n")
f.write("// be allocated at 0x80000100.\n")
f.write("//\n")
f.write("// " + author + "\n")
f.write("// Created "+str(datetime.now())+"\n")
# insert generic header
h = open("testgen_header.S", "r")
for line in h:
f.write(line)
# print directed test vectors
for i in range(0,31):
writeForwardsJumpVector(randint(0,4))
for i in range(0,31):
writeBackwardsJumpVector(randint(0,4))
writeForwardsJumpVector(100)
writeBackwardsJumpVector(100)
writeChainVector(6,True)
writeChainVector(16,False)
# print footer
h = open("testgen_footer.S", "r")
for line in h:
f.write(line)
# Finish
f.write(".fill "+str(sum(TestGroupSizes))+", "+str(wordsize)+", -1\n")
f.write("\nRV_COMPLIANCE_DATA_END\n")
f.close()
r.close()

View File

@ -18,15 +18,56 @@ from random import randint, seed, getrandbits
##################################
def rand_reg():
"""Produce a random register (skipping 6, since r6 is used for other things"""
r = randint(1,30)
"""Produce a random register (skipping 6 and 31, since they're used for other things)"""
r = randint(1,29)
if r >= 6:
r += 1
return r
def rand_value(width):
"""Generate a random value which fits in the given width"""
return randint(0, (1 << width) - 1)
def rand_offset():
"""Generate a random offset"""
ret = rand_value(12)
# print("Random offset: %d" % ret)
return ret
def rand_source():
"""Generate a random value for the source register, such that the load address is in the test data"""
ret = randint(1 << 12, (1 << 12) + (1 << 10))
# print("Random source: %d" % ret)
return ret
def add_offset_to_source(source, offset):
"""Find the address from the given source value and offset"""
if offset & 0x800:
offset -= 0x1000
return source + offset
def insert_into_data(test_data, source, offset, value, width, xlen):
"""Insert the given value into the given location of the test data"""
address = add_offset_to_source(source, offset)
# print("Test #%d" % testcase_num)
# print(f"Source: {source}, Offset: {offset}, Value: {value}, Width: {width}, xlen: {xlen}, Addr: {address}")
if address < 0:
return False
word_offset = address % (xlen // 8)
word_address = address - word_offset
if word_address in test_data:
return False
test_data[word_address] = value * (1 << (word_offset*8)) + ((~(((1 << width)-1) << (word_offset*8))) & rand_value(xlen))
# print(f"Word: {hex(test_data[word_address])}")
return True
def align(address, width):
"""Align the address to the given width, in bits"""
return address - (address % (width // 8))
testcase_num = 0
def generate_case(xlen, instruction, load_register, source_register, source_register_value, offset, expected):
"""Produce the specified test case and return it as a string"""
"""Produce the specified test case and return it as a pair of strings, where the first is the test case and the second is the output"""
global testcase_num
if xlen == 64:
store = "sd"
@ -36,35 +77,89 @@ def generate_case(xlen, instruction, load_register, source_register, source_regi
store = "sw"
else:
raise Exception("Unknown xlen value: %s" % xlen)
data = f"""# Testcase {testcase_num}: source {offset}(x{source_register} == {source_register_value}), rresult: x{load_register} == {expected}
if offset >= 0x800:
offset -= 0x1000
if widths[instruction] != xlen:
expected = expected % (1 << widths[instruction])
if 'u' not in instruction:
if expected & (1 << (widths[instruction] - 1)):
expected = (expected + ~((1 << widths[instruction]) - 1)) & ((1 << xlen) - 1)
data = f"""# Testcase {testcase_num}: source {offset}(x{source_register} == {source_register_value}), result: x{load_register} == {expected}
la x31, test_data
lui x{source_register}, {source_register_value // (1 << 12)}
addi x{source_register}, x{source_register}, {source_register_value % (1 << 12)}
add x{source_register}, x{source_register}, x31
{instruction} x{load_register}, {offset}(x{source_register})
{store} x{load_register}, {testcase_num}(x6)
{store} x{load_register}, {(testcase_num*xlen//8) % 0x800}(x6)
RVTEST_IO_ASSERT_GPR_EQ(x8, x{load_register}, {expected})
"""
testcase_num += 1
return data
if testcase_num*xlen//8 % 0x800 == 0:
data += "# Adjust x6 because we're storing too many things\naddi x6, x6, 1024\naddi x6, x6, 1024\n\n"
if xlen == 32:
reference_output = "{:08x}\n".format(expected)
elif xlen == 64:
reference_output = "{:08x}\n{:08x}\n".format(expected % (1 << 32), expected >> 32)
return (data, reference_output)
def write_header(outfile):
outfile.write(f"""///////////////////////////////////////////
//
// WALLY-LOAD
//
// Author: f{author}
//
// Created {str(datetime.now())}
//
///////////////////////////////////////////
//
// WALLY-LOAD
//
// Author: {author}
//
// Created {str(datetime.now())}
//
""")
outfile.write(open("testgen_header.S", "r").read())
def write_test_data(outfile, test_data, xlen):
# print("Begin writing test data:")
# print("{} entries, from address {} to {}".format(len(test_data), min(test_data.keys()), max(test_data.keys())))
# print(test_data)
outfile.write("""
.align 16
test_data:
""")
outfile.write(open("testgen_header.S", "r").read())
if xlen == 32:
data_word = ".word"
elif xlen == 64:
data_word = ".dword"
else:
raise Exception("Unknown xlen: %d" % xlen)
byte_width = xlen // 8
for addr in [0] + sorted(test_data.keys()):
if addr in test_data:
word = f" {data_word} {hex(test_data[addr] % (1 << xlen))} # test_data+{hex(addr)}\n"
else:
word = ""
try:
fill_len = (min(k for k in test_data.keys() if k > addr) - addr) // byte_width - 1
if word == "":
fill_len += 1
fill = f" .fill {fill_len}, {byte_width}, 0x0\n"
except:
fill = ""
case = word+fill
outfile.write(case)
##################################
# main body
##################################
instructions = ["lb", "lbu", "lh", "lhu", "lw", "lwu", "ld"]
widths = {
"lb": 8,
"lbu": 8,
"lh": 16,
"lhu": 16,
"lw": 32,
"lwu": 32,
"ld": 64,
}
instructions = [i for i in widths]
author = "Jarred Allen"
xlens = [32, 64]
numrand = 100;
@ -73,16 +168,60 @@ numrand = 100;
seed(0) # make tests reproducible
for xlen in xlens:
testcase_num = 0
fname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/src/WALLY-LOAD.S".format(xlen)
refname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/references/WALLY-LOAD.S.reference_output".format(xlen)
refname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/references/WALLY-LOAD.reference_output".format(xlen)
f = open(fname, "w")
r = open(refname, "w")
write_header(f)
test_data = dict()
corner_values = [0x00, 0xFF, 0xFFFF, 0xFFFFFFFF, 0x7F, 0x7FFF, 0x7FFFFFFF, 0x01]
corner_values = [0x00, 0xFFFFFFFF, 0x7F, 0x7FFF, 0x7FFFFFFF]
if xlen == 64:
corner_values += [0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF]
corner_offsets = [0x800, 0x000, 0x7FF]
for instruction in instructions:
print("Running xlen: %d, instruction: %s" % (xlen, instruction))
if xlen == 32:
if instruction in ["lwu", "ld"]:
continue
for value in corner_values + [rand_value(widths[instruction]) for _ in range(3)]:
value = value % (1 << widths[instruction])
source_reg = rand_source()
for offset in corner_offsets + [rand_offset() for _ in range(3)]:
offset = align(offset, widths[instruction])
source_reg = align(source_reg, widths[instruction])
if insert_into_data(test_data, source_reg, offset, value, widths[instruction], xlen):
data, output = generate_case(xlen, instruction, rand_reg(), rand_reg(), source_reg, offset, value)
f.write(data)
r.write(output)
while testcase_num % 4:
source = rand_source()
offset = rand_offset()
value = rand_value(widths[instruction])
if insert_into_data(test_data, source, offset, value, widths['lb'], xlen):
data, output = generate_case(xlen, 'lb', rand_reg(), rand_reg(), source, offset, value)
f.write(data)
r.write(output)
f.write("""# ---------------------------------------------------------------------------------------------
RVTEST_IO_WRITE_STR(x31, "Test End\\n")
# ---------------------------------------------------------------------------------------------
RV_COMPLIANCE_HALT
RV_COMPLIANCE_CODE_END
.data
# Input data section
""")
write_test_data(f, test_data, xlen)
f.write("""# Output data section.
RV_COMPLIANCE_DATA_BEGIN
test_1_res:
""")
f.write(f".fill {testcase_num}, {xlen//8}, -1\n")
f.write("\nRV_COMPLIANCE_DATA_END\n")
f.close()
r.close()

View File

@ -0,0 +1,282 @@
#!/usr/bin/python3
##################################
# testgen-STORE.py
#
# Jessica Torrey <jtorrey@hmc.edu> 03 February 2021
# Thomas Fleming <tfleming@hmc.edu> 03 February 2021
#
# Generate directed and random test vectors for RISC-V Design Validation.
##################################
##################################
# libraries
##################################
from datetime import datetime
from random import randint, seed, getrandbits
from textwrap import dedent
##################################
# global structures
##################################
size_to_store = {8: "sd", 4: "sw", 2: "sh", 1: "sb"}
size_to_load = {8: "ld", 4: "lw", 2: "lh", 1: "lb"}
store_to_size = {"sd": 8, "sw": 4, "sh": 2, "sb": 1}
testcase_num = 0
signature_len = 2000
signature = [0xff for _ in range(signature_len)]
##################################
# functions
##################################
def rand_reg():
"""
Produce a random register from 1 to 31 (skipping 6, since r6 is used for
other things).
"""
r = randint(1,30)
if r >= 6:
r += 1
return r
def rand_regs():
"""
Generate two random, unequal register numbers (skipping x6).
"""
rs1 = rand_reg()
rs2 = rand_reg()
while rs1 == rs2:
rs2 = rand_reg()
return rs1, rs2
def generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta):
"""
Create assembly code for a given STORE test case, returned as a string.
Generates an `xlen`-bit test case for `instruction` (one of sb, sh, sw, or
sd) that loads `value` into `value_register`, then attempts to store that
value in memory at address (x6 + `base_delta`). The test case
assumes the current base address for the signature is in register x6.
The form of the STORE instruction is as follows:
`instruction` `value_register` `offset`(`addr_register`)
"""
global testcase_num
hex_value = f"{value:0{xlen // 4}x}"
data = f"""# Testcase {testcase_num}: source: x{value_register} (value 0x{hex_value}), destination: {offset}(x{addr_register}) ({base_delta} bytes into signature)
addi x{addr_register}, x6, {base_delta}
li x{value_register}, MASK_XLEN({-offset})
add x{addr_register}, x{addr_register}, x{value_register}
li x{value_register}, 0x{hex_value}
{instruction} x{value_register}, {offset}(x{addr_register})
"""
update_signature(store_to_size[instruction], value, base_delta)
testcase_num += 1
return data
def validate_memory(scratch_register, value_register, value, base_delta, length):
"""
Create assembly code to verify that `length` bytes at mem[x6 + `base_delta`]
store `value`.
Assumes x6 stores the current base address for the signature.
"""
truncated_value = value & (2**(length * 8) - 1)
hex_value = f"{truncated_value:0{length * 2}x}"
load = size_to_load[length]
data = f"""addi x{scratch_register}, x6, {base_delta}
{load} x{value_register}, 0(x{scratch_register})
RVTEST_IO_ASSERT_GPR_EQ(x{scratch_register}, x{value_register}, 0x{hex_value})
"""
return data
def update_signature(length, value, base_delta):
"""
Write the lower `length` bytes of `value` to the little-endian signature
array, starting at byte `base_delta`.
"""
truncated_value = value & (2**(length * 8) - 1)
value_bytes = truncated_value.to_bytes(length, 'little')
#print("n: {}, value: {:x}, trunc: {:x}, length: {}, bd: {:x}".format(testcase_num, value, truncated_value, length, base_delta))
for i in range(length):
signature[base_delta + i] = value_bytes[i]
def write_signature(outfile):
"""
Writes successive 32-bit words from the signature array into a given file.
"""
for i in range(0, signature_len, 4):
word = list(reversed(signature[i:i+4]))
hexword = bytearray(word).hex()
outfile.write(f"{hexword}\n")
def write_header(outfile):
"""
Write the name of the test file, authors, and creation date.
"""
outfile.write(dedent(f"""\
///////////////////////////////////////////
//
// WALLY-STORE
//
// Author: {author}
//
// Created {str(datetime.now())}
"""))
outfile.write(open("testgen_header.S", "r").read())
def write_footer(outfile):
"""
Write necessary closing code, including a data section for the signature.
"""
outfile.write(open("testgen_footer.S", 'r').read())
data_section = dedent(f"""\
\t.fill {signature_len}, 1, -1
RV_COMPLIANCE_DATA_END
""")
outfile.write(data_section)
##################################
# test cases
##################################
def write_basic_tests(outfile, xlen, instr_len, num, base_delta):
"""
Test basic functionality of STORE, using random registers, offsets, and
values.
Creates `num` tests for a single store instruction of length `instr_len`,
writing to memory at consecutive locations, starting `base_delta` bytes from
the start of the signature.
Returns the number of bytes from the start of the signature where testing
ended.
"""
instruction = size_to_store[instr_len]
for i in range(num):
value_register, addr_register = rand_regs()
offset = randint(-2**(12 - 1), 2**(12 - 1) - 1)
value = randint(0, 2**(instr_len * 8) - 1)
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
outfile.write(test)
outfile.write(validate)
base_delta += instr_len
return base_delta
def write_random_store_tests(outfile, xlen, instr_len, num, min_base_delta):
"""
Test random access of STORE, using random registers, offsets, values, and
memory locations.
Creates `num` tests for a single store instruction of length `instr_len`,
writing to memory at random locations between `min_base_delta` bytes past
the start of the signature to the end of the signature.
"""
instruction = size_to_store[instr_len]
for i in range(num):
base_delta = randint(min_base_delta, signature_len - 1)
base_delta -= (base_delta % instr_len)
value_register, addr_register = rand_regs()
offset = randint(-2**(12 - 1), 2**(12 - 1) - 1)
value = randint(0, 2**(instr_len * 8) - 1)
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
outfile.write(test)
outfile.write(validate)
def write_repeated_store_tests(outfile, xlen, instr_len, num, base_delta):
"""
Test repeated access of STORE, using random registers, offsets, values, and a
single memory location.
Creates `num` tests for a single store instruction of length `instr_len`,
writing to memory `base_delta` bytes past the start of the signature.
"""
instruction = size_to_store[instr_len]
for i in range(num):
value_register, addr_register = rand_regs()
offset = 0
value = (1 << ((2 * i) % xlen))
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
outfile.write(test)
outfile.write(validate)
def write_corner_case_tests(outfile, xlen, instr_len, base_delta):
instruction = size_to_store[instr_len]
corner_cases_32 = [0x0, 0x10000001, 0x01111111]
corner_cases_64 = [0x1000000000000001, 0x0111111111111111]
corner_cases = corner_cases_32
if xlen == 64:
corner_cases += corner_cases_64
for offset in corner_cases:
for value in corner_cases:
value_register, addr_register = rand_regs()
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
outfile.write(test)
outfile.write(validate)
base_delta += instr_len
return base_delta
##################################
# main body
##################################
instructions = ["sd", "sw", "sh", "sb"]
author = "Jessica Torrey <jtorrey@hmc.edu> & Thomas Fleming <tfleming@hmc.edu>"
xlens = [32, 64]
numrand = 100
# setup
seed(0) # make tests reproducible
for xlen in xlens:
if (xlen == 32):
wordsize = 4
else:
wordsize = 8
fname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/src/WALLY-STORE.S"
refname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/references/WALLY-STORE.reference_output"
f = open(fname, "w")
r = open(refname, "w")
write_header(f)
base_delta = 0
for instruction in instructions:
if xlen == 32 and instruction == 'sd':
continue
instr_len = store_to_size[instruction]
base_delta = write_basic_tests(f, xlen, instr_len, 5, base_delta)
write_repeated_store_tests(f, xlen, instr_len, 32, base_delta)
write_random_store_tests(f, xlen, instr_len, 5, base_delta + wordsize)
write_footer(f)
write_signature(r)
f.close()
r.close()
# Reset testcase_num and signature
testcase_num = 0
signature = [0xff for _ in range(signature_len)]