From 49dab3b448b7f20398774a199272b7b4708f544e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 29 Oct 2018 08:49:32 +0100 Subject: [PATCH] build/lattice/prjtrellis: simplify code, remove some workarounds --- .../boards/targets/versaecp55g_prjtrellis.py | 6 +- litex/build/lattice/prjtrellis.py | 110 +++++++++--------- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/litex/boards/targets/versaecp55g_prjtrellis.py b/litex/boards/targets/versaecp55g_prjtrellis.py index 40cd52ab..fd972ed1 100755 --- a/litex/boards/targets/versaecp55g_prjtrellis.py +++ b/litex/boards/targets/versaecp55g_prjtrellis.py @@ -16,7 +16,7 @@ class BaseSoC(Module): led0_pads = platform.request("user_led", 0) led1_pads = platform.request("user_led", 1) - # no constraint file for now with prjtrellis + # FIXME: no constraint file for now with prjtrellis platform.lookup_request("clk100").attr.add(("LOC", "P3")) platform.lookup_request("clk100").attr.add(("IO_TYPE", "LVDS")) platform.lookup_request("user_dip_btn").attr.add(("LOC", "H2")) @@ -26,7 +26,7 @@ class BaseSoC(Module): platform.lookup_request("user_led", 1).attr.add(("LOC", "D17")) platform.lookup_request("user_led", 1).attr.add(("IO_TYPE", "LVCMOS25")) - # add TRELLIS_IO instance on all inputs/outputs + # FIXME: add TRELLIS_IO instance on all inputs/outputs sys_clk_pads_i = Signal() btn_pads_i = Signal() led0_pads_i = Signal() @@ -53,7 +53,7 @@ class BaseSoC(Module): def main(): platform = versaecp55g.Platform(toolchain="prjtrellis") soc = BaseSoC(platform) - platform.build(soc) + platform.build(soc, toolchain_path="/home/florent/dev/symbiflow/prjtrellis") # FIXME if __name__ == "__main__": diff --git a/litex/build/lattice/prjtrellis.py b/litex/build/lattice/prjtrellis.py index 3801e9a1..642c9be6 100644 --- a/litex/build/lattice/prjtrellis.py +++ b/litex/build/lattice/prjtrellis.py @@ -2,7 +2,6 @@ # License: BSD import os -import sys import subprocess from migen.fhdl.structure import _Fragment @@ -12,19 +11,17 @@ from litex.build import tools from litex.build.lattice import common -def _build_script(source, build_template, build_name, device, basecfg): - build_script_contents = "# Autogenerated by LiteX\nset -e\n" - for s in build_template: - build_script_contents += s.format(build_name=build_name, device=device, basecfg=basecfg) + '\n' - build_script_file = "build_" + build_name + ".sh" - tools.write_to_file(build_script_file, build_script_contents) - return build_script_file - - -def _run_script(script): - r = subprocess.call(["bash", script]) - if r != 0: - raise OSError("Subprocess failed") +nextpnr_ecp5_architectures = { + "lfe5u-25f": "25k", + "lfe5u-45f": "45k", + "lfe5u-85f": "85k", + "lfe5um-25f": "um-25k", + "lfe5um-45f": "um-45k", + "lfe5um-85f": "um-85k", + "lfe5um5g-25f": "um5g-25k", + "lfe5um5g-45f": "um5g-45k", + "lfe5um5g-85f": "um5g-85k", +} class LatticePrjTrellisToolchain: @@ -43,25 +40,13 @@ class LatticePrjTrellisToolchain: special_overrides = common.lattice_ecpx_special_overrides - def __init__(self): - self.nextpnr_yosys_template = [ - "{read_files}", - "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0", - "synth_ecp5 -nomux -json {build_name}.json -top {build_name}", - ] - - self.nextpnr_build_template = [ - "yosys -q -l {build_name}.rpt {build_name}.ys", - "nextpnr-ecp5 --json {build_name}.json --textcfg {build_name}.config --basecfg {basecfg} --{device}", - "ecppack {build_name}.config {build_name}.bit" - ] - def build(self, platform, fragment, build_dir="build", build_name="top", toolchain_path=None, run=True): os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() os.chdir(build_dir) + # generate verilog if not isinstance(fragment, _Fragment): fragment = fragment.get_fragment() platform.finalize(fragment) @@ -70,36 +55,57 @@ class LatticePrjTrellisToolchain: named_sc, named_pc = platform.resolve_signals(v_output.ns) v_file = build_name + ".v" v_output.write(v_file) + platform.add_source(v_file) + + # generate yosys script + def yosys_import_sources(platform): + includes = "" + reads = [] + for path in platform.verilog_include_paths: + includes += " -I" + path + for filename, language, library in platform.sources: + reads.append("read_{}{} {}".format( + language, includes, filename)) + return "\n".join(reads) + + yosys_script_file = build_name + ".ys" + yosys_script_contents = [ + yosys_import_sources(platform), + "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) + tools.write_to_file(yosys_script_file, yosys_script_contents) + + # transform platform.device to nextpnr's architecture / basecfg + (family, size, package) = platform.device.split("-") + architecture = nextpnr_ecp5_architectures[(family + "-" + size).lower()] + basecfg = "empty_" + (family + "-" + size).lower() + ".config" + basecfg = os.path.join(toolchain_path, "misc", "basecfgs", basecfg) + + # generate build script + 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}", + "ecppack {build_name}.config {build_name}.bit" - yosys_template = self.nextpnr_yosys_template - ys_contents = "\n".join(_.format(build_name=build_name, - read_files=self.gen_read_files(platform, v_file)) - for _ in yosys_template) - - ys_name = build_name + ".ys" - tools.write_to_file(ys_name, ys_contents) - - build_template = self.nextpnr_build_template - script = _build_script(False, build_template, build_name, - "um5g-45k", # FIXME - "../../../../../../../symbiflow/prjtrellis/misc/basecfgs/empty_lfe5um5g-45f.config") # FIXME - _run_script(script) + ] + build_script_contents = "\n".join(build_script_contents) + build_script_contents = build_script_contents.format( + build_name=build_name, + architecture=architecture, + basecfg=basecfg) + tools.write_to_file(build_script_file, build_script_contents) + + # run scripts + if run: + if subprocess.call(["bash", build_script_file]) != 0: + raise OSError("Subprocess failed") os.chdir(cwd) return v_output.ns - def gen_read_files(self, platform, main): - sources = platform.sources + [(main, "verilog", "work")] - incflags = "" - read_files = list() - for path in platform.verilog_include_paths: - incflags += " -I" + path - for filename, language, library in sources: - read_files.append("read_{}{} {}".format(language, - incflags, - filename)) - return "\n".join(read_files) - def add_period_constraint(self, platform, clk, period): print("TODO: add_period_constraint") -- 2.30.2