This section describes the Simics target parameter framework. For the older script declaration system, see chapter 17. The target parameter framework introduces a few concepts:
YAML
-based format. Parameters from other scripts can be
imported, which results in a tree structure. At run-time, the
resulting parameter tree has write-once semantics, and individual
parameters can be accessed from a special singleton Simics object
(in CLI), or via a Python object acting as a
dictionary, i.e. they are unrelated to CLI variables. In
Python one can also pass around handles to parts of the parameter
tree as function arguments.targets/*/*.target.yml
then it is
considered a target. Simics scans all available packages
for targets during startup and keeps track of the target list. A
target can be run by only specifying the target name, without
having to know the full path.YAML
-based format of the parameter system. A preset
does not have to specify arguments for all parameters, but can
just override some of them and point to another preset for more
arguments. The write-once semantics of the parameter system
implies that the arguments in the top-level preset takes
precedence over any arguments specified in presets that it points
to, facilitating easy creation of override presets. When running a
target, preset files can also be provided to specify arguments. A
preset can also point to a target or script, with the effect that
the preset itself can be run as if it was a script. Presets
facilitates easy sharing of individual target configurations.The advantages compared with the script declaration system are as follows:
Parameters are write-once, hence the first value provided for a parameter is what gets used. I.e. values provided by the user when running a script will take precedence over default values provided in the script. Scripts can also provide new default values for parameters declared by scripts that they include, and those defaults will take precedence over the defaults in the declaring script. Scripts can also set defaults from their script code, to facilitate the provision of default values that require calculations, potentially using other parameters.
The whole parameter tree is exposed to the user running a script, and via the write-once semantics, the user can specify/override arguments for all parameters. Arguments can be provided on the command line, but the more powerful method is to provide them via preset files.
The write-once semantics implies that the "earliest setting wins". Arguments can come from
The parameter declarations and the presets are specified in the
standard YAML
format. Usage of a standard format means that
one can easily process the files outside of Simics, although to resolve
file paths using %script%
or %simics%
knowledge of the underlying Simics installation is required.
We have two types of files: scripts and presets.
Script files consist of
params
key,
which can import parameters from other scripts, and/or define
individual parameters with names, their types, default values,
description strings, and flags indicating if the
parameter is required and if it is an output parameter, andcode-type
key). The code section can either be below
the YAML
section, inlined using the cmd
key, or in a
separate file specified by the script
key.See section 5.3.3 for an example of a script.
Preset files
args
key,See section 5.3.4 for an example of a preset.
The write-once semantics implies that the arguments specified in a preset overrides any arguments specified in included presets. This facilitates easily creating more specialized presets where only a few arguments are changed.
Presets can also specify the script where the corresponding parameter
declarations are given, using the target
key. Such a preset
is a simple way to describe a Simics configuration, and can be used to
start Simics, meaning that the specified script is run with the
arguments from the preset. The script corresponding to the preset can
also be specified implicitly by including other presets using
the import
.
For more details about the syntax, see the Target parameters reference.
Here is a small example that illustrates how to write a target with parameters:
%YAML 1.2 --- # Declaration section params: # A simple parameter sigma: type: str required: true default: sigmoid description: |- A potentially multi-line text describing this parameter. # List parameters can have typed elements resources: type: list[list[int]] default: [] # A complex parameter epsilon: mu: type: str nu: type: int tau: # Import parameters from other script import: inner.yml # beta parameter is set by this script, not required provides: - beta # new default value of imported parameter defaults: gamma: true # Type of code code-type: simics # Code inlined in the YAML section cmd: | echo `params["sigma"]` echo (params.get "epsilon:mu") echo `params.get("epsilon:nu")` params.setdefault "tau:beta" (params.get "sigma") run-script script = "inner.yml" namespace = "tau" ...
And the imported file:
%YAML 1.2 --- params: alpha: type: int beta: type: str required: true gamma: type: bool cmd: | # Use dict syntax to read parameter print(f"beta={params['beta']}") ...
As can be seen from the example, the target script code can be inlined
in the YAML section. One can also place the code in a separate file
which is referred from the parameter section using the script
tag. A third option is to place the code below the parameter section,
but then the file as a whole will typically no longer be valid
YAML.
The example also illustrates how to import parameters from other
scripts. The result is that the parameter tree defined in the imported
script becomes a sub-tree in the current script, in this case with the
root node tau
. To refer to parameters further down in the
tree, the :
character is used as separator. Note that
importing a parameter tree from another script does not mean that the
imported script has to be run, but all scripts that are run must have
been imported. When running an imported script, the root node of the
imported sub-tree must be provided.
Notice that in the first file we have to declare the code type to be
Simics CLI, using the code-type
key, since Python is the
default. The code type defaults to Simics CLI if the file (or the file
specified by the script
key) has extension .simics
or .include
and defaults to Python if the extension
is .py
or .yml
.
Finally, as can be seen, the parameters are accessed via a global
object params
, both in CLI and in Python. In Python the
object acts like a regular Python dictionary and in CLI it is a Simics
object with various commands.
Notice how we illustrate different ways to read parameters: one can
use the CLI command params.get, or params.get
via
inline Python, or Python dictionary notation. The latter will throw an
exception if the parameter is not assigned.
For more details about the syntax, available types etc, see the Target parameters reference.
Here is an example preset for to the example target. The target is assumed
to be a file named example.target.yml
:
%YAML 1.2 --- args: tau: beta: test epsilon: mu: foo import: include.preset.yml ...
As can be seen, argument values are specified under the args
using the parameter names as keys. Also note that presets can include other presets.
Here is the the included preset, include.preset.yml
:
%YAML 1.2 --- args: sigma: foo tau: beta: bar target: example.target.yml ...
Notice that the first preset overrides the argument beta
in
the included preset. This illustrates how presets can be stacked on
top of each other, only overriding what is necessary. This facilitates
easily creating variants of target configurations for runs with
different parameters.
Also note that the second preset specifies the target that it is based on. The result is that the preset, and all presets that import it, can be run directly.
As mentioned at the top of this section, a target is a file
with name that matches targets/*/*.target.yml
, located in
the Simics project or in a package available in the project.
The intention is that the top level scripts, that should be exposed to the user via the load-target command, are turned into targets by naming them accordingly.
Targets can be listed from the Simics CLI or from the shell as mentioned in 5.3.6. The idea is to make it easy to find the main entry points to a hardware model without looking for a particular script name in the package or project.
There are two main CLI commands:
-l
.Calling load-target with a target name has the same effect as calling run-script on the file that defines the target.
Target names, script file names can also be provided directly to
Simics on the command line, in order to run them. Presets for a target
can be added using the --preset
command line flag.
As mentioned above, the parameters are accessed via a
global params
object, which has a number of CLI commands as
well. These can be discovered using tab completion or by
running help on the object.
Consider the situation where there are two scripts, perhaps hardware and software setup, that are connected by a main target script. Often the software script has parameters that should have the same value as some parameter in the hardware script, and the main script has to make sure this happens.
Here are examples of sub-scripts, alpha.yml
and beta.yml
.
%YAML 1.2 --- # This is alpha.yml params: foo: type: str default: alpha cmd: print(params['foo']) ...
%YAML 1.2 --- # This is beta.yml params: foo: type: str required: true bar: type: int required: true cmd: print(params['foo']) ...
Without parameter references, the main script can look like this:
%YAML 1.2 --- params: bar: type: int required: true alpha: import: "%script%/alpha.yml" beta: import: "%script%/beta.yml" code-type: simics cmd: | run-script "%script%/alpha.yml" namespace = alpha params.setdefault "beta:foo" (params.get "alpha:foo") params.setdefault "beta:bar" (params.get "bar") run-script "%script%/beta.yml" namespace = beta ...
Parameter references facilitate avoiding the explicit copying of parameter values, so that the main script can be expressed like this:
%YAML 1.2 --- params: bar: type: int required: true alpha: import: "%script%/alpha.yml" beta: import: "%script%/beta.yml" defaults: foo: ^alpha:foo bar: ^bar code-type: simics cmd: | run-script "%script%/alpha.yml" namespace = alpha run-script "%script%/beta.yml" namespace = beta ...