Simics is often started with ready to run configurations using scripts. The configurations define components and objects and how they are connected. This chapter discusses how to write new configurations.
The file targets/vacuum/vacuum.simics is a Simics script; it contains the same sort of commands that you enter on the Simics command line. This script does not contain any components as it is a very simple system not simulating anything real. In this section we will write a simple Simics script which extends this script and creates an instance of the devices we have written. This avoids having to write the same sets of commands every time you load Simics.
Create a file named [project]/targets/vacuum/my-vacuum.simics with the following contents for creating the device object, and mapping it into the physical memory:
run-script "%script%/vacuum.simics"
@plugin = pre_conf_object("plugin", "plugin_module")
@dev1 = pre_conf_object("dev1", "simple_device")
@dev1.plugin = plugin
@SIM_add_configuration([dev1, plugin], None)
phys_mem.add-map dev1.bank.regs 0x1000 0x100
Now, each time you start from the my-vacuum.simics script, your device will be automatically loaded and configured. Test this by loading the script and manually reading from the register:
project$ ./simics targets/vacuum/my-vacuum.simics
[...]
simics> phys_mem.read 0x1000 -l
[plugin info] Hi there!
42
Simics includes many scripts representing different configurations of systems and machines You can find links to them in your project, at [project]/targets/architecture.
Each configuration typically consist of at least three script files:
<machine>-common.simics
Script that defines a complete simulated machine, i.e., both hardware and software, that can be run by Simics directly. The common script uses the -system.include script to define the hardware, and the -setup.include script for software configuration. The -common.simics scripts may add additional hardware in some cases.
These are the files you want to use to start the standard example machines in this directory.
<machine> in the script name is either a Linux machine name, or a some other name that defines the hardware/software combination.
<architecture-variant>-system.include
Script that defines the hardware of a machine. This script can be shared by several simulated machines that are based on the same hardware. The hardware setup is typically configurable using some standard parameters.
<machine>-setup.include
Script that defines the software and possibly configures the machine to run the selected software, for example setting boot path, and scripting automatic login.
You can find example configuration scripts in [simics]/targets/sample/. The sample configuration uses the x58-ich10-comp component as a base and sets up a simple system to boot Linux. It also creates an instance of the sample-component described in section 4.4.1.
The configuration is loaded by starting Simics with sample-linux-common.simics. The script name contains linux as the machine runs Linux. This is the contents of the script:
run-script "%script%/sample-system.include"
instantiate-components
run-script "%script%/sample-linux-setup.include"
The first line of the script executes sample-system.include. This script adds all components and possible objects for the configuration. This is what is required to add a sample-pci-card component:
load-module sample-components
$card = (create-sample-pci-card integer_attribute = $int_val)
To connect it to a PCI slot use:
connect "board.mb.sb.pci_slot[0]" $card.pci_bus
Note that the system script is operating system independent. The instantiate-components command creates real instances of all components previously defined.
The last line of sample-linux-common.simics executes sample-linux-setup.include. This script loads operating system binaries and defines script branches. Note that this can not be done before instantiating the components, as there are no memory to load the binaries into prior to that point.
Follow this pattern when creating your own machine scripts, i.e, divide the machine into three scripts: one to create non-instantiated components for the hardware of the system, one to load software onto the machine, and one which uses the other two scripts to create the entire system with both hardware and software.
One advantage of Simics is that you can simulate several machines simultaneously. To take advantage of this feature you need to make sure that you can create several instances of your machines. This imposes certain requirements on your machine scripts. If the components used in the script do not use the new component system with hierarchical namespaces you must give each machine its own name prefix with the set-component-prefix command:
set-component-prefix machine1
run-script -local "%script%/machine-script.simics"
set-component-prefix machine2
run-script -local "%script%/machine-script.simics"
The set-component-prefix sets a name prefix which the component system applies to all objects it creates. Already created objects are not affected.
If the script uses new components you do not have to use the set-component-prefix command:
run-script -local "%script%/machine-script.simics"
run-script -local "%script%/machine-script.simics"
Note that we run the machine scripts with the -local flag to run-script. It makes the script run with local copies of all global variables. This provides two-way protection: the script is insulated from changes to the global variables and the global variables are protected from changes in the script.
Your scripts must make no assumption about the names of components and objects it creates. This means that you should not use hard coded object names in your scripts. Use variables to get references to the parts of the system you need to access and use these variables instead:
$system = create-my-system-component
$pci_card = create-my-pci-card
connect $system.connector_pci_slot1 $pci_card.pci_bus
Do the same when accessing parts of a component:
$part = $system.system_part
If you use script branches in your script additional care must be taken. The script branch will run after your script has returned. By using local copies of the variables you use in your script branch you can insulate it from changes to the values of the global variables.
script-branch "sample script branch" {
local $con = $con0
$con.bp-wait-for-console-string "booted"
}
Here we made a local copy $con of the global variable $con0, which means that the script branch is protected from changes to $con0. Always program script branches in machine scripts in this way.
As always, test your script by booting several instances of your machine in parallel. Each instance should be created properly and all script branches should work properly for all the machines.
When creating multi-machine setups by running the same machine script several times you often need to set parameters for the machine script. To make sure the parameters do not pollute the namespace of the script instantiating the machines, you should create a block which create local variables for the parameters, sets the component prefix and runs the machine script. If you do not have a natural block which contains this code you can use a if statement to create the block:
if (1) {
local $ip_address = "10.10.0.50"
local $host_name = "t1000"
# The next line should only be used with old non-hierarchical components
set-component-prefix $host_name + "_"
run-script -local "%script%/machine-script.simics"
}
If a simulated system contains multiple machines, Simics can in many cases speed up the simulation using multithreading; this is particularly useful if the host system has multiple processor cores. More details are available in the "Multithreading" section of the API Reference Manual.
Exactly how to test your machine varies based on its configuration and the software you intend to run on it. However, there are a couple of test libraries in Simics you can use to find some errors in the way the machine handles checkpointing and snapshotting. These tests will only ensure the basics of being able to handle checkpointing and snapshotting and will not exercises all possibilities. They are still good to ensure that the target can handle at least the basics of checkpointing and snapshots.
The way these libraries works means that it is important that the target software uses the devices in the target around the points in time the tests are run.
Since one major feature in Simics is its ability to checkpoint the system, a basic test library to see how a target handles checkpointing is provided. This test library requires that you have a complete target, with models and target software which uses the models. It checks that the behavior of the target remains the same after a certain point in time, whether you run up to that point from a target script, run up to that point and save a checkpoint, or run from a checkpoint saved at that point. The library runs Simics several times.
Here is an example which creating checkpoint test suite for target qsp-x86.
A target represents as a subdirectory in the targets directory of your project. First, we need to create a suite directory to add tests inside it, e.g. targets/qsp-x86/ckpt-test. A file targets/qsp-x86/ckpt-test/SUITEINFO should also be created to indicate it is a test suite directory.
Create a new file targets/qsp-x86/ckpt-test/tests.py which can be used to define the test suite.
# contents of tests.py
from vptest_utils import add_checkpoint_tests
def tests(suite):
add_checkpoint_tests(suite,
'qsp-x86',
'firststeps.simics',
10000000,
10000000,
assert_objs = ['board.mb.cpu0.core[0][0]'],
check_cycles_and_steps_in_sync = False)
It will create checkpoint tests for target qsp-x86 based on the Simics script firststeps.simics. You can also add several checkpoint tests by calling add_checkpoint_tests more than once.
You can now check if the tests have been created properly by listing the test suite:
$ ./bin/test-runner -t --suite=targets/qsp-x86/ckpt-test
Suite: targets/qsp-x86/ckpt-test
qsp-x86/firststeps.simics-cleanup()
qsp-x86/firststeps.simics-initial-setup()
qsp-x86/firststeps.simics-after-config-write()
qsp-x86/firststeps.simics-after-config-read()
qsp-x86/firststeps.simics-after-config-from-config()
qsp-x86/firststeps.simics-multi-checkpoint()
Then the tests can be easily run by:
$ ./bin/test-runner --suite=targets/qsp-x86/ckpt-test
......
Ran 6 tests in 1 suites in 14.976005 seconds.
Please refer to Simics Reference Manual for more information about the checkpoint test library and Test Framework.