[dvsim] Fix for missing coverage

- The while loop in `Deploy.deploy()` method that sequences the deployed
processes had a bug that caused it to exit when there was more work to
be done. I reordered it so that it works correctly now. `cov_report`
should now get dispatched after `cov_merge`.
- This fixes #1792.

- Some minor fixes to the way things are displayed in stdout.

Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/util/dvsim/Deploy.py b/util/dvsim/Deploy.py
index aba91e8..065bfb4 100644
--- a/util/dvsim/Deploy.py
+++ b/util/dvsim/Deploy.py
@@ -311,7 +311,7 @@
     @staticmethod
     def deploy(items):
         dispatched_items = []
-        queued_items = items
+        queued_items = []
 
         if Deploy.print_legend:
             # Print legend once at the start of the run.
@@ -342,7 +342,7 @@
                     log.log(VERBOSE, "[%s]: [%s]: [dispatch]:\n%s",
                             get_etime(), target, item_names[target])
 
-        def track_progress(status, print_status):
+        def track_progress(status, print_status_flag):
             all_done = True
             for target in status.keys():
                 if "target_done" in status[target].keys(): continue
@@ -361,7 +361,7 @@
                     target_done = True
                 all_done &= target_done
 
-                if print_status:
+                if print_status_flag:
                     width = "0{}d".format(len(str(stats["T"])))
                     msg = "["
                     for s in stats.keys():
@@ -373,16 +373,43 @@
 
         all_done = False
         status = {}
+        print_status_flag = True
 
         # Queue all items
+        queued_items.extend(items)
         for item in queued_items:
             if item.target not in status.keys():
                 status[item.target] = {}
             status[item.target][item] = "Q"
 
         while not all_done:
+            # Get status of dispatched items.
+            for item in dispatched_items:
+                if item.status == "D": item.get_status()
+                if item.status != status[item.target][item]:
+                    print_status_flag = True
+                    if item.status != "D":
+                        if item.status != "P":
+                            # Kill its sub items if item did not pass.
+                            item.set_sub_status("K")
+                            log.error("[%s]: [%s]: [status] [%s: %s]",
+                                      get_etime(), item.target,
+                                      item.identifier, item.status)
+                        else:
+                            log.log(VERBOSE, "[%s]: [%s]: [status] [%s: %s]",
+                                    get_etime(), item.target, item.identifier,
+                                    item.status)
+                        # Queue items' sub-items if it is done.
+                        queued_items.extend(item.sub)
+                        for sub_item in item.sub:
+                            if sub_item.target not in status.keys():
+                                status[sub_item.target] = {}
+                            status[sub_item.target][sub_item] = "Q"
+                status[item.target][item] = item.status
+
             # Dispatch items from the queue as slots free up.
-            if len(queued_items) != 0:
+            all_done = (len(queued_items) == 0)
+            if not all_done:
                 num_slots = Deploy.max_parallel - Deploy.dispatch_counter
                 if num_slots > 0:
                     if len(queued_items) > num_slots:
@@ -394,33 +421,15 @@
                         dispatched_items.extend(queued_items)
                         queued_items = []
 
-            # Advance time by 1s.
-            time.sleep(1)
-            Deploy.num_secs += 1
-            print_status = ((Deploy.num_secs % Deploy.print_interval) == 0)
-
-            # Get status of dispatched items.
-            for item in dispatched_items:
-                if item.status == "D": item.get_status()
-                if item.status != status[item.target][item]:
-                    print_status = True
-                    if item.status != "D":
-                        if item.status != "P":
-                            # Kill its sub items if item did not pass.
-                            item.set_sub_status("K")
-                        log.log(VERBOSE, "[%s]: [%s]: [status]\n  [%s: %s]",
-                                get_etime(), item.target, item.identifier,
-                                item.status)
-                        # Queue items' sub-items if it is done.
-                        queued_items.extend(item.sub)
-                        for sub_item in item.sub:
-                            if sub_item.target not in status.keys():
-                                status[sub_item.target] = {}
-                            status[sub_item.target][sub_item] = "Q"
-                status[item.target][item] = item.status
-
             # Check if we are done and print the status periodically.
-            all_done = track_progress(status, print_status)
+            all_done &= track_progress(status, print_status_flag)
+
+            # Advance time by 1s if there is more work to do.
+            if not all_done:
+                time.sleep(1)
+                Deploy.num_secs += 1
+                print_status_flag = ((Deploy.num_secs %
+                                      Deploy.print_interval) == 0)
 
 
 class CompileSim(Deploy):
diff --git a/util/dvsim/FlowCfg.py b/util/dvsim/FlowCfg.py
index a001f7b..6e438f8 100644
--- a/util/dvsim/FlowCfg.py
+++ b/util/dvsim/FlowCfg.py
@@ -430,7 +430,7 @@
         results = []
         for item in self.cfgs:
             result = item._gen_results()
-            print(result)
+            log.info("[results]: [%s]:\n%s\n\n", item.name, result)
             results.append(result)
             self.errors_seen |= item.errors_seen
 
diff --git a/util/dvsim/LintCfg.py b/util/dvsim/LintCfg.py
index 670e5e3..4adfd1e 100644
--- a/util/dvsim/LintCfg.py
+++ b/util/dvsim/LintCfg.py
@@ -41,7 +41,6 @@
         # Set the title for lint results.
         self.results_title = self.name.upper() + " Lint Results"
 
