[dv common] Wave dumping improvements / fix

The original scope of this change was to fix the broken FSDB dumping
with Xcelium. I eventually ended up adding some more improvements to it.

- Got rid of the extra `--dump` switch in `dvsim`.
The existing `--waves` is update to accept one optional argument. If no
argument is specified, then it picks up whatever is the tool default.
Else, the user can set the preferred dumping format like this: `--waves
vpd`.

- Moved the suppprted tool-specific wave formats to HJson. This is
helpful when adding support for a new simulator (no need to poke around
the source code to figure out what needs to be done to get wave dump
supported).

- Added ability for the user to override the default run scripts (User
can override `run_script` HJson variable to supply a different file,
other than `<tool>.tcl`. They can set `skip_run` to take full control of
the simulation flow, or set `dump_tb_top` to 0 to add custom set of
hierarchies for dumping waves.

- Simulator run script (tcl) updates:
  - Added `common.tcl` for common (global) variables and procedures.
  - Added `wavedumpScope` proc - user can use this to dump custom
  scopes rather than the full testbench.
  - Added support for vcd and evcd dump formats (not expected to be
  used, but its there).
  - Fixed FSDB dumping for Xcelium (required 'call' to be added before
  `fsdbDump*` commands).

Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/dv/tools/common.tcl b/hw/dv/tools/common.tcl
new file mode 100644
index 0000000..f9a941d
--- /dev/null
+++ b/hw/dv/tools/common.tcl
@@ -0,0 +1,61 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Commonly used globals & procs. This file must be sourced first.
+set simulator ""
+if {[info exists ::env(SIMULATOR)]} {
+  set simulator "$::env(SIMULATOR)"
+} else {
+  puts "ERROR: tool script run without SIMULATOR environment variable."
+  quit
+}
+
+set waves "none"
+if {[info exists ::env(WAVES)]} {
+  set waves "$::env(WAVES)"
+}
+
+set tb_top "tb"
+if {[info exists ::(TB_TOP)]} {
+  set tb_top "$::env(TB_TOP)"
+  puts "WARNING: TB_TOP environment variable not set - using \"tb\" as the
+        top level testbench hierarchy."
+}
+
+# Checks if variable is defined, else throw an error and exit.
+proc checkVarExists {var} {
+  upvar $var var_
+  if {![info exists var_]} {
+    puts "ERROR: Variable \"$var\" not found."
+    quit
+  }
+}
+
+# If variable is defined, then use it, else set the default value.
+proc setDefault {var value} {
+  upvar $var var_
+  if {[info exists var_]} {
+    puts "INFO: \"$var\" is already set to \"$var_\"."
+  } else {
+    puts "INFO: Setting \"$var\" to \"$value\"."
+    set var_ $value
+  }
+  return $var_
+}
+
+proc checkEq {var value} {
+  upvar $var var_
+  if {$var_ != $value} {
+    puts "ERROR: Check failed \"$var\" == \"$value\"!. Actual: \"$var_\"."
+    quit
+  }
+}
+
+proc checkNe {var value} {
+  upvar $var var_
+  if {$var_ == $value} {
+    puts "ERROR: Check failed \"$var\" != \"$value\"!. Actual: \"$var_\"."
+    quit
+  }
+}
diff --git a/hw/dv/tools/dvsim/common_sim_cfg.hjson b/hw/dv/tools/dvsim/common_sim_cfg.hjson
index 56daa36..e038460 100644
--- a/hw/dv/tools/dvsim/common_sim_cfg.hjson
+++ b/hw/dv/tools/dvsim/common_sim_cfg.hjson
@@ -76,8 +76,8 @@
   // Default list of things to export to shell
   exports: [
     { TOOL_SRCS_DIR: "{tool_srcs_dir}" },
-    { EN_WAVES: "{waves}" },
-    { DUMP_FMT: "{dump_fmt}" },
+    { SIMULATOR: "{tool}" },
+    { WAVES: "{waves}" },
     { DUT_TOP: "{dut}" },
     { TB_TOP: "{tb}" },
     { dut_instance: "{dut_instance}" }
@@ -141,7 +141,9 @@
   // Add waves.tcl to the set of sources to be copied over to
   // {tool_srcs_dir}. This can be sourced by the tool-specific TCL
   // script to set up wave dumping.
-  tool_srcs:  ["{dv_root}/tools/waves.tcl"],
+  tool_srcs:  ["{dv_root}/tools/sim.tcl",
+               "{dv_root}/tools/common.tcl",
+               "{dv_root}/tools/waves.tcl"]
 
   // Project defaults for VCS
   vcs_cov_cfg_file: "{{build_mode}_vcs_cov_cfg_file}"
diff --git a/hw/dv/tools/dvsim/dsim.hjson b/hw/dv/tools/dvsim/dsim.hjson
index 69de770..f5a61a3 100644
--- a/hw/dv/tools/dvsim/dsim.hjson
+++ b/hw/dv/tools/dvsim/dsim.hjson
@@ -5,6 +5,12 @@
   build_cmd:  "{job_prefix} dsim"
   run_cmd:    "{job_prefix} dsim"
 
+  // Indicate the tool specific helper sources - these are copied over to the
+  // {tool_srcs_dir} before running the simulation.
+  // TODO, there is no dsim tool file, point to vcs for now to avoid error from script
+  // tool_srcs: ["{dv_root}/tools/dsim/*"]
+
+
   build_opts: ["-work {build_dir}/dsim_out",
                "-genimage image",
                "-sv",
@@ -32,10 +38,11 @@
                "+UVM_TESTNAME={uvm_test}",
                "+UVM_TEST_SEQ={uvm_test_seq}"]
 
-  // Indicate the tool specific helper sources - these are copied over to the
-  // {tool_srcs_dir} before running the simulation.
-  // TODO, there is no dsim tool file, point to vcs for now to avoid error from script
-  tool_srcs: ["{dv_root}/tools/vcs/*"]
+  // Supported wave dumping formats (in order of preference).
+  supported_wave_formats: ["vcd", "fst"]
+
+  // Default tcl script used when running the sim. Override if needed.
+  run_script: ""
 
   // TODO: refactor coverage configuration for DSim.
 
@@ -86,8 +93,6 @@
   run_fail_patterns:   ["^Error-.*$"] // Null pointer error
 
   // waveform
-  wave_type:  "vcd"
-  wave_file:  "dsim_wave.{wave_type}"
   probe_file: "dsim.probe"
 
   build_modes: [
@@ -95,7 +100,7 @@
       name: dsim_waves
       is_sim_mode: 1
       build_opts: ["+acc+b"]
-      run_opts:   ["-waves {wave_file}",
+      run_opts:   ["-waves waves.{waves}",
                    // dsim.probe is currently undefined
                    //"-wave-scope-specs {probe_file}",
                    // Dump unpacked structs and arrays.
diff --git a/hw/dv/tools/dvsim/riviera.hjson b/hw/dv/tools/dvsim/riviera.hjson
index 0e44d27..6be02dc 100644
--- a/hw/dv/tools/dvsim/riviera.hjson
+++ b/hw/dv/tools/dvsim/riviera.hjson
@@ -20,7 +20,14 @@
                "-lib {sv_flist_gen_dir}/work",
                "+UVM_TESTNAME={uvm_test}",
                "+UVM_TEST_SEQ={uvm_test_seq}",
-               "-do {tool_srcs_dir}/riviera_run.do"]
+               "-do {run_script}"]
+
+
+  // Supported wave dumping formats (in order of preference).
+  supported_wave_formats: []
+
+  // Default tcl script used when running the sim. Override if needed.
+  run_script: "{tool_srcs_dir}/riviera_run.do"
 
   // Coverage related.
   // TODO: These options have to be filled in.
diff --git a/hw/dv/tools/dvsim/vcs.hjson b/hw/dv/tools/dvsim/vcs.hjson
index 4646811..82bc6df 100644
--- a/hw/dv/tools/dvsim/vcs.hjson
+++ b/hw/dv/tools/dvsim/vcs.hjson
@@ -88,7 +88,7 @@
                ]
 
   run_opts:   ["-licqueue",
-               "-ucli -do {tool_srcs_dir}/vcs.tcl",
+               "-ucli -do {run_script}",
                "+ntb_random_seed={seed}",
                // Disable the display of the SystemVerilog assert and cover statement summary
                // at the end of simulation. This summary is list of assertions that started but
@@ -99,6 +99,12 @@
                "+UVM_TESTNAME={uvm_test}",
                "+UVM_TEST_SEQ={uvm_test_seq}"]
 
+  // Supported wave dumping formats (in order of preference).
+  supported_wave_formats: ["fsdb", "vpd"]
+
+  // Default tcl script used when running the sim. Override if needed.
+  run_script: "{tool_srcs_dir}/sim.tcl"
+
   // Coverage related.
   cov_db_dir: "{scratch_path}/coverage/{build_mode}.vdb"
 
diff --git a/hw/dv/tools/dvsim/xcelium.hjson b/hw/dv/tools/dvsim/xcelium.hjson
index 1a47c88..29de0a6 100644
--- a/hw/dv/tools/dvsim/xcelium.hjson
+++ b/hw/dv/tools/dvsim/xcelium.hjson
@@ -23,7 +23,7 @@
                "+define+XCELIUM",
                ]
 
-  run_opts:   ["-input {tool_srcs_dir}/xcelium.tcl",
+  run_opts:   ["-input {run_script}",
                "-licqueue",
                "-64bit -xmlibdirname {build_dir}/xcelium.d -R",
                "+SVSEED={seed}",
@@ -48,6 +48,12 @@
     { cov_report_dir: "{cov_report_dir}" }
   ]
 
+  // Supported wave dumping formats (in order of preference).
+  supported_wave_formats: ["shm", "fsdb", "vcd"]
+
+  // Default tcl script used when running the sim. Override if needed.
+  run_script: "{tool_srcs_dir}/sim.tcl"
+
   // Coverage related.
   // By default, collect all coverage metrics: block:expr:fsm:toggle:functional.
   cov_metrics: all
diff --git a/hw/dv/tools/sim.tcl b/hw/dv/tools/sim.tcl
new file mode 100644
index 0000000..9bad749
--- /dev/null
+++ b/hw/dv/tools/sim.tcl
@@ -0,0 +1,21 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+# Common TCL script invoked at run-time by the simulator.
+# VCS syntax: -ucli -do <this file>
+# Xcelium syntax: -input <this file>
+
+set tool_srcs_dir ""
+if {[info exists ::env(TOOL_SRCS_DIR)]} {
+  set tool_srcs_dir "$::env(TOOL_SRCS_DIR)"
+} else {
+  puts "ERROR: Script run without TOOL_SRCS_DIR environment variable."
+  quit
+}
+
+source "${tool_srcs_dir}/common.tcl"
+source "${tool_srcs_dir}/waves.tcl"
+
+run
+quit
diff --git a/hw/dv/tools/vcs/vcs.tcl b/hw/dv/tools/vcs/vcs.tcl
deleted file mode 100644
index aca0eed..0000000
--- a/hw/dv/tools/vcs/vcs.tcl
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-# TCL file invoked from VCS's simv at run-time using this: -ucli -do <this file>
-
-# Get some environment variables we need.
-set en_waves 0
-set tool_srcs_dir ""
-if {[info exists ::env(EN_WAVES)]} {
-    set en_waves "$::env(EN_WAVES)"
-}
-if {[info exists ::env(TOOL_SRCS_DIR)]} {
-    set tool_srcs_dir "$::env(TOOL_SRCS_DIR)"
-} else {
-    puts "ERROR: tool script run without TOOL_SRCS_DIR environment variable."
-    quit
-}
-
-# If wave dumping is enabled, run waves.tcl
-if {"$en_waves" == 1} {
-    source "${tool_srcs_dir}/waves.tcl"
-}
-
-run
-quit
diff --git a/hw/dv/tools/waves.tcl b/hw/dv/tools/waves.tcl
index 87d64ad..23f806a 100644
--- a/hw/dv/tools/waves.tcl
+++ b/hw/dv/tools/waves.tcl
@@ -2,44 +2,157 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
-#
-# Generic TCL included by tool-specific scripts when wave dumping is
-# enabled.
-#
-# This is used by all supported simulators, and the driver scripts
+# This is sourced by all supported simulators. The driver scripts
 # (dvsim.py) need to make sure that we don't ask for an unsupported
-# dumping format (SHM with VCS, for example).
+# dumping format (SHM with VCS, for example). The adjoining common.tcl
+# must be sourced prior to sourcing this file.
+
+if {[info proc setDefault] ne "setDefault"} {
+  puts "ERROR: Please ensure that common.tcl is sourced."
+  quit
+}
+
+global simulator
+global waves
+global tb_top
+
+set wavedump_db "waves.$waves"
+
+# TODO: convert this to a proc?
+switch $waves {
+  "none" {
+    puts "INFO: Dumping waves is not enabled."
+  }
+
+  "fsdb" {
+    if {$simulator eq "xcelium"} {
+      call fsdbDumpfile $wavedump_db
+    } else {
+      fsdbDumpfile $wavedump_db
+    }
+  }
+
+  "shm" {
+    checkEq simulator "xcelium"
+    database -open $wavedump_db -default -shm
+  }
+
+  "vpd" {
+    checkEq simulator "vcs"
+    dump -file $wavedump_db -type VPD
+  }
+
+  "vcd" {
+    if {$simulator eq "xcelium"} {
+      database -open $wavedump_db -default -vcd
+    } else {
+      puts "ERROR: Simulator $simulator does not support dumping waves in VCD."
+      quit
+    }
+  }
+
+  "evcd" {
+    if {$simulator eq "xcelium"} {
+      database -open $wavedump_db -default -evcd
+    } else {
+      puts "ERROR: Simulator $simulator does not support dumping waves in EVCD."
+      quit
+    }
+  }
+
+  default {
+    puts "ERROR: Unknown wave format: ${waves}."
+    quit
+  }
+}
+
+if {$waves ne "none"} {
+  puts "INFO: Dumping waves in [string toupper $waves] format to $wavedump_db."
+}
+
+# Provides wave-format-agnostic way to set a scope (design heirarchy).
 #
+# In large designs, dumping waves on the entire hierarchy can significantly slow down the
+# simulation. It is useful in that case to only dump the relevant scopes of interest during debug.
+#
+# scope       : Design / testbench hierarchy to dump waves. Defaults to $tb_top.
+# depth       : Levels in the hierarchy to dump waves. Defaults to 0 (dump all levels).
+# fsdb_flags  : Additional string flags passed to fsdbDumpVars. Defaults to "+all".
+# probe_flags : Additional string flags passed to probe command (Xcelium). Defaults to "-all".
+# dump_flags  : Additional string flags passed to dump command (VCS). Defaults to "-aggregates".
+#
+# Depending on the need, more such technlogy specific flags can be added in future.
+proc wavedumpScope {scope {depth 0} {fsdb_flags "+all"} {probe_flags  "-all"}
+                    {dump_flags "-aggregates"}} {
+  global simulator
+  global waves
+  global wavedump_db
 
-set dump_fmt none
-if {[info exists ::env(DUMP_FMT)]} {
-    set dump_fmt "$::env(DUMP_FMT)"
-} else {
-    puts "ERROR: No DUMP_FMT specified for wave dumping."
-    quit
+  switch $waves {
+    "none" {
+    }
+
+    "fsdb" {
+      # The fsdbDumpvars +all command dumps everything: memories, MDAs,
+      # structs, unions, power, packed structs. In addition, also dump SVAs.
+      if {$simulator eq "xcelium"} {
+        call fsdbDumpvars $depth $scope $fsdb_flags
+        call fsdbDumpSVA $depth $scope
+      } else {
+        fsdbDumpvars $depth $scope $fsdb_flags
+        fsdbDumpSVA $depth $scope
+      }
+    }
+
+    "shm" {
+      if {$depth == 0} {
+        set depth "all"
+      }
+      probe "$scope" $probe_flags -depth $depth -shm
+    }
+
+    "vpd" {
+      # The dump command switch -aggregates enables dumping of structs &
+      # arrays.
+      dump -add "$scope" -depth $depth $dump_flags
+    }
+
+    "vcd" {
+      if {$simulator eq "xcelium"} {
+        if {$depth == 0} {
+          set depth "all"
+        }
+        probe "$scope" $probe_flags -depth $depth -vcd
+      }
+    }
+
+    "evcd" {
+      if {$simulator eq "xcelium"} {
+        if {$depth == 0} {
+          set depth "all"
+        }
+        probe "$scope" $probe_flags -depth $depth -evcd
+      }
+    }
+
+    default {
+      puts "ERROR: Unknown wave format: ${waves}."
+      quit
+    }
+  }
+  puts "INFO: Dumping waves in scope \"$scope:$depth\"."
 }
 
-set tb_top "tb"
-if {[info exists ::(TB_TOP)]} {
-    set tb_top "$::env(TB_TOP)"
-}
+# Decide whether to dump the entire testbench hierarchy by default.
+#
+# If this variable is not set externally, it is set to 1 by default here. When set to 1, it adds the
+# entire top-level testbench instance for dumping waves. For larger designs, this may slow down the
+# simulation. The user can if needed, set it to 0 in the external tcl script that sources this
+# script and manually add the hierarchies of interest in there, using the wavedumpScope proc.
+setDefault dump_tb_top 1
 
-if {"$dump_fmt" == "fsdb"} {
-    # The fsdbDumpvars +all command dumps everything: memories,
-    # MDA signals, structs, unions, power and packed structs.
-    puts "Dumping waves with VERDI to waves.fsdb"
-    fsdbDumpfile  "waves.fsdb"
-    fsdbDumpvars  0 $tb_top +all
-    fsdbDumpSVA   0 $tb_top
-} elseif {"$dump_fmt" == "shm"} {
-    puts "Dumping waves in SHM format to waves.shm"
-    database -open -default -shm "waves.shm"
-    probe "$tb_top" -all -depth all -shm
-} elseif {"$dump_fmt" == "vpd"} {
-    puts "Dumping waves in VCD+ format to waves.vpd"
-    dump -file "waves.vpd"
-    dump -add "$tb_top" -depth 0 -aggregates -scope "."
-} else {
-    puts "ERROR: Unknown dump format: ${dump_fmt}"
-    quit
+
+# By default, add the full test bench scope for wavedump.
+if {$dump_tb_top == 1} {
+  wavedumpScope $tb_top
 }
diff --git a/hw/dv/tools/xcelium/xcelium.tcl b/hw/dv/tools/xcelium/xcelium.tcl
deleted file mode 100644
index bd328c7..0000000
--- a/hw/dv/tools/xcelium/xcelium.tcl
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-# TCL file invoked from xcelium simulations at run-time using this: -input <this file>
-
-# Get some environment variables we need.
-set en_waves 0
-set tool_srcs_dir ""
-if {[info exists ::env(EN_WAVES)]} {
-    set en_waves "$::env(EN_WAVES)"
-}
-if {[info exists ::env(TOOL_SRCS_DIR)]} {
-    set tool_srcs_dir "$::env(TOOL_SRCS_DIR)"
-} else {
-    puts "ERROR: tool script run without TOOL_SRCS_DIR environment variable."
-    quit
-}
-
-# If wave dumping is enabled, run waves.tcl
-if {"$en_waves" == 1} {
-    source "${tool_srcs_dir}/waves.tcl"
-}
-
-run
-quit
diff --git a/util/dvsim/SimCfg.py b/util/dvsim/SimCfg.py
index ebea603..b7dff52 100644
--- a/util/dvsim/SimCfg.py
+++ b/util/dvsim/SimCfg.py
@@ -20,8 +20,8 @@
 from utils import VERBOSE, find_and_substitute_wildcards
 
 
-def pick_dump_format(fmts):
-    '''Choose a supported wave dumping format
+def pick_wave_format(fmts):
+    '''Pick a supported wave format from a list.
 
     fmts is a list of formats that the chosen tool supports. Return the first
     that we think is possible (e.g. not fsdb if Verdi is not installed).
@@ -29,53 +29,17 @@
     '''
     assert fmts
     fmt = fmts[0]
+    # TODO: This will not work if the EDA tools are expected to be launched
+    # in a separate sandboxed environment such as Docker /  LSF. In such case,
+    # Verdi may be installed in that environment, but it may not be visible in
+    # the current repo environment where dvsim is invoked.
     if fmt == 'fsdb' and not shutil.which('verdi'):
-        return pick_dump_format(fmts[1:])
+        log.log(VERBOSE, "Skipping fsdb since verdi is not found in $PATH")
+        return pick_wave_format(fmts[1:])
 
     return fmt
 
 
-def resolve_dump_format(tool, dump):
-    '''Decide on the correct dumping format
-
-    This is called after reading the config file. tool is the chosen tool,
-    which will always have been resolved by this point. waves is a boolean
-    which determines whether waves should be dumped at all (from the --waves
-    argument). dump is the dumping format chosen on the command line or None.
-
-    '''
-    assert tool is not None
-
-    SUPPORTED_DUMP_FMTS = {
-        'vcs': ['fsdb', 'vpd'],
-        'xcelium': ['fsdb', 'shm', 'vpd']
-    }
-
-    # Look up which dumping formats the tool supports
-    fmts = SUPPORTED_DUMP_FMTS.get(tool)
-
-    if dump is not None:
-        # If the user has specified their preferred dumping format, use it. As
-        # a sanity check, error out if the chosen tool doesn't support the
-        # format, but only if we know about the tool. If not, we'll just assume
-        # they know what they're doing.
-        if fmts is not None and dump not in fmts:
-            log.error('Chosen tool ({}) does not support wave '
-                      'dumping format {!r}.'.format(tool, dump))
-            sys.exit(1)
-
-        return dump
-
-    # If the user hasn't specified a dumping format, but has asked for waves,
-    # we need to decide on a format for them. If fmts is None, we don't know
-    # about this tool. Maybe it's a new simulator, in which case, default to
-    # VPD and hope for the best.
-    if not fmts:
-        return 'vpd'
-
-    return pick_dump_format(fmts)
-
-
 class SimCfg(FlowCfg):
     """Simulation configuration object
 
@@ -98,7 +62,9 @@
         self.run_only = args.run_only
         self.reseed_ovrd = args.reseed
         self.reseed_multiplier = args.reseed_multiplier
-        self.waves = args.waves
+        # Waves must be of type string, since it may be used as substitution
+        # variable in the HJson cfg files.
+        self.waves = args.waves or 'none'
         self.max_waves = args.max_waves
         self.cov = args.cov
         self.cov_merge_previous = args.cov_merge_previous
@@ -118,7 +84,7 @@
             self.cov = False
 
         # Set default sim modes for unpacking
-        if self.waves is True:
+        if args.waves is not None:
             self.en_build_modes.append("waves")
         if self.cov is True:
             self.en_build_modes.append("cov")
@@ -145,6 +111,7 @@
         self.build_modes = []
         self.run_modes = []
         self.regressions = []
+        self.supported_wave_formats = None
 
         # Options from tools - for building and running tests
         self.build_cmd = ""
@@ -168,11 +135,10 @@
         # Parse the cfg_file file tree
         self._parse_flow_cfg(flow_cfg_file)
 
-        # Choose a dump format now. Note that this has to happen after parsing
+        # Choose a wave format now. Note that this has to happen after parsing
         # the configuration format because our choice might depend on the
         # chosen tool.
-        self.dump_fmt = (resolve_dump_format(self.tool, args.dump)
-                         if self.waves and not self.is_primary_cfg else 'none')
+        self.waves = self._resolve_waves()
 
         # If build_unique is set, then add current timestamp to uniquify it
         if self.build_unique:
@@ -236,6 +202,47 @@
         # Run some post init checks
         super().__post_init__()
 
+    def _resolve_waves(self):
+        '''Choose and return a wave format, if waves are enabled.
+
+        This is called after reading the config file. This method is used to
+        update the value of class member 'waves', which must be of type string,
+        since it is used as a substitution variable in the parsed HJson dict.
+        If waves are not enabled, or if this is a primary cfg, then return
+        'none'. 'tool', which must be set at this point, supports a limited
+        list of wave formats (supplied with 'supported_wave_formats' key). If
+        waves is set to 'default', then pick the first item on that list; else
+        pick the desired format.
+        '''
+        if self.waves == 'none' or self.is_primary_cfg:
+            return 'none'
+
+        assert self.tool is not None
+
+        # If the user hasn't specified a wave format (No argument supplied
+        # to --waves), we need to decide on a format for them. The supported
+        # list of wave formats is set in the tool's HJson configuration using
+        # the `supported_wave_formats` key. If that list is not set, we use
+        # 'vpd' by default and hope for the best. It that list if set, then we
+        # pick the first available format for which the waveform viewer exists.
+        if self.waves == 'default':
+            if self.supported_wave_formats:
+                return pick_wave_format(self.supported_wave_formats)
+            else:
+                return 'vpd'
+
+        # If the user has specified their preferred wave format, use it. As
+        # a sanity check, error out if the chosen tool doesn't support the
+        # format, but only if we know about the tool. If not, we'll just assume
+        # they know what they're doing.
+        if self.supported_wave_formats and \
+           self.waves not in self.supported_wave_formats:
+            log.error('Chosen tool ({}) does not support wave format '
+                      '{!r}.'.format(self.tool, self.waves))
+            sys.exit(1)
+
+        return self.waves
+
     def kill(self):
         '''kill running processes and jobs gracefully
         '''
diff --git a/util/dvsim/dvsim.py b/util/dvsim/dvsim.py
index 2e1dd78..465bcae 100755
--- a/util/dvsim/dvsim.py
+++ b/util/dvsim/dvsim.py
@@ -351,7 +351,9 @@
                             'applied to each simulation run.'))
 
     rung.add_argument("--profile", "-p",
+                      nargs="?",
                       choices=['time', 'mem'],
+                      const="time",
                       metavar="P",
                       help=('Turn on simulation profiling (where P is time '
                             'or mem).'))
@@ -409,16 +411,15 @@
     waveg = parser.add_argument_group('Dumping waves')
 
     waveg.add_argument("--waves", "-w",
-                       action='store_true',
-                       help="Enable dumping of waves")
-
-    waveg.add_argument("-d",
-                       "--dump",
-                       choices=["fsdb", "shm", "vpd"],
-                       help=("Format to dump waves for simulation. The default "
-                             "format depends on the tool. With VCS, this "
-                             "defaults to fsdb if Verdi is installed, else "
-                             "vpd. With Xcelium, defaults to shm."))
+                       nargs="?",
+                       choices=["default", "fsdb", "shm", "vpd", "vcd", "evcd",
+                                "fst"],
+                       const="default",
+                       help=("Enable dumping of waves. It takes an optional "
+                             "argument to pick the desired wave format. If "
+                             "the optional argument is not supplied, it picks "
+                             "whatever is the default for the chosen tool. "
+                             "By default, dumping waves is not enabled."))
 
     waveg.add_argument("--max-waves", "-mw",
                        type=int,
@@ -467,7 +468,6 @@
     dvg.add_argument("--verbose",
                      nargs="?",
                      choices=['default', 'debug'],
-                     default=None,
                      const="default",
                      metavar="D",
                      help=('With no argument, print verbose dvsim tool '