mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-03 02:05:21 +00:00
Add test vector set for load instructions
This commit is contained in:
parent
493bab529e
commit
a3f2f4c7bc
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user