# License: BSD
import os
-import sys
import subprocess
from migen.fhdl.structure import _Fragment
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:
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)
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")