diff --git a/timing/fuzzers/LIFCL/02-ram/gen_ram.py b/timing/fuzzers/LIFCL/02-ram/gen_ram.py index 4dae903..e7582dd 100644 --- a/timing/fuzzers/LIFCL/02-ram/gen_ram.py +++ b/timing/fuzzers/LIFCL/02-ram/gen_ram.py @@ -21,7 +21,6 @@ def get_next_data(i, N): return ["d_{}[{}]".format(i, j) for j in range(N)] N = 80 -M = 2 for i in range(N): prim = random.choice(["DP16K", "PDP16K", "PDPSC16K", "SP16K", "FIFO16K"]) @@ -118,69 +117,5 @@ def get_next_data(i, N): assert False data = next_data -for i in range(N, N+M): - lram_prim = random.choice(["DPSC512K", "PDPSC512K", "SP512K"]) - if lram_prim == "DPSC512K": - next_data = get_next_data(i, 32+32+4) - print(" DPSC512K lram_{} (".format(i)) - clock_port("CLK") - ce_port("CEA") - ce_port("CEB") - ce_port("WEA") - ce_port("WEB") - ce_port("CSA") - ce_port("CSB") - ce_port("CEOUTA") - ce_port("CEOUTB") - rst_port("RSTA") - rst_port("RSTB") - data_port("BENA_N", 4) - data_port("BENB_N", 4) - data_port("ADA", 14) - data_port("ADB", 14) - data_port("DIA", 32) - data_port("DIB", 32) - output_port("DOA", i, 0, 32, False) - output_port("DOB", i, 32, 32, False) - output_port("ERRDECA", i, 64, 2, False) - output_port("ERRDECB", i, 66, 2, True) - print(" );") - elif lram_prim == "PDPSC512K": - next_data = get_next_data(i, 32+4) - print(" PDPSC512K lram_{} (".format(i)) - clock_port("CLK") - ce_port("CEW") - ce_port("CER") - ce_port("WE") - ce_port("CSW") - ce_port("CSR") - rst_port("RSTR") - data_port("BYTEEN_N", 4) - data_port("ADW", 14) - data_port("ADR", 14) - data_port("DI", 32) - output_port("DO", i, 0, 32, False) - output_port("ERRDECA", i, 32, 2, False) - output_port("ERRDECB", i, 34, 2, True) - print(" );") - elif lram_prim == "SP512K": - next_data = get_next_data(i, 32+4) - print(" SP512K lram_{} (".format(i)) - clock_port("CLK") - ce_port("CE") - ce_port("WE") - ce_port("CS") - ce_port("CEOUT") - rst_port("RSTOUT") - data_port("BYTEEN_N", 4) - data_port("AD", 14) - data_port("DI", 32) - output_port("DO", i, 0, 32, False) - output_port("ERRDECA", i, 32, 2, False) - output_port("ERRDECB", i, 34, 2, True) - print(" );") - else: - assert False - data = next_data print(" assign q = {};".format(data_bits(8))) print("endmodule") diff --git a/timing/fuzzers/LIFCL/09-lram/Makefile b/timing/fuzzers/LIFCL/09-lram/Makefile new file mode 100644 index 0000000..cc34db9 --- /dev/null +++ b/timing/fuzzers/LIFCL/09-lram/Makefile @@ -0,0 +1,7 @@ +NAME=lram +RUNS=$(shell seq 10) +GENERATOR2=gen_lram.py +DEVICE=LIFCL-17 +ALLOW_FAIL=false + +include ../../../tools/fuzzer.mk diff --git a/timing/fuzzers/LIFCL/09-lram/gen_lram.py b/timing/fuzzers/LIFCL/09-lram/gen_lram.py new file mode 100644 index 0000000..e38dd65 --- /dev/null +++ b/timing/fuzzers/LIFCL/09-lram/gen_lram.py @@ -0,0 +1,151 @@ +import argparse +import random +import json + +def main(): + + parser = argparse.ArgumentParser() + parser.add_argument( + "--vlog", + type=str, + required=True, + help="Output Verilog file" + ) + parser.add_argument( + "--conf", + type=str, + required=True, + help="Output cell configuration file" + ) + + args = parser.parse_args() + + vlog = open(args.vlog, "w") + + print("module top(input [3:0] clk, ce, rst, input [7:0] d, output [7:0] q);", file=vlog) + data = ["d[{}]".format(i) for i in range(8)] + + def data_bits(N): + return "{{{}}}".format(", ".join([random.choice(data) for i in range(N)])) + def clock_port(name): + print(" .{}(clk[{}]),".format(name, random.randint(0, 3)), file=vlog) + def ce_port(name): + print(" .{}(ce[{}]),".format(name, random.randint(0, 3)), file=vlog) + def rst_port(name): + print(" .{}(rst[{}]),".format(name, random.randint(0, 3)), file=vlog) + def data_port(name, N): + print(" .{}({}),".format(name, data_bits(N)), file=vlog) + def output_port(name, i, j, N, last=False): + print(" .{}(d_{}[{} +: {}]){}".format(name, i, j, N, "" if last else ","), file=vlog) + + def get_next_data(i, N): + print(" wire [{}:0] d_{};".format(N-1, i), file=vlog) + return ["d_{}[{}]".format(i, j) for j in range(N)] + + N = 5 + config = {} + + for i in range(N): + lram_prim = random.choice(["DPSC512K", "PDPSC512K", "SP512K"]) + if lram_prim == "DPSC512K": + oreg_a = random.choice(["NO_REG", "OUT_REG"]) + oreg_b = random.choice(["NO_REG", "OUT_REG"]) + next_data = get_next_data(i, 32+32+4) + print(" DPSC512K #(.OUTREG_A(\"{}\"),.OUTREG_B(\"{}\")) lram_{} (".format(oreg_a, oreg_b, i), file=vlog) + clock_port("CLK") + ce_port("CEA") + ce_port("CEB") + ce_port("WEA") + ce_port("WEB") + ce_port("CSA") + ce_port("CSB") + ce_port("CEOUTA") + ce_port("CEOUTB") + rst_port("RSTA") + rst_port("RSTB") + data_port("BENA_N", 4) + data_port("BENB_N", 4) + data_port("ADA", 14) + data_port("ADB", 14) + data_port("DIA", 32) + data_port("DIB", 32) + output_port("DOA", i, 0, 32, False) + output_port("DOB", i, 32, 32, False) + output_port("ERRDECA", i, 64, 2, False) + output_port("ERRDECB", i, 66, 2, True) + print(" );", file=vlog) + + key = f"lram_{i}" + config[key] = { + "type": "DPC512K", + "params": { + "OUTREG_A": oreg_a, + "OUTREG_B": oreg_b, + }, + } + + elif lram_prim == "PDPSC512K": + oreg = random.choice(["NO_REG", "OUT_REG"]) + next_data = get_next_data(i, 32+4) + print(" PDPSC512K #(.OUTREG(\"{}\")) lram_{} (".format(oreg, i), file=vlog) + clock_port("CLK") + ce_port("CEW") + ce_port("CER") + ce_port("WE") + ce_port("CSW") + ce_port("CSR") + rst_port("RSTR") + data_port("BYTEEN_N", 4) + data_port("ADW", 14) + data_port("ADR", 14) + data_port("DI", 32) + output_port("DO", i, 0, 32, False) + output_port("ERRDECA", i, 32, 2, False) + output_port("ERRDECB", i, 34, 2, True) + print(" );", file=vlog) + + key = f"lram_{i}" + config[key] = { + "type": "PDPSC512K", + "params": { + "OUTREG": oreg, + }, + } + + elif lram_prim == "SP512K": + oreg = random.choice(["NO_REG", "OUT_REG"]) + next_data = get_next_data(i, 32+4) + print(" SP512K #(.OUTREG(\"{}\")) lram_{} (".format(oreg, i), file=vlog) + clock_port("CLK") + ce_port("CE") + ce_port("WE") + ce_port("CS") + ce_port("CEOUT") + rst_port("RSTOUT") + data_port("BYTEEN_N", 4) + data_port("AD", 14) + data_port("DI", 32) + output_port("DO", i, 0, 32, False) + output_port("ERRDECA", i, 32, 2, False) + output_port("ERRDECB", i, 34, 2, True) + print(" );", file=vlog) + + key = f"lram_{i}" + config[key] = { + "type": "SP512K", + "params": { + "OUTREG": oreg, + }, + } + + else: + assert False + data = next_data + print(" assign q = {};".format(data_bits(8)), file=vlog) + print("endmodule", file=vlog) + + with open(args.conf, "w") as fp: + fp.write(json.dumps(config, sort_keys=True, indent=2)) + +if __name__ == "__main__": + main() diff --git a/timing/tools/fuzzer.mk b/timing/tools/fuzzer.mk index a843ee2..1208b61 100644 --- a/timing/tools/fuzzer.mk +++ b/timing/tools/fuzzer.mk @@ -1,3 +1,5 @@ +PYTHON ?= python3 + all: work/stamp work/stamp: $(foreach run,$(RUNS),work/$(run).stamp) @@ -6,9 +8,17 @@ work/stamp: $(foreach run,$(RUNS),work/$(run).stamp) BASE_DIR=../../../../ OUT_DIR=../../../output/ +ifneq ($(GENERATOR),) work/design_%.v: $(GENERATOR) mkdir -p work/ - python $(GENERATOR) > $@ + $(PYTHON) $(GENERATOR) > $@ +endif + +ifneq ($(GENERATOR2),) +work/design_%.v: $(GENERATOR2) + mkdir -p work/ + $(PYTHON) $(GENERATOR2) --vlog $@ --conf $(subst .v,.json,$@) +endif work/design_%.bit: work/design_%.v $(BASE_DIR)/radiant.sh $(DEVICE) $< || $(ALLOW_FAIL) @@ -16,7 +26,7 @@ work/design_%.bit: work/design_%.v work/%.stamp: work/design_%.bit mkdir -p $(OUT_DIR) - python $(BASE_DIR)/timing/util/extract_route.py work/design_$*.tmp/par.udb $(OUT_DIR)/$(NAME)_$*_route.pickle + $(PYTHON) $(BASE_DIR)/timing/util/extract_route.py work/design_$*.tmp/par.udb $(OUT_DIR)/$(NAME)_$*_route.pickle # we need the '|| true' because of # malloc_consolidate(): unaligned fastbin chunk detected @@ -31,6 +41,8 @@ work/%.stamp: work/design_%.bit $(BASE_DIR)/radiant_cmd.sh backanno -min -w -o $(OUT_DIR)/$(NAME)_$*_M.vo work/design_$*.tmp/par.udb || true + [ -f "work/design_$*.json" ] && cp -f "work/design_$*.json" $(OUT_DIR)/$(NAME)_$*.json + touch $@ .PRECIOUS: work/design_%.v work/design_%.bit work/%.stamp diff --git a/timing/util/extract_cell_timings.py b/timing/util/extract_cell_timings.py index a01ccd8..07e8f92 100644 --- a/timing/util/extract_cell_timings.py +++ b/timing/util/extract_cell_timings.py @@ -75,7 +75,7 @@ def unescape_sdf_name(name): subtracts = {} -def rewrite_path(modules, modtype, from_pin, to_pin): +def rewrite_path(modules, modtype, from_pin, to_pin, cellconf=None): # Rewrite a (celltype, from_pin, to_pin) tuple given cell data, or returns None to drop the path # This looks at the JSON output by Yosys from the Lattice structural Verilog netlist in order # to determine what the cells in the SDF file are actually doing @@ -233,7 +233,17 @@ def strip_prefix_ebr(x, p): continue return (ebr_type, strip_prefix_ebr(from_pin, ebr_prefixes), strip_prefix_ebr(to_pin, ebr_prefixes)) if celltype.startswith("LRAM_CORE"): - return ("LRAM_CORE", strip_prefix(from_pin, lram_prefixes), strip_prefix(to_pin, lram_prefixes)) + conf_str = "" + if cellconf is not None: + spen = "ENABLE" if cellconf["type"] == "SP512K" else "DISABLE" + if "OUTREG" in cellconf["params"]: + oreg_a = cellconf["params"]["OUTREG"] + oreg_b = cellconf["params"]["OUTREG"] + else: + oreg_a = cellconf["params"]["OUTREG_A"] + oreg_b = cellconf["params"]["OUTREG_B"] + conf_str = ":{},{},{}".format(spen, oreg_a, oreg_b) + return ("LRAM_CORE" + conf_str, strip_prefix(from_pin, lram_prefixes), strip_prefix(to_pin, lram_prefixes)) return None def main(): @@ -256,13 +266,23 @@ def main(): with open(sdffile, "rb") as sdff: sdf = pickle.load(sdff) + # Load cell configuration if any + conffile = netlist.rsplit("_", maxsplit=1)[0] + ".json" + try: + with open(conffile, "r") as fp: + conf = json.load(fp) + except FileNotFoundError: + conf = dict() + speed = sdffile.replace(".sdf.pickle", "").split("_")[-1] assert speed in speedgrades for cell in sdf.cells.values(): celltype = unescape_sdf_name(cell.type) + if conf is not None: + cellconf = conf.get(cell.inst.split("\\",maxsplit=1)[0], None) for entry in cell.entries: if isinstance(entry, IOPath): - rewritten = rewrite_path(modules, celltype, entry.from_pin, entry.to_pin) + rewritten = rewrite_path(modules, celltype, entry.from_pin, entry.to_pin, cellconf) if rewritten is None: continue if rewritten in iopaths[speed]: