from litex.build.generic_platform import GenericPlatform
-from litex.build.lattice import common, diamond, icestorm
+from litex.build.lattice import common, diamond, icestorm, prjtrellis
class LatticePlatform(GenericPlatform):
GenericPlatform.__init__(self, *args, **kwargs)
if toolchain == "diamond":
self.toolchain = diamond.LatticeDiamondToolchain()
+ elif toolchain == "prjtrellis":
+ self.toolchain = prjtrellis.LatticePrjTrellisToolchain()
elif toolchain == "icestorm":
self.bitstream_ext = ".bin"
self.toolchain = icestorm.LatticeIceStormToolchain()
--- /dev/null
+# This file is Copyright (c) 2018 Florent Kermarrec <florent@enjoy-digital.fr>
+# License: BSD
+
+import os
+import sys
+import subprocess
+
+from migen.fhdl.structure import _Fragment
+
+from litex.build.generic_platform import *
+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")
+
+
+class LatticePrjTrellisToolchain:
+ attr_translate = {
+ # FIXME: document
+ "keep": ("keep", "true"),
+ "no_retiming": None,
+ "async_reg": None,
+ "mr_ff": None,
+ "mr_false_path": None,
+ "ars_ff1": None,
+ "ars_ff2": None,
+ "ars_false_path": None,
+ "no_shreg_extract": None
+ }
+
+ 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)
+
+ if not isinstance(fragment, _Fragment):
+ fragment = fragment.get_fragment()
+ platform.finalize(fragment)
+
+ v_output = platform.get_verilog(fragment)
+ named_sc, named_pc = platform.resolve_signals(v_output.ns)
+ v_file = build_name + ".v"
+ v_output.write(v_file)
+
+ 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)
+
+ 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")