_yosys→_toolchain.yosys
authorwhitequark <whitequark@whitequark.org>
Thu, 2 Jul 2020 18:26:08 +0000 (18:26 +0000)
committerwhitequark <whitequark@whitequark.org>
Thu, 2 Jul 2020 18:26:08 +0000 (18:26 +0000)
nmigen/_toolchain.py [deleted file]
nmigen/_toolchain/__init__.py [new file with mode: 0644]
nmigen/_toolchain/yosys.py [new file with mode: 0644]
nmigen/_yosys.py [deleted file]
nmigen/back/cxxrtl.py
nmigen/back/verilog.py

diff --git a/nmigen/_toolchain.py b/nmigen/_toolchain.py
deleted file mode 100644 (file)
index fca2bac..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-import os
-import shutil
-
-
-__all__ = ["ToolNotFound", "tool_env_var", "has_tool", "require_tool"]
-
-
-class ToolNotFound(Exception):
-    pass
-
-
-def tool_env_var(name):
-    return name.upper().replace("-", "_")
-
-
-def _get_tool(name):
-    return os.environ.get(tool_env_var(name), name)
-
-
-def has_tool(name):
-    return shutil.which(_get_tool(name)) is not None
-
-
-def require_tool(name):
-    env_var = tool_env_var(name)
-    path = _get_tool(name)
-    if shutil.which(path) is None:
-        if env_var in os.environ:
-            raise ToolNotFound("Could not find required tool {} in {} as "
-                               "specified via the {} environment variable".
-                               format(name, path, env_var))
-        else:
-            raise ToolNotFound("Could not find required tool {} in PATH. Place "
-                               "it directly in PATH or specify path explicitly "
-                               "via the {} environment variable".
-                               format(name, env_var))
-    return path
diff --git a/nmigen/_toolchain/__init__.py b/nmigen/_toolchain/__init__.py
new file mode 100644 (file)
index 0000000..fca2bac
--- /dev/null
@@ -0,0 +1,37 @@
+import os
+import shutil
+
+
+__all__ = ["ToolNotFound", "tool_env_var", "has_tool", "require_tool"]
+
+
+class ToolNotFound(Exception):
+    pass
+
+
+def tool_env_var(name):
+    return name.upper().replace("-", "_")
+
+
+def _get_tool(name):
+    return os.environ.get(tool_env_var(name), name)
+
+
+def has_tool(name):
+    return shutil.which(_get_tool(name)) is not None
+
+
+def require_tool(name):
+    env_var = tool_env_var(name)
+    path = _get_tool(name)
+    if shutil.which(path) is None:
+        if env_var in os.environ:
+            raise ToolNotFound("Could not find required tool {} in {} as "
+                               "specified via the {} environment variable".
+                               format(name, path, env_var))
+        else:
+            raise ToolNotFound("Could not find required tool {} in PATH. Place "
+                               "it directly in PATH or specify path explicitly "
+                               "via the {} environment variable".
+                               format(name, env_var))
+    return path
diff --git a/nmigen/_toolchain/yosys.py b/nmigen/_toolchain/yosys.py
new file mode 100644 (file)
index 0000000..c223306
--- /dev/null
@@ -0,0 +1,229 @@
+import os
+import sys
+import re
+import subprocess
+import warnings
+import pathlib
+try:
+    from importlib import metadata as importlib_metadata # py3.8+ stdlib
+except ImportError:
+    try:
+        import importlib_metadata # py3.7- shim
+    except ImportError:
+        importlib_metadata = None # not installed
+try:
+    try:
+        from importlib import resources as importlib_resources
+        try:
+            importlib_resources.files # py3.9+ stdlib
+        except AttributeError:
+            import importlib_resources # py3.8- shim
+    except ImportError:
+        import importlib_resources # py3.6- shim
+except ImportError:
+    importlib_resources = None
+
+from . import has_tool, require_tool
+
+
+__all__ = ["YosysError", "YosysBinary", "find_yosys"]
+
+
+class YosysError(Exception):
+    pass
+
+
+class YosysWarning(Warning):
+    pass
+
+
+class YosysBinary:
+    @classmethod
+    def available(cls):
+        """Check for Yosys availability.
+
+        Returns
+        -------
+        available : bool
+            ``True`` if Yosys is installed, ``False`` otherwise. Installed binary may still not
+            be runnable, or might be too old to be useful.
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def version(cls):
+        """Get Yosys version.
+
+        Returns
+        -------
+        ``None`` if version number could not be determined, or a 3-tuple ``(major, minor, distance)`` if it could.
+
+        major : int
+            Major version.
+        minor : int
+            Minor version.
+        distance : int
+            Distance to last tag per ``git describe``. May not be exact for system Yosys.
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def data_dir(cls):
+        """Get Yosys data directory.
+
+        Returns
+        -------
+        data_dir : pathlib.Path
+            Yosys data directory (also known as "datdir").
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def run(cls, args, stdin=""):
+        """Run Yosys process.
+
+        Parameters
+        ----------
+        args : list of str
+            Arguments, not including the program name.
+        stdin : str
+            Standard input.
+
+        Returns
+        -------
+        stdout : str
+            Standard output.
+
+        Exceptions
+        ----------
+        YosysError
+            Raised if Yosys returns a non-zero code. The exception message is the standard error
+            output.
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def _process_result(cls, returncode, stdout, stderr, ignore_warnings, src_loc_at):
+        if returncode:
+            raise YosysError(stderr.strip())
+        if not ignore_warnings:
+            for match in re.finditer(r"(?ms:^Warning: (.+)\n$)", stderr):
+                message = match.group(1).replace("\n", " ")
+                warnings.warn(message, YosysWarning, stacklevel=3 + src_loc_at)
+        return stdout
+
+
+class _BuiltinYosys(YosysBinary):
+    YOSYS_PACKAGE = "nmigen_yosys"
+
+    @classmethod
+    def available(cls):
+        if importlib_metadata is None or importlib_resources is None:
+            return False
+        try:
+            importlib_metadata.version(cls.YOSYS_PACKAGE)
+            return True
+        except importlib_metadata.PackageNotFoundError:
+            return False
+
+    @classmethod
+    def version(cls):
+        version = importlib_metadata.version(cls.YOSYS_PACKAGE)
+        match = re.match(r"^(\d+)\.(\d+)(?:\.post(\d+))?", version)
+        return (int(match[1]), int(match[2]), int(match[3] or 0))
+
+    @classmethod
+    def data_dir(cls):
+        return importlib_resources.files(cls.YOSYS_PACKAGE) / "share"
+
+    @classmethod
+    def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
+        popen = subprocess.Popen([sys.executable, "-m", cls.YOSYS_PACKAGE, *args],
+            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            encoding="utf-8")
+        stdout, stderr = popen.communicate(stdin)
+        return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
+
+
+class _SystemYosys(YosysBinary):
+    YOSYS_BINARY = "yosys"
+
+    @classmethod
+    def available(cls):
+        return has_tool(cls.YOSYS_BINARY)
+
+    @classmethod
+    def version(cls):
+        version = cls.run(["-V"])
+        match = re.match(r"^Yosys (\d+)\.(\d+)(?:\+(\d+))?", version)
+        if match:
+            return (int(match[1]), int(match[2]), int(match[3] or 0))
+        else:
+            return None
+
+    @classmethod
+    def data_dir(cls):
+        popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY) + "-config", "--datdir"],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            encoding="utf-8")
+        stdout, stderr = popen.communicate()
+        if popen.returncode:
+            raise YosysError(stderr.strip())
+        return pathlib.Path(stdout.strip())
+
+    @classmethod
+    def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
+        popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY), *args],
+            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            encoding="utf-8")
+        stdout, stderr = popen.communicate(stdin)
+        # If Yosys is built with an evaluation version of Verific, then Verific license
+        # information is printed first. It consists of empty lines and lines starting with `--`,
+        # which are not normally a part of Yosys output, and can be fairly safely removed.
+        #
+        # This is not ideal, but Verific license conditions rule out any other solution.
+        stdout = re.sub(r"\A(-- .+\n|\n)*", "", stdout)
+        return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
+
+
+def find_yosys(requirement):
+    """Find an available Yosys executable of required version.
+
+    Parameters
+    ----------
+    requirement : function
+        Version check. Should return ``True`` if the version is acceptable, ``False`` otherwise.
+
+    Returns
+    -------
+    yosys_binary : subclass of YosysBinary
+        Proxy for running the requested version of Yosys.
+
+    Exceptions
+    ----------
+    YosysError
+        Raised if required Yosys version is not found.
+    """
+    proxies = []
+    clauses = os.environ.get("NMIGEN_USE_YOSYS", "system,builtin").split(",")
+    for clause in clauses:
+        if clause == "builtin":
+            proxies.append(_BuiltinYosys)
+        elif clause == "system":
+            proxies.append(_SystemYosys)
+        else:
+            raise YosysError("The NMIGEN_USE_YOSYS environment variable contains "
+                             "an unrecognized clause {!r}"
+                             .format(clause))
+    for proxy in proxies:
+        if proxy.available():
+            version = proxy.version()
+            if version is not None and requirement(version):
+                return proxy
+    else:
+        if "NMIGEN_USE_YOSYS" in os.environ:
+            raise YosysError("Could not find an acceptable Yosys binary. Searched: {}"
+                             .format(", ".join(clauses)))
+        else:
+            raise YosysError("Could not find an acceptable Yosys binary. The `nmigen-yosys` PyPI "
+                             "package, if available for this platform, can be used as fallback")
diff --git a/nmigen/_yosys.py b/nmigen/_yosys.py
deleted file mode 100644 (file)
index e84da53..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-import os
-import sys
-import re
-import subprocess
-import warnings
-import pathlib
-try:
-    from importlib import metadata as importlib_metadata # py3.8+ stdlib
-except ImportError:
-    try:
-        import importlib_metadata # py3.7- shim
-    except ImportError:
-        importlib_metadata = None # not installed
-try:
-    try:
-        from importlib import resources as importlib_resources
-        try:
-            importlib_resources.files # py3.9+ stdlib
-        except AttributeError:
-            import importlib_resources # py3.8- shim
-    except ImportError:
-        import importlib_resources # py3.6- shim
-except ImportError:
-    importlib_resources = None
-
-from ._toolchain import has_tool, require_tool
-
-
-__all__ = ["YosysError", "YosysBinary", "find_yosys"]
-
-
-class YosysError(Exception):
-    pass
-
-
-class YosysWarning(Warning):
-    pass
-
-
-class YosysBinary:
-    @classmethod
-    def available(cls):
-        """Check for Yosys availability.
-
-        Returns
-        -------
-        available : bool
-            ``True`` if Yosys is installed, ``False`` otherwise. Installed binary may still not
-            be runnable, or might be too old to be useful.
-        """
-        raise NotImplementedError
-
-    @classmethod
-    def version(cls):
-        """Get Yosys version.
-
-        Returns
-        -------
-        ``None`` if version number could not be determined, or a 3-tuple ``(major, minor, distance)`` if it could.
-
-        major : int
-            Major version.
-        minor : int
-            Minor version.
-        distance : int
-            Distance to last tag per ``git describe``. May not be exact for system Yosys.
-        """
-        raise NotImplementedError
-
-    @classmethod
-    def data_dir(cls):
-        """Get Yosys data directory.
-
-        Returns
-        -------
-        data_dir : pathlib.Path
-            Yosys data directory (also known as "datdir").
-        """
-        raise NotImplementedError
-
-    @classmethod
-    def run(cls, args, stdin=""):
-        """Run Yosys process.
-
-        Parameters
-        ----------
-        args : list of str
-            Arguments, not including the program name.
-        stdin : str
-            Standard input.
-
-        Returns
-        -------
-        stdout : str
-            Standard output.
-
-        Exceptions
-        ----------
-        YosysError
-            Raised if Yosys returns a non-zero code. The exception message is the standard error
-            output.
-        """
-        raise NotImplementedError
-
-    @classmethod
-    def _process_result(cls, returncode, stdout, stderr, ignore_warnings, src_loc_at):
-        if returncode:
-            raise YosysError(stderr.strip())
-        if not ignore_warnings:
-            for match in re.finditer(r"(?ms:^Warning: (.+)\n$)", stderr):
-                message = match.group(1).replace("\n", " ")
-                warnings.warn(message, YosysWarning, stacklevel=3 + src_loc_at)
-        return stdout
-
-
-class _BuiltinYosys(YosysBinary):
-    YOSYS_PACKAGE = "nmigen_yosys"
-
-    @classmethod
-    def available(cls):
-        if importlib_metadata is None or importlib_resources is None:
-            return False
-        try:
-            importlib_metadata.version(cls.YOSYS_PACKAGE)
-            return True
-        except importlib_metadata.PackageNotFoundError:
-            return False
-
-    @classmethod
-    def version(cls):
-        version = importlib_metadata.version(cls.YOSYS_PACKAGE)
-        match = re.match(r"^(\d+)\.(\d+)(?:\.post(\d+))?", version)
-        return (int(match[1]), int(match[2]), int(match[3] or 0))
-
-    @classmethod
-    def data_dir(cls):
-        return importlib_resources.files(cls.YOSYS_PACKAGE) / "share"
-
-    @classmethod
-    def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
-        popen = subprocess.Popen([sys.executable, "-m", cls.YOSYS_PACKAGE, *args],
-            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-            encoding="utf-8")
-        stdout, stderr = popen.communicate(stdin)
-        return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
-
-
-class _SystemYosys(YosysBinary):
-    YOSYS_BINARY = "yosys"
-
-    @classmethod
-    def available(cls):
-        return has_tool(cls.YOSYS_BINARY)
-
-    @classmethod
-    def version(cls):
-        version = cls.run(["-V"])
-        match = re.match(r"^Yosys (\d+)\.(\d+)(?:\+(\d+))?", version)
-        if match:
-            return (int(match[1]), int(match[2]), int(match[3] or 0))
-        else:
-            return None
-
-    @classmethod
-    def data_dir(cls):
-        popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY) + "-config", "--datdir"],
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-            encoding="utf-8")
-        stdout, stderr = popen.communicate()
-        if popen.returncode:
-            raise YosysError(stderr.strip())
-        return pathlib.Path(stdout.strip())
-
-    @classmethod
-    def run(cls, args, stdin="", *, ignore_warnings=False, src_loc_at=0):
-        popen = subprocess.Popen([require_tool(cls.YOSYS_BINARY), *args],
-            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-            encoding="utf-8")
-        stdout, stderr = popen.communicate(stdin)
-        # If Yosys is built with an evaluation version of Verific, then Verific license
-        # information is printed first. It consists of empty lines and lines starting with `--`,
-        # which are not normally a part of Yosys output, and can be fairly safely removed.
-        #
-        # This is not ideal, but Verific license conditions rule out any other solution.
-        stdout = re.sub(r"\A(-- .+\n|\n)*", "", stdout)
-        return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at)
-
-
-def find_yosys(requirement):
-    """Find an available Yosys executable of required version.
-
-    Parameters
-    ----------
-    requirement : function
-        Version check. Should return ``True`` if the version is acceptable, ``False`` otherwise.
-
-    Returns
-    -------
-    yosys_binary : subclass of YosysBinary
-        Proxy for running the requested version of Yosys.
-
-    Exceptions
-    ----------
-    YosysError
-        Raised if required Yosys version is not found.
-    """
-    proxies = []
-    clauses = os.environ.get("NMIGEN_USE_YOSYS", "system,builtin").split(",")
-    for clause in clauses:
-        if clause == "builtin":
-            proxies.append(_BuiltinYosys)
-        elif clause == "system":
-            proxies.append(_SystemYosys)
-        else:
-            raise YosysError("The NMIGEN_USE_YOSYS environment variable contains "
-                             "an unrecognized clause {!r}"
-                             .format(clause))
-    for proxy in proxies:
-        if proxy.available():
-            version = proxy.version()
-            if version is not None and requirement(version):
-                return proxy
-    else:
-        if "NMIGEN_USE_YOSYS" in os.environ:
-            raise YosysError("Could not find an acceptable Yosys binary. Searched: {}"
-                             .format(", ".join(clauses)))
-        else:
-            raise YosysError("Could not find an acceptable Yosys binary. The `nmigen-yosys` PyPI "
-                             "package, if available for this platform, can be used as fallback")
index 38cb41b15a2c6f4cacf35f4e18d7ebee974525c0..f7c18ec9fd63d2d5749533b57c5105bfda1c8df3 100644 (file)
@@ -1,4 +1,4 @@
-from .._yosys import *
+from .._toolchain.yosys import *
 from . import rtlil
 
 
index 1d2cb4a52273c4c2fdcf438ddda2e19499fe19ef..31db02bfc75ccf8e97b764c25ebc69df908968a4 100644 (file)
@@ -1,4 +1,4 @@
-from .._yosys import *
+from .._toolchain.yosys import *
 from . import rtlil