From 0c1d8d59935c2ddca8f44e961c975640736b8096 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 31 Oct 2018 11:43:39 +0000 Subject: [PATCH] trellis: Switch to using LPF for constraints Signed-off-by: David Shah --- litex/build/lattice/prjtrellis.py | 133 ++++++++---------------------- 1 file changed, 36 insertions(+), 97 deletions(-) diff --git a/litex/build/lattice/prjtrellis.py b/litex/build/lattice/prjtrellis.py index d019e147..e27ae1c6 100644 --- a/litex/build/lattice/prjtrellis.py +++ b/litex/build/lattice/prjtrellis.py @@ -13,8 +13,6 @@ from litex.build.lattice import common # TODO: # - add timing constraint support. # - check/document attr_translate. -# - use constraint file when prjtrellis will support it. - nextpnr_ecp5_architectures = { "lfe5u-25f": "25k", @@ -29,6 +27,37 @@ nextpnr_ecp5_architectures = { } +def _format_constraint(c): + if isinstance(c, Pins): + return ("LOCATE COMP ", " SITE " + "\"" + c.identifiers[0] + "\"") + elif isinstance(c, IOStandard): + return ("IOBUF PORT ", " IO_TYPE=" + c.name) + elif isinstance(c, Misc): + return c.misc + + +def _format_lpf(signame, pin, others, resname): + fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)] + r = "" + for pre, suf in fmt_c: + r += pre + "\"" + signame + "\"" + suf + ";\n" + return r + + +def _build_lpf(named_sc, named_pc): + r = "BLOCK RESETPATHS;\n" + r += "BLOCK ASYNCPATHS;\n" + for sig, pins, others, resname in named_sc: + if len(pins) > 1: + for i, p in enumerate(pins): + r += _format_lpf(sig + "[" + str(i) + "]", p, others, resname) + else: + r += _format_lpf(sig, pins[0], others, resname) + if named_pc: + r += "\n" + "\n\n".join(named_pc) + return r + + def yosys_import_sources(platform): includes = "" reads = [] @@ -40,93 +69,6 @@ def yosys_import_sources(platform): return "\n".join(reads) -def generate_prjtrellis_top(top_file, platform, vns): - # resolve ios directions / types - ios, _ = platform.resolve_signals(vns) - ios_direction = {} - ios_type = {} - cm = platform.constraint_manager - for io_name, io_pins, _, _ in ios: - for cm_sig, cm_pins, _, _ in cm.get_sig_constraints(): - if io_pins == cm_pins: - ios_direction[io_name] = cm_sig.direction - ios_type[io_name] = cm_sig.type - last_io_name = io_name - - # prjtrellis module / ios declaration - top_contents = [] - top_contents.append("module prjtrellis_{build_name}(") - ios_declaration = "" - for io_name, io_pins, io_others, _ in ios: - for io_other in io_others: - if isinstance(io_other, IOStandard): - io_standard = io_other.name - for i, io_pin in enumerate(io_pins): - ios_declaration += "(* LOC=\"{}\" *) (* IO_TYPE=\"{}\" *)\n".format(io_pin, io_standard) - ios_declaration += "\t" + ios_direction[io_name] + " " + io_name + "_io" + (str(i) if len(io_pins) > 1 else "") - ios_declaration += ",\n" if io_name != last_io_name or (i != len(io_pins) - 1) else "" - top_contents.append(ios_declaration) - top_contents.append(");\n") - - # top signals declaration - signals_declaration = "" - for io_name, io_pins, _, _ in ios: - signals_declaration += ios_type[io_name] + " " - if len(io_pins) > 1: - signals_declaration += "[{}:0] ".format(len(io_pins) - 1) - signals_declaration += io_name - signals_declaration += ";\n" - top_contents.append(signals_declaration) - - # trellis_ios declaration - trellis_io_declaration = "" - for io_name, io_pins, io_others, _ in ios: - for i, io_pin in enumerate(io_pins): - io_suffix = "io" + str(i) if len(io_pins) > 1 else "io" - if ios_direction[io_name] == "input": - trellis_io_declaration += \ - "TRELLIS_IO #(.DIR(\"INPUT\")) {} (.B({}), .O({}));\n".format( - io_name + "_buf" + str(i), io_name + "_" + io_suffix, io_name + "[" + str(i) + "]") - elif ios_direction[io_name] == "output": - trellis_io_declaration += \ - "TRELLIS_IO #(.DIR(\"OUTPUT\")) {} (.B({}), .I({}));\n".format( - io_name + "_buf" + str(i), io_name + "_" + io_suffix, io_name + "[" + str(i) + "]") - else: - pass # handled by Migen's Tristate - top_contents.append(trellis_io_declaration) - - # top_recopy: - # - skip module definition. - # - use ios names for inouts. - def replace_inouts(l): - r = l - for io_name, io_pins, _, _ in ios: - if ios_direction[io_name] == "inout": - if len(io_pins) > 1: - for i in range(len(io_pins)): - r = r.replace(io_name + "[" + str(i) + "]", io_name + "_io" + str(i)) - else: - r = r.replace(io_name, io_name + "_io") - return r - - skip = True - f = open(top_file, "r") - for l in f: - if not skip: - l = l.replace("\n", "") - l = l.replace("{", "{{") - l = l.replace("}", "}}") - l = replace_inouts(l) - top_contents.append(l) - if ");" in l: - skip = False - f.close() - - top_contents = "\n".join(top_contents) - - return top_contents - - class LatticePrjTrellisToolchain: attr_translate = { # FIXME: document @@ -157,21 +99,18 @@ class LatticePrjTrellisToolchain: platform.finalize(fragment) top_output = platform.get_verilog(fragment) + named_sc, named_pc = platform.resolve_signals(top_output.ns) top_file = build_name + ".v" top_output.write(top_file) - # insert constraints and trellis_io to generated verilog - prjtrellis_top_file = build_name + "_prjtrellis.v" - prjtrellis_top_contents = generate_prjtrellis_top(top_file, platform, top_output.ns) - prjtrellis_top_contents = prjtrellis_top_contents.format(build_name=build_name) - tools.write_to_file(prjtrellis_top_file, prjtrellis_top_contents) - platform.add_source(prjtrellis_top_file) + # generate constraints + tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc)) # generate yosys script yosys_script_file = build_name + ".ys" yosys_script_contents = [ yosys_import_sources(platform), - "synth_ecp5 -nomux -json {build_name}.json -top prjtrellis_{build_name}" + "synth_ecp5 -nomux -json {build_name}.json -top {build_name}" ] yosys_script_contents = "\n".join(yosys_script_contents) yosys_script_contents = yosys_script_contents.format(build_name=build_name) @@ -187,7 +126,7 @@ class LatticePrjTrellisToolchain: build_script_file = "build_" + build_name + ".sh" build_script_contents = [ "yosys -q -l {build_name}.rpt {build_name}.ys", - "nextpnr-ecp5 --json {build_name}.json --textcfg {build_name}.config --basecfg {basecfg} --{architecture}", + "nextpnr-ecp5 --json {build_name}.json --lpf {build_name}.lpf --textcfg {build_name}.config --basecfg {basecfg} --{architecture}", "ecppack {build_name}.config {build_name}.bit" ] -- 2.30.2