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.
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.
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.
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
} else {
on
the same line.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
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.
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.
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.