Check for supported tool versions
Define supported tool versions in tool_requirements.py, and check them
in a fusesoc run. If an unsupported tool version is found, fusesoc
outputs an error like this:
```
$ fusesoc --cores-root ../../ run --target=lint lowrisc:ip:aes
INFO: Preparing lowrisc:constants:top_pkg:0
INFO: Preparing lowrisc:lint:comportable:0.1
...
INFO: Preparing lowrisc:tool:check_tool_requirements:0.1
INFO: Preparing lowrisc:lint:common:0.1
...
INFO: Preparing lowrisc:ip:aes:0.5
ERROR: verilator is too old: found version 4.016, need at least 4.028
ERROR: Tool requirements not fulfilled. Please update the tools and retry.
ERROR: Failed to build lowrisc:ip:aes:0.5 : pre_build script \
'check_tool_requirements' exited with error code 1
```
The only version checked at this point is Verilator, which is set to
version 4.028, the first version to support wildcard matching for
`lint_off` rules.
The whole infrastructure has been created by @imphil in the Ibex
repository (see lowRISC/Ibex#604). This commit just copies the
framework over to OpenTitan.
Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/check_tool_requirements.core b/check_tool_requirements.core
new file mode 100644
index 0000000..375970c
--- /dev/null
+++ b/check_tool_requirements.core
@@ -0,0 +1,31 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:tool:check_tool_requirements:0.1"
+description: "Check tool requirements"
+
+filesets:
+ files_check_tool_requirements:
+ files:
+ - ./util/check_tool_requirements.py : { copyto: util/check_tool_requirements.py }
+ - ./tool_requirements.py : { copyto: tool_requirements.py }
+
+scripts:
+ check_tool_requirements:
+ cmd:
+ - python3
+ - util/check_tool_requirements.py
+ # TODO: Use this syntax once https://github.com/olofk/fusesoc/issues/353 is
+ # fixed. Remove the filesets from the default target, and also remove the
+ # copyto.
+ #filesets:
+ # - files_check_tool_requirements
+
+targets:
+ default:
+ filesets:
+ - files_check_tool_requirements
+ hooks:
+ pre_build:
+ - tool_verilator ? (check_tool_requirements)
diff --git a/hw/lint/common.core b/hw/lint/common.core
index 64e323c..f7ce7f7 100644
--- a/hw/lint/common.core
+++ b/hw/lint/common.core
@@ -15,10 +15,13 @@
- tools/ascentlint/common.waiver: {file_type: waiver}
- tools/ascentlint/ascentlint-config.tcl: {file_type: tclSource}
+ files_check_tool_requirements:
+ depend:
+ - lowrisc:tool:check_tool_requirements
+
targets:
default: &default_target
filesets:
- tool_verilator ? (files_verilator)
- tool_ascentlint ? (files_ascentlint)
-
-
+ - files_check_tool_requirements
diff --git a/tool_requirements.py b/tool_requirements.py
new file mode 100644
index 0000000..7777c6e
--- /dev/null
+++ b/tool_requirements.py
@@ -0,0 +1,9 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Version requirements for various tools. Checked by tooling (e.g. fusesoc),
+# and inserted into the documentation.
+__TOOL_REQUIREMENTS__ = {
+ 'verilator': '4.028',
+}
diff --git a/util/check_tool_requirements.py b/util/check_tool_requirements.py
new file mode 100755
index 0000000..5a59d4c
--- /dev/null
+++ b/util/check_tool_requirements.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+from distutils.version import StrictVersion
+import logging as log
+import os
+import subprocess
+import sys
+
+# Display INFO log messages and up.
+log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
+
+# Populate __TOOL_REQUIREMENTS__
+topsrcdir = os.path.join(os.path.dirname(__file__), '..')
+exec(open(os.path.join(topsrcdir, 'tool_requirements.py')).read())
+
+def get_verilator_version():
+ try:
+ # Note: "verilator" needs to be called through a shell and with all
+ # arguments in a string, as it doesn't have a shebang, but instead
+ # relies on perl magic to parse command line arguments.
+ version_str = subprocess.run('verilator --version', shell=True,
+ check=True, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
+ return version_str.stdout.split(' ')[1].strip()
+
+ except subprocess.CalledProcessError as e:
+ log.error("Unable to call Verilator to check version: " + str(e))
+ log.error(e.stdout)
+ return None
+
+def check_version(tool_name, required_version, actual_version):
+ if required_version is None or actual_version is None:
+ return False
+
+ if StrictVersion(actual_version) < StrictVersion(required_version):
+ log.error("%s is too old: found version %s, need at least %s",
+ tool_name, actual_version, required_version)
+ return False
+ else:
+ log.info("Found sufficiently recent version of %s (found %s, need %s)",
+ tool_name, actual_version, required_version)
+ return True
+
+
+def main():
+ any_failed = False
+
+ if not check_version('verilator', __TOOL_REQUIREMENTS__['verilator'],
+ get_verilator_version()):
+ any_failed = True
+
+ if any_failed:
+ log.error("Tool requirements not fulfilled. "
+ "Please update the tools and retry.")
+ return 1
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())