build/lattice: import changes from migen
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 12 Nov 2018 09:23:10 +0000 (10:23 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 12 Nov 2018 09:46:49 +0000 (10:46 +0100)
litex/build/altera/quartus.py
litex/build/lattice/common.py
litex/build/lattice/diamond.py
litex/build/lattice/icestorm.py
litex/build/lattice/platform.py
litex/build/lattice/prjtrellis.py [deleted file]
litex/build/lattice/trellis.py [new file with mode: 0644]
litex/build/xilinx/ise.py
litex/build/xilinx/vivado.py

index 0dcdb53ada3e52f633c720c62f999ad6584f2943..76ec775c8e35f01765684f1ede803b58943761b4 100644 (file)
@@ -92,7 +92,7 @@ def _build_files(device, sources, vincpaths, named_sc, named_pc, build_name):
 
 
 def _run_quartus(build_name, quartus_path):
-    build_script_contents = """# Autogenerated by LiteX
+    build_script_contents = """# Autogenerated by Migen
 
 set -e
 
index 4e84329574269032ef7ef00ce46a819f927b6155..a4f211309fc73854edb3ecef883cd6d178cbe97b 100644 (file)
@@ -35,14 +35,13 @@ class LatticeECPXDDROutput:
     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):
@@ -55,15 +54,14 @@ class LatticeECPXPrjTrellisTristateImpl(Module):
                     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
 }
 
@@ -125,7 +123,6 @@ class LatticeiCE40DifferentialOutput:
     def lower(dr):
         return LatticeiCE40DifferentialOutputImpl(dr.i, dr.o_p, dr.o_n)
 
-
 lattice_ice40_special_overrides = {
     AsyncResetSynchronizer: LatticeiCE40AsyncResetSynchronizer,
     Tristate:               LatticeiCE40Tristate,
index 17516aa471805d937dc4ddb3c2c05161e6b3d1d9..1569f56738e8ddd7f89885acd4a1f1fedb1e2293 100644 (file)
@@ -15,13 +15,17 @@ from litex.build import tools
 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):
@@ -48,56 +52,87 @@ def _build_lpf(named_sc, named_pc):
 
 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)
@@ -106,17 +141,18 @@ class LatticeDiamondToolchain:
             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)
 
index f5b3586bf40bb0d3f2dd992240a98e8301488d82..72eb00239b84033eca5c842eed8aa092faea0e75 100644 (file)
@@ -37,11 +37,11 @@ def _build_script(source, build_template, build_name, pnr_pkg_opts,
                   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:
index 385fba5bbe9d9ca8526bb523e160a9941d43c985..0091f97b9d5af735676ea4369f27a3f81bd2da04 100644 (file)
@@ -1,5 +1,5 @@
 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):
@@ -9,8 +9,8 @@ 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()
diff --git a/litex/build/lattice/prjtrellis.py b/litex/build/lattice/prjtrellis.py
deleted file mode 100644 (file)
index 79df493..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-# 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")
diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py
new file mode 100644 (file)
index 0000000..8f27292
--- /dev/null
@@ -0,0 +1,198 @@
+# 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.")
index ef561f4b92d7973b0d9e80630974727b68709495..1b5a6644a7060cc1102c8960c8255c49fdd39e7f 100644 (file)
@@ -88,13 +88,13 @@ def _run_ise(build_name, ise_path, source, mode, ngdbuild_opt,
         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")
index a1f94d9fb3a767dd71faf579c5f84f67a173bc07..4859c149c35e8dc7f4ff182d3a5df193219fc2d0 100644 (file)
@@ -56,13 +56,13 @@ def _build_xdc(named_sc, named_pc):
 
 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"