forked from Github_Repos/cvw
		
	Add test vector set for load instructions
This commit is contained in:
		
							parent
							
								
									5c017bac1f
								
							
						
					
					
						commit
						edd758453e
					
				@ -18,15 +18,56 @@ from random import randint, seed, getrandbits
 | 
				
			|||||||
##################################
 | 
					##################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def rand_reg():
 | 
					def rand_reg():
 | 
				
			||||||
  """Produce a random register (skipping 6, since r6 is used for other things"""
 | 
					  """Produce a random register (skipping 6 and 31, since they're used for other things)"""
 | 
				
			||||||
  r = randint(1,30)
 | 
					  r = randint(1,29)
 | 
				
			||||||
  if r >= 6:
 | 
					  if r >= 6:
 | 
				
			||||||
    r += 1
 | 
					    r += 1
 | 
				
			||||||
  return r
 | 
					  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
 | 
					testcase_num = 0
 | 
				
			||||||
def generate_case(xlen, instruction, load_register, source_register, source_register_value, offset, expected):
 | 
					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
 | 
					    global testcase_num
 | 
				
			||||||
    if xlen == 64:
 | 
					    if xlen == 64:
 | 
				
			||||||
        store = "sd"
 | 
					        store = "sd"
 | 
				
			||||||
@ -36,35 +77,89 @@ def generate_case(xlen, instruction, load_register, source_register, source_regi
 | 
				
			|||||||
        store = "sw"
 | 
					        store = "sw"
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        raise Exception("Unknown xlen value: %s" % xlen)
 | 
					        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)}
 | 
					    lui x{source_register}, {source_register_value // (1 << 12)}
 | 
				
			||||||
    addi x{source_register}, 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})
 | 
					    {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})
 | 
					    RVTEST_IO_ASSERT_GPR_EQ(x8, x{load_register}, {expected})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    testcase_num += 1
 | 
					    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):
 | 
					def write_header(outfile):
 | 
				
			||||||
    outfile.write(f"""///////////////////////////////////////////
 | 
					    outfile.write(f"""///////////////////////////////////////////
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// WALLY-LOAD
 | 
					// WALLY-LOAD
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
    // Author: f{author}
 | 
					// Author: {author}
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Created {str(datetime.now())}
 | 
					// Created {str(datetime.now())}
 | 
				
			||||||
// 
 | 
					// 
 | 
				
			||||||
    ///////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
""")
 | 
					""")
 | 
				
			||||||
    outfile.write(open("testgen_header.S", "r").read())
 | 
					    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:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    """)
 | 
				
			||||||
 | 
					    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
 | 
					# 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"
 | 
					author = "Jarred Allen"
 | 
				
			||||||
xlens = [32, 64]
 | 
					xlens = [32, 64]
 | 
				
			||||||
numrand = 100;
 | 
					numrand = 100;
 | 
				
			||||||
@ -73,16 +168,60 @@ numrand = 100;
 | 
				
			|||||||
seed(0) # make tests reproducible
 | 
					seed(0) # make tests reproducible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for xlen in xlens:
 | 
					for xlen in xlens:
 | 
				
			||||||
 | 
					    testcase_num = 0
 | 
				
			||||||
    fname = "../../imperas-riscv-tests/riscv-test-suite/rv{}i/src/WALLY-LOAD.S".format(xlen)
 | 
					    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")
 | 
					    f = open(fname, "w")
 | 
				
			||||||
    r = open(refname, "w")
 | 
					    r = open(refname, "w")
 | 
				
			||||||
    write_header(f)
 | 
					    write_header(f)
 | 
				
			||||||
    test_data = dict()
 | 
					    test_data = dict()
 | 
				
			||||||
    corner_values = [0x00, 0xFF, 0xFFFF, 0xFFFFFFFF, 0x7F, 0x7FFF, 0x7FFFFFFF, 0x01]
 | 
					    corner_values = [0x00, 0xFFFFFFFF, 0x7F, 0x7FFF, 0x7FFFFFFF]
 | 
				
			||||||
    if xlen == 64:
 | 
					    if xlen == 64:
 | 
				
			||||||
        corner_values += [0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF]
 | 
					        corner_values += [0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF]
 | 
				
			||||||
 | 
					    corner_offsets = [0x800, 0x000, 0x7FF]
 | 
				
			||||||
    for instruction in instructions:
 | 
					    for instruction in instructions:
 | 
				
			||||||
 | 
					        print("Running xlen: %d, instruction: %s" % (xlen, instruction))
 | 
				
			||||||
        if xlen == 32:
 | 
					        if xlen == 32:
 | 
				
			||||||
            if instruction in ["lwu", "ld"]:
 | 
					            if instruction in ["lwu", "ld"]:
 | 
				
			||||||
                continue
 | 
					                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