def _run_quartus(build_name, quartus_path):
- build_script_contents = """# Autogenerated by LiteX
+ build_script_contents = """# Autogenerated by Migen
set -e
def lower(dr):
return LatticeECPXDDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk)
-
lattice_ecpx_special_overrides = {
AsyncResetSynchronizer: LatticeECPXAsyncResetSynchronizer,
- DDROutput: LatticeECPXDDROutput
+ DDROutput: LatticeECPXDDROutput
}
-class LatticeECPXPrjTrellisTristateImpl(Module):
+class LatticeECPXTrellisTristateImpl(Module):
def __init__(self, io, o, oe, i):
nbits, sign = value_bits_sign(io)
for bit in range(nbits):
i_T=~oe,
)
-class LatticeECPXPrjTrellisTristate(Module):
+class LatticeECPXTrellisTristate(Module):
@staticmethod
def lower(dr):
- return LatticeECPXPrjTrellisTristateImpl(dr.target, dr.o, dr.oe, dr.i)
+ return LatticeECPXTrellisTristateImpl(dr.target, dr.o, dr.oe, dr.i)
-
-lattice_ecpx_prjtrellis_special_overrides = {
+lattice_ecpx_trellis_special_overrides = {
AsyncResetSynchronizer: LatticeECPXAsyncResetSynchronizer,
- Tristate: LatticeECPXPrjTrellisTristate,
+ Tristate: LatticeECPXTrellisTristate,
DDROutput: LatticeECPXDDROutput
}
def lower(dr):
return LatticeiCE40DifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
-
lattice_ice40_special_overrides = {
AsyncResetSynchronizer: LatticeiCE40AsyncResetSynchronizer,
Tristate: LatticeiCE40Tristate,
from litex.build.lattice import common
+def _produces_jedec(device):
+ return device.startswith("LCMX")
+
+
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
+ return ("IOBUF PORT ", " " + c.misc)
def _format_lpf(signame, pin, others, resname):
def _build_files(device, sources, vincpaths, build_name):
tcl = []
- tcl.append("prj_project new -name \"{}\" -impl \"implementation\" -dev {} -synthesis \"synplify\"".format(build_name, device))
+ tcl.append("prj_project new -name \"{}\" -impl \"impl\" -dev {} -synthesis \"synplify\"".format(build_name, device))
for path in vincpaths:
tcl.append("prj_impl option {include path} {\"" + path + "\"}")
for filename, language, library in sources:
tcl.append("prj_src add \"" + filename + "\" -work " + library)
tcl.append("prj_impl option top \"{}\"".format(build_name))
- tcl.append("prj_run Synthesis -impl implementation -forceOne")
- tcl.append("prj_run Translate -impl implementation")
- tcl.append("prj_run Map -impl implementation")
- tcl.append("prj_run PAR -impl implementation")
- tcl.append("prj_run Export -impl implementation -task Bitgen")
+ tcl.append("prj_project save")
+ tcl.append("prj_run Synthesis -impl impl -forceOne")
+ tcl.append("prj_run Translate -impl impl")
+ tcl.append("prj_run Map -impl impl")
+ tcl.append("prj_run PAR -impl impl")
+ tcl.append("prj_run Export -impl impl -task Bitgen")
+ if _produces_jedec(device):
+ tcl.append("prj_run Export -impl impl -task Jedecgen")
tools.write_to_file(build_name + ".tcl", "\n".join(tcl))
-def _run_diamond(build_name, toolchain_path, ver=None):
- if sys.platform == "win32" or sys.platform == "cygwin":
- build_script_contents = "REM Autogenerated by LiteX\n"
- build_script_contents += "pnmainc " + build_name + ".tcl\n"
- build_script_file = "build_" + build_name + ".bat"
- tools.write_to_file(build_script_file, build_script_contents)
- r = subprocess.call([build_script_file])
- shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit")
- shutil.copy(os.path.join("implementation", build_name + "_implementation.jed"), build_name + ".jed")
- elif sys.platform == "linux":
- bindir = os.path.join(toolchain_path, 'bin/lin64')
- envfile = os.path.join(bindir, 'diamond_env')
- build_script_contents = "# Autogenerated by LiteX\n"
- build_script_contents += "set -e\n"
- build_script_contents += "bindir='{}/'\n".format(bindir)
- build_script_contents += "source {}\n".format(envfile)
- build_script_contents += "diamondc {}.tcl | tee build.log\n".format(build_name)
- build_script_file = "build_{}.sh".format(build_name)
-
- tools.write_to_file(build_script_file, build_script_contents)
- r = subprocess.call(["bash", build_script_file])
- shutil.copy(os.path.join("implementation", build_name + "_implementation.bit"), build_name + ".bit")
+def _build_script(build_name, device, toolchain_path, ver=None):
+ if sys.platform in ("win32", "cygwin"):
+ script_ext = ".bat"
+ build_script_contents = "@echo off\nrem Autogenerated by Migen\n\n"
+ copy_stmt = "copy"
+ fail_stmt = " || exit /b"
+ else:
+ script_ext = ".sh"
+ build_script_contents = "# Autogenerated by Migen\nset -e\n\n"
+ copy_stmt = "cp"
+ fail_stmt = ""
+
+ if sys.platform not in ("win32", "cygwin"):
+ build_script_contents += "bindir={}\n".format(toolchain_path)
+ build_script_contents += ". ${{bindir}}/diamond_env{fail_stmt}\n".format(
+ fail_stmt=fail_stmt)
+ build_script_contents += "{pnmainc} {tcl_script}{fail_stmt}\n".format(
+ pnmainc=os.path.join(toolchain_path, "pnmainc"),
+ tcl_script=build_name + ".tcl",
+ fail_stmt=fail_stmt)
+ for ext in (".bit", ".jed"):
+ if ext == ".jed" and not _produces_jedec(device):
+ continue
+ build_script_contents += "{copy_stmt} {diamond_product} {migen_product}" \
+ "{fail_stmt}\n".format(
+ copy_stmt=copy_stmt,
+ fail_stmt=fail_stmt,
+ diamond_product=os.path.join("impl", build_name + "_impl" + ext),
+ migen_product=build_name + ext)
+
+ build_script_file = "build_" + build_name + script_ext
+ tools.write_to_file(build_script_file, build_script_contents,
+ force_unix=False)
+ return build_script_file
+
+
+def _run_script(script):
+ if sys.platform in ("win32", "cygwin"):
+ shell = ["cmd", "/c"]
else:
- raise NotImplementedError
+ shell = ["bash"]
- if r != 0:
+ if subprocess.call(shell + [script]) != 0:
raise OSError("Subprocess failed")
class LatticeDiamondToolchain:
- attr_translate = DummyAttrTranslate()
+ attr_translate = {
+ # FIXME: document
+ "keep": ("syn_keep", "true"),
+ "no_retiming": ("syn_no_retiming", "true"),
+ "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 build(self, platform, fragment, build_dir="build", build_name="top",
- toolchain_path="/opt/Diamond", run=True, **kwargs):
+ toolchain_path="/opt/Diamond", run=True):
os.makedirs(build_dir, exist_ok=True)
cwd = os.getcwd()
os.chdir(build_dir)
fragment = fragment.get_fragment()
platform.finalize(fragment)
- v_output = platform.get_verilog(fragment, name=build_name, **kwargs)
+ 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)
- sources = platform.sources + [(v_file, "verilog", "work")]
+ sources = platform.sources | {(v_file, "verilog", "work")}
_build_files(platform.device, sources, platform.verilog_include_paths, build_name)
tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc))
+ script = _build_script(build_name, platform.device, toolchain_path)
if run:
- _run_diamond(build_name, toolchain_path)
+ _run_script(script)
os.chdir(cwd)
icetime_pkg_opts, freq_constraint):
if sys.platform in ("win32", "cygwin"):
script_ext = ".bat"
- build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
+ build_script_contents = "@echo off\nrem Autogenerated by Migen\n"
fail_stmt = " || exit /b"
else:
script_ext = ".sh"
- build_script_contents = "# Autogenerated by LiteX\nset -e\n"
+ build_script_contents = "# Autogenerated by Migen\nset -e\n"
fail_stmt = ""
for s in build_template:
from litex.build.generic_platform import GenericPlatform
-from litex.build.lattice import common, diamond, icestorm, prjtrellis
+from litex.build.lattice import common, diamond, icestorm, trellis
class LatticePlatform(GenericPlatform):
GenericPlatform.__init__(self, *args, **kwargs)
if toolchain == "diamond":
self.toolchain = diamond.LatticeDiamondToolchain()
- elif toolchain == "prjtrellis":
- self.toolchain = prjtrellis.LatticePrjTrellisToolchain()
+ elif toolchain == "trellis":
+ self.toolchain = trellis.LatticeTrellisToolchain()
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 subprocess
-
-from migen.fhdl.structure import _Fragment
-
-from litex.build.generic_platform import *
-from litex.build import tools
-from litex.build.lattice import common
-
-# TODO:
-# - add timing constraint support.
-# - check/document attr_translate.
-
-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",
-}
-
-
-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 ("IOBUF PORT ", " " + 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 = []
- 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)
-
-
-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_prjtrellis_special_overrides
-
- def build(self, platform, fragment, build_dir="build", build_name="top",
- toolchain_path=None, run=True):
- if toolchain_path is None:
- toolchain_path = "/usr/share/trellis/"
- 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)
-
- top_output = platform.get_verilog(fragment, name=build_name)
- named_sc, named_pc = platform.resolve_signals(top_output.ns)
- top_file = build_name + ".v"
- top_output.write(top_file)
- platform.add_source(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 {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 --lpf {build_name}.lpf --textcfg {build_name}.config --basecfg {basecfg} --{architecture}",
- "ecppack {build_name}.config {build_name}.bit"
-
- ]
- 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 top_output.ns
-
- def add_period_constraint(self, platform, clk, period):
- print("TODO: add_period_constraint")
--- /dev/null
+# This file is Copyright (c) 2018 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
+# License: BSD
+
+import os
+import subprocess
+import sys
+
+from migen.fhdl.structure import _Fragment
+
+from litex.build.generic_platform import *
+from litex.build import tools
+from litex.build.lattice import common
+
+# TODO:
+# - check/document attr_translate.
+
+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",
+}
+
+
+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 ("IOBUF PORT ", " " + c.misc)
+
+
+def _format_lpf(signame, pin, others, resname):
+ fmt_c = [_format_constraint(c) for c in ([Pins(pin)] + others)]
+ r = ""
+ print(fmt_c)
+ 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 _build_script(source, build_template, build_name, architecture,
+ basecfg, freq_constraint):
+ if sys.platform in ("win32", "cygwin"):
+ script_ext = ".bat"
+ build_script_contents = "@echo off\nrem Autogenerated by Migen\n\n"
+ fail_stmt = " || exit /b"
+ else:
+ script_ext = ".sh"
+ build_script_contents = "# Autogenerated by Migen\nset -e\n\n"
+ fail_stmt = ""
+
+ for s in build_template:
+ s_fail = s + "{fail_stmt}\n" # Required so Windows scripts fail early.
+ build_script_contents += s_fail.format(build_name=build_name,
+ architecture=architecture,
+ basecfg=basecfg,
+ freq_constraint=freq_constraint,
+ fail_stmt=fail_stmt)
+
+ build_script_file = "build_" + build_name + script_ext
+ tools.write_to_file(build_script_file, build_script_contents,
+ force_unix=False)
+ return build_script_file
+
+
+def _run_script(script):
+ if sys.platform in ("win32", "cygwin"):
+ shell = ["cmd", "/c"]
+ else:
+ shell = ["bash"]
+
+ if subprocess.call(shell + [script]) != 0:
+ raise OSError("Subprocess failed")
+
+
+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)
+
+
+class LatticeTrellisToolchain:
+ 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_trellis_special_overrides
+
+ def __init__(self):
+ self.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.build_template = [
+ "yosys -q -l {build_name}.rpt {build_name}.ys",
+ "nextpnr-ecp5 --json {build_name}.json --lpf {build_name}.lpf --textcfg {build_name}.config --basecfg {basecfg} --{architecture} --freq {freq_constraint}",
+ "ecppack {build_name}.config {build_name}.bit"
+ ]
+
+ self.freq_constraints = dict()
+
+ def build(self, platform, fragment, build_dir="build", build_name="top",
+ toolchain_path=None, run=True):
+ if toolchain_path is None:
+ toolchain_path = "/usr/share/trellis/"
+ 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)
+
+ top_output = platform.get_verilog(fragment, name=build_name)
+ named_sc, named_pc = platform.resolve_signals(top_output.ns)
+ top_file = build_name + ".v"
+ top_output.write(top_file)
+ platform.add_source(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 = "\n".join(_.format(build_name=build_name,
+ read_files=yosys_import_sources(platform))
+ for _ in self.yosys_template)
+ 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)
+ freq_constraint = str(max(self.freq_constraints.values(),
+ default=0.0))
+
+ script = _build_script(False, self.build_template, build_name,
+ architecture, basecfg, freq_constraint)
+
+ # run scripts
+ if run:
+ _run_script(script)
+
+ os.chdir(cwd)
+
+ return top_output.ns
+
+ # Until nextpnr-ecp5 can handle multiple clock domains, use the same
+ # approach as the icestorm and use the fastest clock for timing
+ # constraints.
+ def add_period_constraint(self, platform, clk, period):
+ new_freq = 1000.0/period
+
+ if clk not in self.freq_constraints.keys():
+ self.freq_constraints[clk] = new_freq
+ else:
+ raise ConstraintError("Period constraint already added to signal.")
source_cmd = "call "
script_ext = ".bat"
shell = ["cmd", "/c"]
- build_script_contents = "@echo off\nrem Autogenerated by LiteX\n"
+ build_script_contents = "@echo off\nrem Autogenerated by Migen\n"
fail_stmt = " || exit /b"
else:
source_cmd = "source "
script_ext = ".sh"
shell = ["bash"]
- build_script_contents = "# Autogenerated by LiteX\nset -e\n"
+ build_script_contents = "# Autogenerated by Migen\nset -e\n"
fail_stmt = ""
if source:
settings = common.settings(ise_path, ver, "ISE_DS")
def _run_vivado(build_name, vivado_path, source, ver=None):
if sys.platform == "win32" or sys.platform == "cygwin":
- build_script_contents = "REM Autogenerated by LiteX\n"
+ build_script_contents = "REM Autogenerated by Migen\n"
build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n"
build_script_file = "build_" + build_name + ".bat"
tools.write_to_file(build_script_file, build_script_contents)
command = build_script_file
else:
- build_script_contents = "# Autogenerated by LiteX\nset -e\n"
+ build_script_contents = "# Autogenerated by Migen\nset -e\n"
# For backwards compatibility with ISE paths, also
# look for a version in a subdirectory named "Vivado"