From bddec3741e1dc2cba856850e23fbbcaddcd5e40e Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 11 Jun 2020 16:12:52 +0000 Subject: [PATCH] _yosys: translate Yosys warnings to Python warnings. This isn't used yet (the only Yosys warning we can get is useless), but will be handy for CXXRTL. --- nmigen/_yosys.py | 29 +++++++++++++++++++---------- nmigen/back/verilog.py | 6 +++++- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/nmigen/_yosys.py b/nmigen/_yosys.py index 913d5cc..dcade81 100644 --- a/nmigen/_yosys.py +++ b/nmigen/_yosys.py @@ -2,6 +2,7 @@ import os import sys import re import subprocess +import warnings try: from importlib import metadata as importlib_metadata # py3.8+ stdlib except ImportError: @@ -20,6 +21,10 @@ class YosysError(Exception): pass +class YosysWarning(Warning): + pass + + class YosysBinary: @classmethod def available(cls): @@ -72,6 +77,16 @@ class YosysBinary: """ 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" @@ -93,15 +108,12 @@ class _BuiltinYosys(YosysBinary): return (int(match[1]), int(match[2]), int(match[3] or 0)) @classmethod - def run(cls, args, stdin=""): + 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) - if popen.returncode: - raise YosysError(stderr.strip()) - else: - return stdout + return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at) class _SystemYosys(YosysBinary): @@ -118,7 +130,7 @@ class _SystemYosys(YosysBinary): return (int(match[1]), int(match[2]), int(match[3] or 0)) @classmethod - def run(cls, args, stdin=""): + 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") @@ -129,10 +141,7 @@ class _SystemYosys(YosysBinary): # # This is not ideal, but Verific license conditions rule out any other solution. stdout = re.sub(r"\A(-- .+\n|\n)*", "", stdout) - if popen.returncode: - raise YosysError(stderr.strip()) - else: - return stdout + return cls._process_result(popen.returncode, stdout, stderr, ignore_warnings, src_loc_at) def find_yosys(requirement): diff --git a/nmigen/back/verilog.py b/nmigen/back/verilog.py index 19a91e4..cb684ab 100644 --- a/nmigen/back/verilog.py +++ b/nmigen/back/verilog.py @@ -38,7 +38,11 @@ write_verilog -norename {write_verilog_opts} prune="# " if yosys_version < (0, 9, 231) else "", attr_map=" ".join(attr_map), write_verilog_opts=" ".join(write_verilog_opts), - )) + ), + # At the moment, Yosys always shows a warning indicating that not all processes can be + # translated to Verilog. We carefully emit only the processes that *can* be translated, and + # squash this warning. Once Yosys' write_verilog pass is fixed, we should remove this. + ignore_warnings=True) def convert_fragment(*args, strip_internal_attrs=False, **kwargs): -- 2.30.2