[util] Rejig how we load hjson configurations for dvsim.py

The main new feature from this patch is that a dvsim configuration
should now set a "dvsim_flow" value. This value is used to decide
which subclass of FlowCfg to construct (in CfgFactory.py).

There are two upsides to this:

  1. You can now run a lint or synthesis run without specifying the
     tool on the command line (before, the code made a SimCfg unless
     it recognised the tool).

  2. If you run dvsim.py on some other random hjson file, you get a
     somewhat helpful error message. Before, you'd get something
     cryptic about expanding verbosity flags.

There is also a downside:

  1. Every configuration needs to specify dvsim_flow. In practice,
     this isn't so bad, because this can be done in the included
     common_*_cfg.hjson.

Note that "every configuration" here includes primary configurations.
This is kind of silly, because a "primary configuration" is really
just a list of other things to run. In later patches, we can split
these out into their own type, which should clean up quite a lot of
the code, and get rid of this requirement. However, you can't do that
splitting without the change in this patch (I tried!), so I've done
this patch first.

To make sense of how this all works:

  - dvsim.py calls CfgFactory.make_config

  - This uses CfgJson.load_hjson to load an hjson file and everything
    it includes.

  - After loading the file, make_config looks at dvsim_flow (which
    must have a value) to decide which subclass of FlowCfg to
    instantiate.

  - The constructor for FlowCfg gets passed hjson_data. It sets up
    a whole list of attributes, then calls self._merge_hjson to merge
    the data from hjson_data into itself. It then calls self._expand
    to expand all the wildcards. Subclasses can hook in to these two
    methods if they need things to happen at specific times.

The only slight complication is from primary configs: configurations
that have a list of children to be loaded and run. These need to load
up some new hjson files. They can do so by calling back to the
factory (passed in as an argument to avoid circular dependencies).

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/util/dvsim/OneShotCfg.py b/util/dvsim/OneShotCfg.py
index 5687729..1612734 100644
--- a/util/dvsim/OneShotCfg.py
+++ b/util/dvsim/OneShotCfg.py
@@ -13,18 +13,17 @@
 from Deploy import CompileOneShot
 from FlowCfg import FlowCfg
 from Modes import BuildModes, Modes
-from utils import VERBOSE, find_and_substitute_wildcards
 
 
 class OneShotCfg(FlowCfg):
     """Simple one-shot build flow for non-simulation targets like
     linting, synthesis and FPV.
     """
-    def __init__(self, flow_cfg_file, proj_root, args):
-        super().__init__(flow_cfg_file, proj_root, args)
 
-        assert args.tool is not None
+    ignored_wildcards = (FlowCfg.ignored_wildcards +
+                         ['build_mode', 'index', 'test'])
 
+    def __init__(self, flow_cfg_file, hjson_data, args, mk_config):
         # Options set from command line
         self.tool = args.tool
         self.verbose = args.verbose
@@ -75,22 +74,18 @@
         self.build_list = []
         self.deploy = []
         self.cov = args.cov
-        # Parse the cfg_file file tree
-        self._parse_flow_cfg(flow_cfg_file)
 
+        super().__init__(flow_cfg_file, hjson_data, args, mk_config)
+
+    def _merge_hjson(self, hjson_data):
         # If build_unique is set, then add current timestamp to uniquify it
         if self.build_unique:
             self.build_dir += "_" + self.timestamp
 
-        # Process overrides before substituting the wildcards.
-        self._process_overrides()
+        super()._merge_hjson(hjson_data)
 
-        # Make substitutions, while ignoring the following wildcards
-        # TODO: Find a way to set these in sim cfg instead
-        ignored_wildcards = ["build_mode", "index", "test"]
-        self.__dict__ = find_and_substitute_wildcards(self.__dict__,
-                                                      self.__dict__,
-                                                      ignored_wildcards)
+    def _expand(self):
+        super()._expand()
 
         # Stuff below only pertains to individual cfg (not primary cfg).
         if not self.is_primary_cfg:
@@ -113,13 +108,6 @@
             # tests and regressions, only if not a primary cfg obj
             self._create_objects()
 
-        # Post init checks
-        self.__post_init__()
-
-    def __post_init__(self):
-        # Run some post init checks
-        super().__post_init__()
-
     # Purge the output directories. This operates on self.
     def _purge(self):
         if self.scratch_path: