yosys/tests/xprop/generate.py

288 lines
10 KiB
Python
Raw Permalink Normal View History

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')
parser.add_argument('-m', '--more', action='store_true', help='run more tests')
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"
f"\t@grep '^.*: ok' {workdir}/status\n"
,
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"]:
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)
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)
if args.more:
binary_test(cell, 2, 2, False, 1)
binary_test(cell, 2, 1, False, 2)
binary_test(cell, 2, 1, False, 1)
# [, "pow"] are not implemented yet
for cell in ["add", "sub", "mul", "div", "mod", "divfloor", "modfloor"]:
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)
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"]:
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)
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"]:
if args.more:
unary_test(cell, 1, False, 1)
unary_test(cell, 3, False, 1)
unary_test(cell, 3, True, 1)
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"]:
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)
shift_test(cell, 4, 3, False, False, 3)
shift_test(cell, 4, 3, True, False, 3)
for cell in ["shift"]:
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)
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"]:
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)
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"