mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Use `$finish(0)` to silently exit even when using recent iverlog versions. Run `write_verilog -noexpr` before `write_verilog` as the latter can modify the design. This also enables checking the tests results, as xprop should be in a state where the existing tests pass.
		
			
				
	
	
		
			287 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 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"
 |