|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | import logging as log | 
|  | import sys | 
|  | import os | 
|  |  | 
|  | from CfgJson import load_hjson | 
|  |  | 
|  | import FormalCfg | 
|  | import LintCfg | 
|  | import SimCfg | 
|  | import SynCfg | 
|  |  | 
|  |  | 
|  | def _load_cfg(path, initial_values): | 
|  | '''Worker function for make_cfg. | 
|  |  | 
|  | initial_values is passed to load_hjson (see documentation there). | 
|  |  | 
|  | Returns a pair (cls, hjson_data) on success or raises a RuntimeError on | 
|  | failure. | 
|  |  | 
|  | ''' | 
|  | # Set the `self_dir` template variable to the path of the currently | 
|  | # processed Hjson file. | 
|  | assert 'self_dir' in initial_values | 
|  | initial_values['self_dir'] = os.path.dirname(path) | 
|  |  | 
|  | # Start by loading up the hjson file and any included files | 
|  | hjson_data = load_hjson(path, initial_values) | 
|  |  | 
|  | # Look up the value of flow in the loaded data. This is a required field, | 
|  | # and tells us what sort of FlowCfg to make. | 
|  | flow = hjson_data.get('flow') | 
|  | if flow is None: | 
|  | raise RuntimeError('{!r}: No value for the "flow" key. Are you sure ' | 
|  | 'this is a dvsim configuration file?' | 
|  | .format(path)) | 
|  |  | 
|  | classes = [ | 
|  | LintCfg.LintCfg, | 
|  | SynCfg.SynCfg, | 
|  | FormalCfg.FormalCfg, | 
|  | SimCfg.SimCfg | 
|  | ] | 
|  | found_cls = None | 
|  | known_types = [] | 
|  | for cls in classes: | 
|  | assert cls.flow is not None | 
|  | known_types.append(cls.flow) | 
|  | if cls.flow == flow: | 
|  | found_cls = cls | 
|  | break | 
|  | if found_cls is None: | 
|  | raise RuntimeError('{}: Configuration file sets "flow" to {!r}, but ' | 
|  | 'this is not a known flow (known: {}).' | 
|  | .format(path, flow, ', '.join(known_types))) | 
|  |  | 
|  | return (found_cls, hjson_data) | 
|  |  | 
|  |  | 
|  | def _make_child_cfg(path, args, initial_values): | 
|  | try: | 
|  | cls, hjson_data = _load_cfg(path, initial_values) | 
|  | except RuntimeError as err: | 
|  | log.error(str(err)) | 
|  | sys.exit(1) | 
|  |  | 
|  | # Since this is a child configuration (from some primary configuration), | 
|  | # make sure that we aren't ourselves a primary configuration. We don't need | 
|  | # multi-level hierarchies and this avoids circular dependencies. | 
|  | if 'use_cfgs' in hjson_data: | 
|  | raise RuntimeError('{}: Configuration file has use_cfgs, but is ' | 
|  | 'itself included from another configuration.' | 
|  | .format(path)) | 
|  |  | 
|  | # Call cls as a constructor. Note that we pass None as the mk_config | 
|  | # argument: this is not supposed to load anything else. | 
|  | return cls(path, hjson_data, args, None) | 
|  |  | 
|  |  | 
|  | def make_cfg(path, args, proj_root): | 
|  | '''Make a flow config by loading the config file at path | 
|  |  | 
|  | args is the arguments passed to the dvsim.py tool and proj_root is the top | 
|  | of the project. | 
|  |  | 
|  | ''' | 
|  | initial_values = { | 
|  | 'proj_root': proj_root, | 
|  | 'self_dir': os.path.dirname(path), | 
|  | } | 
|  | if args.tool is not None: | 
|  | initial_values['tool'] = args.tool | 
|  |  | 
|  | try: | 
|  | cls, hjson_data = _load_cfg(path, initial_values) | 
|  | except RuntimeError as err: | 
|  | log.error(str(err)) | 
|  | sys.exit(1) | 
|  |  | 
|  | def factory(child_path): | 
|  | child_ivs = initial_values.copy() | 
|  | child_ivs['flow'] = hjson_data['flow'] | 
|  | return _make_child_cfg(child_path, args, child_ivs) | 
|  |  | 
|  | return cls(path, hjson_data, args, factory) |