Add bitmanip test vector generation script
This commit is contained in:
parent
5d093487b7
commit
6f1a10724b
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -0,0 +1,9 @@
|
|||
Random Bitmanip Test Vectors
|
||||
============================
|
||||
|
||||
At time of writing there are no upstream compliance tests for the new bitmanip extensions.
|
||||
|
||||
So, generate some constrained-random input vectors, and run them against the [reference simulator](https://github.com/riscv-software-src/riscv-isa-sim) to get golden output vectors. Not perfect, but enough to give me some confidence in my implementation until the official tests come out.
|
||||
|
||||
People on the mailing lists seem to defer to spike over the pseudocode in the spec anyway, so that is probably a better verification target than trying to write my own vectors based on my own interpretation of the spec.
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from random import seed, randrange
|
||||
from pathlib import Path
|
||||
|
||||
XLEN = 32
|
||||
XLEN_MASK = (1 << XLEN) - 1
|
||||
|
||||
all_onehot = [1 << i for i in range(XLEN)]
|
||||
all_onehot0 = [0] + all_onehot
|
||||
all_onehot0_neg = all_onehot0 + [~i & XLEN_MASK for i in all_onehot0]
|
||||
all_shamt = list(range(XLEN))
|
||||
|
||||
seed(XLEN_MASK // 29)
|
||||
RAND_COUNT = 20
|
||||
def get_random():
|
||||
return [randrange(0, 1 << XLEN) for i in range(RAND_COUNT)]
|
||||
|
||||
# Lists of instructions and their test inputs
|
||||
|
||||
instr_one_operand = [
|
||||
("clz" , [*all_onehot0_neg, *get_random()]),
|
||||
("cpop" , [*all_onehot0_neg, *get_random()]),
|
||||
("ctz" , [*all_onehot0_neg, *get_random()]),
|
||||
("orc.b" , [*all_onehot0_neg, *get_random()]),
|
||||
("rev8" , [*all_onehot0_neg, *get_random()]),
|
||||
("sext.b" , [*all_onehot0_neg, *get_random()]),
|
||||
("sext.h" , [*all_onehot0_neg, *get_random()]),
|
||||
("zext.h" , [*all_onehot0_neg, *get_random()]),
|
||||
]
|
||||
|
||||
instr_reg_reg = [
|
||||
("sh1add" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("sh2add" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("sh3add" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("andn" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("max" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("maxu" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("min" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("minu" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("orn" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("rol" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("ror" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("xnor" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("clmul" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("clmulh" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("clmulr" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("bclr" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("bext" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("binv" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
("bset" , [*all_onehot0_neg, *get_random()], [*all_onehot0_neg, *all_shamt, *get_random()]),
|
||||
]
|
||||
|
||||
instr_reg_imm = [
|
||||
("rori" , [*all_onehot0_neg, *get_random()], all_shamt),
|
||||
("bclri" , [*all_onehot0_neg, *get_random()], all_shamt),
|
||||
("bexti" , [*all_onehot0_neg, *get_random()], all_shamt),
|
||||
("binvi" , [*all_onehot0_neg, *get_random()], all_shamt),
|
||||
("bseti" , [*all_onehot0_neg, *get_random()], all_shamt),
|
||||
]
|
||||
|
||||
# Generate output files
|
||||
|
||||
prolog = """
|
||||
.option norelax
|
||||
.section .text
|
||||
|
||||
// Automatically-generated test vector. Don't edit.
|
||||
|
||||
#define IO_BASE 0x80000000
|
||||
#define IO_PRINT_CHAR (IO_BASE + 0x0)
|
||||
#define IO_PRINT_U32 (IO_BASE + 0x4)
|
||||
#define IO_EXIT (IO_BASE + 0x8)
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
la sp, test_signature_start
|
||||
|
||||
"""
|
||||
|
||||
interlude = """
|
||||
test_end:
|
||||
li a0, IO_EXIT
|
||||
sw zero, (a0)
|
||||
|
||||
.section .data
|
||||
|
||||
.p2align 2
|
||||
.global test_signature_start
|
||||
test_signature_start:
|
||||
"""
|
||||
|
||||
epilog = """
|
||||
.global test_signature_end
|
||||
test_signature_end:
|
||||
"""
|
||||
|
||||
def sanitise(name):
|
||||
return "".join(c if ("_" + c).isidentifier() else "_" for c in name)
|
||||
|
||||
Path("test").mkdir(exist_ok = True)
|
||||
|
||||
for instr, data in instr_one_operand:
|
||||
with open(f"test/{sanitise(instr)}.S", "w") as f:
|
||||
f.write(prolog)
|
||||
for d in data:
|
||||
f.write(f"\tli a1, 0x{d:08x}\n")
|
||||
f.write(f"\t{instr} a0, a1\n")
|
||||
f.write( "\tsw a0, (sp)\n")
|
||||
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
|
||||
f.write(interlude)
|
||||
# Label the output locations for easier debug
|
||||
i = 0
|
||||
for d in data:
|
||||
f.write(f"test{i}_{sanitise(instr)}_{d:08x}:\n")
|
||||
f.write("\t.word 0\n" if XLEN == 32 else "\tdword 0\n")
|
||||
i = i + 1
|
||||
f.write(epilog)
|
||||
|
||||
for instr, rs1_list, rs2_list in instr_reg_reg:
|
||||
with open(f"test/{sanitise(instr)}.S", "w") as f:
|
||||
f.write(prolog)
|
||||
for rs1 in rs1_list:
|
||||
for rs2 in rs2_list:
|
||||
f.write(f"\tli a1, 0x{rs1:08x}\n")
|
||||
f.write(f"\tli a2, 0x{rs2:08x}\n")
|
||||
f.write(f"\t{instr} a0, a1, a2\n")
|
||||
f.write( "\tsw a0, (sp)\n")
|
||||
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
|
||||
f.write(interlude)
|
||||
i = 0
|
||||
for rs1 in rs1_list:
|
||||
for rs2 in rs2_list:
|
||||
f.write(f"test{i}_{sanitise(instr)}_{rs1:08x}__{rs2:08x}:\n")
|
||||
f.write("\t.word 0\n" if XLEN == 32 else "\tdword 0\n")
|
||||
i = i + 1
|
||||
f.write(epilog)
|
||||
|
||||
for instr, rs1_list, imm_list in instr_reg_imm:
|
||||
with open(f"test/{sanitise(instr)}.S", "w") as f:
|
||||
f.write(prolog)
|
||||
for rs1 in rs1_list:
|
||||
for imm in imm_list:
|
||||
f.write(f"\tli a1, 0x{rs1:08x}\n")
|
||||
f.write(f"\t{instr} a0, a1, 0x{imm:02x}\n")
|
||||
f.write( "\tsw a0, (sp)\n")
|
||||
f.write(f"\taddi sp, sp, {XLEN // 8}\n\n")
|
||||
f.write(interlude)
|
||||
i = 0
|
||||
for rs1 in rs1_list:
|
||||
for imm in imm_list:
|
||||
f.write(f"test{i}_{sanitise(instr)}_{rs1:08x}__{imm:02x}:\n")
|
||||
f.write("\t.word 0\n" if XLEN == 32 else "\tdword 0\n")
|
||||
i = i + 1
|
||||
f.write(epilog)
|
Loading…
Reference in New Issue