-
     @staticmethod
     def create_instance(flow_cfg_file, proj_root, args):
         '''Create a new instance of this class as with given parameters.
@@ -125,7 +124,6 @@
         results_str += "### " + self.timestamp_long + "\n"
         results_str += "### Lint Tool: " + self.tool.upper() + "\n\n"
 
-
         header = [
             "Build Mode", "Tool Warnings", "Tool Errors", "Lint Warnings",
             "Lint Errors"
@@ -213,8 +211,8 @@
 
         # Write results to the scratch area
         self.results_file = self.scratch_path + "/results_" + self.timestamp + ".md"
-        log.info("Detailed results are available at %s", self.results_file)
         with open(self.results_file, 'w') as f:
             f.write(self.results_md)
 
+        log.info("[results page]: [%s] [%s]", self.name, results_file)
         return self.results_md
diff --git a/util/dvsim/OneShotCfg.py b/util/dvsim/OneShotCfg.py
index 10fff9a..cc78d8c 100644
--- a/util/dvsim/OneShotCfg.py
+++ b/util/dvsim/OneShotCfg.py
@@ -84,30 +84,31 @@
                                                       self.__dict__,
                                                       ignored_wildcards)
 
-        # Print info
-        log.info("Scratch path for %s: %s", self.name, self.scratch_path)
-
-        # Set directories with links for ease of debug / triage.
-        self.links = {
-            "D": self.scratch_path + "/" + "dispatched",
-            "P": self.scratch_path + "/" + "passed",
-            "F": self.scratch_path + "/" + "failed",
-            "K": self.scratch_path + "/" + "killed"
-        }
-
-        # Use the default build mode for tests that do not specify it
-        if not hasattr(self, "build_mode"):
-            setattr(self, "build_mode", "default")
-
-        self._process_exports()
-
-        # Create objects from raw dicts - build_modes, sim_modes, run_modes,
-        # tests and regressions, only if not a master cfg obj
+        # Stuff below only pertains to individual cfg (not master cfg).
         if not self.is_master_cfg:
+            # Print info
+            log.info("[scratch_dir]: [%s]: [%s]", self.name, self.scratch_path)
+
+            # Set directories with links for ease of debug / triage.
+            self.links = {
+                "D": self.scratch_path + "/" + "dispatched",
+                "P": self.scratch_path + "/" + "passed",
+                "F": self.scratch_path + "/" + "failed",
+                "K": self.scratch_path + "/" + "killed"
+            }
+
+            # Use the default build mode for tests that do not specify it
+            if not hasattr(self, "build_mode"):
+                setattr(self, "build_mode", "default")
+
+            self._process_exports()
+
+            # Create objects from raw dicts - build_modes, sim_modes, run_modes,
+            # tests and regressions, only if not a master cfg obj
             self._create_objects()
 
-        # Post init checks
-        self.__post_init__()
+            # Post init checks
+            self.__post_init__()
 
     def __post_init__(self):
         # Run some post init checks
diff --git a/util/dvsim/SimCfg.py b/util/dvsim/SimCfg.py
index ada0961..6cf16da 100644
--- a/util/dvsim/SimCfg.py
+++ b/util/dvsim/SimCfg.py
@@ -125,26 +125,27 @@
         # Set the title for simulation results.
         self.results_title = self.name.upper() + " Simulation Results"
 
-        # Print info
-        log.info("Scratch path for %s: %s", self.name, self.scratch_path)
-
-        # Set directories with links for ease of debug / triage.
-        self.links = {
-            "D": self.scratch_path + "/" + "dispatched",
-            "P": self.scratch_path + "/" + "passed",
-            "F": self.scratch_path + "/" + "failed",
-            "K": self.scratch_path + "/" + "killed"
-        }
-
-        # Use the default build mode for tests that do not specify it
-        if not hasattr(self, "build_mode"):
-            setattr(self, "build_mode", "default")
-
-        self._process_exports()
-
-        # Create objects from raw dicts - build_modes, sim_modes, run_modes,
-        # tests and regressions, only if not a master cfg obj
+        # Stuff below only pertains to individual cfg (not master cfg).
         if not self.is_master_cfg:
+            # Print info
+            log.info("[scratch_dir]: [%s]: [%s]", self.name, self.scratch_path)
+
+            # Set directories with links for ease of debug / triage.
+            self.links = {
+                "D": self.scratch_path + "/" + "dispatched",
+                "P": self.scratch_path + "/" + "passed",
+                "F": self.scratch_path + "/" + "failed",
+                "K": self.scratch_path + "/" + "killed"
+            }
+
+            # Use the default build mode for tests that do not specify it
+            if not hasattr(self, "build_mode"):
+                setattr(self, "build_mode", "default")
+
+            self._process_exports()
+
+            # Create objects from raw dicts - build_modes, sim_modes, run_modes,
+            # tests and regressions, only if not a master cfg obj
             # TODO: hack to prevent coverage collection if tool != vcs
             if self.cov and self.tool != "vcs":
                 self.cov = False
@@ -514,12 +515,12 @@
 
         # Write results to the scratch area
         results_file = self.scratch_path + "/results_" + self.timestamp + ".md"
-        log.info("Detailed results are available at %s", results_file)
         f = open(results_file, 'w')
         f.write(self.results_md)
         f.close()
 
         # Return only the tables
+        log.info("[results page]: [%s] [%s]", self.name, results_file)
         return results_str
 
     def gen_results_summary(self):
@@ -533,7 +534,7 @@
             row = []
             for title in item.results_summary:
                 row.append(item.results_summary[title])
-            if len(row) == len(header): table.append(row)
+            if row != []: table.append(row)
         self.results_summary_md = "## " + self.results_title + " (Summary)\n"
         self.results_summary_md += "### " + self.timestamp_long + "\n"
         self.results_summary_md += tabulate(table,