[dv. tool] Add fusesoc generator for CSR asserts

Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/formal/tools/csr_assert_gen/csr_assert_gen.core b/hw/formal/tools/csr_assert_gen/csr_assert_gen.core
new file mode 100644
index 0000000..25f470f
--- /dev/null
+++ b/hw/formal/tools/csr_assert_gen/csr_assert_gen.core
@@ -0,0 +1,11 @@
+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:fpv:csr_assert_gen"
+description: "Generator for CSR assertion check module used in FPV and DV testbenches."
+generators:
+  csr_assert_gen:
+    interpreter: python3
+    command: csr_assert_gen.py
diff --git a/hw/formal/tools/csr_assert_gen/csr_assert_gen.py b/hw/formal/tools/csr_assert_gen/csr_assert_gen.py
new file mode 100644
index 0000000..e6045c7
--- /dev/null
+++ b/hw/formal/tools/csr_assert_gen/csr_assert_gen.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+r"""FuseSoc generator for creating the CSR assert file using regtool.py, used
+in DV and FPV testbenches.
+"""
+import os
+import subprocess
+import sys
+
+import yaml
+
+try:
+    from yaml import CSafeLoader as YamlLoader
+except ImportError:
+    from yaml import SafeLoader as YamlLoader
+
+# Repo root is 4 levels up. Note that this will require an update if the path to
+# this tool is changed.
+REPO_ROOT = "../../../.."
+
+
+def main():
+    if len(sys.argv) != 2:
+        print("ERROR: This script takes a single YAML file as input argument")
+        sys.exit(1)
+
+    gapi_filepath = sys.argv[1]
+    gapi = yaml.load(open(gapi_filepath), Loader=YamlLoader)
+
+    # This is just a wrapper around regtool.py from proj_root/util area.
+    self_path = os.path.dirname(os.path.realpath(__file__))
+    util_path = os.path.abspath(os.path.join(self_path, REPO_ROOT, "util"))
+
+    # Retrieve the parameters from the yml.
+    files_root_dir = gapi['files_root']
+    spec = gapi['parameters'].get('spec')
+    name = os.path.basename(spec).replace(".hjson", "")
+    depend = gapi['parameters'].get('depend') or "lowrisc:ip:{}".format(name)
+
+    if not name or not spec:
+        print("Error: \"spec\" parameter missing or invalid: {}".format(spec))
+        sys.exit(1)
+
+    # Generate the CSR assert file.
+    csr_assert_file = name + "_csr_assert_fpv.sv"
+
+    # Convert spec (partial path relative to `files_root_dir`) into absolute
+    # path so that we can pass it to `regtool.py`.
+    spec = os.path.abspath(os.path.join(files_root_dir, spec))
+    if not os.path.exists(spec):
+        print("Error: spec path appears to be invalid: {}".format(spec))
+        sys.exit(1)
+
+    cmd = os.path.join(util_path, "regtool.py")
+    args = [cmd, "-f", "-t", ".", spec]
+
+    try:
+        subprocess.run(args, check=True)
+    except subprocess.CalledProcessError as e:
+        print("Error: CSR assert gen failed:\n{}".format(str(e)))
+        sys.exit(e.returncode)
+    print("CSR assert file written to {}".format(
+        os.path.abspath(csr_assert_file)))
+
+    # Generate the FuseSoc core file.
+    csr_assert_core_text = {
+        'name': "lowrisc:fpv:{}_csr_assert".format(name),
+        'filesets': {
+            'files_dv': {
+                'depend': [
+                    depend,
+                    "lowrisc:tlul:headers",
+                    "lowrisc:prim:assert",
+                ],
+                'files': [
+                    csr_assert_file,
+                ],
+                'file_type': 'systemVerilogSource'
+            },
+        },
+        'targets': {
+            'default': {
+                'filesets': [
+                    'files_dv',
+                ],
+            },
+        },
+    }
+    csr_assert_core_file = os.path.abspath(name + "_csr_assert_fpv.core")
+    with open(csr_assert_core_file, 'w') as f:
+        f.write("CAPI=2:\n")
+        yaml.dump(csr_assert_core_text,
+                  f,
+                  encoding="utf-8",
+                  default_flow_style=False,
+                  sort_keys=False)
+    print("CSR assert core file written to {}".format(csr_assert_core_file))
+
+
+if __name__ == '__main__':
+    main()