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

5.1 Script Support in CLI

5.1.1 Why Use CLI Scripting Instead of Python

There are a number of situations where it may make sense to use the scripting support in CLI due to its advantages over Python. Still, if the script starts to grow in size and complexity, or if more complete and detail control of the simulation is needed, then Python is the obvious choice.

Same environment as on the command line
CLI is suitable for interactive use with its simple syntax and features such as context sensitive tab completion. Being able to script using the same set of command simplifies script writing.
CLI hides Simics API restrictions
The Simics API has restrictions on when certain API functions may be called. For example, some functions can not be used while an instruction is executing. The CLI script environment will only run commands in a context where the full API is available, greatly simplifying scripting.
Easy to write sequential code that waits for events to occur
By using script branches, it is easy to write sequential code that can wait for various events in the system, postponing the rest of the script until they occur.

5.1.2 Variables

The Simics command line has support for string, integer, floating point, list and Boolean variables. Variables are always prefixed with the $ character. A variable has to be created by assigning a value to it, before it can be used.

simics> $foo = "some text"
simics> $foo
"some text"
simics> echo $not_used_before
No CLI variable "not_used_before"

The defined expression can be used to test if a variable has been defined. Note that this command takes the name of the variable only, i.e. without the $.

simics> $foo = 4711
simics> if defined foo { echo "foo is defined"}
foo is defined

List variables can be indexed, something that is useful in loops for example.

simics> $foo = []
simics> $foo[0] = 10
simics> $foo[1] = 20
simics> echo $foo[0] + $foo[1]
30
simics> $foo
[10, 20]
simics> $foo += ["abc"]
[10, 20, "abc"]
simics> list-length $foo
3

CLI also has support for local variables, described later in this chapter.

5.1.3 Command Return Values

The return value of a command is printed on the console, unless it is used as argument to some other command. Parenthesis () are used to group a command with arguments together, allowing the return value to be used as argument. The return value can also be used as namespace in another command. Variables can be used in the same way.

simics> $address = 0x7ff00000
simics> set $address 20
simics> echo "The Value at address " + $address + " is " + (get $address)
The Value at address 2146435072 is 20

simics> $id = 0
simics> ("board.mb.cpu0.core[" + $id + "][" + $id + "]").print-time
processor                   steps  cycles  time [s]
board.mb.cpu0.core[0][0]        0       0     0.000

Although in this particular case it is simpler to write:

simics> board.mb.cpu0.core[$id][$id].print-time
processor                   steps  cycles  time [s]
board.mb.cpu0.core[0][0]        0       0     0.000
simics> $cpu = board.mb.cpu0.core[0][0]
simics> $cpu.print-time
processor                   steps  cycles  time [s]
board.mb.cpu0.core[0][0]        0       0     0.000

Parenthesis can also be used to break a command with its arguments across multiple lines, making it easier to read scripts with expressions and nested command invocations.

5.1.4 Control Flow Commands

The script support in CLI has support for common flow control commands such as if, else, while as well as foreach.

simics> $value = 10
simics> if $value > 5 { echo "Larger than five!" }
Larger than five!

The if statement has a return value:

simics> $num_cpus = 2
simics> (if $num_cpus > 1 { "multi" } else { "single" }) + "-pro"
multi-pro

Note: Multi-line if-else statements must have } else { on the same line.
It is also possible to have else followed by another if statement.
simics> $b = 0
simics> if $b == 1 {
.......     echo 10
....... } else if $b == 0 {
.......     echo 20
....... } else {
.......     echo 30
....... }
20

Loops can be written with the while command.

simics> $loop = 3
simics> while $loop {
.......     echo $loop
.......     $loop -= 1
....... }
3
2
1

They can also be written using the foreach list iteration command. The range commands in the example returns a list of integers from 0 up to, but not including, 3.

simics> foreach $loop in (range 3) {
.......     echo $loop
....... }
0
1
2

Here is another example that shows how foreach can be used. The get-object-list commands return a list of all objects that implement the processor_internal interface in Simics:

simics> foreach $cpu in (list-objects -all processor_internal) {
.......     echo "Cycles on " + ($cpu->name) + ": " + ($cpu.print-time -c)
....... }
Cycles on board.mb.cpu0.core[0][0]: 0

Lists can also be written directly, for example:

simics> foreach $loop in [1, 2, 3] {
.......     echo $loop
....... }
1
2
3

Within command blocks, it can be useful to have variables that are local to the scope and thus do not collide with the names of global variables. By adding local before the first assignment of a variable, the variable is made local.

simics> $global = 10
simics> if TRUE {
.......     local $global = 20
.......     echo $global
....... }
20
simics> echo $global
10

5.1.5 Integer Conversion

In some cases it is useful to interpret an integer as a signed value of a specific bit size, for example when reading four bytes from memory that should be interpreted as a signed 32 bit integer. The signed, signed8, ..., signed64 commands can be used to perform the conversion.

simics> board.mb.phys_mem.set 0x7fe00000 0xffffffff 4
simics> board.mb.phys_mem.get 0x7fe00000 4
4294967295 (LE)
simics> signed32 (board.mb.phys_mem.get 0x7fe00000 4)
-1

Other useful and related commands are atoi, bits, int-to-*-float, bin, dec, hex, and oct.

5.1.6 Accessing Configuration Attributes

Simics configuration attributes that are of string, integer, floating point, Boolean, nil, and list types can be accessed directly from CLI using the -> operator.

simics> echo "Current project: " + (sim->project)
Current project: C:\Users\joe\Desktop\project

An object referenced with this operator returns the object's name as a string.

A nil attribute value is represented by NIL in CLI.

To access attributes that use other data types than the ones listed above, you need to use Python:

simics> @conf.myobject.attr.dictionary_attribute = { 1 : "abc" }

See chapter 5.4.3.1 for more information about accessing attributes from Python.

5.1.7 Error Handling in Scripts

When a Simics command encounters an error, an error message is typically printed, and the script execution is interrupted. In some cases the script itself want to handle the error, in order to try some alternative approach, or to present the error message with more context. The try-except statement can be used for this purpose.

try {
    load-module my-own-components
} except {
    echo "Simics failed to import my-own components. Perhaps you forgot to "
    echo "install the latest modules from the development team? See the "
    echo "project web-site for more info.\n"

    interrupt-script "Cannot continue"
}

Without the try-except statement, the example above would print an error message like Error loading module and the script execution would be interrupted with an error.

The error message from the failing command can be obtained inside the except block by calling the get-error-message CLI command. The get-error-line command returns the line of the error in the script file and get-error-file the file name. The get-error-command returns the command name if the error occurred within a command.

5 Simics Scripting Environment 5.2 Script Branches