This chapter provides a checklist for use when developing models of devices and systems for Simics. The intention is to help developers with creating high quality models that work well in Simics, including future versions, that behave in a way that Simics users expect models to, and that can be used together with other device models easily.
This section describes important generic items that should be taken into consideration when working with Simics. This applies if one is writing device models, components or general functionality to extend Simics.
Device models and other Simics extensions must support checkpointing. All state associated with the modeled machine should be included in the checkpoint. The simulation session is not checkpointed. Simply loading a machine, taking a checkpoint without having advanced the simulation and restarting from that checkpoint should result in the same machine state. The same should be true at anytime during the simulation and care must be taken to checkpoint any transient state in a module, such as pending events.
For more information refer to the sections about events and attributes in “Programming with DML”, the section about general usability in “Building Well-Behaved Models” and the section about configuration attributes in “Overview” in the Model Builder User’s Guide. Also refer to the section “Configuration and Checkpointing” in the Simics User’s Guide
Models that support
checkpointing also work with in-memory snapshots. But the performance of the
attribute get/set methods, as well as their memory consumption, are more
important. Use image objects for storing data-type attributes, such as
internal memories, of more than a few kilo bytes.
For more information refer to the sections about events and attributes in “Programming with DML”, the section about general usability in “Building Well-Behaved Models” and the section about configuration attributes in “Overview” in the Model Builder User’s Guide. Also refer to the section “Configuration and Checkpointing” in the Simics User’s Guide
The most recent version of the Simics API should be used. Functions and interfaces marked as deprecated should be avoided.
The latest API is documented in the Reference Manuals included in each Simics package.
The Simics
interface mechanism should be used when communicating between objects. The
standard interface types should be used when possible, allowing newly
developed objects to connect to existing ones. Memory transactions shall
however not explicitly use the connected interface but instead use
SIM_new_map_target() together with SIM_issue_transaction() on the
connected memory object. References between objects should be implemented
using attribute, with the type “o” for objects and “n” to allow no connection.
It is recommended that both variants are supported, i.e. “o|n”.
For more information see the section about Simics interfaces in “Overview” in the Model Builder User’s Guide. The standard interfaces are documented in the Reference Manuals included in each Simics package.
Memory accesses shall not use direct interface calls for memory accesses
but shall instead use function SIM_issue_transaction()
on a map_target_t.
In Simics there are several memory interfaces. Each serving a different
purpose. For your device to be generic and easily integrated into
a platform it is best to be agnostic about which memory interface
the device is connected to.
Code should be written to work on both little- and big-endian host systems. Operating system specifics should be avoided if possible, allowing code to run on Windows and Linux. Any access to the host, for example a real network, real display, real USB, etc, should be in a separate “host access” module and not in the device itself
All
code should compile without warnings. It is recommended that the default flags
for the compiler in the Simics build environment are used. For GCC, this is
something like -O2 -Wall -Werror.
info and status CommandsAll
Simics classes should have an info and a status command. The info shows
static information about an object. Required attributes used for configuration
are typically presented here. The status command shows dynamic information
about an object. For really detailed information, a class specific command is
better suited. Objects that do not have any dynamic information should print
this fact in the status command output.
For more information refer to the section about general usability in “Building Well-Behaved Models” in the Model Builder User’s Guide.
A module should not
leak memory while running the simulation, including when taking checkpoints
and snapshots. The internal Simics command mm-list-* can be used to see
where memory has been allocated. To enable the command, set the environment
variable SIMICS_MEMORY_TRACKING before starting Simics and enable internal
commands, using the enable-unsupported-feature "malloc-debug" command.
For more information see the application note on Debugging User-Developed Simics Modules.
There should never be any side effects when attributes are read. It should always be possible to read out attribute values without affecting the model.
For more information refer to the sections about attributes in “Programming with DML” and the section about configuration attributes in “Overview” in the Model Builder User’s Guide.
Classes, non-internal attributes and CLI commands should all be properly documented. For attributes that users may change, all allowed values have to be described.
For more information refer to the sections about structuring DML code in “Building Well-Behaved Models” and “Adding New Commands” in the Model Builder User’s Guide.
Try to use coherent naming when creating files, classes, components, objects, attributes and commands in Simics. As a general rule, use lower case names. Abbreviations may be written in all capital letters, but avoid mixing upper and lower case letters, e.g., do not use capitalization. Avoid special characters and stick to plain ASCII.
-comp suffix.list-objects.Look at the existing naming for things not covered by the guidelines here.
Index
support for attributes should only be added if it is really needed for
performance reasons. When lists attributes have index support, the index
should run from 0 up to size - 1. If this is not the case, a dictionary
attribute should be used instead of a list.
A simulation
model should behave exactly the same way when it is run with identical
external stimuli (e.g., using a recorder, or only scripted input). Never use
host functions that do not behave identically between runs in your model, such
as gettimeofday() or rand().
This greatly helps in pinpointing bugs, as those are guaranteed to be repeatable in a deterministic simulation.
For more information refer to the section about general usability in “Building Well-Behaved Models” in the Model Builder User’s Guide.
All user visible strings should be checked for correct spelling and grammar.
Errors that can be triggered by a user, for example by running target software that does not follow the specification should not cause Simics to assert. For errors signalling use log messages of the “info”, “spec-violation” or “error” type depending on severity. Assert should only be used to protect against bugs in the simulator code.
Avoid using
features listed as deprecated in the Simics Migration Guide. Check the
prefs object for settings (attributes) whose names start with legacy_.
Make sure your system works with all such settings turned off. Also run Simics
with the -wdeprecated command line argument and make sure that there are no
run-time warnings generated during simulation.
Structured attribute data should not be saved in binary form, since it prevents user inspection, for example by the info and status commands, and makes it difficult to keep compatibility with old checkpoints. Binary data should only be used when saving memory images and similar.
This section describes important items that, in addition to the generic checklist, should be taken into consideration when writing device models. For more in depth understanding of the importance of these items, please refer to the Model Builder User’s Guide.
Device models should in general be written in DML. Example of an exception to this rule is code for algorithms already available, or better expressed, in some other language.
Models of devices with one
or more reset inputs should properly implement reset. The Simics signal
interface should be used as input with one port interface for each reset
input.
The standard Simics log mechanism should be used to trace things happening in the device. It is important that target software access to unimplemented registers and features of the device are properly logged with the correct type.
A message is most of the time a fragment or, more rarely, one or more complete sentences. If it is a fragment, the message shall start with a lowercase letter (with the obvious exception for words and abbreviations that shall start with an uppercase letter) and have no period at the end. Sentences shall start with an uppercase letter and end with a period.
In DML, a typical log statement may read: log info, 2, 0: "increased counter: %d", value;.
Do not use exclamation marks and avoid question marks. Multiple question marks in a row shall never be used.
Do not start an “info” message with the words “error”, “unimplemented” or “spec_violation”, use the appropriate log-type instead.
Do not start an “error” message with the word “error”, it is just a repetition. The word “error” might be appropriate inside the message but should in most circumstances be avoided. Same goes for the “critical”, “spec_violation”, and “unimplemented” log-types.
Do not use newlines, in particular not at the end of the message. Also do not use multiple log statements to output longer messages, include everything in one statement. It is up to the presentation layer to output a long message in a readable format.
Do not mention the name of the object or class which the message refers to, as it is implicitly given by the log statement and output in the log message prefix.
For abbreviations and other special words, write them as specified in the
“Dictionary” chapter of the “Writing Documentation” manual or in the
src/docs/common/simics-documentation-word-list or
src/docs/internal/documentation-manual/usage.docu files. Here are some
examples: IRQ, DMA, CPU, CPUs.
A message followed by a more specific message, such as: "can't open file "abc": no such file or directory" should be (as above) separated by a colon. If even
more specific messages follow, these are also appended using a colon as
separator.
A message which contains some extra information at the end should be written as:
"read from register XYZ (value = 0x5000)"
Do not use cryptic abbreviations such as @, addr, idx, reg, len. Instead use: at, address, index, register, length
Do not use variable names (if they aren’t complete words) in log messages with log levels 1-3. If values are output, it should be possible to understand what the value represents without reading the source code. I.e. it should be possible to understand the log message without reading the source code.
Do not use assert statements on conditions that can be triggered by users, see GE-15.
Use pre-defined DML templates for different implementations. Log level is
automatically handled in some of these templates. For example, reserved,
unimplemented and read_only. Full list and descriptions about these
templates can be found in the Model Builder DML 1.2 reference manual.
Spec-violation and unimplemented messages are typically logged on level 1. Sometimes they are first logged at log level 1 then log level 3 for spam reduction when unimplemented registers or features are always accessed. log level 3 should be avoided for spec-violation.
For more information refer to “Logging” in the Model Builder User’s Guide.
SIM_ Functions when Modeling BehaviorCode that models the behavior of a device should avoid SIM_
and internal VT_ functions as far as possible. Such functions are mainly
intended for simulator specifics such as configuration and logging, but not to
model the actual device. Simics interfaces should be used instead to
communicate with other objects that a device is connected to. The most common
exceptions are SIM_ functions used to access fields in the
generic_transaction_t, timing API functions and event API functions for
devices not written in DML.
Simics attributes are intended for configuration and diagnostic access to a device. Communication between devices should use Simics interfaces and not rely on reading or writing attributes.
For more information see the section about Simics interfaces in “Overview” in the Model Builder User’s Guide. The standard interfaces are documented in the Reference Manuals included in each Simics package.
Some kinds of
storage are persistent and survive power cycling, for example NVRAMs, certain
device registers, and disk images. Models of such entities should be handled
as persistent in Simics, allowing the save-persistent-state and
load-persistent-state commands to work properly for simulating power off
followed by power on. To check which images are marked as persistent, use the
list-persistent-images command.
The image interface on objects of the Simics image class provides a way to
mark an image object as holding persistent data. Custom disk and storage models
must call this interface on their associated image objects, if they are
persistent.
Device register and device state saved in attributes are marked as persistent by
using the Sim_Attr_Persistent flag on the attribute when it is registered with
Simics.
For NVRAMs the persistent-ram class can be used.
For more information see the section about saving and restoring persistent data in “Configuration and Checkpointing” in the Simics User’s Guide
Device models should share common code if possible, such as the generic PCI, I2C or MII device code, see the Model Builder User’s Guide.
Parts and features of
a device that is not modeled should be described in documentation. For devices
written in DML, use the limitations parameter. For devices not written in
DML add the information to the class documentation. Use free form complete
sentences or bullet lists:
<ul>
<li>The X device does not implement Y hashing.</li>
<li>The Z feature does not work with the Windows 7 driver.</li>
<li>...</li>
</ul>
See the DML 1.4 Reference Manual for more information.
Unimplemented registers, or registers with limited functionality, should use the
standard Simics log mechanism with the Sim_Log_Unimplemented type to log any
accesses.
Devices should be written with performance in mind. In general this simply means avoiding expensive operations and using events instead of polling. The Model Builder User’s Guide includes a discussion on performance for device models.
Device objects should use the int_register interface if it has to access
registers in another object directly. The typical case is for objects that
represent tightly coupled devices. In other situations the devices can use the
architecturally specified way of communicating, for example by doing memory
mapped accesses or sending bus transactions if a bus interface exists.
The int_register interface is documented in the Simics Reference Manual
Device objects
should handle inquiry accesses without performing any side effects beyond
changing the state of the register itself. This is done automatically for
registers which does not override the read_access and write_access
methods, but if you override these methods or implement the access at the bank
level you have to implement it yourself.
A machine model should
support system reboot. This means software reboot and commands to trigger any
reset buttons. Reset signals are typically distributed between simulated
devices using the signal interface unless reset is already part of some
technology specific interface such as the pci_device interface.
Any optional attribute should be truly optional. It should make sense and be possible to instantiate the object without setting any optional attributes. Accesses to the device should not cause simulation errors if any optional attributes are not set, for example dereferencing a NIL pointer for an optional object attribute.
It should always be possible to create multiple instances of a device model, for example to have several similar systems networked together.
When modeling address spaces, reusing the Simics memory-space or
port-space classes is almost always possible. Similarly, the ram, rom
and persistent-ram classes should be used to model RAM and ROM. This is true
also for on-chip memory, unless the memory is very small, perhaps a few
kilobytes or less. The storage for larger memory areas should be implemented
using the standard image class, that provides delta checkpointing and
efficient run-time memory handling.
When writing
device models only the Device API should be used. API function, and
interfaces, from the Simulator API should not be used. The Device API is
documented in the Model Builder User’s Guide. See also DE-04 about avoiding
SIM_ functions.
It should be possible to delete object of the device class. All allocated memory should be freed, events should be cancelled, etc.
Ethernet devices where the transceiver is visible to the software, for example exposed by the MII or similar interface, should have the transceiver modeled as a separate object in Simics. This allows for reuse of transceivers and a number of such models already exist, including a generic MII transceiver.
For more information see the section on Ethernet transceiver in “Modeling Ethernet Devices” in the Model Builder User’s Guide.
Ethernet devices
should use the standard bandwidth limitation support provided by the
ieee_802_3_phy_v3 interface. This interface is used when communicating with
PHY devices.
Ethernet devices
should provide a way to set the Ethernet MAC address when setting up the
system. Typically by providing a mac_address attribute.
signal Interface Ports for Inputsignal type.bios
attribute that is the image file for the expansion ROM.This section describes important items that, in addition to the generic checklist, should be taken into consideration when writing processor models. For more information about processor models, see the Processor Model Integration Guide.
This section describes important items that, in addition to the generic checklist, should be taken into consideration when writing components. For more in depth understanding of the importance of these items, please refer to the Model Builder User’s Guide.
eth_adapter — basename for Ethernet PCI cards.ethernet — ethernet-link connector name for components with a single
ethernet-link connector.cpu_frequencynum_cpusnum_coresmemory_megs — for components with RAM.rtc_time — format: “YYYY-MM-DD HH:MM:SS Z”.mac_address — single Ethernet device.mac_address0, mac_address1, ... — multiple Ethernet devices.size — for disk components.pre_instantiate method. The connect_<connection>(), add_objects() and
post_instantiate() methods should never trigger any errors.This section describes important items that, in addition to the generic checklist, should be taken into consideration when assembling a larger system. See also the “Target Script Checklist”.
This section describes important items that, in addition to previous checklists, should be taken into consideration when writing the target scripts for a virtual platforms.
The .simics and .include scripts for a machine should follow the
guidelines in the section about ready-to-run configurations in
“Configuration and Checkpointing” in the Simics User’s Guide. For example
the setup of the simulated hardware should be separate from the software
configuration. See also “System Configurations” in the Model Builder User’s
Guide.
.simics ScriptsIt should be possible to start any .simics file from scratch.
Scripts that require other files to have run first, or require CLI variables
to be set, should have the .include suffix.
It should be
possible to launch a target script in Simics no matter what the current
directory of Simics is. The %simics% path marker can be used to reference
other scripts in a Simics project, the same, or other packages.
A target script should not run the simulation, but start all processors at step and cycle 0. Script branches can be used to automate setup needed while the system is booting although adding support for it in a system component is recommended, to make sure checkpoints can be taken early.
Errors that
are detected in a script should be reported using the interrupt-script
command. Using the quit command is not advisable in scripts since it will
close the interactive session for a user. It is not needed either since Simics
will exit on errors anyway when run in batch mode.
If the script
uses files which are not included in the same package, it should verify their
presence before referencing them and, if needed, interrupt the script. The
lookup-file command searches for a file and, if not found, it emits an error
message and interrupts the script. Otherwise, use the two commands
file-exists and interrupt-script.
A machine
script (<architecture>-system.include) should create the top level component
with the name configured by the $machine_name variable. If this variable is
not set, it should default to the system name. The name of the created
component should then be saved in $system. It will typically be the same as
$machine_name unless there is a name collision. See also “System
Configurations” in the Model Builder User’s Guide.
For example:
(in decl) param machine_name : string = "board"
$system = (create-chassis-qsp-x86 name = $machine_name)
As a result, multiple machines can be instantiated in the following way:
$machine_name = machine1
run-script "%simics%/targets/qsp-x86/firststeps.simics"
$machine_name = machine2
run-script "%simics%/targets/qsp-x86/firststeps.simics"
The old component prefix support should not be used anymore as it will be removed in the future.
If applicable to the system being modeled, use the
targets/common/add-eth-link.include script to create a simulated Ethernet
network and to configure the service-node.
Target scripts should create an Ethernet network by default and connect the primary Ethernet adapter of the system to it.
Target scripts should not connect the virtual Ethernet network to the real network by default.
Target scripts should allow users to modify its behavior by setting parameters using CLI variables. All parameters should be optional and have good default values. For boolean variables, TRUE/FALSE should be used. See also ST-13.
The following standard variables should be implemented if applicable for the target system:
$cpu_cores.$num_cpus would be misleading.$disk_image, if it cannot be automatically determined from the file."YYYY-MM-DD HH:MM:SS UTC" format.The following variables are automatically supported if the
targets/common/add-eth-link.include script is used to create a virtual
Ethernet network. Scripts creating their own Ethernet network without using
add-eth-link.include should support some subset of these variables.
$service_node object on the $eth_link link.$service_node. Set to 0 to disable DHCP.$eth_link link.$eth_link link, used in distributed simulation.CLI variables are global by default. Scripts should try to make variables local if possible, or unset them after use, to avoid conflicts with other scripts. See also ST-15.
It should be
possible to create multiple target machines by setting the $host_name
variable and then running the target start script (with the -local flag)
without getting any conflicts.
All top-level
components should have software slot with an os_awareness component in it.
This is typically created in the <architecture>-system.include script:
new-os-awareness $system.software
If the OS awareness framework in Simics supports the operating system that is
configured on the machine, then a parameter file should be created that matches
the operating system and that is loaded in the software setup script (i.e. the
<architecture>-<software>-setup.include file), typically using:
$system.software.load-parameters <architecture>-<software>.params
For more details refer to the section “OS Awareness Details” in the Analyzer User’s Guide.
Simics scripts should not expect that objects created as part of components will get certain names. When creating a component, the returned component name can be saved in a variable for later use.
$console = (new-text-console-comp)
$console.con->title = "new title"
When referencing component and objects created by another machine script, the
$system variable (ST-08) will provide a reference to the top-level component
created by that script.
Check that the cell partitioning set up by the script is correct by using
check-cell-partitioning, both after the script has run and for checkpoints
taken of the system. For more information see the section on simulation
cells in the “Multithreading” section of the API Reference Manual.
Scripts should not modify default simulation settings. Examples of settings
that should not be done in scripts: changing log-level (log-level 2),
changing output radix (<output-radix 16).
While following the guidelines in this section, also try to keep the target scripts as simple as possible. Avoid switching between Python and CLI for example. If Python code is needed in a target script, then some component is probably not powerful enough or some new CLI command is needed.