diff --git a/migen/build/lattice/diamond.py b/migen/build/lattice/diamond.py index afc6cc41e..7a134cb66 100644 --- a/migen/build/lattice/diamond.py +++ b/migen/build/lattice/diamond.py @@ -14,6 +14,24 @@ from migen.build.lattice import common +def _get_bindir(path, ver=None): + if ver is None: + # _x64 suffix means StrictVersion will fail. + vers = list(tools.versions(path, strict=False)) + if not vers: + raise OSError("no version directory for Diamond tools found in " + + path) + ver = max(vers) + + # Lattice does not provide 32-bit binaries anymore. + if sys.platform in ("win32", "cygwin"): + bin_suffix = "nt64" + else: + bin_suffix = "lin64" + + return os.path.join(path, str(ver), "bin", bin_suffix) + + def _produces_jedec(device): return device.startswith("LCMX") @@ -68,7 +86,7 @@ def _build_files(device, sources, vincpaths, build_name): tools.write_to_file(build_name + ".tcl", "\n".join(tcl)) -def _build_script(build_name, device, toolchain_path, ver=None): +def _build_script(build_name, device, toolchain_path, source, ver=None): if sys.platform in ("win32", "cygwin"): script_ext = ".bat" build_script_contents = "@echo off\nrem Autogenerated by Migen\n\n" @@ -80,22 +98,36 @@ def _build_script(build_name, device, toolchain_path, ver=None): 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"), + bindir = _get_bindir(toolchain_path, ver) + if source: + if sys.platform in ("win32", "cygwin"): + build_script_contents += "set PATH={};%PATH%\n".format(bindir) + else: + build_script_contents += "bindir={}\n".format(bindir) + build_script_contents += ". ${{bindir}}/diamond_env{fail_stmt}\n".format( + fail_stmt=fail_stmt) + + build_script_contents += "pnmainc {tcl_script}{fail_stmt}\n".format( tcl_script=build_name + ".tcl", fail_stmt=fail_stmt) for ext in (".bit", ".jed"): if ext == ".jed" and not _produces_jedec(device): continue + + diamond_product = os.path.join("impl", build_name + "_impl" + ext) + if sys.platform in ("win32", "cygwin"): + # While Windows itself has no problems with forward slashes + # in paths, the COPY command on Windows uses forward slash for + # arguments. MinGW Python 3 may (it is not consistent) create + # paths with forward slashes on Windows, so remove them just in + # case. + diamond_product = diamond_product.replace("/", "\\") + 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), + diamond_product=diamond_product, migen_product=build_name + ext) build_script_file = "build_" + build_name + script_ext @@ -131,9 +163,15 @@ class LatticeDiamondToolchain: special_overrides = common.lattice_ecpx_special_overrides def build(self, platform, fragment, build_dir="build", build_name="top", - toolchain_path=None, run=True, **kwargs): + toolchain_path=None, source=True, run=True, ver=None, **kwargs): if toolchain_path is None: - toolchain_path = "/opt/Diamond" + if sys.platform == "win32": + toolchain_path = "C:\\lscc\\diamond" + elif sys.platform == "cygwin": + toolchain_path = "/cygdrive/c/lscc/diamond" + else: + toolchain_path = "/usr/local/diamond" + os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() os.chdir(build_dir) @@ -151,7 +189,8 @@ def build(self, platform, fragment, build_dir="build", build_name="top", tools.write_to_file(build_name + ".lpf", _build_lpf(named_sc, named_pc)) - script = _build_script(build_name, platform.device, toolchain_path) + script = _build_script(build_name, platform.device, toolchain_path, + source, ver) if run: _run_script(script) diff --git a/migen/build/tools.py b/migen/build/tools.py index 313abaea4..16d6fe866 100644 --- a/migen/build/tools.py +++ b/migen/build/tools.py @@ -1,6 +1,6 @@ import os import struct -from distutils.version import StrictVersion +from distutils.version import StrictVersion, LooseVersion import re import subprocess import sys @@ -28,13 +28,16 @@ def arch_bits(): return struct.calcsize("P")*8 -def versions(path): +def versions(path, strict=True): for n in os.listdir(path): full = os.path.join(path, n) if not os.path.isdir(full): continue try: - yield StrictVersion(n) + if strict: + yield StrictVersion(n) + else: + yield LooseVersion(n) except ValueError: continue