[dv/common] VCS UNR flow

Set up VCS UNR flow. For detail refer to [slides](https://docs.google.com/presentation/d/13FwwSeBaxtHZkLMmW3TI0YGO93_BTPZZFnIpX2kQhHI/edit#slide=id.ga3bb534d6e_0_57)

Remaining TODO
1. Some module doesn’t use tb.dut as dut hierarchy, may need separate
cfg file
2. Make sure all IPs pass with UNR flow (need solution for issue 3)
3. Document the flow

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/tools/dvsim/common_sim_cfg.hjson b/hw/dv/tools/dvsim/common_sim_cfg.hjson
index 002fa57..bcc7e0c 100644
--- a/hw/dv/tools/dvsim/common_sim_cfg.hjson
+++ b/hw/dv/tools/dvsim/common_sim_cfg.hjson
@@ -71,6 +71,7 @@
 
   // Default list of things to export to shell
   exports: [
+    { SCRATCH_BASE_PATH: "{scratch_base_path}" },
     { TOOL_SRCS_DIR: "{tool_srcs_dir}" },
     { SIMULATOR: "{tool}" },
     { WAVES: "{waves}" },
@@ -138,6 +139,7 @@
 
   // Project defaults for VCS
   vcs_cov_cfg_file: "{{build_mode}_vcs_cov_cfg_file}"
+  vcs_unr_cfg_file: "{tool_srcs_dir}/unr.cfg"
   vcs_cov_excl_files: ["{tool_srcs_dir}/common_cov_excl.el"]
 
   // Build-specific coverage cfg files for VCS.
diff --git a/hw/dv/tools/dvsim/sim.mk b/hw/dv/tools/dvsim/sim.mk
index 341e966..adceb0b 100644
--- a/hw/dv/tools/dvsim/sim.mk
+++ b/hw/dv/tools/dvsim/sim.mk
@@ -115,6 +115,14 @@
 ############################
 ## coverage rated targets ##
 ############################
+cov_unr_build: gen_sv_flist
+	@echo "[make]: cov_unr_build"
+	cd ${sv_flist_gen_dir} && ${cov_unr_build_cmd} ${cov_unr_build_opts}
+
+cov_unr: cov_unr_build
+	@echo "[make]: cov_unr"
+	cd ${sv_flist_gen_dir} && ${cov_unr_run_cmd} ${cov_unr_run_opts}
+
 # Merge coverage if there are multiple builds.
 cov_merge:
 	@echo "[make]: cov_merge"
diff --git a/hw/dv/tools/dvsim/vcs.hjson b/hw/dv/tools/dvsim/vcs.hjson
index 812eae8..c5d86de 100644
--- a/hw/dv/tools/dvsim/vcs.hjson
+++ b/hw/dv/tools/dvsim/vcs.hjson
@@ -152,6 +152,40 @@
   cov_report_txt:       "{cov_report_dir}/dashboard.txt"
   cov_report_page:      "dashboard.html"
 
+  // UNR related.
+  // All code coverage, assert isn't supported
+  cov_unr_metrics: "line+cond+fsm+tgl+branch"
+  cov_unr_dir:     "{scratch_base_path}/cov_unr"
+
+  cov_unr_common_build_opts: ["-sverilog -full64 -licqueue -ntb_opts uvm-1.2",
+                              "-timescale=1ns/1ps"]
+
+  // Use recommended UUM (Unified usage model) 3 steps flow. The other flow defines macro
+  // "SYNTHESIS", which we have used in design
+  cov_unr_build_cmd: [// Step 1
+                      "{job_prefix} vlogan {cov_unr_common_build_opts} &&",
+                      // Step 2
+                      "{job_prefix} vlogan {cov_unr_common_build_opts}",
+                      // grep all defines from {build_opts} from step 2
+                      '''{eval_cmd} opts=`echo {build_opts}`; defines=; d=; \
+                      for o in $opts; \
+                      do \
+                        d=`echo $o | grep -o '+define+.*'`; \
+                        defines="$defines $d"; \
+                      done; \
+                      echo $defines
+                      ''',
+                      "-f {sv_flist} &&",
+                      // Step 3
+                      "{job_prefix} vcs {cov_unr_common_build_opts}"]
+  cov_unr_build_opts: ["-cm {cov_unr_metrics}",
+                       "{vcs_cov_cfg_file}",
+                       "-unr={vcs_unr_cfg_file}",
+                       "{dut}"]
+
+  cov_unr_run_cmd:   ["{job_prefix} ./unrSimv"]
+  cov_unr_run_opts:  ["-unr"]
+
   // Analyzing coverage - this is done by invoking --cov-analyze switch. It opens up the
   // GUI for visual analysis.
   cov_analyze_dir:  "{scratch_base_path}/cov_analyze"
diff --git a/hw/dv/tools/vcs/unr.cfg b/hw/dv/tools/vcs/unr.cfg
new file mode 100644
index 0000000..1a6711a
--- /dev/null
+++ b/hw/dv/tools/vcs/unr.cfg
@@ -0,0 +1,23 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+-covInput $SCRATCH_BASE_PATH/cov_merge/merged.vdb
+-covDUT $dut_instance
+
+# Provide the clock specification
+-clock clk 100
+# Provide the reset specification: signal_name, active_value, num clk cycles reset to be active
+-reset rst_n 0 20
+
+# Black box some of the modules
+# -blackBoxes -type design *
+
+# Include common el file, so that it doesn't generate reviewed common exclusions
+-covEL $TOOL_SRCS_DIR/common_cov_excl.el
+
+# Name of the generated exclusion file
+-save_exclusion $SCRATCH_BASE_PATH/cov_unr/unr_exclude.el
+
+# Enables verbose reporting in addition to summary reporting.
+-verboseReport
diff --git a/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson b/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
index aab05cf..82ebe0c 100644
--- a/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
+++ b/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
@@ -6,7 +6,7 @@
   name: flash_ctrl
 
   // Top level dut name (sv module).
-  dut: flash_ctrl
+  dut: flash_ctrl_wrapper
 
   // Top level testbench name (sv module).
   tb: tb
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index 95bdc4b..b4aae3f 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -6,7 +6,7 @@
   name: chip
 
   // Top level dut name (sv module).
-  dut: top_earlgrey
+  dut: top_earlgrey_asic
 
   // Top level testbench name (sv module).
   tb: tb
diff --git a/util/dvsim/Deploy.py b/util/dvsim/Deploy.py
index 6cd7eec..91e3ec0 100644
--- a/util/dvsim/Deploy.py
+++ b/util/dvsim/Deploy.py
@@ -843,6 +843,55 @@
         return RunTest.seeds.pop(0)
 
 
+class CovUnr(Deploy):
+    """
+    Abstraction for coverage UNR flow.
+    """
+
+    # Register all builds with the class
+    items = []
+
+    def __init__(self, sim_cfg):
+        # Initialize common vars.
+        super().__init__(sim_cfg)
+
+        self.target = "cov_unr"
+        self.mandatory_cmd_attrs.update({
+            # tool srcs
+            "tool_srcs": False,
+            "tool_srcs_dir": False,
+
+            # Need to generate filelist based on build mode
+            "sv_flist_gen_cmd": False,
+            "sv_flist_gen_dir": False,
+            "sv_flist_gen_opts": False,
+            "build_dir": False,
+            "cov_unr_build_cmd": False,
+            "cov_unr_build_opts": False,
+            "cov_unr_run_cmd": False,
+            "cov_unr_run_opts": False
+        })
+
+        self.mandatory_misc_attrs.update({
+            "cov_unr_dir": False,
+            "build_fail_patterns": False
+        })
+
+        super().parse_dict(sim_cfg.__dict__)
+        self.__post_init__()
+
+        self.pass_patterns = []
+        # Reuse fail_patterns from sim build
+        self.fail_patterns = self.build_fail_patterns
+
+        # Start fail message construction
+        self.fail_msg = "\n**COV_UNR:** {}<br>\n".format(self.name)
+        log_sub_path = self.log.replace(self.sim_cfg.scratch_path + '/', '')
+        self.fail_msg += "**LOG:** $scratch_path/{}<br>\n".format(log_sub_path)
+
+        CovUnr.items.append(self)
+
+
 class CovMerge(Deploy):
     """
     Abstraction for merging coverage databases. An item of this class is created AFTER
diff --git a/util/dvsim/SimCfg.py b/util/dvsim/SimCfg.py
index 05b571e..238359d 100644
--- a/util/dvsim/SimCfg.py
+++ b/util/dvsim/SimCfg.py
@@ -12,13 +12,15 @@
 import sys
 from collections import OrderedDict
 
-from Deploy import CompileSim, CovAnalyze, CovMerge, CovReport, Deploy, RunTest
+from Deploy import (CompileSim, CovAnalyze, CovMerge, CovReport, CovUnr,
+                    Deploy, RunTest)
 from FlowCfg import FlowCfg
 from Modes import BuildModes, Modes, Regressions, RunModes, Tests
 from tabulate import tabulate
-from testplanner import class_defs, testplan_utils
 from utils import VERBOSE, find_and_substitute_wildcards
 
+from testplanner import class_defs, testplan_utils
+
 
 def pick_wave_format(fmts):
     '''Pick a supported wave format from a list.
@@ -508,8 +510,6 @@
         if self.cov:
             self.cov_merge_deploy = CovMerge(self)
             self.cov_report_deploy = CovReport(self)
-            # Generate reports only if merge was successful; add it as a dependency
-            # of merge.
             self.cov_merge_deploy.sub.append(self.cov_report_deploy)
 
         # Create initial set of directories before kicking off the regression.
@@ -542,6 +542,9 @@
         '''Use the last regression coverage data to open up the GUI tool to
         analyze the coverage.
         '''
+        # Create initial set of directories, such as dispatched, passed etc.
+        self._create_dirs()
+
         cov_analyze_deploy = CovAnalyze(self)
         self.deploy = [cov_analyze_deploy]
 
@@ -551,6 +554,26 @@
         for item in self.cfgs:
             item._cov_analyze()
 
+    def _cov_unr(self):
+        '''Use the last regression coverage data to generate unreachable
+        coverage exclusions.
+        '''
+        # TODO, Only support VCS
+        if self.tool != 'vcs':
+            log.error("Currently only support VCS for coverage UNR")
+            sys.exit(1)
+        # Create initial set of directories, such as dispatched, passed etc.
+        self._create_dirs()
+
+        cov_unr_deploy = CovUnr(self)
+        self.deploy = [cov_unr_deploy]
+
+    def cov_unr(self):
+        '''Public facing API for analyzing coverage.
+        '''
+        for item in self.cfgs:
+            item._cov_unr()
+
     def _gen_results(self):
         '''
         The function is called after the regression has completed. It collates the
diff --git a/util/dvsim/dvsim.py b/util/dvsim/dvsim.py
index 53ccc62..f4bef41 100755
--- a/util/dvsim/dvsim.py
+++ b/util/dvsim/dvsim.py
@@ -441,6 +441,11 @@
                             'coverage database directory with the new '
                             'coverage database.'))
 
+    covg.add_argument("--cov-unr",
+                      action='store_true',
+                      help=('Run coverage UNR analysis and generate report. '
+                            'This only supports VCS now.'))
+
     covg.add_argument("--cov-analyze",
                       action='store_true',
                       help=('Rather than building or running any tests, '
@@ -572,6 +577,17 @@
         cfg.print_list()
         sys.exit(0)
 
+    # Purge the scratch path if --purge option is set.
+    if args.purge:
+        cfg.purge()
+
+    # If --cov-unr is passed, run UNR to generate report for unreachable
+    # exclusion file.
+    if args.cov_unr:
+        cfg.cov_unr()
+        cfg.deploy_objects()
+        sys.exit(0)
+
     # In simulation mode: if --cov-analyze switch is passed, then run the GUI
     # tool.
     if args.cov_analyze:
@@ -579,10 +595,6 @@
         cfg.deploy_objects()
         sys.exit(0)
 
-    # Purge the scratch path if --purge option is set.
-    if args.purge:
-        cfg.purge()
-
     # Deploy the builds and runs
     if args.items != []:
         # Create deploy objects.