26 Software Domains V Creating Own Packages
Model Builder User's Guide  /  IV Creating Virtual Systems  / 

27 System Configurations

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.

27.1 Simple Command Script

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-command-file "%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

27.2 Creating New Machine Scripts

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:

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-command-file "%script%/sample-system.include"

instantiate-components

run-command-file "%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.

27.3 Multi-Machine Scripts

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-command-file -local "%script%/machine-script.simics"
set-component-prefix machine2
run-command-file -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-command-file -local "%script%/machine-script.simics"
run-command-file -local "%script%/machine-script.simics"

Note that we run the machine scripts with the -local flag to run-command-file. 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.wait-for-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-command-file -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.

27.4 Testing Machines

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 reverse execution. These tests will only ensure the basics of being able to handle checkpointing and reverse execution and will not exercises all possibilities. They are still good to ensure that the target can handle at least the basics of checkpointing and reverse execution.

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.

27.4.1 Checkpoint Test

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.

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

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

  3. 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()
    
  4. 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.

27.4.2 Reverse Execution Test

The reverse execution test library checks that a target handles reverse execution in a particular interval of time. It has several parameters you can set to get it to target a time interval when a large part of the system is used.

The reverse execution library is written to be used from within Simics, here are the steps to create reverse execution test for target qsp-x86.

  1. Create a test suite targets/qsp-x86/reverse-test in the your target directory.

  2. Instead of having a tests.py, just add a Simics test by adding a file named s-reverse-execution.py and edit it to use the reverse execution library:

    # contents of s-reverse-execution.py
    import reverse_execution
    import simics
    import os
    
    simics.SIM_run_command_file(
            os.path.join('..', 'firststeps.simics'), False)
    rt = reverse_execution.reverse_execution_test(start = 1000000,
                                                  totlen = 1000000)
    rt.runtest()
    

    The test use a relative path to find the target script. This depends on the test suite being a subdirectory of the target directory. Alternatively you can use the sim.project attribute to find the script.

  3. Now it's able to check and run the test.

    $ ./bin/test-runner -t --suite=targets/qsp-x86/reverse-test
    Suite: targets/qsp-x86/reverse-test
        s-reverse-execution
    
    $ ./bin/test-runner -t --suite=targets/qsp-x86/reverse-test
    .
    Ran 1 tests in 1 suites in 30.647487 seconds.
    

More information about the reverse execution testing library, please refer to Simics Reference Manual.

26 Software Domains V Creating Own Packages