5.2 Script Branches 5.4 Scripting Using Python
Simics User's Guide  /  II Feature Overview  /  5 Simics Scripting Environment  / 

5.3 Targets and parameters

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:

The advantages compared with the script declaration system are as follows:

5.3.1 Semantics

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

  1. User specification at command line.
  2. User specification via preset files.
  3. (Default) values specified in parameter declarations.
  4. (Default) values specified in script code.
and the first argument for a specific parameter sticks, e.g. user input overrides values in scripts (hence they are only default values). Note that this also implies that script code cannot unilaterally set arguments, not even input to another script that it calls, it can only provide default values, which can always be overridden by an earlier setting, such as user input.

5.3.2 File types

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

See section 5.3.3 for an example of a script.

Preset files

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.

5.3.3 Example target

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.

5.3.4 Example presets

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.

5.3.5 Target definition

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.

5.3.6 Run-time usage

There are two main CLI commands:

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.

5.3.7 Using parameter references

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
...

5.2 Script Branches 5.4 Scripting Using Python