1 Introduction 1.2 Simics API Information
API Reference Manual  /  1 Introduction  / 

1.1 Programming Concepts

This chapter describes the major programming concepts in Simics. It is intended for anyone who wants to write extensions or modules for Simics.

A Simics module is just some executable code loaded dynamically into the simulator, so it could perform virtually any operation. To be of any practical use however, a module has to interact with Simics, other modules, or the user. Simics provides a set of functions (the Simics API) for the modules to work within the simulator framework. The API defines a number of concepts like classes, objects, interfaces, haps, and events, which will be presented below.

Simics modules can be written using different programming languages:

DML
DML has been designed to make writing new device model as simple as possible. It integrates in the language many of the concepts defined by the Simics API so that the user can focus on the model rather than on the interaction with Simics. This is by far the best language for writing device models. Note that although it was designed with device models in mind, DML can be used to develop other types of modules.
Python
Python can be used to quickly write a new Simics module. It is well suited for Simics extensions that are not called very often, like some types of statistics gathering, or BIOS emulation. It can also be used for fast prototyping of more complex extensions that later on will be rewritten in a compiled language like DML or C. Note that in all cases, DML is easier to use than Python to write a device model.
C/C++
C and C++ can be used for writing any type of Simics module. Writing in C or C++ exposes all interactions with Simics, which can be sometimes cumbersome. C or C++ development is only recommended for specialized cases when DML or Python do not provide the functionality needed. A few specialized functions in the API are only available to C and C++ modules.
SystemC
Integrating existing SystemC device models into Simics simulations is supported by the SystemC Library. The library provides a set of gaskets that bridge from TLM-2.0 interface to Simics interfaces and from Simics interfaces to TLM-2.0 interface. See the SystemC Library Programming Guide for details. For new device modeling, DML is recommended since it is more efficient to model in and automatically supports all Simics features.

This chapter will cover the concepts that the Simics API defines. It will also present how to use them, first in DML, then in Python and C/C++.

1.1.1 Classes and Objects

Each device is represented by an object whose attributes correspond to the state of the device.

Most Simics modules work the same way: they define classes describing the properties of an object. This includes its attributes, interfaces and the class name. The objects are created by instantiating a class and setting the required attributes.

Note that modules and classes are not the same thing. A module can define two or more classes, or none at all. But many modules define a single class with the same name as the module.

1.1.2 Type

When registering an attribute, a type definition should be provided for Simics to check that the attribute is always set properly. This type definition is a string that is defined according to the following rules:

As an example, the "[s*]|s" string defines an attribute that can hold either a string or a (possibly empty) list of strings.

When writing complex attributes, you may notice that the type description strings do not cover all the possibilities offered by the attribute structure definition. If you need to register attributes that cannot be described in a type string (like complex variable size lists), you will need to use the a type and perform the type checking by yourself in the set() function. You may also want to review your attribute and change its definition to match a possible type description, or divide your attribute into several simpler attributes.

For example, an attribute accepting a list composed of one object and one or more integers can not be described in a type string (list definition with variable size can only have one element). You may want to rewrite your attribute to use a sub-list for the integers: [o[i+]], or you can perform type checking yourself.

1.1.3 Interfaces

Interfaces allow objects to interact with each other. An interface defines a number of functions. Every class that implements an interface (by registering it) must define those functions. In some cases, it is sufficient to implement just a subset of the functions. An object A may then ask for an interface registered by an object B, and thus use the interface's functions to communicate with B. Simics comes with many predefined interfaces but it is also possible to define new interfaces.

One of the most important interfaces for a device class is probably the io_memory interface. Implementing the io_memory interface enables a class to be mapped into a memory space and be accessed by the simulated machine. In C or DML, it is defined as:

typedef struct io_memory_interface {
        int (*_deprecated_map)(conf_object_t *NOTNULL obj,
                               addr_space_t memory_or_io,
                               map_info_t map_info);
        exception_type_t (*operation)(conf_object_t *NOTNULL obj,
                                      generic_transaction_t *NOTNULL mem_op,
                                      map_info_t map_info);
      } io_memory_interface_t;

Other interfaces can be used for things like raising processor interrupts or implementing PCI device functionality.

Interfaces are either implemented by the device class itself, or by one of its ports. This way, a device can have several ports implementing the same interface, for example interrupt controllers with several sources or memory mapped devices with separate banks of registers.

1.1.4 Logging

A device model should log its activities so that it is possible to see what happens. It is useful both while developing the model and while developing target software, or to help finding problems in the system. Logging should not be used in attribute accessor functions or in CLI commands where there are other ways to report errors. The Simics API provides logging facilities that classifies log messages based on the following criteria:

level
The verbosity level ranging from 1 through 4 in decreasing importance order. The term 'high' and 'low' for log-level is based on its priority, thus 1 is the highest log-level.
type
Each log message belongs to a specific category:

info
Info or debug message without any consequence on the simulation.
error
An error occurred that prevents the simulation (or part of the simulation) from running properly. Note that error messages do not have any logging level and are always printed. If the sim->fail_on_warnings attribute is set to true, for example if Simics was started with the -werror command line flag, then Simics will exit with an error code when a log message of the error type is generated.
critical
Used to signal serious errors that the model may not be able to resume from. Simics will stop the simulation as soon as a critical error is logged.
unimplemented
A model does not implement a specific functionality, bit or register.
spec_violation
A model received commands from the target program that violates the device specification.

group
A bit-field, defined and registered by the module, used to separate different part of the device, for example to separate between the configuration of a device and using the device's services, or the PCI interface and the Ethernet interface, etc.

1.1.5 Events

When a device model wants some action to be taken at a later time, it posts an event and returns control to the simulation engine. This will cause a callback to be called after the requested simulated time has passed.

For example, a device that wants to raise a time interrupt every 10 ms would post an event with a callback that raises the interrupt and then reposts the event with a 10 ms delay.

The events are posted on a clock, which is usually one of the processor cores in the system. Typically, each device is associated with one clock on which it posts all its events, but it is possible to choose which clock to post on, as long as it is in the same simulation cell as the device.

Note: Some clocks, in particular the processor cores, also allow posting events on a step queue which doesn't count time, but CPU steps. This is usually not used by device models, but can be used for profiling extensions etc.
You can print out the current event queue by using the print-event-queue command (or peq for short).

1.1.6 Haps

Another way that models may react to Simics events is to use haps. (The term was chosen because happenstance was considered too long.) To react to a hap, a module can register a callback function to the hap. This callback function will then be called every time the hap occurs. A complete list of all haps, descriptions of what parameters the callback functions should take and all functions used to register callbacks and manipulate haps can be found in chapter 12.

In general, haps are slower than notifiers, and therefore less suitable for communication between models. However, haps allow sending additional parameters to the callback function.

1.1.7 Commands

A user interface for a module can be created by adding new commands to the Simics command line interface. Commands can be bound to a specific namespace (i.e., a class or an interface) or to the global namespace.

1 Introduction 1.2 Simics API Information