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/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())