2022-11-25 10:48:15 -06:00
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
import random
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
|
|
parser.add_argument('-S', '--seed', type=int, help='seed for PRNG')
|
2023-02-13 07:02:02 -06:00
|
|
|
parser.add_argument('-m', '--more', action='store_true', help='run more tests')
|
2022-11-25 10:48:15 -06:00
|
|
|
parser.add_argument('-c', '--count', type=int, default=32, help='number of random patterns to test')
|
|
|
|
parser.add_argument('-f', '--filter', default='', help='regular expression to filter tests to generate')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
if args.seed is None:
|
|
|
|
args.seed = random.randrange(1 << 32)
|
|
|
|
|
|
|
|
print(f"xprop PRNG seed: {args.seed}")
|
|
|
|
|
|
|
|
makefile = open("run-test.mk", "w")
|
|
|
|
|
|
|
|
def add_test(name, src, seq=False):
|
|
|
|
if not re.search(args.filter, name):
|
|
|
|
return
|
|
|
|
workdir = f"xprop_{name}"
|
|
|
|
|
|
|
|
os.makedirs(workdir, exist_ok=True)
|
|
|
|
with open(f"{workdir}/uut.v", "w") as uut:
|
|
|
|
print(src, file=uut)
|
|
|
|
print(f"all: {workdir}", file=makefile)
|
|
|
|
print(f".PHONY: {workdir}", file=makefile)
|
|
|
|
print(f"{workdir}:", file=makefile)
|
|
|
|
seq_arg = " -s" if seq else ""
|
|
|
|
print(
|
|
|
|
f"\t@cd {workdir} && python3 -u ../test.py -S {args.seed} -c {args.count}{seq_arg} > test.log 2>&1 || echo {workdir}: failed > status\n"
|
|
|
|
f"\t@cat {workdir}/status\n"
|
2023-02-13 07:03:08 -06:00
|
|
|
f"\t@grep '^.*: ok' {workdir}/status\n"
|
2022-11-25 10:48:15 -06:00
|
|
|
,
|
|
|
|
file=makefile,
|
|
|
|
)
|
|
|
|
|
|
|
|
def cell_test(name, cell, inputs, outputs, params, initial={}, defclock=False, seq=False):
|
|
|
|
ports = []
|
|
|
|
port_conns = []
|
|
|
|
for inport, width in inputs.items():
|
|
|
|
ports.append(f"input [{width-1}:0] {inport}")
|
|
|
|
if defclock and inport in ["C", "CLK"]:
|
|
|
|
port_conns.append(f".{inport}({inport} !== 0)")
|
|
|
|
else:
|
|
|
|
port_conns.append(f".{inport}({inport})")
|
|
|
|
for outport, width in outputs.items():
|
|
|
|
reg = " reg" if outport in initial else ""
|
|
|
|
ports.append(f"output{reg} [{width-1}:0] {outport}")
|
|
|
|
port_conns.append(f".{outport}({outport})")
|
|
|
|
param_defs = []
|
|
|
|
for param, value in params.items():
|
|
|
|
param_defs.append(f".{param}({value})")
|
|
|
|
initials = []
|
|
|
|
# for port, value in initial.items():
|
|
|
|
# initials.append(f"initial {port} = {value};\n")
|
|
|
|
add_test(name,
|
|
|
|
f"module uut({', '.join(ports)});\n"
|
|
|
|
f"\\${cell} #({', '.join(param_defs)}) cell ({', '.join(port_conns)});\n"
|
|
|
|
f"{''.join(initials)}"
|
|
|
|
"endmodule",
|
|
|
|
seq=seq,
|
|
|
|
)
|
|
|
|
|
|
|
|
def unary_test(cell, width, signed, out_width):
|
|
|
|
add_test(
|
|
|
|
f"{cell}_{width}{'us'[signed]}_{out_width}",
|
|
|
|
f"module uut(input [{width-1}:0] A, output [{out_width}-1:0] Y);\n"
|
|
|
|
f"\\${cell} #(.A_WIDTH({width}), .A_SIGNED({int(signed)}), .Y_WIDTH({out_width}))"
|
|
|
|
" cell (.A(A), .Y(Y));\n"
|
|
|
|
"endmodule",
|
|
|
|
)
|
|
|
|
|
|
|
|
def binary_test(cell, a_width, b_width, signed, out_width):
|
|
|
|
add_test(
|
|
|
|
f"{cell}_{a_width}{'us'[signed]}{b_width}_{out_width}",
|
|
|
|
f"module uut(input [{a_width-1}:0] A, input [{b_width-1}:0] B, output [{out_width}-1:0] Y);\n"
|
|
|
|
f"\\${cell} #(.A_WIDTH({a_width}), .A_SIGNED({int(signed)}), .B_WIDTH({b_width}), .B_SIGNED({int(signed)}), .Y_WIDTH({out_width}))"
|
|
|
|
" cell (.A(A), .B(B), .Y(Y));\n"
|
|
|
|
"endmodule",
|
|
|
|
)
|
|
|
|
|
|
|
|
def shift_test(cell, a_width, b_width, a_signed, b_signed, out_width):
|
|
|
|
add_test(
|
|
|
|
f"{cell}_{a_width}{'us'[a_signed]}{b_width}{'us'[b_signed]}_{out_width}",
|
|
|
|
f"module uut(input [{a_width-1}:0] A, input [{b_width-1}:0] B, output [{out_width}-1:0] Y);\n"
|
|
|
|
f"\\${cell} #(.A_WIDTH({a_width}), .A_SIGNED({int(a_signed)}), .B_WIDTH({b_width}), .B_SIGNED({int(b_signed)}), .Y_WIDTH({out_width}))"
|
|
|
|
" cell (.A(A), .B(B), .Y(Y));\n"
|
|
|
|
"endmodule",
|
|
|
|
)
|
|
|
|
|
|
|
|
def mux_test(width):
|
|
|
|
cell_test(f"mux_{width}", 'mux', {"A": width, "B": width, "S": 1}, {"Y": width}, {"WIDTH": width})
|
|
|
|
|
|
|
|
def bmux_test(width, s_width):
|
|
|
|
cell_test(f"bmux_{width}_{s_width}", 'bmux', {"A": width << s_width, "S": s_width}, {"Y": width}, {"WIDTH": width, "S_WIDTH": s_width})
|
|
|
|
|
|
|
|
def demux_test(width, s_width):
|
|
|
|
cell_test(f"demux_{width}_{s_width}", 'demux', {"A": width, "S": s_width}, {"Y": width << s_width}, {"WIDTH": width, "S_WIDTH": s_width})
|
|
|
|
|
|
|
|
def pmux_test(width, s_width):
|
|
|
|
cell_test(f"pmux_{width}_{s_width}", 'pmux', {"A": width, "B": width * s_width, "S": s_width}, {"Y": width}, {"WIDTH": width, "S_WIDTH": s_width})
|
|
|
|
|
|
|
|
def bwmux_test(width):
|
|
|
|
cell_test(f"bwmux_{width}", 'bwmux', {"A": width, "B": width, "S": width}, {"Y": width}, {"WIDTH": width})
|
|
|
|
|
|
|
|
def bweqx_test(width):
|
|
|
|
cell_test(f"bweqx_{width}", 'bweqx', {"A": width, "B": width}, {"Y": width}, {"WIDTH": width})
|
|
|
|
|
|
|
|
def ff_test(width):
|
|
|
|
cell_test(f"ff_{width}", 'ff', {"D": width}, {"Q": width}, {"WIDTH": width}, seq=True)
|
|
|
|
|
|
|
|
def dff_test(width, pol, defclock):
|
|
|
|
cell_test(f"dff_{width}{'np'[pol]}{'xd'[defclock]}", 'dff', {"CLK": 1, "D": width}, {"Q": width}, {"WIDTH": width, "CLK_POLARITY": int(pol)}, defclock=defclock, seq=True)
|
|
|
|
|
|
|
|
def dffe_test(width, pol, enpol, defclock):
|
|
|
|
cell_test(f"dffe_{width}{'np'[pol]}{'np'[enpol]}{'xd'[defclock]}", 'dffe', {"CLK": 1, "EN": 1, "D": width}, {"Q": width}, {"WIDTH": width, "CLK_POLARITY": int(pol), "EN_POLARITY": int(enpol)}, defclock=defclock, seq=True)
|
|
|
|
|
|
|
|
|
|
|
|
print(".PHONY: all", file=makefile)
|
|
|
|
print("all:\n\t@echo done\n", file=makefile)
|
|
|
|
|
|
|
|
for cell in ["not", "pos", "neg"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
unary_test(cell, 1, False, 1)
|
|
|
|
unary_test(cell, 3, False, 3)
|
|
|
|
unary_test(cell, 3, True, 3)
|
|
|
|
unary_test(cell, 3, True, 1)
|
|
|
|
unary_test(cell, 3, False, 5)
|
2022-11-25 10:48:15 -06:00
|
|
|
unary_test(cell, 3, True, 5)
|
|
|
|
|
|
|
|
for cell in ["and", "or", "xor", "xnor"]:
|
|
|
|
binary_test(cell, 1, 1, False, 1)
|
|
|
|
binary_test(cell, 1, 1, True, 2)
|
|
|
|
binary_test(cell, 2, 2, False, 2)
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
binary_test(cell, 2, 2, False, 1)
|
|
|
|
binary_test(cell, 2, 1, False, 2)
|
|
|
|
binary_test(cell, 2, 1, False, 1)
|
2022-11-25 10:48:15 -06:00
|
|
|
|
|
|
|
# [, "pow"] are not implemented yet
|
|
|
|
for cell in ["add", "sub", "mul", "div", "mod", "divfloor", "modfloor"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
binary_test(cell, 1, 1, False, 1)
|
|
|
|
binary_test(cell, 1, 1, False, 2)
|
|
|
|
binary_test(cell, 3, 3, False, 1)
|
|
|
|
binary_test(cell, 3, 3, False, 3)
|
|
|
|
binary_test(cell, 3, 3, False, 6)
|
|
|
|
binary_test(cell, 3, 3, True, 1)
|
|
|
|
binary_test(cell, 3, 3, True, 3)
|
|
|
|
binary_test(cell, 3, 3, True, 6)
|
2022-11-25 10:48:15 -06:00
|
|
|
binary_test(cell, 5, 3, False, 3)
|
|
|
|
binary_test(cell, 5, 3, True, 3)
|
|
|
|
|
|
|
|
for cell in ["lt", "le", "eq", "ne", "eqx", "nex", "ge", "gt"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
binary_test(cell, 1, 1, False, 1)
|
|
|
|
binary_test(cell, 1, 1, False, 2)
|
|
|
|
binary_test(cell, 3, 3, False, 1)
|
|
|
|
binary_test(cell, 3, 3, False, 2)
|
|
|
|
binary_test(cell, 3, 3, True, 1)
|
|
|
|
binary_test(cell, 3, 3, True, 2)
|
|
|
|
binary_test(cell, 5, 3, False, 1)
|
|
|
|
binary_test(cell, 5, 3, True, 1)
|
2022-11-25 10:48:15 -06:00
|
|
|
binary_test(cell, 5, 3, False, 2)
|
|
|
|
binary_test(cell, 5, 3, True, 2)
|
|
|
|
|
|
|
|
for cell in ["reduce_and", "reduce_or", "reduce_xor", "reduce_xnor"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
unary_test(cell, 1, False, 1)
|
|
|
|
unary_test(cell, 3, False, 1)
|
|
|
|
unary_test(cell, 3, True, 1)
|
2022-11-25 10:48:15 -06:00
|
|
|
unary_test(cell, 3, False, 3)
|
|
|
|
unary_test(cell, 3, True, 3)
|
|
|
|
|
|
|
|
for cell in ["reduce_bool", "logic_not"]:
|
|
|
|
unary_test(cell, 1, False, 1)
|
|
|
|
unary_test(cell, 3, False, 3)
|
|
|
|
unary_test(cell, 3, True, 3)
|
|
|
|
unary_test(cell, 3, True, 1)
|
|
|
|
|
|
|
|
for cell in ["logic_and", "logic_or"]:
|
|
|
|
binary_test(cell, 1, 1, False, 1)
|
|
|
|
binary_test(cell, 3, 3, False, 3)
|
|
|
|
binary_test(cell, 3, 3, True, 3)
|
|
|
|
binary_test(cell, 3, 3, True, 1)
|
|
|
|
|
|
|
|
for cell in ["shl", "shr", "sshl", "sshr", "shift"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
shift_test(cell, 2, 1, False, False, 2)
|
|
|
|
shift_test(cell, 2, 1, True, False, 2)
|
|
|
|
shift_test(cell, 2, 1, False, False, 4)
|
|
|
|
shift_test(cell, 2, 1, True, False, 4)
|
|
|
|
shift_test(cell, 4, 2, False, False, 4)
|
|
|
|
shift_test(cell, 4, 2, True, False, 4)
|
|
|
|
shift_test(cell, 4, 2, False, False, 8)
|
|
|
|
shift_test(cell, 4, 2, True, False, 8)
|
2022-11-25 10:48:15 -06:00
|
|
|
shift_test(cell, 4, 3, False, False, 3)
|
|
|
|
shift_test(cell, 4, 3, True, False, 3)
|
|
|
|
|
|
|
|
for cell in ["shift"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
shift_test(cell, 2, 1, False, True, 2)
|
|
|
|
shift_test(cell, 2, 1, True, True, 2)
|
|
|
|
shift_test(cell, 2, 1, False, True, 4)
|
|
|
|
shift_test(cell, 2, 1, True, True, 4)
|
|
|
|
shift_test(cell, 4, 2, False, True, 4)
|
|
|
|
shift_test(cell, 4, 2, True, True, 4)
|
2022-11-25 10:48:15 -06:00
|
|
|
shift_test(cell, 4, 2, False, True, 8)
|
|
|
|
shift_test(cell, 4, 2, True, True, 8)
|
|
|
|
shift_test(cell, 4, 3, False, True, 3)
|
|
|
|
shift_test(cell, 4, 3, True, True, 3)
|
|
|
|
|
|
|
|
for cell in ["shiftx"]:
|
2023-02-13 07:02:02 -06:00
|
|
|
if args.more:
|
|
|
|
shift_test(cell, 2, 1, False, True, 2)
|
|
|
|
shift_test(cell, 2, 1, False, True, 4)
|
|
|
|
shift_test(cell, 4, 2, False, True, 4)
|
2022-11-25 10:48:15 -06:00
|
|
|
shift_test(cell, 4, 2, False, True, 8)
|
|
|
|
shift_test(cell, 4, 3, False, True, 3)
|
|
|
|
|
|
|
|
mux_test(1)
|
|
|
|
mux_test(3)
|
|
|
|
|
|
|
|
bmux_test(1, 2)
|
|
|
|
bmux_test(2, 2)
|
|
|
|
bmux_test(3, 1)
|
|
|
|
|
|
|
|
demux_test(1, 2)
|
|
|
|
demux_test(2, 2)
|
|
|
|
demux_test(3, 1)
|
|
|
|
|
|
|
|
pmux_test(1, 4)
|
|
|
|
pmux_test(2, 2)
|
|
|
|
pmux_test(3, 1)
|
|
|
|
pmux_test(4, 4)
|
|
|
|
|
|
|
|
bwmux_test(1)
|
|
|
|
bwmux_test(3)
|
|
|
|
|
|
|
|
bweqx_test(1)
|
|
|
|
bweqx_test(3)
|
|
|
|
|
|
|
|
ff_test(1)
|
|
|
|
ff_test(3)
|
|
|
|
|
|
|
|
dff_test(1, True, True)
|
|
|
|
dff_test(1, False, True)
|
|
|
|
dff_test(3, True, True)
|
|
|
|
dff_test(3, False, True)
|
|
|
|
|
|
|
|
# dff_test(1, True, False) # TODO support x clocks
|
|
|
|
# dff_test(1, False, False) # TODO support x clocks
|
|
|
|
# dff_test(3, True, False) # TODO support x clocks
|
|
|
|
# dff_test(3, False, False) # TODO support x clocks
|
|
|
|
|
|
|
|
dffe_test(1, True, False, True)
|
|
|
|
dffe_test(1, False, False, True)
|
|
|
|
dffe_test(3, True, False, True)
|
|
|
|
dffe_test(3, False, False, True)
|
|
|
|
dffe_test(1, True, True, True)
|
|
|
|
dffe_test(1, False, True, True)
|
|
|
|
dffe_test(3, True, True, True)
|
|
|
|
dffe_test(3, False, True, True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO "shift", "shiftx"
|
|
|
|
|
|
|
|
# TODO "fa", "lcu", "alu", "macc", "lut", "sop"
|
|
|
|
|
|
|
|
# TODO "slice", "concat"
|
|
|
|
|
|
|
|
# TODO "tribuf", "specify2", "specify3", "specrule"
|
|
|
|
|
|
|
|
# TODO "assert", "assume", "live", "fair", "cover", "initstate", "anyconst", "anyseq", "anyinit", "allconst", "allseq", "equiv",
|
|
|
|
|
|
|
|
# TODO "bweqx", "bwmux"
|
|
|
|
|
|
|
|
# TODO "sr", "ff", "dff", "dffe", "dffsr", "sffsre", "adff", "aldff", "sdff", "adffe", "aldffe", "sdffe", "sdffce", "dlatch", "adlatch", "dlatchsr"
|
|
|
|
|
|
|
|
# TODO "fsm"
|
|
|
|
|
|
|
|
# TODO "memrd", "memrd_v2", "memwr", "memwr_v2", "meminit", "meminit_v2", "mem", "mem_v2"
|