API Reference Manual
This manual contains the reference documentation for most Simics
APIs. It describes the Device API, as well as the interfaces and haps
that are available for developing models. The manual also describes
the Simulator API and its interfaces, for use when developing
extensions to Simics. Furthermore, the manual details the Link Library
API - that's used to create link models to connect devices in
different cells. The Processor API is used to create models of
processors for use in Simics; the reference documentation for the
Processor API is also present in this manual. The manual is concluded
with the reference documentation of the Python API.
This manual is primarily meant to be used as reference documentation, but it
also describes some concepts of central importance closely related
to the API. Refer to the other Simics manuals, listed in the
Documentation Contents document, for more details
about other things.
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
- Device Modeling Language (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++.
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.
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:
- A simple type is represented by a single letter:
i (integer),
f (floating), s (string), b (boolean), d
(data), o (object), D (dictionary), n (nil) or
a (all).
- You can match several types by using the operator
| like in
s|o (string OR object).
- Lists are defined by square brackets:
[ and ]. Lists can
be specified in three ways:
- Lists with a fixed elements:
[iffsb] matches a list of five
elements; an integer, two floating-point values, a string and a boolean
value.
- lists of an arbitrary number of elements:
[i*] and
[i+] both match any list containing only integers, with
the difference that [i*] will match an empty list, while
[i+] requires at least one list element.
- lists with a size specifier:
[i{1:4}] matches lists of
integers with 1 to 4 elements. [i{4}] is the same as
[i{4:4}] or [iiii], i.e., a list of four integers.
- The
| operator has higher precedence than juxtaposition in the
list type definitions, which means that [i|si|s] matches any
two-elements list with integer or string elements. For clarity you can use a
comma anywhere in the type definition, it will be ignored. The example could
be written as [i|s,i|s]
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.
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.
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.
warning- Warning message about a problem in the
simulation, which however still allows the simulation to
continue.
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.
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).
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.
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.
- Commands that are bound to classes can be used to manipulate
individual instances of that class. For example, all devices should
have an info command that prints static information about the
device and a status command that prints the state of the
device.
- Commands that are bound to interfaces can be used on all
objects implementing that interface.
- Global commands can be used for actions that do not pertain to a specific
object. This is the case of commands like output-radix or
print.
This chapter describes the organization of the Simics API,
and how to use it. It also shows how it interacts with
system, Device, Simulator, Processor, and Link Library APIs.
Simics provides a number of unique
APIs designed to allow the integration of new modules with the Simics family of
products.
The Simics API is partitioned into three major parts, and an additional three
groups of interfaces. There is one header file to include for each part of the
Simics API, while the interfaces are split over several independent header
files.
With a partitioned API the part needed by models can be kept as small and
simple as possible, and the boundary between models and the simulator
infrastructure is more clearly defined. A small Device API makes device
modeling easier and reduces the risk of writing code with the
potential to break determinism or multi-threading.
For a model representing a piece of hardware, you should
only need to use the Device API together with the
necessary model-to-model and model-to-simulator interfaces.
To find out how to get access to a particular API function or data type, you
can use the api-help CLI command. This will tell you
which header file, if any, to include (in either DML or C/C++).
The basic functionality of the Simics API and the only part available to device
models.
The Device API is always accessible from DML; from C/C++ it is available
using:
C: #include <simics/device-api.h>
C++: #include <simics/cc-api.h>
Interfaces between models typically represent standard hardware
interfaces such as PCI, IC, Ethernet and interrupt
lines. These interfaces are included in the Device API.
Accessible from DML and C/C++ using:
DML: import "simics/devs/interface.dml";
C: #include <simics/devs/interface.h>
C++: #include <simics/c++/devs/interface.h>
where interface should be replaced with the actual header file name.
To find out which header file the foo interface is defined in, you can
use the Simics CLI command api-help foo_interface_t.
These interfaces fall into two categories:
- Interfaces that models may implement, which are called by the
Simics framework.
- Interfaces implemented by the Simics framework or by Simics simulator
objects, which may be called by simulation models.
Interfaces included in this list are part of the Device API.
They are accessed from DML and C/C++ using:
DML: import "simics/model-iface/interface.dml";
C: #include <simics/model-iface/interface.h>
C++: #include <simics/c++/model-iface/interface.h>
where interface should be replaced with the actual header file name.
To find out which header file the foo interface is defined in, you can
use the Simics CLI command api-help foo_interface_t.
The Simulator API contains the complete Simics API, including parts that are
not available to models. This API may be used by simulator extensions.
Accessible from DML and C/C++ using:
DML: import "simics/simulator-api.dml";
C/C++: #include <simics/simulator-api.h>
Interfaces that are only used between simulator extensions and that
should not be used by any model are collected into this group. These
interfaces are part of the Simulator API.
Accessible from DML and C/C++ using:
DML: import "simics/simulator-iface/interface.dml";
C: #include <simics/simulator-iface/interface.h>
C++: #include <simics/c++/simulator-iface/interface.h>
where interface should be replaced with the actual header file name.
To find out which header file the foo interface is defined in, you can
use the Simics CLI command api-help foo_interface_t.
The Processor API extends the Device API with functions needed when modeling
processors in Simics.
Accessible from DML and C/C++ using:
DML: import "simics/processor-api.dml";
C/C++: #include <simics/processor-api.h>
The Link Library API extends device modeling capabilities with Simics by
allowing users to write Simics link models.
Accessible from DML and C/C++ using:
DML: import "simics/devs/liblink.dml";
C/C++: #include <simics/devs/liblink.h>
Simics users may utilize Python to interact with the Simics API. For
example, Python can be used to write or run Simics commands.
Python may also be used to write components and modules for Simics.
The API is accessible from Python by importing the respective
modules listed in chapter
10.
Python can also be used directly from the Simics command line and
in set-up scripts.
Device makefiles have a variable called SIMICS_API, which
specifies which version of the Simics API the model uses.
It is a good idea to set SIMICS_API to the current
Simics API. This will cause compile errors for uses of deprecated features.
SIMICS_API := 6
Python modules do not have a SIMICS_API flag to force compiler
checking and thus need to be checked manually. Command line options can be
passed to Simics to ensure any runtime usage of deprecated features trigger
errors.
On Linux,
Simics will register its built-in signal handlers to make
system calls restartable after the signal has been handled (cf. the
SA_RESTART flag in the
sigaction(2) man page).
However, only some system calls are restartable, so when writing
modules for Simics, you have to make sure that you restart the other
system calls yourself:
do {
res = accept(sock, &saddr, &slen);
} while (res == -1 && errno == EINTR);
Simics has its own text output routines that use the command-line
window for display and also allow output to be directed elsewhere. To
maintain this functionality these output routines
should be used instead of the standard C library output routines: Use
SIM_printf instead of
printf, SIM_putchar
instead of putchar, and so on.
The Simics output functions (SIM_write,
SIM_printf, etc.) also send the resulting text to handlers
registered using SIM_add_output_handler.
Here is an example showing how a module could get Simics to write a
copy of all its text output to a log file:
static void
output_handler(void *file, const void *buf, size_t count)
{
fwrite(buf, 1, count, (FILE *)file);
}
static void
init_local(void)
{
SIM_add_output_handler(output_handler,
(void *)fopen("my.log", "a"));
}
It is possible to write modules for Simics that use
POSIX threads, but only a restrictive part of the
Simics API can be used directly from such threads.
It is possible, however, to post callbacks that have
access to the entire API. One way to do that is through the
SIM_thread_safe_callback API function. It is also possible
to enter a context where a larger part of the Simics API is available.
This, and the threading model in general, is discussed in some
detail in chapter 2.
For modules written in C or C++, the general order of header file inclusion
should be from most to least general:
| Language |
e.g., <stdio.h> (C), <map> (C++) |
| Operating system |
e.g., <unistd.h> (Linux),
<windows.h> (Windows) |
| Simics |
e.g., <simics/device-api.h> |
| Application |
specific to your module |
When this order is observed problems related to interference between
include files should be minimized. In particular, Simics may redefine
some standard functions with preprocessor macros and this can cause
problems unless the standard headers are included first.
The owner of a value in memory is the code or object
responsible for freeing the value when it is no longer needed.
Failure to do so may cause excessive memory consumption
(a memory leak). Deallocation of objects that
are not owned, or use of objects after they have been freed, will
likely result in a crash.
The ownership rules only apply to code written in C, C++ and DML.
In Python, memory management is entirely
automatic.
The general rules in Simics are:
-
The caller of a function retains ownership of the arguments
it passes to that function. Called functions do not assume
ownership of the arguments they receive.
-
The caller of a function receives ownership of the value
returned from that function. Called functions must relinquish
ownership of values they return.
-
A return type
const T *, for some
type T, is taken to mean that ownership of the
returned value is not transferred to the caller,
overriding the previous rule.
Exceptions to the rules above are documented for each interface or
API call.
Each data type has its own way of deallocation. It is generally
documented where objects of that type are created; see below for
some specific examples.
- Strings
- Null-terminated strings are freed using
MM_FREE in C/C++,
delete in DML. They are created using
MM_MALLOC, MM_STRDUP
or other functions that create heap-allocated strings.
(The standard C library functions malloc,
free etc should not be used.)
The pointer-to-const rule applies: a string
returned as char * becomes owned by the
caller, but not one returned as
const char *.
- Attribute values
- Values of type
attr_value_t are freed
using SIM_attr_free.
Since the values may refer to heap-allocated data, they cannot
be copied by simple (shallow) assignment. To create a (deep)
copy of an attr_value_t that is safe to access
after the original has been freed,
use SIM_attr_copy.
The attr_value_t accessor functions return values
that borrow references to parts of the argument. Therefore, the
returned values cannot be altered, and cannot be used beyond
the life-time of the argument. (This obviously does not apply
to non-allocated values such as numbers or booleans.)
- Simics-managed types
- Values of some types are always owned and managed by Simics
itself and should never be freed by the user. Examples are
conf_object_t
and conf_class_t.
The set of Simics API functions and interface methods that can be
called at a given point depends on the state of the execution thread
at the time of the call. The thread states are classified into
API execution contexts. Three distinct execution
contexts are defined, and they are inclusive, as illustrated in
the figure below:
Below is a description of the defined execution contexts:
- Global Context
- Previously, this context was known as Outside Execution Context (OEC).
The most permissive context. A thread running in
Global Context has exclusive access to all objects in the simulation.
In Global Context, either the simulation is not running or
all simulation activity
has temporarily been suspended. The front-end runs in this
context, as do the callbacks from SIM_run_alone,
SIM_thread_safe_callback and
SIM_notify_on_socket with the
run_in_thread argument set to 0. Module initialisation,
object creation and object destruction are also performed in
this context.
The full API is available, including functions
and methods documented as callable in other contexts.
- Cell Context (EC/IC)
- This is a single context which was introduced in Simics 6 instead
of Execution Context (EC) and Instruction Context (IC) that were
around before.
The context used for most device simulation. Typically used
when the simulation is running.
Only functions and methods documented as callable in
Cell Context or Threaded Context are available in this context.
Other objects in the simulation may be accessed or referenced,
but only objects belonging to the same simulation cell.
The cell concept is discussed in some detail in section
2.3, but basically
it is a partitioning of the simulation into groups of objects.
Cell Context is always tied to a specific cell.
Most device code run in this context, for instance when
a CPU accesses a device register, as do event callbacks
and many hap handlers.
- Threaded Context
- Previously, this context was known as Foreign Thread Context (FTC).
The most restrictive context, denoting a thread which is
in neither Cell Context nor Global Context.
Manually created threads and SIM_run_in_thread callbacks
are examples where this context is applicable.
Thread-aware models, like a CPU with support for multicore threading,
also perform most of its simulation in Threaded Context.
The available API is limited to functions explicitly
declared as being available in Threaded Context, but
a more permissive context can be entered when needed. For example,
SIM_thread_safe_callback posts a
callback which is invoked in Global Context, and
Cell Context can be reached with
the SIM_ACQUIRE_CELL primitive.
While objects can be accessed in this context, it is only permitted
after special primitives are used to ensure single-threaded access.
This usually amounts to entering Cell Context, but
thread-aware models can actually access their own object
state directly from Threaded Context. This is discussed in
chapter 2.
The reference manuals detail the permitted API execution context for
each API function and interface method. Calls are allowed in the
specified and more permissive contexts.
Violations of the API execution context rules have undefined
consequences. They may result in warnings or error messages, but this
is not guaranteed. In particular, a class implementing an interface
method is under no obligation to perform any such checks.
Most of the information in this chapter uses C syntax, extended with two
additional keywords:
NOTNULL- The
NOTNULL keyword means that this function argument must not
be a null pointer. In Python, where None is used as the null
pointer value, there will be an exception thrown if such a function is
called with a None value. PYTHON_METHOD- Most interfaces are in canonical form; i.e., they only contain function pointers, and the
first argument is always the object whose interface is called.
For non-canonical interfaces, the keyword PYTHON_METHOD is used to
mark regular methods. These should be called without their first
argument when used from Python.
Note that there is no special mark-up for canonical interfaces.
This chapter describes the Simics threading model from a device
model perspective. Important concepts as cells,
thread domains and execution context are explained
in some detail. The Standard Device Model and the
Threaded Device Model are also defined.
At the highest level, a Simics configuration is partitioned
into one or multiple simulation cells. Each cell can be
simulated in parallel with the other cells, with maintained determinism.
Distinct cells are loosely coupled. A typical example is a
multi-machine configuration, where each machine consists of a single cell,
and where the machines are connected with a simulated Ethernet network.
Communication between cells occurs through special objects called
links that forward messages between cells.
A device model should not access objects belonging to a different
cell directly.
Each cell is partitioned into one or more
thread domains. Models belonging to different thread domains
can be simulated in parallel. However, objects within a single thread domain
can only be accessed by a single thread at a time, namely by the
thread currently holding the domain.
A thread domain should be thought of as a high-level locking construct
ensuring single-threaded access to the objects it contains.
Unlike the cell partitioning, which is static and given by the configuration,
the partitioning of a cell into thread domains is performed by Simics as a
function of the selected simulation mode, model capabilities, and
any declared thread domain constraints.
The thread domains in a cell are not all equal. The thread domain which
contains the cell object itself is special and is called the cell thread
domain (cell TD). Objects residing in this domain use a very permissive
device model, the Standard Device Model, described in
section 2.6. Among other
things, such models do not need to worry about thread domain boundary
crossings or threading issues. Most models use this device model.
Models located in thread domains other than the cell TD are called
thread-aware, and use the more restrictive Threaded Device Model,
which is described in section 2.7.
The threads used to actually simulate the models are usually created by
Simics, but models can also create their own threads. The Simics scheduler is
briefly discussed in section 2.9.
To use multi-threading in Simics, all modules used in the
simulation must be thread safe. This section describes what it means
for a module to be thread safe, and what conditions must be fulfilled.
Note:
In this section, thread safe is used in the sense that models
instantiated in different cells can be simulated
concurrently without issues. This is a weaker definition than normally used.
Simics checks each module it loads to see if it has been marked as
safe. A module is thread safe if it fulfills the following conditions:
- It must run without execution context violations.
- The module makefile variable THREAD_SAFE must be set to
yes when compiling the module.
Below is an example makefile for a module marked as thread safe.
It can be found in the
[project]/modules/sample-user-decoder directory
if the sample-user-decoder has been copied to the
project.
MODULE_CLASSES = sample-user-decoder
SRC_FILES = sample-user-decoder.c
SIMICS_API := 6
THREAD_SAFE = yes
include $(MODULE_MAKEFILE)
To make a module thread safe, global state should be avoided, both in
the form of global variables and in the form of local static
variables in C. Having constant global variables are fine. Modules written
in pure DML do not have this problem since the DML compiler
does not emit any non-constant global state.
Simics checks for some execution context violations during
run-time and emits warnings if they occur. When running
with multi-threading disabled, violations result in warnings that can
optionally be turned off. With multi-threading enabled,
violations cause hard errors.
If a module that is not marked with THREAD_SAFE=yes is
loaded, multi-threading will be turned off automatically and a warning
will be shown. The list-modules command will show whether a
module is marked thread safe or not.
A cell is a group of configuration objects which may interact with
each other through direct function calls. If a model needs to
communicate with objects in other cells during the simulation, it
needs to do this through links (see section 2.3.4 or the Link Library Programming Guide). A link
introduces a delay in the communication
(unless immediate_delivery is set), which means that
messages cannot be sent and received in the same cycle.
In a configuration, a cell is represented by a configuration object of
class cell. All objects that implement the cycle
interface (referred to as clocks) automatically have a cell
attribute that will point to the cell they belong to. Since all Simics objects
have a queue attribute pointing at a clock object, they will by
extension belong to the cell of their clock object. This is illustrated
in the figure below:
Another example is the following configuration:
OBJECT cell0 TYPE cell {
}
OBJECT cell1 TYPE cell {
}
OBJECT cpu0 TYPE cpu {
cell: cell0
}
OBJECT cpu1 TYPE cpu {
cell: cell0
}
OBJECT cpu2 TYPE cpu {
cell: cell1
}
OBJECT device0 TYPE device {
queue = cpu0
}
OBJECT device1 TYPE device {
queue = cpu0
}
OBJECT device2 TYPE device {
queue = cpu2
}
In this example, device0 has cpu0 as a queue, and thus
belongs to cell0, while device2
has cpu2 as a queue, and thus belongs to cell1.
Simics provides an
automatic cell partitioning based on top-level components. Each
component object implements a create_cell()
method that can
return True or False to the question:
should a simulation cell be created to contain this component and all
its sub-components? By default, top-level components return
True and all other components return False.
By overriding this method, it is possible to
automatically create cells at lower levels in the component hierarchy,
or to disable cell creation altogether. In the latter case, the
create_cell() should return False and the
components should define cell objects themselves and assign clocks to
them as appropriate, just as normal configuration objects.
The code snippets below show how to overload
the create_cell() function for both old-style and hierarchical
way of writing components.
class mycomp(component_object):
...
def create_cell(self):
return False
class mycomp(StandardConnectorComponent): # or StandardComponent
....
class component(comp.StandardComponent.component):
def create_cell(self):
return False
Cells can also be created independently of components, by
creating cell objects and setting the cell
attribute of the clock objects which should belong to the cell.
If clock objects are created that do not point to a cell, then
a default_cell object will be created, unless it exists already,
to make sure these clock objects are scheduled as intended.
This is a simple compatibility mechanism for use with older scripts.
If you are building your configurations in several steps, but without
using components, you will have to introduce your own cells and configure them.
The check-cell-partitioning command checks
either a checkpoint or the currently loaded configuration for
violations of the cell partitioning rules—namely, that
objects belonging to one cell do not have any references to
objects in another cell. Such references will be shown
in the form of a chain of attributes connecting the cells.
An object is considered to belong to a cell if either it is a cell
object, or if it refers to or is referred to by an object belonging to
that cell. Object references are object values in (checkpointed)
attributes.
False positives can be suppressed by defining the attribute
outside_cell and setting it to true for objects
that should not be considered part of any cell but still refer
to other objects in cells. This can be necessary for objects
that only use these references in safe ways, e.g., in Global Context.
Links are the only Simics objects that should connect different cells
together. In other words, link components are allowed to connect to
device components
belonging to different cells without breaking the cell isolation rules. This
works because all communication over the links are asynchronous with a delay
that is constrained by the synchronization parameters so that the information
exchange never becomes indeterministic.
Note:
While it is possible to perform cross-cell calls if special
precautions are taken, it should be avoided since it likely prevents the
simulation from being deterministic even when the simulation is
running in the "serial" threading mode.
All cells are connected to a synchronization domain that
controls the execution in the cells to ensure that they do not run too
far apart in virtual time. The domain has a min_latency
parameter that limits the allowed difference in time between clocks in
all the cells connected to it. This works as a lower limit for the
latency that link objects can use when communicating between cells.
Each object in the simulation has a thread domain associated with it. The same
thread domain can be associated with multiple objects.
The basic rule is that before the state of an object is accessed, the
corresponding thread domain needs to be held by the thread performing the
access. This ensures that an object is never accessed concurrently
by two different threads.
The thread domain containing the cell object, the cell thread domain
(cell TD), has some special properties. Sometimes it is referred to as just
the "cell" for brevity, as in "acquiring the cell", and "holding the cell",
which should be read as "acquiring the cell thread domain", and
"holding the cell thread domain" respectively.
The cell TD should be thought of as a single-threaded domain.
To a model in the cell TD, everything in the entire cell appears to be
simulated from a single thread, even if this is not the case.
Note:
In most cases, the appropriate thread domain is already held, and no
special action needs to be taken. This is for instance the case for normal
device models, which run in Cell Context, or for code running in
Global Context.
Only models which use custom threads or use the Threaded Device Model
need to acquire thread domains explicitly.
The relationship between the API execution context, defined in
section 1.3.2, and thread domains
is as follows:
- Global Context
- All thread domains (and by implication, all cells) in
the simulation are held by the thread.
The thread has exclusive access to all objects. CLI scripts,
Python scripts, CLI commands, script-branches, and
object initialization code, all run in Global Context.
- Cell Context
- The cell TD is held by the thread. The thread can freely
access all other objects in the cell. Normal device models (i.e. models
which are not thread-aware) can assume that they are invoked in this
context.
- Threaded Context
- No thread domains are required to be held, but thread-aware models
often hold their own thread domain.
Note:
The locking model in Simics is asymmetrical. Models running in
Cell Context can call interface functions on any object in the cell
without taking any special measures, and this includes interfaces on
objects belonging to a different TD. This is possible since thread-aware
models are required to guard model entry points by acquiring
their own domains. Conversely, thread-aware models are required to enter
Cell Context explicitly, by using a special API call, before
calling interface functions on objects in the cell TD.
A thread domain has the following basic properties:
- Exclusive - a thread domain can only be held by a single thread at
a time
- Recursive - a thread domain can be acquired multiple times
by the same thread
- Extendable - multiple thread domains can be held simultaneously
by a thread, and the thread may access any object whose thread domain is
held.
The following macros are used to acquire thread domains.
- SIM_ACQUIRE_OBJECT
- Acquires the thread domain associated with the object.
This function is intended to be used by thread-aware objects
to obtain its own thread domain before modifying internal state
protected by the domain.
This primitive does not enter Cell Context, even if the
cell TD is acquired. The reason is that the retention mechanism
is not activated (see below).
- SIM_ACQUIRE_TARGET
- Enters Cell Context if the specified object belongs
to the cell TD. As part of entering Cell Context,
the cell TD is acquired.
This primitive does nothing if the object does not belong to
the cell TD. In other words, it is a no-op if the specified
object is thread-aware.
Thread-aware code, which is not running in Cell Context, uses this
function before invoking an interface method on an external object.
- SIM_ACQUIRE_CELL
- Enters Cell Context unconditionally. The specified object
is associated with a cell whose TD is acquired as part of entering
Cell Context.
The function should be used before calling an API function, or callback,
requiring Cell Context.
Each primitive above
should be used together with the corresponding release function.
Macros are used in order to allow lock statistics to be collected
with information about where the lock was acquired. There are also
corresponding SIM-functions available.
Note:
If multiple thread domains are acquired, then they must be released
in strict reverse order. Failure to do so will result in a hard error
and a complaint about locks being released in an incorrect order.
Note:
The difference between
SIM_ACQUIRE_CELL and
SIM_ACQUIRE_TARGET is really that the former
always acquires the
cell thread domain and enters Cell Context, whereas the latter is a
no-op when a thread-aware object is specified.
The reason for the distinction is that thread-aware objects
are required to protect incoming as needed; this self-protection
usually involves a call to SIM_ACQUIRE_OBJECT, but
models are free to use alternate locking schemes.
Note:
This section describes how Simics handles thread domain contention,
and it is mostly provided to allow for a deeper understanding of the
Simics threading model.
When a thread tries to acquire a thread domain which is already held or
requested by another thread, then the following happens:
- The thread is assigned a priority, using the table below.
- All domains held by the thread are released and marked as contended
- The current holder of the requested domain is notified that a thread
is waiting for the domain, and the domain is marked as contended.
- The thread is blocked until all needed domains are available and can
be assigned to the thread. Among all threads waiting for a domain,
the domain can only be assigned to the thread with the highest priority.
The priority is assigned as follows:
-
| Priority | Name | Situation |
| 1 | Execute |
TD acquired for instruction execution (lowest priority)
|
| 2 | Yield |
domains reacquired after explicit yield
|
| 3 | Entry |
TD acquired, no other domains held
|
| 4 | Entry 2 |
TD acquired, other TDs already held
|
| 5 | Cell Entry |
cell acquired with
SIM_ACQUIRE_CELL/TARGET
|
| 6 | Elevated |
TD acquired in Cell Context
|
| 7 | Message |
TD acquired for delivery of direct memory message
|
In the table above, TD stands for a thread domain which is not the cell TD.
A contended thread domain is always assigned to the waiting thread with
the highest priority. The domain is never released to a thread with lower
priority, even if the domain is unused and the highest priority thread is
waiting upon some other domain.
The priority scheme serves two purposes:
- It ensure that a deadlock situation cannot occur.
- It ensures that a thread in Cell Context is not preempted
by other threads when there is lock contention.
Note:
For performance reasons, a thread waiting for a thread domain will typically
spin for a certain amount of time before falling back to sleeping on some
condition variable.
In Cell Context, a special mechanism is used when
additionally acquired thread domains are released:
- Domain retention mechanism
- The release of additionally acquired domains is deferred until
Cell Context is exited, or in other words, until the cell TD
is released.
As an example, consider a thread doing the following, with CPU1 belonging
to thread domain TD_cpu1, CPU2 to TD_cpu2, and device DEV to TD_cell,
respectively:
- CPU1 is simulated while holding TD_cpu1
- EC is entered before the model calls an interface on DEV.
TD_cell is acquired when EC is entered.
- device DEV queries CPU2 for its cycle count. The TD_cpu2 domain is
acquired and released during this operation, but the actual release
of TD_cpu2 is deferred by the retention mechanism
- device DEV posts an event on CPU2, again taking and releasing TD_cpu2
- TD_cell is released when the DEV interface call returns, and
the thread leaves Cell Context. The retention mechanism causes TD_cpu2
to be released for real at this point
The retention mechanism ensures that TD_cpu2, in the example above, is
held until the device access is complete. Between point 3 and point 5,
CPU2 will not be simulated, and its state will be stable.
Note:
The retention mechanism ensures that a device model sees
a stable state for all objects it interacts with. The mechanism allows
CPUs to run concurrently with device models, but when a
device model interacts with a CPU, it is stopped until the device
operation is complete.
A device model can run in one of three concurrency modes. The modes are as
follows:
Sim_Concurrency_Mode_Serialized- The model can assume Cell Context.
The model is put in the cell thread domain.
The device may interact with all
objects in the cell without having to acquire any thread domains or take
threading into account.
Objects in the same cell, including objects belonging in other
thread domains, always have a stable state when queried.
Sim_Concurrency_Mode_Serialized_Memory- The model runs in Threaded Context.
The model is put in a separate thread domain.
The model is required to handle locking explicitly for both incoming and
outgoing interface calls.
Whenever the model crosses a thread domain boundary, or enters
Cell Context, all devices
in the cell can potentially undergo state transitions.
Models that share memory must be grouped together (see the section on
Thread Domain Groups below).
Sim_Concurrency_Mode_Full- The model runs in Threaded Context.
The model is put in a separate thread domain.
The model is required to handle locking explicitly for both incoming and
outgoing interface calls.
Whenever the model crosses a thread domain boundary, or enters
Cell Context, all devices
in the cell can potentially undergo state transitions.
The model cannot assume that pages granted through the direct-memory
subsystem are not accessed concurrently from a different thread, unless
exclusive access have been requested explicitly.
Note:
The concurrency mode basically only affects whether the model is put in the cell
thread domain or not. Simics cannot automatically detect needed grouping of models,
therefore it is the responsibility of the platform developer to assure that models
are grouped in a correct way.
A model advertises its supported concurrency modes through the
concurrency_mode interface. If the interface is omitted,
and the object is not grouped with an object implementing the
concurrency_mode interface (see the next section), then the
model is assumed to only support
Sim_Concurrency_Mode_Serialized.
If the model supports multiple modes, the interface is also used by
Simics to select the concurrency mode the model should use. The mode
is derived from the simulation mode set through the
set-threading-mode command.
Device models normally run in the serialized concurrency mode, whereas
CPU models preferably should support all the modes.
Note:
The
set-threading-mode command is used by the user to set
the threading mode of the simulation.
The "serialized" mode puts models in the serialized
concurrency mode.
The "subsystem" mode configures models to use the serialized
memory concurrency mode, if supported, and serialized mode
otherwise.
The "multicore" mode configures models to use the full
concurrency mode, if supported, and serialized memory or
just serialized mode otherwise.
Objects that are part of a thread domain group will be put in the same
thread domain. There can be different reasons for models to be part of the
same thread domain. To keep memory accesses serialized when subsystem threading
is used all models that share memory should be put in the same group.
Even when running in multithreading mode there are objects that should reside
in the same thread domain.
Examples include:
- a CPU and an object representing its TLB
- a CPU and a CPU-specific timer
- two hyper threads which share a substantial amount of registers
and whose implementation is not thread safe
When forming thread domain groups, Simics queries all objects implementing
the concurrency_group interface. The interface returns
constraints of the type "these objects should be put in the same thread domain",
and they are of two kinds:
- constraints that are used in all concurrency modes
- constraints that are only used in the serialized memory mode.
A port object is always placed in the same thread domain as
its parent, unless it implements the concurrency_mode interface
or is grouped explicitly with such an object.
For CPU models, the following is recommended:
Sim_Concurrency_Mode_Serialized_Memory- Tightly connected CPUs are grouped together.
In this context, tightly connected really means CPUs that run
the same OS instance. CPUs which run distinct OS instances,
but share memory, or devices, through
some fabric, do not need to be placed in the same group.
Sim_Concurrency_Mode_Full- All CPU cores are placed in separate thread domains.
The above allows groups of tightly coupled CPUs
to be simulated in parallel when the simulation is configured
to use subsystem threading, while allowing all the CPUs to
run in parallel in multicore mode.
By default, devices in Simics use the Standard Device Model. Such
models run in the Sim_Concurrency_Mode_Serial
concurrency mode.
Using the Standard Device Model amounts to being able to assume at
least Cell Context when interface methods are invoked. Certain things,
like object initialization, run in Global Context, which is
the most permissive context.
Cell Context has the following properties:
- Any object belonging to the same cell may be accessed or referenced.
Interfaces marked as available in Cell Context can be
called directly without any additional steps.
- Accessed objects always have a stable state.
- The cell thread domain is held.
- The direct memory subsystem ensures that there is no observable
concurrency with respect to simulated RAM.
In Cell Context, everything within the cell appears
to be completely serialized. Under to hood, this may not be the case, and
CPUs might be running concurrently. But when a CPU is accessed from a
device, it is stopped until the device access is complete. For instance,
a device will always see a stable cycle count when it repeatedly
queries its associated clock during a register access.
An object using one of the concurrency modes
Sim_Concurrency_Mode_Serialized_Memory or
Sim_Concurrency_Mode_Full is called a thread-aware
model. The Threaded Device Model must be followed by such objects.
Thread-aware models run mostly in Threaded Context.
This section primarily discusses thread-aware models, but much of the
contents also applies to code invoked directly from a "foreign" thread.
Note:
A CPU is the typical example of a thread-aware model. Most devices should
rather use the Standard Device Model.
Thread-aware models need to take the following into account:
- Incoming Interface Calls
- Interfaces implemented by thread-aware models can be invoked in
Threaded Context rather than Cell Context, and the thread
domain associated with the object cannot be assumed to be held on entry.
It is the responsibility of the model to ensure that its state is
protected, usually by calling SIM_ACQUIRE_OBJECT
from its interface methods, as in the following example:
static void
some_interface_method(conf_object *obj)
{
domain_lock_t *lock;
SIM_ACQUIRE_OBJECT(obj, &lock);
/* ... internal state is protected by the TD ... */
SIM_RELEASE_OBJECT(obj, &lock);
}
No extra protection is needed for interfaces which are only available
in OEC. All thread domains are already held on entry.
Note:
There are a few situations when the model is invoked with
its thread domain already held:
-
The run method of the
execute
interface is invoked with the object's thread domain held.
The model should not acquire the domain again, since this
would block the signaling mechanism used to notify the model
when another thread tries to acquire the domain.
-
The methods in the the
direct_memory_update
interface are always invoked with the thread domain held.
- Outgoing Interface Calls
- When a thread-aware model invokes an interface method on an
object which is not known to reside in the same thread domain,
then the call must be protected with SIM_ACQUIRE_TARGET,
with the interface object provided as an argument.
This ensures that Cell Context is entered, when necessary.
Example of an "outgoing" interface call:
domain_lock_t *lock;
/* incoming interface calls may occur here */
SIM_ACQUIRE_TARGET(target_obj, &lock);
some_interface->some_method(target_obj, ...);
SIM_RELEASE_TARGET(target_obj, &lock);
Note:
If the target object is thread-aware, then
SIM_ACQUIRE_TARGET will actually be a no-op.
Note:
If the cell TD is busy when SIM_ACQUIRE_TARGET is executed,
then the model may see incoming interface calls while waiting for the
domain, since all held domains are temporarily released while
waiting.
- API Calls
- Cell Context must be entered before any API function can be called
which requires this context. The context is entered with
the SIM_ACQUIRE_CELL primitive, as in this example:
domain_lock_t *lock;
/* incoming interface calls may occur here */
SIM_ACQUIRE_CELL(obj, &lock);
/* this code runs in Cell Context */
breakpoint_id = SIM_breakpoint(...);
SIM_RELEASE_CELL(obj, &lock);
Some functions that need this protection:
- HAP functions (SIM_hap_add_callback, ...)
- SIM_breakpoint, SIM_delete_breakpoint
- SIM_issue_transaction
There are, however, many functions that can be called directly
in Threaded Context, e.g.
- functions performing logging (SIM_log_info, ...)
- functions returning constant object properties
(SIM_object_name, SIM_get_interface, ...)
- allocations (MM_MALLOC,
SIM_alloc_attr_list, ...)
- accessors (SIM_attr_integer,
SIM_transaction_is_read, ...)
- dbuffer API (but the dbuffer itself is not thread safe)
- SIM_run_unrestricted, SIM_run_alone
Some API functions can be called directly, as long as the TD has
been acquired for the object in question:
- event related functions (SIM_event_post_cycle, ...)
- time related functions (SIM_time,
SIM_cycle_count, ...)
- Callbacks
- Callbacks triggered by the model are often expected to
be dispatched in Cell Context. The model must
enter Cell Context using SIM_ACQUIRE_CELL
before dispatching such callbacks.
Note:
Events registered with the Sim_Event_No_Serialize flag
and callbacks used by the CPU instrumentation framework do not need to be
protected. For these callbacks, it is the callee's responsibility to be
aware that the context can be more limited than Cell Context.
This is a performance optimization to allow fast callbacks with
minimal overhead.
- Attributes
- Registered attribute setters and getters are automatically protected;
an object's thread domain is always held when attribute setters and getters
are invoked.
Note:
Attributes should be used for configuration and to hold
state. Attributes should never be used for communication between
objects during simulation.
Whenever a thread-domain boundary is crossed, already held
domains may temporarily be released to avoid deadlock situations.
This allows unrelated, incoming, interface calls to occur at such points.
A thread-aware model must ensure that potential state changes caused
by incoming interface calls are taken into account. This is one of the
challenging points when writing a thread-aware model.
In Cell Context, boundary crossings are not an issue, since this
context is prioritized exactly to avoid unexpected
interface calls. Thread-aware models, running in Threaded Context,
are not as fortunate and need to be aware of the possibility.
It is recommended that incoming interface calls are kept as
simple as possible for thread-aware models. If possible,
the interface action should be deferred and handled from an
inner loop, especially for CPUs. For instance, a RESET interface
should not perform the reset immediately, but instead set a flag that
a reset should be performed before dispatching the next instruction.
It is easy to run into problems when different locking schemes
are combined. This is also the case when mixing mutexes
and thread domains. The following examples illustrate some
pitfalls:
- Example 1
- Acquiring a thread domain while holding a lock:
Thread 1 Thread 2
Locks Mutex1 Acquires TD1
Acquires TD1 (blocks) Locks Mutex1 (blocks)
Thread 1 will never be able to acquire TD1 since this domain is held by
thread 2 which blocks on Mutex1.
Note that the above example will also cause a deadlock if two mutexes
are used rather than one mutex and one thread domain:
Thread 1 Thread 2
Locks Mutex1 Locks Mutex2
Locks Mutex2 (blocks) Locks Mutex1 (blocks)
Whereas no deadlock occurs with two thread domains:
Thread 1 Thread 2
Acquires TD2 Acquires TD1
Acquires TD1* Acquires TD2*
*Not a deadlock - Simics detects and resolves this situation
- Example 2
- Waiting for a condition variable while holding a thread domain:
Thread 1 Thread 2
Acquires TD1 .
Waits for COND1 Acquires TD1 (blocks)
Releases TD1 (not reached)
.
Signals COND1 (not reached)
Sleeping on a condition while holding a thread domain easily
leads to deadlocks. Threads requiring the thread domain
will get stuck and potentially prevent the condition from being
signaled.
In practice, code can seldom make assumptions about which thread domains
are held. For instance, an interface function can be invoked with an
unknown set of thread domains already acquired. The domain retention mechanism
also makes the picture more complex.
To avoid deadlocks, the following general principles are encouraged:
- Do not acquire a thread domain while holding a lock
- Do not sleep while holding a thread domain
- Use thread domains to prevent concurrent simulation
- Use mutexes to protect specific data structures
When needed, it is possible to drop all thread domains,
which is illustrated in the following example:
domain_lock_t *lock;
SIM_DROP_THREAD_DOMAINS(obj, &lock);
/* no thread domains are held here... */
SIM_REACQUIRE_THREAD_DOMAINS(obj, &lock);
Note:
Avoid empty drop/reacquire pairs. If the intention is allowing
other objects to access held domains, then
SIM_yield_thread_domains should be used instead. The yield
function, besides being faster, guarantees that all waiting
threads are given an opportunity to acquire the held domains.
Thread-aware CPUs have a few extra things to consider.
- Execution
- CPU models are driven from the run method
of the
execute interface. The method
is invoked in Threaded Context, with the CPU thread
domain already held.
The thread calling run is a simulation thread
managed by the Simics scheduler. It is possible that this thread
is used to simulate more than one model.
The model is not guaranteed that the run function is always
invoked by the same thread.
- Signaling
- Whenever another CPU, or a device model, tries to acquire the
CPU domain, the CPU is notified through the
execute_control
interface.
When a CPU is signaled in this way, it should as soon as possible
call SIM_yield_thread_domains. The yield function ensures
that pending direct memory update messages are delivered and allows
other threads to invoke interfaces on the CPU object.
The signaling methods are invoked asynchronously, and the implementation
must not acquire any thread domains or call API functions.
The signaling only occurs when the CPU's thread domain is the only
domain held. Acquiring an additional domain, even the already held domain,
temporarily blocks the signaling mechanism. Due to this, it is
important that the CPU thread domain is not acquired in the
run method, since it is already held on entry.
Note:
To minimize the waiting time for other threads, it is important
that the signaling is detected quickly.
- Direct Memory
- The methods of the
direct_memory_update interface
are invoked with the CPU thread domain already acquired.
The model should service requests quickly and without
acquiring additional thread domains.
Statistics about thread-domain acquisition can be collected with the
enable-object-lock-stats command. This functionality is useful
when a model is optimized to avoid unnecessary thread-domain
crossings or to investigate thread-domain contention.
There is a definite overhead associated with collecting the
statistics; it should not be turned on by default.
The collected statistics can be shown with the
print-object-lock-stats command:
┌─────┬───────┬─┬────────────────────────────┬─────────────────────────────────┐
│Count│Avg(us)│ │ Function │ File │
├─────┼───────┼─┼────────────────────────────┼─────────────────────────────────┤
│ 396│ 1.94│ │get_cycles │core/clock/clock.c:172 │
│ 369│ 1.91│ │post │core/clock/clock.c:254 │
│ 27│ 2.00│C│handle_event │core/clock/clock-src.c:211 │
│ 12│ 2.33│ │pb_lookup │core/common/image.c:3965 │
│ 7│ 2.86│C│cpu_access │cpu/cpu-common/memory.c:508 │
│ 8│ 2.38│C│perform_io │cpu/x86/x86-io.c:128 │
│ 6│ 1.83│ │dml_lookup │core/common/memory-page.c:431 │
│ 3│ 3.00│C│call_hap_functions_serialize│core/common/hap.c:1410 │
│ 3│ 2.33│ │cancel │core/clock/clock.c:280 │
└─────┴───────┴─┴────────────────────────────┴─────────────────────────────────┘
The command basically displays the location in the source where thread
domains have been acquired, and how quickly the domains were acquired.
The 'C' indicates that Cell Context was entered.
Threads created explicitly by models are called foreign threads.
Such threads run in Threaded Context. There are also
various API functions that registers callbacks that are called in FTC, like
SIM_run_in_thread and SIM_notify_on_socket with
the run_in_thread argument set to 1.
Many of the things stated in the preceding section is also relevant to foreign
threads. One difference, however, is that foreign threads can be created by
models using the Standard Device Model.
The following outlines how a foreign thread can interact with the
rest of the simulation:
- Accessing a Device Object
- A foreign thread can enter Cell Context using the
SIM_ACQUIRE_CELL function. Once in Cell Context, the thread
can interact with the object just like a normal device would do,
and without needing any additional locking.
/* foreign thread */
SIM_ACQUIRE_CELL(obj, &lock);
/* safe to access the device */
SIM_RELEASE_CELL(obj, &lock);
- Entering Global Context
- A foreign thread can post callbacks that are run
in Global Context, and hence
allowed to access everything in the simulation. This
is done using SIM_thread_safe_callback
static void
global_context_callback(void *data)
{
/* this code runs in Global Context */
}
{
/* ... Threaded Context ... */
SIM_thread_safe_callback(global_context_callback, data);
}
It should be noted that the function posting the callback returns
immediately, usually before the callback has started executing. Also,
posting a Global Context callback is a relatively expensive operation
since it involves stopping all running CPUs.
The Simics scheduler is responsible for ensuring that models implementing the
execute interface are scheduled. It is also
responsible for mapping actual threads to the simulation workload and
for keeping distinct CPUs synchronized in virtual time.
The Simics Scheduler compiles a list of simulation tasks that can be
run in parallel. Each task consists of a thread domain with
one or more models implementing the execute interface.
The number of tasks that can be simulated in parallel depends on the
thread domain partitioning, which in turn depends on the selected
simulation mode. The simulation mode is configurable with the
set-threading-mode command.
The available tasks are mapped to a set of execution threads
managed by the scheduler. The number of threads used
depends on the host hardware and any limit imposed by the user.
The latter is settable with the set-thread-limit command.
A particular simulation task is usually simulated from a specific
simulation thread in order to maximize cache locality. However, a task can be
migrated to another thread when this is needed for load-balancing reasons.
Thus, a model should not make any assumptions about the thread it is simulated
from.
The scheduler ensures that all CPUs (and clocks) are kept synchronized
in virtual time. More specifically, the virtual time for
a pair of CPUs are not allowed to differ more than a fixed amount.
A simulation task becomes blocked when it is about to break this
invariant.
If a single thread domain contains more than one object implementing the
execute interface, then the scheduler switches between
them in a round-robin fashion. Each executor is simulated until the
virtual time has advanced one time-quantum. The interval
is settable with the set-time-quantum command.
The time difference for CPUs in the same cell, but in distinct
thread domains, is not allowed to exceed the max-time-span
limit. The limit is settable with the set-max-time-span
command and is usually of the same order of magnitude as the time quantum.
The time difference between CPUs in distinct cells is kept below
the min-latency limit. This limit is set with
the set-min-latency command. The min-latency is often allowed
to be a bit higher than the other limits.
The Simics Device API is a set of types and functions that provide access
to Simics functionality from device models, usually written in DML or
C/C++. The Device API is the same in all languages but the syntax of the
types and functions declarations will of course differ.
Whenever an error occurs in a Simics API function, that function will raise
an exception. An exception consists of an exception type and
an error message.
The following exception types are defined in the Simics API:
typedef enum sim_exception {
SimExc_No_Exception,
SimExc_General,
SimExc_Lookup,
SimExc_Attribute,
SimExc_IOError,
SimExc_Index,
SimExc_Memory,
SimExc_InquiryOutsideMemory,
SimExc_InquiryUnhandled,
SimExc_Type,
SimExc_Break,
SimExc_PythonTranslation,
SimExc_License,
SimExc_IllegalValue,
SimExc_InterfaceNotFound,
SimExc_AttrNotFound,
SimExc_AttrNotReadable,
SimExc_AttrNotWritable
} sim_exception_t;
Note that API users writing in C must use SIM_clear_exception()
and SIM_last_error() since C does not support exceptions. In
Python, the Simics API exceptions will trigger actual Python exceptions,
which you can capture using try ... except.
- NAME
-
attr_value_t
- DESCRIPTION
-
The
attr_value_t is the type used for all values in the
configuration system. It is a tagged union.
The following table shows the different types of values, the type of their
payload in C, and the corresponding Python types:
| Kind | C payload | Python type |
| Invalid | - | raises exception |
| String | const char * | str or unicode |
| Integer | int64 or uint64 | int or long |
| Boolean | bool | bool |
| Floating | double | float |
| Object |
conf_object_t * | simics.conf_object_t |
| List |
array of attr_value_t | list |
| Dict |
array of pairs of attr_value_t | dict |
| Data |
array of bytes | tuple of small integers |
| Nil | - | None |
The members inside attr_value_t should not be accessed
directly. Instead, use the corresponding functions for each type:
| Constructor | SIM_make_attr_TYPE |
| Destructor | SIM_attr_free |
| Type predicate | SIM_attr_is_TYPE |
| Access | SIM_attr_TYPE |
Values of type List and Dict can be modified using
SIM_attr_TYPE_set_item and
SIM_attr_TYPE_resize.
None of these functions are available or needed in Python. The
attr_value_t values are translated to the ordinary Python
values as shown in the table above.
Some values may have data in separate heap allocations. These are normally
managed by the respective constructor and destructor methods, but careless
copying of values may introduce aliasing errors. Use
SIM_attr_copy to duplicate values. Again, this is of no concern
in Python.
- SEE ALSO
-
SIM_make_attr_int64, SIM_attr_is_integer,
SIM_attr_integer, SIM_attr_free,
SIM_attr_list_resize, SIM_attr_list_set_item,
SIM_attr_dict_resize, SIM_attr_dict_set_item,
SIM_attr_copy
- NAME
-
buffer_t
- SYNOPSIS
-
typedef struct {
uint8 *data;
size_t len;
} buffer_t;
- DESCRIPTION
-
A reference to a (mutable) buffer. When used as a function parameter,
the callee is permitted to write up to
len bytes into
the buffer pointed to by data.
Returning values of this type from interface methods should be
avoided. If this is the case the scope of the returned object should be
documented.
The corresponding Python type is called buffer_t,
and behaves like a fixed-size mutable byte vector. The constructor
takes as argument either a string, providing the initial value,
or an integer, specifying the buffer size.
- NAME
-
bytes_t
- SYNOPSIS
-
typedef struct {
const uint8 *data;
size_t len;
} bytes_t;
- DESCRIPTION
-
An immutable sequence of bytes. When used as a function parameter,
the callee should treat the data as read-only.
When used as a return value, the data member must point to a
heap-allocated memory block whose ownership is transferred to the
caller. The caller is then responsible for freeing the block.
The corresponding Python type is Python's built-in class 'bytes'. Here
are a few code examples that create 'bytes' objects in Python:
b'abcd', b'\xf0\xf1\xf2\xf3', bytes([0xf0, 0xf1, 0xf2, 0xf3]),
0xf3f2f1f0.to_bytes(length=4, byteorder='little'),
bytes.fromhex('f0f1f2f3').
- NAME
-
cbdata_t, cbdata_call_t, cbdata_register_t,
cbdata_type_t
- SYNOPSIS
-
typedef struct {
const char *name;
void (*dealloc)(void *data);
} cbdata_type_t;
typedef struct cbdata cbdata_t;
typedef cbdata_t cbdata_register_t, cbdata_call_t;
- DESCRIPTION
-
These data types are used by API functions and interface methods that
provide callbacks with callback data. By using these data types instead of a
simple
void *, the callback data can be freed correctly when
not needed anymore.
The types cbdata_register_t and cbdata_call_t are
only aliases for cbdata_t, used to annotate whether the object
is passed to a registration function or a callback function. This is used by
the automatic Python wrapping to ensure that the callback data is freed
correctly.
Objects of this type can be created by using either
SIM_make_cbdata or SIM_make_simple_cbdata. The latter
creates an untyped objects with no deallocation function, while the former
takes a cbdata_type_t argument, specifying a type name and a
deallocation function.
The following example shows how an API function could be defined using these
data types:
void for_all_ids(void (*callback)(const char *id,
cbdata_call_t data),
cbdata_register_t data);
Note how the two flavors of cbdata_t are used.
cbdata_register_t is used to pass some data to
for_all_ids which passes the same data unmodified to
callback. Here is an example of how this function could be
called; from C:
static void callback(const char *id, cbdata_call_t data)
{
const char *prefix = SIM_cbdata_data(&data);
printf("%s %s\n", prefix, id);
}
:
for_all_ids(callback, SIM_make_simple_cbdata("Testing"));
and from Python:
def callback(id, prefix):
print("%s %s" % (prefix, id))
for_all_ids(callback, "Testing")
Note in particular that the Python code does not mention "cbdata" anywhere;
it is all automatically handled by the Python wrapping code.
The C version of the previous example used
SIM_make_simple_cbdata, as the constant string "Testing"
does not need any deallocation function. For dynamically allocated data, you
must use SIM_make_cbdata instead:
static const cbdata_type_t malloced_int_type = {
"integer", // name
free // dealloc
};
static void callback(const char *id, cbdata_call_t data)
{
int *count = SIM_cbdata_data(&data);
printf("%d %s\n", *count, id);
++*count;
}
:
int *counter = malloc(sizeof *counter);
*counter = 1;
for_all_ids(callback, SIM_make_cbdata(malloced_int_type, counter));
In this example, for_all_ids is responsible for calling the
deallocation function for the callback data after it has completed all calls
to callback. It does this by calling SIM_free_cbdata,
which in turn will call malloced_int_type.dealloc; i.e.,
free.
The same example in Python; we still do not have to call any cbdata function
manually, but we do have to pass the counter in a one-element list since
integers are immutable in Python:
def callback(id, count):
print("%s %s" % (prefix, count[0]))
count[0] += 1
for_all_ids(callback, [1])
While the use of cbdata_t over a simple void * in
these examples seems redundant, they are needed if for_all_ids
does not call callback before returning, but asynchronously at
some later point in time. The use of cbdata_t also ensures that
the data is freed correctly even when any of the involved functions is
implemented in Python. This case often arises in conjunction with Simics
interfaces.
See the Callback Functions in Interfaces section in the
Simics Model Builder User's Guide for more information on how
to use the cbdata_t types.
- SEE ALSO
-
lang_void, SIM_make_cbdata,
SIM_make_simple_cbdata, SIM_free_cbdata,
SIM_cbdata_data, SIM_cbdata_type
- NAME
-
class_data_t, class_kind_t
- SYNOPSIS
-
typedef struct class_data {
conf_object_t *(*alloc_object)(lang_void *data);
lang_void *(*init_object)(conf_object_t *obj, lang_void *data);
void (*finalize_instance)(conf_object_t *obj);
void (*pre_delete_instance)(conf_object_t *obj);
int (*delete_instance)(conf_object_t *obj);
const char *description;
const char *class_desc;
class_kind_t kind;
} class_data_t;
- DESCRIPTION
-
The
class_data_t type is used when a new class is registered.
Uninitialized fields should be set to zero before the structure is passed to
SIM_register_class.
When a new object is created, memory for the conf_object_t is
allocated by Simics unless alloc_object has been provided by the
class. Classes written in C may implement alloc_object to have a
single allocation and must then place conf_object_t first in the
object data structure. This has the advantage of allowing casts directly from
a conf_object_t * to a pointer to the user structure instead of
using SIM_object_data.
When the conf_object_t has been allocated, the
init_object function is called. If the object instance needs
additional storage, it may allocate its own memory and return a pointer to
it from init_object. This pointer can later be obtained using
SIM_object_data. The return value from init_object
has to be non-null to signal a successful object initialization. If a null
value is returned, no configuration object will be created and an error will
be reported. For classes that implement their own alloc_object,
there is no need to allocate additional storage in the init_object
function and they can simply return the conf_object_t pointer
from init_object.
alloc_object and init_object both receive a
data parameter; they are currently not used, and should be
ignored.
The optional finalize_instance function is called when all
attributes have been initialized in the object, and in all other objects
that are created at the same time.
The pre_delete_instance and delete_instance fields can
be set to let the objects of this class support deletion:
-
pre_delete_instance will be called in the first phase of the
object deletion, during which objects are expected to clean-up their
external links to other objects (breakpoints, hap
callbacks, file or network resources, ...). They may also trigger the
deletion of other objects. pre_delete_instance is only called
for objects that have reached at least finalize_instance
during initialization.
-
delete_instance will be called in the second phase of the
object deletion: objects are expected to deallocate the memory they use
including the object data structure. They may not communicate with other
objects as these may already have been destroyed. The return value from
delete_instance is ignored for compatibility.
delete_instance is always called unless
alloc_object is not defined, or if it returned NULL.
The delete functions may be called by Simics before an object is fully
configured. That is, without any call to finalize_instance and
possibly before all the attribute set methods have been called. This may
happen when the object is part of a configuration that fails to load. The
SIM_object_is_configured function can be used to determine if
finalize_instance has run or not.
The description string is used to describe the class in several
sentences. It is used in the help commands and reference manuals. The
class_desc string is a short class description beginning with
lower case, without any trailing dot, and at most 50 characters long. It is
used in help commands and for example in the GUI.
Note:
The old class functions are legacy. New code should use
class_info_t and SIM_create_class.
.
- NAME
-
class_info_t, class_kind_t
- SYNOPSIS
-
typedef enum {
Sim_Class_Kind_Vanilla = 0, /* object is saved at checkpoints */
Sim_Class_Kind_Session = 1, /* object is saved as part of a
* session only */
Sim_Class_Kind_Pseudo = 2, /* object is never saved */
Sim_Class_Kind_Extension = 3, /* extension class
(see SIM_extend_class) */
} class_kind_t;
typedef struct class_info {
conf_object_t *(*alloc)(conf_class_t *cls);
lang_void *(*init)(conf_object_t *obj);
void (*finalize)(conf_object_t *obj);
void (*objects_finalized)(conf_object_t *obj);
void (*deinit)(conf_object_t *obj);
void (*dealloc)(conf_object_t *obj);
const char *description;
const char *short_desc;
class_kind_t kind;
} class_info_t;
- DESCRIPTION
-
The
class_info_t type is used when a new class is registered.
Uninitialized fields should be set to zero before the structure is passed to
SIM_create_class.
The alloc method is responsible for allocating memory for the
object itself, i.e. the conf_object_t structure. If no
alloc method is provided, Simics will use a default one, which
uses MM_MALLOC. Classes written in C may implement
alloc to have a single allocation and must then place
conf_object_t first in the object data structure. This has the
advantage of allowing casts directly from a conf_object_t * to a
pointer to the user structure instead of using
SIM_object_data. The alloc method can fail, e.g. if
memory allocation fails, and signals this by returning NULL.
After alloc has run on all objects being created, the
init function is called, if defined. This method should do any
class specific initialization, such as initializing internal data
structures. The init method may also use SIM_get_object
to obtain pointers to other objects, and it can use
SIM_set_attribute_default on its descendants, but it may not call
interfaces on other objects, or post events. If the object instance needs
additional storage, it may allocate its own memory and return a pointer to it
from init. This pointer can later be obtained using
SIM_object_data. However, for classes that implement their own
alloc, there is no need for that, since it can be done by
co-allocating the conf_object_t struct in a larger data
structure, and simply return the conf_object_t pointer from
init. The init method is allowed to fail, and it
signals this by returning NULL.
The finalize method, if defined, is called when all attributes
have been initialized in the object, and in all other objects that are
created at the same time. This method is supposed to do any
object initialization that require attribute values. Communication with other
objects, e.g. via interfaces, should ideally be deferred until the
objects_finalized method, but is permitted if
SIM_require_object is first called.
The objects_finalized method, if defined, is called after
finalize has been called on all objects, so in this method the
configuration is ready, and communication with other objects is permitted
without restrictions.
The deinit and dealloc methods are called during object
destruction. The deinit method, if defined, is called first on all
objects being deleted, and is supposed to do the inverse of the
init method. The dealloc method is supposed to free the
conf_object_t itself, i.e. it should be the inverse of
alloc. It is not defined, a default dealloc method is used, which
uses MM_FREE.
The delete functions may be called by Simics before an object is fully
configured. That is, without any call to finalize and possibly
before all the attribute set methods have been called. This may happen when
the object is part of a configuration that fails to load. The
SIM_object_is_configured function can be used to determine if
finalize has run or not.
All functions are called in hierarchical order, starting from the root, so
each object can assume that in each case, a function has already been called
on all its ancestors. This can be used to e.g. set attribute default values
on descendants in the init method.
If the initialization fails, i.e. if init fails, or if any
attribute setter fails, then the configuration creation is rolled back. For
those objects where init succeeded (or no init was defined), the
deinit function will be called, and on all created objects
(i.e. not ones where alloc failed) the dealloc method
is called.
The description string is used to describe the class in several
sentences. It is used in the help commands and reference manuals. The
short_desc string is a short class description beginning with
lower case, without any trailing dot, and at most 50 characters long. It is
used in help commands and for example in the GUI.
- NAME
-
conf_object_t
- DESCRIPTION
-
All objects in the Simics simulator have an associated
conf_object_t struct.
Pointers to conf_object_t are used
in the Simics simulator API to refer to a
specific object in the current Simics session.
conf_object_t is an opaque data structure whose members
should only be accessed using the Simics API.
- NAME
-
data_or_instr_t
- SYNOPSIS
-
typedef enum {
Sim_DI_Instruction = 0,
Sim_DI_Data = 1
} data_or_instr_t;
- DESCRIPTION
-
This type is used to differentiate between data and instruction, usually in
a TBL or memory transaction context.
- NAME
-
endianness_t
- SYNOPSIS
-
typedef enum {
Sim_Endian_Target,
Sim_Endian_Host_From_BE,
Sim_Endian_Host_From_LE
} endianness_t;
- DESCRIPTION
-
Specifies the endianness to use for certain memory operations. When
Sim_Endian_Target is used, the data from memory is
copied without any endian conversion.
Sim_Endian_Host_From_BE and
Sim_Endian_Host_From_LE copies data between a
big-endian, or little-endian, memory and a host buffer.
- NAME
-
exception_type_t
- SYNOPSIS
-
typedef enum {
SIM_PSEUDO_EXC(SIM_PSEUDO_EXC_ENUM)
} exception_type_t;
- DESCRIPTION
-
Used to signal simulator exceptions for memory accesses. Errors
usually correspond to hardware exceptions, but in some cases additional
return values are needed, and then pseudo exceptions are used.
The most common is
Sim_PE_No_Exception, indicating that no error
has occurred. Pseudo exceptions are used by devices, memory spaces, and
Simics internally.
- Sim_PE_No_Exception
- No error.
- Sim_PE_Deferred
- Transaction completion is deferred via
the call to SIM_defer_transaction.
- Sim_PE_Async_Required
- The endpoint tried to defer the transaction
with SIM_defer_transaction but the transaction
cannot be deferred.
- Sim_PE_Cancelled
- Special completion status passed to
transaction_completion_t callbacks when asynchronous
transactions are cancelled by Simics, for example, when simulation state
is restored from a snapshot. - Sim_PE_IO_Not_Taken
- Access to unmapped memory. In the
PCI memory spaces interpreted as master abort.
- Sim_PE_IO_Error
- Accessed device returned error. In the
PCI memory spaces interpreted as target abort.
- Sim_PE_Inquiry_Outside_Memory
- Same as Sim_PE_IO_Not_Taken,
but for inquiry accesses.
- Sim_PE_Execute_Outside_Memory
- A processor tried to fetch
instruction where no memory is defined.
- Sim_PE_Inquiry_Unhandled
- The accessed device does not
support inquiry operations.
- Sim_PE_Stall_Cpu
- Timing model requested stall.
- Sim_PE_Default_Semantics
- Used by user decoders and
user ASI handlers on SPARC to signal that the
default semantics should be run.
- Sim_PE_Ignore_Semantics
- Used by user ASI handlers on SPARC
to signal no update of destination registers.
- Simics internal:
- Sim_PE_Silent_Break,
Sim_PE_Instruction_Finished, Sim_PE_Last.
- NAME
-
generic_transaction_t
- DESCRIPTION
-
A
generic_transaction_t
represents a memory transaction. It should only be accessed via the accessor
functions documented in
Device API Functions, Core, Memory
Transactions.
- NAME
-
global_notifier_type_t
- SYNOPSIS
-
typedef enum {
Sim_Global_Notify_Object_Delete = 100,
Sim_Global_Notify_Objects_Finalized,
Sim_Global_Notify_Message,
Sim_Global_Notify_Before_Snapshot_Restore = 150,
Sim_Global_Notify_After_Snapshot_Restore,
} global_notifier_type_t;
- DESCRIPTION
-
This enum is used to identify pre-defined global notifier. The
Sim_Global_Notify_Object_Delete notifier is triggered by Simics
when objects are being deleted. In the callback, objects are still fully
available, but SIM_marked_for_deletion can be used to determine
if an object is being deleted.
The Sim_Global_Notify_Objects_Finalized notifier is triggered by
Simics when new objects have been finalized, after their
objects_finalized methods have been called.
The Sim_Global_Notify_Message notifier is used by
SIM_trigger_global_message.
The corresponding names used in e.g. list-notifiers
are as follows:
- "global-object-delete" (Sim_Global_Notify_Object_Delete)
- "global-objects-finalized" (Sim_Global_Notify_Objects_Finalized)
- "global-message" (Sim_Global_Notify_Message)
- SEE ALSO
-
SIM_add_global_notifier,
SIM_add_global_notifier_once,
SIM_delete_global_notifier,
- NAME
-
hap_type_t
- SYNOPSIS
-
typedef int hap_type_t;
- DESCRIPTION
-
This data type is used to represent hap (occurrence) types. This is
a runtime number that may change between different Simics
invocations. Haps are normally identified by strings, but by
calling SIM_hap_get_number(), a lookup from such a name
to a
hap_type_t can be made.
- SEE ALSO
-
SIM_get_all_hap_types,
SIM_hap_get_number,
SIM_hap_add_type
- NAME
-
init_arg_t
- SYNOPSIS
-
typedef struct {
const char *name;
bool boolean;
union {
const char *string;
bool enabled;
} u;
} init_arg_t;
- DESCRIPTION
-
Data structure used to pass an initialization argument to the
SIM_init_simulator2 function. The
name field is
mandatory and the associated data is either a boolean or a string
(char *). A list of init_arg_t is passed to
SIM_init_simulator2 where the last entry has the
name field set to NULL.
- NAME
-
int8, int16, int32, int64,
uint8, uint16, uint32, uint64,
intptr_t, uintptr_t
- SYNOPSIS
-
These data types have host-dependent definitions. Use the
api-help Simics command line command to get their
exact definition.
- DESCRIPTION
-
These are basic integer data types defined by the Simics headers
(unless defined by system header files).
The intn types are defined to be signed
integers of exactly n bits. The
uintn types are their unsigned counterparts.
intptr_t and uintptr_t are signed and
unsigned integer types of a size that lets any pointer to
void be cast to it and then cast back to a pointer to
void, and the result will compare equal to the
original pointer. This typically means that the two types are 64
bits wide.
- NAME
-
lang_void
- SYNOPSIS
-
typedef void lang_void;
- DESCRIPTION
-
In some places in the Simics API, arguments of type
lang_void * are used. This data type is used to
allow transparent passing of any data type in the current programming
language as argument. In C, this works exactly like a
void * and in Python, it is any Python
object.
Typically, this is used by iterator functions in the API which take callback
functions as arguments. The callback function is later called with the
lang_void data and the object being iterated over.
- SEE ALSO
-
SIM_hap_add_callback,
SIM_register_typed_attribute
- NAME
-
logical_address_t, physical_address_t, generic_address_t,
linear_address_t
- SYNOPSIS
-
These data types are target architecture independent, and always
large enough to hold 64-bit addresses.
- DESCRIPTION
-
These are integer data types defined to reflect the nature of the
simulated architecture.
logical_address_t is an unsigned integer sufficiently
large to contain logical (virtual) addresses on the target machine.
physical_address_t is an unsigned integer sufficiently
large to contain physical addresses on the target machine.
generic_address_t is defined to be the largest of the
logical_address_t and physical_address_t
types.
linear_address_t is used for linear addresses used on
x86 machines after segmentation but before paging.
Note that these data types are all defined to be 64-bit unsigned
integers, and they can be printed by printf using the
ll (ell-ell) size modifier.
- NAME
-
map_info_t, swap_mode_t
- SYNOPSIS
-
typedef enum swap_mode {
Sim_Swap_None = 0,
Sim_Swap_Bus = 1,
Sim_Swap_Bus_Trans = 2,
Sim_Swap_Trans = 3
} swap_mode_t;
typedef struct map_info {
physical_address_t base;
physical_address_t start;
physical_address_t length;
int function;
int16 priority;
int align_size;
swap_mode_t reverse_endian;
} map_info_t;
- DESCRIPTION
-
The
map_info_t structure members have the following meaning:
-
base: The base address of the device mapping in the memory space.
-
start: The address inside the device memory space where the mapping
starts.
length: The length of the mapped memory, in bytes.
function: Used to map the same object several times
with different functionality. Corresponds to the function argument used
when mapping devices into a memory space.
- If the map target does not support large accesses, then
align_size can be set to the maximum allowed size. Accesses
spanning align boundaries will be split into several smaller
transactions. The align size must be a power of two, or zero (which
means "use the default value": 8 for devices and 8192 for memory).
- Mappings with an align size of 2, 4, or 8 may set the
reverse_endian field to a non zero value. This can be used to
model bridges that perform byte swapping on a specific bus width.
If both base and length are 0 the map will become a
default_target.
- NAME
-
map_list_t, map_type_t
- SYNOPSIS
-
typedef enum {
Sim_Map_Ram,
Sim_Map_Rom,
Sim_Map_IO,
Sim_Map_Port,
Sim_Map_Translate = 0x100, /* pseudo - do not use */
Sim_Map_Translate_To_Space,
Sim_Map_Translate_To_Ram,
Sim_Map_Translate_To_Rom
} map_type_t;
typedef struct map_list {
map_type_t map_type;
conf_object_t *object;
const char *port;
#if !defined(PYWRAP)
const void *interface_ptr;
const void *target_interface;
const void *breakpoint_interface;
#if defined(SIMICS_6_API)
const void *breakpoint_query_interface;
#else
const void *breakpoint_query_v2_interface;
#endif
const void *bridge_interface;
#endif
conf_object_t *target_object;
const char *target_port;
conf_object_t *bridge;
map_info_t map_info;
physical_address_t map_size; /* not constant, use with caution */
int deleted; /* internal flag - should always be 0 ! */
} map_list_t;
- DESCRIPTION
-
This data structure is used to pass information about the set of
mappings a particular address in an address space contains.
- NAME
-
map_target_t
- SYNOPSIS
-
typedef struct map_target map_target_t;
- DESCRIPTION
-
A map target can be viewed as an opaque representation of
an object/interface pair which can function either as an endpoint
for a memory transaction or as an address space where a
memory transaction can be performed. To create a
map_target_t
object one should use the SIM_new_map_target function.
The SIM_free_map_target function frees
a map_target_t object. In order to get better performance,
it is better to allocate a map target once and reuse it rather
than to allocate and free it every time.
Examples of map targets include IO banks, RAM, ROM, memory spaces,
port spaces, translators and bridges.
For certain targets, e.g. bridges or translators, the map target also
holds information about a chained, or default, target.
- PYTHON SPECIFICS
-
In Python, it is allowed to use arguments of the
conf_object_t
type with Simics API functions that have parameters of
the map_target_t type. The arguments of
the conf_object_t type will be converted to
map_target_t values automatically, via the call to
the SIM_new_map_target function. Here is an example where
memory_space is a Simics object, i.e. has
the conf_object_t type:
t = transaction_t(...)
SIM_issue_transaction(memory_space, t, addr)
In Python, the objects of the map_target_t type have
read-only obj, port, and target attributes.
These attributes correspond to the arguments given to
SIM_new_map_target that created
a map_target_t object.
- SEE ALSO
-
SIM_new_map_target, SIM_free_map_target,
SIM_map_target_object, SIM_map_target_port,
SIM_map_target_target,
translator_interface_t
- NAME
-
mem_op_type_t
- SYNOPSIS
-
typedef enum {
Sim_Trans_Load = 0,
Sim_Trans_Store = Sim_Trn_Write,
Sim_Trans_Instr_Fetch = Sim_Trn_Instr,
Sim_Trans_Prefetch = Sim_Trn_Prefetch | Sim_Trn_Control,
Sim_Trans_Cache = Sim_Trn_Control
} mem_op_type_t;
- DESCRIPTION
-
This enum is used to identify the type of a memory operation. The
function SIM_get_mem_op_type() returns the type of a
generic_transaction_t, and SIM_set_mem_op_type()
is used to set it.
- SEE ALSO
-
SIM_get_mem_op_type, SIM_set_mem_op_type,
SIM_get_mem_op_type_name
generic_transaction_t,
- NAME
-
notifier_type_t
- SYNOPSIS
-
/* Note that notifier types can be added either by modifying this enum or
by using SIM_notifier_type. The latter is typically preferred since it does
not change the Simics API. */
typedef enum {
Sim_Notify_Queue_Change,
Sim_Notify_Cell_Change,
Sim_Notify_Frequency_Change,
Sim_Notify_Concurrency_Change,
Sim_Notify_Object_Delete,
Sim_Notify_Map_Change,
Sim_Notify_State_Change,
Sim_Notify_Freerunning_Mode_Change,
Sim_Notify_Bank_Register_Value_Change,
} notifier_type_t;
- DESCRIPTION
-
Values of the
notifier_type_t type identify notification events.
A notifier_type_t value should be obtained from
the SIM_notifier_type function and can then be used in other
functions such as SIM_register_notifier,
SIM_add_notifier, SIM_notify.
A few notification events have predefined (constant) values. They are listed
below where a notifier type in the form of a string (as accepted by
SIM_notifier_type) is followed by the constant of the
notifier_type_t type corresponding to the notification event
(as returned by SIM_notifier_type):
- "queue-change" (Sim_Notify_Queue_Change)
- "cell-change" (Sim_Notify_Cell_Change)
- "frequency-change" (Sim_Notify_Frequency_Change)
- "concurrency-change" (Sim_Notify_Concurrency_Change)
- "object-delete" (Sim_Notify_Object_Delete)
- "map-change" (Sim_Notify_Map_Change)
- "state-change" (Sim_Notify_State_Change)
- "freerunning-mode-change"
(Sim_Notify_Freerunning_Mode_Change)
- "bank-register-value-change"
(Sim_Notify_Bank_Register_Value_Change)
- SEE ALSO
-
SIM_notify,
SIM_add_notifier,
SIM_register_notifier,
SIM_notifier_type,
SIM_describe_notifier,
SIM_notifier_description
- NAME
-
processor_mode_t
- SYNOPSIS
-
typedef enum {
Sim_CPU_Mode_User = 0,
Sim_CPU_Mode_Supervisor = 1,
Sim_CPU_Mode_Hypervisor
} processor_mode_t;
- DESCRIPTION
-
The
processor_mode_t data type is used to specify if a
CPU is running in user mode or in a privileged mode (often called
supervisor mode). For processor architectures with several
privilege levels, the non-user levels are all identified as
Sim_CPU_Mode_Supervisor.
- NAME
-
read_or_write_t
- SYNOPSIS
-
typedef enum {
Sim_RW_Read = 0,
Sim_RW_Write = 1
} read_or_write_t;
- DESCRIPTION
-
Whether a memory access is a read (from memory) or a write
(to memory).
- NAME
-
set_error_t
- SYNOPSIS
-
typedef enum {
Sim_Set_Ok,
Sim_Set_Object_Not_Found,
Sim_Set_Interface_Not_Found,
Sim_Set_Illegal_Value,
Sim_Set_Illegal_Type,
Sim_Set_Illegal_Index,
Sim_Set_Attribute_Not_Found,
Sim_Set_Not_Writable,
Sim_Set_Error_Types /* number of error types */
} set_error_t;
- DESCRIPTION
-
The SIM_set_attribute() family of functions and the set functions
registered with the SIM_register_attribute() family of
functions return a
set_error_t value to report success or
failure.
Sim_Set_Ok
The attribute was successfully set.
Sim_Set_Object_Not_Found
The string value does not match any object name. Deprecated, use attributes
of object type instead of string attributes referring to object names.
Sim_Set_Interface_Not_Found
The object value does not implement an interface required by the attribute.
Sim_Set_Illegal_Value
The value is of a legal type for the attribute, but outside the legal range.
Sim_Set_Illegal_Type
The value is of an illegal type for the attribute.
Sim_Set_Attribute_Not_Found
The object has no attribute with the specified name. Should only be returned
by SIM_set_attribute() family of functions, not by attribute set
functions.
Sim_Set_Not_Writable
The attribute is read-only.
Sim_Set_Error_Types
This is the number of valid error values and should not be used as
an error code.
- NAME
-
simtime_t, cycles_t, pc_step_t, nano_secs_t
- SYNOPSIS
-
typedef int64 simtime_t;
typedef simtime_t cycles_t;
typedef simtime_t pc_step_t;
typedef int64 nano_secs_t;
- DESCRIPTION
-
These are the types used for keeping track of time in Simics.
cycles_t is used when the time is specified in cycles,
pc_step_t is used when the time is specified in steps, and
simtime_t is used in places where it is unknown whether the
time is in steps or cycles. See the Understanding Simics Timing
application note for a discussion about the difference between steps and
cycles.
nano_secs_t is used to express a number of nanoseconds
(10−9 seconds).
- NAME
-
translation_t
- DESCRIPTION
-
The
translation_t type is used for the implementation
of the translator and transaction_translator
interfaces. It describes the range
for which the translation is valid, its target as well as
translation properties.
The range for which the translation is valid is specified by the
fields base and size. As a special case,
if size and base are both 0, then the
translation is valid for the entire address space. To allow optimizations
(e.g., caching of translations) translators should return as wide ranges
as possible.
The target field specifies the object and interface
port which is mapped into the address range in the form of a map target.
Map targets can be created using the function
SIM_new_map_target. Please note that the ownership over
the returned map target is not transferred to the interface caller.
This means that to avoid memory leaks the reference to the map
target must be kept by the implementing object, and
SIM_free_map_target function should be later used to
deallocate the map target. Possible map targets include IO
banks, RAM, ROM, memory spaces, port spaces, bridges, and translators.
The base address in the source address space is
mapped to the target address returned in the start field.
A null value returned in the target field signifies that
the translation cannot be done. This can happen if there is nothing mapped
in the range defined by base and size
(transactions directed to this region will be terminated
with the pseudo exception Sim_PE_IO_Not_Taken) or
if a translation valid for all requested accesses cannot be performed.
In the latter case, the requestor is expected to repeat
the interface call with just a single bit set in the access mask,
e.g. Sim_Access_Read.
If the returned translation is not static but instead depends on e.g.
a device register, then the translator can set the flags field
to Sim_Translation_Dynamic. This flag indicates that
the translation must not be cached. If this flag is not used, then it
is the responsibility of the translator to call
either SIM_map_target_flush (preferably)
or SIM_translation_changed function when a previously performed
translation is no longer valid.
The Sim_Translation_Ambiguous flag should not generally
be used by models. It is used by Simics objects of
the memory-space class to indicate an error in
the memory mapping when several destinations are specified for the address.
typedef enum {
Sim_Translation_Dynamic = 1,
Sim_Translation_Ambiguous = 2
} translation_flags_t;
typedef struct translation {
const map_target_t *target; /* target of translation */
physical_address_t base; /* base address of translated range */
physical_address_t start; /* start address in mapped object */
physical_address_t size; /* size of translated range */
translation_flags_t flags;
} translation_t;
- SEE ALSO
-
SIM_map_target_flush,
SIM_translation_changed
- NAME
-
arm_device_type_t
- SYNOPSIS
-
typedef enum {
Arm_DeviceType_nGnRnE = 0x0,
Arm_DeviceType_nGnRE = 0x1,
Arm_DeviceType_nGRE = 0x2,
Arm_DeviceType_GRE = 0x3,
Arm_DeviceType_Unknown
} arm_device_type_t;
- DESCRIPTION
-
Arm device memory types. Corresponds to the DeviceType pseudo code
enumeration in the Armv8 A-profile Architecture Reference Manual.
- NAME
-
arm_mem_attr_t
- SYNOPSIS
-
typedef enum {
Arm_MemAttr_NC = 0x0, // Non-cacheable
Arm_MemAttr_WT = 0x2, // Write-through
Arm_MemAttr_WB = 0x3, // Write-back
Arm_MemAttr_Unknown
} arm_mem_attr_t;
- DESCRIPTION
-
Memory cacheability. Corresponds to the MemAttr pseudo code constants
in the Armv8 A-profile Architecture Reference Manual.
- NAME
-
arm_mem_hint_t
- SYNOPSIS
-
typedef enum {
Arm_MemHint_No = 0x0, // No Read-Allocate, No Write-Allocate
Arm_MemHint_WA = 0x1, // No Read-Allocate, Write-Allocate
Arm_MemHint_RA = 0x2, // Read-Allocate, No Write-Allocate
Arm_MemHint_RWA = 0x3, // Read-Allocate, Write-Allocate
Arm_MemHint_Unknown
} arm_mem_hint_t;
- DESCRIPTION
-
Cache allocation hint. Corresponds to the MemHint pseudo code
constants in the Armv8 A-profile Architecture Reference Manual.
- NAME
-
arm_mem_instr_origin_t
- SYNOPSIS
-
typedef enum {
/* Normal load or store instructions */
Instr_Normal_Arm = 0,
/* Unprivileged memory access instructions. */
Instr_Unprivileged_Load,
Instr_Unprivileged_Store,
/* Other loads/stores or cache affecting instructions */
Instr_ldrex,
Instr_strex,
Instr_ldxp,
Instr_stxp,
/* Address translation instruction */
Instr_At,
/* Atomic read-modify-write instructions */
Instr_Atomic,
/* Cache maintenance instructions */
Instr_Cache_Maintenance,
/* Number of different of enum values, not a value in itself. */
Instr_Count
} arm_mem_instr_origin_t;
- DESCRIPTION
-
List of special memory operations that can be send by a ARM processor.
- NAME
-
arm_mem_transient_t
- SYNOPSIS
-
typedef enum {
Arm_Transient_True,
Arm_Transient_False,
Arm_Transient_Unknown
} arm_mem_transient_t;
- DESCRIPTION
-
Transcience hint. Corresponds to the boolean used for transience by
the pseudo code in the Armv8 A-profile Architecture Reference Manual.
- NAME
-
arm_mem_type_t
- SYNOPSIS
-
typedef enum {
Arm_MemType_Normal,
Arm_MemType_Device
} arm_mem_type_t;
- DESCRIPTION
-
Arm memory types. Corresponds to the MemType pseudo code
enumeration in the Armv8 A-profile Architecture Reference
Manual.
- NAME
-
arm_memory_attributes_encoding_t
- SYNOPSIS
-
typedef union {
struct {
uint64 memory_type:2; // arm_mem_type_t
uint64 device_type:3; // arm_device_type_t
uint64 inner_cacheability:3; // arm_mem_attr_t
uint64 inner_allocation_hint:3; // arm_mem_hint_t
uint64 inner_transcience_hint:2; // arm_mem_transient_t
uint64 outer_cacheability:3; // arm_mem_attr_t
uint64 outer_allocation_hint:3; // arm_mem_hint_t
uint64 outer_transcience_hint:2; // arm_mem_transient_t
uint64 shareable:1; // bool
uint64 outer_shareable:1; // bool
} u;
uint64 u64;
} arm_memory_attributes_encoding_t;
- DESCRIPTION
-
This type should be used to encode or decode the uint64 value
contained in an arm_memory_attributes atom. The comment beside each
field is the type that should be used to interpret the field value.
- NAME
-
arm_memory_transaction_t
- SYNOPSIS
-
typedef struct arm_memory_transaction {
generic_transaction_t s;
processor_mode_t mode;
int rotate;
arm_mem_instr_origin_t instr_origin;
} arm_memory_transaction_t;
- DESCRIPTION
-
This is the ARM specific memory transaction data structure.
The generic data is stored in the s field.
The mode field specifies the processor mode the MMU should assume
when processing the transaction. This is the same as the current mode of the
processor except for unprivileged load and store instructions when it is
always Sim_CPU_Mode_User.
The rotate field is non-zero if this transaction is from one of
the AArch32 instructions for which an unaligned address is interpreted as an
aligned load with the value rotated so that the addressed byte becomes the
least significant byte if neither SCTLR.U nor SCTLR.A
is set.
The instr_origin field specifies the type of instruction that
initiated this memory transaction.
- NAME
-
arm_smmu_attributes_t
- SYNOPSIS
-
typedef union {
struct {
uint64 sid:32; // IMPLEMENTATION DEFINED size, between 0 and 32 bits
uint64 ssid:20; // IMPLEMENTATION DEFINED size, between 0 and 20 bits
uint64 secsid:1; // bool
uint64 ssidv:1; // bool
uint64 atst:1; // bool
} u;
uint64 u64;
} arm_smmu_attributes_t;
- DESCRIPTION
-
This type should be used to encode or decode the uint64 value
contained in an arm_smmu_attributes atom. The comment beside each
field is the type that should be used to interpret the field value.
- NAME
-
arm_translation_regime_t
- SYNOPSIS
-
typedef enum {
Arm_TR_EL3, /* EL3 */
Arm_TR_EL2, /* EL2 PL2 */
Arm_TR_EL20, /* EL2&0 */
Arm_TR_EL10, /* EL1&0 PL1&0 */
} arm_translation_regime_t;
,
- DESCRIPTION
-
Arm MMU translation regimes. Named after the AArch64 translation
regimes, but also used for the AArch32 ones.
- NAME
-
i2c_status_t
- SYNOPSIS
-
typedef enum {
/* The ACK bit related to the operation was 0. This typically
means that the operation was successful */
I2C_status_success = 0,
/* The ACK bit related to the operation was 1. This typically
means that the operation was unsuccessful */
I2C_status_noack = 1,
/* The operation could not be carried out, because the link is
currently in use by another master */
I2C_status_bus_busy
} i2c_status_t;
- DESCRIPTION
-
The
i2c_status_t type is used to communicate the
results of various operations on the I2C link. The type is an enum,
with the values I2C_status_success,
I2C_status_noack and
I2C_status_bus_busy.
The i2c_status_t type typically represents an ACK bit;
in this case I2C_status_success corresponds to 0,
and I2C_status_noack corresponds to 1. In the
start_response function of the i2c_master
interface, the i2c_status_t parameter is additionally
allowed to take the value I2C_status_bus_busy,
meaning that the start failed since some other master is active
using the i2c link. The value I2C_status_bus_busy is
disallowed in all other function parameters in the
i2c_link, i2c_slave and
i2c_master interfaces.
- SEE ALSO
-
i2c_link_interface_t,
i2c_master_interface_t, i2c_slave_interface_t
- NAME
-
interrupt_source_t
- SYNOPSIS
-
typedef enum {
Interrupt_Source_Icr_Ipr,
Interrupt_Source_Msi,
Interrupt_Source_Virtual_Wire,
Interrupt_Source_Nmi_Pin,
Interrupt_Source_Lvt,
Interrupt_Source_Iommu,
Interrupt_Source_Int2,
Interrupt_Source_Vmcs_Injection,
Interrupt_Source_Legacy_Apic_Vector,
Interrupt_Source_Self_Ipi,
Interrupt_Source_Unknown,
} interrupt_source_t;
- DESCRIPTION
-
Sources of interrupts.
Interrupt_Source_Icr_Ipr means that the source is
the Interrupt Control Register - Inter Processor Interrupt.
Interrupt_Source_Msi means that the source is an
MSI.
Interrupt_Source_Virtual_Wire means that the
source is the Virtual Wire.
Interrupt_Source_Nmi_Pin means that the source is
the external NMI pin.
Interrupt_Source_Lvt means that the source is the
local vector table (LVT).
Interrupt_Source_Iommu means that the source is
the IOMMU.
Interrupt_Source_Int2 means that the source is the
INT2 instruction.
Interrupt_Source_Vmcs_Injection means that the
source is an interrupt injected through the VMCS.
Interrupt_Source_Legacy_Apic_Vector means that the
source is the legacy APIC interrupt vector.
Interrupt_Source_Self_Ipi means that the source is
the SELF IPI Register.
Interrupt_Source_Unknown means that the source is
unknown.
- SEE ALSO
-
interrupt_subscriber_interface_t
- NAME
-
mips_memory_transaction_t
- SYNOPSIS
-
typedef struct mips_memory_transaction {
/* generic transaction */
generic_transaction_t s;
/* Cache coherency, values as the C field in EntryLo0 and EntryLo1. */
unsigned int cache_coherency:3;
} mips_memory_transaction_t;
- DESCRIPTION
-
This is the MIPS specific memory transaction data structure.
The generic data is stored in the s field.
The cache_coherency field specifies the cache coherency attribute
of the memory transaction, as defined by the C field of the EntryLo0 and
EntryLo1 coprocessor 0 registers.
- NAME
-
nios_memory_transaction_t
- SYNOPSIS
-
typedef struct nios_memory_transaction {
/* generic transaction */
generic_transaction_t s;
} nios_memory_transaction_t;
- DESCRIPTION
-
The s field contains generic information about memory operations (see
generic_transaction_t).
- NAME
-
pci_memory_transaction_t
- SYNOPSIS
-
typedef struct pci_memory_transaction {
generic_transaction_t INTERNAL_FIELD(s);
uint32 INTERNAL_FIELD(original_size);
int INTERNAL_FIELD(bus_address);
int INTERNAL_FIELD(bus_number);
int INTERNAL_FIELD(device_number);
int INTERNAL_FIELD(function_number);
uint32 INTERNAL_FIELD(tlp_prefix);
} pci_memory_transaction_t;
- DESCRIPTION
-
The
pci_memory_transaction_t is used for memory accesses
initiated by PCI devices.
Note:
All struct fields are internal and should never be used
directly.
A generic_transaction_t can be converted to a
pci_memory_transaction_t via the
SIM_pci_mem_trans_from_generic() function. Never explicitly cast
one struct to the other, always use the Simics API functions.
- SEE ALSO
-
SIM_pci_mem_trans_from_generic,
generic_transaction_t
- NAME
-
ppc_mem_instr_origin_t
- SYNOPSIS
-
typedef enum {
/* Normal load or store instructions */
Normal_Load_Store = 0,
/* No data touched by the load/store will be placed in cache */
Caching_Inhibited,
Instr_Multiple, /* load/store multiple */
Instr_String, /* load/store string */
Instr_Altivec_Element, /* Altivec load/store element */
/* Data cache manipulations */
Instr_dcbt, /* data cache block touch */
Instr_dcbst, /* data cache block store */
Instr_dcbtst, /* data cache block touch for store */
Instr_dcbi, /* data cache block invalidate */
Instr_dcbf, /* data cache block flush */
Instr_dcbfl, /* data cache block flush local */
Instr_dcba, /* data cache block allocate */
Instr_dcbz, /* data cache block to zero */
/* Instruction cache manipulations */
Instr_icbi, /* instruction cache block invalidate */
/* Data stream (Altivec) manipulations */
Instr_dst, /* data stream touch */
Instr_dstt, /* data stream touch transient */
Instr_dstst, /* data stream touch for store */
Instr_dststt, /* data stream touch for store transient */
/* e500 cache lock apu instructions */
Instr_dcblc_l1, /* data cache block lock clear (L1) */
Instr_dcblc_l2, /* data cache block lock clear (L2) */
Instr_dcbtls_l1, /* data cache block touch and lock set (L1)*/
Instr_dcbtls_l2, /* data cache block touch and lock set (L1)*/
Instr_dcbtstls_l1, /* data cache block touch for store and lock
set (L1)*/
Instr_dcbtstls_l2, /* data cache block touch for store and lock
set (L1)*/
Instr_icblc_l1, /* instruction cache block clear (L1) */
Instr_icblc_l2, /* instruction cache block clear (L2) */
Instr_icbtls_l1, /* instruction cache block touch and lock
set (L1) */
Instr_icbtls_l2, /* instruction cache block touch and lock
set (L1) */
/* Other loads/stores or cache affecting instructions */
Instr_lwarx,
Instr_stwcx,
Instr_ldarx,
Instr_stdcx,
Instr_lq,
Instr_stq,
/* Other cache affecting instructions */
Instr_sync,
Instr_eieio,
Instr_ecowx,
Instr_eciwx,
Instr_tlbie,
Instr_tlbsync,
Instr_isync,
Instr_lfdp, /* Load Floating point Double Pair */
Instr_stfdp, /* Store Floating point Double Pair */
Instr_spe,
Instr_dcbal, /* Obsolete - use Instr_dcba. */
/* e500 cache lock apu instructions, platform cache versions */
Instr_dcblc_pc, /* data cache block lock clear */
Instr_dcbtls_pc, /* data cache block touch and lock set*/
Instr_dcbtstls_pc, /* data cache block touch for store and lock
set */
Instr_icblc_pc, /* instruction cache block clear */
Instr_icbtls_pc, /* instruction cache block touch and lock
set */
Instr_Fpu /* Load/store from FPU unit */
} ppc_mem_instr_origin_t;
- DESCRIPTION
-
List of special memory operations that can be send by a PPC processor.
- NAME
-
ppc_memory_transaction_t
- SYNOPSIS
-
typedef struct ppc_memory_transaction {
/* generic transaction */
generic_transaction_t s;
processor_mode_t mode;
ppc_mem_instr_origin_t instr_origin;
logical_address_t ea_origin;
uint8 wimg;
uint8 alignment;
/* cache operations may flag this to cause prefetches to be no-ops */
uint8 inhibit_exception;
/* External PID */
uint8 external_pid;
/* Decorated storage */
ppc_decoration_t decoration;
} ppc_memory_transaction_t;
- DESCRIPTION
-
This is the PPC specific memory transaction data structure.
The generic data is stored in the s field.
The current processor mode when generating this transaction is stored in the
mode field.
The type of instruction generating the memory transactions is provided by
the instr_origin field. Note that it is mainly provided for
special memory accesses like cache block operations..
The wimg field is filled in by the MMU with the corresponding
WIMG bits during the translation.
The alignment field contains the size on which the transaction is
required to be aligned.
The inhibit_exception field is set for operations that should be
ignored if triggering an exception.
The external_pid field is only used internally for some Book-E
cores. It is undefined for cores which do not have this feature.
decoration contains decoration data.
typedef struct {
ppc_decoration_type_t type;
uint64 data;
} ppc_decoration_t;
The type field specifies whether the transaction is decorated or
not, and if it is, the decoration type. It will be one of:
typedef enum {
Decoration_None,
Decoration_Notify,
Decoration_Load,
Decoration_Store
} ppc_decoration_type_t;
The data field holds the decoration data supplied by the
instruction. It is only valid if type is not
Decoration_None.
Note that not all processors implement decorated storage.
- NAME
-
riscv_cpu_mode_t
- SYNOPSIS
-
typedef enum {
Riscv_Mode_User = 0x0,
Riscv_Mode_Supervisor = 0x1,
Riscv_Mode_Reserved = 0x2,
Riscv_Mode_Machine = 0x3,
Riscv_Mode_Guest_User = 0x10,
Riscv_Mode_Guest_Supervisor = 0x11
} riscv_cpu_mode_t;
- DESCRIPTION
-
List of privilege levels of the RISC-V core.
- NAME
-
serial_peripheral_interface_flags_t
- SYNOPSIS
-
typedef enum serial_peripheral_interface_flags {
SPI_Flags_CPHA = 0x1,
SPI_Flags_CPOL = 0x2
} serial_peripheral_interface_flags_t;
- DESCRIPTION
-
The
serial_peripheral_interface_flags_t type is used
to describe some properties of an SPI connection. The type is a
bitfield, currently defining two values, CPOL and CPHA. If a
master device connects to a slave using a CPOL/CPHA combination
incompatible with the slave device, then the results of any SPI
transfer are undefined.
The SPI_Flags_CPOL bit defines the polarity of
the clock pin (SCK): A value of zero means that the pin is low when
the bus is idle, while a value of one means that the pin is high
when the bus is idle.
The SPI_Flags_CPHA bit defines the phase of the
clock pin. If the CPHA and CPOL bits are equal, data bits are read
on the falling edge of the SCK pin and changed on the rising edge
of the pin; if the bits are not equal, data bits are read on the
rising edge and changed on the falling edge of the SCK pin.
- SEE ALSO
-
serial_peripheral_interface_slave_interface_t
- NAME
-
usb_transfer_t
- SYNOPSIS
-
typedef enum {
USB_Transfer_Completed,
USB_Transfer_Not_Ready
} usb_transfer_completion_t;
typedef enum {
USB_Direction_None,
USB_Direction_In,
USB_Direction_Out
} usb_direction_t;
typedef enum {
USB_Status_Undef,
USB_Status_Ack,
USB_Status_Nak,
USB_Status_Stall
} usb_status_t;
typedef enum {
USB_Type_Control,
USB_Type_Interrupt,
USB_Type_Isochronous,
USB_Type_Bulk
} usb_type_t;
typedef enum {
USB_Speed_Low,
USB_Speed_Full,
USB_Speed_High
} usb_speed_t;
typedef struct {
uint8 bmRequestType;
uint8 bRequest;
uint16 wValue;
uint16 wIndex;
uint16 wLength;
} usb_device_request_t;
typedef struct {
/* Endpoint/function specific information */
uint8 function_address;
uint8 endpoint_number;
/* Type specific information */
usb_type_t type;
#ifndef PYWRAP
union {
usb_device_request_t control_request;
nano_secs_t periodic_time;
} u;
#endif /* PYWRAP */
/* Data specific */
usb_direction_t direction;
int size;
dbuffer_t *buf;
/* Status */
usb_status_t status;
} usb_transfer_t;
- DESCRIPTION
-
All USB related data types are Simics internal, and should not be
used by user-defined classes. The data types may change in future
versions of Simics.
The usb_transfer_t type is independent of USB host and
USB device implementations and is used for sending data over USB.
There are two fields to identify the pipe: function_address is
the function/device address for the target USB device;
endpoint_number specifies the endpoint number.
The type of transfer is defined using the type field. The type is
either control, bulk, interrupt, or isochronous. The
u.control_request field is only valid for control transfers. It
contains the information that would be in the setup packet of a control
transfer. The u.periodic_time field is only valid for periodic
transfers, i.e., interrupt and isochronous transfers. It specifies the
minimum response time for a transfer expected by the USB host. A USB device
do not need to fulfill the expectation. It is merely a way to tell the USB
device how to keep the timing specified in the periodic list scheduling.
The usb_direction field specifies the direction of the data in
the USB transfer. Only the actual data packet is used to specify the
direction, even if a real transfer consists of a mix of SETUP/OUT/IN/STATUS
packets. USB_Direction_None means that the transfer does not
contain any data, for example, in Set_Address control
transfers. size is the number of bytes the USB host can
receive for IN transfers and the number of bytes sent for OUT
transfers. buf contains the IN or OUT data. Note that buf
can contain data for several data packets concatenated together. The
endpoint descriptors in USB host and USB device define the maximum packet
size for the pipe, but there is no limitation in Simics.
The status field contains the status for the transfer. The status
is typically only set by the USB device. The USB host does not set the
status field when it has completed an IN transfer.
- NAME
-
x86_execution_mode_t
- SYNOPSIS
-
typedef struct x86_execution_mode {
uint64 ac:1,
seam:1,
sgx:1,
smm:1,
vmx_root:1,
vmx_non_root:1;
} x86_execution_mode_t;
- DESCRIPTION
-
Processor execution mode for x86.
Used by
x86_execution_mode_interface_t interface.
- NAME
-
x86_memory_transaction_t
- SYNOPSIS
-
typedef struct x86_memory_transaction {
generic_transaction_t s; /* Superclass */
linear_address_t linear_address;
physical_address_t guest_physical_address;
uint16 segnum; /* segment number */
uint16 access_linear:1; /* Linear access */
uint16 io:1; /* I/O (port) access */
uint16 fault_as_if_write:1;
uint16 guest_phys_valid:1;
processor_mode_t mode;
x86_access_type_t access_type;
x86_memory_type_t pat_type;
x86_memory_type_t mtrr_type;
x86_memory_type_t effective_type;
int sequence_number; /* used for -stall */
} x86_memory_transaction_t;
- DESCRIPTION
-
The s field contains generic information about memory
operations (see
generic_transaction_t).
The mode is the current mode (user or supervisor) of the cpu.
The linear_address contains the address for transactions
with linear addresses.
The access_linear flag is set for all transactions with
linear addresses.
The io flag is set on port accesses (from IN and OUT instructions).
It is cleared for regular memory accesses, and also for memory mapped I/O.
The fault_as_if_write flag indicates that an access should set
the page fault access bits as a write even if the access is a read.
The access_type field contains the type of the transaction.
See online help for expanded output of this type:
api-help x86_access_type_t
typedef enum x86_access_type {
FOR_X86_ACCESS_TYPES(X86_ACCESS_TYPE_ENUM)
} x86_access_type_t;
The effective memory type for the access is contained in
effective_type. The MMU calculates the effective memory type and uses
the pat_type and mtrr_type members as temporary storage and
input to that calculation. The pat_type and mtrr_type members
should not be used by code outside of the MMU.
typedef enum {
X86_None,
X86_Strong_Uncacheable, /* UC */
X86_Uncacheable, /* UC- */
X86_Write_Combining, /* WC */
X86_Write_Through, /* WT */
X86_Write_Back, /* WB */
X86_Write_Protected /* WP */
} x86_memory_type_t;
- NAME
-
x86_sync_instruction_type_t
- SYNOPSIS
-
typedef enum {
X86_SFence = 1,
X86_LFence = 2,
X86_MFence = 3
} x86_sync_instruction_type_t;
- DESCRIPTION
-
Type of synchronisation instruction for x86.
Used in the
Core_Sync_Instruction hap.
- NAME
-
xtensa_memory_transaction_t
- SYNOPSIS
-
typedef struct xtensa_memory_transaction {
/* generic transaction */
generic_transaction_t s;
} xtensa_memory_transaction_t;
- DESCRIPTION
-
The s field contains generic information about memory operations (see
generic_transaction_t).
- NAME
-
addr_type_t,
byte_string_t,
struct ether_addr,
event_queue_type_t,
icode_mode_t,
image_spage_t,
instruction_trace_callback_t,
intervals_func_t,
interval_set_t,
interval_set_iter_t,
os_time_t,
struct os_tm,
page_info_t,
prof_data_t,
prof_data_address_t,
prof_data_counter_t,
prof_data_iter_t,
rand_state_t,
range_node_t,
sim_ic_type_t,
simics_internal_counters_t,
socket_t,
state_save_kind_t,
strbuf_t,
struct simcontext,
vtmem_inform_opcode_t
- DESCRIPTION
-
These data types are exported for Simics internal use.
- NAME
-
SIM_alloc_attr_dict — create empty attribute dictionary
- SYNOPSIS
-
attr_value_t
SIM_alloc_attr_dict(unsigned length);
- DESCRIPTION
-
Returns an
attr_value_t of type
dict with size len. The dictionary
elements are initialized to invalid values.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_attr_dict_set_item, SIM_alloc_attr_list
- NAME
-
SIM_alloc_attr_list — create uninitialized attribute list
- SYNOPSIS
-
attr_value_t
SIM_alloc_attr_list(unsigned length);
- DESCRIPTION
-
Returns an
attr_value_t of type
list with size length. The list
elements are initialized to invalid values.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_make_attr_list, SIM_attr_list_set_item
- NAME
-
SIM_attr_copy — copy attribute value
- SYNOPSIS
-
attr_value_t
SIM_attr_copy(attr_value_t val);
- DESCRIPTION
-
Return a deep copy of val. The caller obtains ownership
of the copy and needs to free it after use; the argument is not modified.
This function is not available from Python.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_attr_free
- NAME
-
SIM_attr_dict_resize — resize dict attribute value
- SYNOPSIS
-
void
SIM_attr_dict_resize(attr_value_t *NOTNULL attr, unsigned newsize);
- DESCRIPTION
-
Resize attr, which must be of dict type, to
newsize elements. New elements are marked invalid.
Dropped elements are freed.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_attr_dict_set_item — set dict attribute element
- SYNOPSIS
-
void
SIM_attr_dict_set_item(attr_value_t *NOTNULL attr, unsigned index,
attr_value_t key, attr_value_t value);
- DESCRIPTION
-
Set the element numbered index of the dict
attr to key and value. The
previous key and value at that position are freed. The ownership for
key and value is transferred from the caller to
attr. The key must be of integer, string or
object type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_attr_free, SIM_free_attribute — free attribute
- SYNOPSIS
-
void
SIM_attr_free(attr_value_t *NOTNULL value);
void
SIM_free_attribute(attr_value_t value);
- DESCRIPTION
-
Free the memory allocation used by the value pointed to by
value. For values of list or dict type, this recursively
frees all contents; for string or data values, the allocation containing the
payload is freed. It is an error to use the value or any sub-part of it
after it has been freed.
SIM_attr_free is the preferred call because it changes the type
of the argument variable to Invalid, preventing accidental use after
freeing. SIM_free_attribute only differs in how the argument is
passed, but cannot change the argument variable as it is passed by value.
Note:
These functions are not available in Python; memory
allocation is managed automatically there.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_attr_integer, SIM_attr_boolean, SIM_attr_string, SIM_attr_string_detach, SIM_attr_floating, SIM_attr_object, SIM_attr_object_or_nil, SIM_attr_data_size, SIM_attr_data, SIM_attr_list_size, SIM_attr_list_item, SIM_attr_list, SIM_attr_dict_size, SIM_attr_dict_key, SIM_attr_dict_value — extract values stored in
attr_value_t values
- SYNOPSIS
-
FORCE_INLINE int64
SIM_attr_integer(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_boolean(attr_value_t attr);
FORCE_INLINE const char *
SIM_attr_string(attr_value_t attr);
FORCE_INLINE char *
SIM_attr_string_detach(attr_value_t *attr);
FORCE_INLINE double
SIM_attr_floating(attr_value_t attr);
FORCE_INLINE conf_object_t *
SIM_attr_object(attr_value_t attr);
FORCE_INLINE conf_object_t *
SIM_attr_object_or_nil(attr_value_t attr);
FORCE_INLINE unsigned
SIM_attr_data_size(attr_value_t attr);
FORCE_INLINE const uint8 *
SIM_attr_data(attr_value_t attr);
FORCE_INLINE unsigned
SIM_attr_list_size(attr_value_t attr);
FORCE_INLINE attr_value_t
SIM_attr_list_item(attr_value_t attr, unsigned index);
FORCE_INLINE attr_value_t *
SIM_attr_list(attr_value_t attr);
FORCE_INLINE unsigned
SIM_attr_dict_size(attr_value_t attr);
FORCE_INLINE attr_value_t
SIM_attr_dict_key(attr_value_t attr, unsigned index);
FORCE_INLINE attr_value_t
SIM_attr_dict_value(attr_value_t attr, unsigned index);
- DESCRIPTION
-
Extract a value encapsulated in attr. It is an error to
call an accessor function with an attr of the wrong type.
SIM_attr_integer returns the integer attribute value
modulo-reduced to the interval
[−263,263−1].
(Converting the return value to uint64 gives the integer
attribute value modulo-reduced to [0,264−1].)
SIM_attr_string, SIM_attr_data and
SIM_attr_list return values owned by attr.
Ownership is not transferred to the caller.
SIM_attr_string_detach returns the string
in attr and changes the value pointed to by
attr into a nil attribute. Ownership of the string is
transferred to the caller.
SIM_attr_object_or_nil accepts an attr parameter
of either object or nil type. In case of a nil attribute, the function
returns NULL.
SIM_attr_list_size and SIM_attr_dict_size return
the number of items in the list and key-value pairs in the dict
respectively. SIM_attr_data_size returns the number of bytes
in the data value.
SIM_attr_list_item returns the item at index.
The index must be less than the number of items in the list. The item
returned is still owned by attr. Ownership is not
transferred to the caller.
SIM_attr_list returns a pointer directly into the internal
array of the attribute value; it is mainly present as an optimisation. Use
SIM_attr_list_item and SIM_attr_list_set_item
for type-safety instead.
SIM_attr_dict_key and SIM_attr_dict_value return
the key and value at index. The index must be less than the
number of items in the dict. The value returned is still owned by
attr. Ownership is not transferred to the caller.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_attr_is_integer, SIM_attr_is_boolean, SIM_attr_is_string, SIM_attr_is_floating, SIM_attr_is_object, SIM_attr_is_invalid, SIM_attr_is_data, SIM_attr_is_list, SIM_attr_is_dict, SIM_attr_is_nil, SIM_attr_is_int64, SIM_attr_is_uint64 —
attr_value_t type predicates
- SYNOPSIS
-
FORCE_INLINE bool
SIM_attr_is_integer(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_boolean(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_string(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_floating(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_object(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_invalid(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_data(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_list(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_dict(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_nil(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_int64(attr_value_t attr);
FORCE_INLINE bool
SIM_attr_is_uint64(attr_value_t attr);
- DESCRIPTION
-
Indicates whether the value stored in attr is of the specified
type. SIM_attr_is_int64 and SIM_attr_is_uint64
additionally test whether the integer value would fit in the given C type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_attr_list_resize — resize list attribute value
- SYNOPSIS
-
void
SIM_attr_list_resize(attr_value_t *NOTNULL attr, unsigned newsize);
- DESCRIPTION
-
Resize attr, which must be of list type,
to newsize elements.
New elements are set to invalid value.
Dropped elements are freed.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_attr_list_set_item — set list attribute element
- SYNOPSIS
-
void
SIM_attr_list_set_item(attr_value_t *NOTNULL attr, unsigned index,
attr_value_t elem);
- DESCRIPTION
-
Set the element numbered index of the list
attr to elem. The previous value at
that position is freed. The ownership for elem is transferred
from the caller to attr.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_attr_scanf, SIM_ascanf — parse list attribute values
- SYNOPSIS
-
bool
SIM_attr_scanf(attr_value_t *NOTNULL list, const char *NOTNULL fmt, ...);
bool
SIM_ascanf(attr_value_t *NOTNULL list,
const char *NOTNULL fmt, ...) __attribute__((alias("SIM_attr_scanf")));
- DESCRIPTION
-
Reads and converts entries in list according to the format
string fmt. Returns
true if all elements were
successfully converted, false otherwise.
The characters in the format string mean:
| format char |
argument type |
element must be |
i |
int64 * |
integer |
b |
int * |
boolean |
f |
double * |
floating |
s |
const char ** |
string |
S |
const char ** |
string or nil |
o |
conf_object_t ** |
object |
O |
conf_object_t ** |
object or nil |
l |
attr_value_t ** |
list |
d |
attr_value_t ** |
data |
a |
attr_value_t ** |
any except invalid |
The fmt string may also include a period (.) at the end,
taken to mean that more elements may follow. If the period is not present,
the length of the list must equal the number of specified elements.
Converted values of type attr_value_t * and
const char * are still owned by list.
SIM_ascanf is an alias of SIM_attr_scanf
and will be deprecated.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_make_attr_boolean — make boolean attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_boolean(bool b);
- DESCRIPTION
-
Returns an
attr_value_t of boolean type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_data, SIM_make_attr_data_adopt — create raw data attribute
- SYNOPSIS
-
attr_value_t
SIM_make_attr_data(size_t size, const void *data);
FORCE_INLINE attr_value_t
SIM_make_attr_data_adopt(size_t size, void *data);
- DESCRIPTION
-
Returns an
attr_value_t of type data using
size and data for the binary data.
The maximum size of the binary data is 2**32-1 bytes, i.e.
size should fit into a 32-bit unsigned integer.
SIM_make_attr_data will make a copy of the argument data.
SIM_make_attr_data_adopt is mainly provided for compatibility;
it will assume ownership of the argument data, which must have been
allocated using one of the MM_MALLOC functions.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_make_attr_floating — make floating point attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_floating(double d);
- DESCRIPTION
-
Returns an
attr_value_t of floating type with value
d.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_int64, SIM_make_attr_uint64 — make integer attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_int64(int64 i);
FORCE_INLINE attr_value_t
SIM_make_attr_uint64(uint64 i);
- DESCRIPTION
-
Returns an
attr_value_t of integer type with value
i.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_invalid — make invalid attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_invalid(void);
- DESCRIPTION
-
Returns an
attr_value_t of invalid type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_list, SIM_make_attr_list_vararg — make list attribute
- SYNOPSIS
-
attr_value_t
SIM_make_attr_list(unsigned length, ...);
attr_value_t
SIM_make_attr_list_vararg(unsigned length, va_list va);
- DESCRIPTION
-
Returns an
attr_value_t of type list
with size length. The list is filled with data from the
arguments following, which should be of type attr_value_t.
This function must be called with exactly length+1 arguments.
The attribute parameters should all be valid attributes; e.g.,
attributes of invalid type are not allowed.
The length argument must be a constant expression.
The newly created list assumes ownership of the passed parameters, which
therefore should not be freed.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_alloc_attr_list
- NAME
-
SIM_make_attr_nil — make nil attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_nil(void);
- DESCRIPTION
-
Returns an
attr_value_t of type nil.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_object — make object attribute
- SYNOPSIS
-
FORCE_INLINE attr_value_t
SIM_make_attr_object(conf_object_t *obj);
- DESCRIPTION
-
Returns an
attr_value_t of object type
with value obj. Returns a nil value if
obj is NULL.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_attr_string, SIM_make_attr_string_adopt — make string attribute
- SYNOPSIS
-
attr_value_t
SIM_make_attr_string(const char *str);
FORCE_INLINE attr_value_t
SIM_make_attr_string_adopt(char *str);
- DESCRIPTION
-
Returns an
attr_value_t of type string with value
str. Returns Nil if str is NULL.
SIM_make_attr_string will make a copy of the argument string.
SIM_make_attr_string_adopt is mainly provided for
compatibility; it will assume ownership of the argument string, which
must have been allocated using one the MM_MALLOC functions.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_attribute_error, SIM_c_attribute_error — specify reason for attribute error
- SYNOPSIS
-
void
SIM_attribute_error(const char *NOTNULL msg);
void
SIM_c_attribute_error(const char *NOTNULL msg, ...);
- DESCRIPTION
-
When used inside an attribute set_attr/get_attr
method, indicates why it failed to set or retrieve the attribute.
This function only serves to give an informative message to the user.
The object or attribute names need not be mentioned in the
msg argument; Simics will supply this automatically.
SIM_c_attribute_error is similar but the msg
argument and those following it are used for string formatting in the
same way as in the standard sprintf function. This function
is not available from Python.
The error message supplied will be attached to any frontend exception
generated by the attribute access.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_attribute,
SIM_get_attribute, SIM_set_attribute
- NAME
-
SIM_class_port — check if class has specified port object
- SYNOPSIS
-
conf_class_t *
SIM_class_port(const conf_class_t *NOTNULL cls, const char *NOTNULL name);
- DESCRIPTION
-
Returns the class of objects on the port named name,
or NULL if no such port is registered.
- SEE ALSO
-
SIM_register_port, SIM_register_simple_port
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_copy_class — create a copy of an existing class
- SYNOPSIS
-
conf_class_t *
SIM_copy_class(const char *NOTNULL name, const conf_class_t *NOTNULL src_cls,
const char *desc);
- DESCRIPTION
-
This function creates a copy of the class src_class
named name.
Additional attributes and interfaces can be registered on the
newly created class.
The new class is described by desc unless
this parameter is NULL which means that the original class description
should be used.
- RETURN VALUE
-
The newly created class is returned.
- SEE ALSO
-
SIM_extend_class, SIM_create_class
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_create_class — create class
- SYNOPSIS
-
conf_class_t *
SIM_create_class(const char *NOTNULL name,
const class_info_t *NOTNULL class_info);
- DESCRIPTION
-
This function creates a new class that can be instantiated by
calling the SIM_create_object function. It is a
replacement for SIM_register_class and should be
used in all new code.
The name can contain upper and lower case ASCII letters,
hyphens, underscores, and digits. It must not begin with a digit or a hyphen
and must not end with a hyphen.
class_info may be freed when the function has returned.
typedef enum {
Sim_Class_Kind_Vanilla = 0, /* object is saved at checkpoints */
Sim_Class_Kind_Session = 1, /* object is saved as part of a
* session only */
Sim_Class_Kind_Pseudo = 2, /* object is never saved */
Sim_Class_Kind_Extension = 3, /* extension class
(see SIM_extend_class) */
} class_kind_t;
typedef struct class_info {
conf_object_t *(*alloc)(conf_class_t *cls);
lang_void *(*init)(conf_object_t *obj);
void (*finalize)(conf_object_t *obj);
void (*objects_finalized)(conf_object_t *obj);
void (*deinit)(conf_object_t *obj);
void (*dealloc)(conf_object_t *obj);
const char *description;
const char *short_desc;
class_kind_t kind;
} class_info_t;
- RETURN VALUE
-
Class structure, or
NULL on error.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_register_class_alias, class_info_t
- NAME
-
SIM_ensure_partial_attr_order — ensure attribute order
- SYNOPSIS
-
void
SIM_ensure_partial_attr_order(conf_class_t *NOTNULL cls,
const char *NOTNULL before,
const char *NOTNULL after);
- DESCRIPTION
-
Attribute initialization order is guaranteed to be identical to the order
in which the attributes were registered. In some cases a particular order
is required in order for a model to work correctly.
This function checks the registration order of the attributes
before and after in the class
cls. If before is not registered
before after, or if at least one of the two are not
registered at all, an ASSERT is triggered.
Use this function to ensure that e.g. code refactoring does not break
a required attribute order.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_attribute
- NAME
-
SIM_extend_class — extend class with contents from an extension class
- SYNOPSIS
-
void
SIM_extend_class(conf_class_t *NOTNULL cls, conf_class_t *NOTNULL ext);
- DESCRIPTION
-
The function extends the class cls with attributes,
interfaces, port objects and port interfaces defined by the
extension class ext.
The extension class must be of the type
Sim_Class_Kind_Extension and must not define any attributes
or interfaces which have already been defined by the class being
augmented.
Besides normal object initialization, the init_object
method for the extension class, will be called when
cls is instantiated. The pointer returned by
init_object can be retrieved using
SIM_extension_data. The init_object method
may return NULL if no private data pointer is needed; this does
not signify an error condition for extension classes.
The finalize_instance method defined by the extension class
will be called before the finalize_instance method is called for
the class being extended.
The SIM_extension_class function is intended to be used
to extend a class with generic functionality, common to multiple
classes.
- SEE ALSO
-
SIM_create_class, SIM_register_class, SIM_extension_data
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_extension_data — get class extension data
- SYNOPSIS
-
void *
SIM_extension_data(conf_object_t *obj, conf_class_t *ext_cls);
- DESCRIPTION
-
Returns the private data pointer of an object associated
with the extension class ext_cls. The returned pointer is
the value returned by the init_object method called
for the extension class ext_cls.
The object obj must be an instance of a class
which has been extended with the extension class ext_cls
using the SIM_extend_class function.
- SEE ALSO
-
SIM_object_data, SIM_register_class, SIM_extend_class
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_class — get class
- SYNOPSIS
-
conf_class_t *
SIM_get_class(const char *NOTNULL name);
- DESCRIPTION
-
Returns the configuration class called name.
If it finds no class called name, SIM_get_class
will load a module implementing that class, if any can be found, and return
the newly created class.
Note that loading a module can not be done during the simulation execution:
in that case, SIM_get_class will trigger an error instead. If
you encounter this problem, a simple work-around is to make sure that all
necessary modules are loaded before starting the execution.
- RETURN VALUE
-
Opaque pointer referencing the class,
or NULL if not found.
- EXCEPTIONS
-
SimExc_General Thrown if the class has not been registered.
- EXECUTION CONTEXT
-
Cell Context, except when loading a module.
- SEE ALSO
-
SIM_get_class_name
- NAME
-
SIM_get_class_data — get class data
- SYNOPSIS
-
lang_void *
SIM_get_class_data(conf_class_t *cls);
- DESCRIPTION
-
Obtain the class data that was set using SIM_set_class_data. This
can be called at any time during the object initialisation process.
- SEE ALSO
-
SIM_set_class_data
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_class_name — get class name
- SYNOPSIS
-
const char *
SIM_get_class_name(const conf_class_t *NOTNULL class_data);
- DESCRIPTION
-
Returns the name of the class. Simics retains ownership of the returned
string; it must not be modified or freed by the caller.
In Python, the name of an object's class is available via
the classname attribute:
obj.classname
.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_class
- NAME
-
SIM_get_interface, SIM_c_get_interface, SIM_get_class_interface, SIM_c_get_class_interface, SIM_get_port_interface, SIM_c_get_port_interface, SIM_get_class_port_interface, SIM_c_get_class_port_interface — get interface
- SYNOPSIS
-
const void *
SIM_get_interface(const conf_object_t *NOTNULL obj, const char *NOTNULL name);
const void *
SIM_c_get_interface(const conf_object_t *NOTNULL obj, const char *NOTNULL name);
const void *
SIM_get_class_interface(const conf_class_t *NOTNULL cls,
const char *NOTNULL name);
const void *
SIM_c_get_class_interface(const conf_class_t *NOTNULL cls,
const char *NOTNULL name);
const void *
SIM_get_port_interface(const conf_object_t *NOTNULL obj,
const char *NOTNULL name, const char *portname);
const void *
SIM_c_get_port_interface(const conf_object_t *NOTNULL obj,
const char *NOTNULL name,
const char *portname);
const void *
SIM_get_class_port_interface(const conf_class_t *NOTNULL cls,
const char *NOTNULL name,
const char *portname);
const void *
SIM_c_get_class_port_interface(const conf_class_t *NOTNULL cls,
const char *NOTNULL name,
const char *portname);
- DESCRIPTION
-
Get the interface with name name from object
obj. Returns NULL, and raises an exception if
obj does not implement the interface.
SIM_get_port_interface returns a port interface
instance as registered with
SIM_register_port_interface. The
portname selects a particular implementation of the
interface by obj's class. If no port name is supplied,
the function behaves as SIM_get_interface.
SIM_get_class_interface and
SIM_get_class_port_interface are similar but return the
interface for a class instead of an object.
SIM_c_get_interface,
SIM_c_get_port_interface,
SIM_c_get_class_interface and
SIM_c_get_class_port_interface are similar to their respective
counterparts but never raise an exception, nor do they accept dashes
inside name or portname instead of
underscores.
The SIM_C_GET_INTERFACE macro is a useful type-safe replacement
for SIM_c_get_interface. The macro takes an object and the name of the
interface without quotes. Compare the three forms:
SIM_c_get_interface(obj, PCI_DEVICE_INTERFACE);
SIM_c_get_interface(obj, "pci_device");
SIM_C_GET_INTERFACE(obj, pci_device);
The data the result points to is owned by Simics. The caller
must not deallocate or modify it.
In Python, there is usually no need to use these functions
since Simics objects' interfaces are available via the iface
attribute. Here is sample Python code calling
the signal_raise method of the object's
signal interface:
obj.iface.signal.signal_raise()
In a similar way one can call interfaces of an object's
port objects. Here is a respective example where
an object obj with a port object obj.port.reset
has a signal interface:
obj.port.reset.iface.signal.signal_raise()
Port interfaces - interfaces that are registered with
SIM_register_port_interface and are considered legacy - are also
directly accessible in Python. Here is sample code calling
the signal_raise method of the signal interface
from the object's RESET port:
obj.ports.RESET.signal.signal_raise()
In order to check if a Simics object implements an interface
the following Python code can be used:
if hasattr(obj.iface, "signal"): # check whether obj has signal interface
...
- RETURN VALUE
-
Pointer to interface, or NULL if not found.
- EXCEPTIONS
-
SimExc_Lookup Thrown if the interface is not implemented by
obj's class.
SimExc_General Thrown if the interface name is illegal.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_register_interface
- NAME
-
SIM_is_restoring_state — check if state restoring phase
- SYNOPSIS
-
bool
SIM_is_restoring_state(conf_object_t *obj);
- DESCRIPTION
-
Returns true if the configuration system is currently restoring the saved
state for the object
obj when reading a checkpoint, applying a
persistent state or restoring a snapshot.
SIM_is_restoring_state is typically used to prevent side effects
in attribute set methods that only should run when the attribute is set
manually, for example when hot plugging.
|
SIM_object_is_configured |
SIM_is_restoring_state |
| Creating object | false | false |
| Loading checkpoint | false | true |
| Loading persistent state | true | true |
| Loading snapshot | true | true |
| Manual attribute access (hot plug) |
true | false |
LIMITATION: This function currently returns true for all objects in Simics
while some state is being restored and not only for the affected objects.
- SEE ALSO
-
SIM_object_is_configured
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_marked_for_deletion — is object being deleted
- SYNOPSIS
-
bool
SIM_marked_for_deletion(const conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Indicates if the given object is being deleted. This information can be
useful by other objects that want to clean up their references.
- RETURN VALUE
-
true if the object is being
deleted.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_delete_objects
- NAME
-
SIM_object_clock — get object clock
- SYNOPSIS
-
conf_object_t *
SIM_object_clock(const conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Retrieve the default clock used by an object. This is either set by
the queue attribute, or inherited from the default clock of
the object's parent. The default clock is used as time reference for the
object.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_object_data — get object-specific data pointer
- SYNOPSIS
-
lang_void *
SIM_object_data(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the private data pointer of an object. This pointer is
available to the class for storing instance-specific state.
It is initialised to the return value of the init
(from class_info_t) method
that is called during object creation. For classes created using
the legacy SIM_register_class, the same functionality
is provided by the init_object method .
For classes implemented in Python, the data (which is then a Python
value) can also be accessed as obj.object_data.
For classes written in C, the preferred way to store
instance-specific state is by co-allocation with the object's
conf_object_t structure instead of using
SIM_object_data. Such classes should define the
alloc method in the class_info_t
passed to SIM_create_class for allocating its instance
data. For classes using the legacy SIM_register_class
class registration function, they should define the
alloc_object method in the class_data_t
data structure.
- SEE ALSO
-
SIM_create_class, SIM_register_class
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_object_id — get object identifier
- SYNOPSIS
-
const char *
SIM_object_id(const conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the unique identifier for an object. The identifier is a
string that is guaranteed to be unique and will never change, even
if the object moves to another hierarchical location.
The return value is a static string that should not be modified or
freed by the caller.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_object_name
- NAME
-
SIM_object_is_configured, SIM_set_object_configured — get/set configured status
- SYNOPSIS
-
bool
SIM_object_is_configured(const conf_object_t *NOTNULL obj);
void
SIM_set_object_configured(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
SIM_object_is_configured indicates whether
obj is configured. SIM_set_object_configured
sets the object as configured.
An object is configured once its finalize_instance method
(post_init in DML) has completed, or
SIM_set_object_configured has been called for it. Being
configured indicates that the object is in a consistent state and is
ready to be used by other objects.
SIM_set_object_configured is used to avoid circular
dependencies between objects. It may only be called from the object's
own finalize_instance method, when the object is known to
be in a consistent state.
- EXECUTION CONTEXT
-
SIM_object_is_configured:
all contexts (including Threaded Context);
SIM_set_object_configured: Global Context
- SEE ALSO
-
SIM_require_object, SIM_register_class, SIM_is_restoring_state
- NAME
-
SIM_object_name — get object name
- SYNOPSIS
-
const char *
SIM_object_name(const conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the name of an object. This name identifies the object
uniquely, but may change if the object is moved to another
hierarchical location.
The return value is a string, owned by obj, that should not be
modified or freed by the caller.
In Python, an object's name is available via the name attribute:
obj.name
.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_object_id
- NAME
-
SIM_picosecond_clock — get object picosecond clock
- SYNOPSIS
-
conf_object_t *
SIM_picosecond_clock(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Return the picosecond clock used by an object obj.
The returned clock uses a cycle period of exactly 1 ps. It
has full picosecond resolution even if the processor (or clock)
driving the simulation uses a lower resolution.
An event posted at a particular picosecond triggers always at that
precise time, without any rounding issues.
The returned object is the vtime.ps port object of
the default clock for the object, and it implements the
cycle_event interface.
The API functions SIM_event_post_cycle,
SIM_event_post_time, SIM_event_find_next_cycle,
SIM_event_cancel_time, and SIM_cycle_count
can be used directly on the picosecond clock.
Note:
The function SIM_time is currently not
supported for the picosecond clock; it will return
same value as if the function is invoked on the default clock.
Note:
The picosecond clock will wrap around after roughly
200 days of virtual time (2^64 ps).
- SEE ALSO
-
SIM_object_clock
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_register_attribute, SIM_register_class_attribute, SIM_register_attribute_with_user_data, SIM_register_class_attribute_with_user_data — register attribute
- SYNOPSIS
-
void
SIM_register_attribute(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(conf_object_t *),
set_error_t (*set_attr)(conf_object_t *, attr_value_t *),
attr_attr_t attr, const char *type, const char *desc);
void
SIM_register_class_attribute(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(conf_class_t *),
set_error_t (*set_attr)(conf_class_t *, attr_value_t *),
attr_attr_t attr, const char *type, const char *desc);
void
SIM_register_attribute_with_user_data(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(conf_object_t *, lang_void *),
lang_void *user_data_get,
set_error_t (*set_attr)(conf_object_t *, attr_value_t *, lang_void *),
lang_void *user_data_set,
attr_attr_t attr, const char *type, const char *desc);
void
SIM_register_class_attribute_with_user_data(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(conf_class_t *, lang_void *),
lang_void *user_data_get,
set_error_t (*set_attr)(conf_class_t *, attr_value_t *, lang_void *),
lang_void *user_data_set,
attr_attr_t attr, const char *type, const char *desc);
- DESCRIPTION
-
Add the attribute name to the set of attributes
of the class cls.
For SIM_register_attribute and
SIM_register_class_attribute, the function
get_attr is called with the object as argument, and returns
the current value of the attribute. For
SIM_register_attribute_with_user_data and
SIM_register_class_attribute_with_user_data, the function
get_attr takes an additional user data argument, which takes
the value passed as user_data_get.
On error, get_attr should call
SIM_attribute_error. The return value is then ignored; typically,
SIM_make_attr_invalid is used to generate an explicitly invalid
value.
If get_attr is a null pointer, the attribute will be
write-only.
For SIM_register_attribute and
SIM_register_class_attribute, the function
set_attr is called with the object as argument. For
SIM_register_attribute_with_user_data and
SIM_register_class_attribute_with_user_data, the function
set_attr takes an additional user data argument, which takes
the value passed as user_data_set. The
set_attr function is called when the attribute is initialised
or changed. The argument value is owned by the caller, so any data from it
must be copied.
The set_attr method should return Sim_Set_Ok
if the new value could be set. On error, it should return an appropriate
error code (usually Sim_Set_Illegal_Value), and optionally
call SIM_attribute_error with an explanatory message.
If set_attr is a null pointer, the attribute will be
read-only.
The attr parameter is one of
Sim_Attr_Required, Sim_Attr_Optional or
Sim_Attr_Pseudo.
Attributes marked Sim_Attr_Required or
Sim_Attr_Optional are saved in checkpoints. Both
set_attr and get_attr must be non-null
for such attributes.
All attributes that are marked Sim_Attr_Required
must be present in all configurations.
The set of permitted values is encoded in the string type.
The type strings are composed as follows:
-
Most types are represented by a single letter:
i |
integer |
f |
floating-point |
s |
string |
b |
boolean |
o |
object |
d |
data |
n |
nil |
a |
any type (not valid when the attribute is marked with
Sim_Attr_Required) |
-
The
| (vertical bar) operator specifies the union of
two types; eg, s|o is the type of a string or an object.
-
Lists are defined inside square brackets:
[]. There are two
kinds of list declarations:
Inside heterogeneous lists, | (union) has higher precedence
than juxtaposition; ie, [i|so|n] defines a list of two
elements, the first being an integer or a string and the second
an object or NIL.
SIM_register_class_attribute and
SIM_register_class_attribute_with_user_data will register a class
attribute. Class attributes are the same for all instances of the class.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_class — register class
- SYNOPSIS
-
conf_class_t *
SIM_register_class(const char *NOTNULL name,
const class_data_t *NOTNULL class_data);
- DESCRIPTION
-
This function is considered legacy. New code should use the
SIM_create_class function to create new classes
in the Simics simulator.
The function registers a new class that can be instantiated by
calling the SIM_create_object function.
The name can contain upper and lower case ASCII letters,
hyphens, underscores, and digits. It must not begin with a digit or a hyphen
and must not end with a hyphen.
class_data may be freed when the function has returned.
typedef struct class_data {
conf_object_t *(*alloc_object)(lang_void *data);
lang_void *(*init_object)(conf_object_t *obj, lang_void *data);
void (*finalize_instance)(conf_object_t *obj);
void (*pre_delete_instance)(conf_object_t *obj);
int (*delete_instance)(conf_object_t *obj);
const char *description;
const char *class_desc;
class_kind_t kind;
} class_data_t;
- RETURN VALUE
-
Class structure, or
NULL on error.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_create_class, SIM_register_class_alias, class_data_t
- NAME
-
SIM_register_class_alias — register class alias
- SYNOPSIS
-
void
SIM_register_class_alias(const char *NOTNULL alias, const char *NOTNULL name);
- DESCRIPTION
-
Register an alias alias for the existing
class class_name. Using aliases allows the
read-configuration command to read configuration files that
define objects of type alias, while the
write-configuration command always uses class_name.
Aliases are used to support compatibility with old class names if a
class is renamed. They can also be used to allow different modules,
which define different specific implementations of the same generic
base class, to read the same configuration files.
- SEE ALSO
-
SIM_create_class, SIM_register_class
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_clock — register mandatory interface and attributes for clock objects
- SYNOPSIS
-
int
SIM_register_clock(conf_class_t *NOTNULL cls,
const cycle_interface_t *NOTNULL iface);
- DESCRIPTION
-
Register the cls class as a class for schedulable clock
objects. This includes registering the
cycle interface
(iface), in addition to which SIM_register_clock
registers the cell attribute required for scheduling the clock
and some other Simics specific attributes. Simics will be able to schedule
objects instantiated from the class cls.
The return value is 0 if everything works, and non-zero if something
fails. Depending on the stage that failed, SIM_register_clock()
will return the error value provided by SIM_register_interface().
- RETURN VALUE
-
Returns non-zero on failure, 0 otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if the
cycle interface has
already been registered for this class.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_register_interface,
SIM_register_attribute
- NAME
-
SIM_register_compatible_interfaces — register earlier versions of interface
- SYNOPSIS
-
void
SIM_register_compatible_interfaces(conf_class_t *NOTNULL cls,
const char *NOTNULL name);
- DESCRIPTION
-
Register any earlier versions of the interface name for class
cls. The interface name must already be registered for
the class.
When supported, this function lets a module implement a single version of an
interface while still exporting earlier versions.
The following interfaces are currently accepted by this function, with the
additional interfaces that are exported given in parenthesis:
BREAKPOINT_QUERY_V2, PROCESSOR_INFO_V2 (PROCESSOR_INFO).
- EXCEPTIONS
-
SimExc_General Thrown if no interface is registered with the given
name, if compatible versions of the interface have already been registered,
or if the interface does not have any earlier versions that this function
knows about.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_interface, SIM_register_port_interface — register interface
- SYNOPSIS
-
int
SIM_register_interface(conf_class_t *NOTNULL cls, const char *NOTNULL name,
const void *NOTNULL iface);
int
SIM_register_port_interface(conf_class_t *NOTNULL cls,
const char *NOTNULL name,
const void *NOTNULL iface,
const char *NOTNULL portname,
const char *desc);
- DESCRIPTION
-
Register that cls implements the name
interface. The interface itself should be supplied in the
iface argument.
SIM_register_port_interface registers a port instance of an
interface that must be looked up using
SIM_get_port_interface. The portname parameter is
the name of the port. The port name may not be the same as any attribute
name used by the class. A short description of the port is provided with the
desc parameter and should be identical for all interfaces for
a port. These two functions are considered legacy. New code should use
SIM_register_port and SIM_register_interface instead.
The data iface points to must not be deallocated or overwritten
by the caller. Simics will use that data to store the interface
structure. It will never be freed or written to by Simics.
- RETURN VALUE
-
Returns non-zero on failure, 0 otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if the interface name is illegal, or if this
interface has already been registered for this class.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_get_interface
- NAME
-
SIM_register_port — register port class
- SYNOPSIS
-
void
SIM_register_port(conf_class_t *NOTNULL cls, const char *NOTNULL name,
conf_class_t *NOTNULL port_cls, const char *desc);
- DESCRIPTION
-
Add a port named name of class port_cls
to the set of ports defined by the class cls.
The result of this is that whenever an object of class cls is
created, Simics will automatically create a port object of class
port_cls. The name of the port object is created by appending
. followed by the name string to the parent object's
name.
If the port name contains dots or brackets, then intermediate port objects
are registered as well. For instance, the port name x.array[2] will
implicitly register ports x of class namespace, and
x.array of class index-map.
Each port name may be registered at most once in a class. One exception is
namespace classes: If the port is registered once as class
namespace and once as some other class, then the namespace
registration is dropped. Also, if a port is registered twice as class
index-map, or twice as class namespace, then the second
registration is dropped.
- SEE ALSO
-
SIM_register_simple_port
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_simple_port — register port
- SYNOPSIS
-
conf_class_t *
SIM_register_simple_port(conf_class_t *NOTNULL cls, const char *NOTNULL name,
const char *desc);
- DESCRIPTION
-
Add a port named name to the set of
ports defined by the class cls. The port will be an
instance of a class named "parent_class_name.portname" where
portname is the specified name of the port with
leading namespaces omitted and any array indices removed.
The port class is created if it does not exist already.
- RETURN VALUE
-
The port class is returned.
- SEE ALSO
-
SIM_register_port
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_typed_attribute, SIM_register_typed_class_attribute — register attribute
- SYNOPSIS
-
int
SIM_register_typed_attribute(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(lang_void *user_data,
conf_object_t *obj,
attr_value_t *idx),
lang_void *user_data_get,
set_error_t (*set_attr)(lang_void *user_data,
conf_object_t *obj,
attr_value_t *val, attr_value_t *idx),
lang_void *user_data_set,
attr_attr_t attr, const char *type, const char *idx_type,
const char *desc);
int
SIM_register_typed_class_attribute(
conf_class_t *NOTNULL cls, const char *NOTNULL name,
attr_value_t (*get_attr)(lang_void *ptr,
conf_class_t *c,
attr_value_t *idx),
lang_void *user_data_get,
set_error_t (*set_attr)(lang_void *ptr,
conf_class_t *c,
attr_value_t *val,
attr_value_t *idx),
lang_void *user_data_set,
attr_attr_t attr, const char *type, const char *idx_type,
const char *desc);
- DESCRIPTION
-
Note:
The functions SIM_register_typed_attribute and
SIM_register_typed_class_attribute are legacy. New code should
use SIM_register_attribute or
SIM_register_class_attribute.
Add the attribute name to the set of attributes
of the class cls.
The function get_attr is called with the object and the value
from user_data_get as arguments, and returns the current
value of the attribute.
On error, get_attr should call
SIM_attribute_error. The return value is then ignored; typically,
SIM_make_attr_invalid is used to generate an explicitly invalid
value.
If get_attr is a null pointer, the attribute will be
write-only.
The function set_attr is called with the object and the value
from user_data_set as arguments when the attribute is
initialised or changed. The argument value is owned by the caller, so any
data from it must be copied.
The set_attr method should return Sim_Set_Ok
if the new value could be set. On error, it should return an appropriate
error code (usually Sim_Set_Illegal_Value), and optionally
call SIM_attribute_error with an explanatory message.
If set_attr is a null pointer, the attribute will be
read-only.
The attr parameter is one of
Sim_Attr_Required, Sim_Attr_Optional
or Sim_Attr_Pseudo.
Attributes marked Sim_Attr_Required or
Sim_Attr_Optional are saved in checkpoints. Both
set_attr and get_attr must be non-null
for such attributes.
All attributes that are marked Sim_Attr_Required
must be present in all configurations.
The set of permitted values is encoded in the string type,
and in idx_type for values during indexed access.
A NULL value for either type string means that values of
any type are permitted.
The type strings are composed as follows:
-
Most types are represented by a single letter:
i |
integer |
f |
floating-point |
s |
string |
b |
boolean |
o |
object |
d |
data |
n |
nil |
D |
dictionary |
a |
any type |
-
The
| (vertical bar) operator specifies the union of
two types; eg, s|o is the type of a string or an object.
-
Lists are defined inside square brackets:
[]. There are two
kinds of list declarations:
Inside heterogeneous lists, | (union) has higher precedence
than juxtaposition; ie, [i|so|n] defines a list of two
elements, the first being an integer or a string and the second
an object or NIL.
SIM_register_typed_class_attribute will register a class
attribute. Class attributes are the same for all instances of the class.
- RETURN VALUE
-
Returns zero if successful, and
non-zero otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if the attribute name is invalid, and if the
attribute is not a required, optional, session or pseudo attribute.
SimExc_AttrNotReadable Thrown if a checkpointed attribute is not
readable.
SimExc_AttrNotWritable Thrown if a checkpointed attribute is not
writable.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_require_object — make sure an object is fully configured
- SYNOPSIS
-
void
SIM_require_object(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
If obj has not yet been set as configured, then that
object's finalize method (post_init in
DML) is run; otherwise, nothing happens. After completion of that
method, obj will be set as configured.
Each object will have its finalize method called automatically,
usually in hierarchical order, during object creation. Since it is only
permitted to call methods on objects that have been configured,
SIM_require_object is a way to allow such calls during
finalisation by ensuring that those objects are correctly set up. A better
way to call methods on other objects during finalization is to defer such
calls to the objects_finalized method.
SIM_require_object may only be called from the
finalize method of another object.
Finalisation cycles can occur if two or more objects call
SIM_require_object on each other. Such cycles are treated as
errors. To avoid them, call SIM_set_object_configured as soon
as the object has reached a consistent state.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_object_is_configured,
SIM_create_class,
SIM_is_restoring_state
- NAME
-
SIM_set_attribute_default — set default value for an attribute in a child object
- SYNOPSIS
-
set_error_t
SIM_set_attribute_default(conf_object_t *NOTNULL obj, const char *NOTNULL name,
attr_value_t val);
- DESCRIPTION
-
SIM_set_attribute_default sets the default value
for attribute name of object obj.
The default value is used if no explicit value has been provided
when the object is instantiated.
After the call val is still owned by the caller.
The function may only called while obj is being
under construction and before its attributes have been set.
More precisely, it is only legal to use this function from
init_object callbacks or from an attribute setters
belonging to a hierarchical ancestor of the object.
The main purpose of this function is setting suitable default
attribute values for port objects.
- RETURN VALUE
-
Returns
Sim_Set_Ok
if successful.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_register_port, SIM_register_class
- NAME
-
SIM_set_class_data — set class data
- SYNOPSIS
-
void
SIM_set_class_data(conf_class_t *cls, lang_void *data);
- DESCRIPTION
-
Set extra data for the specified class. This is particularly useful if the
same class methods are used for multiple distinct classes, for instance for
generated classes.
The class data can be fetched at any time during the object initialisation,
using SIM_get_class_data.
- SEE ALSO
-
SIM_get_class_data
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_cbdata_data — get cbdata data pointer
- SYNOPSIS
-
FORCE_INLINE void *
SIM_cbdata_data(const cbdata_t *cbd);
- DESCRIPTION
-
Return the data pointer of the callback data cbd.
- SEE ALSO
-
cbdata_t
- NAME
-
SIM_cbdata_type — get cbdata type pointer
- SYNOPSIS
-
FORCE_INLINE const cbdata_type_t *
SIM_cbdata_type(const cbdata_t *cbd);
- DESCRIPTION
-
Return a pointer to the type information of the callback data
cbd.
- SEE ALSO
-
cbdata_t
- NAME
-
SIM_free_cbdata — free cbdata
- SYNOPSIS
-
FORCE_INLINE void
SIM_free_cbdata(cbdata_t *cbd);
- DESCRIPTION
-
Free the callback data cbd by calling its
dealloc function.
- SEE ALSO
-
cbdata_t
- NAME
-
SIM_make_cbdata — create cbdata
- SYNOPSIS
-
FORCE_INLINE cbdata_t
SIM_make_cbdata(const cbdata_type_t *type, void *data);
- DESCRIPTION
-
Create new callback data of type type and value
data.
- SEE ALSO
-
cbdata_t
- NAME
-
SIM_make_simple_cbdata — create untyped cbdata
- SYNOPSIS
-
FORCE_INLINE cbdata_t
SIM_make_simple_cbdata(void *obj);
- DESCRIPTION
-
Create new untyped callback data of value data. An untyped
callback data has no dealloc function.
- SEE ALSO
-
cbdata_t
- NAME
-
SIM_clear_exception — clear pending exception
- SYNOPSIS
-
sim_exception_t
SIM_clear_exception();
- DESCRIPTION
-
Clears the currently pending frontend exception and returns the value of it.
- RETURN VALUE
-
Returns the exception that was pending before
the call, or
SimExc_No_Exception.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_pending_exception, SIM_last_error
- NAME
-
SIM_describe_pseudo_exception — return pseudo exception description
- SYNOPSIS
-
const char *
SIM_describe_pseudo_exception(exception_type_t ex);
- DESCRIPTION
-
This function returns a descriptive string for the specified
exception_type_t.
- RETURN VALUE
-
Exception description, or
an error message if input is not a known pseudo-exception.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
exception_type_t
- NAME
-
SIM_get_pending_exception — get current pending exception
- SYNOPSIS
-
sim_exception_t
SIM_get_pending_exception();
- DESCRIPTION
-
This function returns the exception type of the current pending exception,
or
SimExc_No_Exception if none available.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_clear_exception, SIM_last_error
- NAME
-
SIM_last_error — get error message from last frontend exception
- SYNOPSIS
-
const char *
SIM_last_error();
- DESCRIPTION
-
Returns the error message associated with the most recently raised
frontend exception, even if that exception has been cleared.
The returned string is only valid until the next use of the Simics API
in the same thread.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_clear_exception, SIM_get_pending_exception
- NAME
-
SIM_add_notifier — add a notifier callback
- SYNOPSIS
-
notifier_handle_t *
SIM_add_notifier(
conf_object_t *NOTNULL obj,
notifier_type_t type,
conf_object_t *subscriber,
void (*callback)(conf_object_t *subscriber,
conf_object_t *NOTNULL notifier,
lang_void *data),
lang_void *data);
- DESCRIPTION
-
SIM_add_notifier installs a notifier of type type
on the object obj.
The subscriber argument should be the object listening for
the notification; this object is passed as the first
argument to the callback function. The installed callback is
automatically removed if the subscriber object is deleted.
It is legal to pass NULL in the subscriber
argument if there is no object associated with the callback.
The data argument is passed as the last argument to the
callback function.
The function returns a handle to the installed notifier
or NULL if the notifier type is not supported by the object.
Adding a notifier callback from another notifier callback of the same
notifier type and object does not trigger an immediate callback invocation
(from the same call to SIM_notify).
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_delete_notifier
- SEE ALSO
-
SIM_delete_notifier, SIM_register_notifier
- NAME
-
SIM_class_has_notifier — query class for notifier
- SYNOPSIS
-
bool
SIM_class_has_notifier(conf_class_t *NOTNULL cls, notifier_type_t type);
- DESCRIPTION
-
Sim_class_has_notifier returns
true if the class
cls supports the notifier specified by type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_delete_notifier — delete notifier callback
- SYNOPSIS
-
void
SIM_delete_notifier(conf_object_t *NOTNULL obj, notifier_handle_t *handle);
- DESCRIPTION
-
SIM_delete_notifier deletes the notifier callback
specified by the handle handle.
Notifiers callbacks are deleted automatically when
the subscribing object is deleted.
Deleting a notifier callback from another notifier callback of the same
notifier type and object may or may not inhibit the last invocation of the
deleted callback; this is undefined.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_add_notifier
- NAME
-
SIM_describe_notifier, SIM_notifier_description — set short description
- SYNOPSIS
-
void
SIM_describe_notifier(notifier_type_t type, const char *NOTNULL generic_desc);
const char *
SIM_notifier_description(notifier_type_t type);
- DESCRIPTION
-
SIM_describe_notifier sets generic_desc as
a generic description of the notification specified by the type
argument. If the function is called multiple times then the description
supplied during the last invocation of the function will be used.
The generic description is shown when no description has been provided to the
SIM_register_notifier or SIM_register_tracked_notifier
functions.
SIM_notifier_description returns a generic description that
was set with the SIM_describe_notifier
for the notification specified by the type argument, or the empty
string if no description has been set.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_has_notifier — query object for notifier
- SYNOPSIS
-
bool
SIM_has_notifier(conf_object_t *NOTNULL obj, notifier_type_t type);
- DESCRIPTION
-
SIM_has_notifier returns
true if the object
obj supports the notifier specified by type.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_notifier
- NAME
-
SIM_notifier_type — get notifier type
- SYNOPSIS
-
notifier_type_t
SIM_notifier_type(const char *NOTNULL type);
- DESCRIPTION
-
Given a notifier type type specified in the form of a
string, return a
notifier_type_t identifier which uniquely
corresponds to this type.
This function always returns a valid notifier type; if a particular
type string has not been seen before, then a new notifier type is created
and associated with this string.
The string must consist of printable 7-bit ASCII characters, and by
convention it should be expressed as a noun with words separated by dashes.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_notify — trigger notification callbacks
- SYNOPSIS
-
void
SIM_notify(conf_object_t *NOTNULL obj, notifier_type_t type);
- DESCRIPTION
-
The SIM_notify function triggers all callbacks
associated with the notifier notifier which have been
installed on the object obj.
The order in which notifier callbacks are invoked is undefined, but the same
order every time.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_notifier, SIM_add_notifier
- NAME
-
SIM_register_notifier, SIM_register_tracked_notifier — register notifier
- SYNOPSIS
-
void
SIM_register_notifier(conf_class_t *NOTNULL cls, notifier_type_t type,
const char *desc);
void
SIM_register_tracked_notifier(conf_class_t *NOTNULL cls, notifier_type_t type,
const char *desc,
void (*subscribed_changed)(conf_object_t *obj,
notifier_type_t type,
bool has_subscribers));
- DESCRIPTION
-
These functions add the notifier type (returned by
the SIM_notifier_type function) to the set of
notifiers supported by the class cls. The desc
argument can be used to provide any relevant documentation, e.g.,
information about when the notifier is triggered and how it should be used
by the objects that subscribe to it. For uniformity, we suggest formatting
the description similar to this one of the "frequency-change"
notifier: "Notifier that is triggered when frequency changes. New frequency
can be read via the frequency interface of the object."
SIM_register_notifier is the base registration function. It should
be used in most cases.
SIM_register_tracked_notifier accepts an additional argument -
the subscribed_changed callback. This callback can be used
to track whether any respective notification subscribers are installed.
The callback is invoked in following cases:
- a. there are no objects subscribed to type's
notifications from obj of cls class,
and a new object subscribes to such notifications, i.e., calls
SIM_add_notifier. In this case the callback is invoked
with the has_subscribers argument equal to
true.
- b. the only object that was subscribed to type's
notifications from obj of cls class
unsubscribes from such notifications, either explicitly by a
call to SIM_delete_notifier, or implicitly when the
subscriber object is deleted.
In this case the callback is
invoked with the has_subscribers argument equal to
false.
If the subscribed_changed argument is equal to
NULL then it is just ignored.
The subscribed_changed callback is not invoked while the notifier
object is being deleted. Thus, if the callback relies on data structures
owned by the notifier object, then it is still safe for the object's
destructor to deinitialize these data structures needed by the
callback.
It is legal to call SIM_register_notifier multiple times for
the same class and the same notifier type. All subsequent invocations done
after the notifier was registered are ignored. Calling
SIM_register_tracked_notifier multiple times registers multiple
subscribed_changed callbacks. All of them will be invoked as
it is specified above.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_notifier_type,
SIM_notify, SIM_add_notifier
- NAME
-
SIM_add_global_notifier — add a global notifier callback
- SYNOPSIS
-
global_notifier_callback_t *
SIM_add_global_notifier(
global_notifier_type_t type,
conf_object_t *subscriber,
void (*callback)(conf_object_t *subscriber, lang_void *data),
lang_void *data);
- DESCRIPTION
-
SIM_add_global_notifier installs a callback on the global
notifier of type type. The callback will be executed in
Global Context. The callback can uninstall itself, using
SIM_delete_global_notifier, but must not uninstall any other
global notifiers.
The subscriber argument should be the object listening on
the notifier; this object is passed as the first
argument to the callback. The installed callback is automatically
removed if the subscriber object is deleted.
It is legal to pass NULL in the subscriber
argument if there is no object associated with the callback.
The function returns a handle to the installed callback
or NULL if the notifier type is unknown.
Adding a notifier callback from another notifier callback of the same
notifier type does not trigger an immediate callback invocation.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_add_global_notifier_once — add a global notifier callback
- SYNOPSIS
-
global_notifier_callback_t *
SIM_add_global_notifier_once(
global_notifier_type_t type,
conf_object_t *subscriber,
void (*callback)(conf_object_t *subscriber, lang_void *data),
lang_void *data);
- DESCRIPTION
-
The SIM_add_global_notifier_once is similar to
SIM_add_global_notifier, except that the notifier will be removed
automatically after the callback has been called once.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_delete_global_notifier — delete global notifier callback
- SYNOPSIS
-
void
SIM_delete_global_notifier(global_notifier_callback_t *handle);
- DESCRIPTION
-
SIM_delete_global_notifier deletes the global notifier callback
specified by the handle handle.
Global notifier callbacks are deleted automatically when
the subscribing object is deleted.
Deleting a notifier callback from another notifier callback of the same
notifier type may or may not inhibit the last invocation of the deleted
callback; this is undefined.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_hap_add_type — register a new hap type
- SYNOPSIS
-
hap_type_t
SIM_hap_add_type(const char *NOTNULL hap,
const char *NOTNULL params,
const char *param_desc,
const char *index,
const char *desc,
int unused);
- DESCRIPTION
-
Creates a run-time defined hap type.
The params parameter specifies the argument that callbacks
for this hap is called with; e.g., "s" or
"II". The first two arguments are always lang_void *
and conf_object_t * respectively, and should not be included
in that string. The table below shows which characters may be used, and
what their meaning is:
i | an int |
I | an int64 (64 bit integer) |
e | an exception_type_t |
o | a script specific object; i.e.,
void * in C and any Python object in Python |
s | a string |
m | a memory transaction
(generic_transaction_t * in C) |
c | a configuration object
(conf_object_t * in C) |
param_desc should be a string of space-separated
parameter names, or NULL if params is the empty
string. There should be one word in param_desc for each
character in params.
index is a string describing the index value for this hap, or
NULL if there is no index value.
desc is a description string for the hap.
- EXCEPTIONS
-
SimExc_General Thrown if hap is already defined. However, consequent
calls with the same parameters will be successful, and return the same hap
type number each time.
- RETURN VALUE
-
The hap type
number or -1 on error.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_hap_get_name — get hap name by number
- SYNOPSIS
-
const char *
SIM_hap_get_name(hap_type_t hap);
- DESCRIPTION
-
Returns the name of hap, or
NULL for no
such hap. The returned value is a static string that should not
be modified or freed by the caller.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_hap_get_number — get hap number by name
- SYNOPSIS
-
hap_type_t
SIM_hap_get_number(const char *NOTNULL hap);
- DESCRIPTION
-
Return the runtime number associated with a hap identifier. All haps are
listed in the Haps chapter in each reference manual.
- EXCEPTIONS
-
SimExc_Lookup Thrown if no hap is associated with name hap.
- RETURN VALUE
-
The hap type number, or 0 on failure.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_hap_is_active, SIM_hap_is_active_obj, SIM_hap_is_active_obj_idx — check if hap has callbacks
- SYNOPSIS
-
bool
SIM_hap_is_active(hap_type_t hap);
bool
SIM_hap_is_active_obj(hap_type_t hap, conf_object_t *NOTNULL obj);
bool
SIM_hap_is_active_obj_idx(hap_type_t hap, conf_object_t *NOTNULL obj,
int64 index);
- DESCRIPTION
-
Indicate whether the hap has any callback functions to be called
when the hap is triggered with the given arguments (object and
index). The return value is approximate: if false, no functions
would be called; if true, there may be functions to call.
The SIM_hap_is_active function should be avoided; it may be
slower and less precise than the other variants.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_hap_occurred_always, SIM_c_hap_occurred_always_vararg, SIM_c_hap_occurred_always, SIM_hap_occurred, SIM_c_hap_occurred_vararg, SIM_c_hap_occurred — trigger a hap occurrence
- SYNOPSIS
-
int
SIM_hap_occurred_always(hap_type_t hap, conf_object_t *obj,
int64 value, attr_value_t *NOTNULL list);
int
SIM_c_hap_occurred_always_vararg(hap_type_t hap, conf_object_t *obj,
int64 value, va_list ap);
int
SIM_c_hap_occurred_always(hap_type_t hap, conf_object_t *obj,
int64 value, ...);
int
SIM_hap_occurred(hap_type_t hap, conf_object_t *obj,
int64 value, attr_value_t *NOTNULL list);
int
SIM_c_hap_occurred_vararg(hap_type_t hap, conf_object_t *obj,
int64 value, va_list ap);
int
SIM_c_hap_occurred(hap_type_t hap, conf_object_t *obj,
int64 value, ...);
- DESCRIPTION
-
These functions are used to trigger a hap of type
hap. When a hap
triggers, all callback functions installed on the hap are called.
The obj argument is the object that the hap triggering is
associated with. It may be NULL for haps that are not associated with an
object.
The value argument is used for filtering out callback functions to
call based on the index or range that they are installed for. What the
index or range corresponds to is hap specific, but could for example be the
exception number for the Core_Exception hap.
SIM_hap_occurred() will only call the callbacks once every simulated cycle;
if this hap is triggered several times during one cycle, the callbacks will
still only be called once. The SIM_hap_occurred_always() function will
always call the hap callback functions every time. It is recommended that
SIM_hap_occurred_always() is used.
These hap triggering functions return whether or not there were any matching
callback function registered on the hap. This can be useful information when
one wants a default behavior to be triggered (for example, stopping the
simulation) if nobody is listening to the hap.
The hap-specific parameters to the callback function can be passed in
various ways: The SIM_c_hap_occurred... functions are only
available in C/C++ and are variadic or take a va_list as argument.
SIM_hap_occurred and SIM_hap_occurred_always are
mainly intended to be used from Python, taking the parameters from an
attribute value of list type, or an empty list ([]) if no
parameters are passed. In all cases, the number and types of passed
parameters must agree with the hap type definition.
- RETURN VALUE
-
The return value is 0 if no callbacks are
registered on the hap and non-zero if there are callbacks registered.
- EXCEPTIONS
-
SimExc_General Thrown if
hap is not a valid hap type or if
the values in the list argument are of the wrong type.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_hap_remove_type — remove a hap type
- SYNOPSIS
-
void
SIM_hap_remove_type(const char *NOTNULL hap);
- DESCRIPTION
-
Remove a run-time defined hap type.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_log_info, SIM_log_spec_violation, SIM_log_unimplemented, SIM_log_error, SIM_log_critical, SIM_log_message, SIM_log_message_vararg — output log message
- SYNOPSIS
-
void
SIM_log_info(int level, conf_object_t *NOTNULL dev, int grp,
const char *NOTNULL fmt, ...);
void
SIM_log_spec_violation(int level, conf_object_t *NOTNULL dev, int grp,
const char *NOTNULL fmt, ...);
void
SIM_log_unimplemented(int level, conf_object_t *NOTNULL dev, int grp,
const char *NOTNULL fmt, ...);
void
SIM_log_error(conf_object_t *NOTNULL dev, int grp,
const char *NOTNULL fmt, ...);
void
SIM_log_critical(conf_object_t *NOTNULL dev, int grp,
const char *NOTNULL fmt, ...);
void
SIM_log_message(conf_object_t *obj, int level, uint64 group_ids,
log_type_t log_type, const char *message);
void
SIM_log_message_vararg(conf_object_t *NOTNULL obj, int level, uint64 grp,
log_type_t log_type, const char *NOTNULL fmt, ...);
- DESCRIPTION
-
SIM_log_warning(dev, grp, msg) # Python-only
Logging functions and macros are used to emit information and error messages.
The functions above should only be used in Python. In C they are
deprecated and the following preprocessor macros can be used instead.
#define SIM_LOG_INFO(level, dev, grp, ...)
#define SIM_LOG_SPEC_VIOLATION(level, dev, grp, ...)
#define SIM_LOG_UNIMPLEMENTED(level, dev, grp, ...)
#define SIM_LOG_ERROR(dev, grp, ...)
#define SIM_LOG_WARNING(dev, grp, ...)
#define SIM_LOG_CRITICAL(dev, grp, ...)
#define SIM_LOG_INFO_ONCE(level1, level2, dev, grp, ...)
#define SIM_LOG_SPEC_VIOLATION_ONCE(level1, level2, dev, grp, ...)
#define SIM_LOG_UNIMPLEMENTED_ONCE(level1, level2, dev, grp, ...)
#define SIM_LOG_WARNING_ONCE(dev, grp, ...)
The logging macros are among the few API features that may be
called while a frontend exception is pending.
The level parameter indicates the importance; a lower value
means a more important message.
level should be between 1 and 4:
- important messages that are always printed
- "high-level" informative messages
- standard debug messages
- detailed information, such as register accesses
SIM_LOG_ERROR has no level parameter and will always emit
messages.
The grp parameter should have a bit set for each log
group that the message corresponds to, as defined by the
SIM_log_register_groups function, while a value of 0
equals any group.
The level and grp parameters allow
the user to selectively display more or fewer messages using the
log-level, log-group and log-type
commands.
The fmt argument and those following it are used for string
formatting in the same way as in the standard sprintf function.
The use of the different functions and macros is discussed in
Simics Model Builder User's Guide, section "Logging":
- info: Normal informational message
- warning: Unexpected problem in the model, but simulation
can continue.
- error: Unexpected error in the model
(indicates a bug in the model)
- critical: Critical error that will interrupt the simulation
(indicates a bug that the model may not recover from)
- spec_violation: Target program violates the specification
- unimplemented: Attempt to use not yet implemented
functionality
If the sim->stop_on_error attribute is set to true, for
example if Simics was started with the --stop-on-error command
line flag, then Simics will exit with an error code when a log message of the
error type is generated.
If the sim->warnings_as_errors attribute is set to true, for
example if Simics was started with the --warnings-as-errors command
line flag, then a log warning has the same effect as a log error.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- SEE ALSO
-
SIM_log_register_groups, SIM_attribute_error
- NAME
-
SIM_log_level, SIM_set_log_level — set and get log level
- SYNOPSIS
-
unsigned
SIM_log_level(const conf_object_t *NOTNULL obj);
void
SIM_set_log_level(conf_object_t *NOTNULL obj, unsigned level);
- DESCRIPTION
-
Retrieve or set the log level of an object.
The level must be in the range 0..4 inclusive.
Higher values mean more detailed logging.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_log_register_groups — register names of log groups
- SYNOPSIS
-
void
SIM_log_register_groups(conf_class_t *NOTNULL cls,
const char *const *NOTNULL names);
- DESCRIPTION
-
Register a list of log groups that an object can
use to separate messages. The order of the groups in the list defines the
group ids that should be used in calls to SIM_log_info and
similar functions. The group_ids argument to those functions
should have a bit set corresponding to the group; i.e., a value of 1 for the
first group, 2 for the second, 4 for the third, etc. names
should be a
NULL-terminated array.
A class may have up to 63 user-defined log groups.
The Default_Log_Group group is present on all classes. It is used
for log entries where no group is specified.
- EXCEPTIONS
-
SimExc_General Thrown in case of an error, e.g. if log groups are
already registered.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_log_info
- NAME
-
atom_id_t
- DESCRIPTION
-
Each atom type is associated
with a unique id, the
atom_id_t. Most atoms types are
pre-defined by Simics Core and have static ids, but there are
also dynamically assigned ids which are used for custom atom types.
Atom ids are internal to Simics Core and should never be used explicitly
by a Simics models. Instead, there are API functions like
e.g. ATOM_size or ATOM_initiator which should be
used instead.
- NAME
-
atom_t
- DESCRIPTION
-
The
atom_t type is a container
type for tagged data associated with a transaction. The kind of data
stored in the atom is determined by the id field, and a pointer
to the data or the data itself is stored in the ptr field.
Atoms should always be initialized using provided constructor functions
like ATOM_flags or ATOM_size. Usage of
the constructors ensures that the data payload is of the correct type
and that the id is set to the correct value.
Atom lists must be terminated with the special ATOM_LIST_END
marker.
- NAME
-
transaction_completion_t
- SYNOPSIS
-
typedef exception_type_t (*transaction_completion_t)(
conf_object_t *obj, transaction_t *t, exception_type_t ex);
- DESCRIPTION
-
Callback invoked when an asynchronous transaction is completed.
The callback is stored in a
completion atom belonging
to the transaction t. Similarly, obj is an
object stored in either an owner atom or an
initiator atom. The former takes precedence if both are
present.
Completion callbacks are only invoked for transactions monitored
with either SIM_monitor_transaction or
SIM_monitor_chained_transaction, or for transactions
deferred with SIM_defer_owned_transaction.
The completion status for the operation is given in the
ex argument, and is usually equal to
Sim_PE_No_Exception.
The return value of the callback is the completion status
for the transaction t. This status is used to complete
the parent transaction if the transaction is being monitored with
SIM_monitor_chained_transaction. The return value is
also returned by SIM_monitor_transaction or
SIM_monitor_chained_transaction when a transaction is
completed synchronously.
If the callback returns Sim_PE_Deferred, then
the transaction t is left uncompleted. It must then
be completed later on by an explicit call to
SIM_complete_transaction.
- NAME
-
transaction_flags_t
- SYNOPSIS
-
typedef enum {
Sim_Transaction_Fetch = 1 << 0,
Sim_Transaction_Write = 1 << 1,
Sim_Transaction_Control = 1 << 2,
Sim_Transaction_Inquiry = 1 << 8,
Sim_Transaction_Incoherent = 1 << 9,
Sim_Transaction_Atomic = 1 << 10,
} transaction_flags_t;
- DESCRIPTION
-
The
transaction_flags_t type is bitmask
used to specify the transaction type. It is a combination
of the following bits:
Sim_Transaction_Fetch indicates that the transaction is
an instruction fetch.
Sim_Transaction_Write is set if the transaction is a write.
Sim_Transaction_Control is set if the transaction does not
actually transfer any data. One example of such transactions is
cache control operations.
The Sim_Transaction_Inquiry bit signifies that side
effects normally triggered by the transaction should be suppressed.
Examples of side effects include triggering breakpoints and
clearing "read-to-clear" device registers.
When neither Sim_Transaction_Fetch
nor Sim_Transaction_Write is set the transaction is
a read transaction.
- NAME
-
transaction_t
- DESCRIPTION
-
A
transaction_t
represents a memory transaction. The properties of the
transaction is stored in the form of an atom list, where each
atom describes a particular aspect of the transaction, like the
size of the transaction.
The field atoms points to the atoms list,
which must be terminated with the constant ATOM_LIST_END.
The prev field points to an optional parent transaction.
If a particular atom is not found in the atoms list, then the
parent's list of atoms is consulted instead. The prev
pointer is also used when a chained transaction is monitored
with SIM_monitor_chained_transaction.
Besides the fields above, the transaction contains some internal
fields that should be initialized to 0. The internal fields should
not be referenced explicitly since they are likely to change
in future Simics releases.
For details, please refer to "Transactions" chapter in
the Model Builder's User Guide.
- NAME
-
ATOM_flags, ATOM_data, ATOM_size, ATOM_initiator, ATOM_completion, ATOM_list_end — transaction atom's constructor
- SYNOPSIS
-
static inline atom_t ATOM_flags(transaction_flags_t val);
static inline atom_t ATOM_data(uint8 *val);
static inline atom_t ATOM_size(uint32 val);
static inline atom_t ATOM_initiator(conf_object_t *val);
static inline atom_t ATOM_completion(transaction_completion_t val);
static inline atom_t ATOM_list_end(int val);
- DESCRIPTION
-
The functions construct transaction atoms.
ATOM_flags returns a transaction atom specifying transaction
flags (see description of transaction_flags_t for information
about available transaction flags).
ATOM_data returns a transaction atom that holds the pointer
to a buffer that is used to get the data from (for write transactions)
to store the data to (for read and instruction fetch transactions).
ATOM_size returns a transaction atom that holds
the size of a transaction.
ATOM_initiator returns a transaction atom that holds
the initiator of a transaction.
ATOM_completion creates a completion atom - a special atom
that holds a callback that is invoked when a transaction is completed
asynchronously.
ATOM_list_end returns a special atom that should end the list
of transaction atoms. One can use the ATOM_LIST_END macro instead.
- RETURN VALUE
-
An atom value
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- EXAMPLE
-
Sample C code to create a 1-byte read transaction:
uint8 val;
atom_t atoms[] = {
// the flags atom value specifies the transaction type:
// - 0 defines a read transaction
// - Sim_Transaction_Write - a write transaction
// - Sim_Transaction_Fetch - an instruction fetch transaction
ATOM_flags(0),
ATOM_data(&val),
ATOM_size(sizeof val),
ATOM_initiator(obj),
ATOM_LIST_END
};
transaction_t t = { atoms };
- SEE ALSO
-
transaction_t, transaction_flags_t,
transaction_completion_t
- NAME
-
SIM_complete_transaction — complete a deferred transaction
- SYNOPSIS
-
void
SIM_complete_transaction(transaction_t *t, exception_type_t status);
- DESCRIPTION
-
The SIM_complete_transaction completes a previously
deferred transaction t using the exception status
status. The transaction t must be the
return value of a previous call to SIM_defer_transaction
or a transaction passed to SIM_defer_owned_transaction.
If the transaction t has not been monitored, then the
completion code is stored in an internal transaction field
until the transaction is monitored with SIM_monitor_transaction
or SIM_monitor_chained_transaction, at which time
the completion callback is invoked using the stored completion code.
Note that SIM_complete_transaction is normally only used
to complete asynchronous transactions. Synchronous transactions are
completed by returning the appropriate return code directly
from the issue method.
- SEE ALSO
-
SIM_defer_transaction,
SIM_monitor_transaction,
SIM_monitor_chained_transaction,
SIM_poll_transaction
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_defer_owned_transaction — defer transaction completion using an existing transaction
- SYNOPSIS
-
transaction_t *
SIM_defer_owned_transaction(transaction_t *t);
- DESCRIPTION
-
When a transaction cannot be completed immediately in the issue
method of the
transaction interface, then the completion
can be deferred to a later time by calling SIM_defer_transaction
which allocates a new transaction. One alternative is calling
SIM_defer_owned_transaction which allows the caller to
allocate the deferred transaction explicitly, in which case
provides a heap-allocated transaction t which is linked
to the transaction which should be deferred through its prev
field. The provided transaction should have an owner and a
completion atoms, which are used when the deferred
transaction is completed.
When a transaction is deferred, the status code
Sim_PE_Deferred must be returned from
the issue method of the transaction interface.
- RETURN VALUE
-
The transaction t, or
NULL
if the transaction was issued synchronously and cannot be deferred.
When a transaction cannot be deferred, the issue method
may choose to return the error status
Sim_PE_Async_Required.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_defer_transaction — defer transaction completion
- SYNOPSIS
-
transaction_t *
SIM_defer_transaction(conf_object_t *obj, transaction_t *t);
- DESCRIPTION
-
When a transaction cannot be completed immediately in the issue
method of the
transaction interface, then the completion
can be deferred to a later time by calling SIM_defer_transaction
with the transaction as a parameter.
The SIM_defer_transaction function returns a new transaction
pointer which is guaranteed to be available until it is completed
with a call to SIM_complete_transaction.
When a transaction is deferred, the status code
Sim_PE_Deferred must be returned from
the issue method of the transaction interface.
- RETURN VALUE
-
Deferred transaction, or
NULL
if the transaction was issued synchronously and cannot be deferred.
When a transaction cannot be deferred, the issue method
may choose to return the error status
Sim_PE_Async_Required.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_transaction_bytes, SIM_get_transaction_bytes_offs, SIM_get_transaction_value_le, SIM_get_transaction_value_be — get transaction data payload
- SYNOPSIS
-
void
SIM_get_transaction_bytes(const transaction_t *t, buffer_t buf);
void
SIM_get_transaction_bytes_offs(const transaction_t *t, unsigned offs,
buffer_t buf, bool zerofill_holes);
uint64
SIM_get_transaction_value_le(const transaction_t *t);
uint64
SIM_get_transaction_value_be(const transaction_t *t);
- DESCRIPTION
-
Copy the data payload from a transaction to the provided buffer
buf. The size of the buffer must match the size of the
transaction.
SIM_get_transaction_bytes_offs retrieves
the bytes of the transaction which starts at offset offs.
The sum of the offset and the buffer size must not
exceed the transaction size.
SIM_get_transaction_value_le returns the value obtained
when the transaction buffer is interpreted as an encoded
little endian integer. The size of the transaction must
not exceed 8 for this function to be used.
SIM_get_transaction_value_be returns the value obtained
when the transaction buffer is interpreted as an encoded
big endian integer.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_get_transaction_id — obtain checkpoint ID for a deferred a transaction
- SYNOPSIS
-
int64
SIM_get_transaction_id(transaction_t *t);
- DESCRIPTION
-
The SIM_get_transaction_id function is used by objects that
checkpoint the transaction state. The returned ID uniquely identifies the
transaction and should be stored in a checkpoint together with the relevant
state that the object keeps for the transaction. The same ID should then be
given to SIM_reconnect_transaction during checkpoint load.
This function must only be called on a deferred transaction.
- SEE ALSO
-
SIM_reconnect_transaction
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_inspect_address_routing — track the route of a transaction through memory hierarchy
- SYNOPSIS
-
bool
SIM_inspect_address_routing(const map_target_t *NOTNULL mt,
transaction_t *NOTNULL t,
uint64 addr,
bool (*NOTNULL callback)(
const map_target_t *mt,
const transaction_t *t,
uint64 addr,
uint64 base,
uint64 start,
uint64 size,
access_t access,
translation_flags_t flags,
lang_void *data),
lang_void *data);
- DESCRIPTION
-
This function allows to track the route of a transaction through memory
hierarchy. The route is traced as if the transaction t was
issued at the address addr to the destination represented
by the map target mt. Note that when this function is used
the endpoint of the transaction will not be accessed.
The transaction t can be of any type: a read, a write, or an
instruction fetch. Please note that the type of the transaction may affect
its path through memory hierarchy. The size of the transaction
t is ignored: when accesses are done larger transactions
may be split depending on how the memory mapping are set up;
no such splitting is occurred while the transaction route is traced with
SIM_inspect_address_routing. It is allowed to use transactions
with zero size.
The callback callback will be called for every device (memory
spaces and translator objects) encountered on the transaction’s route to the
destination as well as for the destination device (this is usually a device
implementing the transaction interface or the
io_memory interface). The first invocation of
callback is done with the mt argument itself.
The arguments passed to the callback are:
- mt is a map target representing an intermediate device or
the endpoint. If nothing is mapped then NULL (or None
in Python) value is passed. The map target value should not be cached
but it can be inspected
- t is usually the original transaction, but it can be also a
new transaction in the case when additional atoms were appended to the
original transaction via the transaction chaining (see, e.g., the
documentation for the transaction_translator interface)
- addr is address inside the intermediate device or the
endpoint where the transaction is sent
- base, start, size,
access, and flags arguments describe
the mapping which led to the mt map target. These
arguments (except for access) are the same as
the fields of the translation_t structure. Please refer to
the translation_t's documentation for their description.
The access argument is a bitmask specifying access types.
The bit corresponding to the type of the t transaction
is always set. Other access bits may also be set optionally. But
the latter is not guaranteed even if read/write/execute accesses
are routed similarly
- data is the data argument passed to
SIM_inspect_address_routing
The callback callback may return false to stop inspection.
I.e. if the false value is returned callback will not be
invoked any more.
- RETURN VALUE
-
The function returns false if
callback returned false in order to stop the inspection.
Otherwise, true is returned.
- EXAMPLE
-
# The following example shows how one can determine
# the destination of a read transaction sent from a CPU object:
import conf, simics
def get_destination(memory_space, address):
'''Example function returning destination object for the access
sent to address in the memory space memory_space.'''
mt = simics.SIM_new_map_target(memory_space, None, None)
t = simics.transaction_t() # read transaction of zero size
l = [None] # data for the callback
def callback(mt, t, addr, base, start, size, access, flags, l):
l[0] = (simics.SIM_map_target_object(mt)
if mt is not None
else None)
return True
simics.SIM_inspect_address_routing(mt, t, address, callback, l)
# We free mt here but it can be saved and reused if needed.
# Transaction t can also be reused.
simics.SIM_free_map_target(mt)
return l[0]
# Please specify here CPU object and address you are interested in:
cpu = simics.SIM_get_processor(0)
address_of_access = 0x1000
dest = get_destination(
cpu.iface.processor_info_v2.get_physical_memory(),
address_of_access)
print("Destination: ",
dest.name if dest is not None else "'nothing is mapped'")
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_inspect_breakpoints — find out breakpoints that a transaction would trigger
- SYNOPSIS
-
bool
SIM_inspect_breakpoints(
const map_target_t *NOTNULL mt,
transaction_t *NOTNULL t,
uint64 start,
uint64 end,
bool (*NOTNULL callback)(
conf_object_t *trigger_object,
breakpoint_set_t bp_set,
const transaction_t *t,
uint64 start,
uint64 end,
lang_void *data),
lang_void *data);
- DESCRIPTION
-
The function allows to find out the breakpoints that would be triggered
if a transaction t would be sent to the address range inside
the map target mt. The address range is specified by
the start and end arguments and includes
both start and end of the range. Only breakpoints matching
the transaction t's type (i.e., a read, a write,
or an instruction fetch) are reported. The size of
the transaction t is ignored and can be zero.
For all matching breakpoints Simics invokes callback.
The callback function may be called multiple times: with
different trigger_object objects. The callback
function gets the following two arguments that describe the breakpoints:
- trigger_object is the object implementing
the breakpoint_trigger interface. The interface is used
during simulation to signal that an access triggers a breakpoint
- bp_set is a set of breakpoints. The breakpoints
match the transaction t's type and intersect
the [start, end] range within
the mt map target. Bp_set should
only be used inside callback. Data ownership is preserved
by the caller (i.e., Simics)
Auxiliary information is provided to callback via
the following arguments:
- t is usually the original transaction, but it can be also
a new transaction in the case when additional atoms were appended to the
original transaction via the transaction chaining (see, e.g., the
documentation for the transaction_translator interface)
- callback's start and end
arguments specify an address range inside the trigger_object
Simics object where the accesses to the requested address range inside
the mt map target would go. The size of the range
reported to callback may be smaller than the size of
the requested range. This may occur, e.g., when different parts of
the original address range are translated to different destinations
based the memory mappings of the simulated machine
- callback's data is
the data argument passed to
SIM_inspect_breakpoints
The callback function may return false
to stop searching for breakpoints. I.e. if the false value
is returned callback will not be invoked any more
even if more breakpoints are present.
The SIM_inspect_breakpoints function is an inspection function:
the endpoint of the transaction is never accessed when the function
is used.
- RETURN VALUE
-
The function returns
false if
callback returned false in order to stop the inspection.
Otherwise, true is returned.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_issue_read_transaction, SIM_issue_write_transaction — functions for issuing
transaction_t transactions
- SYNOPSIS
-
FORCE_INLINE exception_type_t
SIM_issue_read_transaction(
map_target_t *NOTNULL mt, uint64 addr, buffer_t buf,
bool inquiry, conf_object_t *initiator);
FORCE_INLINE exception_type_t
SIM_issue_write_transaction(
map_target_t *NOTNULL mt, uint64 addr, bytes_t bytes,
bool inquiry, conf_object_t *initiator);
- DESCRIPTION
-
These functions provide a simple way to issue read and write
transaction_t transactions in C code. In Python, please use
the SIM_issue_transaction function.
The functions have the following parameters:
- mt specifies the destination to send a transaction to.
- addr is the address used to issue a transaction.
- the SIM_issue_read_transaction's buf parameter
has buffer_t type and specifies a writable buffer for storing
the read data. The data.data field points to the host memory
where the results should be stored. The data.len field
specifies the number of bytes to read.
- The SIM_issue_write_transaction's bytes parameter
is of bytes_t type and provides the data that should
be written. The data.data field points to the buffer
holding the data that should be written. The data.len field
specifies the number of bytes to write.
- inquiry specifies whether the transaction should have
the Sim_Transaction_Inquiry flag set. The flag signifies that
side effects normally triggered by the transaction should be suppressed.
Examples of side effects include triggering breakpoints and clearing
"read-to-clear" device registers.
- initiator specifies the object issuing a transaction. It
may be NULL. The value is used for setting the
initiator atom of the transaction.
These functions don't support the case when a model needs to provide custom
atoms in transaction_t transactions. For such cases as well as
when using Python the SIM_issue_transaction function should be
used.
- RETURN VALUE
-
Status of the issued transaction, usually
Sim_PE_No_Exception or Sim_PE_IO_Not_Taken.
See the exception_type's documentation for more information.
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
/* Sample C code that reads an 8-byte little-endian value. If in the
simulated hardware the endpoint stores values in big-endian format then
macros from <simics/util/swabber.h> can be used for conversion. */
uint64 value = -1; // variable to read data into
exception_type_t ex = SIM_issue_read_transaction(
mt,
addr,
(buffer_t) {
.data = (uint8 *)&value,
.len = sizeof value,
},
false, /* inquiry flag */
obj /* initiator */
);
if (ex == Sim_PE_No_Exception) {
/* Read was successful: 'value' contains valid data. */
SIM_LOG_INFO(4, obj, 0, "Read '%#llx' at %#llx", value, addr);
} else {
/* Read operation was not successful. There is no valid data
in 'value'. Put any error handling code here. */
SIM_LOG_ERROR(obj, 0, "Read at %#llx failed", addr);
}
/* Sample C code that writes an 8-byte little-endian value. If in the
simulated hardware the endpoint stores values in big-endian format then
macros from <simics/util/swabber.h> can be used for conversion. */
uint64 write_value = 1; // Data to write. '1' is written in this example.
SIM_LOG_INFO(4, obj, 0, "Writing '%#llx' at %#llx", write_value, addr);
exception_type_t ex = SIM_issue_write_transaction(
mt,
addr,
(bytes_t) {
.data = (uint8 *)&write_value,
.len = sizeof write_value,
},
false, /* inquiry flag */
obj /* initiator */
);
if (ex == Sim_PE_No_Exception) {
/* Write was successful. */
} else {
/* Write operation was not successful.
Put any error handling code here. */
SIM_LOG_ERROR(obj, 0, "Write at %#llx failed", addr);
}
- SEE ALSO
-
exception_type_t, map_target_t,
SIM_issue_transaction, transaction_t
- NAME
-
SIM_issue_transaction — issue transaction
- SYNOPSIS
-
exception_type_t
SIM_issue_transaction(const map_target_t *NOTNULL mt,
transaction_t *NOTNULL t, uint64 addr);
- DESCRIPTION
-
SIM_issue_transaction issues the transaction t
with the address addr to the destination
represented by the map target mt. In Python, the mt
argument can also be a
conf_object_t.
- RETURN VALUE
-
The function returns
Sim_PE_Deferred if the transaction was
deferred for completion at a some later time. The corresponding pseudo
exception is returned if the transaction completed directly (normally
Sim_PE_No_Exception or Sim_PE_IO_Not_Taken).
- SEE ALSO
-
exception_type_t, transaction_t,
SIM_new_map_target, SIM_free_map_target,
SIM_issue_read_transaction,
SIM_issue_write_transaction,
SIM_defer_transaction, SIM_complete_transaction,
SIM_monitor_transaction, SIM_transaction_wait
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_monitor_transaction, SIM_monitor_chained_transaction — monitor a transaction for deferred completion
- SYNOPSIS
-
exception_type_t
SIM_monitor_transaction(transaction_t *t, exception_type_t ex);
exception_type_t
SIM_monitor_chained_transaction(transaction_t *t, exception_type_t ex);
- DESCRIPTION
-
The SIM_monitor_transaction function monitors
an asynchronously issued transaction for completion.
A transaction is asynchronously issued if it has a
completion atom with a callback which is
not NULL. The function should be
called after the transaction has been issued, and the
ex status code should be the return value from
function used to issue the transaction, for example
the issue method of the transaction
interface.
If ex equals Sim_PE_Deferred, then
SIM_monitor_transaction will check if the transaction has in
fact been completed already, and in that case, immediately invoke the
completion callback. If the transaction is still uncompleted, then it
will be marked as monitored and a subsequent call to
SIM_complete_transaction will immediately complete the
transaction by invoking the completion callback.
If ex is not equal to Sim_PE_Deferred, then the
transaction has been completed synchronously, and the completion
callback is called using ex as the completion status.
Note that it is illegal to call SIM_monitor_transaction
for transactions that do not have a valid
completion callback.
SIM_monitor_chained_transaction is similar to
SIM_monitor_transaction except that when a deferred
transaction is completed, its parent transaction will be completed too.
- RETURN VALUE
-
Exception code returned by the
completion function, or
Sim_PE_Deferred if the
transaction is monitored for completion at a later time.
- SEE ALSO
-
SIM_defer_transaction,
SIM_complete_transaction
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_poll_transaction — check if a transaction has completed
- SYNOPSIS
-
exception_type_t
SIM_poll_transaction(transaction_t *t);
- DESCRIPTION
-
The SIM_poll_transaction function checks if the transaction
t is marked as completed, in which case the associated
status code is returned and the completion status for the transaction
is cleared. If the transaction is uncompleted, then
Sim_PE_Deferred is returned.
It is illegal to call SIM_poll_transaction on a transaction
which is monitored for completion using e.g. the
SIM_monitor_transaction function.
- SEE ALSO
-
SIM_complete_transaction
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_reconnect_transaction — register that a deferred transaction has been restored
- SYNOPSIS
-
void
SIM_reconnect_transaction(transaction_t *t, int64 id);
- DESCRIPTION
-
The SIM_reconnect_transaction function is used by objects that
checkpoint the transaction state. It should be called when the relevant
state has been read from a checkpoint.
- SEE ALSO
-
SIM_get_transaction_id
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_python_atom_type — register an atom type which takes plain Python objects
- SYNOPSIS
-
void
SIM_register_python_atom_type(const char *NOTNULL name);
- DESCRIPTION
-
Register an atom type named name. The atom type
can be used from Python and can hold any Python object.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_replace_transaction — replace transaction
- SYNOPSIS
-
void
SIM_replace_transaction(transaction_t *t_old, transaction_t *t_new);
- DESCRIPTION
-
Replace a transaction t_old with a new transaction
t_new.
A transaction which has been issued and is deferred by
some downstream device can be replaced with a different
transaction by initiator. This is mostly useful when a
transaction is allocated on the stack and it turns out that the
transaction is not completed synchronously, in which case
SIM_replace_transaction can be used to move the
transaction to e.g. the heap.
This function ensures that the deferred transaction is
properly linked with the t_new transaction. It
is the caller's responsibility to fill in the contents
of the new transaction, including the prev pointer.
It is illegal to replace a transaction which has been monitored.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_transaction_bytes, SIM_set_transaction_bytes_offs, SIM_set_transaction_value_le, SIM_set_transaction_value_be, SIM_set_transaction_bytes_constant — set transaction data payload
- SYNOPSIS
-
void
SIM_set_transaction_bytes(const transaction_t *t, bytes_t bytes);
void
SIM_set_transaction_bytes_offs(const transaction_t *t, unsigned offs,
bytes_t bytes);
void
SIM_set_transaction_value_le(const transaction_t *t, uint64 value);
void
SIM_set_transaction_value_be(const transaction_t *t, uint64 value);
void
SIM_set_transaction_bytes_constant(const transaction_t *t, uint8 value);
- DESCRIPTION
-
Set the data payload of a transaction to the contents provided by
bytes. The number of provided bytes must match the
transaction size exactly.
The SIM_set_transaction_bytes_offs function sets
some bytes of the transaction starting at offset offs.
The sum of the offset and the number of provided bytes must not
exceed the transaction size.
The SIM_set_transaction_value_le function sets
the transaction bytes to the little endian representation of
value. The size of the transaction must
not exceed 8 for this function to be used. Similarly,
SIM_set_transaction_value_be sets the transaction bytes
to the big endian representation of the provided value.
If the transaction is smaller than 8 bytes the functions will truncate
the representation of the value.
The SIM_set_transaction_bytes_constant function can be used
when an endpoint wants to set all transaction bytes to value.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_transaction_flags, SIM_transaction_is_fetch, SIM_transaction_is_write, SIM_transaction_is_read, SIM_transaction_is_inquiry — return transaction type
- SYNOPSIS
-
transaction_flags_t
SIM_transaction_flags(const transaction_t *NOTNULL t);
bool
SIM_transaction_is_fetch(const transaction_t *NOTNULL t);
bool
SIM_transaction_is_write(const transaction_t *NOTNULL t);
bool
SIM_transaction_is_read(const transaction_t *NOTNULL t);
bool
SIM_transaction_is_inquiry(const transaction_t *NOTNULL t);
- DESCRIPTION
-
SIM_transaction_flags returns a
transaction_flags_t bitmap describing transaction
type. Most of the flags can be queried using
specific accessors.
The SIM_transaction_is_fetch function returns
true if the transaction is an instruction fetch.
The SIM_transaction_is_read function returns
true if the transaction is a read operation.
The SIM_transaction_is_write function returns
true if the transaction is a write operation.
The SIM_transaction_is_inquiry function returns
true if the transaction is an inquiry operation.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_transaction_initiator — return transaction initiator
- SYNOPSIS
-
conf_object_t *
SIM_transaction_initiator(const transaction_t *t);
- DESCRIPTION
-
Return the initiator of the transaction.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_transaction_is_deferrable — check if a transaction can be deferred for later completion
- SYNOPSIS
-
bool
SIM_transaction_is_deferrable(const transaction_t *NOTNULL t);
- DESCRIPTION
-
The function allows to check whether a transaction can be deferred (with the
SIM_defer_transaction or SIM_defer_owned_transaction
function) for later completion which is done with a call
to SIM_complete_transaction.
Usually, this function is not needed since SIM_defer_transaction
and SIM_defer_owned_transaction return NULL
for transactions that cannot be deferred.
- RETURN VALUE
-
false if the transaction was issued
synchronously and cannot be deferred. Otherwise, true.
When a transaction cannot be deferred, endpoint's issue method
of the transaction interface may choose
to return the error status Sim_PE_Async_Required.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_transaction_size — return transaction size
- SYNOPSIS
-
unsigned
SIM_transaction_size(const transaction_t *NOTNULL t);
- DESCRIPTION
-
Return the size of the transaction, in bytes.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_transaction_wait — wait for transaction completion
- SYNOPSIS
-
exception_type_t
SIM_transaction_wait(transaction_t *t, exception_type_t ex);
- DESCRIPTION
-
SIM_transaction_wait waits until an issued transaction
has completed.
The function may only be invoked for transactions which
have a completion atom containing a NULL
pointer. The NULL pointer means that the
initiator will wait for transaction completion using this function.
Moreover, SIM_transaction_wait must always be called
after a transaction has been issued with a NULL
completion callback.
The ex argument should be the return value of
the function or method used to issue the transaction.
SIM_transaction_wait will not return until the
transaction has completed. While waiting, a different
user-level thread will be activated, which allows
simulated time to advance.
Note that the simulator cannot create a checkpoint while a call to
the SIM_transaction_wait is in progress. See
help transaction-wait-all-completed for more information
related to checkpointing and SIM_transaction_wait.
Transaction wait is not supported from all contexts. When unsupported,
the transaction will appear to be issued synchronously.
- RETURN VALUE
-
Completion status of the transaction
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_arm_mem_trans_from_generic, SIM_mips_mem_trans_from_generic, SIM_ppc_mem_trans_from_generic, SIM_x86_mem_trans_from_generic, SIM_pci_mem_trans_from_generic — convert generic transaction to CPU specific
- SYNOPSIS
-
struct arm_memory_transaction *
SIM_arm_mem_trans_from_generic(generic_transaction_t *NOTNULL mop);
struct mips_memory_transaction *
SIM_mips_mem_trans_from_generic(generic_transaction_t *NOTNULL mop);
struct ppc_memory_transaction *
SIM_ppc_mem_trans_from_generic(generic_transaction_t *NOTNULL mop);
struct x86_memory_transaction *
SIM_x86_mem_trans_from_generic(generic_transaction_t *NOTNULL mop);
struct pci_memory_transaction *
SIM_pci_mem_trans_from_generic(generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Converts a pointer to a generic memory transaction into a pointer
to a CPU specific memory transaction. The generic memory transaction
must be part of a CPU specific one for this function to succeed.
The pointer returned will be the same the input pointer if conversion
is allowed, and NULL on failure.
- EXCEPTIONS
-
SimExc_Type Thrown if the generic transaction is not part of a CPU
specific transaction.
- RETURN VALUE
-
New memory transaction pointer, or NULL on
error.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_c_get_mem_op_value_buf, SIM_get_mem_op_value_buf, SIM_get_mem_op_value_cpu, SIM_get_mem_op_value_le, SIM_get_mem_op_value_be — get value for a memory operation
- SYNOPSIS
-
void
SIM_c_get_mem_op_value_buf(const generic_transaction_t *NOTNULL mop,
uint8 *NOTNULL dst);
attr_value_t
SIM_get_mem_op_value_buf(const generic_transaction_t *NOTNULL mop);
uint64
SIM_get_mem_op_value_cpu(const generic_transaction_t *NOTNULL mop);
uint64
SIM_get_mem_op_value_le(const generic_transaction_t *NOTNULL mop);
uint64
SIM_get_mem_op_value_be(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Returns load or store value for a memory transaction. If the data
size is 8 bytes or less the SIM_get_mem_op_value_be
and SIM_get_mem_op_value_le functions can be used. For
reads/writes larger than 8 bytes, the functions
SIM_c_get_mem_op_value_buf or
SIM_get_mem_op_value_buf
should be used to get the data.
If your model is compiled with one of the
DEVICE_IS_LITTLE_ENDIAN, DEVICE_IS_BIG_ENDIAN
pre-processor defines, then the
SIM_get_mem_op_value function can be used
as an alias to the SIM_get_mem_op_value_le and
SIM_get_mem_op_value_be versions.
The SIM_c_get_mem_op_value_buf function is only available
from C/C++. It places the data into the buffer pointed to by dst.
No endian conversion is performed, i.e. data is returned in target
endianness. There is no alignment requirement on the dst
parameter.
- WARNING
-
When called from a memory-hierarchy
(timing-model) only store values can be retrieved, since the load
has not yet performed. To get the load value, a snoop-device
should be used.
- RETURN VALUE
-
SIM_c_get_mem_op_value_buf returns nothing. The out
parameter dst is filled with the data buffer of the memory
transaction. SIM_get_mem_op_value_buf returns an
attr_value_t (type data) containing the data buffer
of the memory transaction.
SIM_get_mem_op_value_be returns the zero-extended value
in host endian order (interpreted as big endian) for the memory transaction.
SIM_get_mem_op_value_le returns the zero-extended value
in host endian order (interpreted as little endian).
SIM_get_mem_op_value_cpu interprets the data in the default
endian order for the initiating processor. This function can only be used
for processor initiated memory operations. It is recommended that one of the
other functions are used instead.
- EXCEPTIONS
-
SimExc_Memory Thrown if the size of the operation is illegal.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_c_set_mem_op_value_buf, SIM_set_mem_op_value_buf, SIM_set_mem_op_value_cpu, SIM_set_mem_op_value_le, SIM_set_mem_op_value_be — set value for a memory operation
- SYNOPSIS
-
void
SIM_c_set_mem_op_value_buf(generic_transaction_t *NOTNULL mop,
const uint8 *NOTNULL src);
void
SIM_set_mem_op_value_buf(generic_transaction_t *NOTNULL mop,
attr_value_t value);
void
SIM_set_mem_op_value_cpu(generic_transaction_t *NOTNULL mop, uint64 value);
void
SIM_set_mem_op_value_le(generic_transaction_t *NOTNULL mop, uint64 value);
void
SIM_set_mem_op_value_be(generic_transaction_t *NOTNULL mop, uint64 value);
- DESCRIPTION
-
Set the value returned to the requester of a memory operation.
If the data size is 8 bytes or less the SIM_set_mem_op_value_be
and SIM_set_mem_op_value_le functions can be used. For sizes
larger than 8 bytes, the functions SIM_c_set_mem_op_value_buf
or SIM_set_mem_op_value_buf should be used to set the data
as an
attr_value_t of data type.
If your model is compiled with one of the
DEVICE_IS_LITTLE_ENDIAN, DEVICE_IS_BIG_ENDIAN
pre-processor defines, then the
SIM_set_mem_op_value function can be used
as an alias to the SIM_set_mem_op_value_le and
SIM_set_mem_op_value_be versions.
SIM_c_set_mem_op_value_buf is only available from C/C++,
it operates on data in target endian order. There is no alignment
requirement on the buf parameter.
SIM_set_mem_op_value_be takes data in host endian order
and sets it in big-endian.
SIM_set_mem_op_value_le takes data in host endian order
and sets it in little-endian.
SIM_set_mem_op_value_cpu takes data in host endian order
and sets it in the default endian order for the initiating processor.
This function can only be used for processor initiated memory operations.
It is recommended that one of the other functions are used instead.
The functions that set the memory operation based on a value will
truncate the representation of that value if the memory operation
is smaller than 8 bytes.
- WARNING
-
These functions cannot be called from a
timing-model since the real operation will overwrite the value
set. They should instead be used from a snoop-device.
- EXCEPTIONS
-
SimExc_Memory Thrown if the size of the operation is illegal.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_mem_op_page_cross — detect transaction split
- SYNOPSIS
-
FORCE_INLINE unsigned
SIM_get_mem_op_page_cross(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
If a memory transaction was split because it straddled an MMU page,
return 1 if it is the first part and 2 for the second. If the transaction
was not split, return zero.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_mem_op_size — get transaction size
- SYNOPSIS
-
FORCE_INLINE unsigned
SIM_get_mem_op_size(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve the size, in bytes, of a memory transaction.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_mem_op_type — get type of transaction
- SYNOPSIS
-
FORCE_INLINE mem_op_type_t
SIM_get_mem_op_type(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
This function returns the type of the memory transaction.
- SEE ALSO
-
generic_transaction_t,
SIM_set_mem_op_type
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_mem_op_type_name — get name of memory operation type
- SYNOPSIS
-
const char *
SIM_get_mem_op_type_name(mem_op_type_t type);
- DESCRIPTION
-
Returns a string describing type or
NULL
if unknown.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_make_mem_op_write, SIM_make_mem_op_read — create a memory transaction
- SYNOPSIS
-
generic_transaction_t
SIM_make_mem_op_write(physical_address_t addr, bytes_t data,
bool inquiry, conf_object_t *initiator);
generic_transaction_t
SIM_make_mem_op_read(physical_address_t addr, buffer_t buffer,
bool inquiry, conf_object_t *initiator);
- DESCRIPTION
-
Create and return a memory transaction for writing data to
addr, or reading from addr into
buffer. The number of bytes to transfer is specified by
data and buffer respectively. The
initiator is the object issuing the transaction; it may be
NULL.
These functions do not actually perform any memory operation; they just
construct the generic_transaction_t that can be used in
other calls.
The buffer argument must refer to an allocated buffer, and
data must contain valid data. They must remain valid and
allocated during the life-time of the returned value.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_mem_op_ensure_future_visibility — request transaction visibility
- SYNOPSIS
-
FORCE_INLINE void
SIM_mem_op_ensure_future_visibility(generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Request that future accesses from the same virtual address (using a
granularity given by the min_cacheline_size processor
attribute) will be seen by the memory hierarchy. Otherwise, the simulator
may cache accesses to this address for performance so that they are not seen
by the memory model.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_atomic — detect transaction atomicity
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_atomic(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Return true if the transaction was part of an atomic instruction
(usually a read followed by a write), false otherwise.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_control — transaction control predicates
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_control(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Checks whether
mem_op is a control transaction (one that does not
actually transfer any data, such as cache control operations).
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_data, SIM_mem_op_is_instruction — transaction data/instruction predicates
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_data(const generic_transaction_t *NOTNULL mop);
FORCE_INLINE bool
SIM_mem_op_is_instruction(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
These functions check whether
mem_op is a data or an instruction
transaction. Currently, the only transactions that are instruction
transactions are instruction fetches.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_from_cache — Cache initiated transaction
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_from_cache(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Checks whether
mem_op is sent from a cache timing model.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_from_cpu — CPU initiated transaction
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_from_cpu(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Checks whether
mem_op is sent from a processor.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_from_cpu_arch — CPU initiated transaction
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_from_cpu_arch(const generic_transaction_t *NOTNULL mop,
ini_type_t arch);
- DESCRIPTION
-
Checks whether
mem_op is sent from a processor
of a specific architecture.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_from_device — Device initiated transaction
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_from_device(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Checks whether
mem_op is sent from a device.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_prefetch — transaction control predicates
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_prefetch(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Checks whether
mem_op is prefetch transaction.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_is_read, SIM_mem_op_is_write — transaction read/write predicates
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_is_read(const generic_transaction_t *NOTNULL mop);
FORCE_INLINE bool
SIM_mem_op_is_write(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
These functions check whether
mem_op is a read or a write
transaction.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_mem_op_may_stall — detect transaction stall possibility
- SYNOPSIS
-
FORCE_INLINE bool
SIM_mem_op_may_stall(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
If true, the simulator will allow the transaction to stall execution.
When false, a memory hierarchy must not attempt any stalling.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_exception, SIM_get_mem_op_exception — get/set transaction exception
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_exception(generic_transaction_t *NOTNULL mop,
exception_type_t exc);
FORCE_INLINE exception_type_t
SIM_get_mem_op_exception(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve or change the transaction exception. If set to a value other
than
Sim_PE_No_Exception, the transaction will be interrupted
and an exception will be taken.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_initiator, SIM_get_mem_op_initiator, SIM_get_mem_op_ini_type — get/set transaction initiator
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_initiator(generic_transaction_t *NOTNULL mop,
ini_type_t type, conf_object_t *obj);
FORCE_INLINE conf_object_t *
SIM_get_mem_op_initiator(const generic_transaction_t *NOTNULL mop);
FORCE_INLINE ini_type_t
SIM_get_mem_op_ini_type(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve or change the transaction initiator type and object.
These two parameters must agree.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_inquiry, SIM_get_mem_op_inquiry — get/set transaction inquiry flag
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_inquiry(generic_transaction_t *NOTNULL mop, bool inquiry);
FORCE_INLINE bool
SIM_get_mem_op_inquiry(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve or change the transaction inquiry flag. An inquiry read has no
side-effects. An inquiry write has no other side-effect than changing the
bytes at the specified address and size.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_physical_address, SIM_get_mem_op_physical_address, SIM_set_mem_op_virtual_address, SIM_get_mem_op_virtual_address — get or set transaction address
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_physical_address(generic_transaction_t *NOTNULL mop,
physical_address_t pa);
FORCE_INLINE physical_address_t
SIM_get_mem_op_physical_address(const generic_transaction_t *NOTNULL mop);
FORCE_INLINE void
SIM_set_mem_op_virtual_address(generic_transaction_t *NOTNULL mop,
logical_address_t va);
FORCE_INLINE logical_address_t
SIM_get_mem_op_virtual_address(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve or set the physical or virtual (logical) addresses of a
memory transaction.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_reissue — request transaction reissue
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_reissue(generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Request that the transaction will be re-issued if a non-zero stall time
is returned from a memory hierarchy. Otherwise, the memory model
will not see the transaction again.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_type — set type of transaction
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_type(generic_transaction_t *NOTNULL mop, mem_op_type_t type);
- DESCRIPTION
-
This function sets the type of the memory transaction.
- SEE ALSO
-
generic_transaction_t,
SIM_get_mem_op_type
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_mem_op_user_data, SIM_get_mem_op_user_data — get/set transaction user data
- SYNOPSIS
-
FORCE_INLINE void
SIM_set_mem_op_user_data(generic_transaction_t *NOTNULL mop,
void *data);
FORCE_INLINE void *
SIM_get_mem_op_user_data(const generic_transaction_t *NOTNULL mop);
- DESCRIPTION
-
Retrieve or change user data associated with the transaction.
This data is not touched by Simics in any way and its handling and
interpretation is left to the user. It can be used
to pass information from a timing model to a snoop device, but the data
does not survive across a stall.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_free_map_target — free a map target
- SYNOPSIS
-
void
SIM_free_map_target(map_target_t *mt);
- DESCRIPTION
-
Releases a map target and all associated resources.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_new_map_target
- NAME
-
SIM_map_target_flush — ensure that old translations are not used
- SYNOPSIS
-
bool
SIM_map_target_flush(const map_target_t *NOTNULL mt,
uint64 base, uint64 size, access_t access);
- DESCRIPTION
-
This API function is intended to be used for the implementation
the
translation_flush interface. The documentation for
the translation_flush interface describes
how to use this function for the interface implementation.
Additionally, this function can be used as a replacement for
the SIM_translation_changed function
to do a more fine-grain invalidation in the case when a previously
returned translation becomes invalid.
When a previously returned translation becomes invalid the translator object
should notify Simics which can have translations cached. To notify Simics
the translator object can either do the call to
the SIM_translation_changed function or, as a potential
performance optimization, do a more fine-grain invalidation by using
the SIM_map_target_flush function.
The translator object is expected to call
the SIM_map_target_flush function for
all targets of all previously returned translations which became invalid.
If there are too many translations which are to be invalidated, then,
performance-wise, it may be better just to do a single call to the
SIM_translation_changed function. Also, if,
during invalidation, any of the calls to the SIM_map_target_flush
fails (i.e. the false value is returned by the function) then
the translator is expected to call
the SIM_translation_changed function which always succeeds.
Please note that there is no need to call
the SIM_map_target_flush function for the translations which
were tagged with the Sim_Translation_Dynamic flag. Either, no
invalidation is needed for the destinations where nothing is mapped.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_map_target_object, SIM_map_target_port, SIM_map_target_target — inspect a map target
- SYNOPSIS
-
conf_object_t *
SIM_map_target_object(const map_target_t *NOTNULL mt);
const char *
SIM_map_target_port(const map_target_t *NOTNULL mt);
const map_target_t *
SIM_map_target_target(const map_target_t *NOTNULL mt);
- DESCRIPTION
-
Helper functions allowing inspection of the map_target_t objects.
- RETURN VALUE
-
Returns a Simics object, port, or
chained target which was used
for the creation of the mt map target, i.e.,
the respective argument passed to SIM_new_map_target
when the map target was created.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_new_map_target
- NAME
-
SIM_new_map_target — create a map target
- SYNOPSIS
-
map_target_t *
SIM_new_map_target(conf_object_t *NOTNULL obj, const char *port,
const map_target_t *chained_target);
- DESCRIPTION
-
Create and return a new map target. A map target can be viewed as an opaque
representation of an object/interface pair which can function
either as an endpoint for a memory transaction
or as an address space where a memory transaction can be performed.
Map targets are usually used in conjunction with the
translator interface and can represent anything
which is mappable in a memory space, e.g., IO banks, RAM, ROM,
memory spaces, port spaces, bridges, or translators. In order to
get better performance, we recommend to allocate a map target once
and reuse it rather than to allocate and delete it every time.
If the chained_target parameter is null,
obj is searched for one of the following interfaces:
ram, rom, io_memory,
port_space, translator,
transaction_translator, transaction or
memory_space. The interfaces are tried in the
listed order, and the first interface found determines the "type" of the
map target. For example, if obj implements both the
io_memory and the translator
interface, then the created map target will direct memory transactions
to the io_memory interface.
If a map target argument is passed in the
chained_target parameter, then obj must
implement one of the following interfaces:
translator, bridge,
or translate. The chained target contains information
about a secondary map target used either directly or indirectly
by the interface. For objects implementing the
translator interface, the chained
target is passed as an argument to the translate
method. For bridges, the chained target is the target which
is accessed through the bridge. For objects implementing
translate, the chained target is used as the target
of the translation if the translate method returns null.
Note: Information about the chained target is encoded in the
created map target, but no direct references are kept to the argument.
In other words, ownership is not transferred by this call and
the caller is responsible for releasing chained_target
as appropriate.
If a string is passed in the port parameter, then
Simics looks for port interfaces instead of regular interfaces.
- RETURN VALUE
-
Returns a map target, encoding information
about the object, the interface, and the chained target, if any.
NULL is returned if an exception was thrown.
- EXCEPTIONS
-
SimExc_Lookup Thrown if no usable port interface was found.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_free_map_target,
map_target_t,
SIM_map_target_object, translator_interface_t
- NAME
-
SIM_translation_changed — ensure that old translations are not used
- SYNOPSIS
-
void
SIM_translation_changed(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Devices implementing the
translator interface
need to call this function whenever a previously returned
translation becomes invalid; the only exception is
if all invalid translations were tagged with
Sim_Translation_Dynamic, in which case this is
not necessary.
Failure to call this function will likely result in Simics
continuing to use old translations, since those may have been
cached internally.
The object implementing the translator should be passed
in the obj parameter.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
translator_interface_t
- NAME
-
SIM_cycle_count — read cycle counter
- SYNOPSIS
-
cycles_t
SIM_cycle_count(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
SIM_cycle_count returns the current simulated clock cycle
count at obj.
If obj is a cycle counter implementing either the
cycle_event interface or the cycle
interface, then the returned count is the number of elapsed
cycles according to that object. If obj is not a cycle
counter, then the default clock associated with the object is
queried for its cycle count.
- SEE ALSO
-
SIM_object_clock
- RETURN VALUE
-
SIM_cycle_count returns the current time in number of
cycles.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_event_cancel_time, SIM_event_cancel_step — cancel an event before expiration
- SYNOPSIS
-
void
SIM_event_cancel_time(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
void
SIM_event_cancel_step(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
- DESCRIPTION
-
All unexpired evclass events posted for obj
on clock for which pred returns nonzero will
be cancelled and their destructor methods (if any) called.
pred will be called with the data associated with the event
and the supplied match_data. If pred is null
(None in Python), all evclass events for obj
on clock will be cancelled.
There are separate calls for events posted at a point in time (cycle or
seconds) and on a specific step.
- EXCEPTIONS
-
SimExc_InterfaceNotFound Thrown by SIM_event_cancel_step
if the clock object doesn't implement the
step
interface.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_event, SIM_event_post_time
- NAME
-
SIM_event_class_flags — get event class flags
- SYNOPSIS
-
event_class_flag_t
SIM_event_class_flags(event_class_t *NOTNULL ec);
- DESCRIPTION
-
Get the event class flags from a registered event class ec.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_event
- NAME
-
SIM_event_find_next_cycle, SIM_event_find_next_time, SIM_event_find_next_step — find event expiration time
- SYNOPSIS
-
cycles_t
SIM_event_find_next_cycle(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
double
SIM_event_find_next_time(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
pc_step_t
SIM_event_find_next_step(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
- DESCRIPTION
-
Return the number of cycles/seconds/steps to the first event of
evclass of obj posted on clock
for which pred is true, or −1 if no event
matched. pred will be called with the data associated with
the event and the supplied match_data. If pred
is null (None in Python), the first evclass event for
obj on clock will be used.
There are separate calls of events posted at a point in time (cycle
or seconds) and on a specific step. Note that the return value of
SIM_event_find_next_cycle is only a preliminary
estimate; the number of remaining cycles will change if the
clock's frequency changes dynamically. To handle dynamically
changing clock frequencies correctly, subscribe to the frequency
changes via the clock's simple_dispatcher interface.
- EXCEPTIONS
-
SimExc_InterfaceNotFound Thrown by
SIM_event_find_next_step if the clock object
doesn't implement the
step interface: Minus one is returned
in such a case.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_event, SIM_event_post_time
- NAME
-
SIM_event_post_time, SIM_event_post_cycle, SIM_event_post_step — post an event
- SYNOPSIS
-
void
SIM_event_post_time(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
double seconds,
lang_void *user_data);
void
SIM_event_post_cycle(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
cycles_t cycles,
lang_void *user_data);
void
SIM_event_post_step(conf_object_t *NOTNULL clock,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
pc_step_t steps,
lang_void *user_data);
- DESCRIPTION
-
An event of evclass for object obj is posted
on clock to occur at a given point in the future. The
user_data will be associated with the event.
The clock is the object that should be used for keeping track
of time for the event. It can be a processor or an instance of the
clock class.
If a configuration class was specified when evclass was
registered, then obj must be an instance of that class.
The expiration point can be specified in seconds, cycles or steps by using
the appropriate call, and these values are relative to the current
state. Events that need to run synchronized
(Sim_EC_Machine_Sync) can only be posted in seconds or
cycles, not steps, since synchronization can only be perform in virtual
time.
Note:
Events posted with SIM_event_post_cycle are posted at
a certain point in time based on the clock's current frequency, not
at a certain clock cycle. The difference is significant if the
frequency of the clock object can change dynamically.
- EXCEPTIONS
-
- SimExc_InterfaceNotFound
- Thrown by
SIM_event_post_step if the clock object doesn't
implement the
step interface. - SimExc_General
- Thrown if the number of steps or time is
negative or too far ahead, and, for
Sim_EC_Machine_Sync
events, if the event is posted less than a time quantum in the future.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_event, SIM_event_cancel_time
- NAME
-
SIM_get_event_class — get the event class
- SYNOPSIS
-
event_class_t *
SIM_get_event_class(conf_class_t *NOTNULL cl, const char *NOTNULL name);
- DESCRIPTION
-
Get an event class registered for a configuration class, as done by the
SIM_register_event function. The cl is the configuration
class and name is the name of the event class to retrieve.
If the event class cannot be found, NULL is returned.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_event
- NAME
-
SIM_register_event — register an event
- SYNOPSIS
-
event_class_t *
SIM_register_event(
const char *NOTNULL name,
conf_class_t *cl,
event_class_flag_t flags,
void (*NOTNULL callback)(conf_object_t *obj, lang_void *data),
void (*destroy)(conf_object_t *obj, lang_void *data),
attr_value_t (*get_value)(conf_object_t *obj, lang_void *data),
lang_void *(*set_value)(conf_object_t *obj, attr_value_t value),
char *(*describe)(conf_object_t *obj, lang_void *data));
- DESCRIPTION
-
Registers events identified by name and to be posted for
objects of class cl, and returns the event class to be used
in other calls. The supplied methods are:
- callback
- Called when the event expires.
- destroy
- Called when the event is removed from the queue without being called.
The method is not allowed to use any event API calls; it is mainly
intended for freeing event data. May be null.
- get_value
- Called to convert the event data into a value that can be saved in a
configuration. May be null when the event carries no data of
interest.
- set_value
- Called to convert a configuration value into event data.
May be null when the event carries no data of interest.
- describe
- Called to generate a human-readable description of the event to be used
in the print-event-queue command. If written in C, must
return an allocated string (using
MM_MALLOC or
MM_STRDUP).
May be null, in which case the name is used.
Null function pointers correspond to the value None when invoked from
Python.
The flags are typically either zero or Sim_EC_Notsaved, where
Sim_EC_Notsaved indicates that the event should not be saved as part of the
configuration. In that case, get_value and
set_value must both be null, and cl may also
be null.
Additionally, the Sim_EC_No_Serialize flag can be used to specify that the
event should not serialize the cell if Multicore Accelerator mode (MCA) is
activated. This flag allows the event to run in a threaded context instead
of the default cell context. As with all threaded context code, the event
callback must protect against threading violations by using
SIM_acquire_target and SIM_acquire_object. Setting this flag can
significantly speed up the simulation if such events are posted frequently.
The other flag bits defined in event_class_flag_t are reserved for internal
use in the Simics platform and some tightly coupled modules. See the event
queue sample code for details on their use
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_event_post_time
- NAME
-
SIM_run_unrestricted — run callback after current instruction
- SYNOPSIS
-
void
SIM_run_unrestricted(conf_object_t *NOTNULL obj,
void (*NOTNULL func)(conf_object_t *obj,
lang_void *param),
lang_void *user_data);
- DESCRIPTION
-
The func functions will be called immediately, if Simics is not
currently running an instruction, or as soon as the current instruction has
completed.
Note that with the introduction of Multicore Accelerator, if an instruction
is running when calling SIM_run_unrestricted, other simulation
threads may continue for a while until they stop and the callback is
serviced. This means that an object using SIM_run_unrestricted
may receive calls through for example the io_memory interface
after returning from the scope where SIM_run_unrestricted is
called but before the func callback function is called. For more
information on considerations for Multicore Accelerator, see the
Simics Model Builder User's Guide.
If several functions are registered this way before any of them has had a
chance to run, the functions will be run in their order of registration.
This call is mainly useful for actions that for various reasons can not be
done while an instruction is being emulated.
The obj is an object that has a clock (as defined by
SIM_object_clock). This object and user_data are
passed to the callback function.
Since the callback is run in Cell Context, simulation threads
for other cells may be running when the callback is executed. Consequently,
only objects in the same cell as obj may be accessed from
the callback.
- SEE ALSO
-
SIM_run_alone
- EXECUTION CONTEXT
-
All contexts including Threaded Context (call);
Cell Context (callback)
- NAME
-
SIM_step_count — get step count
- SYNOPSIS
-
pc_step_t
SIM_step_count(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the number of steps executed by the processor obj.
A step is a completed instruction, an instruction causing a synchronous
exception, or an asynchronous exception (interrupt).
- EXCEPTIONS
-
SimExc_InterfaceNotFound Thrown if the obj object
doesn't implement the
step interface. Minus one is returned
in such a case.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_time — get current simulated time
- SYNOPSIS
-
double
SIM_time(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
SIM_time returns the current time at obj.
The returned time relates to how long the simulation has been
running, and is usually not very useful in itself, but it can be
used to compare with other times. The time on a specific processor
is guaranteed to increase when simulation progresses, even if the
clock frequency is changed. When adding a processor, it is assigned
a current time to be synchronized with other processors in the
simulation, or the time 0.0 if it is the first processor.
Note:
The precision of the returned value degrades significantly
with simulated time due to its representation as a double.
When absolute timestamps are needed for the actual simulation,
it is recommended that the SIM_cycle_count function
is used instead on the picosecond clock.
Note:
Using SIM_time on the picosecond clock will currently
give the same result as SIM_time on the default clock.
That is, the precision of this API function is limited
by the frequency of the default clock.
- SEE ALSO
-
SIM_picosecond_clock
- RETURN VALUE
-
SIM_time returns the current time in seconds as
a floating point value.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_register_copyright — register copyright information
- SYNOPSIS
-
void
SIM_register_copyright(const char *NOTNULL str);
- DESCRIPTION
-
This registers specific copyright information related to an extension
module or similar component of Simics. The Simics front-end command
"copyright" will list, in addition to Simics copyright notices, any
registered notices from libraries or plug-ins that have added a string
using this function.
The string should contain only standard ASCII characters, be pre-formatted
for at most 80-character width terminal, be non-indented, and have
no spurious new-line characters before or after the last line (except
for the new-line that marks the end of the last line).
The string will not be copied so needs to be either static or
a copy generated by the callee (preferably static).
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_version, SIM_version_base, SIM_version_major, SIM_license, SIM_license_file, SIM_copyright, SIM_vmxmon_version — get Simics version and license/copyright information
- SYNOPSIS
-
const char *
SIM_version();
const char *
SIM_version_base();
const char *
SIM_version_major();
void
SIM_license();
char *
SIM_license_file(const char *format);
char *
SIM_copyright();
char *
SIM_vmxmon_version();
- DESCRIPTION
-
- SIM_version
- returns the version of all installed
Simics products.
- SIM_version_base
- returns the version of the Simics
base package only.
- SIM_version_major
- returns the current major
version of Simics.
- SIM_vmxmon_version
- returns the version of the VMP
kernel module loaded on the host machine.
NULL is returned
if the module is not loaded. - SIM_license_file
- returns the filename of the
currently applying License Agreement (SLA/EULA), if any is found. The
format parameter can be either an empty string (text version)
or "rtf" (RTF version).
- SIM_copyright
- returns the copyright notice
for Simics.
- SIM_license
- doesn't return anything but
prints out a short text describing licensing conditions.
SIM_version, SIM_version_base,
SIM_version_major return a string
owned by Simics. These strings must not be deallocated or modified by the
caller.
SIM_vmxmon_version, SIM_license_file,
and SIM_copyright return
a newly allocated string which is owned by the caller. This means that
when the function is called from C its return value should be later freed
with the use of the MM_FREE macro.
- EXECUTION CONTEXT
-
Global Context
The frags_t data type is part of the Simics API. It is used to
manipulate and modify network packets inside models efficiently. It is
meant to replace DBuffer in network device models wherever appropriate.
See the Model Builder User's Guide for an introduction to
programming with frags_t.
- NAME
-
frags_add — add data to a
frags_t
- SYNOPSIS
-
FORCE_INLINE void
frags_add(frags_t *buf, const void *data, size_t len);
- DESCRIPTION
-
Append the new data data of size len to
buf.
A
frags_t can hold up to 8 data fragments.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 new_data[2] = { 7, 8 };
frags_add(&foo, new_data, sizeof(new_data));
- SEE ALSO
-
frags_init_add, frags_init_add_from_frags,
frags_add_from_frags
- NAME
-
frags_add_from_frags — append an existing
frags_t to another
- SYNOPSIS
-
FORCE_INLINE void
frags_add_from_frags(frags_t *dst, const frags_t *src,
size_t offset, size_t len);
- DESCRIPTION
-
Append len bytes of the data at offset
offset in src to dst.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
frags_add_from_frags(&foo, &bar, 4, frags_len(&bar) - 4);
- SEE ALSO
-
frags_init_add, frags_add,
frags_init_add_from_frags
- NAME
-
frags_extract — extract the contents of a
frags_t
- SYNOPSIS
-
void frags_extract(const frags_t *buf, void *vdst);
- DESCRIPTION
-
Copy the whole contents of buf to vdst. The
destination buffer vdst should be large enough to contain
all data in buf.
This function is completely equivalent to frags_extract_slice()
with an offset and a length covering the
whole contents of the frags_t, and is provided for
convenience.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 all_data[frags_len(&foo)];
frags_extract(&foo, all_data);
- SEE ALSO
-
frags_extract_8, frags_extract_slice,
frags_extract_alloc, frags_extract_slice_alloc
- NAME
-
frags_extract_8, frags_extract_be16, frags_extract_le16, frags_extract_be32, frags_extract_le32, frags_extract_be64, frags_extract_le64 — extract a value
- SYNOPSIS
-
uint8 frags_extract_8(const frags_t *buf, size_t offset);
uint16 frags_extract_be16(const frags_t *buf, size_t offset);
uint16 frags_extract_le16(const frags_t *buf, size_t offset);
uint32 frags_extract_be32(const frags_t *buf, size_t offset);
uint32 frags_extract_le32(const frags_t *buf, size_t offset);
uint64 frags_extract_be64(const frags_t *buf, size_t offset);
uint64 frags_extract_le64(const frags_t *buf, size_t offset);
- DESCRIPTION
-
Extract a 8, 16, 32 or 64 bits value in either big-endian (_be)
or little-endian (_le) format from the contents of the
frags_t buf at offset offset.
- RETURN VALUE
-
Extracted value
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 val8 = frags_extract_8(&frame, 1);
uint16 val16 = frags_extract_be16(&frame, 2);
uint32 val32 = frags_extract_le32(&frame, 4);
uint32 val64 = frags_extract_be64(&frame, 8);
- SEE ALSO
-
frags_extract, frags_extract_slice
- NAME
-
frags_extract_alloc — return a copy of the contents of a
frags_t
- SYNOPSIS
-
void *frags_extract_alloc(const frags_t *buf);
- DESCRIPTION
-
Return an allocated copy of the contents of buf. The buffer
returned is allocated with MM_MALLOC(), and its ownership is
passed to the caller, which should free it when appropriate.
This function is equivalent to allocating a buffer of the correct size
with MM_MALLOC() followed by a call to
frags_extract(), and is provided for convenience.
- RETURN VALUE
-
A newly allocated copy of the contents
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 *all = frags_extract_alloc(&foo);
/* ... */
MM_FREE(all);
- SEE ALSO
-
frags_extract, frags_extract_slice,
frags_extract_slice_alloc
- NAME
-
frags_extract_slice — extract a slice of a
frags_t
- SYNOPSIS
-
void frags_extract_slice(const frags_t *buf, void *vdst, size_t offset,
size_t len);
- DESCRIPTION
-
Copy a slice of size len, starting at offset
offset, of the contents of buf, to
vdst. The destination buffer vdst should be
able to contain at least len bytes.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 some_data[16];
frags_extract_slice(&foo, some_data, 4, 16);
- SEE ALSO
-
frags_extract_8, frags_extract,
frags_extract_alloc, frags_extract_slice_alloc
- NAME
-
frags_extract_slice_alloc — return a partial copy of the contents of a
frags_t
- SYNOPSIS
-
void *frags_extract_slice_alloc(const frags_t *buf, size_t offset, size_t len);
- DESCRIPTION
-
Return an allocated copy of a slice of size len, starting
at offset offset, of the contents of
buf. The return value is allocated with
MM_MALLOC(), and its ownership is passed to the caller, which
should free it when appropriate.
This function is equivalent to allocating a buffer of the correct size
with MM_MALLOC() followed by a call to
frags_extract_slice(), and is provided for convenience.
- RETURN VALUE
-
A newly allocated, partial copy of the data
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 *slice = frags_extract_slice_alloc(&foo, 4, 16);
/* ... */
MM_FREE(slice);
- SEE ALSO
-
frags_extract, frags_extract_slice,
frags_extract_alloc
- NAME
-
frags_init — initialize a
frags_t
- SYNOPSIS
-
FORCE_INLINE void frags_init(frags_t *buf);
- DESCRIPTION
-
Initialize the
frags_t buf. An alternative is
to use the FRAGS_INIT constant value.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
/* Initialization with frags_init() */
frags_t bar;
frags_init(&bar);
/* Initialization with FRAGS_INIT */
frags_t foo = FRAGS_INIT;
- SEE ALSO
-
frags_init_add
- NAME
-
frags_init_add — initialize a
frags_t with an initial value
- SYNOPSIS
-
FORCE_INLINE void
frags_init_add(frags_t *buf, const void *data, size_t len);
- DESCRIPTION
-
Initialize the
frags_t buf and set it to
represent the initial data data of size
len.
This function is exactly equivalent to using frags_init(),
followed by frags_add(), and is provided for convenience.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
frags_t baz;
uint8 data[5] = { 0, 1, 2, 3, 4 };
frags_init_add(&baz, data, sizeof(data));
- SEE ALSO
-
frags_init, frags_add
- NAME
-
frags_init_add_from_frags — initialize a
frags_t from another
- SYNOPSIS
-
FORCE_INLINE void
frags_init_add_from_frags(frags_t *dst, const frags_t *src,
size_t offset, size_t len);
- DESCRIPTION
-
Initialize dst and set its initial value to the data of
size len starting at offset offset in
src.
This function is exactly equivalent to using frags_init(),
followed by frags_add_from_frags(), and is provided for
convenience.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
frags_t bat;
ASSERT(frags_len(&foo) > 16);
frags_init_add_from_frags(&bat, &foo, 16, frags_len(&foo) - 16);
- SEE ALSO
-
frags_init_add, frags_add,
frags_add_from_frags
- NAME
-
frags_it — return an iterator
- SYNOPSIS
-
FORCE_INLINE frags_it_t
frags_it(const frags_t *buf, size_t offset, size_t len);
- DESCRIPTION
-
Return an iterator on the fragments that compose the data in
buf, starting from offset offset and up to a
length of len. To iterate on all the data in
buf, offset should be set to 0 and
len to the value returned by frags_len().
- RETURN VALUE
-
An iterator on the fragments covering the desired
data range
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned sum = 0;
for (frags_it_t it = frags_it(&foo, 0, frags_len(&foo));
!frags_it_end(it);
it = frags_it_next(it)) {
unsigned f_len = frags_it_len(it);
const uint8 *f_data = frags_it_data(it);
for (int i=0; i<f_len; i++)
sum += f_data[i];
}
- SEE ALSO
-
frags_it_end, frags_it_next,
frags_it_len, frags_it_data
- NAME
-
frags_it_data — return the data of the current fragment
- SYNOPSIS
-
FORCE_INLINE const uint8 *
frags_it_data(frags_it_t it);
- DESCRIPTION
-
Return a pointer to the data of the current fragment pointed by the
iterator it.
- RETURN VALUE
-
The data of the current fragment
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned sum = 0;
for (frags_it_t it = frags_it(&foo, 0, frags_len(&foo));
!frags_it_end(it);
it = frags_it_next(it)) {
unsigned f_len = frags_it_len(it);
const uint8 *f_data = frags_it_data(it);
for (int i=0; i<f_len; i++)
sum += f_data[i];
}
- SEE ALSO
-
frags_it, frags_it_end,
frags_it_next, frags_it_len
- NAME
-
frags_it_end — return whether an iterator is finished
- SYNOPSIS
-
FORCE_INLINE bool
frags_it_end(frags_it_t it);
- DESCRIPTION
-
Return
true when the iterator it does not
have any next fragment to return at the next call of
frags_it_next(), and false otherwise.
- RETURN VALUE
-
true if the iterator is finished,
false otherwise.
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned sum = 0;
for (frags_it_t it = frags_it(&foo, 0, frags_len(&foo));
!frags_it_end(it);
it = frags_it_next(it)) {
unsigned f_len = frags_it_len(it);
const uint8 *f_data = frags_it_data(it);
for (int i=0; i<f_len; i++)
sum += f_data[i];
}
- SEE ALSO
-
frags_it, frags_it_next,
frags_it_len, frags_it_data
- NAME
-
frags_it_len — return the length of the current fragment
- SYNOPSIS
-
FORCE_INLINE size_t
frags_it_len(frags_it_t it);
- DESCRIPTION
-
Return the length of the current fragment pointed by the iterator
it.
- RETURN VALUE
-
The length of the current fragment
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned sum = 0;
for (frags_it_t it = frags_it(&foo, 0, frags_len(&foo));
!frags_it_end(it);
it = frags_it_next(it)) {
unsigned f_len = frags_it_len(it);
const uint8 *f_data = frags_it_data(it);
for (int i=0; i<f_len; i++)
sum += f_data[i];
}
- SEE ALSO
-
frags_it, frags_it_end,
frags_it_next, frags_it_data
- NAME
-
frags_it_next — return the next fragment's iterator
- SYNOPSIS
-
FORCE_INLINE frags_it_t
frags_it_next(frags_it_t it);
- DESCRIPTION
-
Return an iterator pointing at the next data fragment. This function
should only be called if frags_end(it) returns
false.
- RETURN VALUE
-
An iterator on the next fragment
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned sum = 0;
for (frags_it_t it = frags_it(&foo, 0, frags_len(&foo));
!frags_it_end(it);
it = frags_it_next(it)) {
unsigned f_len = frags_it_len(it);
const uint8 *f_data = frags_it_data(it);
for (int i=0; i<f_len; i++)
sum += f_data[i];
}
- SEE ALSO
-
frags_it, frags_it_end,
frags_it_len, frags_it_data
- NAME
-
frags_len — return the total data length
- SYNOPSIS
-
FORCE_INLINE size_t frags_len(const frags_t *buf);
- DESCRIPTION
-
Return the total length of the data represented by buf.
- RETURN VALUE
-
The total data length
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
unsigned len = frags_len(&foo);
- NAME
-
frags_prefix — prefix a
frags_t with a header
- SYNOPSIS
-
FORCE_INLINE frags_t
frags_prefix(const void *header, size_t header_len, const frags_t *body);
- DESCRIPTION
-
Create a
frags_t composed of the header header
of size header_len, followed by the contents of the
frags_t body.
This function is equivalent to a sequence of frags_init(),
frags_add(), frags_add_from_frags() to build a new
fragment containing the prefix. It is provided for convenience.
- RETURN VALUE
-
A new
frags_t including
header and body
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 eth_header[14] = { 0 };
frags_t packet = frags_prefix(eth_header, sizeof(eth_header), &foo);
- SEE ALSO
-
frags_suffix, frags_add_from_frags
- NAME
-
frags_suffix — append a suffix to a
frags_t
- SYNOPSIS
-
FORCE_INLINE frags_t
frags_suffix(const frags_t *body, void *header, size_t header_len);
- DESCRIPTION
-
Create a
frags_t composed of the contents of the
frags_t body, followed by the data
header of size header_len.
This function is equivalent to a sequence of frags_init(),
frags_add_from_frags(), frags_add() to build a new
fragment containing the suffix. It is provided for convenience.
- RETURN VALUE
-
A new
frags_t including
body and header
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
uint8 eth_checksum[4] = { 0 };
frags_t frame = frags_suffix(&foo, eth_checksum, sizeof(eth_checksum));
- SEE ALSO
-
frags_prefix, frags_add_from_frags
- NAME
-
frags_t, frags_it_t
- SYNOPSIS
-
typedef struct frags frags_t;
typedef struct frags_it frags_it_t;
- DESCRIPTION
-
These types encapsulate a data packet, for use by
models that send and receive data, such as network devices.
The structures should never be used directly. Only use the accessor
functions.
These are routines for manual dynamic memory allocation providing
some memory leak detection. They replace the standard C malloc
facility in Simics APIs.
Example: to allocate an array of 13 elements of type device_t,
use
device_t *d = MM_MALLOC(13, device_t);
It must be possible to get a pointer to the type by appending an asterisk to
the type name; so struct foo * is acceptable, but
int (*)(void) is not. Use a typedef in these cases.
It is not possible to mix these calls with the malloc
facility for the same allocations.
- NAME
-
MM_FREE — free allocation
- SYNOPSIS
-
MM_FREE(p);
- DESCRIPTION
-
MM_FREE frees an allocation previously made with
MM_MALLOC, MM_MALLOC_SZ, MM_ZALLOC,
MM_ZALLOC_SZ, MM_REALLOC, MM_REALLOC_SZ
or MM_STRDUP.
A null pointer argument is legal, in which case nothing happens.
- NAME
-
MM_MALLOC, MM_MALLOC_SZ, MM_ZALLOC, MM_ZALLOC_SZ — allocate memory
- SYNOPSIS
-
MM_MALLOC(nelems, type);
MM_MALLOC_SZ(size, type);
MM_ZALLOC(nelems, type);
MM_ZALLOC_SZ(size, type);
- DESCRIPTION
-
MM_MALLOC allocates nelems objects of type
type. MM_MALLOC_SZ specifies the total allocation size
in bytes.
MM_ZALLOC and MM_ZALLOC_SZ do the same thing as
MM_MALLOC and MM_ZALLOC respectively but in addition
fill the allocated memory with null bytes.
If nelems or size are zero, either a null pointer
or a pointer to a zero-sized allocation is returned.
- RETURN VALUE
-
Pointer to the allocated object(s).
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
MM_REALLOC, MM_REALLOC_SZ — reallocate memory
- SYNOPSIS
-
MM_REALLOC(p, nelems, type);
MM_REALLOC_SZ(p, size, type);
- DESCRIPTION
-
MM_REALLOC changes the size of an allocated memory block to
nelems elements. MM_REALLOC_SZ specifies the new size
in bytes.
The allocation must originally have been made by a call to
MM_MALLOC, MM_MALLOC_SZ, MM_ZALLOC,
MM_ZALLOC_SZ, MM_REALLOC, MM_REALLOC_SZ
or MM_STRDUP.
If the passed pointer is null, then these macros are equivalent to an
allocation of the desired amount. If nelems or size is
zero, either a null pointer or a pointer to a zero-sized allocation is
returned, and the original allocation is freed.
The allocation must be freed using MM_FREE.
- RETURN VALUE
-
Pointer to the reallocated object(s).
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
MM_STRDUP — duplicate a string
- SYNOPSIS
-
MM_STRDUP(str);
- DESCRIPTION
-
Allocates and initializes a copy of the null-terminated string
str. The allocation must be freed with MM_FREE.
- RETURN VALUE
-
Pointer to the newly allocated
string.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
The following types and functions are still available when a module is
compiled for an obsolete API. Compiling for an obsolete API is described
in the Model Builder User's Guide.
The DBuffer library is part of the Simics API. Up to Simics 4.0, it was
the preferred method to transfer data blocks, such as network packets,
inside the simulation. For code using the new link based on the link
library, and for new models, we recommend using the frags_t
data type instead.
- NAME
-
dbuffer_t
- SYNOPSIS
-
typedef struct dbuffer dbuffer_t;
- DESCRIPTION
-
This type is used to store blocks of binary data. It is optimized
for fast adding and removing of data, and does fast copying between
buffers using copy-on-write semantics.
The type is not inherently thread safe, so each instance must have a single
thread as owner, and only the owner can read or write from the instance,
however ownership can be transferred to another thread. To share the data
with other threads, the instance must first be cloned using
dbuffer_clone.
Note:
This is a legacy data type. New code should use one of
frags_t, bytes_t or buffer_t.
- NAME
-
init_prefs_t
- SYNOPSIS
-
typedef struct {
bool batch_mode;
bool quiet;
bool verbose;
bool python_verbose;
bool disable_istc;
bool disable_dstc;
bool module_cache_enable;
bool rdp;
bool sign_module;
const char *log_file;
/* The Simics project to use */
const char *project; // NULL to use saved prefs value
const char *package_list; // internal, do not use
bool no_windows;
bool fail_on_warnings;
const char *deprecation_level; // see sim->warn_deprecated
bool warn_deprecated; // same as deprecation_level == 2
bool no_warn_deprecated; // same as deprecation_level == 0
bool warn_multithread; /* deprecated and ignored (bug 21597) */
bool check_ifaces;
bool no_global_settings; // do not read preferences and recent-files
/* the following should be -1 if not set by command line options
to tell SIM_init_simulator() to use the saved preference value */
int log_enable;
} init_prefs_t;
- DESCRIPTION
-
The
init_prefs_t types are
deprecated and should not be used in new code.
- NAME
-
log_type_t
- SYNOPSIS
-
typedef enum {
Sim_Log_Info, // Normal informational message
Sim_Log_Error, // Simics error
Sim_Log_Spec_Violation, // target program violates the specification
Sim_Log_Unimplemented, // not implemented in Simics
Sim_Log_Critical, // Critical error stopping Simics
Sim_Log_Trace, // Breakpoint trace messages
Sim_Log_Warning, // Simics warning
Sim_Log_Num_Types, // Do not use
} log_type_t;
- DESCRIPTION
-
This type defines different log types that are used by the logging
facility to categorise messages.
- NAME
-
SIM_is_loading_micro_checkpoint — obsolete API function
- SYNOPSIS
-
bool
SIM_is_loading_micro_checkpoint(conf_object_t *obj);
- DESCRIPTION
-
Don't use. There is no longer a concept of micro-checkpoints after
removal of reverse execution.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
dbuffer_append, dbuffer_prepend, dbuffer_insert — Add data to a dbuffer
- SYNOPSIS
-
uint8 *
dbuffer_append(dbuffer_t *dbuffer, size_t len);
uint8 *
dbuffer_prepend(dbuffer_t *dbuffer, size_t len);
uint8 *
dbuffer_insert(dbuffer_t *dbuffer, size_t offset, size_t len);
- DESCRIPTION
-
These functions will extend the dbuffer with len
bytes and return a pointer to the added bytes. The
dbuffer_insert function adds the new data at
offset in the buffer, while the
dbuffer_prepend and dbuffer_append functions
add it at the beginning and end, respectively.
The returned pointer points to a memory area that is only guaranteed to
contain valid data for the newly added bytes, and it is illegal to
reference data before it or more than len-1 bytes ahead.
The new memory area is not guaranteed to be initialized.
The returned pointer is also only valid until the next operation on
the dbuffer function, except for calling dbuffer_len.
- NAME
-
dbuffer_append_external_data, dbuffer_prepend_external_data — Add static data
- SYNOPSIS
-
uint8 *
dbuffer_append_external_data(dbuffer_t *dbuffer, void *data,
size_t len, bool adopt);
uint8 *
dbuffer_prepend_external_data(dbuffer_t *dbuffer, void *data,
size_t len, bool adopt);
- DESCRIPTION
-
These functions work similar to dbuffer_append and
dbuffer_prepend, but with the difference that the data
isn't copied. Instead, the buffer will reference the data pointed
to directly.
If the adopt flag is true, the control of the data
block is transferred to the dbuffer. It is assumed to be a block
allocated with MM_MALLOC, and will be freed with
MM_FREE when the dbuffer is released.
If the adopt flag is false, the dbuffer will not free the
memory. Since there is no way to control the lifetime of the external
reference if the dbuffer reference has been passed to another function, this
option should never be used to point to memory on the stack or to memory
that will eventually deallocated. Pointing to static memory is usually
safe. This should also only be used for buffers that will only be read from,
since there is no way to know when the external pointer is used, and when a
copy is used.
- SEE ALSO
-
dbuffer_append
- NAME
-
dbuffer_append_value, dbuffer_prepend_value — Add data with uniform content
- SYNOPSIS
-
uint8 *
dbuffer_append_value(dbuffer_t *dbuffer, int value, size_t len);
uint8 *
dbuffer_prepend_value(dbuffer_t *dbuffer, int value, size_t len);
- DESCRIPTION
-
This adds data to a dbuffer and sets all the added bytes to
value. It has the same effect as using
dbuffer_append or dbuffer_append and calling
memset to set the contents.
The return value is a pointer to the data just added.
- SEE ALSO
-
dbuffer_append
- NAME
-
dbuffer_clone — Make a full copy of another buffer
- SYNOPSIS
-
dbuffer_t *
dbuffer_clone(dbuffer_t *dbuffer);
- DESCRIPTION
-
This function returns a new dbuffer that contains the same data as
the buffer given in the dbuffer parameter. This
doesn't involve copying any memory, since they can share the same
storage initially. However, they are still completely independent,
and operations on one buffer has no effect on the other.
The returned dbuffer should be released with
dbuffer_free when it is no longer needed.
- SEE ALSO
-
new_dbuffer, dbuffer_free
- NAME
-
dbuffer_copy_append, dbuffer_copy_prepend — Copy data from a dbuffer
- SYNOPSIS
-
void
dbuffer_copy_append(dbuffer_t *dst, dbuffer_t *src, size_t offset, size_t len);
void
dbuffer_copy_prepend(dbuffer_t *dst, dbuffer_t *src, size_t offset, size_t len);
- DESCRIPTION
-
These functions copies len bytes from the dbuffer
src, at offset offset, and adds it to
the beginning or end of the dbuffer dst.
This can often be done without actually copying any memory, so it
is usually very efficient.
- SEE ALSO
-
dbuffer_append
- NAME
-
dbuffer_free — Release a dbuffer
- SYNOPSIS
-
void
dbuffer_free(dbuffer_t *dbuffer);
- DESCRIPTION
-
Release a dbuffer that will not be used anymore. This will also
free any data in the buffer that isn't also used by other buffers.
After calling this function, the dbuffer must not be used anymore.
See also src/include/simics/util/dbuffer.h
- SEE ALSO
-
new_dbuffer
- NAME
-
dbuffer_len — Get the size of a dbuffer
- SYNOPSIS
-
size_t
dbuffer_len(const dbuffer_t *dbuffer);
- DESCRIPTION
-
This function returns the amount of data stored in a dbuffer. This
is the number of bytes that will be returned by
dbuffer_read_all.
- NAME
-
dbuffer_read, dbuffer_read_all, dbuffer_read_some — Extract data for reading
- SYNOPSIS
-
const uint8 *
dbuffer_read(dbuffer_t *dbuffer, size_t offset, size_t len);
const uint8 *
dbuffer_read_all(dbuffer_t *dbuffer);
const uint8 *
dbuffer_read_some(dbuffer_t *dbuffer, size_t offset, size_t len,
size_t *actual_len);
- DESCRIPTION
-
The offset and len parameters specify
a region of the buffer to read from. The returned pointer is
guaranteed to point to a contiguous block of memory of size
len. It is illegal to write to the block return by
these functions, since they may be shared by other dbuffers. Use
the dbuffer_update functions if you need to both read
and write to the dbuffer.
The returned pointer is only valid until the next operation on the
dbuffer, except for calling dbuffer_len.
The offset and len must specify a
valid region, so that the end of the region is not past the end of
the dbuffer.
The dbuffer_read_some function takes an
actual_len parameter, and may return a smaller
buffer than requested. The actual number of valid bytes in the
returned buffer is stored in *actual_len. It will
return a smaller buffer if it would have had to copy memory to
return a pointer to the whole region. This means that you can use
this function repeatedly to extract all the requested data in the
most efficient way. If NULL is passed for
actual_len, it will return the full region.
The dbuffer_read_all function assumes 0 for
offset, and buffer_len(dbuffer) for
len.
- SEE ALSO
-
dbuffer_update, dbuffer_replace
- NAME
-
dbuffer_remove, dbuffer_remove_head, dbuffer_remove_tail — Remove data from a dbuffer
- SYNOPSIS
-
void
dbuffer_remove(dbuffer_t *dbuffer, size_t offset, size_t remove_len);
void
dbuffer_remove_head(dbuffer_t *dbuffer, size_t remove_len);
void
dbuffer_remove_tail(dbuffer_t *dbuffer, size_t remove_len);
- DESCRIPTION
-
These functions will remove remove_len bytes from
dbuffer. The dbuffer_remove function will remove
data starting at offset, while the other functions will
remove data from the beginning or end of the buffer.
This usually doesn't involve moving any memory contents, and should
be very efficient even if the buffer is large.
The size of data to remove must be available in the buffer. For example
offset + remove_len must not be greater than
the buffers length. Similarly for the dbuffer_truncate function
there must be at least new_size bytes in the current buffer.
- NAME
-
dbuffer_replace, dbuffer_replace_all, dbuffer_replace_some — Replace data
- SYNOPSIS
-
uint8 *
dbuffer_replace(dbuffer_t *dbuffer, size_t offset, size_t len);
uint8 *
dbuffer_replace_all(dbuffer_t *dbuffer);
uint8 *
dbuffer_replace_some(dbuffer_t *dbuffer, size_t offset, size_t len,
size_t *actual_len);
- DESCRIPTION
-
The offset and len parameters specify
a region of the buffer to write to. The returned pointer is
guaranteed to point to a contiguous block of memory of size
len, but is not guaranteed to contain the existing
data in the buffer. Use these functions when completely replacing
a region of the buffer with new data.
The returned pointer is only valid until the next operation on the
dbuffer, except for calling dbuffer_len.
The offset and len must specify a
valid region, so that the end of the region is not past the end of
the dbuffer.
The dbuffer_replace_some function takes an
actual_len parameter, and may return a smaller
buffer than requested. The actual number of valid bytes in the
returned buffer is stored in *actual_len. It will
return a smaller buffer if it would have had to copy memory to
return a pointer to the whole region. This means that you can use
this function repeatedly to write all the requested data in the
most efficient way. If NULL is passed for
actual_len, it will return the full region.
The dbuffer_replace_all function assumes 0 for
offset, and buffer_len(dbuffer) for
len.
- SEE ALSO
-
dbuffer_read, dbuffer_update
- NAME
-
dbuffer_split — Split a dbuffer
- SYNOPSIS
-
dbuffer_t *
dbuffer_split(dbuffer_t *dbuffer, size_t offset);
- DESCRIPTION
-
This function returns a new dbuffer that contains the
offset first bytes from dbuffer, and
removes those bytes from dbuffer The effect is that
the dbuffer is split in two halves, leaving the second half in the
original dbuffer and returning the first half as a new dbuffer.
The returned dbuffer should be released with
dbuffer_free when it is no longer needed.
- SEE ALSO
-
new_dbuffer, dbuffer_free
- NAME
-
dbuffer_update, dbuffer_update_all, dbuffer_update_some — Extract data for updating
- SYNOPSIS
-
uint8 *
dbuffer_update(dbuffer_t *dbuffer, size_t offset, size_t len);
uint8 *
dbuffer_update_all(dbuffer_t *dbuffer);
uint8 *
dbuffer_update_some(dbuffer_t *dbuffer, size_t offset, size_t len,
size_t *actual_len);
- DESCRIPTION
-
The offset and len parameters specify
a region of the buffer to access. The returned pointer is
guaranteed to point to a contiguous block of memory of size
len. The block can be used for reading and writing
data to the dbuffer.
The returned pointer is only valid until the next operation on the
dbuffer, except for calling dbuffer_len.
The offset and len must specify a
valid region, so that the end of the region is not past the end of
the dbuffer.
The dbuffer_update_some function takes an
actual_len parameter, and may return a smaller
buffer than requested. The actual number of valid bytes in the
returned buffer is stored in *actual_len. It will
return a smaller buffer if it would have had to copy memory to
return a pointer to the whole region. This means that you can use
this function repeatedly to access all the requested data in the
most efficient way. If NULL is passed for
actual_len, it will return the full region.
The dbuffer_update_all function assumes 0 for
offset, and buffer_len(dbuffer) for
len.
- SEE ALSO
-
dbuffer_read, dbuffer_replace
- NAME
-
new_dbuffer — Create a new dbuffer
- SYNOPSIS
-
dbuffer_t *
new_dbuffer();
- DESCRIPTION
-
This function returns an empty dbuffer. Use it when you need a new
dbuffer, and call dbuffer_free when it isn't needed
anymore.
See also src/include/simics/util/dbuffer.h
- SEE ALSO
-
dbuffer_free, dbuffer_clone
- Description
- This interface is used between the A20 line handling device
(typically the keyboard controller) and the x86 processor. The processor
implements this interface and the keyboard controller calls it.
SIM_INTERFACE(a20) {
void (*set_a20_line)(conf_object_t *NOTNULL obj, int value);
int (*get_a20_line)(conf_object_t *NOTNULL obj);
};
#define A20_INTERFACE "a20"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by all apic buses, and used by the IO-APICs to
send a message over the bus.
Messages with delivery mode Apic_Delivery_Mode_Ext_INT needs to be
acknowledged. They are acknowledged at the object pointed to by the apic's
"pic" attribute via the interrupt_cpu interface.
SIM_INTERFACE(apic_bus) {
apic_bus_status_t (*interrupt)(conf_object_t *obj,
apic_destination_mode_t dest_mode,
apic_delivery_mode_t delivery_mode,
int level_assert,
apic_trigger_mode_t trigger_mode,
uint8 vector,
uint8 destination);
};
#define APIC_BUS_INTERFACE "apic_bus"
typedef enum {
Apic_Destination_Mode_Physical = 0,
Apic_Destination_Mode_Logical = 1
} apic_destination_mode_t;
typedef enum {
Apic_Delivery_Mode_Fixed = 0,
Apic_Delivery_Mode_Lowest_Priority = 1,
Apic_Delivery_Mode_SMI = 2,
Apic_Delivery_Mode_Remote_Read = 3,
Apic_Delivery_Mode_NMI = 4,
Apic_Delivery_Mode_INIT = 5,
Apic_Delivery_Mode_Start_Up = 6,
Apic_Delivery_Mode_Ext_INT = 7
} apic_delivery_mode_t;
typedef enum {
Apic_Trigger_Mode_Edge = 0,
Apic_Trigger_Mode_Level = 1
} apic_trigger_mode_t;
typedef enum {
Apic_Bus_Accepted = 0,
Apic_Bus_Retry = 1,
Apic_Bus_No_Target = 2,
Apic_Bus_Invalid = 3
} apic_bus_status_t;
See the architecture software developer's manual for more information about
the parameters. For IPIs, the sender is responsible for filtering out
reserved vectors (vectors 0 through 15) and flagging the appropriate error
on the sending side. For I/O-APIC initiated interrupts, reserved vectors can
be sent and will flag errors in the receiving APICs.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the local APIC device and is used by the
processor and machine initialization code to interact with the local APIC.
The tpr_r and tpr_w methods read and write the task
priority register. The format of the tpr argument and the
returned value from tpr_r is the same as for CR8, meaning
TPR[bits 7:4], zero extended to 64 bits.
Interrupts coming from the CPU itself are passed via the
local_int function. The type of interrupt is one of the constants
defined in local_apic_interrupt_t.
typedef enum {
Apic_Lvt_2e = 0x2e0,
Apic_CMCI = 0x2f0,
Apic_Performance_Counter = 0x340,
Apic_Thermal_Sensor = 0x330
} local_apic_interrupt_t;
The init function is called by the CPU when it receives the INIT
signal. The APIC should only update its internal state and not propagate
this signal further. Both the CPU and the APIC should reset their pending
interrupt flags when this function is called. The init function
is not called at instantiation time.
The power_on function is called at machine creation time, and the
call initializes the APIC to the power on state. The bsp argument
is true if the APIC is connected to the boot processor, and false
otherwise. The initial APIC ID is set through the apic_id
argument. The power_on function would typically be called from
component code for the processor that includes the APIC.
The enabled_r method returns bit 11 from the APIC BASE MSR, and
is used by the processor to return the correct status for CPUID.
SIM_INTERFACE(apic_cpu) {
uint64 (*tpr_r)(conf_object_t *NOTNULL obj);
void (*tpr_w)(conf_object_t *NOTNULL obj, uint64 tpr);
void (*local_int)(conf_object_t *NOTNULL obj,
local_apic_interrupt_t int_type);
void (*power_on)(conf_object_t *NOTNULL obj, bool bsp, int apic_id);
void (*init)(conf_object_t *NOTNULL obj);
bool (*enabled_r)(conf_object_t *NOTNULL obj);
};
#define APIC_CPU_INTERFACE "apic_cpu"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(arinc429_bus) {
void (*send_word)(conf_object_t *bus, uint32 word, int parity_ok);
};
Interface to Arinc-429 serial buses.
The send_word function is used by a device to send an
Arinc-429 formatted word. The most significant bit (bit 31) is the
parity bit, but if the device have checksumming built in, it can
set parity_ok to tell the bus to ignore bit 31 of the data.
If the parity bit is already calculated, pass -1 as parity_ok.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(arinc429_receiver) {
void (*receive_word)(conf_object_t *dev, uint32 word, int parity_ok);
};
Interface to Arinc-429 compatible receivers.
The receive_word is called when there is traffic on the bus.
word contains the data received (with valid parity bit),
and the parity_ok tells whether the parity of the word
is correct or not.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by ARM processors to provide various
functionality that is specific for this class of processors.
The read_register_mode and write_register_mode
functions are used to access banked copies of the registers. They are used
just like the int_register interface read and
write functions, except that they take an extra parameter
mode that specifies which register bank should be used.
mode should be the mode bits in the cpsr corresponding to
the mode shifted right to bits 0-4.
SIM_INTERFACE(arm) {
uint64 (*read_register_mode)(conf_object_t *processor_obj,
int reg_num, int mode);
void (*write_register_mode)(conf_object_t *processor_obj,
int reg_num, int mode, uint64 value);
};
#define ARM_INTERFACE "arm"
- Execution Context
- Cell Context for all methods.
- Description
- The
ARM AVIC interface makes it possible for an ARM
processor to get the interrupt vector address from an AVIC device
connected to the processor core. Both processor and AVIC must
enable the AVIC interface to support this feature.
The processor calls get_interrupt_address function to
get the interrupt vector address. The AVIC returns an
arm_avic_t struct with a valid field and an
address field, the address field is only valid when
the valid is not 0.
typedef struct arm_avic {
int valid;
uint32 address;
} arm_avic_t;
SIM_INTERFACE(arm_avic) {
arm_avic_t (*get_interrupt_address)(conf_object_t *obj);
};
#define ARM_AVIC_INTERFACE "arm_avic"
- Execution Context
- Cell Context for all methods.
- Description
- A coprocessor for the ARM has to provide the
arm_coprocessor_interface. This interface
defines the functions that will be called when
the coprocessor instructions (cdp, ldc, mcr, mrc, mrrc, mcrr, stc)
are executed.
The read_register_64_bit and write_register_64_bit are used for
mrrc and mccr instructions which read and write 64 bit values
in to two registers.
The interface also defines a flag, finished, which indicates
whether a memory transfer operation is finished or not.
The function reset is called when the cpu is reset,
and allows the coprocessor to also do a reset,
the argument hard_reset indicates whether the reset
was soft (0) or hard (1).
SIM_INTERFACE(arm_coprocessor) {
void (*process_data)(conf_object_t *NOTNULL obj,
uint32 CRd,
uint32 opcode_1,
uint32 CRn,
uint32 CRm,
uint32 opcode_2,
int type);
void (*load_coprocessor)(conf_object_t *NOTNULL obj,
uint32 CRd,
uint32 N,
uint32 Options,
uint32 value,
int type);
uint32 (*read_register)(conf_object_t *NOTNULL obj,
uint32 opcode_1,
uint32 CRn,
uint32 CRm,
uint32 opcode_2,
int type);
void (*write_register)(conf_object_t *NOTNULL obj,
uint32 value,
uint32 opcode_1,
uint32 CRn,
uint32 CRm,
uint32 opcode_2,
int type);
uint64 (*read_register_64_bit)(conf_object_t *NOTNULL obj,
uint32 opcode_1,
uint32 CRm,
int type);
void (*write_register_64_bit)(conf_object_t *NOTNULL obj,
uint64 value,
uint32 opcode_1,
uint32 CRm,
int type);
uint32 (*store_coprocessor)(conf_object_t *NOTNULL obj,
uint32 CRd,
uint32 N,
uint32 Options,
int type);
void (*reset)(conf_object_t *NOTNULL obj, int hard_reset);
};
#define ARM_COPROCESSOR_INTERFACE "arm_coprocessor"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is only intended to be used between Arm CPU objects. It
contains the functions needed for cross-CPU communication related to
event signalling.
signal_event notifies the CPU to set the event register.
SIM_INTERFACE(arm_cpu_group_event) {
void (*signal_event)(conf_object_t *obj);
};
#define ARM_CPU_GROUP_EVENT_INTERFACE "arm_cpu_group_event"
- Execution Context
- Threaded Context for all methods.
- Description
- This interface is only intended to be used between Arm CPU objects. It
contains the functions needed for cross-CPU communication related to
exclusive memory accesses.
mark_exclusive notifies the CPU that another CPU has marked the
address range as exclusive. The CPU must then probe all CPUs in the CPU
group for exclusive address ranges using probe_exclusive and
possibly invalidate them using clear_exclusive before accessing
the address range.
clear_and_probe_exclusive notifies the CPU to invalidate any
exclusive address ranges that it has overlapping the specified clear address
range. Also returns true if the CPU still has any exclusive address ranges
overlapping the specified probe address range.
SIM_INTERFACE(arm_cpu_group_exclusive) {
void (*mark_exclusive)(
conf_object_t *obj,
physical_address_t address,
physical_address_t size);
bool (*clear_and_probe_exclusive)(
conf_object_t *obj,
physical_address_t clear_address,
physical_address_t clear_size,
physical_address_t probe_address,
physical_address_t probe_size);
};
#define ARM_CPU_GROUP_EXCLUSIVE_INTERFACE "arm_cpu_group_exclusive"
- Execution Context
- Threaded Context for all methods.
- Description
- This interface is only intended to be used between Arm CPU objects. It
contains the functions needed for cross-CPU communication related to
TLB invalidation.
invalidate_tlb notifies the CPU to invalidate TLB entries related
to the translation regime. If by_virtual_address is true only
entries containing the specified virtual address should be invalidated,
otherwise all entries should be invalidated.
SIM_INTERFACE(arm_cpu_group_tlb) {
void (*invalidate_tlb)(
conf_object_t *obj,
arm_translation_regime_t translation_regime,
bool by_virtual_address,
logical_address_t virtual_address);
};
#define ARM_CPU_GROUP_TLB_INTERFACE "arm_cpu_group_tlb"
- Execution Context
- Threaded Context for all methods.
- Description
- This
arm_external_debug interface is used for
external debug feature.
The handle_semihosting function is called whenever the aarch64
instruction hlt 0xf000 is executed where semihosting is enabled for use.
The read_reg function is called reading the registers in external
debug device.
The write_reg function is called writing the registers in
external debug device.
- Execution Context
- Cell Context for all methods.
- Description
- This
arm_gic interface is used
accessing registers in a device implementing the Generic Interrupt
Controller architecture..
The read_register function is called reading the registers in GIC
device.
The write_register function is called writing the registers in
GIC device.
The cpu_state_changed function is called to notify the GIC device
that the cpu has changed state. This function is only called when the cpu
changes state with an interrupt pending.
- Execution Context
- Cell Context for all methods.
- Description
- This
arm_gic_cpu_state
interface is used providing cpu states for a device implementing the Generic
Interrupt Controller architecture.
The get_cpu_state_info function is called to get current state of
the a CPU, e.g. exception level, secure mode.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by ARM processors that supports the arm ARM
TrustZone feature. The get_security_mode function returns the
current state of the processor, whereas mem_op_security_mode
extracts the mode of a memory operation in progress.
The get_security_mode functions corresponds to the expression
(cpsr.mode != Monitor && scr.ns) ? Arm_Trustzone_Non_Secure :
Arm_Trustzone_Secure. The mem_op_security_mode function
always returns Arm_Trustzone_Non_Secure when the processor is in
non-secure mode, in secure mode it returns the ns bit in the
first-level page table entry for the actual area being accessed.
typedef enum {
Arm_Trustzone_Secure = 0,
Arm_Trustzone_Non_Secure = 1
} arm_trustzone_mode_t;
SIM_INTERFACE(arm_trustzone) {
arm_trustzone_mode_t (*get_security_mode)(conf_object_t *NOTNULL obj);
arm_trustzone_mode_t (*mem_op_security_mode)(
conf_object_t *NOTNULL obj,
generic_transaction_t *NOTNULL memop);
};
#define ARM_TRUSTZONE_INTERFACE "arm_trustzone"
- Execution Context
- Cell Context for all methods.
- Description
- The
bridge interface is implemented by objects
that bridge between memory spaces. The not_taken function
is called if the access is not claimed by any device in the
destination memory-space. If a memory transaction reaches a mapping
that has the same bridge object as the previous mapping, the access
is considered as not taken, and the not_taken function
for the first bridge mapping is called.
SIM_INTERFACE(bridge) {
exception_type_t (*not_taken)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL src_space,
conf_object_t *NOTNULL dst_space,
exception_type_t ex,
generic_transaction_t *NOTNULL mem_op,
map_info_t mapinfo);
};
#define BRIDGE_INTERFACE "bridge"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(can_device) {
void (*receive)(conf_object_t *obj, can_frame_t *frame);
};
#define CAN_DEVICE_INTERFACE "can_device"
The can_device interface is implemented by CAN controllers.
The receive function is called by can-endpoint to pass CAN frame
from other can-endpoint to the connected CAN controller.
The CAN frame is expressed by the frame parameter, which is a
pointer of can_frame_t. The following is the details of
can_frame_t:
Standard Format:
Arbitration Field(11bit_ID+RTR)+Control Field(IDE+r0+DLC)
Extended Format:
Arbitration Field(11bit_sID+SRR+IDE+18bit_eID+RTR)+Control Field(r1+r0+DLC)
Above are the Arbitration Field and Control Field of the physical Standard
frame and Extended frame. But the can_frame_t only focus on the
logical meanings of such fields and tries to adapt different CAN controllers:
identifier: For Standard frame, 11bit_ID should be put in
identifier[10:0];for Extended frame, 11bit_sID should be put in
identifier[28:18] and 18bit_eID should be put in
identifier[17:0].
extended: There isn't IDE in can_frame_t, instead,
extended is used to indicate if the frame is Extended frame or
Standard frame.
rtr: There isn't SRR in can_frame_t for Extended frame,
instead, rtr is used to indicate if the frame is a remote frame or
not. Here we don't care whether the frame is Extended frame or Standard
frame.
data_length: The data_length contains the arithmetic
value of the DLC.
data[CAN_DATA_MAX_NUM]: This is the data field of Date frame.
crc: This is the crc field of a CAN frame.
typedef struct {
/* arbitration field */
uint32 identifier;
bool extended;
bool rtr;
/* control field */
uint8 data_length;
/* data field */
uint8 data[CAN_DATA_MAX_NUM];
/* crc field */
uint16 crc;
} can_frame_t;
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(can_link) {
can_status_t (*send)(conf_object_t *obj, can_frame_t *frame);
};
#define CAN_LINK_INTERFACE "can_link"
The can_link interface is implemented by can-endpoint.
The send function is called by CAN controller to pass CAN frame
to the connected can-endpoint. Then can-link delivers the CAN frame to other
can-endpoints.
- Execution Context
- Cell Context for all methods.
- Description
- Interface between CoreInt capable processor and interrupt controller.
This interface is implemented by CoreInt capable interrupt controllers and
allows the processor to automatically acknowledge external interrupts
without software intervention.
The acknowledge function is called by the processor when an
external interrupt is taken. If coreint is enabled in the interrupt
controller, the interrupt controller should lower the interrupt signal
towards the processor and return the interrupt source
vector. This way the software doesn't have to go and query the
interrupt controller for the source. If coreint is not enabled, the
interrupt should not do anything and the vector value in the reply is
undefined.
#include <simics/pywrap.h>
#include <simics/base/types.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct {
bool enabled;
uint64 vector;
} coreint_reply_t;
#define COREINT_INTERFACE "coreint"
SIM_INTERFACE(coreint) {
coreint_reply_t (*acknowledge)(conf_object_t *obj, conf_object_t *core);
};
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used to claim ranges in CXL address spaces.
Functions add_map and del_map are used to add and
remove maps, map_obj will be mapped in the address space
indicated by type according to the information in info.
Note: This interface is considered tech-preview and may change without
notice.
typedef enum {
CXL_Type_Not_Set,
CXL_Type_Io,
CXL_Type_Mem,
CXL_Type_Cache,
CXL_Type_Other,
} cxl_type_t;
SIM_INTERFACE(cxl_map)
{
void (*add_map)(conf_object_t *obj, conf_object_t *map_obj,
map_info_t info, cxl_type_t type);
void (*del_map)(conf_object_t *obj, conf_object_t *map_obj,
physical_address_t base, cxl_type_t type);
};
#define CXL_MAP_INTERFACE "cxl_map"
- Execution Context
- Cell Context for all methods.
- Description
- Functions enable_decoder and disable_decoder are used
to enable and disable HDM decoders on a cxl-hdm-port device.
SIM_INTERFACE(cxl_mem_downstream_port_managing)
{
bool (*register_port_mem_obj)(conf_object_t *obj, uint8 port_number,
conf_object_t *port_mem_obj);
void (*unregister_port_mem_obj)(conf_object_t *obj, uint8 port_number);
};
#define CXL_MEM_DOWNSTREAM_PORT_MANAGING_INTERFACE "cxl_mem_downstream_port_managing"
- Execution Context
- Cell Context for all methods.
- Description
- Functions enable_decoder and disable_decoder are used
to enable and disable HDM decoders on a cxl-hdm-port device.
SIM_INTERFACE(cxl_non_device_decoder_handling)
{
int (*enable_decoder)(conf_object_t *obj, uint8 index, uint8 ig,
uint8 iw, uint64 base, uint64 size,
uint64 target_list);
int (*disable_decoder)(conf_object_t *obj, uint8 decoder_index);
};
#define CXL_NON_DEVICE_DECODER_HANDLING_INTERFACE "cxl_non_device_decoder_handling"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(datagram_link) {
/* Transmit a message to the object. */
void (*receive)(conf_object_t *NOTNULL obj, bytes_t msg);
};
#define DATAGRAM_LINK_INTERFACE "datagram_link"
This interface is implemented by objects that receive messages from a
datagram-link, and by the datagram-link connection endpoints themselves.
There is a single function receive(), which is used to pass the
message msg to the object obj.
The message msg is treated as a series of bytes with no
special format or meaning expected. If obj is a datagram-link
endpoint, it will forward the message to all other endpoints registered on
the link except the sender, effectively broadcasting the message on the
link. If obj is a device, it will simply receive the message
as sent by the original sender.
Note that the symmetry of the interface allows two devices to be connected
directly to each other and talk as if connected via a datagram-link. This is
however not supported by the default datagram-link component, so a special
connector must be created for this purpose. Additionally, the standard link
features, such as multicell configurations and latency, will not be available
in that setup.
- Execution Context
-
- Description
SIM_INTERFACE(ethernet_cable) {
void (*link_status)(conf_object_t *NOTNULL ep, bool link_up);
};
#define ETHERNET_CABLE_INTERFACE "ethernet_cable"
This interface is implemented by Ethernet devices and link endpoints that
are interested in the link status of the peer.
The link_status function is used to notify the peer that the link
status at the local end is up or down. The
ethernet-cable-link class propagates this information to the
device connected at the other end.
- Execution Context
-
- Description
SIM_INTERFACE(ethernet_common) {
void (*frame)(conf_object_t *NOTNULL obj, const frags_t *frame,
eth_frame_crc_status_t crc_status);
};
#define ETHERNET_COMMON_INTERFACE "ethernet_common"
This interface is implemented by objects that receive Ethernet frames, both
Ethernet devices and Ethernet link endpoints.
There is a single function frame which sends an Ethernet frame,
without preamble nor SFD (Start Frame Delimiter), but with a CRC field.
The crc_status parameter provides out-of-band information on
the contents of the frame with regards to the CRC field using one of the
values in the eth_frame_crc_status_t enum:
Eth_Frame_CRC_Match means that the frame contents are
correct. The CRC field in the frame should not be relied upon as its
computation may have been skipped for optimization, and it may contain any
value, including zero, a random value or a correctly computed CRC.
Eth_Frame_CRC_Mismatch means that the frame contents are
incorrect. The CRC field in the frame must contain a CRC that does not
match the frame contents, i.e., to send an incorrect frame on the link,
you must make sure that the CRC field will not match when computed.
Eth_Frame_CRC_Unknown means that the relation between the
frame contents and the CRC field is unknown. The relation can be
established by computing the frame's CRC and comparing it to the frame's
CRC field.
typedef enum {
Eth_Frame_CRC_Match,
Eth_Frame_CRC_Mismatch,
Eth_Frame_CRC_Unknown
} eth_frame_crc_status_t;
When a device calls a link's frame function, it can set
crc_status to any of the three values. If the link receives a
Eth_Frame_CRC_Unknown, it will compute the CRC itself to set the
status to Eth_Frame_CRC_Match or Eth_Frame_CRC_Mismatch.
When a link calls a device's frame function, crc_status will be set
to either Eth_Frame_CRC_Match or Eth_Frame_CRC_Mismatch,
and never Eth_Frame_CRC_Unknown.
When two devices are directly connected to each others without using a link,
the interpretation of Eth_Frame_CRC_Unknown is up to the devices'
implementation.
- Execution Context
-
- Description
//:: pre eth_probe_side_t {{
typedef enum {
Eth_Probe_Port_A = 0,
Eth_Probe_Port_B = 1
} eth_probe_side_t;
// }}
//:: pre ethernet_probe_snoop_t {{
typedef void (*ethernet_probe_snoop_t)(lang_void *user_data,
conf_object_t *probe,
eth_probe_side_t to_side,
const frags_t *frame,
eth_frame_crc_status_t crc_status);
//:: pre ethernet_probe_interface_t_def {{
SIM_INTERFACE(ethernet_probe) {
void (*attach_snooper)(conf_object_t *NOTNULL probe,
ethernet_probe_snoop_t snoop_fun,
lang_void *user_data);
void (*attach_probe)(conf_object_t *NOTNULL probe,
ethernet_probe_snoop_t snoop_fun,
lang_void *user_data);
void (*detach)(conf_object_t *NOTNULL probe);
void (*send_frame)(conf_object_t *NOTNULL probe,
eth_probe_side_t to_side,
const frags_t *frame,
eth_frame_crc_status_t crc_status);
};
#define ETHERNET_PROBE_INTERFACE "ethernet_probe"
// }}
This interface is implemented by eth-probe objects. Once a
probe has been inserted between a device and an Ethernet link, the functions
of this interface can be used to setup callbacks:
- attach_snooper()
- Attach a snooper function: the
probe will pass each frame to the snooper function, then forward it
unchanged where it should be going
- attach_probe()
- Attach a probe function: the probe
will pass each frame to the probe function, and give it the responsibility
of forwarding the frame or any number of modified or additional frames using
the send_frame() function.
- detach
- Detach the currently registered callback from
the probe.
- send_frame
- Send a frame via the probe, either to the
side A or B of the probe. Which side is which can be obtained with the <eth-probe>.info function.
This interface should only be used for inspection, and never as part of the
actual simulation. The snoop functions must not affect the simulation in any
way.
The clock parameter tells the link on which clock to post the
events that call the snoop function. The snoop function will be called at
the delivery time of the network packet, which means that it will be called
at the same time as any Ethernet devices attached to the same clock that
receives packets from the same link.
Snooped frames with a matching CRC will contain the correct frame check
sequence.
The user_data parameter is passed to the snoop function every
time it is called.
- Execution Context
- Cell Context for all methods.
- Description
typedef void (*ethernet_link_snoop_t)(lang_void *user_data,
conf_object_t *clock,
const frags_t *packet,
eth_frame_crc_status_t crc_status);
//:: pre ethernet_snoop_interface_t {{
SIM_INTERFACE(ethernet_snoop) {
conf_object_t *(*attach)(conf_object_t *NOTNULL link,
conf_object_t *clock,
ethernet_link_snoop_t snoop_fun,
lang_void *user_data);
};
#define ETHERNET_SNOOP_INTERFACE "ethernet_snoop"
// }}
This interface is implemented by Ethernet link objects. It is used to attach
snoop functions to the link. The snoop function will receive all traffic
going over the link.
This interface should only be used for inspection, and never as part of the
actual simulation. The snoop functions must not affect the simulation in any
way.
The clock parameter tells the link on which clock to post the
events that call the snoop function. The snoop function will be called at
the delivery time of the network packet, which means that it will be called
at the same time as any Ethernet devices attached to the same clock that
receives packets from the same link.
Snooped frames with a matching CRC will contain the correct frame check
sequence.
The user_data parameter is passed to the snoop function every
time it is called.
- Execution Context
-
- Description
typedef void (*ethernet_link_snoop_t)(lang_void *user_data,
conf_object_t *clock,
const frags_t *packet,
eth_frame_crc_status_t crc_status);
SIM_INTERFACE(ethernet_vlan_snoop) {
conf_object_t *(*attach)(
conf_object_t *NOTNULL link, conf_object_t *clock,
ethernet_link_snoop_t snoop_fun, lang_void *user_data,
uint16 vlan_id, bool is_vlan_trunk);
};
#define ETHERNET_VLAN_SNOOP_INTERFACE "ethernet_vlan_snoop"
This interface is implemented by Ethernet VLAN switch link objects. It is
used to attach snoop functions to the link. The snoop function will receive
all traffic going over the link, either on a single VLAN, or on all of them.
This interface should only be used for inspection, and never as part of the
actual simulation. The snoop functions must not affect the simulation in any
way.
The clock parameter tells the link on which clock to post the
events that call the snoop function. The snoop function will be called at
the delivery time of the network packet, which means that it will be called
at the same time as any Ethernet devices attached to the same clock that
receives packets from the same link.
Snooped frames with a matching CRC will contain the correct frame check
sequence.
The user_data parameter is passed to the snoop function every
time it is called.
The vlan_id indicates on which VLAN the snoop function should
be attached (as its native VLAN).
The is_vlan_trunk flag indicates whether the snoop function
should also receive the traffic on all other VLANs, tagged with an 802.1Q
tag.
- Execution Context
-
- Description
- This interface extends the
serial_device with
a write_at() function. It is similar to the write()
function of the mentioned interface, but accepts an on-screen character
position. This interface is implemented by text consoles allowing them
to be connected to text oriented frame buffers, such as VGA in text mode.
SIM_INTERFACE(extended_serial) {
void (*write_at)(conf_object_t *obj,
int value, int x, int y, int fg, int bg);
void (*graphics_mode)(conf_object_t *obj, int in_graphics_mode);
};
#define EXTENDED_SERIAL_INTERFACE "extended_serial"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(firewire_bus) {
int (*connect_device)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev);
int (*disconnect_device)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev);
void (*set_device_bus_id)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev,
uint16 bus_id);
void (*set_id_mask)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev,
uint16 id_mask);
firewire_ack_code_t (*transfer)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL source,
dbuffer_t *packet, int crc_calculated);
int (*register_channel)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev,
uint32 channel);
int (*unregister_channel)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL dev,
uint32 channel);
void (*reset)(conf_object_t *NOTNULL bus);
};
#define FIREWIRE_BUS_INTERFACE "firewire_bus"
This interface must be implemented by all firewire buses.
connect_device is called when a device wants to connect to the
bus. The bus should return 0 upon success.
disconnect_device is called when a device wants to disconnect
from the bus. The bus should return 0 upon success.
set_device_bus_id sets the bus id for the device. This needs to
be called by a device when its Node_IDS[bus_id] field is updated. The
new bus id should be placed in bits 15-6 in the bus_id argument.
set_id_mask can be called by a device to specify a mask that
should be applied to the device ID when routing transfers. This can be
used to e.g. accept transfers to multiple bus-numbers.
transfer sends a packet. The bus will
route the transfer to the correct device(s). The source
parameter should be set to the device which sent the transfer. The bus uses
this parameter to avoid sending packets to their sender. If the
crc_calculated argument
is non-zero the packet's crc fields are filled in.The return code is one
of:
typedef enum {
/* Values defined in the FireWire specification */
Firewire_Ack_Complete = 1,
Firewire_Ack_Pending = 2,
Firewire_Ack_Busy_X = 4,
Firewire_Ack_Busy_A = 5,
Firewire_Ack_Busy_B = 6,
Firewire_Ack_Tardy = 0xb,
Firewire_Ack_Conflict_Error = 0xc,
Firewire_Ack_Data_Error = 0xd,
Firewire_Ack_Type_Error = 0xe,
Firewire_Ack_Address_Error = 0xf,
/* Values not defined in FireWire but used in Simics */
Firewire_Ack_No_Destination = 0x10, /* no destination found */
Firewire_Ack_No_Ack = 0x11 /* no ack signal sent for packet */
} firewire_ack_code_t;
register_channel can be called to tell the bus that the device
want to receive isochronous transfers to channel channel.
channel must be in the range [0, 63).
A device can register several channels. It is an error to subscribe a
device to a channel it is already subscribed to.
Returns 0 on success.
unregister_channel tells the bus the device is no longer
interested in transfers to channel channel. channel must be
in the range [0, 63). It is an error to unsubscribe a device from a channel
if it isn't subscribing to it. Returns 0 on success.
reset can be called to cause a bus reset. After the bus reset,
all the devices may have received new IDs.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(firewire_device) {
firewire_ack_code_t (*transfer)(conf_object_t *NOTNULL dev,
dbuffer_t *packet, int crc_calculated);
void (*reset)(conf_object_t *NOTNULL dev, uint16 id,
uint8 root_id,
uint32_array_t self_ids);
uint32 (*get_self_id_template)(
conf_object_t *NOTNULL dev);
int (*get_rhb)(conf_object_t *NOTNULL dev);
uint8 (*get_port_count)(conf_object_t *NOTNULL dev);
uint16 (*get_port_mask)(conf_object_t *NOTNULL dev);
};
#define FIREWIRE_DEVICE_INTERFACE "firewire_device"
This interface must be implemented by all firewire devices.
transfer is called when the device receives a packet.
If the crc_calculated argument
is non-zero the packet's crc fields are filled in.The return code is one
of:
typedef enum {
/* Values defined in the FireWire specification */
Firewire_Ack_Complete = 1,
Firewire_Ack_Pending = 2,
Firewire_Ack_Busy_X = 4,
Firewire_Ack_Busy_A = 5,
Firewire_Ack_Busy_B = 6,
Firewire_Ack_Tardy = 0xb,
Firewire_Ack_Conflict_Error = 0xc,
Firewire_Ack_Data_Error = 0xd,
Firewire_Ack_Type_Error = 0xe,
Firewire_Ack_Address_Error = 0xf,
/* Values not defined in FireWire but used in Simics */
Firewire_Ack_No_Destination = 0x10, /* no destination found */
Firewire_Ack_No_Ack = 0x11 /* no ack signal sent for packet */
} firewire_ack_code_t;
reset is called when the bus is reset. id is
the new ID of the device (top 10 bits represent the bus number, and the low
6 bits the node ID). root_id is the node ID for the root
node. self_ids is the list of Self-ID packets
during the Self-ID phase of the reset.
An array of unsigned 32-bit integers.
typedef struct {
size_t len;
uint32 *data;
} uint32_array_t;
get_self_id_template is an accessor function called by the bus
or other self-ID provider to provide the static parts of the Self-ID for
this device. The ID and port parts will be overwritten by the Self-ID
provider.
get_rhb gets the current status of the root hold off bit in the
device.
get_port_count returns the number of ports the device has. The
largest allowed value is 16 and the lowest 1. This should remain constant
during the lifetime of the device and always return a valid value.
get_port_mask returns a bitmask. Each bit is one if that port is
enabled and zero if it is disabled. The least significant bit describes port
0 and the most significant bit port 15. The bits for ports which do not
exist on the device should be set to zero.
- Execution Context
- Cell Context for all methods.
- Description
- The
fmn_station_control interface is implemented by
Fast Messaging Network stations for processors prior to the XLP II.
For all functions, the thread_id parameter denotes
the thread id for the core that invokes the call.
The send_message function notifies the station to
initiate a message send on the FMN. The rt_value
parameter carries control bits and the message to send; its content
and bit layout is determined by the system architecture. The return
value indicates whether the FMN station is able to send the message.
The station must check for available resources and immediately return
1 if the message will be queued for delivery, otherwise, if
the station is not ready or if no buffers are available, the station
immediately returns 0.
The load_message function notifies the station
to initiate a message load on the FMN. The bucket
indicates the FMN station bucket to read from.
The wait function is used by the core to probe the
station if it should put itself to sleep waiting for a message or
not. Each bit in the vector corresponds to a bucket
to check for messages, i.e. bit 0 corresponds to bucket 0. The
station must return 0 if there are any messages in any of
the buckets requested. The station must return 1 if there
are no messages in any of the buckets. Returning 1 means
that the core can go to sleep until the station wakes the core. The
station must later send a wake signal to the core when a new
message arrive to any of the buckets checked in the last call to
wait. The station wakes the core by raising the signal
on the wakeup port interface for the core.
The sync function enforces a hazard barrier across
the send_message function executions, thereby enforcing
a strict ordering of the message sequence delivered to the FMN.
SIM_INTERFACE(fmn_station_control) {
uint64 (*send_message)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint64 rt_value);
void (*load_message)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint8 bucket);
int (*wait)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint8 vector);
void (*sync)(conf_object_t *NOTNULL obj,
uint32 thread_id);
};
#define FMN_STATION_CONTROL_INTERFACE "fmn_station_control"
- Execution Context
- Cell Context for all methods.
- Description
- The
fmn_station_control_v2 interface is implemented by Fast
Messaging Network stations for the XLP II processor.
For all functions, the thread_id parameter denotes the thread
id for the core that invokes the call.
The send_message function is called when the processor executes
the msgsnd instruction. The rt_value parameter
contains the value of the rt register. The function must return
the value to be written into the rd register.
The load_message function is called when the processor executes
the msgld instruction. The rt_value parameter
contains the value of the rt register. The function must return
the value to be written into the rd register.
The wait function is called when the processor executes the
msgwait instruction. The rt_value parameter contains
the value of the rt register. The function should return 1
if the receive queues are empty, 0 if not. If the receive queues
are empty the station must wake the thread by raising the signal on the
wakeup port of the thread when the next message arrives to one of
the receive queues.
The sync function is called when the processor executes the
msgsync instruction.
SIM_INTERFACE(fmn_station_control_v2) {
uint64 (*send_message)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint64 rt_value);
uint64 (*load_message)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint64 rt_value);
int (*wait)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint64 rt_value);
void (*sync)(conf_object_t *NOTNULL obj,
uint32 thread_id);
};
#define FMN_STATION_CONTROL_V2_INTERFACE "fmn_station_control_v2"
- Execution Context
- Cell Context for all methods.
- Description
- The
frequency interface is used to publish
a frequency to other objects.
The get method returns the current frequency.
The object implementing this interface is expected to implement
the Sim_Notify_Frequency_Change notifier, which should be
raised when the object changes its frequency. Objects subscribing
to this notifier can acquire the new frequency by doing a new call
to the get method.
SIM_INTERFACE(frequency) {
double (*get)(conf_object_t *NOTNULL obj);
};
#define FREQUENCY_INTERFACE "frequency"
- Execution Context
- Cell Context for all methods.
- Description
- The
frequency_listener interface is used for
modeling frequency changes.
The frequency change initiator should call set() to set the
new frequency. The set() function may be called multiple times
with the same frequency value. The frequency is specified by the
numerator and denominator arguments in units of Hz.
The set() function should also be used to set the initial
value for a target.
An object that implements the frequency_listener
interface typically has an attribute that refers to an object and
port that implements the simple_dispatcher
interface, from where the frequency originates.
The initiator of a frequency change should implement the
simple_dispatcher interface, and it should only call
the set() function on objects that have registered with
this interface.
SIM_INTERFACE(frequency_listener) {
void (*set)(conf_object_t *NOTNULL obj, uint64 numerator,
uint64 denominator);
};
#define FREQUENCY_LISTENER_INTERFACE "frequency_listener"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(generic_message_device) {
void (*receive_frame)(conf_object_t *dev, conf_object_t *link,
dbuffer_t *frame);
};
#define GENERIC_MESSAGE_DEVICE_INTERFACE "generic_message_device"
This interface is implemented by generic message device objects that connect
to generic-message-link objects. It is used by the link
object to send messages to the device object. The link should implement the
generic_message_link interface.
The receive_frame function is called by the link to send a frame
to the device. The frame is passed as a dbuffer_t
pointer that may not be modified without cloning it first.
- Execution Context
| receive_frame | Cell Context |
- Description
SIM_INTERFACE(generic_message_link) {
#ifndef PYWRAP
int (*connect_device)(conf_object_t *_obj, conf_object_t *dev,
int *new_connection, uint32 address);
void (*disconnect_device)(conf_object_t *_obj, conf_object_t *dev);
#endif
void (*send_frame)(conf_object_t *_obj, int id, uint32 address,
dbuffer_t *frame, nano_secs_t delay);
};
#define GENERIC_MESSAGE_LINK_INTERFACE "generic_message_link"
Note:
This interface is used for gml-link which is based on the link library.
Refer to the Link Library for more information.
This interface is implemented by generic message link objects that provide a
data link layer interface for frame delivery. It is used by the device
object to talk to the link object. The device must implement the
generic_message_device interface.
The connect_device function attaches a generic link device to the
link. The return value is an identification number that should be used
in subsequent calls to the link to identify the device. The
address parameter sets the address of the device on the link.
Currently the new_connection parameter is not in use, a NULL
pointer can be passed as the parameter.
The disconnect_device function detaches a generic link
device from the link. It will not receive any more frames from the
link and may not call any functions in the interface, except
connect_device.
The send_frame function is used by a device to send a generic
device frame onto the link to be delivered to another device connected to
the same link. The frame should be a dbuffer_t
containing a data frame. The address parameter is the address
to sent the frame to. The delay makes it possible to add a
small delay to the frame. This can be used when a device wants to send
multiple frames at once, but want them to be delivered in a specific
sequence. Instead of using an event handler to send each frame, they can be
sent at once, with an increasing delay for each frame. The delay is given in
nanoseconds.
- Execution Context
| connect_device | Global Context |
| disconnect_device | Global Context |
| send_frame | Cell Context |
- Description
- This interface defines HPI, Host Port Interface, which can be
used by a host to access the DSP memory space. The access
functions have been designed to resemble the HPI hardware interface.
The interface consists of three read/write access functions;
read/write_hpic() accesses the HPI controller
register. Typically the host uses write_hpic()
to clear the HINT bit (writing a one to the bit) when the
interrupt has been serviced.
The read/write_hpia() functions are used to read
or set the address to the memory location which should be later
read or written. Reading HPIA either returns HPIAR or HPIAW
depending on if last access to HPID was a read or write.
Setting HPIA sets both HPIAR and HPIAW.
Finally, to access the memory the read/write_hpid()
functions are used. These functions have a autoincrement flag
allowing the HPIAR or HPIAW to automatically increment the
value with 4 after the access is finished.
All access functions assumes that the registers and data are
represented in host endianness.
SIM_INTERFACE(hpi) {
/* HCNTL = 0 */
uint32 (*read_hpic)(conf_object_t *obj);
void (*write_hpic)(conf_object_t *obj, uint32 value);
/* HCNTL = 1 */
uint32 (*read_hpia)(conf_object_t *obj);
void (*write_hpia)(conf_object_t *obj, uint32 value);
/* HCNTL = 1 (autoincrement == 0) */
/* HCNTL = 2 (autoincrement == 1) */
uint32 (*read_hpid)(conf_object_t *obj, int autoincrement);
void (*write_hpid)(conf_object_t *obj, uint32 value,
int autoincrement);
};
#define HPI_INTERFACE "hpi"
- Execution Context
- Cell Context for all methods.
- Description
typedef enum {
I2C_ack = 0,
I2C_noack = 1
} i2c_ack_t;
SIM_INTERFACE(i2c_master_v2) {
void (*acknowledge)(conf_object_t *device, i2c_ack_t ack);
void (*read_response)(conf_object_t *device, uint8 value);
};
#define I2C_MASTER_V2_INTERFACE "i2c_master_v2"
The i2c_master_v2 interface should be implemented
by devices that intend to act as a master on an I2C link.
The function acknowledge is called in response to a
start or write call in the
i2c_slave_v2 interface of the slave device.
read_response is called as response to a
read call. More details can be found in the
documentation of the i2c_slave_v2 interface.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i2c_slave_v2) {
void (*start)(conf_object_t *device, uint8 address);
void (*read)(conf_object_t *device);
void (*write)(conf_object_t *device, uint8 value);
void (*stop)(conf_object_t *device);
attr_value_t (*addresses)(conf_object_t *device);
};
#define I2C_SLAVE_V2_INTERFACE "i2c_slave_v2"
The i2c_slave_v2 interface is used together with the i2c_master_v2
interface to model communication over an I2C bus. Most calls to a method in
the i2c_slave_v2 interface expect a response call to a method
in the i2c_master_v2 interface. It is up to each device to
find the caller's interface; usually it is configured with an attribute in
both the master and slave device.
The i2c_slave_v2 and i2c_master_v2 interfaces
replace the obsolete interfaces i2c_master,
i2c_slave, i2c_link, and
i2c_bridge.
An I2C bus consists of a number of master devices and a number of
slave devices. Each slave device listens to one or more 7-bit
addresses or 10-bit addresses. It is an error to connect two
slave devices to the same bus if they listen to the same address.
Communication over the bus is initiated by a master, which can communicate
with one slave device at a time. Only one master on a bus can communicate
at a time.
Two I2C devices can communicate directly if one implements the
i2c_master_v2 interface and the other one implements the
i2c_slave_v2 interface. An I2C bus with multiple masters or
slaves is typically modeled using an i2c-link-v2 object,
where each device is connected to an endpoint object.
The start method starts a transfer. The
address parameter is the address of the slave device, encoded
as an 8-bit number. To communicate with 7-bit address slave device, using
little-endian bit numbering, bit 0 is a read/write bit (0 → master
writes, 1 → master reads) and bits 1 to 7 is the 7-bit address of
the slave device. The address parameter should normally
be in the (inclusive) range 0x10 - 0xef; the ranges 0x00 -
0x0f and 0xf0 - 0xff are reserved for special addressing modes.
To communicate with 10-bit address slave device, using little-endian bit
numbering, bit 0 is a read/write bit (same as 7-bit address), bits 1 to 2
is part of 10-bit address, and bits 3 to 7 is 10-bit address mode 0b11110.
The slave responds to start using the
acknowledge method. The ack parameter may be
I2C_ack or I2C_noack if the start is acked
or noacked, respectively. In a multi-master configuration, the slave may
instead respond by calling the start method in the
i2c_slave_v2 interface of the master device; this signals
that the master lost the bus arbitration. This is discussed further below.
If a start was acked by a slave device, read/write bit in the
start method was 1, the master proceeds with a sequence
of read calls. Each call is followed by a
read_response call from the slave. If the read/write bit in
the start was 0, the master instead proceeds with a
sequence of write calls, each one followed by an
acknowledge call. The ack parameter of the
acknowledge method may be either I2C_ack or
I2C_noack, representing ack and noack, respectively.
After sending a number of reads or writes, the master may choose to
either call the stop method to issue a stop condition
which terminates the transfer, or to call the start
method again to issue a repeated start condition. The repeated
start condition works like a normal start condition.
When 0 is passed as the address parameter of the
start method, a General Call transfer is initiated. A
General Call transfer works like a normal write transfer, except that
multiple slave devices may acknowledge the start and write requests. The
master will conceive a request as acknowledged if it was acknowledged by at
least one of the slaves.
When 10-bit address pattern is passed as the address
parameter of the start method, a 10-bit address
transaction is initiated. A 10-bit address transaction begins with write
status (read/write bit should be 0). As mentioned before, bits 1 to 2 are
the most significant bits of 10-bit address. Then following is a call
to the write method with the last 8 bits of 10-bit address.
If the transaction is slave-receiver, the next transfer works like a
normal write transfer. If the transaction is slave-transmitter, then
the start method is called again with the same address pattern
as before, but with bit 0 (the read/write bit) set to 1. This is followed
by calls to read like in a normal read transaction.
The addresses method is used to retrieve the set of addresses a
device currently listens to. The method is called by the
i2c-link-v2 to provide an overview of the bus topology, and
to detect address collisions early. The method may not have any
side-effects on the simulation. The return value is a list containing all
the different values of the address parameter in a
start call that the slave would respond to with
I2C_ack. The list may also contain an element
Nil to mark that the device might respond to other addresses as
well. If a device is configured to listen to a specific address but is
currently disabled, then that address may still be included in the list.
For example, if a slave device listens to the single 7-bit address
0x55, the return value of addresses would be
[0xaa, 0xab], using Python list syntax.
The specification of the return value may be extended in the future, to
allow other values than Nil and 8-bit integers. Therefore, callers
should not make any assumptions on how the elements are formatted in the
return value.
For most I2C devices it is sufficient to implement only one of the
i2c_slave_v2 and i2c_master_v2 interfaces. In
some cases it may be useful for a device to implement both interfaces,
either because the device can act both as a master and as a slave on the
bus, or because it needs to use the start and
stop methods to monitor start and stop conditions on the bus.
I2C link endpoints also implement both interfaces.
If multiple master devices are connected to the same i2c link, then all
master devices need to implement the i2c_slave_v2 interface
in addition to i2c_master_v2, in order to handle bus
arbitration correctly:
- A master device should monitor calls to the start and
stop functions: After a call to start in a master
device, the master should not call start in the slave until
after a subsequent call to stop in the master.
- When a master calls start in a link endpoint device, the
endpoint may respond with a call to start instead of
acknowledge; this means that there was bus arbitration, which
the master lost to the given start request. Note that this
case can not happen on a latency-free connection, since all arbitration is
handled by the master's monitoring of start and stop
calls. Note also that user-written slave devices are required to respond
with acknowledge to a start call; only the i2c link
endpoint (and other i2c infrastructure objects from the Simics-Base
package) are allowed to respond with a start call.
Note that there is no need for a master device to implement the
i2c_slave_v2 interface if the device only will be used in
single-master configurations.
The start, write and read methods in the
i2c_slave_v2 interface are allowed to respond synchronously;
i.e., the acknowledge or read_response method may be
called before the corresponding method in the slave interface has returned.
A master that needs to connect directly to a slave device needs to take this
into consideration; however, when communicating via an
i2c-link-v2 object, the link guarantees that all responses
are asynchronous.
- Execution Context
addresses | Global Context |
| All other methods | Cell Context |
- Description
SIM_INTERFACE(i3c_daa_snoop) {
void (*assigned_address)(conf_object_t *obj, uint64 id,
uint8 bcr, uint8 dcr, uint8 address);
};
#define I3C_DAA_SNOOP_INTERFACE "i3c_daa_snoop"
During DAA process, the assigned address information will be monitored
to devices who implement the interface i3c_daa_snoop.
Whenever an address is assigned to a slave, the method
assigned_address is called in all devices that implement the
interface. The parameter id, bcr and
dcr in method assigned_address is slave specific
daa data which indicates who gets the assigned address. Parameter
address stores the assigned address. The 7-bit address
is represented as 8-bit number with the highest bit set to 0.
Interface i3c_daa_snoop is mainly implemented by slave who
may become secondary master later and needs to know the information about
slave addresses.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i3c_hdr_master) {
void (*hdr_read_response)(conf_object_t *obj, bytes_t bytes, bool more);
void (*hdr_acknowledge)(conf_object_t *obj, i3c_ack_t ack);
};
#define I3C_HDR_MASTER_INTERFACE "i3c_hdr_master"
The interfaces i3c_hdr_slave and i3c_hdr_master
are used together to model I3C HDR communication over the bus.
HDR modes are entered by sending one of the ENTHDRx broadcast CCCs on the bus
through normal SDR communication.
Slaves that support HDR shall now internally switch to HDR mode.
The master can exit HDR mode by calling hdr_exit in
the i3c_hdr_slave interface and
then follow it with a stop call. All slaves that support HDR
shall now internally switch back to SDR mode.
All write transfers in HDR mode are done using the hdr_write
method. Slaves must always respond through method hdr_acknowledge
to either ACK or NACK the write. Devices not supporting active acknowledgement
for a certain write transfer block must always respond with an ACK as it
represents a passive acknowledgement according to MIPI I3C V1.1.1 spec.
All read transfers in HDR mode are done using the hdr_read method.
Parameter max_len in method hdr_read is the maximum
number of bytes that the slave is allowed to send in response.
The slave shall respond with an hdr_read_response
call after each hdr_read call. The parameter more
indicates if the slave has more data to send.
The slave is allowed to send back less than max_len and at the same time
set more to true. This feature is an optimization in order to:
1. Minimize the number of hdr_read calls needed to read a large amount of data.
2. Avoid underflow on the slave side by allowing the slave respond with less data.
If more is set to false, the master has to ends it current transfer
by either calling hdr_restart or exit HDR through the procedure described above.
Examples of HDR write transactions:
The sequence of hdr_write calls could be made differently. Master can send smaller or larger
chunks of data in each hdr_write call. The main concerns are to minimize the number
of interface calls and to avoid overflow on the slave side. A balance between the
two should be considered in the implementation of the master.
The sequence of hdr_read calls could be made differently. Master can read smaller
chunks of data in each hdr_read call. The main concerns are to minimize the number
of interface calls and to avoid underflow on the slave side. A balance between the
two should be considered in the implementation of the master.
Note: This interface is in tech-preview and may change without
notice.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i3c_hdr_slave) {
void (*hdr_write)(conf_object_t *obj, bytes_t data);
void (*hdr_read)(conf_object_t *obj, uint32 max_len);
void (*hdr_restart)(conf_object_t *obj);
void (*hdr_exit)(conf_object_t *obj);
};
#define I3C_HDR_SLAVE_INTERFACE "i3c_hdr_slave"
- Execution Context
- Cell Context for all methods.
- Description
typedef enum {
I3C_ack = 0,
I3C_noack
} i3c_ack_t;
SIM_INTERFACE(i3c_master) {
void (*acknowledge)(conf_object_t *obj, i3c_ack_t ack);
void (*read_response)(conf_object_t *obj, uint8 value, bool more);
void (*daa_response)(conf_object_t *obj,
uint64 id, uint8 bcr, uint8 dcr);
void (*ibi_request)(conf_object_t *obj);
void (*ibi_address)(conf_object_t *obj, uint8 address);
};
#define I3C_MASTER_INTERFACE "i3c_master"
The interfaces i3c_master i3c_slave
and i3c_daa_snoop are used together to model
communication over an I3C bus.
There are four kinds of devices roles on the I3C bus: Main Master,
Secondary Master, Slave and Legacy I2C Slave. Exactly one device
must be the Main Master; this is typically configured statically.
Main Master should implement the i3c_master interface,
while slave should implement the i3c_slave interface.
Secondary Master should implement both.
Most calls to a method in the slave device interfaces expect a response
call to a method in the master device interfaces. One exception is the
method sdr_write in the i3c_slave interface, master
expects no response when calling it.
It is up to each device to find the caller's interfaces; usually it is
configured with attributes in both the master and slave device.
Two I3C devices can communicate directly if one implements the
i3c_master interface and the other one implements the
i3c_slave interface. An I3C bus with multiple masters
or slaves is typically modelled using an i3c-link object,
where each device is connected to an endpoint object.
An I3C bus consists of a number of master devices and a number
of slave devices. Each I3C slave device listens to one or more
7-bit addresses. The slave devices can be I3C slave devices or
Legacy I2C slave devices. This is because I3C protocol is compatible with
I2C protocol, so that I3C master device can communicate with I2C slave
devices.
For legacy I2C slave device, the address it listens to is
pre-configured by the device, i.e. static address. For I3C slave device,
the address it listens to can be either static address or dynamic address.
The dynamic address is assigned by master during Dynamic Address Assignment
process. It is an error to connect two slave devices to the same
bus if they listen to the same address.
In a communication, the Current Master refers to the device who now drives
the bus. It can be Main Master, or Secondary Master.
Usually, communication over the bus is initiated by the Current Master,
which can communicate with one or more slave devices at a time.
A slave device can request to initiate an communication, i.e., issue
an ibi_request, in three cases:
Hot-Join, In-Band Interrupt and as a Secondary Master other than the
Current Master requesting to become Current Master.
Only one device on a bus can communicate at a time.
The start method starts a transfer. The address
parameter is the address header combined with read/write bit encoded as an
8-bit number. The least significant bit is the read/write bit and the other
bits is the 7-bit address header.
If the start method is called from master, the address header
can be address pattern 0x7E for broadcast, or specific slave address (either
I2C slave static address or I3C slave dynamic address).
In I3C bus or link implementation, every start request will broadcast to
all other devices. So does the stop request. This will monitor bus/link
status to all devices.
Normally, master starts a transfer, then the slave responds to
start using the acknowledge method (implemented by
master side interface). The ack parameter may be
I3C_ack or I3C_noack if the start is acked or
noacked, respectively.
There are five types of different start requests:
- I3C master read transaction
- If a master's start with specific slave address was acked by other
device, and read/write bit in the address parameter of
the start method was 1, then master proceeds with a sequence
of read calls. Each call is followed by a read_response
call from the slave. Parameter data in the method
read_response is the data transferred. The procedure is no
difference with regard to read from I3C slave or read from I2C slave.
In hardware, the ACK/T bit is handled differently for i2c and i3c, and
the master is supposed to know whether the slave is an i2c or i3c device.
In the i3c case, the slave is supposed to pass the T bit in the
more argument of read_response, while an i2c
device always passes more as true. Further more, in the
i2c case, a master sends an ACK bit, which is not represented explicitly
in the interface. The value of this bit can be deduced from whether the
following operation is START/STOP or READ. For i3c case, parameter
more in method read_response indicates if
there are still data waiting to be transferred from slave to master.
more is true when there are still data left, false otherwise.
- I3C master write transaction (write to I3C slave)
- If a master's start with specific slave address was acked by other
device, and the read/write bit in the address parameter
of start method was 0, the master proceeds with a
sdr_write call, no response is expected. Parameter
data in method write is the data transferred.
The parity bit is not passed explicitly in sdr_write, and that the slave
can assume the parity bit is correctly set.
- I3C master write transaction (write to I2C slave)
- When the master's start request is to write to I2C slave, i.e.,
master issues a start request to I2C slave address with read/write bit
is 0, then master proceeds with a sequence of write calls,
each call expects a response call to a method acknowledge.
This is quite similar to I2C write transaction.
- I3C broadcast transaction
- When master starts a transfer with I3C Broadcast Address 0x7E which
is passed as address header, i.e., address 0xFC passed in the
address argument of method start, a typical
I3C message transfer is initiated.
Multiple I3C slave devices may acknowledge the start request. The master
will conceive a request as being acknowledged if it was acknowledged by
at least one of the slaves. Note that there will be a single
acknowledge call in the master; the link or bus handles
aggregation of acks.
Master sends the I3C Commands (Common Command Code, CCC) using
sdr_write method after receiving ACK, showing to communicate
with either all Slaves (Broadcast CCCs) or specific individual Slaves
(Direct CCCs). This operation expects no response, and master will proceed.
If Broadcast CCC sent previously, master calls sdr_write method
to transfer data to all slaves who acked the initial access.
- I3C direct transaction
- After sending a Direct CCC, master continues with a repeated start
request along with one specific I3C slave address. The transaction goes
on just like master is communicating with only one slave. After the
communication with one slave, master may be issue a repeated start request
to another slave. Further communication is routed only to the targeted
slave device.
After sending a number of reads or a number of writes, the master may
choose to either call the stop method to issue a stop
condition which terminates the transfer, or to call the start
method again to issue a repeated start condition. The repeated start
condition works like a normal start condition.
The start method and read method in the slave
interfaces are allowed to respond synchronously; i.e., the
acknowledge or read method may be called before the
corresponding method in the slave interfaces has returned. A master that
needs to connect directly to a slave device needs to take this into
consideration; however, when communicating via an i3c-link
object, the link guarantees that all responses are asynchronous.
The method daa_read and method daa_response are used
in Dynamic Address Assignment process.
Method daa_read is called from master to signal a daa read request.
Method daa_response is called from slave to send slave specific
8-bytes data (48-bit Unique ID, BCR, DCR) to master. The parameter
id, bcr and dcr in method
daa_response represent the slave specific daa data.
If multiple slaves response daa data, the slave with the lowest data wins
and it will get the assigned address this time.
Master calls method write in slave interfaces to send assigned
dynamic address to the slave who wins. This operation expects a response
call to method acknowledge in master side. Parameter
data in method write stores the assigned address.
Master should implement the method stop in the interface
i3c_slave in case there is secondary master in the
configuration which may issue start request.
Slave can request to start a communication through ibi_request.
The request is sent to Current Master which drives the bus now.
If the master chooses to continue the slave request, ibi_start
is called, this ibi start will broadcast to all devices in the configuration.
Then slave can send its address header with ibi_address
argument address. The address header can be 0x02 for Hot-Join,
or the address of the slave itself for IBI and secondary master with
read/write bit 1 and 0 respectively.
If more than one slave issues ibi_address, arbitration occurs,
the slave with lowest address header wins and the winning address will be
delivered to master by link or bus.
At that time, master issues ibi_acknowledge to the slave who wins.
Other slaves which do not receive ibi_acknowledge will consume it
lost arbitration already.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i3c_slave) {
void (*start)(conf_object_t *obj, uint8 address);
void (*write)(conf_object_t *obj, uint8 value);
void (*sdr_write)(conf_object_t *obj, bytes_t data);
void (*read)(conf_object_t *obj);
void (*daa_read)(conf_object_t *obj);
void (*stop)(conf_object_t *obj);
void (*ibi_start)(conf_object_t *obj);
void (*ibi_acknowledge)(conf_object_t *obj, i3c_ack_t ack);
};
#define I3C_SLAVE_INTERFACE "i3c_slave"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i8051_interrupt) {
int (*active_interrupt)(conf_object_t *NOTNULL obj);
void (*reti)(conf_object_t *NOTNULL obj);
bool (*suppress_irq)(conf_object_t *NOTNULL obj, uint32 addr);
};
#define I8051_INTERRUPT_INTERFACE "i8051_interrupt"
The active_interrupt() function returns the interrupt vector
address of the highest pending interrupt. This function should only be
called when the processor should take an interrupt. This function may also
set internal interrupt controller state, which can be cleared by the
reti function call when returning from the interrupt.
The reti function is used to notify the interrupt controller that
the currently active interrupt has completed.
The suppress_irq function is used to determine whether interrupt
should be blocked after a writing access to a memory location.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(i8051_timer) {
void (*change_mode)(conf_object_t *NOTNULL obj, uint8 mode);
void (*switch_timer)(conf_object_t *obj, uint8 caller, bool onoff);
};
#define I8051_TIMER_INTERFACE "i8051_timer"
The change_mode function is used to change the working mode (e.g.
16bit timer, 8 bit timer or event counting etc.)
of the timer.
The switch_timer function is used to enable or disable
the timer. Timers can be switched on or off by either software or hardware.
The parameter caller is either 0 or 1, indicating the control
is from software or hardware. Only when the timer is switched on or off
by hardware, the third parameter onoff is used, which indicates
whether the timer is to be enabled or disabled.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(ieee_802_15_4_control) {
void (*set_rssi)(conf_object_t *NOTNULL obj,
uint64 tgt_ep_id,
uint32 rssi);
void (*remove_rssi)(conf_object_t *NOTNULL obj,
uint64 tgt_ep_id);
void (*clear_all_rssi)(conf_object_t *NOTNULL obj);
};
#define IEEE_802_15_4_CONTROL_INTERFACE "ieee_802_15_4_control"
The ieee_802_15_4_control interface is implemented by the
IEEE 802.15.4 link endpoint objects that provide a interface for endpoint
configuration. Simics command (Python program) calls set_rssi,
remove_rssi and clear_all_rssi to update
the RSSI table.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(ieee_802_15_4_link) {
ieee_802_15_4_transmit_status_t (*transmit)(
conf_object_t *NOTNULL obj,
const frags_t *frame,
uint16 channel_page,
uint16 channel_number,
ieee_802_15_4_frame_crc_status_t crc_status);
};
#define IEEE_802_15_4_LINK_INTERFACE "ieee_802_15_4_link"
The ieee_802_15_4_link interface is implemented by the IEEE
802.15.4 link endpoint objects that provide an interface for frame traffic.
Transceiver calls transmit to send out frames. The return value
is using one of the values in the
ieee_802_15_4_transmit_status_t enum:
IEEE_802_15_4_Transmit_No_Error means that the frame was
sent out without error.
IEEE_802_15_4_Transmit_Channel_Contention means that there
was collision and the frame was not sent out.
IEEE_802_15_4_Transmit_Data_Corruption means that the
endpoint detected CRC mismatch and didn't send out the frame.
typedef enum {
IEEE_802_15_4_Transmit_No_Error = 0,
IEEE_802_15_4_Transmit_Channel_Contention,
IEEE_802_15_4_Transmit_Data_Corruption
} ieee_802_15_4_transmit_status_t;
The crc_status parameter provides out-of-band information on
the contents of the frame with regards to the CRC field using one of the
values in the ieee_802_15_4_frame_crc_status_t enum:
IEEE_802_15_4_Frame_CRC_Match means that to the link that,
regardless of the actual contents of the CRC field in frame, the CRC is
considered matching the frame contents.
IEEE_802_15_4_Frame_CRC_Mismatch means that the CRC field
and the frame contents do not agree. Just like the Ethernet links, the
endpoint does not really send out the packet in this case.
IEEE_802_15_4_Frame_CRC16_Unknown/IEEE_802_15_4_Frame_CRC32_Unknown
means that the link to compute the CRC and compare it with
FCS (Frame Check Sequence) of the MAC frame. If the CRC field and frame
contents do not agree, the endpoint does not send out the packet.
IEEE_802_15_4_Frame_CRC32_Unknown is for 802.15.4g only.
typedef enum {
IEEE_802_15_4_Frame_CRC_Match = 0,
IEEE_802_15_4_Frame_CRC_Mismatch,
IEEE_802_15_4_Frame_CRC16_Unknown,
IEEE_802_15_4_Frame_CRC32_Unknown,
} ieee_802_15_4_frame_crc_status_t;
The frequency channels are defined through a combination of channel numbers
and channel pages. Channel page is a concept added to IEEE 802.15.4 in 2006
to distinguish between supported PHYs. Both channel page and channel number
must match on source and target sides for successful transmission.
- Execution Context
- Cell Context for all methods.
- Description
typedef void (*ieee_802_15_4_probe_snoop_t)(
lang_void *user_data,
conf_object_t *probe,
ieee_802_15_4_probe_side_t to_side,
const frags_t *frame,
uint32 rssi,
uint16 channel_page,
uint16 channel_number,
ieee_802_15_4_frame_crc_status_t crc_status);
IEEE_802_15_4_Probe_Port_A means that the frame is
from device to link.
IEEE_802_15_4_Probe_Port_B means that the frame is
from link to device.
typedef enum {
IEEE_802_15_4_Probe_Port_A = 0,
IEEE_802_15_4_Probe_Port_B = 1
} ieee_802_15_4_probe_side_t;
SIM_INTERFACE(ieee_802_15_4_probe) {
void (*attach_snooper)(conf_object_t *NOTNULL probe,
ieee_802_15_4_probe_snoop_t snoop_fun,
lang_void *user_data);
void (*detach)(conf_object_t *NOTNULL probe);
};
#define IEEE_802_15_4_PROBE_INTERFACE "ieee_802_15_4_probe"
The ieee_802_15_4_probe interface is implemented by the
IEEE 802.15.4 probe devices that provide an interface for Simics users to
register their own callback to listen to the traffic going-on in the probe.
The attach_snooper attaches a snooper function. The probe will
pass each frame to the snooper function, then forward it unchanged where it
should be going.
The detach detaches the currently registered callback from
the probe.
This interface should only be used for inspection, and never as part of
the actual simulation. The snoop functions must not affect the simulation
in any way.
The user_data parameter is passed to the snoop function every time
it is called.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(ieee_802_15_4_receiver) {
void (*receive)(conf_object_t *NOTNULL obj,
const frags_t *frame,
uint32 rssi,
uint16 channel_page,
uint16 channel_number,
ieee_802_15_4_frame_crc_status_t crc_status);
void (*frame_lost)(conf_object_t *NOTNULL obj,
uint32 rssi,
uint16 channel_page,
uint16 channel_number);
};
#define IEEE_802_15_4_RECEIVER_INTERFACE "ieee_802_15_4_receiver"
The ieee_802_15_4_receiver interface is implemented by the
IEEE 802.15.4 transceivers that provide an interface for traffic.
Endpoints call receive to deliver a frame to transceiver.
Transceiver should check if the received frame from endpoint is in the
channel that it is using. The channel being used is defined by channel_page
and channel_number.
Endpoints call frame_lost to notify transceivers on that a frame
was lost because of low RSSI value.
- Execution Context
- Cell Context for all methods.
- Description
#define IEEE_802_3_MAC_INTERFACE "ieee_802_3_mac"
SIM_INTERFACE(ieee_802_3_mac) {
int (*receive_frame)(conf_object_t *obj, int phy,
dbuffer_t *buf, int crc_ok);
void (*tx_bandwidth_available)(conf_object_t *obj, int phy);
void (*link_status_changed)(conf_object_t *obj, int phy,
ieee_802_3_link_status_t status);
};
typedef enum {
IEEE_link_unconnected,
IEEE_link_down,
IEEE_link_up
} ieee_802_3_link_status_t;
Deprecated; use ieee_802_3_mac_v3 instead.
Interface that should be implemented by 802.3 media access control layers.
The receive_frame function is called when a frame has
been received by the phy. The frame is passed as a
dbuffer_t that may not be modified without
cloning it first. The return value have no meaning, callers should
ignore it, and new implementations should return 0.
The tx_bandwidth_available is called by the PHY when a
previous call to send_frame or check_tx_bandwidth
in the ieee_802_3_phy interface have returned no bandwidth
available.
link_status_changed is called when the phy detects a change
of the link status.
The phy parameter is a number that identifies this particular
PHY, in configurations with several PHYs connected to the same MAC.
- Execution Context
- Cell Context for all methods.
- Description
#define IEEE_802_3_MAC_V3_INTERFACE "ieee_802_3_mac_v3"
SIM_INTERFACE(ieee_802_3_mac_v3) {
void (*receive_frame)(
conf_object_t *obj, int phy, const frags_t *frame, int crc_ok);
void (*tx_bandwidth_available)(conf_object_t *obj, int phy);
void (*link_status_changed)(
conf_object_t *obj, int phy, ieee_802_3_link_status_t status);
};
typedef enum {
IEEE_link_unconnected,
IEEE_link_down,
IEEE_link_up
} ieee_802_3_link_status_t;
Interface that should be implemented by 802.3 media access control layers.
The receive_frame function is called when a frame has been
received by the phy. The frame is passed as a
frags_t that must not be modified.
The crc_ok flag is set to indicate that the frame is valid
with regards to CRC calculations. If the crc_ok flag is not
set, the frame is considered invalid. Note that in general,
crc_ok does not indicate whether or not the CRC field in the
frame can be relied upon, or whether its computation has been skipped to
improve simulation performance. When using new-style links,
crc_ok set to false indicates that the CRC field contains
valid information that is not matching with the frame contents.
The tx_bandwidth_available is called by the PHY when a
previous call to send_frame or check_tx_bandwidth
in the ieee_802_3_phy_v3 interface have returned no bandwidth
available.
link_status_changed is called when the phy detects a change
of the link status.
The phy parameter is deprecated and should be ignored.
- Execution Context
- Cell Context for all methods.
- Description
#define IEEE_802_3_PHY_INTERFACE "ieee_802_3_phy"
SIM_INTERFACE(ieee_802_3_phy) {
int (*send_frame)(conf_object_t *obj, dbuffer_t *buf, int replace_crc);
int (*check_tx_bandwidth)(conf_object_t *obj);
#if !defined(PYWRAP)
void (*add_mac)(conf_object_t *obj, const uint8 *mac);
void (*del_mac)(conf_object_t *obj, const uint8 *mac);
void (*add_mac_mask)(conf_object_t *obj, const uint8 *mac,
const uint8 *mask);
void (*del_mac_mask)(conf_object_t *obj, const uint8 *mac,
const uint8 *mask);
#endif
void (*set_promiscous_mode)(conf_object_t *obj, int enable);
};
Interface that should be implemented by 802.3 physical layers.
Deprecated; use ieee_802_3_phy_v2 instead.
- Execution Context
- Undefined.
- Description
#define IEEE_802_3_PHY_V2_INTERFACE "ieee_802_3_phy_v2"
SIM_INTERFACE(ieee_802_3_phy_v2) {
int (*send_frame)(conf_object_t *obj, dbuffer_t *buf, int replace_crc);
int (*check_tx_bandwidth)(conf_object_t *obj);
void (*add_mac)(conf_object_t *obj, byte_string_t mac);
void (*del_mac)(conf_object_t *obj, byte_string_t mac);
void (*add_mac_mask)(conf_object_t *obj, byte_string_t mac,
byte_string_t mask);
void (*del_mac_mask)(conf_object_t *obj, byte_string_t mac,
byte_string_t mask);
void (*set_promiscous_mode)(conf_object_t *obj, int enable);
};
Deprecated; use ieee_802_3_phy_v3 instead.
Interface that should be implemented by 802.3 physical layers.
The send_frame function is used by a device to send an
Ethernet frame. The frame should be a
dbuffer_t containing a complete Ethernet frame.
excluding the preamble and SFD, but including the CRC. The
replace_crc flag indicates whether the CRC is
not actually calculated yet. The passed buf should
not be modified by the called function.
If the function return 0, the frame was sent to the link; In case
-1 is returned, there was not enough bandwidth available right now,
and the frame could not be sent. The PHY should call the
tx_bandwidth_available in the ieee_802_3_mac
interface at the MAC, when the frame can be sent.
The check_tx_bandwidth can also be used to check that there
is bandwidth available, without sending a frame. It returns 0 if there
is no bandwidth available, and a positive value if the frame can be
sent right away.
add_mac, del_mac and set_promiscous_mode
have the same functionality as the equivalent
functions in ethernet_link interface. They do nothing
if the PHY is connected to the new-style links using the
ethernet_common interface.
The word "promiscuous" is misspelled in the interface.
- Execution Context
- Cell Context for all methods.
- Description
#define IEEE_802_3_PHY_V3_INTERFACE "ieee_802_3_phy_v3"
SIM_INTERFACE(ieee_802_3_phy_v3) {
int (*send_frame)(
conf_object_t *obj, const frags_t *frame, int replace_crc);
int (*check_tx_bandwidth)(conf_object_t *obj);
};
Interface that should be implemented by 802.3 physical layers.
The send_frame function is used by a device to send an Ethernet
frame. The frame should be a frags_t containing a
complete Ethernet frame, excluding the preamble and SFD, but including space
for the CRC field. The passed frame must not be modified by
the called function.
The replace_crc flag indicates whether the CRC field contents
can be modified by the implementing object: if replace_crc is
not set, the implementing object will leave the CRC field untouched; if
replace_crc is set, the implementing object is free to
rewrite the CRC field according to the link constraints. Note that in many
cases, setting replace_crc to true will allow the link to
assume the CRC field to be matching the frame contents, thus skipping CRC
calculation and improving simulation performance. replace_crc
should only be set to false when the device wants to send a frame with a CRC
field not matching the frame contents.
If the function return 0, the frame was sent to the link; In case
-1 is returned, there was not enough bandwidth available right now,
and the frame could not be sent. The PHY should call the
tx_bandwidth_available in the ieee_802_3_mac_v3
interface at the MAC, when the frame can be sent.
The check_tx_bandwidth can also be used to check that there
is bandwidth available, without sending a frame. It returns 0 if there
is no bandwidth available, and a positive value if the frame can be
sent right away.
- Execution Context
- Cell Context for all methods.
- Description
- The
interrupt_ack_fn_t function is called by an interrupt target
to ack an interrupt. Returns the interrupt vector.
typedef int (*interrupt_ack_fn_t)(conf_object_t *NOTNULL);
Interface for acked interrupts. The target is typically a cpu that
later calls the supplied ack function when the interrupt is
actually taken.
The ack argument in the lower_interrupt function
serves no purpose and should not be used.
To recover the ack function after a checkpoint restoration,
read it from the interrupt_cpu interface.
SIM_INTERFACE(interrupt_ack) {
void (*raise_interrupt)(conf_object_t *NOTNULL obj,
interrupt_ack_fn_t cb,
conf_object_t *ack_obj);
void (*lower_interrupt)(conf_object_t *NOTNULL obj,
interrupt_ack_fn_t cb);
};
#define INTERRUPT_ACK_INTERFACE "interrupt_ack"
- Execution Context
- Cell Context for all methods.
- Description
- Interface that must be implemented by an interrupt source that
sends interrupts through the
x86 interface. Used to
reestablish the ack function when loading a checkpoint.
SIM_INTERFACE(interrupt_cpu) {
interrupt_ack_fn_t ack;
};
#define INTERRUPT_CPU_INTERFACE "interrupt_cpu"
- Execution Context
- Cell Context for all methods.
- Description
- The target is typically a CPU that reacts to the interrupt.
The function notify notifies when an interrupt has occurred.
The function reset is run when the interrupt notifier source is
reset.
#define INTERRUPT_SUBSCRIBER_INTERFACE "interrupt_subscriber"
SIM_INTERFACE(interrupt_subscriber) {
void (*notify)(
conf_object_t *NOTNULL obj,
apic_delivery_mode_t delivery_mode,
bool level_assert,
apic_trigger_mode_t trigger_mode,
uint8 vector,
interrupt_source_t source);
void (*reset)(conf_object_t *NOTNULL obj);
};
- Execution Context
- Threaded Context for all methods.
- Description
- This interface is implemented by devices that can be mapped into address
spaces (including port spaces). The operation() is called when
the object is accessed through an address space.
The obj argument is a pointer to the mapped object and
map_info contains information about how and where
the device is mapped into memory. The mem_op argument
to operation() contains information about the access.
The offset into the device mapping for the access is typically
calculated in the following way:
offset = SIM_get_mem_op_physical_address(mem_op)
- map_info.base + map_info.start
Note:
The map() function is deprecated and should not be
used. The function may be called when the object is mapped into an address
space, but it is not guaranteed that this happens. The function can be left
unimplemented (NULL).
The exception_type_t type, returned by the
operation() function may be used to signal errors to
Simics, but should in most cases be Sim_PE_No_Exception.
If the device does not support inquiry accesses, it should return
Sim_PE_Inquiry_Unhandled if mem_op->inquiry is 1.
Note:
This interface is legacy. New code should use the
transaction interface.
typedef enum {
Sim_Addr_Space_Conf,
Sim_Addr_Space_IO,
Sim_Addr_Space_Memory
} addr_space_t;
SIM_INTERFACE(io_memory) {
int (*DEPRECATED_FUNC(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);
};
#define IO_MEMORY_INTERFACE "io_memory"
- Execution Context
- Cell Context for all methods.
- Description
- Interface used to dynamically add and remove mappings in a memory space.
The first argument to all functions, space is the memory
space to map an object in.
The map_simple function adds a device/port pair to the
memory map. The added device (port) must implement either the
ram, rom, io_memory,
port_space, translator,
transaction_translator, transaction or
memory_space interfaces.
The map_bridge function adds a device/port pair to the
memory map to act as a bridge that translates memory accesses
before passing them on to another object. The added device (port)
must implement either the translate interface or the
bridge interface, and the target and
target_port parameter specifies the object behind
the bridge. The target is typically another memory space.
The unmap removes an object from the memory map. The
dev and port parameters are the same
as those given to the map_simple and
map_bridge functions.
The unmap_address removes all mappings that map
object and start at the base address.
The add_map, remove_map,
add_default and remove_default functions are
deprecated and should not be used.
Both base and length of the map_info_t structure
should be 0 to map a default_target.
All functions in the map_demap return 1 on success and 0 on
failure.
More information about the different kinds of memory space mappings is
available in Simics Model Builder User's Guide.
SIM_INTERFACE(map_demap) {
/* old-style */
int (*add_map)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
conf_object_t *target,
map_info_t map_info);
int (*remove_map)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
int function);
int (*add_default)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
conf_object_t *target,
map_info_t map_info);
void (*remove_default)(conf_object_t *NOTNULL space);
/* new-style */
int (*map_simple)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
const char *dev_port,
map_info_t map_info);
int (*map_bridge)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
const char *dev_port,
conf_object_t *target,
const char *target_port,
map_info_t map_info);
int (*unmap)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
const char *dev_port);
int (*unmap_address)(conf_object_t *NOTNULL space,
conf_object_t *NOTNULL dev,
physical_address_t base,
const char *dev_port);
};
#define MAP_DEMAP_INTERFACE "map_demap"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(mdio45_bus) {
uint16 (*read_register)(conf_object_t *obj, int phy, int mmd, int reg);
void (*write_register)(conf_object_t *obj, int phy, int mdd, int reg,
uint16 value);
};
#define MDIO45_BUS_INTERFACE "mdio45_bus"
Interface that should be implemented by classes that either represent
an MDIO bus, or multi PHY devices implementing the IEEE 802.3 clause 45
MDIO management interface.
The read_register function should return the 16-bit value of
the specified register. phy specifies the PHY address (0-31),
mmd specifies the MMD (MDIO manageable device) within the PHY
(0-31) and reg specifies the register number within the MMD
(0-65535).
Devices modeling a single PHY should implement the mdio45_phy
interface instead.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(mdio45_phy) {
uint16 (*read_register)(conf_object_t *obj, int mmd, int reg);
void (*write_register)(conf_object_t *obj, int mmd, int reg,
uint16 value);
};
#define MDIO45_PHY_INTERFACE "mdio45_phy"
Interface that should be implemented by classes representing a single PHY
implementing the IEEE 802.3 clause 45 MDIO management interface.
The read_register function should return the 16-bit value of
the specified register. mmd specifies the MMD
(MDIO manageable device) within the PHY (0-31) and reg
specifies the register number within the MMD (0-65535).
Devices modeling either an MDIO bus, or multiple PHYs should implement
the mdio45_bus interface instead.
- Execution Context
- Cell Context for all methods.
- Description
-
This interface is implemented by classes that provide linear address
spaces.
Other objects may perform accesses in the address space using
the access function or one of the simplified access functions,
or may ask for mapped objects using space_lookup. Typical usage
of this interface would be memory accesses from devices or processors.
The space_lookup function would be used to find end-points for a
memory request. The mop needs to be crafted similarly as for a
regular read or write operation and would typically be created with
SIM_make_mem_op_read or SIM_make_mem_op_write. The
return value for space_lookup is a list of all mappings that
match the input mop.
The access function operates on a generic transaction that would
typically be created with SIM_make_mem_op_read or
SIM_make_mem_op_write.
The access_simple function is similar to access
but takes some additional arguments instead of a complete
generic_transaction_t structure. An inquiry version of this
function is available as access_simple_inq. Both these
functions can perform endian conversion if the buffer pointed to by
buf contains a value in host endian byte-order. To avoid endian
conversion, Sim_Endian_Target should be specified as
endian.
These two functions are not available from Python.
The read and write methods are primarily intended
for use in Python. They operate on data encapsulated in attribute values
which should be of data type; in Python, this corresponds to tuples of
integers (bytes). These two methods signal errors by raising a frontend
exception. They can be used to read or write up to 1024 bytes in a single
call. The return value from write should be ignored.
The fill method fills size bytes starting at
start with value. It only works on memory,
and returns the number of bytes actually written before encountering
something that isn't RAM.
SIM_INTERFACE(memory_space) {
map_list_t *(*space_lookup)(conf_object_t *NOTNULL obj,
generic_transaction_t *NOTNULL mop,
map_info_t mapinfo);
exception_type_t (*access)(conf_object_t *NOTNULL obj,
generic_transaction_t *NOTNULL mop);
#if !defined(PYWRAP)
exception_type_t (*access_simple)(conf_object_t *obj,
conf_object_t *initiator,
physical_address_t addr,
uint8 *buf,
physical_address_t len,
read_or_write_t type,
endianness_t endian);
exception_type_t (*access_simple_inq)(conf_object_t *obj,
conf_object_t *initiator,
physical_address_t addr,
uint8 *buf,
physical_address_t len,
read_or_write_t type,
endianness_t endian);
#endif /* !PYWRAP */
attr_value_t (*read)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
physical_address_t addr,
int length,
int inquiry);
exception_type_t (*write)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
physical_address_t addr,
attr_value_t data,
int inquiry);
cycles_t (*DEPRECATED_FUNC(timing_model_operate))(
conf_object_t *NOTNULL space,
generic_transaction_t *NOTNULL mop);
uint64 (*fill)(conf_object_t *NOTNULL obj,
physical_address_t start, uint64 size, uint8 value,
bool inquiry);
};
#define MEMORY_SPACE_INTERFACE "memory_space"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used to communicate with a 3-wire
(microwire) serial EEPROM device, for example, the 93Cxx
series, via its pins. To set the values of the CS, SK, and
DI pins, use the set_cs(), set_sk(),
and set_di() functions, respectively. To read the
value output on the DO pin, use the get_do()
function. Zero represents low signal and non-zero high
signal. The read_word() and write_word()
functions are provided to shortcut high-level operations.
They operate on 8-bit or 16-bit entities depending on the
width of the eeprom.
#define MICROWIRE_INTERFACE "microwire"
SIM_INTERFACE(microwire) {
void (*set_cs)(conf_object_t *obj, int cs);
void (*set_sk)(conf_object_t *obj, int sk);
void (*set_di)(conf_object_t *obj, int di);
int (*get_do)(conf_object_t *obj);
uint16 (*read_word)(conf_object_t *obj, int offset);
void (*write_word)(conf_object_t *obj, int offset, uint16 value);
};
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(mii) {
int (*serial_access)(conf_object_t *obj, int data_in, int clock);
uint16 (*read_register)(conf_object_t *obj, int index);
void (*write_register)(conf_object_t *obj, int index, uint16 value);
};
#define MII_INTERFACE "mii"
Obsolete interface that is implemented by some PHY's that support the MII
management interface.
It has the same methods as the mii_management interface,
but does not pass along the PHY number.
To support low-level bitwise accesses via MDIO and MDC pins, the
function serial_access can be used. It is recommended to
leave this function unimplemented and let an instance of
mii-management-bus convert the low-level bit operations
to higher level read/write register calls.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(mii_management) {
int (*serial_access)(conf_object_t *obj, int data_in, int clock);
uint16 (*read_register)(conf_object_t *obj, int phy, int reg);
void (*write_register)(conf_object_t *obj, int phy, int reg,
uint16 value);
};
#define MII_MANAGEMENT_INTERFACE "mii_management"
Interface that should be implemented by classes that represents one
or multiple PHY's that have MII management interfaces.
The read_register function should return the 16-bit value
of the specified register. There are 32 registers numbered 0-31. The
phy argument indicates the PHY number (0-31). Classes that represents
one PHY can ignore this argument.
The write_register function is called when a register is
written.
To support low-level bitwise accesses via MDIO and MDC pins, the
function serial_access can be used. It is recommended to
leave this function unimplemented and let an instance of
mii-management-bus convert the low-level bit operations
to higher level read/write register calls.
The serial_access function takes as argument the MDIO and MDC
pin levels on the master, and return the MDIO pin from the slave. Note
that mii-management-bus also have signal
interfaces for these pins.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by MIPS processors to provide various
functionality that is specific for this class of processors.
There are currently no MIPS-specific functions.
SIM_INTERFACE(mips) {
int dummy;
};
#define MIPS_INTERFACE "mips"
- Execution Context
- Not applicable.
- Description
- This
mips_cache_instruction interface is used when
side-effects are wanted when cache instructions are run.
The cache_instruction function is called whenever the
cache instruction is run, and the parameters operation
and vaddr are taken directly from the instruction.
The exact meaning of operation is processor-dependent.
A non-zero return value indicates that an exception should be raised on the
MIPS core), whereas a zero value means no exception.
SIM_INTERFACE(mips_cache_instruction) {
int (*cache_instruction)(conf_object_t *NOTNULL self,
conf_object_t *NOTNULL cpu,
uint32 op, logical_address_t vaddr);
};
#define MIPS_CACHE_INSTRUCTION_INTERFACE "mips_cache_instruction"
- Execution Context
- Cell Context.
- Description
- This
mips_coprocessor interface is implemented by
MIPS coprocessors. The MIPS processor cores use this interface to
access coprocessor registers.
The read_register function returns a 64-bit value from a
coprocessor register. The return value should be zero extended if
the coprocessor register is less than 64-bits.
The write_register function writes a 64-bit value to a
coprocessor register. The target register can be smaller than
64-bits.
The thread_id is the thread id for the calling
processor core. The reg and sel
selects the coprocessor register to read or write. For instructions
that make use of the whole implementation-defined bits 15:0, that
field is passed as reg and sel is zero.
SIM_INTERFACE(mips_coprocessor) {
uint64 (*read_register)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint32 reg,
uint32 sel);
void (*write_register)(conf_object_t *NOTNULL obj,
uint32 thread_id,
uint64 value,
uint32 reg,
uint32 sel);
};
#define MIPS_COPROCESSOR_INTERFACE "mips_coprocessor"
- Execution Context
- Cell Context for all methods.
- Description
- The
mips_eic must be
implemented by devices that acts as MIPS External Interrupt
Controllers. After the external IRQ signal in the CPU has been raised, the
CPU will query the registered External Interrupt Controller for information
about the current interrupt request. When the CPU starts the interrupt
servicing it calls the handled function.
The cpu_pending_irqs function sends current cause register which
stores the pending irqs for software irq, timer irq, fdci irq and pci
irq. The external irq controller should take this information to do irq
arbitration.
requested_ipl should used to return the
requested interrupt priority level.
There are two options for vector offset calculation. Option 1, EIC device
returns a vector number. This vector number will be used together with
intctl.vs to calculate the offset. Option 2, EIC returns the offset
directly. When using option 1, the requested_vect_num function
should be used to return the vector number. When using option 2, the
requested_offset should be used to return the offset of the
requested interrupt.
The reg_set should return the shadow register set number.
SIM_INTERFACE(mips_eic) {
void (*cpu_pending_irqs)(conf_object_t *NOTNULL obj, uint32 cause);
uint32 (*requested_ipl)(conf_object_t *NOTNULL obj);
uint32 (*requested_offset)(conf_object_t *NOTNULL obj);
uint32 (*requested_vect_num)(conf_object_t *NOTNULL obj);
uint32 (*reg_set)(conf_object_t *NOTNULL obj);
void (*handled)(conf_object_t *NOTNULL obj);
};
#define MIPS_EIC_INTERFACE "mips_eic"
- Execution Context
- Cell Context for all methods.
- Description
- Used to query information of an exception from a
cpu_exception_cb_t callback.
SIM_INTERFACE(mips_exception_query) {
logical_address_t (*return_pc)(conf_object_t *cpu,
exception_handle_t *handle);
};
#define MIPS_EXCEPTION_QUERY_INTERFACE "mips_exception_query"
pc is used to get the address of the faulting instruction.
return_pc is used to get the return address for the exception.
number is used to get the exception number.
- Execution Context
- Cell Context for all methods.
- Description
- This
mips_ite interface is implemented by the CPU, for
communicating with the MIPS Inter-Thread Communication Unit.
The set_dtag_lo function sets the DTagLo SPR.
The get_dtag_lo function returns the value of the DTagLo SPR.
The get_errctl function returns the value of the ErrCtl SPR.
The block_tc function marks the current TC as blocked on gating
storage and swaps in another TC.
The gated_exception function throws an immediate exception.
The current_tc_num function returns the currently running TC
number on the VPE.
The unblock_tc function unblocks the specified TC if it is
currently blocked on gating storage.
The is_big_endian function indicates if the CPU expects
big endian memory storage.
SIM_INTERFACE(mips_ite) {
void (*set_dtag_lo)(conf_object_t *NOTNULL obj, uint32 value);
uint32 (*get_dtag_lo)(conf_object_t *NOTNULL obj);
uint32 (*get_errctl)(conf_object_t *NOTNULL obj);
void (*block_tc)(conf_object_t *NOTNULL obj);
void (*gated_exception)(conf_object_t *NOTNULL obj);
int (*current_tc_num)(conf_object_t *NOTNULL obj);
void (*unblock_tc)(conf_object_t *NOTNULL obj, int tc_num);
bool (*is_big_endian)(conf_object_t *NOTNULL obj);
};
#define MIPS_ITE_INTERFACE "mips_ite"
- Execution Context
- Cell Context for all methods.
- Description
- Interface to model a signal with multiple levels, such as an analog signal.
Note:
Obsoleted by the uint64_state interface.
The signal initiator (i.e. the object producing the signal) should call
signal_level_change when the level changes. Multiple calls with
the same level should be accepted by the signal receiver.
The optional function signal_current_level can be called when
a new target is connected.
SIM_INTERFACE(multi_level_signal) {
void (*signal_level_change)(conf_object_t *NOTNULL obj, uint64 level);
void (*signal_current_level)(conf_object_t *NOTNULL obj, uint64 level);
};
#define MULTI_LEVEL_SIGNAL_INTERFACE "multi_level_signal"
- Execution Context
- Cell Context for all methods.
- Description
- The
nand_flash interface is used to perform read and write
accesses and control some pins on NAND Flash devices.
The read_access() and write_access() functions perform
read and write accesses.
The set_command_latch_enable(),
set_address_latch_enable(), set_write_protect() and
set_spare_area_enable() functions set the input level of the pins
with the same names. 0 represents low input and 1 represents high input.
The chip enable and ready/busy pins are not modelled. The NAND Flash device
assumes that chip enable is always asserted, and the device is never busy.
#define NAND_FLASH_INTERFACE "nand_flash"
SIM_INTERFACE(nand_flash) {
uint16 (*read_access)(conf_object_t *obj);
void (*write_access)(conf_object_t *obj, uint16 value);
void (*set_command_latch_enable)(conf_object_t *obj, int value);
void (*set_address_latch_enable)(conf_object_t *obj, int value);
void (*set_write_protect)(conf_object_t *obj, int value);
void (*set_spare_area_enable)(conf_object_t *obj, int value);
};
- Execution Context
- Cell Context for all methods.
- Description
- The
network_breakpoint interface is implemented by
objects that handles ethernet links to have breakpoints.
The add is used to set a breakpoint on a given src mac
address or gived dst mac address or by ether type. If they are combined
then the criteria is that all given has to match.
The remove is used to remove an existing
breakpoint.
SIM_INTERFACE(network_breakpoint) {
int64 (*add)(conf_object_t *NOTNULL obj, bytes_t src_mac_addr,
bytes_t dst_mac_addr, int ether_type,
break_net_cb_t cb, bool once, int64 bp_id);
void (*remove)(conf_object_t *NOTNULL obj, int64 bp_id);
};
#define NETWORK_BREAKPOINT_INTERFACE "network_breakpoint"
- Execution Context
- Global Context
for all methods
- Description
- This interface is implemented by Intel®
Nios® processors to provide various functionality that is specific for
this class of processors.
There are currently no Nios-specific functions.
SIM_INTERFACE(nios) {
int dummy;
};
#define NIOS_INTERFACE "nios"
- Execution Context
- Not applicable.
- Description
- This
nios_cache interface is used when
the side-effects are required for cache instructions.
Each function is called when the corresponding instruction is executed. See
Nios® II processor reference guide, section 8, for further
information.
SIM_INTERFACE(nios_cache) {
void (*flushd)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*flushda)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*flushi)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*flushp)(conf_object_t *NOTNULL self);
void (*initd)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*initda)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*initi)(conf_object_t *NOTNULL self, logical_address_t addr);
void (*sync)(conf_object_t *NOTNULL self);
};
#define NIOS_CACHE_INTERFACE "nios_cache"
- Execution Context
- Cell Context for all methods.
- Description
- This
nios_custom interface is used when
the custom instruction needs to be used.
The custom function is called whenever the
custom instruction is executed.
See Nios® II processor reference guide page 8-35 for further
information about the parameters.
SIM_INTERFACE(nios_custom) {
uint32 (*custom)(conf_object_t *NOTNULL self, uint32 n,
uint32 a, uint32 b, uint32 c, uint32 rA, uint32 rB,
bool readra, bool readrb, bool writerc);
};
#define NIOS_CUSTOM_INTERFACE "nios_custom"
- Execution Context
- Cell Context
- Description
- The
nios_eic must be implemented by devices that acts as
Nios®
External Interrupt Controllers. After the external IRQ signal in the CPU
has been raised, the CPU will query the registered External Interrupt
Controller for information about the current interrupt request.
When the CPU calls the handled function, it has finished
processing the request.
The handler function should return the logical address of
the interrupt handler.
The level should return the interrupt level.
The reg_set should return the shadow register set number.
The nmi should indicate if this is a non-maskable interrupt.
See Nios® II processor reference guide page 3-41 for further
information.
SIM_INTERFACE(nios_eic) {
logical_address_t (*handler)(conf_object_t *NOTNULL obj);
uint32 (*level)(conf_object_t *NOTNULL obj);
uint32 (*reg_set)(conf_object_t *NOTNULL obj);
bool (*nmi)(conf_object_t *NOTNULL obj);
void (*handled)(conf_object_t *NOTNULL obj);
};
#define NIOS_EIC_INTERFACE "nios_eic"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by all PCI bridges.
For interrupts, the initiating device is specified with a pci-bus object and
PCI device number pair, and the pin represents PCI interrupt lines (A, B, C,
or D) as numbers in the range of 0 to 3.
SIM_INTERFACE(pci_bridge) {
void (*system_error)(conf_object_t *obj);
void (*raise_interrupt)(conf_object_t *obj, conf_object_t *pci_bus,
int device, int pin);
void (*lower_interrupt)(conf_object_t *obj, conf_object_t *pci_bus,
int device, int pin);
};
#define PCI_BRIDGE_INTERFACE "pci_bridge"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by all PCI buses and its functions are
accessed by PCI devices. For further details, see Model Builder
User's Guide, chapter "Modeling PCI Devices".
Note:
The memory_access function is deprecated and must not be
called (as it is not implemented by Simics pci-bus object). The
interrupt_acknowledge, special_cycle,
add_default and remove_default functions are also
deprecated, but they are still implemented by Simics pci-bus and thus
callable.
SIM_INTERFACE(pci_bus) {
/* Deprecated; memory_access */
exception_type_t (*memory_access)(
conf_object_t *obj, generic_transaction_t *NOTNULL mem_op);
void (*raise_interrupt)(conf_object_t *obj, conf_object_t *NOTNULL dev,
int pin);
void (*lower_interrupt)(conf_object_t *obj, conf_object_t *NOTNULL dev,
int pin);
/* Deprecated; interrupt_acknowledge */
int (*interrupt_acknowledge)(conf_object_t *obj);
int (*add_map)(conf_object_t *obj, conf_object_t *dev,
addr_space_t space, conf_object_t *target,
map_info_t info);
int (*remove_map)(conf_object_t *obj, conf_object_t *dev,
addr_space_t space, int function);
void (*set_bus_number)(conf_object_t *obj, int bus_id);
void (*set_sub_bus_number)(conf_object_t *obj, int bus_id);
/* Deprecated; add_default, remove_default */
void (*add_default)(conf_object_t *obj, conf_object_t *dev,
addr_space_t space, conf_object_t *target,
map_info_t info);
void (*remove_default)(conf_object_t *obj, addr_space_t space);
void (*bus_reset)(conf_object_t *obj);
/* Deprecated; special_cycle */
void (*special_cycle)(conf_object_t *obj, uint32 value);
void (*system_error)(conf_object_t *obj);
int (*get_bus_address)(conf_object_t *obj, conf_object_t *NOTNULL dev);
void (*set_device_status)(conf_object_t *obj, int device, int function,
int enabled);
/* Memory spaces */
conf_object_t *(*configuration_space)(conf_object_t *obj);
conf_object_t *(*io_space)(conf_object_t *obj);
conf_object_t *(*memory_space)(conf_object_t *obj);
};
#define PCI_BUS_INTERFACE "pci_bus"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by all PCI devices (including bridges).
Note:
The interrupt_acknowledge and special_cycle
functions are deprecated. The functions can be left
unimplemented (NULL).
SIM_INTERFACE(pci_device) {
void (*bus_reset)(conf_object_t *obj);
/* Deprecated; interrupt_acknowledge, special_cycle */
int (*DEPRECATED_FUNC(interrupt_acknowledge))(conf_object_t *obj);
void (*DEPRECATED_FUNC(special_cycle))(conf_object_t *obj,
uint32 value);
/* System Error */
void (*system_error)(conf_object_t *obj);
/* peer-to-peer interrupt mechanism */
void (*interrupt_raised)(conf_object_t *obj, int pin);
void (*interrupt_lowered)(conf_object_t *obj, int pin);
};
#define PCI_DEVICE_INTERFACE "pci_device"
- Execution Context
- Cell Context for all methods.
- Description
- The
pci_downstream interface is implemented by
PCI(e) buses to handle downstream transactions.
SIM_INTERFACE(pci_downstream) {
exception_type_t (*operation)(conf_object_t *obj,
generic_transaction_t *mem_op,
addr_space_t space);
};
#define PCI_DOWNSTREAM_INTERFACE "pci_downstream"
- Execution Context
- Cell Context for all methods.
- Description
- Deprecated as part of the old PCIe library. Replaced by the new PCIe library.
Note:
This interface is deprecated. The transaction interface
implemented by the pcie-bus (upstream and downstream ports) can be used to
send any type of message with any type of routing by adding related
pcie_type and pcie_msg_route ATOMs to
the transaction.
This interface can be implemented by any PCI Express device, switch or
endpoint. It is also implemented by the pci-bus, which will pass it on
to the other end; e.g. if the endpoint sends a message, the pci-bus will
pass it on to the bridge (downport), and if the downport sends it, it will
be broadcasted to all devices on the bus.
Please note that message routing is not supported. The implications of this
limitation is that a switch does not know if the message is intended for the
switch itself or for some device connected to it. In addition, since the bus
does not replace the src parameter when forwarding the
message, and the bus does not support port mappings, it is impossible for a
bus-to-bus bridge (up-port/down-port) to know from which bus the message
originates making it impossible to forward the message to the other side.
Another way of looking at this limitation is to say that the only message
routing currently supported is the implicit routing that terminates at the
receiver (Type[2:0] = 0b100), so bus-to-bus bridges should not try to
forward the message to the other side.
src is the object sending the message. type is
one of:
typedef enum {
/* Address Translation */
PCIE_ATS_Invalidate = 0x01,
PCIE_ATS_Invalidate_Completion = 0x02,
PCIE_PRS_Request = 0x04,
PCIE_PRS_Response = 0x05,
PCIE_Latency_Tolerance_Reporting = 0x10,
PCIE_Optimized_Buffer_Flush_Fill = 0x12,
/* INTx emulation */
PCIE_Msg_Assert_INTA = 0x20,
PCIE_Msg_Assert_INTB = 0x21,
PCIE_Msg_Assert_INTC = 0x22,
PCIE_Msg_Assert_INTD = 0x23,
PCIE_Msg_Deassert_INTA = 0x24,
PCIE_Msg_Deassert_INTB = 0x25,
PCIE_Msg_Deassert_INTC = 0x26,
PCIE_Msg_Deassert_INTD = 0x27,
/* Power Management */
PCIE_PM_Active_State_Nak = 0x14,
PCIE_PM_PME = 0x18,
PCIE_PM_Turn_Off = 0x19,
PCIE_PM_PME_TO_Ack = 0x1B,
/* Error Messages */
PCIE_ERR_COR = 0x30,
PCIE_ERR_NONFATAL = 0x31,
PCIE_ERR_FATAL = 0x33,
/* Locked Transaction */
PCIE_Unlock = 0x00,
/* Slot Power Limit */
PCIE_Set_Slot_Power_Limit = 0x50,
PCIE_Precision_Time_Measurement = 0x52,
/* Hot Plug Messages */
PCIE_HP_Power_Indicator_On = 0x45,
PCIE_HP_Power_Indicator_Blink = 0x47,
PCIE_HP_Power_Indicator_Off = 0x44,
PCIE_HP_Attention_Button_Pressed = 0x48,
PCIE_HP_Attention_Indicator_On = 0x41,
PCIE_HP_Attention_Indicator_Blink = 0x43,
PCIE_HP_Attention_Indicator_Off = 0x40,
PCIE_Vendor_Defined_Type_0 = 0x7e,
PCIE_Vendor_Defined_Type_1 = 0x7f,
PCIE_Locked_Transaction = 0x00, // legacy name for PCIE_Unlock
/* Data Link Layer (virtual) Messages
NOTE: these messages only exist on Simics simulator, as they are
normally part of the Data Link Layer which is below the level of
abstraction for Simics PCIe models
According to PCIe rev 2.0, when a target receives a message that it
does not recognize or support, except for the "Vendor Defined Type
1" message, it should treat the request as an "Unsupported Request"
and report it accordingly (see sec 2.3.1 for reference).
Hence models that comply with rev 2.0 must be updated to either
1) handle these messages or 2) ignore these messages.
Ideally we would like to use a new pcie_link interface to transmit
this information - see bug 17849 for more info. */
PCIE_DLL_Link_Down = -1,
PCIE_DLL_Link_Up = -2,
} pcie_message_type_t;
The contents of payload depends on type.
SIM_INTERFACE(pci_express) {
int (*send_message)(conf_object_t *dst, conf_object_t *src,
pcie_message_type_t type, byte_string_t payload);
};
#define PCI_EXPRESS_INTERFACE "pci_express"
- Execution Context
- Cell Context for all methods.
- Description
- Deprecated as part of the old PCIe library. Replaced by the new PCIe library.
This interface is intended for PCI Express switches that need to monitor the
status of their downports. The interface should be implemented by the bridge
object.
presence_change is called from the pci-bus when an device is
added or removed from the bus. is_present is set to 1 when
the device is added, and 0 when it is removed.
inject_power_fault can be used to simulate a power fault on
the downport. It is never called automatically.
press_attention_button can be called to simulate the attention
button being pressed. The switch can respond to this by e.g. raising
an interrupt and setting appropriate status bits. It is never called
automatically.
set_mrl_state is similar to attention_button_press
but controls the Manually operated Retention Latch. Set
locked to 1 to simulate it being locked/closed, and 0 to
simulate it being unlocked/opened.
Finally, get_mrl_state returns the state of the Manually
operated Retention Latch.
SIM_INTERFACE(pci_express_hotplug) {
/* This is sent when a device is added or removed from the bus. */
void (*presence_change)(conf_object_t *dst, conf_object_t *NOTNULL src,
int is_present);
void (*inject_power_fault)(conf_object_t *obj);
void (*press_attention_button)(conf_object_t *obj);
void (*set_mrl_state)(conf_object_t *obj, int locked);
int (*get_mrl_state)(conf_object_t *obj);
};
#define PCI_EXPRESS_HOTPLUG_INTERFACE "pci_express_hotplug"
- Execution Context
- Cell Context for all methods.
- Description
- This interface should only be used when a device other than the bridge
handles PCI interrupts on the PCI bus. The initiating device is specified
with a PCI device number, and the pin represents PCI interrupt lines
(A, B, C, or D) as numbers in the range of 0 to 3.
SIM_INTERFACE(pci_interrupt) {
void (*raise_interrupt)(conf_object_t *obj, conf_object_t *pci_bus,
int device, int pin);
void (*lower_interrupt)(conf_object_t *obj, conf_object_t *pci_bus,
int device, int pin);
};
#define PCI_INTERRUPT_INTERFACE "pci_interrupt"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is intended for PCI devices that want to have multiple
functions implemented within the same device instance, as compared to the
scheme of having each PCI function defined in a separate instance.
supported_functions is called from the pci-bus to find out how
many functions are supported by this device. The expected return value is a
list of tuples, where each tuple contains the PCI function number followed
by one or two elements controlling what to map into the bus'
config-space. The list can consist of any number of tuples using any and all
of the supported formats:
- (fun, str); maps the named port-interface on the object implementing the
current interface. For example, the name of the bank that provides the
configuration registers for this function.
- (fun, obj); maps the object expecting configuration access is handled by
io_memory implemented directly on the object.
- (fun, obj, str); maps the named port-interface on the provided
object.
The list can contain a mix of formats, each entry corresponds to a unique
mapping of a function.
For ARI enabled PCIe devices, the device number is assumed to be zero thus
it is an error to try to claim a function number greater than seven while
connecting with a device number greater than zero.
SIM_INTERFACE(pci_multi_function_device) {
attr_value_t (*supported_functions)(conf_object_t *obj);
};
#define PCI_MULTI_FUNCTION_DEVICE_INTERFACE "pci_multi_function_device"
- Execution Context
- Global Context for all methods.
- Description
- This interface is implemented by PCI(e) buses and
bridges to handle upstream transactions (primarily
memory or IO).
A PCI(e) bus typically forwards all transactions to
an upstream bridge.
PCI(e) bridges either forward a transaction to its primary
side bus or initiate a downstream operation
on the secondary bus using the pci_downstream
interface.
It should be noted that a PCI bridge using
this interface will see peer-to-peer traffic
from its secondary interface; this is a difference
compared to real hardware where such transactions
never involve the bridge. To behave like real
hardware, PCI bridges should send all peer-to-peer
traffic downstream.
SIM_INTERFACE(pci_upstream) {
exception_type_t (*operation)(conf_object_t *obj,
generic_transaction_t *mem_op,
addr_space_t space);
};
#define PCI_UPSTREAM_INTERFACE "pci_upstream"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by PCI(e) buses to handle upstream
transactions (primarily memory or IO) from PCI(e) devices.
The initiator should be the PCI device object itself. There are
currently no requirements on this object in terms of interfaces. It is
intended for future use and could be left NULL.
The 16-bit Requester ID is provided by the rid parameter. This is
the ID that uniquely identifies the initiator in a PCIe hierarchy, also more
commonly known as the BDF (Bus/Device/Function). This ID can be left blank
(0) by non-PCIe devices if the BDF is not known.
Return value is of type exception_type_t and maps, just like
all other PCI interfaces, onto PCI concepts accordingly:
- Sim_PE_No_Exception
- OK
- Sim_PE_IO_Not_Taken
- Master Abort
- Sim_PE_IO_Error
- Target Abort
Other return values are currently unexpected.
SIM_INTERFACE(pci_upstream_operation) {
exception_type_t (*read)(conf_object_t *obj,
conf_object_t *initiator,
uint16 rid,
addr_space_t space,
physical_address_t address,
buffer_t buffer);
exception_type_t (*write)(conf_object_t *obj,
conf_object_t *initiator,
uint16 rid,
addr_space_t space,
physical_address_t address,
bytes_t buffer);
};
#define PCI_UPSTREAM_OPERATION_INTERFACE "pci_upstream_operation"
- Execution Context
- Cell Context for all methods.
- Description
- Deprecated as part of the old PCIe library. Replaced by the new PCIe library.
This interface is used by PCI buses that want to be compatible
with PCIe devices created with the new PCIe library. This interface is
implemented by the legacy-pcie-upstream-adapter.
SIM_INTERFACE(pcie_adapter_compat) {
void (*set_secondary_bus_number)(conf_object_t *obj,
int secondary_bus_number);
};
#define PCIE_ADAPTER_COMPAT_INTERFACE "pcie_adapter_compat"
- Execution Context
- Cell Context for all methods.
- Description
- This interface must be implemented by all PCIe devices that can receive
downstream transactions.
connected and disconnected are used to indicate that
the device is (dis)connected to port_obj with device id
device_id and may use the pcie_map interface to
add/remove functions and claim/release other resources. These functions
should only be called once for each (dis)connected physical device no matter
how many physical or virtual functions it has. The device_id
contains the device number (D part of B:D:F) and should use 0 as the function
number (F part of B:D:F).
hot_reset is used to indicate that a Hot Reset has been signaled
on the PCIe link to which the device is connected. It is up to the device to
reset functions and other resources mapped using the pcie_map
interface.
Note: This interface is considered tech-preview and may change without
notice.
SIM_INTERFACE(pcie_device) {
void (*connected)(conf_object_t *obj, conf_object_t *port_obj,
uint16 device_id);
void (*disconnected)(conf_object_t *obj, conf_object_t *port_obj,
uint16 device_id);
void (*hot_reset)(conf_object_t *obj);
};
#define PCIE_DEVICE_INTERFACE "pcie_device"
- Execution Context
- Global Context for all methods.
- Description
- This interface should be implemented by all PCIe functions that wants to
provide useful information for inspecting the function.
get_device_id returns the device id of the function.
get_upstream_target returns the upstream target of the PCIe device
the PCIe function belongs to.
is_virtual_function returns true if the function is a virtual
function.
get_bar_map_obj returns the object that is mapped by the BAR at
bar_offset. If there is no BAR register at bar_offset,
NULL is returned. For a physical function, the bar_offset is the
offset in the Type 0/1 Configuration Space Header. For a virtual function,
the bar_offset is the offset in the SR-IOV Extended Capability
structure of the associated physical function (starting at 0x24).
SIM_INTERFACE(pcie_function_info)
{
uint16 (*get_device_id)(conf_object_t *obj);
conf_object_t *(*get_upstream_target)(conf_object_t *obj);
bool (*is_virtual_function)(conf_object_t *obj);
conf_object_t *(*get_bar_map_obj)(conf_object_t *obj, uint8 bar_offset);
};
#define PCIE_FUNCTION_INFO_INTERFACE "pcie_function_info"
- Execution Context
- Cell Context for all methods.
- Description
- This interface should be implemented by Hot-Plug capable Downstream Ports.
Such devices should be either a Downstream Port of a PCI Express Switch or a
Root Port of PCI Express Root Complex.
The device that implements this interface should on the invocation of any
of the methods in this interface should do the following:
1. If the applicable Hot-Plug capability has been enabled, set the new value
of the corresponding Hot-Plug event in the applicable register.
2. If the value changed from its previous value, set the changed register
value for the applicable Hot-Plug event.
3. If the value changed from its previous value, notify software using an
interrupt if notifications are enabled for the applicable Hot-Plug event
and an interrupt mechanism has been configured by the software (MSI/MSI-X
or PCI-compatible INTx Emulation).
The presence_change() method is called by the pcie-downstream-port
(if its upstream target implements this interface) when it goes from having
no adapter present to having an adapter present and vice versa.
SIM_INTERFACE(pcie_hotplug_events) {
void (*presence_change)(conf_object_t *obj, pcie_hotplug_pd_t state);
void (*power_fault)(conf_object_t *obj);
void (*attention_button_pressed)(conf_object_t *obj);
void (*mrl_sensor)(conf_object_t *obj, pcie_hotplug_mrl_t state);
void (*data_link_layer)(conf_object_t *obj, bool is_active);
};
#define PCIE_HOTPLUG_EVENTS_INTERFACE "pcie_hotplug_events"
- Execution Context
- Cell Context for all methods.
- Description
- Trigger link training on obj. device_id
provides the device id of device connected to obj which will
be the link training target.
SIM_INTERFACE(pcie_link_training) {
bool (*trigger)(conf_object_t *obj, uint16 device_id);
};
#define PCIE_LINK_TRAINING_INTERFACE "pcie_link_training"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used to claim ranges in PCIe address spaces and to manage
virtual functions.
Functions add_map and del_map are used to add and
remove maps, map_obj will be mapped in the address space
indicated by type according to the information in info.
Functions add_function, del_function,
enable_function and disable_function are used to add,
delete, enable and disable functions, both virtual and physical. The
supplied map_obj must be a valid map-target, it will receive both
Config and Message transactions. For Message transactions, the device id (not
including bus number) will be in bits 55:48 of the 64-bit address. For
Config transactions, the device id is not part of the address. The supplied
device_and_function passed to these methods should contain the
device and function number (D:F part of B:D:F).
The function get_device_id returns the current device id of
dev_obj, as a 16 bit number. Note that the bus number part is
saved immediately after the RC/Switch sets it, even if no successful
Config-Write has been made.
Note: This interface is considered tech-preview and may change without
notice.
typedef enum {
PCIE_Type_Not_Set,
PCIE_Type_Mem,
PCIE_Type_IO,
PCIE_Type_Cfg,
PCIE_Type_Msg,
PCIE_Type_Other,
} pcie_type_t;
SIM_INTERFACE(pcie_map) {
void (*add_map)(conf_object_t *obj, conf_object_t *map_obj,
map_info_t info, pcie_type_t type);
void (*del_map)(conf_object_t *obj, conf_object_t *map_obj,
physical_address_t base, pcie_type_t type);
void (*add_function)(conf_object_t *obj, conf_object_t *map_obj,
uint16 device_and_function);
void (*del_function)(conf_object_t *obj, conf_object_t *map_obj,
uint16 device_and_function);
void (*enable_function)(conf_object_t *obj, uint16 device_and_function);
void (*disable_function)(conf_object_t *obj,
uint16 device_and_function);
uint16 (*get_device_id)(conf_object_t *obj, conf_object_t *dev_obj);
};
#define PCIE_MAP_INTERFACE "pcie_map"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used to configure instances of the
pcie-downstream-port
The set_secondary_bus_number method should be called whenever the
Secondary Bus Number register in the Type 1 Configuration Header of this
downstream port changes.
The hot_reset method sends a hot reset to all downstream devices
Note: This interface is considered tech-preview and may change without
notice.
SIM_INTERFACE(pcie_port_control) {
void (*set_secondary_bus_number)(conf_object_t *obj, uint64 value);
void (*hot_reset)(conf_object_t *obj);
};
#define PCIE_PORT_CONTROL_INTERFACE "pcie_port_control"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(pmr) {
uint64 (*get)(
conf_object_t *obj,
int pmr_number,
bool instruction_read);
void (*set)(
conf_object_t *obj,
int pmr_number,
uint64 value,
bool instruction_write);
};
#define PMR_INTERFACE "pmr"
This interface provides a way for a user to write their own handler for the
performance monitor register bank. The processor's pmr_handler
attribute should be set point at the to the module, which implements the pmr
interface. When set, all reads and writes toward the defined PMR registers
will be forwarded to the user module instead. Simics CPU module will perform
all the privilege checks and only forward the read/write if it is permitted.
The supervisor registers are checkpointed by the CPU module and the register
content for the PMR registers is distributed to the user module in the
finalize phase, after the pmr_handler has been set.
The function get is used for attribute reads, int_register reads
or for mfpmr instructions. The value for the PMR register should be
returned. The instruction_read will be true only for
mfpmr instructions, allowing distinction between register reads by
the user and instructions which could have side-effects.
Similar, the set function is used for attribute writes,
int_register writes or for mtpmr instructions. The
instruction_write will be true only for mtpmr
instructions. The value indicates the value written to the
PMR register.
- Execution Context
- Cell Context for all methods.
- Description
- I/O port interface.
SIM_INTERFACE(port_space) {
exception_type_t (*port_operation)(conf_object_t *NOTNULL pspace_obj,
generic_transaction_t *NOTNULL mop,
map_info_t map_info);
attr_value_t (*read)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
physical_address_t addr,
int length,
int inquiry);
exception_type_t (*write)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
physical_address_t addr,
attr_value_t data,
int inquiry);
};
#define PORT_SPACE_INTERFACE "port_space"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(ppc) {
void (*PYTHON_METHOD clear_atomic_reservation_bit)(conf_object_t *cpu);
void (*PYTHON_METHOD raise_machine_check_exception)(conf_object_t *cpu,
ppc_mc_exc_t exc);
/* Timebase */
unsigned (*PYTHON_METHOD get_timebase_enabled)(conf_object_t *cpu);
void (*PYTHON_METHOD set_timebase_enabled)(conf_object_t *cpu,
unsigned enabled);
/* Power mode */
ppc_sleep_state_t (*PYTHON_METHOD get_sleep_state)(conf_object_t *cpu);
void (*PYTHON_METHOD set_sleep_state)(conf_object_t *cpu,
ppc_sleep_state_t state);
};
#define PPC_INTERFACE "ppc"
The clear_atomic_reservation_bit() function clears the
reservation bit which is set by an lwarx instruction. Clearing the
reservation will cause a following stwcx. instruction to fail.
This function is typically used by a cache hierarchy supporting SMP.
The raise_machine_check_exception() function raises a machine
check exception. The exc argument is of the following type:
typedef enum {
Sim_PPC_Generic_MC,
Sim_PPC_MC_TEA,
Sim_PPC_MC_MCP,
Sim_PPC_Bus_Address_Parity,
Sim_PPC_Bus_Data_Parity,
Sim_PPC_Instruction_Cache_Parity,
Sim_PPC_Data_Cache_Parity,
Sim_PPC_L2_Data_Parity,
Sim_PPC_L3_Data_Parity,
Sim_PPC_L3_Address_Parity,
Sim_PPC970_Data_Cache_Parity,
Sim_PPC970_Data_Cache_Tag_Parity,
Sim_PPC970_D_ERAT_Parity,
Sim_PPC970_TLB_Parity,
Sim_PPC970_SLB_Parity,
Sim_PPC970_L2_Load_ECC_Parity,
Sim_PPC970_L2_Page_Table_ECC_Parity,
Sim_PPC970_Uncacheable_Load_Parity,
Sim_PPC970_MC_External
} ppc_mc_exc_t;
The get_timebase_enabled and set_timebase_enabled
functions can be used to query and set the enabled state of the timebase.
- Execution Context
- Cell Context for all methods.
- Description
- Interface to model a pulse, meaning an event that triggers.
SIM_INTERFACE(pulse) {
void (*pulse)(conf_object_t *NOTNULL obj);
};
#define PULSE_INTERFACE "pulse"
- Execution Context
- Cell Context for all methods.
- Description
-
The ram interface is implemented by classes that provide
random access read/write memory. The rom interface is
identical to ram but provides read only memory (writes are
dropped by the memory system).
Both the ram and rom interfaces are Simics internal, and should not be used
by user-defined classes.
The get_page method is obsolete and should not be implemented.
The fill method fills a range with a specified byte value.
The read method reads a number of bytes from address
addr into the buffer data. The number of
bytes read is given by the buffer size.
The write method writes the bytes in data to
address addr.
The touch method is similar to the read and
write methods, except that no data is actually transferred; the
method triggers side effects like revoking conflicting direct-memory
permissions from affected pages. The rw argument determines
whether the operation is a handled as a read or as a write.
The flags argument is a bitmask which modify the behavior
of read, write and touch operations in
various ways.
The size method returns the memory size in bytes; that is, the
highest usable address plus one.
typedef enum {
Sim_Ram_Op_Fetch = 1, /* Read is an instruction fetch. */
Sim_Ram_Op_Non_Coherent = 2, /* Operation should not cause
atomic reservations to be lost. */
} ram_operation_flags_t;
SIM_INTERFACE(ram) {
#ifndef PYWRAP
/* The get_page is method is obsolete and should be left
unimplemented. */
page_t *(*get_page)(conf_object_t *NOTNULL obj,
physical_address_t addr);
#endif
void (*fill)(conf_object_t *NOTNULL obj,
physical_address_t start, uint64 length, uint8 value);
exception_type_t (*read)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
uint64 addr, buffer_t data,
ram_operation_flags_t flags);
exception_type_t (*write)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
uint64 addr, bytes_t data,
ram_operation_flags_t flags);
exception_type_t (*touch)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
uint64 addr, uint64 size,
read_or_write_t rw,
ram_operation_flags_t flags);
uint64 (*size)(conf_object_t *NOTNULL obj);
};
#define RAM_INTERFACE "ram"
#define ROM_INTERFACE "rom"
typedef ram_interface_t rom_interface_t;
- Execution Context
- Cell Context for all methods.
- Description
- The
riscv_coprocessor interface makes it possible for RISC-V
processors to read and write Control and Status Registers (CSRs) like
mtime
SIM_INTERFACE(riscv_coprocessor) {
uint64 (*read_register)(conf_object_t *obj, uint64 number);
void (*write_register)(conf_object_t *obj, uint64 number, uint64 value);
};
#define RISCV_COPROCESSOR_INTERFACE "riscv_coprocessor"
- Execution Context
- Cell Context for all methods.
- Description
- The
riscv_custom_csr interface lets other Simics objects
implement custom CSR-registers and get callback for each access.
For the methods below, cpu is the RISC-V CPU model that is
extended and ext_obj is the extension object.
The register_csr method registers a custom CSR at
csr_address.
The arguments name and description are for
disassembly and int_register interface.
The argument access is the function implementing the CSR access.
Return true if CSR is successfully registered.
typedef enum {
/* Access through csr/csri instruction */
Riscv_CSR_Instruction_Access = Sim_Gen_Spr_Instruction_Access,
/* Access through attribute */
Riscv_Attribute_Access = Sim_Gen_Spr_Attribute_Access,
/* Access through int_register_interface */
Riscv_Int_Register_Access = Sim_Gen_Spr_Int_Register_Access,
} riscv_csr_access_type_t;
typedef uint64 (*riscv_csr_access_cb_t)(conf_object_t *obj,
conf_object_t *cpu,
uint32 csr_address,
uint64 value,
uint64 write_mask,
riscv_csr_access_type_t type);
The register_reset method registers a reset callback for the
extension. The reset_func callback will be called in connection
with the core CPU reset flow.
typedef uint64 (*riscv_reset_cb_t)(conf_object_t *obj,
conf_object_t *cpu);
SIM_INTERFACE(riscv_custom_csr) {
bool (*register_csr)(conf_object_t *cpu,
conf_object_t *ext_obj,
uint32 csr_address,
const char *name,
const char *description,
riscv_csr_access_cb_t access);
void (*register_reset)(conf_object_t *cpu,
conf_object_t *csr_obj,
riscv_reset_cb_t reset_func);
};
#define RISCV_CUSTOM_CSR_INTERFACE "riscv_custom_csr"
- Execution Context
- Global Context for all methods.
- Description
- RISC-V Internal interface.
SIM_INTERFACE(riscv_imsic) {
// GEILEN
uint32 (*num_guest_files)(conf_object_t *obj);
// id is either one of the standard files, machine or supervisor,
// or one of the guest files (vgein).
uint64 (*read_irq_file)(conf_object_t *obj, riscv_imsic_file_id_t id, uint32 offset);
uint64 (*read_and_write_irq_file)(conf_object_t *obj, riscv_imsic_file_id_t id,
uint32 offset, uint64 new_value, uint64 mask);
uint64 (*read_xtopei)(conf_object_t *obj, riscv_imsic_file_id_t id);
uint64 (*read_and_write_xtopei)(conf_object_t *obj, riscv_imsic_file_id_t id,
uint64 value, uint64 mask);
};
#define RISCV_IMSIC_INTERFACE "riscv_imsic"
- Execution Context
- Cell Context for all methods.
- Description
- The
riscv_instruction_action interface helps with
implementing semantics for user defined instruction.
The cpu argument in all methods below is the processor object
implementing this interface.
X registers
read_X_register return the current value of X register number.
write_X_register updates the value of X register number to
value.
To help with disassembly name_X_register returns the name of the X
register number.
Control and status registers, CSRs
These accesses are not seen as instruction accesses, all access checks are
bypassed and no exception will be thrown.
read_CSR returns current value of the CSR at address.
write_CSR updates the value of the CSR at address to
value. Not all bits of all CSRs is writable.
Memory accesses using logical address
A logical address is passed through MMU based on current mode. This means that
an access can raise exception for page fault or illegal access.
read_memory returns a value of size> bytes zero extended to
64 bits from memory at address/
write_memory writes size bytes to memory at address.
Both read_memory and write_memory can raise exception for unaligned data access if
the core does not support unaligned accesses.
load_memory_buf loads buf.len bytes from address
to buf.
store_memory_buf writes buf.len bytes from buf to
address.
These methods do not raise exception for unaligned accesses, instead large and/or
unaligned accesses are broken down to multiple smaller aligned accesses.
Other
get_current_cpu_mode returns current cpu mode.
raise_exception raises exception with code put in th xCAUSE CSR
and tval put in the xTVAL CSR.
SIM_INTERFACE(riscv_instruction_action) {
uint64 (*read_x_register)(conf_object_t *cpu, uint32 number);
void (*write_x_register)(conf_object_t *cpu, uint32 number, uint64 value);
const char * (*name_x_register)(conf_object_t *cpu, uint32 number);
uint64 (*read_csr)(conf_object_t *cpu, uint32 address);
void (*write_csr)(conf_object_t *cpu, uint32 address, uint64 value);
// Logical address
uint64 (*read_memory)(conf_object_t *cpu, uint64 address,
uint32 size);
void (*write_memory)(conf_object_t *cpu, uint64 address,
uint32 size, uint64 value);
void (*load_memory_buf)(conf_object_t *cpu, uint64 address, buffer_t buf);
void (*store_memory_buf)(conf_object_t *cpu, uint64 address, bytes_t buf);
riscv_cpu_mode_t (*get_current_cpu_mode)(conf_object_t *cpu);
void (*raise_exception)(conf_object_t *cpu, uint64 code, uint64 tval);
};
#define RISCV_INSTRUCTION_ACTION_INTERFACE "riscv_instruction_action"
- Execution Context
- Threaded Context for all methods.
Must be only called from within an instruction emulation callback registered
using the cpu_instruction_decoder interface.
- Description
- The
riscv_signal_sgeip interface makes it possible to signal
Supervisor Guest External (SGE) interrupts with a corresponding vgein.
This is used together with an IMSIC and signaled from the IMSIC.
SIM_INTERFACE(riscv_signal_sgeip) {
void (*signal_raise)(conf_object_t *NOTNULL obj, uint64 vgein);
void (*signal_lower)(conf_object_t *NOTNULL obj, uint64 vgein);
};
#define RISCV_SIGNAL_SGEIP_INTERFACE "riscv_signal_sgeip"
- Execution Context
- Cell Context for all methods.
- Description
- Currently Simics internal.
typedef enum {
Stop_Bits_1,
Stop_Bits_1p5,
Stop_Bits_2
} stop_bits_t;
typedef enum {
Parity_None,
Parity_Even,
Parity_Odd
} parity_mode_t;
SIM_INTERFACE(rs232_console) {
/* Set line parameters */
void (*set_baudrate)(conf_object_t *obj, int rate, int commit);
void (*set_data_bits)(conf_object_t *obj, int bits, int commit);
void (*set_stop_bits)(conf_object_t *obj, stop_bits_t stop_bits,
int commit);
void (*set_parity_mode)(conf_object_t *obj, parity_mode_t parity_mode,
int commit);
/* Flow control lines */
void (*set_dtr)(conf_object_t *obj, int status);
void (*set_rts)(conf_object_t *obj, int status);
/* Break */
void (*set_break)(conf_object_t *obj, int status);
};
#define RS232_CONSOLE_INTERFACE "rs232_console"
- Execution Context
- Cell Context for all methods.
- Description
- Currently Simics internal.
SIM_INTERFACE(rs232_device) {
/* Flow control lines */
void (*cts)(conf_object_t *obj, int status);
void (*dsr)(conf_object_t *obj, int status);
/* Ring indicator */
void (*ring)(conf_object_t *obj, int status);
/* Carrier detect */
void (*carrier)(conf_object_t *obj, int status);
/* Break */
void (*got_break)(conf_object_t *obj);
/* Frame error */
void (*got_frame_error)(conf_object_t *obj);
};
#define RS232_DEVICE_INTERFACE "rs232_device"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(sata) {
void (*receive_fis)(conf_object_t *obj, const bytes_t fis);
};
#define SATA_INTERFACE "sata"
This interface is implemented by SATA objects that provide
an interface for serial data delivery.
This interface can be used in both direction in SATA communication.
The receive_fis function is used by a device to send
a SATA FIS to the SATA controller(HBA). The same function is used
when sending a SATA FIS from HBA to SATA device. The FIS should be
a bytes_t containing a complete SATA FIS.
Different types of FIS may have different length. Please follow
SATA specification when determine the length and content of the FIS.
- Execution Context
- Cell Context for all methods.
- Description
- The
scale_factor_listener interface is used for
modeling changes in scale factors. It is mainly used by the
frequency_bus device, to allow an external device to
affect how much the bus scales its input frequency.
The scale_factor_listener has exactly the same
semantics as the frequency_listener interface, the
two interfaces only differ in convention: The parameters to
scale_factor_listener.set() are typically a scale factor
rather close to 1, while the parameters of
frequency_listener represent a base frequency in Hz,
which is typically significantly larger than 1000000.
See the documentation on the frequency_listener
interface for more information.
SIM_INTERFACE(scale_factor_listener) {
void (*set)(conf_object_t *NOTNULL obj, uint64 numerator,
uint64 denominator);
};
#define SCALE_FACTOR_LISTENER_INTERFACE "scale_factor_listener"
- Execution Context
- Cell Context for all methods.
- Description
- Interface used to connect serial devices together. It can be implemented
both by devices such as UARTs and text consoles, and by links.
A character (byte) is sent with the write() function;
obj is the receiving device or link, and value is
either a data byte, or the out-of-band value TTY_ABORT.
The receiver will return the number of characters accepted; i.e. 1 on
success and 0 if it could not handle the new byte. If the receiver returns
0, it must later call receive_ready() in the sender's
serial_device interface to signal that new bytes can now be
accepted. A serial device must handle the case where the
receive_ready() function is called although it has no more bytes
to send.
#define TTY_ABORT 0x100
SIM_INTERFACE(serial_device) {
int (*write)(conf_object_t *obj, int value);
void (*receive_ready)(conf_object_t *obj);
};
#define SERIAL_DEVICE_INTERFACE "serial_device"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(serial_peripheral_interface_master) {
void (*spi_response)(conf_object_t *obj, int bits, dbuffer_t *payload);
};
#define SERIAL_PERIPHERAL_INTERFACE_MASTER_INTERFACE \
"serial_peripheral_interface_master"
The serial_peripheral_interface_master interface is
implemented by all SPI master devices. The interface contains a
single function spi_response, called by the slave device
in response to a spi_request call. The parameters
bits and payload have the same
meaning as in the spi_request call, and a SPI response
should always have the same length in bits as the corresponding request.
- SEE ALSO
-
serial_peripheral_interface_slave_interface_t
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(serial_peripheral_interface_slave) {
void (*spi_request)(conf_object_t *obj, int first, int last,
int bits, dbuffer_t *payload);
void (*connect_master)(conf_object_t *obj, conf_object_t *master,
const char *port,
serial_peripheral_interface_flags_t flags);
void (*disconnect_master)(conf_object_t *obj, conf_object_t *master);
};
#define SERIAL_PERIPHERAL_INTERFACE_SLAVE_INTERFACE \
"serial_peripheral_interface_slave"
The serial_peripheral_interface_slave interface is
implemented by all SPI slave devices.
The connect_master and disconnect_master
functions are used to select which master device is connected. At
most one master device can be connected to a slave device at once.
The flags parameter to connect_master
should be set according to the documentation of the
serial_peripheral_interface_flags_t type.
An SPI transfer consists of a number of consecutive calls to the
spi_request function. The parameters
first and last represent the rise and
fall of the Slave Select (SS) pin: first is
true on the first spi_request call of a
transfer, while last is true on the
last call of a transfer.
The bits and payload parameters
describe the data sent by the master device. bits
defines the number of bits to send, while payload
defines the data to transfer. The size of the
payload buffer should be ceil(bits / 8)
bytes. The first byte corresponds to the first 8 sent bits, and the
least significant bit in each byte corresponds to the first sent
bit. For example, the 11-bit sequence (first) 11011111101
(last) will be represented as two bytes, 0xfb followed by
0x5.
- SEE ALSO
-
serial_peripheral_interface_master_interface_t,
serial_peripheral_interface_flags_t
- Execution Context
- Cell Context for all methods.
- Description
- The
signal interface is for modeling a logical signal, such
as a reset or interrupt. Signals are always active high in Simics with
respect to their function. This may not correspond to the actual electrical
level in a real system.
A signal connection has one initiator and one target object, where the
initiator calls methods the interface implemented by the target.
The initiator object should have a configuration attribute that pointing to
the target object or to an interface port of the target. This attribute,
like all other attributes representing object connections, should be of the
object kind, or a list of two entries where the first is
an object and the second a string representing the name of the port.
The initiator should call signal_raise() to raise the signal
level to its active level in the target. Once raised, the same initiator may
not call signal_raise() again without an intervening call to
signal_lower(). Similarly, an already low signal may not be
lowered again by a signal_lower() call from the same initiator.
The two functions represent the rising and the falling edge of the signal.
The target should handle the case where a signal is lowered directly after
it has been raised and treat this call sequence as a valid pulse even within
a single clock cycle. The target should also allow the signal to remain
raised for some time before it is lowered.
While a target is disconnected, the input signal level is assumed to be low.
When an initiator connects to a target by hot plugging,
signal_raise() should be called if the output signal from the
initiator was high. If the signal was low, then no function in the target
should be called.
If the signal level is high on disconnect, then the initiator has to call
signal_lower() before disconnecting from the target. Connect and
disconnect is typically done by changing the attribute in the initiator
that identifies the target object.
When an initiator is reset, it should call signal_lower() if the
actual hardware also lowers the output signal on a reset. The target, on the
other hand, should not reset its remembered value of the input.
When a connection attribute is restored from a checkpoint or during reverse
execution, no function should be called in the signal
interface of the target since the actual signal level does not change. The
attribute setter code can distinguish between hot-plugging and state
restoring by using SIM_object_is_configured() and
SIM_is_restoring_state. See the latter of the two for more
documentation.
When an object is first created and the initial signal level is high, the
initiator has to call the signal_raise() function in the target.
This can not be done earlier than in finalize_instance (C/C++) or
in post_init() (DML) since the target has to be fully configured.
Again, this should not be done when restoring a checkpoint.
There must only be a single initiator connected to a target, with the
exception of the signal-bus that may have several initiators.
A target that needs more than one input signal should use ports to implement
several signal interfaces.
SIM_INTERFACE(signal) {
void (*signal_raise)(conf_object_t *NOTNULL obj);
void (*signal_lower)(conf_object_t *NOTNULL obj);
};
#define SIGNAL_INTERFACE "signal"
- Execution Context
- Cell Context for all methods.
- Description
- The
simple_dispatcher interface is used for
subscribing to changes of some monitored state. The interface is
currently used for subscribing to changes in frequencies and to
changes in frequency scale factors, via the interfaces
frequency_listener and
scale_factor_listener, respectively.
A device subscribes with the subscribe function. Before
this function returns, it should send a signal to the calling
object, telling the current state. After this, signals should be
sent whenever the monitored state changes.
The function unsubscribe should be used to unsubscribe
from monitored changes. A listener may not subscribe or unsubscribe
twice on the same port.
SIM_INTERFACE(simple_dispatcher) {
void (*subscribe)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL listener,
const char *listener_port);
void (*unsubscribe)(conf_object_t *NOTNULL bus,
conf_object_t *NOTNULL listener,
const char *listener_port);
};
#define SIMPLE_DISPATCHER_INTERFACE "simple_dispatcher"
- Execution Context
- Global Context for all methods.
- Description
- A device calls interrupt() to logically raise an interrupt and
interrupt_clear() to lower an interrupt.
The first argument is the object to interrupt, usually a cpu. The
integer argument to both functions may indicate an interrupt level
or interrupt pin depending on the receiving device.
On ARM the integer argument indicates whether the interrupt is normal or
fast, by being either ARM_INT_IRQ or ARM_INT_FIQ defined by the ARM API
(by including <simics/arch/arm.h>).
Note:
Obsoleted by the signal interface.
SIM_INTERFACE(simple_interrupt) {
void (*interrupt)(conf_object_t *NOTNULL obj, int value);
void (*interrupt_clear)(conf_object_t *NOTNULL obj, int value);
};
#define SIMPLE_INTERRUPT_INTERFACE "simple_interrupt"
- Execution Context
- Cell Context for all methods.
- Description
- This interface allows a user to keept track of System Management Mode
switches in the processor.
The register_smm_enter_before_cb registers a callback of type
smm_switch_cb_t that will be called before the processor
enters System Management Mode.
The register_smm_enter_after_cb registers a callback of type
smm_switch_cb_t that will be called after the processor
has entered System Management Mode.
The register_smm_leave_before_cb registers a callback of type
smm_switch_cb_t that will be called before the processor
leaves System Management Mode.
The register_smm_leave_after_cb registers a callback of type
smm_switch_cb_t that will be called after the processor
has left System Management Mode.
The callback in all cases looks like this:
This callback type is used by the
smm_instrumentation_subscribe to implement instrumentation.
typedef void (*smm_switch_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
lang_void *user_data);
The obj argument is the user object that registered the
callback, or NULL if no such object exists.
The cpu argument is the processor that enters/leaves System
Management Mode.
The user_data argument is the callback user data, passed to the
register methods.
- Execution Context
- Global Context for all methods.
- Description
SIM_INTERFACE(sparc_v8) {
uint64 (*read_window_register)(conf_object_t *cpu, int window, int reg);
void (*write_window_register)(conf_object_t *cpu,
int window, int reg, uint64 value);
void (*power_down)(conf_object_t *cpu);
};
#define SPARC_V8_INTERFACE "sparc_v8"
SPARC V8 specific functions.
This interface is implemented by SPARC V8 processors to provide
various functionality that is specific for this class of processors.
The read_window_register and write_window_register
functions can be used to access registers in any register window.
The register number when accessing windowed registers is 0 - 7 for accesses
to the global registers, 8 - 15 for the out registers of the selected
window, 16 - 23 for the local registers, and 24 - 31 for the in registers.
The power_down function is used to command the processor to enter
power down mode. During power down mode, the processor will not execute any
instructions, it will instead fast forward the execution to the next event.
If the event is an external interrupt the power down mode is exited and
execution resumed, in other cases the event will be handled and the
processor will remain in power down mode and fast forward to the next event.
One use for the power_down function is for example to have an
external device such as an memory mapped PMU force the processor into power
down mode.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(sparc_v8_ecc_fault_injection) {
void (*inject_instr_access_exception)(conf_object_t *cpu);
void (*inject_data_access_exception)(conf_object_t *cpu);
void (*inject_reg_access_error)(conf_object_t *cpu);
};
#define SPARC_V8_ECC_FAULT_INJECTION_INTERFACE "sparc_v8_ecc_fault_injection"
Support the injection of uncorrectable ECC faults. It can be used to
inject (1) V8_Exc_Data_Access_Exception,
(2) V8_Exc_Instruction_Access_Exception, and
(3) V8_Exc_R_Register_Access_Error. The functions in this interface
can only be called by breakpoint callback functions. Once an ecc
fault is injected, new ecc faults can not be injected until the current
one is handled.
The inject_data_access_exception plants an
V8_Exc_Data_Access_Error for memory access on a location. The fault is
injected when the breakpoint callback function of the location is called.
The inject_instr_access_exception plants an
V8_Exc_Instruction_Access_Exception for an instruction, and this fault is
injected when the breakpoint callback function of the instruction location
is called.
The inject_data_access_exception is used for injecting
V8_Exc_R_Register_Access_Error for a register access. It is right now not
implemented.
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(spr) {
void (*register_user_handlers)(
conf_object_t *cpu,
int64 spr_number,
gen_spr_user_getter_func_t getter,
lang_void *user_getter_data,
gen_spr_user_setter_func_t setter,
lang_void *user_setter_data,
int privilege_checks);
void (*unregister_user_handlers)(
conf_object_t *cpu,
int64 spr_number);
void (*set_target_value)(
conf_object_t *cpu,
uint64 value);
void (*stash_value)(
conf_object_t *cpu,
int64 spr_number,
uint64 value);
uint64 (*fetch_value)(
conf_object_t *cpu,
int64 spr_number);
gen_spr_ret_t (*default_getter)(
conf_object_t *cpu,
int64 spr_number,
gen_spr_access_type_t type);
gen_spr_ret_t (*default_setter)(
conf_object_t *cpu,
int64 spr_number,
uint64 value,
gen_spr_access_type_t type);
const char *(*get_name)(
conf_object_t *cpu,
int64 spr_number);
int64 (*get_number)(
conf_object_t *cpu,
const char *spr_name);
};
#define SPR_INTERFACE "spr"
The register_spr_user_handlers function will register user
implemented get and set functions that will be called every time a
read or write access is made to the SPR with number spr.
The getter and setter function is of the
following type:
typedef gen_spr_ret_t (*gen_spr_user_getter_func_t)(
conf_object_t *cpu,
int64 spr_number,
gen_spr_access_type_t type,
lang_void *user_data);
The type parameter in the get and set functions is one of
the following, depending on where from the access originated:
typedef enum {
/* Access from a mfspr/mtspr instruction */
Sim_Gen_Spr_Instruction_Access,
/* Access through attribute */
Sim_Gen_Spr_Attribute_Access,
/* Access through int_register interface */
Sim_Gen_Spr_Int_Register_Access,
/* For compatibility with former PPC-only implementation */
Sim_PPC_Spr_Instruction_Access = Sim_Gen_Spr_Instruction_Access,
Sim_PPC_Spr_Attribute_Access = Sim_Gen_Spr_Attribute_Access,
Sim_PPC_Spr_Int_Register_Access = Sim_Gen_Spr_Int_Register_Access
} gen_spr_access_type_t;
Both the get and the set functions must return one of these enum values:
typedef enum {
Sim_Gen_Spr_Ok, /* SPR access was OK */
Sim_Gen_Spr_Illegal, /* SPR access should trigger illegal insn exc */
Sim_Gen_Spr_Privilege, /* SPR access should trigger privilege exc */
Sim_Gen_Spr_Processor_Sleeps, /* SPR access suspends the processor */
/* For compatibility with former PPC-only implementation */
Sim_PPC_Spr_Ok = Sim_Gen_Spr_Ok,
Sim_PPC_Spr_Illegal = Sim_Gen_Spr_Illegal,
Sim_PPC_Spr_Privilege = Sim_Gen_Spr_Privilege
} gen_spr_ret_t;
If privilege_checks is not zero, Simics will do privilege
checks when a mfspr/mtspr instruction is executed. If this does not produce
the desired results, you can register the SPR handlers with
privilege_checks set to zero, and do you own checks in your
handlers.
The function unregister_spr_user_handlers will remove any
registered user handlers for a particular SPR.
The function spr_set_target_value should be called from the get
function. The value will be written to the target register
for instruction accesses, and returned for attribute and int register
interface accesses. If this function is not called, the target register is
not changed for instruction accesses (and the mfspr thus acts as a nop).
The functions spr_stash_value and spr_fetch_value can
be used to store a SPR value in the processor. This is useful if only the
getter (or only the setter) has been overridden with a user handler.
Sometimes it may be desirable to let the processor take care of the access.
The functions spr_default_getter and
spr_default_setter exist for this purpose.
The function spr_get_name takes spr_number
as parameter and returns the name of the SPR.
The function spr_get_number takes the spr_name
and returns the SPR number, or -1 if the register does not exist.
Note that the following registers cannot be overridden with user handlers:
xer, lr and ctr.
- Execution Context
register_user_handlers |
Global Context |
unregister_user_handlers |
Global Context |
set_target_value | Cell Context |
stash_value | Cell Context |
fetch_value | Cell Context |
default_getter | Cell Context |
default_setter | Cell Context |
get_name | Cell Context |
get_number | Cell Context |
- Description
- The
telemetry interface is used to fetch telemetry
data.
A model implements one or more telemetry-classes.
These are identified by an identifier (class ID) and a name.
The telemetries also has a name and an identifier (telemetry ID).
This layout forms a two level hierarchy with classes and their telemetries.
The class and telemetry ID's are represented as integers and must be part of a
contiguous range starting from zero, i.e., the hierarchy can be viewed as a table
with telemetries, where the row numbers (>= 0), represents the class ID's, and the
column numbers (>=0) represents the telemetry ID's.
For unknown ID's NULL should be returned.
Both telemetry_class_id and telemetry_id can be enumerated using the functions
get_telemetry_class_name and get_telemetry_name by starting with an ID
of zero and go upp until NULL is returned.
A model should not log an error when an invalid ID is presented (but logging
info on level 3 makes sense for debug purposes).
Error handling for missing expected telemetry IDs should be handled in the model
requesting and retrieving the telemetry value.
The get_telemetry_class_id function returns the telemetry_class_id
for the telemetry class with name telemetry_class_name.
If no telemetry class with that name is found or that telemetry class is not enabled
a negative number is returned.
The get_telemetry_class_name returns the name of the corresponding
telemetry_class_id. If no telemetry class is found with that id the value
NULL is returned.
The get_telemetry_class_description can return a description string for the
telemetry_class_id. If no telemetry class is found with that id the value
NULL is returned.
The get_telemetry_id function returns the telemetry_id for the telemetry
with name telemetry_name belonging to telemetry_class_id.
If no telemetry with that name is found in the telemetry class a negative number is
returned.
The get_telemetry_name returns the name of the corresponding
telemetry_id belonging to telemetry_class_id. If no telemetry
with that id is found in the telemetry class the value NULL is returned.
The get_telemetry_description can return a description string for the
telemetry_id belonging to telemetry_class_id. If no telemetry
with that id the value is found NULL is returned.
The get_value function returns the value for the telemetry_id
within telemetry_class_id.
Note all known telemetry_classes are not always enabled in all models,
i.e. get_telemetry_class_name can return a valid name for some
telemetry_class_id but get_telemetry_id on that name may still
return an invalid identifier if that telemetry_class is not enabled in the model.
Note that the identifiers may vary between invocations of the model and must not be
stored between runs.
The command list-telemetry-classes can be helpful while developing with
the telemetry-interface.
typedef int telemetry_class_id_t;
typedef int telemetry_id_t;
SIM_INTERFACE(telemetry) {
telemetry_class_id_t (*get_telemetry_class_id)(conf_object_t *obj,
const char *telemetry_class_name);
const char *(*get_telemetry_class_name)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id);
const char *(*get_telemetry_class_description)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id);
telemetry_id_t (*get_telemetry_id)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id,
const char *telemetry_name);
const char *(*get_telemetry_name)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id,
telemetry_id_t telemetry_id);
const char *(*get_telemetry_description)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id,
telemetry_id_t telemetry_id);
attr_value_t (*get_value)(conf_object_t *obj,
telemetry_class_id_t telemetry_class_id,
telemetry_id_t telemetry_id);
};
#define TELEMETRY_INTERFACE "telemetry"
- Execution Context
- Global Context for all methods.
- Description
- The
transaction_translator interface is implemented by
objects which would like to inspect and/or modify transactions
before forwarding them to devices or address spaces. In Simics documentation,
such objects are usually called translator objects or, simply, translators.
In comparison with the simpler translator interface,
the transaction_translator interface provides
an opportunity to inspect/modify transactions. We recommend
using the translator interface when the additional
functionality is not needed.
The interface has one method called translate. The arguments
passed to this method describe the access and thus allow
a translator to perform a proper translation. Here is a short description of
the translate method's parameters:
- addr is an address of the access;
- access is a bitmask specifying all requested
access types;
- t is a transaction;
- callback is a callback that should be called by
the object implementing the interface;
- data should be passed to callback
as it is when the callback is invoked by the translator object.
All these arguments are described in detail below.
The transactions done by the translators may be cached by Simics.
To ensure efficient flushing of Simics internal caches we recommend
that the objects implementing the transaction_translator
interface implement also the translation_flush interface.
The absence of the translation_flush interface may lead to
a substantial decrease of simulation speed.
Whenever a previously returned translation becomes invalid the translator
objects are expected to use either SIM_map_target_flush
(preferably) or SIM_translation_changed function to ensure that
Simics will flush any cached translations. Please refer to the documentation
of these functions for the information about how they should be used.
An object implementing the transaction_translator interface
should invoke callback passing to it tree arguments:
translation, transaction
and data. The translation argument
describes the translation that was done, i.e. the transaction destination.
Please refer to the translation_t documentation
for the complete description.
The transaction argument is either the original
transaction passed to the transaction_translator interface
or, if a translator object wants to append atoms to the t
transaction, a new transaction created via transaction chaining.
The transaction chaining is described in detail in the "Transaction Chaining"
chapter of the Model Builder's User Guide. Finally, the
data argument is a parameter which should be passed as it is
when callback is invoked by the translator object.
Simics will report an error if a translator object doesn't invoke
callback from the translate method
of the transaction_translator.
If it is needed, a translator may route transactions based on the value of
certain transaction's atoms. The initiator atom
is a good example of such an atom. Please note that not all atoms are suited
for routing transactions based on their value. This should be checked
in the documentation for the specific atom.
The callback function returns transaction completion status.
This status should be usually returned as it is by the translate
method. The status value is also needed in the case when a translator object
appends atoms via transaction chaining with a non-zero
completion atom. In that case the returned status should be used
when the SIM_monitor_chained_transaction function is called.
Please note that memory accesses in Simics are not always issued with
the transactions of the transaction_t type.
For example, memory access can be done with the use of
the legacy generic_transaction_t type.
One more such example is lookup accesses which are done
via the direct_memory_lookup interface. All such accesses
are converted, if it is needed, and presented to the translator object via
the t parameter.
The access parameter specifies access
types in the form of a bitmask. Its value may be of interest
if a translation is done differently based on whether it is
a read, write or instruction fetch transaction. It can be noted
that a transaction itself already contains information
whether it is a read, write or an instruction fetch.
Usually, the access parameter just reflects that value.
However, for lookup accesses done via
the direct_memory_lookup interface
the access argument may have more bits set. If a translation
which are valid for all requested accesses cannot be performed, then
a null value should be set in the target of
the translation
argument passed to callback. In this case, the requestor is
expected to repeat the interface call with just a single bit set
in the access mask, e.g. Sim_Access_Read.
SIM_INTERFACE(transaction_translator) {
exception_type_t (*translate)(
conf_object_t *NOTNULL obj,
uint64 addr,
access_t access,
transaction_t *t,
exception_type_t (*NOTNULL callback)(
translation_t translation,
transaction_t *transaction,
cbdata_call_t data),
cbdata_register_t data);
};
#define TRANSACTION_TRANSLATOR_INTERFACE "transaction_translator"
- Execution Context
- Cell Context for all methods.
- Description
- The
translate interface is implemented by objects
that bridge between memory spaces.
Note:
There is the translator interface
which is a more restricted version
of the translate interface and should be used when possible.
It allows for better control of memory operations in the Simics core and can
therefore allow optimizations in the memory handling.
The return value of the translate method should be
a memory space, to which the
access is translated at the offset given by the physical address of
mem_op. If the return value is NULL, then the access
is translated to the default target provided in the configuration
(in a memory-space object, this is the 6th index,
target, of an entry in the map attribute).
If the translator marks mem_op as ignored before returning
NULL (using the function SIM_set_mem_op_ignore), then
the return value is ignored, and the transaction is instead terminated in
the translator and handled as an ordinary I/O access.
During a translation, the translator may modify the physical address of
mem_op, but may have no other side-effects. This is because
the caller can choose to cache the translation, in which case the translator
is bypassed in subsequent accesses.
The translator can use SIM_mem_op_ensure_future_visibility to
inhibit caching. Inhibiting caching can be useful for debugging, but
typically comes with a significant performance cost if there is RAM behind
the translator.
The addition of the direct_memory interface in Simics 5
results in new typical access patterns for the translate
interface. Where previously non-inquiry accesses of any size would result in
caching in initiating CPU objects, with the use of
direct_memory no such implicit caching ever takes
place. Instead, caching requests are separate and fed through the
translate method as inquiry accesses of the size that is intended
to be cached. This means that for a translate object to work
properly in a configuration with CPUs using direct_memory,
inquiry accesses must be properly handled. Routing such inquiry accesses to
non-memory, terminating them in the translator (which is not an allowed
behavior for a translate object), or calling
SIM_mem_op_ensure_future_visibility on them results in the
requesting CPU not being able to cache the requested memory region.
Using the translate interface in models is error prone
and usually not recommended unless all alternatives have been
exhausted. Explicit map and demap operations in a memory space avoid the
problems with translate interface implementation
correctness.
The usage of the translate interface is by necessity
less optimal than the usage of the memory-space class as
a call out from the simulation kernel should be made. That said when
the translate() method is called the transaction may be cached
in the STC if the user code does not explicitly block such caching, though
depending on a number of factors it may not always be cached. If the
translation is cached in the STC then performance is the same as with a
memory-space.
There are two reasons to use the translate interface rather than a simple
memory-space: 1) To implement something that the memory-space does not
support, such as different read and write translations, or manipulation of
the transaction, or 2) the translation is accessed infrequently, but updated
on most accesses.
Note:
Up to and including Simics 4.8, inhibiting caching for the instruction
stream did not prevent Simics-provided CPU models from caching. Models
therefore had to use flush or SIM_flush_cell_caches on
mapping changes to get the desired effect. This is no longer needed since
Simics 5.
Up to and including Simics 4.8, CPU models would cache memory for
transactions that pass through a translator in blocks that are larger than
the size provided in the transaction. This meant that a translator needed to
invalidate caches even if a translation changed that had strictly not passed
through the interface. For correctness, when any state that had an effect on
the translation logic changed, the translator would therefore invalidate all
mappings in all initiators, even for mappings that are outside of what has
passed through the translator. These types of workarounds are no longer
required since Simics 5.
SIM_INTERFACE(translate) {
conf_object_t *(*translate)(conf_object_t *NOTNULL obj,
generic_transaction_t *NOTNULL mem_op,
map_info_t mapinfo);
};
#define TRANSLATE_INTERFACE "translate"
- Execution Context
- Cell Context for all methods.
- Description
- The
translation_flush interface is an optional interface
which can be implemented by objects implementing the
transaction_translator or translator interface.
The interface is used
by Simics an optimization when Simics flushes its simulation caches.
Simics caches translations returned by translators but
quite often this cache needs to be invalidated, usually, due to
the changes in the memory map of the target system. In such cases
Simics may use this interface (if it is available) to do a fine-grain
invalidation of its simulation caches.
The translation_flush interface has one method
- flush_range - which will be called whenever there is
a need to flush simulation caches. The flush_range method
has the following parameters:
- base is the start of the region to flush;
- size is the size of the region to flush;
- access is a bitmask which specifies targets
for what access types should be flushed;
- default_target is only used for translators implementing
the translator interface and has the same as value as
the default_target parameter of
the translate method of the translator interface.
Please see the documentation of the translator for more
information about the parameter.
In the flush_range method, the translator object is expected
to flush all previously returned destinations of the translation requests
that the translator did for
the [base, base+size) range.
The flushing is done by calling the SIM_map_target_flush function
for the destination map target(s). If no translation requests were processed
to the range since the last invocation of the flush_range method
then no flushing is needed, and the flush_range may immediately
return the true value.
Please note that there is no need to call
the SIM_map_target_flush function for the translations which
were tagged with the Sim_Translation_Dynamic flag. Either,
no invalidation is needed for the parts of the range where nothing is mapped.
The return value is used to report whether the invalidation request
completed successfully, i.e. whether all calls to
the SIM_map_target_flush function succeeded (i.e. returned
the true value). If a call to
the SIM_map_target_flush fails (i.e.
the false value is returned) then
the flush_range function is expected to
return immediately with the false return value. If, for
some reason, the translator cannot invalidate all possible destinations,
then it can just immediately return the false value.
If false is returned, then all translations in the simulator
will typically be flushed, which could be an expensive operation.
- EXAMPLE
-
Here is pseudo code providing a sample implementation of
the flush_range method:
bool flush_range(obj, base, size, access):
for (map_target, start, size) in destinations(obj, base, size, access):
if not SIM_map_target_flush(map_target, start, size, access):
return False
return True
SIM_INTERFACE(translation_flush) {
bool (*flush_range)(
conf_object_t *obj,
uint64 base,
uint64 size,
access_t access,
const map_target_t *default_target);
};
#define TRANSLATION_FLUSH_INTERFACE "translation_flush"
- Execution Context
- Cell Context for all methods.
- Description
- The
translator interface is implemented by
objects which perform address translations or map
memory transactions to devices or address spaces.
The translate method takes a physical address
addr and returns a value of the type
translation_t which describes the translation for
an address range which must include addr. Please
refer to the translation_t documentation for a complete
description of the return value and more information regarding
the implementation of translator objects.
A translator can translate read transactions, write transactions
and instruction fetches differently. The access parameter
is set to all requested access types in the form of a bitmask.
The translator should return null in the target field
if a translation valid for all requested accesses cannot be performed;
when this happens, the requestor is expected to repeat the interface call
with just a single bit set in the access mask,
e.g. Sim_Access_Read.
The default_target parameter is a default target,
which can be NULL, of the translator mapping (i.e.,
the target field of the respective memory-space's
map entry specifying mapping).
SIM_INTERFACE(translator) {
translation_t (*translate)(conf_object_t *NOTNULL obj,
physical_address_t addr,
access_t access,
const map_target_t *default_target);
};
#define TRANSLATOR_INTERFACE "translator"
- Execution Context
- Cell Context for all methods.
- Description
- The
usb_interface_t interface is implemented by all
USB hosts. USB devices use the interface to communicate with the
USB host. The interface is Simics internal, and may be changed in
future versions of Simics. It should not be used by user-defined
classes.
The connect_device() function is called by the USB device to
connect to the USB. The host returns the physical port to which the device
is connected, or -1 on connection error (for example, if all ports
are occupied). Parameter to connect_device() is the maximum
data speed for the USB device.
The disconnect_device() function is called by the USB device when
it wants to disconnect from the USB. The host returns 0 on success.
The complete_transfer() function is called by a USB device when
it has completed a transfer. Refer to the usb_device_t
interface documentation to know more about how a transfer is sent to the USB
device.
SIM_INTERFACE(usb) {
int (*connect_device)(conf_object_t *bus_obj,
conf_object_t *NOTNULL dev_obj,
usb_speed_t speed);
int (*disconnect_device)(conf_object_t *bus_obj,
conf_object_t *NOTNULL dev_obj);
void (*complete_transfer)(conf_object_t *bus_obj,
conf_object_t *NOTNULL dev_obj,
usb_transfer_t *NOTNULL transfer);
};
#define USB_INTERFACE "usb"
- Execution Context
| connect_device | Global Context |
| disconnect_device |
Global Context |
| complete_transfer | Cell Context |
- Description
- The
usb_device_interface_t interface is implemented
by all USB devices. It is used by the USB host to communicate with
the USB devices. The interface is Simics internal, and may be
changed in future versions of Simics. It should not be used by
user-defined classes.
The submit_transfer() function is used by the USB host controller
to send a new transfer to a USB device. Transfers are the basic means of
communication between the USB host controller and the USB devices. A
transfer contains all information needed to handle control, bulk, interrupt,
and isochronous transfers. A transfer to a USB device simply moves the
control from the USB host to the USB device. The USB device can then
decide when to send back any useful data to the USB host. The USB device
receives a pointer to the transfer to handle. It can either handle the
transfer immediately or send the transfer back later using the
complete_transfer() function in the
usb_interface_t interface, which is implemented by the USB
host.
The USB device must return USB_Transfer_Completed when it
handles the transfer immediately, i.e., it has filled the required fields in
the transfer structure. The USB device must return
USB_Transfer_Not_Ready for unfinished transfers, i.e., the
USB device does not have any interesting data to deliver at this point. The
isochronous and interrupt transfers contain a field indicating how long time
the USB host expects the USB device to wait before returning the
transfer. Note that it is just an indication on how often this transfer is
scheduled in the periodic list and USB devices can complete the transfers at
any time. A value of 0 means that the USB host does have any
expectations about the return time.
The abort_transfer() function tells the USB device to abort a
transfer previously issued by the USB host. The USB device should not call
the complete_transfer() function for a request that has been
aborted.
The reset() function is used by the USB host to reset the USB
device.
The USB host expects the device to return the same transfer pointer it
received when completing, i.e., the transfer pointer is used to identify
uniquely a transfer.
SIM_INTERFACE(usb_device) {
usb_transfer_completion_t (*submit_transfer)(conf_object_t *dev_obj,
usb_transfer_t *transfer);
void (*abort_transfer)(conf_object_t *dev_obj,
usb_transfer_t *transfer);
void (*reset)(conf_object_t *dev_obj);
};
#define USB_DEVICE_INTERFACE "usb_device"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is typically implemented by processors with interrupts
that have vectors and priorities supplied by their sources.
The set_level() method sets the interrupt level on the target
object; zero indicates that no interrupt is requested. The interrupt source
should implement the vectored_interrupt_source interface.
SIM_INTERFACE(vectored_interrupt) {
void (*set_level)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL source, int level);
};
#define VECTORED_INTERRUPT_INTERFACE "vectored_interrupt"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by interrupt sources that use the
vectored_interrupt interface.
The acknowledge() method is called to acknowledge a requested
interrupt of the given level on the interrupt target. It should return
an interrupt vector number, -1 if no vector is supplied, or -2 if
the object does not accept the acknowledgement.
SIM_INTERFACE(vectored_interrupt_source) {
int (*acknowledge)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL target, int level);
};
#define VECTORED_INTERRUPT_SOURCE_INTERFACE "vectored_interrupt_source"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is intended for implementing a FUSE request handler.
handle_request This method takes a FUSE request in req
. It then returns a buffer_t object with the FUSE response. The
caller of handle_request must free the data field in the returned buffer_t
object.
SIM_INTERFACE(virtiofs_fuse)
{
buffer_t (*handle_request)(conf_object_t * obj, bytes_t req);
};
#define VIRTIOFS_FUSE_INTERFACE "virtiofs_fuse"
- Execution Context
- Cell Context for all methods.
- Description
- The
vmp interface is used to control enabling of VMP and VMP
features from a user perspective. Models should use
x86_vmp_control for potential blocking of VMP.
This is an internal interface between VMP and the Simics Base package, and
it may change at any time without notice.
SIM_INTERFACE(vmp) {
bool (*class_has_support)(conf_object_t *obj);
bool (*host_support)(conf_object_t *obj);
bool (*compatible_config)(conf_object_t *obj);
bool (*enable)(conf_object_t *obj);
void (*disable)(conf_object_t *obj);
bool (*enabled)(conf_object_t *obj);
void (*set_threshold)(conf_object_t *obj, int threshold);
bool (*get_feature)(conf_object_t *obj, vmp_feature_t feature);
bool (*set_feature)(conf_object_t *obj, vmp_feature_t feature, bool val);
uint64 (*get_info)(conf_object_t *obj, vmp_info_t info);
};
#define VMP_INTERFACE "vmp"
- Execution Context
- Cell Context for all methods.
- Description
- This x86 specific interface allows a user to keept track of VMX mode
switches in the processor.
The register_vmx_mode_leave_cb registers a callback of type
vmx_mode_switch_cb_t that will be called before the processor
leaves a particular VMX mode.
The register_vmx_mode_enter_cb registers a callback of type
vmx_mode_switch_cb_t that will be called after the processor
enters a particular VMX mode.
The callback in both cases looks like this:
This callback type is used by the
vmx_instrumentation_subscribe to implements VMX mode switch
instrumentation.
typedef void (*vmx_mode_switch_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
vmx_mode_t mode,
physical_address_t vmcs_address,
lang_void *user_data);
The obj argument is the user object that registered the
callback, or NULL if no such object exists.
The cpu argument is the processor that switches VMX mode.
The mode that will be left or entered is passed in the
mode argument in the callback.
The different VMX modes are defined in the following type:
This enum is used to distinguish VMX modes. It is
used by the vmx_mode_switch_cb_t.
typedef enum {
Vmx_Off = 0,
Vmx_Root = 1,
Vmx_Non_Root = 2
} vmx_mode_t;
The vmcs_address argument specifies the Virtual Machine Control
Structure address that is currently being used. If not available, it will be
passed as (physical_address_t)(-1).
When leaving a mode and then entering another mode, the mode can actually be
reported as to be the same in certain situations. This is not a bug, it is a
consequent of how Simics is implemented. It would require a lot of extra code
to filter those out.
The user_data argument is the callback user data, passed to the
register methods.
SIM_INTERFACE(vmx_instrumentation_subscribe) {
cpu_cb_handle_t *(*register_vmx_mode_leave_cb)(
conf_object_t *cpu,
conf_object_t *connection,
vmx_mode_switch_cb_t cb,
lang_void *user_data);
cpu_cb_handle_t *(*register_vmx_mode_enter_cb)(
conf_object_t *cpu,
conf_object_t *connection,
vmx_mode_switch_cb_t cb,
lang_void *user_data);
};
#define VMX_INSTRUMENTATION_SUBSCRIBE_INTERFACE \
"vmx_instrumentation_subscribe"
- Execution Context
- Global Context for all methods.
- Description
- The x86 interface exports functionality used by several other objects to
interact with the processor. The set_pin_status function is used
to set/clear certain processor pins.
typedef enum {
Pin_Init,
Pin_Smi,
Pin_Nmi,
Pin_Ignne,
Pin_Mcerr,
Pin_Cmci
/* Do not add new pins. Instead, define individual signal ports */
} x86_pin_t;
The start_up function is used by the local APIC to bring the
processor obj out of the waiting for start-up IPI state, with a
start address of start_address.
The interrupt function tells the CPU that an interrupt is
waiting. The interrupt vector number is given by the ack callback
function. It is not allowed to call the ack callback during the
interrupt call itself. The data object should
implement the interrupt_cpu interface. Note that the
interrupt_cpu interface defines the ack function,
which should be the same as the ack argument. It is recommended
that new implementations does not use rely on the ack argument,
but rather looks up the callback through the interrupt_cpu
interface from the object given by the data argument. The
interrupt function returns 1 if the interrupt is accepted, and 0
if it is not accepted because there is already an interrupt queued up to be
processed. If 0 is returned, the caller should retry the call after one
step. It should wait one step since the handling of an interrupt takes one
step.
If a checkpoint was taken when an interrupt was waiting, the acknowledge
callback function can be recovered by looking up the
interrupt_cpu interface at the APIC object given in the
data parameter.
If the interrupt was cancelled before it was acknowledged, the
uninterrupt function is used. It is also called by the
acknowledge callback. Thus, each invocation of interrupt is
followed by exactly one call to uninterrupt at all times. The
ack parameter is unused and should be ignored. When the processor
is reset, it forgets a waiting interrupt so it is not necessary to call
uninterrupt during a reset.
The functions in the interrupt_ack interface provides almost
the same functionality as the interrupt and
uninterrupt functions in this interface. The only difference is
that the interrupt function in this interface returns 0 when the
interrupt cannot be handled which allows the device to retry later.
The has_pending_interrupt and has_waiting_interrupt
calls should return information about interrupts in progress. An interrupt
is said to be pending if it is acked by the processor and will be taken
before execution of the next instruction. An interrupt is waiting if the
logical interrupt line is high, but the interrupt has not yet been
acked. These functions are used for sanity checks by the APIC. The APIC
should keep track of posted interrupts by itself. These functions return 1
if an interrupt is pending/waiting, and 0 otherwise.
The logical_to_linear function returns the translated linear
address from the given logical address and segment register number. The
function uses the current content of control registers and segment registers
to calculate the linear address. The tagged return value is marked invalid
if no valid translation exists, for example if the passed logical address is
beyond the segment limit of the passed segment or if it is
non-canonical. The encoding of segment is 0 for ES, 1 for CS, 2
for SS, 3 for DS, 4 for FS, and 5 for GS.
The linear_to_physical function returns the physical address
corresponding to the given linear address. The function uses the
current content of control registers, TLBs and possibly page tables to
calculate the physical address. A return value of -1 signals that no valid
mapping exists.
enter_acpi_c2_state is called from the chipset power module to
request the CPU to enter an energy-saving state.
SIM_INTERFACE(x86) {
void (*set_pin_status)(conf_object_t *obj,
x86_pin_t pin, int status);
void (*start_up)(conf_object_t *obj, uint32 start_address);
int (*interrupt)(conf_object_t *obj,
int (*ack)(conf_object_t *obj),
conf_object_t *data);
void (*uninterrupt)(conf_object_t *obj,
int (*ack)(conf_object_t *obj));
int (*has_pending_interrupt)(conf_object_t *obj);
int (*has_waiting_interrupt)(conf_object_t *obj);
tagged_linear_address_t (*logical_to_linear)(conf_object_t *obj,
int segment,
logical_address_t addr);
physical_address_t (*linear_to_physical)(conf_object_t *obj,
data_or_instr_t d_or_i,
linear_address_t addr);
void (*enter_acpi_c2_state)(conf_object_t *obj);
};
#define X86_INTERFACE "x86"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used to query information about the
x86_access_type_t enum. The get_enum_name method
returns the C enum name for the access type. get_short_name
returns a corresponding short name. More than one access type may have the
same short name. The get_description returns a longer
description of the access type. The implicit function returns
true if the access type is considered implicit or false if it is considered
explicit. This information is used by the
cpu_instrumentation_subscribe interface to separate accesses
in the two different categories.
SIM_INTERFACE(x86_access_type) {
const char *(*get_enum_name)(conf_object_t *obj, x86_access_type_t at);
const char *(*get_short_name)(conf_object_t *obj, x86_access_type_t at);
const char *(*get_description)(conf_object_t *obj, x86_access_type_t at);
bool (*implicit)(conf_object_t *obj, x86_access_type_t at);
};
#define X86_ACCESS_TYPE_INTERFACE "x86_access_type"
- Execution Context
- Cell Context for all methods.
- Description
- The
x86_address_query interface is used to query information
about an address for the x86 architecture and should be used from a
cpu_memory_address_cb_t callback.
SIM_INTERFACE(x86_address_query) {
x86_seg_t (*segment)(
conf_object_t *cpu, address_handle_t *handle);
page_crossing_info_t (*get_page_crossing_info)(
conf_object_t *cpu, address_handle_t *handle);
};
#define X86_ADDRESS_QUERY_INTERFACE "x86_address_query"
The segment is used to get the segment register used in the
address calculation. The handle is the address handle passed to
cpu_memory_address_cb_t.
If the access crosses a page boundary the access will be split into two
calls. The get_page_crossing_info can be used to distinguish the
different cases from each other. The value returned is of type
page_crossing_info_t and is one of:
Sim_Page_Crossing_None (no crossing access),
Sim_Page_Crossing_First (first part of a crossing access),
Sim_Page_Crossing_Second (second part of a crossing access).
- Execution Context
- Cell Context for all methods, but must be called from a callback
receiving a handle of type
address_handle_t.
- Description
- The x86 cache flush interface is implemented by objects
which need to do some special handling when the cpu
flushes the cache.
The flush method is invoked when the cpu
executes an invd or a wbinvd instruction.
The writeback parameter is set for the later instruction.
SIM_INTERFACE(x86_cache_flush) {
void (*flush)(conf_object_t *obj, conf_object_t *cpu, bool writeback);
};
#define X86_CACHE_FLUSH_INTERFACE "x86_cache_flush"
- Execution Context
- Cell Context for all methods.
- Description
SIM_INTERFACE(x86_cpuid) {
cpuid_ret_t (*cpuid)(conf_object_t *obj, conf_object_t *cpu,
uint32 in_eax, uint32 in_ebx, uint32 in_ecx,
uint32 in_edx);
};
#define X86_CPUID_INTERFACE "x86_cpuid"
The CPUID interface makes it possible to customize responses to CPUID
requests. The cpuid method should set taken to nonzero if it
managed to handle the request, zero otherwise. When taken is non-zero,
then the returned values in out_a, out_b, out_c, and out_d will be
written to the first four general purpose registers.
Assigning external handlers to the leaf range reserved for MAGIC instruction
implementation has no effect, because the MAGIC implementation always takes
priority.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by CPUs and can be used to query the values
that would be returned by the CPUID instruction. The interface calculates
the return value both from built in default values and from any handlers
that would be installed using the
x86_cpuid interface.
This is a preliminary interface. Based on feedback, this interface can and
will be changed without regard for the usual ABI compatibility rules.
SIM_INTERFACE(x86_cpuid_query) {
cpuid_value_t (*cpuid_query)(conf_object_t *obj, uint32 leaf,
uint32 subleaf);
};
#define X86_CPUID_QUERY_INTERFACE "x86_cpuid_query"
- Execution Context
- Cell Context for all methods.
- Description
- The methods in this interface can be used to read or change the current
power state the CPU is in. A state value of 0 corresponds to C0, a value of
1 corresponds to C1, etc. HLT will be reported as state 1, substate 0.
MWAIT will reported based upon the eax hint, decoded as state = (eax[7:4] +
1) mod 16, substate = eax[3:0].
set_cstate will perform side-effects such as putting the
processor to sleep or waking it up, and call the registered cstate
listeners.
typedef struct {
uint32 state;
uint32 sub_state;
} x86_cstate_t;
SIM_INTERFACE(x86_cstate) {
x86_cstate_t (*get_cstate)(conf_object_t *cpu_obj);
void (*set_cstate)(conf_object_t *cpu_obj,
uint32 state, uint32 sub_state);
};
#define X86_CSTATE_INTERFACE "x86_cstate"
- Execution Context
- Cell Context for all methods.
- Description
- Objects registered in the CPU's cstate_listeners attribute will
be called via the notification method whenever the CPU's cstate
changes. Only changes caused by instruction execution or calls to the
x86_cstate.set_cstate function will trigger a notification, not
attribute accesses. See the
x86_cstate interface for how
the C-state is encoded in the parameters.
SIM_INTERFACE(x86_cstate_notification) {
void (*notification)(conf_object_t *listener, conf_object_t *cpu,
uint32 state, uint32 sub_state);
};
#define X86_CSTATE_NOTIFICATION_INTERFACE "x86_cstate_notification"
- Execution Context
- Cell Context.
- Description
- The interface provides insight into the Extended Page Table (EPT) address
translation performed by target processors for virtual machine operations.
It takes a result of the first level translation (the classical paging),
called a guest physical address, and returns matching host physical address.
The guest_physical_to_physical function translates a guest
physical address to a host physical address. The
cpu_mode argument sets the processor mode for the lookup.
Access type is defined by access. The function returns a
physical_block_t struct with valid bit and the
address. The host physical address is valid when the valid
flag is not 0. The function also returns block_start and
block_end. The start and end of a block has the same linear
mapping as the translated address. The range is inclusive, so block_end
should be the address of the last byte of the block. This information can
be used to figure out how often the function needs to be called for
traversing larger address ranges.
If the chosen processor's current mode does not use EPT translation,
the function should use the identity mapping between guest and host physical
addresses. An example of such situation would be an x86 processor outside
of VMX non-root mode or with EPT controls disabled.
To check if the processor's current VMCS state has EPT enabled,
is_ept_active function should be used.
SIM_INTERFACE(x86_ept) {
physical_block_t (*guest_physical_to_physical)(
conf_object_t *obj,
generic_address_t address,
x86_processor_mode_t cpu_mode,
access_t access);
bool (*is_ept_active)(conf_object_t* obj);
};
#define X86_EPT_INTERFACE "x86_ept"
- Execution Context
- Cell Context for all methods.
- Description
- The methods in this interface is used to raise exceptions
from the instrumentation replace or user decoder functionality (it is illegal
to invoke these methods from any other context). The
methods perform longjmps and do not return.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_exception) {
void (*DE_fault)(conf_object_t *cpu);
void (*BR_fault)(conf_object_t *cpu);
void (*UD_fault)(conf_object_t *cpu);
void (*NM_fault)(conf_object_t *cpu);
void (*DF_abort)(conf_object_t *cpu, const char *desc);
void (*TS_fault)(conf_object_t *cpu, uint16 sel);
void (*NP_fault)(conf_object_t *cpu, uint16 sel_vec, bool is_vec);
void (*SS_fault)(conf_object_t *cpu, uint16 sel);
void (*GP_fault)(conf_object_t *cpu, uint16 sel_vec, bool is_vec,
const char *desc);
void (*PF_fault)(conf_object_t *cpu, linear_address_t laddr,
uint32 ecode);
void (*MF_fault)(conf_object_t *cpu);
void (*AC_fault)(conf_object_t *cpu);
void (*XM_fault)(conf_object_t *cpu);
};
#define X86_EXCEPTION_INTERFACE "x86_exception"
- Execution Context
- The methods in this interface may only be called from
user decoder service routines.
- Description
- The
x86_exception_query interface is used to query information
about an exception for the x86 architecture and should be used from a
cpu_exception_cb_t callback.
SIM_INTERFACE(x86_exception_query) {
uint8 (*vector)(
conf_object_t *cpu, exception_handle_t *handle);
x86_exception_source_t (*source)(
conf_object_t *cpu, exception_handle_t *handle);
uint32 (*error_code)(
conf_object_t *cpu, exception_handle_t *handle);
};
#define X86_EXCEPTION_QUERY_INTERFACE "x86_exception_query"
The vector method is used to get the exception vector. The
source method is used to get the source of the exception and the
error_code method is used to get the error code of the exception.
- Execution Context
- Cell Context for all methods, but must be called from a callback
receiving a handle of type
exception_handle_t.
- Description
- The interface provides insight into the processor execution mode.
The get_execution_mode returns the current processor execution
mode. Note that several fields in the returned x86_execution_mode_t
structure can be non-zero simultaneously.
typedef struct x86_execution_mode {
uint64 ac:1,
seam:1,
sgx:1,
smm:1,
vmx_root:1,
vmx_non_root:1;
} x86_execution_mode_t;
SIM_INTERFACE(x86_execution_mode) {
x86_execution_mode_t (*get_execution_mode)(conf_object_t *obj);
};
#define X86_EXECUTION_MODE_INTERFACE "x86_execution_mode"
- Execution Context
- Cell Context for all methods.
- Description
- The
x86_instruction_query interface is used to query
additional information about an instruction for the x86 architecture and is a
complement to the cpu_instruction_query interface.
SIM_INTERFACE(x86_instruction_query) {
linear_address_t (*linear_address)(conf_object_t *cpu,
instruction_handle_t *handle);
};
#define X86_INSTRUCTION_QUERY_INTERFACE "x86_instruction_query"
The linear_address is used to get the linear address of the
instruction.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
receiving a handle of type
instruction_handle_t.
- Description
- The
x86_instrumentation_subscribe interface is an x86
specific complement to the cpu_instrumentation_subscribe
interface. It is implemented by processor objects that support
instrumentation. It has the same requirements as the
cpu_instrumentation_subscribe interface.
SIM_INTERFACE(x86_instrumentation_subscribe) {
cpu_cb_handle_t *(*register_mode_switch_cb)(
conf_object_t *cpu, conf_object_t *connection,
x86_mode_switch_cb_t cb,
lang_void *user_data);
cpu_cb_handle_t *(*register_illegal_instruction_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_instruction_decoder_cb_t cb,
cpu_instruction_disassemble_cb_t disass_cb,
lang_void *data);
};
#define X86_INSTRUMENTATION_SUBSCRIBE_INTERFACE \
"x86_instrumentation_subscribe"
The register_mode_switch_cb method is used to register a callback
that is called whenever the processor cpu changes execution
mode. The connection argument is the user object that
registers the callback. This object will be passed to the callback when it
is called. cb is the callback and user_data is user data
for the callback. The signature of the callback looks like this:
typedef void (*x86_mode_switch_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
x86_detailed_exec_mode_t mode,
lang_void *user_data);
The obj is the connection object that registered the
callback. new_mode argument contains the new mode. The possible
modes available are captured in the x86_detailed_exec_mode_t
type:
typedef enum {
X86_Detailed_Exec_Mode_Real_16,
X86_Detailed_Exec_Mode_Real_32,
X86_Detailed_Exec_Mode_V86,
X86_Detailed_Exec_Mode_Protected_16,
X86_Detailed_Exec_Mode_Protected_32,
X86_Detailed_Exec_Mode_Protected_64,
X86_Detailed_Exec_Mode_Compatibility_16,
X86_Detailed_Exec_Mode_Compatibility_32,
} x86_detailed_exec_mode_t;
The user_data is the user data associated with the callback.
register_illegal_instruction_cb lets a user to implement new
instructions. The cb argument is a callback function that will be
called every time Simics does not decode an instruction. Allows new x86
instructions to be implemented which otherwise cause illegal instruction
exception. Compared to register_instruction_decoder_cb method of
cpu_instrumentation_subscribe interface this interface cannot
change any instruction that correctly decodes according to the existing
instruction set architecture. From this callback the user can accept the
instruction or deny it. In most cases this only happens once per instruction
address since Simics usually caches decoding results in the internal
instruction cache. If the cache is flushed the callback may be called again.
This instrumentation feature (if used alone) does not prevent VMP execution
since illegal instructions cause exit while running inside VMP mode.
The callback signature looks like this:
typedef int (*cpu_instruction_decoder_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
decoder_handle_t *decoder_handle,
instruction_handle_t *iq_handle,
lang_void *user_data);
The instruction bytes are read by using the get_instruction_bytes
method of the cpu_instruction_query interface together with
the iq_handle. The returned value is of a
cpu_bytes_t type. To access the bytes use the data and
the size members in the returned value.
If the decoder requires more bytes (i.e., because the new instruction is
longer), a negative integer value should be returned by the cb
function, indicating the number of bytes needed. For example, if the
available bytes are 3 but the decoder need at least 4 bytes, -4 should be
returned. The callback will then be called again with more available bytes
(this can be repeated if the new instruction requires even more bytes at
this point). Note that requesting more data than actual needed can cause
spurious page faults if the data crosses a page boundary.
If the instruction is accepted by the callback a positive integer number
should be returned corresponding to the length of the instruction. In this
case the register_emulation_cb method of the
cpu_instruction_decoder interface should be called to set the
actual (user) function that Simics will call each time the instruction is
executed.
If the cb callback should ignore the instruction the number 0
should be returned. This means that any other registered decoder will have a
chance to decode the instruction. If no decoder accepts it, Simics will
generate illegal instruction exception.
The register_emulation_cb method also needs the
decoder_handle which is available in the dedoder callback. For
more information, see the documentation of the
cpu_instruction_decoder interface.
A disass_cb argument should also be passed to the
register_illegal_instruction_cb method. This function is called
every time Simics wants to disassemble an instruction. For every accepted
instruction a corresponding disassembly string should be returned by this
function. It has the following signature:
typedef tuple_int_string_t (*cpu_instruction_disassemble_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
generic_address_t addr,
cpu_bytes_t bytes);
obj is the object registering the
register_illegal_instruction_cb and cpu is the
processor disassembling the instruction. addr is the address of
the instruction in a generic form. This means that it is typically a
physical address or a logical address depending on the context of the
disassembling. The address can be used for offset calculations, i.e.,
displaying an absolute address instead of a relative one, for example in a
branch instruction. The bytes argument should be used to read
instruction bytes. The return value is of type
tuple_int_string_t and should be filled with the instruction
length and an allocated (e.g., malloc) string representing the disassembly
of the instruction. The ownership of the string is transferred to the
calling environment which will free it when it is no longer needed.
If too few bytes are passed for the instruction to be disassembled a
negative value should be returned for the length indicating the needed
bytes. The disass_cb is then called again with more bytes. If the
instruction is rejected a length of 0 should be returned and the string
should be set to NULL.
To remove the callback used one of the methods remove_callback or
remove_connection_callbacks in the
cpu_instrumentation_subscribe interface.
The callback can also be enabled and disabled with the corresponding methods
in the cpu_instrumentation_subscribe interface.
- Execution Context
- Global Context for all methods.
- Description
- The
x86_instrumentation_subscribe_v2 interface is an x86
specific complement to the cpu_instrumentation_subscribe
interface. It is implemented by x86 processor objects that support
instrumentation. It works in the same way as the
cpu_instrumentation_subscribe interface, and the methods
remove/enabled/disable_callback and
remove/enabled/disable_connection_callbacks in that interface
should be used to operate on callbacks in this interface as well, using the
cpu_cb_handle_t handle.
The v2 variant fixes some problems with the
x86_instrumentation_subscribe. In that interface, the
register_mode_switch_cb method was invoked when the new mode had
already been set up. This means that if you need to do some bookkeeping
when leaving a mode, that mode had already been switched out in the callback.
For instance, descriptor registers has already been changed.
This interface adds two methods to handle this,
register_mode_leave_cb and register_mode_enter_cb. The
leave variant is called when the processor still is located in the previous
mode, but about to enter a new mode, and the enter variant is called when
the processor has switched to the new mode (corresponds to the
register_mode_switch_cb in the old
x86_instrumentation_subscribe interface).
The register_illegal_instruction_cb works as in the
x86_instrumentation_subscribe interface.
SIM_INTERFACE(x86_instrumentation_subscribe_v2) {
cpu_cb_handle_t *(*register_mode_enter_cb)(
conf_object_t *cpu, conf_object_t *connection,
x86_mode_switch_cb_t cb,
lang_void *user_data);
cpu_cb_handle_t *(*register_mode_leave_cb)(
conf_object_t *cpu, conf_object_t *connection,
x86_mode_switch_cb_t cb,
lang_void *user_data);
cpu_cb_handle_t *(*register_illegal_instruction_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_instruction_decoder_cb_t cb,
cpu_instruction_disassemble_cb_t disass_cb,
lang_void *data);
};
#define X86_INSTRUMENTATION_SUBSCRIBE_V2_INTERFACE \
"x86_instrumentation_subscribe_v2"
- Execution Context
- Global Context for all methods.
- Description
- The
x86_memory_access interface is used to access memory
from user decoder service routines. If an exception condition
occurs, a longjmp is taken. The interface methods may only be invoked from
user decoder service routines.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_memory_access) {
uint64 (*read_logical)(
conf_object_t *cpu,
logical_address_t offs,
x86_seg_t seg,
unsigned len,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#if !defined(PYWRAP)
void (*read_logical_buf)(
conf_object_t *cpu,
logical_address_t offs,
x86_seg_t seg,
unsigned len,
void *p,
x86_processor_mode_t mode,
x86_access_type_t access_type,
x86_alignment_t alignment);
#endif
void (*write_logical)(
conf_object_t *cpu,
logical_address_t offs,
x86_seg_t seg,
unsigned len,
uint64 val,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#if !defined(PYWRAP)
void (*write_logical_buf)(
conf_object_t *cpu,
logical_address_t offs,
x86_seg_t seg,
unsigned len,
const void *p,
x86_processor_mode_t mode,
x86_access_type_t access_type,
x86_alignment_t alignment);
#endif
};
#define X86_MEMORY_ACCESS_INTERFACE "x86_memory_access"
- Execution Context
- The methods in this interface may only be called from
user decoder service routines.
- Description
- The
x86_memory_operation interface is used to access memory
from a user instruction. See the
cpu_instrumentation_subscribe and
cpu_instruction_decoder for more information. It is designed
to be more efficient than the x86_memory_access. If an
exception condition occurs, a longjmp is taken. The interface methods may
only be invoked from user instruction.
SIM_INTERFACE(x86_memory_operation) {
uint64 (*read_logical)(
conf_object_t *cpu,
x86_seg_t seg,
logical_address_t offs,
unsigned size,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#if !defined(PYWRAP)
void (*read_logical_buf)(
conf_object_t *cpu,
uint8 *dst,
x86_seg_t seg,
logical_address_t offs,
unsigned size,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#endif
void (*write_logical)(
conf_object_t *cpu,
uint64 val,
x86_seg_t seg,
logical_address_t offs,
unsigned size,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#if !defined(PYWRAP)
void (*write_logical_buf)(
conf_object_t *cpu,
const uint8 *src,
x86_seg_t seg,
logical_address_t offs,
unsigned size,
x86_processor_mode_t mode,
x86_access_type_t access_type);
#endif
x86_read_physical_ret_t (*read_physical)(
conf_object_t *cpu,
physical_address_t address,
unsigned size,
x86_access_type_t access_type);
#if !defined(PYWRAP)
exception_type_t (*read_physical_buf)(
conf_object_t *cpu,
uint8 *dst,
physical_address_t address,
unsigned size,
x86_access_type_t access_type);
#endif
exception_type_t (*write_physical)(
conf_object_t *cpu,
uint64 val,
physical_address_t address,
unsigned size,
x86_access_type_t access_type);
#if !defined(PYWRAP)
exception_type_t (*write_physical_buf)(
conf_object_t *cpu,
const uint8 *src,
physical_address_t address,
unsigned size,
x86_access_type_t access_type);
#endif
};
#define X86_MEMORY_OPERATION_INTERFACE "x86_memory_operation"
- Execution Context
- Cell Context for all methods, but must be called from an invoke
function set by the
instrumentation_replace interface.
- Description
- The
x86_memory_query interface is used to query additional
information about an instruction for the x86 architecture and is a complement
to the cpu_memory_query interface.
SIM_INTERFACE(x86_memory_query) {
linear_address_t (*linear_address)(conf_object_t *cpu,
memory_handle_t *handle);
x86_seg_t (*segment)(conf_object_t *cpu, memory_handle_t *handle);
x86_access_type_t (*access_type)(conf_object_t *obj,
memory_handle_t *handle);
x86_memory_type_t (*memory_type)(conf_object_t *obj,
memory_handle_t *handle);
};
#define X86_MEMORY_QUERY_INTERFACE "x86_memory_query"
The linear_address is used to get the linear address of the
access.
The segment function is used to get the segment register used
in the access.
The access_type returns the x86_access_type_t of the
access and the memory_type returns the
x86_memory_type_t of the access.
- Execution Context
- Cell Context for all methods, but must be called from a callback
receiving a handle of type
memory_handle_t.
- Description
SIM_INTERFACE(x86_msr) {
void (*register_handlers)(
conf_object_t *cpu,
int64 number,
x86_msr_getter_func_t getter,
lang_void *getter_data,
x86_msr_setter_func_t setter,
lang_void *setter_data,
const char *name);
void (*unregister_handlers)(
conf_object_t *cpu,
int64 number);
x86_msr_getter_ret_t (*get)(
conf_object_t *cpu,
int64 number,
x86_msr_access_type_t type);
x86_msr_ret_t (*set)(
conf_object_t *cpu,
int64 number,
uint64 value,
x86_msr_access_type_t type);
const char *(*get_name)(
conf_object_t *cpu,
int64 number);
int64 (*get_number)(
conf_object_t *cpu,
const char *name);
attr_value_t (*get_all_valid_numbers)(
conf_object_t *cpu);
};
#define X86_MSR_INTERFACE "x86_msr"
The register_handlers function will register get and set
functions that will be called every time a read or write access is made to
the MSR with number msr.
typedef struct {
x86_msr_ret_t status;
uint64 value;
} x86_msr_getter_ret_t;
typedef enum {
Sim_X86_Msr_Ok = Sim_Gen_Spr_Ok, /* Access was OK */
Sim_X86_Msr_GP_Fault, /* Raise #GP fault */
Sim_X86_Msr_Not_Handled /* Pass on to next handler */
} x86_msr_ret_t;
typedef x86_msr_getter_ret_t (*x86_msr_getter_func_t)(
conf_object_t *cpu,
int64 number,
x86_msr_access_type_t type,
lang_void *user_data);
typedef x86_msr_ret_t (*x86_msr_setter_func_t)(
conf_object_t *cpu,
int64 spr_number,
uint64 value,
x86_msr_access_type_t type,
lang_void *user_data);
The type parameter in the get and set functions is one of
the following, depending on where from the access originated:
typedef enum {
/* Access from a rdmsr/wrmsr instruction */
Sim_X86_Msr_Instruction_Access = Sim_Gen_Spr_Instruction_Access,
/* Access through attribute */
Sim_X86_Msr_Attribute_Access = Sim_Gen_Spr_Attribute_Access,
/* Access through int_register interface */
Sim_X86_Msr_Int_Register_Access = Sim_Gen_Spr_Int_Register_Access,
/* Access during VMX entry/exit */
Sim_X86_Msr_VMX_Access,
/* Architectural access without side effects within the CPU model, only
reads or writes the register value. However, if it is sent to the
platform as a non-inquiry access, that may cause side effects. */
Sim_X86_Msr_Architectural_Access
} x86_msr_access_type_t;
The getter function returns the status just like the setter together with
the read MSR value. A getter or setter may return the
Sim_X86_MSR_Not_Handled return code, in which case the access will pass
through to the earlier registered handler (or the default handler if there
is no earlier registered handler).
The function unregister_handlers will remove any
non-default handlers for a particular MSR.
The get and set functions get and set MSRs, using both
model default MSR handlers and handlers installed through this interface.
The function get_name takes number
as parameter and returns the name of the MSR.
The function get_number takes the name
and returns the MSR number.
The function get_all_valid_numbers returns a list of integers
corresponding to all the valid MSRs, including both model default MSRs and
MSRs installed through this interface.
- Execution Context
- Cell Context for all methods.
- Description
- The methods in this interface can be used to read or change the current
power state the CPU is in. A state value of 0 corresponds to C0, a value of
1 corresponds to C1, etc. HLT will be reported as state 1, substate 0.
MWAIT will reported based upon the eax hint, decoded as state = (eax[7:4] +
1) mod 16, substate = eax[3:0].
pkg_cstate_update will perform side-effects such as putting the
processor to sleep or waking it up, and call the cstate notification
listeners.
SIM_INTERFACE(x86_pkg_cstate) {
x86_cstate_t (*get_pkg_cstate)(conf_object_t *cpu_obj);
void (*set_pkg_cstate)(conf_object_t *cpu_obj,
uint32 state, uint32 sub_state);
void (*pkg_cstate_update)(conf_object_t *cpu_obj,
bool notify);
};
#define X86_PKG_CSTATE_INTERFACE "x86_pkg_cstate"
- Execution Context
- Cell Context for all methods.
- Description
- The
x86_reg_acc_access interface can be
used to access x86 register state in an efficient manner.
The interface is intended to be used from user decoder
service routines.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_reg_access) {
uint64 (*get_gpr)(conf_object_t *cpu, unsigned index);
void (*set_gpr)(conf_object_t *cpu, unsigned index, uint64 val);
uint64 (*get_rip)(conf_object_t *cpu);
void (*set_rip)(conf_object_t *cpu, uint64 rip);
uint64 (*get_rflags)(conf_object_t *cpu);
void (*set_rflags)(conf_object_t *cpu, uint64 rflags);
/* Possibly faster method for setting only cf,pf,af,zf,sf,of */
void (*set_status_flags)(conf_object_t *cpu, uint16 flags);
/* Regular segment registers */
x86_seg_reg_t (*get_seg)(conf_object_t *cpu, x86_seg_t n);
void (*set_seg)(conf_object_t *cpu, x86_seg_t n, x86_seg_reg_t seg);
/* IDTR and GDTR */
x86_system_seg_reg_t (*get_system_seg)(conf_object_t *cpu,
x86_system_seg_t n);
void (*set_system_seg)(conf_object_t *cpu, x86_system_seg_t n,
x86_system_seg_reg_t seg);
/* Control registers */
uint64 (*get_cr)(conf_object_t *cpu, x86_cr_t n);
void (*set_cr)(conf_object_t *cpu, x86_cr_t n, uint64 val);
uint64 (*get_efer)(conf_object_t *cpu);
void (*set_efer)(conf_object_t *cpu, uint64 efer);
uint64 (*get_xcr)(conf_object_t *cpu, x86_xcr_t n);
void (*set_xcr)(conf_object_t *cpu, x86_xcr_t n, uint64 val);
/* x87 FPU */
x86_fpu_reg_t (*get_freg)(conf_object_t *cpu, unsigned index);
void (*set_freg)(conf_object_t *cpu, unsigned index, x86_fpu_reg_t freg);
x86_fpu_env_t (*get_fpu_env)(conf_object_t *cpu);
void (*set_fpu_env)(conf_object_t *cpu, x86_fpu_env_t state);
/* SIMD */
xmm_reg_t (*get_xmm)(conf_object_t *cpu, unsigned index);
void (*set_xmm)(conf_object_t *cpu, unsigned index, xmm_reg_t val);
ymm_reg_t (*get_ymm)(conf_object_t *cpu, unsigned index);
void (*set_ymm)(conf_object_t *cpu, unsigned index, ymm_reg_t val);
uint32 (*get_mxcsr)(conf_object_t *cpu);
void (*set_mxcsr)(conf_object_t *cpu, uint32 mxcsr);
/* Debug registers */
uint64 (*get_dr)(conf_object_t *cpu, x86_dr_t n);
void (*set_dr)(conf_object_t *cpu, x86_dr_t n, uint64 val);
/* SMM */
bool (*get_in_smm)(conf_object_t *cpu);
void (*set_in_smm)(conf_object_t *cpu, bool val);
uint64 (*get_smm_base)(conf_object_t *cpu);
void (*set_smm_base)(conf_object_t *cpu, uint64 val);
/* Monitor/Mwait */
x86_monitor_info_t (*get_monitor_info)(conf_object_t *cpu);
void (*set_monitor_info)(conf_object_t *cpu, x86_monitor_info_t val);
x86_mwait_info_t (*get_mwait_info)(conf_object_t *cpu);
void (*set_mwait_info)(conf_object_t *cpu, x86_mwait_info_t val);
/* Non-register state */
x86_activity_t (*get_activity_state)(conf_object_t *cpu);
void (*set_activity_state)(conf_object_t *cpu, x86_activity_t val);
x86_intstate_t (*get_interruptibility_state)(conf_object_t *cpu);
void (*set_interruptibility_state)(conf_object_t *cpu,
x86_intstate_t val);
/* A debug exception is pending if triggered by the last instruction,
but not yet taken. */
x86_pending_debug_exc_t (*get_pending_debug_exc)(conf_object_t *cpu);
void (*set_pending_debug_exc)(conf_object_t *cpu,
x86_pending_debug_exc_t val);
/* Derived state for fast/easy access */
x86_xmode_info_t (*get_xmode_info)(conf_object_t *cpu);
x86_exec_mode_t (*get_exec_mode)(conf_object_t *cpu);
/* This is configuration info. No need for a set method. */
uint32 (*get_mxcsr_mask)(conf_object_t *cpu);
/* Extension state dirty bit modification (for XSAVE) */
uint64 (*get_ext_state_dirty_bits)(conf_object_t *cpu);
void (*or_ext_state_dirty_bits)(conf_object_t *cpu, uint64 dirty_bits);
void (*and_ext_state_dirty_bits)(conf_object_t *cpu, uint64 dirty_bits);
/* PDPTE registers used in PAE paging mode */
uint64 (*get_pdpte)(conf_object_t *cpu, int num);
void (*set_pdpte)(conf_object_t *cpu, int num, uint64 val);
uint32 (*get_vmx_mode)(conf_object_t *cpu);
};
#define X86_REG_ACCESS_INTERFACE "x86_reg_access"
- Execution Context
- Cell Context for all methods.
- Description
- The smm interface is used to implement a custom SMRAM
state save map.
The save_state method is invoked when SMM mode
is entered before any cpu state has been modified.
The method should save the current cpu state
to the SMRAM state save map.
The restore_state method is invoked during execution
of the rsm instruction. The method should
restore the cpu state from the SMRAM state save map.
The x86_smm_state interface implemented by
the cpu can be used to facilitate cpu state changes and
SMRAM access.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_smm) {
void (*save_state)(conf_object_t *obj, conf_object_t *cpu);
void (*restore_state)(conf_object_t *obj, conf_object_t *cpu);
};
#define X86_SMM_INTERFACE "x86_smm"
- Execution Context
- Cell Context for all methods.
- Description
- The smm state interface is implemented by the cpu
and is typically used by objects implementing the
x86_smm interface.
The get_state method saves the cpu state in the
state struct. This method is intended to be
used during SMM entry.
The set_state method restores the cpu state
from the state struct. This method is intended
to be used during SMM exit.
The smram_read and smram_write methods
can be used to access the SMRAM during SMM entry/exit.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_smm_state) {
void (*get_state)(conf_object_t *cpu, smm_reg_state_t *state);
void (*set_state)(conf_object_t *cpu, const smm_reg_state_t *state);
uint64 (*smram_read)(conf_object_t *obj,
unsigned smram_offs, unsigned len);
void (*smram_write)(conf_object_t *obj,
unsigned smram_offs, unsigned len, uint64 val);
};
#define X86_SMM_STATE_INTERFACE "x86_smm_state"
- Execution Context
- Cell Context for all methods.
- Description
- The x86 tlb interface is used for communication between an x86 cpu
and its TLB. The TLB is implemented as a separate class for greater
flexibility. The TLB object does no memory operations itself.
typedef struct {
int valid;
physical_address_t paddr;
} tagged_physical_address_t;
SIM_INTERFACE(x86_tlb) {
void (*flush_all)(conf_object_t *obj,
int keep_global_entries);
void (*flush_page)(conf_object_t *obj,
linear_address_t laddr);
int (*lookup)(conf_object_t *obj,
x86_memory_transaction_t *mem_tr);
void (*add)(conf_object_t *obj,
processor_mode_t mode,
read_or_write_t read_or_write,
data_or_instr_t data_or_instr,
int global_page,
x86_memory_type_t pat_type,
x86_memory_type_t mtrr_type,
linear_address_t laddr,
physical_address_t paddr,
int page_size);
tagged_physical_address_t (*itlb_lookup)(conf_object_t *obj,
linear_address_t laddr,
processor_mode_t mode);
void (*set_pae_mode)(conf_object_t *obj, bool pae_mode);
};
#define X86_TLB_INTERFACE "x86_tlb"
All functions in the interface get the object implementing
the interface as their first parameter.
flush_all is called when all TLB entries should be
flushed. If keep_global_entries is set, then TLB entries
with their global bit set should not be flushed.
flush_page is invoked when pages containing laddr are
to be removed from the TLB.
lookup is used by the CPU when a memory access misses the
STC. It must return true (non-zero) if and only if the memory
operation specified by mem_tr hits the TLB and does not
raise an exception. The mode, linear_address are valid when
the method is invoked. The other fields passed through mem_tr
are undefined. If the method returns true, the
s.physical_address, pat_type, and mtrr_type
fields of mem_tr must be updated by lookup.
An access that misses in lookup but does not raise a fault
is inserted into the TLB with add. The page_size
encoding is 0 for 4 kb pages, 1 for 2 Mb pages, and 2 for 4 Mb
pages.
itlb_lookup is a simplified version of lookup used
only for instruction TLB lookups. If the lookup is successful
valid and paddr should be set, otherwise valid
should be cleared.
set_pae_mode is invoked when the cpu changes the
PAE enable bit.
It class implementing the interface must make sure that only
addresses mapped in the TLB are present in the STCs.
This interface may be changed or replaced with an architecture
independent interface in future versions of Simics.
- Execution Context
- Cell Context for all methods.
- Description
- The x86_tlb_v2 interface is used for communication between an x86 cpu
and its TLB. The TLB is implemented as a separate class for greater
flexibility. The TLB object does no memory operations itself.
flush_all is called when all TLB entries should be flushed. If
keep_global_entries is set, then TLB entries with their global
bit set should not be flushed.
flush_page is invoked when pages containing laddr are
to be removed from the TLB.
lookup is used by the CPU when a memory access misses the STC. It
returns the matching TLB entry if the memory operation specified in
mem_tr hits the TLB and does not raise an exception. Otherwise
NULL is returned. The mode, linear_address, and
type fields in mem_tr need to be valid when the method
is invoked. The other fields passed through mem_tr are not to be
used by the method and can carry any value. If the method returns true, the
s.physical_address, pat_type, and mtrr_type
fields of mem_tr must be updated by lookup.
Pages are added to the TLB with add. The
supervisor_access field in attrs argument specifies
the allowed access types in supervisor mode and user_access in
attrs specifies the allowed access types in user mode.
itlb_lookup is a simplified version of lookup used
only for instruction TLB lookups. If the lookup is successful
valid and paddr should be set, otherwise
valid should be cleared.
The class implementing the interface must make sure that only addresses
mapped in the TLB are present in the STCs.
SIM_INTERFACE(x86_tlb_v2) {
void (*flush_all)(conf_object_t *obj,
int keep_global_entries);
void (*flush_page)(conf_object_t *obj,
linear_address_t laddr);
const x86_tlb_entry_t *(*lookup)(conf_object_t *obj,
x86_memory_transaction_t *mem_tr);
void (*add)(conf_object_t *obj,
linear_address_t laddr,
physical_address_t paddr,
x86_tlb_attrs_t attrs);
tagged_physical_address_t (*itlb_lookup)(conf_object_t *obj,
linear_address_t laddr,
processor_mode_t mode);
};
#define X86_TLB_V2_INTERFACE "x86_tlb_v2"
- Execution Context
- Cell Context for all methods.
- Description
- The x86_tlb_v3 interface is used for communication between an x86 cpu
and its TLB. The TLB is implemented as a separate class for greater
flexibility. The TLB object does no memory operations itself.
Pages are added to the TLB with add. Process context identifier,
linear and physical address for translation specified using arguments
hint, laddr and paddr correspondingly.
The fields in attrs argument used for specification of
allowed access types and additional page attributes.
lookup is used by the CPU when a memory access misses the STC.
It returns the matching TLB entry if the memory operation specified in
mem_tr hits the TLB and does not raise an exception. Otherwise
NULL is returned. The hint argument specifies process context
identifier. The mode, linear_address, and
type fields in mem_tr need to be valid when the method
is invoked. The other fields passed through mem_tr are not to be
used by the method and can carry any value. If the method returns not NULL,
the s.physical_address, pat_type, and
mtrr_type fields of mem_tr must be updated by
lookup.
itlb_lookup is a simplified version of lookup used
only for instruction TLB lookups. If the lookup is successful
valid and paddr should be set, otherwise
valid should be cleared.
invalidate_page is used to remove from TLB page corresponding to
given linear address specified by argument laddr in process
context with identifier from argument hint.
invalidate is invoked when value of CR4.PCIDE bit set and CPU
executes INVPCID instruction. Direct and indirect operands of instruction
transferred in hint, la and type
arguments. TLB entries flushed according to INVPCID instruction description.
New invalidation type X86_Tlb_Invalidate_Address_Space added to implement
flush_all function from previous interfaces. The method also can be used to
flush required TLB entries in any required cases.
The class implementing the interface must make sure that only addresses
mapped in the TLB are present in the STCs.
SIM_INTERFACE(x86_tlb_v3) {
void (*add)(conf_object_t *obj,
uint64 hint,
linear_address_t laddr,
physical_address_t paddr,
x86_tlb_attrs_v3_t attrs);
const x86_tlb_entry_v3_t *(*lookup)(conf_object_t *obj,
uint64 hint,
x86_memory_transaction_t *mem_tr);
tagged_physical_address_t (*itlb_lookup)(conf_object_t *obj,
uint64 hint,
linear_address_t laddr,
processor_mode_t mode);
void (*invalidate_page)(conf_object_t *obj,
uint64 hint,
linear_address_t laddr);
void (*invalidate)(conf_object_t *obj,
uint32 type,
uint64 hint,
linear_address_t la);
};
#define X86_TLB_V3_INTERFACE "x86_tlb_v3"
- Execution Context
- Cell Context for all methods.
- Description
- The
x86_vmp_control interface can be
used to prevent VMP from being used.
The set_block_count method sets the VMP block
count. If the VMP block count is non-zero, VMP will not be
used for simulation.
The get_block_count method returns VMP block count.
This interface is internal and may change without notice.
SIM_INTERFACE(x86_vmp_control) {
unsigned (*get_block_count)(conf_object_t *cpu);
void (*set_block_count)(conf_object_t *cpu, unsigned cnt);
};
#define X86_VMP_CONTROL_INTERFACE "x86_vmp_control"
- Execution Context
- Cell Context for all methods.
- Description
- The
xed_access interface is implemented by a processor model.
The interface can be used to call Intel® X86 Encoder Decoder (Intel\reg;
XED) library built into the processor model.
This interface is internal and may change at any time without notice.
SIM_INTERFACE(xed_access) {
int (*get_last)(conf_object_t *obj, xed_data_type_t type);
int (*decode)(conf_object_t *obj, xed_data_type_t type, bytes_t bytes);
const char *(*to_string)(conf_object_t *obj, xed_data_type_t type,
int value);
};
#define XED_ACCESS_INTERFACE "xed_access"
- Execution Context
- Cell Context for all methods.
- Description
- OBSOLETE!
External Xtensa TIE interface for the export state
type. user_object is the user object to use in the
export_state_func callback.
The type of the export_state_func is defined in the
xtensa/tie/cstub-extif.h file in the Xtensa model build
directory.
- Execution Context
- Cell Context for all methods.
- Description
- External Xtensa TIE interface for the import wire type. A callback should be
registered in order to send data to the object obj that
implements the interface, typically a processor. The callback is called when
the wire is accessed. The user_object is the user object to use
in the import_wire_func callback.
The type of the import_wire_func is defined in the
xtensa/tie/cstub-extif.h file in the Xtensa model build
directory.
- Execution Context
- Cell Context for all methods.
- Description
- OBSOLETE!
External Xtensa TIE interface for the input queue type. Two callbacks should
be registered in order to send data to the object obj that
implements the interface, typically a processor. When the queue is accessed
the callbacks are called. user_object is the user object to use
in the empty_callback and data_callback callbacks.
The types of the empty_callback callback and data_callback are defined in
the xtensa/tie/cstub-extif.h file in the Xtensa model build
directory. The empty_callback should return 1 if the queue is empty,
otherwise 0. The data_callback is used for sending the data.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by all Xtensa cores.
The methods correspond to the
iram, irom,
dram and drom attributes, reporting where
the internal memories are located, in the form of:
[[paddr_start, paddr_stop]*].
This is static and will never change, but is differently
configured for each Xtensa cores.
- Execution Context
- Cell Context for all methods.
- Description
- OBSOLETE!
External Xtensa TIE interface for the lookup type. user_object is
the user object to use in the lookup_func callback.
The type of the lookup_func is defined in the
xtensa/tie/cstub-extif.h file in the Xtensa model build
directory.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the Xtensa core which is configured with an
MPU. The primary use of this interface, is the iDMA device which will need
to do various protection checks for the DMA transfers.
The mpu_region returns region data that hits for
the specified address. If the address hits in a background
mapping, the end address will be when a foreground mapping
overrides the background mapping.
typedef struct xtensa_mpu_lookup {
bool background; /* If false, a foreground hit */
uint16 region; /* The foreground/background region */
uint32 start;
uint32 end;
/* Permissions */
bool sr; /* supervisor-read */
bool sw; /* supervisor-write */
bool sx; /* supervisor-execute */
bool ur; /* user-read */
bool uw; /* user-write */
bool ux; /* user-execute */
} xtensa_mpu_lookup_t;
SIM_INTERFACE(xtensa_mpu_lookup) {
xtensa_mpu_lookup_t (*mpu_region)(conf_object_t *obj, uint32 address);
};
#define XTENSA_MPU_LOOKUP_INTERFACE "xtensa_mpu_lookup"
- Execution Context
- Cell Context for all methods.
- Description
- OBSOLETE!
External Xtensa TIE interface for the output queue type. Two callbacks
should be registered in order to receive data from the object obj
that implements the interface, typically a processor. When the queue is
accessed the callbacks are called. user_object is the user object
to use in the full_callback and data_callback
callbacks.
The types of the full_callback and data_callback are defined in the
xtensa/tie/cstub-extif.h file in the Xtensa model build
directory. The full_callback should return 1 if the queue is full, otherwise
0. The data_callback is used for receiving the data.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the Xtensa core, allowing external
devices to programmatically change some aspects of how the reset should
be handled during run-time.
The set_reset_prid method sets the corresponding PRID register,
which gets assigned during reset. The value is also exposed by the
reset_prid attribute.
The set_alternative_reset_vector method sets the address
from which the alternative reset starts executing after reset, when the
reset_select pin is high. The value is also exposed in the
alternative_reset_vector attribute.
Both methods return a bool, indicating if they were successful or not. A
false return indicates that the associated Xtensa options are not included
in the model.
SIM_INTERFACE(xtensa_reset_configure) {
bool (*set_reset_prid)(conf_object_t *obj, uint16 prid_value);
bool (*set_alternative_reset_vector)(conf_object_t *obj, uint32 vector_address);
};
#define XTENSA_RESET_CONFIGURE_INTERFACE "xtensa_reset_configure"
- Execution Context
- Threaded Context for all methods.
- Description
- An
export_state is a way for the Xtensa core to push data
to a device implementing this interface.
The data method contains the transferred data out from the
Xtensa CPU. The out_data pointer holds the data that can be read,
but only bit_width bits should be examined.
- Execution Context
- Cell Context for all methods.
- Description
- The
import_wire supports reading data from a device implementing this
interface.
The data method requests a in_data pointer to be filled with
bit_width of data by the device.
- Execution Context
- Cell Context for all methods.
- Description
- The
input_queue represents a way for the Xtensa CPU to read data from
a queue implemented in a device.
The empty method indicates if there is anything to read in the queue or not.
The data method is used to read data from the input queue implemented in
the device, the device should write the next data in queue to the in_data
pointer and fill it with bit_width bits of data.
If is_peek is true, the data should be returned, but not removed from
the queue.
- Execution Context
- Cell Context for all methods.
- Description
- A
lookup is a bidirectional communication between the Xtensa and
the device implementing this interface. When the data method is
received by the device, the out_data pointer contains
out_width bits of data (from the Xtensa core) that the device
should read and take action upon.
As a response, the device should fill in in_width of bits in
the in_data buffer, providing the result of the lookup
back to the Xtensa instruction.
- Execution Context
- Cell Context for all methods.
- Description
- The
output_queue allows the Xtensa to push data on a queue
which the device needs to implement.
With the full method the Xtensa CPU might ask if the queue
is currently full or not.
To data method is used to push data on the output queue
of the device. out_data is a pointer to the pushed data
and bit_width how many bits that is pushed on the queue.
If reserve_only is true, no data is present but the device
should just allocate space for the data.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the Xtensa core which holds the
configuration of the Windowed Watchdog Timer. The device itself is not part
of the core, but implemented as an external device which fetches these
values for correct device simulation, making the wwdt device generic
for all configurations.
The has_wwdt method reports if the wwdt option is included in the
core at all. The rest of the member functions extract configuration details
from the core, if the core does not have wwdt enabled, all are zeros.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the wwdt timer allowing the SoC device to
read out the status register. On real hardware the Wwdt_faultInfo is an
eight bit output towards the device. However, in a simulator it makes
more sense to allow the SoC-device to read the status when needed, instead
of pushing out the new contents when bits changes. The uint8 value returned
is a bitmask with the bits defined in
xtensa_wwdt_fault_info_t.
typedef enum {
Wwdt_Info_Derr_Inj_Dis = 1 << 7,
Wwdt_Info_Tfv_Err = 1 << 6,
Wwdt_Info_Err_Inj = 1 << 5,
Wwdt_Info_Oor_Exp = 1 << 4,
Wwdt_Info_Oor_Kick = 1 << 3,
Wwdt_Info_Ill_Kick = 1 << 2,
Wwdt_Info_Cnt_Exp = 1 << 1,
Wwdt_Fault_Asserted = 1 << 0,
} xtensa_wwdt_faultinfo_t;
- Execution Context
- Cell Context for all methods.
- Description
- Interface implemented by tablet devices. Used by consoles to send touchpad
events to the controller. The set_state function is called when
something changes in the console. The coordinates are given as scaled
absolute scaled values, where (0, 0) is the upper-left corner and (0xffff,
0xffff) is the lower-right corner.
typedef enum {
Abs_Pointer_Button_Left = 0x20,
Abs_Pointer_Button_Right = 0x10,
Abs_Pointer_Button_Middle = 0x08
} abs_pointer_buttons_t;
typedef struct {
abs_pointer_buttons_t buttons;
uint16 x;
uint16 y;
uint16 z;
} abs_pointer_state_t;
SIM_INTERFACE(abs_pointer) {
void (*set_state)(conf_object_t *obj, abs_pointer_state_t state);
};
#define ABS_POINTER_INTERFACE "abs_pointer"
- Execution Context
- Cell Context for all methods.
- Description
- Interface used by tablet controllers to temporary turn off and on the
tracking of absolute pointer locations. Implemented by consoles. When
disabled, no calls will be made to the controller's
abs_pointer interface.
SIM_INTERFACE(abs_pointer_activate) {
void (*enable)(conf_object_t *obj);
void (*disable)(conf_object_t *obj);
};
#define ABS_POINTER_ACTIVATE_INTERFACE "abs_pointer_activate"
- Execution Context
- Cell Context for all methods.
- Description
- The interface is used to handle extended 32-bit addressing mode supported
by x2APIC. See apic_bus documentation.
SIM_INTERFACE(apic_bus_v2) {
apic_bus_status_t (*interrupt)(conf_object_t *obj,
apic_destination_mode_t dest_mode,
apic_delivery_mode_t delivery_mode,
int level_assert,
apic_trigger_mode_t trigger_mode,
uint8 vector,
uint32 destination);
};
#define APIC_BUS_V2_INTERFACE "apic_bus_v2"
- Execution Context
- Cell Context.
- Description
- The
bank_after_read interface is used to monitor and modify
the state of read accesses from the after_read_callback_t
callback.
SIM_INTERFACE(bank_after_read) {
physical_address_t (*offset)(bank_access_t *handle);
physical_address_t (*size)(bank_access_t *handle);
bool (*missed)(bank_access_t *handle);
uint64 (*value)(bank_access_t *handle);
void (*set_missed)(bank_access_t *handle, bool missed);
void (*set_value)(bank_access_t *handle, uint64 value);
conf_object_t *(*initiator)(bank_access_t *handle);
};
#define BANK_AFTER_READ_INTERFACE "bank_after_read"
offset retrieves the address of the access.
size gets the size of the access.
missed tells you whether or not the access succeeded.
value provides the read value. May not be invoked if
missed is true.
set_missed can be used to inject or forgive an access miss.
set_value can change the read value.
initiator returns the initiator of the access. This method may be
NULL, although this is deprecated. If the interface was implemented
by a DML/C/C++ bank, then the method may only be accessed if the bank was
compiled with Simics Base 6.0.129 or newer.
- Execution Context
- Cell Context for all methods, but must be called from an
after_read_callback_t callback with a valid handle of type
bank_access_t.
- Description
- The
bank_after_write interface is used to monitor and modify
the state of write accesses from the after_write_callback_t
callback.
SIM_INTERFACE(bank_after_write) {
physical_address_t (*offset)(bank_access_t *handle);
physical_address_t (*size)(bank_access_t *handle);
bool (*missed)(bank_access_t *handle);
void (*set_missed)(bank_access_t *handle, bool missed);
conf_object_t *(*initiator)(bank_access_t *handle);
};
#define BANK_AFTER_WRITE_INTERFACE "bank_after_write"
offset retrieves the address of the access.
size gets the size of the access.
missed tells you whether or not the access succeeded.
set_missed can be used to inject or forgive an access miss.
initiator returns the initiator of the access. This method may be
NULL, although this is deprecated. If the interface was implemented
by a DML/C/C++ bank, then the method may only be accessed if the bank was
compiled with Simics Base 6.0.129 or newer.
- Execution Context
- Cell Context for all methods, but must be called from an
after_write_callback_t callback with a valid handle of type
bank_access_t.
- Description
- The
bank_before_read interface is used to monitor and modify
the state of read accesses from the before_read_callback_t
callback.
SIM_INTERFACE(bank_before_read) {
physical_address_t (*offset)(bank_access_t *handle);
physical_address_t (*size)(bank_access_t *handle);
void (*set_offset)(bank_access_t *handle, physical_address_t offset);
void (*inquire)(bank_access_t *handle);
conf_object_t *(*initiator)(bank_access_t *handle);
};
#define BANK_BEFORE_READ_INTERFACE "bank_before_read"
offset retrieves the address of the access.
size gets the size of the access.
set_offset can be used to redirect the access to another address.
inquire can turn the access into an inquiry
access. Subsequent and corresponding after_read callbacks are
invoked regardless.
initiator returns the initiator of the access. This method may be
NULL, although this is deprecated. If the interface was implemented
by a DML/C/C++ bank, then the method may only be accessed if the bank was
compiled with Simics Base 6.0.129 or newer.
- Execution Context
- Cell Context for all methods, but must be called from a
before_read_callback_t callback with a valid handle of type
bank_access_t.
- Description
- The
bank_before_write interface is used to monitor and modify
the state of write accesses from the before_write_callback_t
callback.
SIM_INTERFACE(bank_before_write) {
physical_address_t (*offset)(bank_access_t *handle);
physical_address_t (*size)(bank_access_t *handle);
uint64 (*value)(bank_access_t *handle);
void (*suppress)(bank_access_t *handle);
void (*set_offset)(bank_access_t *handle, physical_address_t offset);
void (*set_value)(bank_access_t *handle, uint64 value);
conf_object_t *(*initiator)(bank_access_t *handle);
};
#define BANK_BEFORE_WRITE_INTERFACE "bank_before_write"
offset retrieves the address of the access.
size gets the size of the access.
value provides the write value.
suppress may be used to prevent the write. Subsequent
and corresponding after_write callbacks are invoked regardless.
set_offset can be used to redirect the write to an another
address.
set_value can change the write value.
initiator returns the initiator of the access. This method may be
NULL, although this is deprecated. If the interface was implemented
by a DML/C/C++ bank, then the method may only be accessed if the bank was
compiled with Simics Base 6.0.129 or newer.
- Execution Context
- Cell Context for all methods, but must be called from a
before_write_callback_t callback with a valid handle of type
bank_access_t.
- Description
- The
bank_instrumentation_subscribe interface is implemented
by non-anonymous register banks. The interface may be used to monitor and
modify register accesses using callbacks.
Similar to the CPU instrumentation framework, a bank that implements the
interface is considered an instrumentation provider and is typically used by
an instrumentation tool. The tool registers callbacks using this interface
and performs its actions once they are called. Using this interface, tools
may also group registered callbacks using connection objects. This can be
useful to enforce a certain evaluation order of grouped callbacks.
The bank argument in all methods is the register bank object
implementing this interface.
The connection can be used to group registered callbacks
together, so that their order may be changed or their registered
callbacks be enabled, disabled, or removed collectively. If
connection is NULL when registering a callback, the callback is
considered anonymous. Anonymous callbacks are evaluated before any other
callbacks in the order of creation. See instrumentation_order
interface for more details on the callback order.
Each registration method installs a callback which is called at a
particular time, before or after, read and write register
accesses. Callbacks are not invoked during inquiry accesses. Using
the offset and size arguments, a user may
install the callback only for a particular range. If
offset and size are 0 the callback is
installed for the entire bank.
The user_data is used to associate user defined data with every
callback. Every time the callback is invoked the data is provided as an
argument to the callback.
SIM_INTERFACE(bank_instrumentation_subscribe) {
bank_callback_handle_t (*register_before_read)(
conf_object_t *NOTNULL bank,
conf_object_t *connection,
uint64 offset,
uint64 size,
before_read_callback_t before_read,
lang_void *user_data);
bank_callback_handle_t (*register_after_read)(
conf_object_t *NOTNULL bank,
conf_object_t *connection,
uint64 offset,
uint64 size,
after_read_callback_t after_read,
lang_void *user_data);
bank_callback_handle_t (*register_before_write)(
conf_object_t *NOTNULL bank,
conf_object_t *connection,
uint64 offset,
uint64 size,
before_write_callback_t before_write,
lang_void *user_data);
bank_callback_handle_t (*register_after_write)(
conf_object_t *NOTNULL bank,
conf_object_t *connection,
uint64 offset,
uint64 size,
after_write_callback_t after_write,
lang_void *user_data);
void (*remove_callback)(conf_object_t *NOTNULL bank,
bank_callback_handle_t callback);
void (*remove_connection_callbacks)(conf_object_t *NOTNULL bank,
conf_object_t *NOTNULL connection);
void (*enable_connection_callbacks)(conf_object_t *NOTNULL bank,
conf_object_t *NOTNULL connection);
void (*disable_connection_callbacks)(conf_object_t *NOTNULL bank,
conf_object_t *NOTNULL connection);
};
#define BANK_INSTRUMENTATION_SUBSCRIBE_INTERFACE \
"bank_instrumentation_subscribe"
Every function that registers a callback returns a unique handle of type
bank_callback_handle_t. The remove_callback method
uninstalls the callback associated with the handle. The
remove_connection_callbacks uninstalls all callbacks associated
with a connection object. Similarly, the
enable_connection_callbacks and
disable_connection_callbacks methods are used to temporarily
enable or disable a group of callbacks.
Callback functions registered through the
bank_instrumentation_subscribe interface are called before or
after read and write accesses, like so:
typedef void (*before_read_callback_t)(conf_object_t *connection,
bank_before_read_interface_t *access,
bank_access_t *handle,
lang_void *user_data);
typedef void (*after_read_callback_t)(conf_object_t *connection,
bank_after_read_interface_t *access,
bank_access_t *handle,
lang_void *user_data);
typedef void (*before_write_callback_t)(conf_object_t *connection,
bank_before_write_interface_t *access,
bank_access_t *handle,
lang_void *user_data);
typedef void (*after_write_callback_t)(conf_object_t *connection,
bank_after_write_interface_t *access,
bank_access_t *handle,
lang_void *user_data);
The connection is the object used to group the callback with
any other callbacks, which may be NULL. The access object
provides a number of methods which may be used along with the
handle to perform a certain set of actions at the particular
point of the access. The user_data is the custom data
which was associated with the callback at registration.
For every callback, additional information may be accessed using a specific
interface which is passed as a parameter to the callback. See
bank_before_read, bank_after_read,
bank_before_write, and bank_after_write for
details.
- Execution Context
- Cell Context for all methods.
- Description
- An internal interface. Can be changed at any time.
- Execution Context
- Internal.
- Description
- The breakpoint interface is implemented by any object that supports breaking
on an address range.
SIM_INTERFACE(breakpoint) {
void (*insert_breakpoint)(conf_object_t *object,
conf_object_t *caller,
breakpoint_handle_t handle,
access_t access,
generic_address_t start,
generic_address_t end);
void (*remove_breakpoint)(conf_object_t *object,
breakpoint_handle_t handle);
breakpoint_info_t (*get_breakpoint)(conf_object_t *obj,
breakpoint_handle_t handle);
};
#define BREAKPOINT_INTERFACE "breakpoint"
The insert_breakpoint function is called when adding a
breakpoint on object. The handle identified the
breakpoint and is to be used when triggering the breakpoint and when
breakpoints are removed. The access parameter specifies the types
of accesses that the breakpoint is set for. The breakpoint range is from
start to end and includes both ends.
The implementer of this interface should call caller through the
breakpoint_trigger interface to trigger the breakpoint.
remove_breakpoint should remove the breakpoint and further accesses
to the address range should not trigger that breakpoint.
This interface is only to be used by the Simics core. Other uses of
breakpoints should go through the available breakpoint API calls such as
SIM_breakpoint.
- Execution Context
- Cell Context for all methods.
- Description
- The
breakpoint_change interface is implemented by
objects that wish to get notified when breakpoints are added,
removed, or changed in some way.
The object that wants to get notified of changes to breakpoints in
a another object would use the simple_dispatcher in
the breakpoint_change port of that other object. The other object
will then lookup the breakpoint_change interface in
the object to notify and use that when breakpoint updates occur.
The breakpoint_change port is implemented by objects of the
cell class, and a listener that registers on a cell with get
notified on any breakpoint changes in that cell.
SIM_INTERFACE(breakpoint_change) {
void (*breakpoint_added)(conf_object_t *obj,
conf_object_t *bp_obj,
breakpoint_handle_t handle);
void (*breakpoint_removed)(conf_object_t *obj,
conf_object_t *bp_obj,
breakpoint_handle_t handle);
};
#define BREAKPOINT_CHANGE_INTERFACE "breakpoint_change"
- Execution Context
- Cell Context for all methods.
- Description
- Objects of the context and memory-space
classes implement the
breakpoint_query_v2 interface. It is
used by processors to check for breakpoints.
Implementors of this interface should use
SIM_register_compatible_interfaces after
SIM_register_interface to also register earlier versions of the
interface.
The get_breakpoints function returns a set of
breakpoints that intersect the range given in start and
end, including both start and end in the range. Only
breakpoints set on access types with bits set in
read_write_execute will be returned.
When information from get_breakpoints has been processed, the
breakpoints array in the breakpoint_set_t structure should be freed with
MM_FREE.
SIM_INTERFACE(breakpoint_query_v2) {
breakpoint_set_t (*get_breakpoints)(conf_object_t *obj,
access_t read_write_execute,
generic_address_t start,
generic_address_t end);
};
#define BREAKPOINT_QUERY_V2_INTERFACE "breakpoint_query_v2"
- Execution Context
- Cell Context for all methods.
- Description
- Objects implementing the
breakpoint interface
typically also implement the breakpoint_trigger
interface. Processors call the trigger_breakpoint
function to signal that a memory access intersects a
breakpoint. The trigger_breakpoint function will raise
the appropriate haps and the currently scheduled execute object may
receive a stop call during the call to
trigger_breakpoint.
The obj argument is the object that holds the
breakpoint, typically a memory space or a context
object. initiator_obj is the source of the memory
operation that triggers the breakpoint. The handle
argument identifies the breakpoint to trigger. A value of
BREAKPOINT_HANDLE_ANY can be passed as
handle, in which case all the breakpoints that match the
given address, size, and access
will be triggered. The address, size, and
access arguments specify information about the access
that triggers the breakpoint. The data argument points
to a buffer where the data for the access is kept.
If a stop is received during a call to
trigger_breakpoint, then it is recommended that any
software visible actions carried out after the breakpoint are
logged. That could for example be to notify the user if the entire
instruction that triggers a breakpoint will complete, and that the
instruction will then not be re-executed when the simulation
restarts.
SIM_INTERFACE(breakpoint_trigger) {
void (*trigger_breakpoint)(conf_object_t *obj,
conf_object_t *initiator_obj,
breakpoint_handle_t handle,
generic_address_t address,
generic_address_t size,
access_t access,
uint8 *data);
};
#define BREAKPOINT_TRIGGER_INTERFACE "breakpoint_trigger"
- Execution Context
- Cell Context for all methods.
- Description
- This interface can be implemented by any object that can issue callbacks.
The get_callbacks method returns a
attr_value_t list
of type [[(o|n)sss*]] where o is the object that installed
the callback (if applicable, otherwise NIL). The sss strings are:
- A one liner description about the callback. Could for example contain the
interface method that installed the callback, if such one exist.
- The function name.
- A string describing the user data.
SIM_INTERFACE(callback_info) {
attr_value_t (*get_callbacks)(conf_object_t *obj);
};
#define CALLBACK_INFO_INTERFACE "callback_info"
- Execution Context
- Cell Context for all methods, but must be called from a callback
receiving a handle of type
instruction_handle_t.
- Description
- The
cell_inspection interface is implemented by
objects of the cell class. It is used by objects implementing the
execute interface to update the currently executing
objects when control is transferred outside of the execute object.
The current object implementing processor_info is set with
set_current_processor_obj(). Similarly, the current object
implementing step is set with
set_current_step_obj().
SIM_INTERFACE(cell_inspection) {
void (*set_current_processor_obj)(conf_object_t *obj,
conf_object_t *cpu_obj);
void (*set_current_step_obj)(conf_object_t *obj,
conf_object_t *step_obj);
};
#define CELL_INSPECTION_INTERFACE "cell_inspection"
- Execution Context
- Cell Context for all methods.
- Description
- Experimental, may change without notice.
SIM_INTERFACE(co_execute) {
void (*start_thread)(conf_object_t *NOTNULL obj,
void (*entry)(lang_void *arg), lang_void *arg);
void (*yield)(conf_object_t *NOTNULL obj);
};
#define CO_EXECUTE_INTERFACE "co_execute"
- Execution Context
- Cell Context
- Description
- All component classes must implement the
component
interface. All functions in the interface must be implemented.
The pre_instantiate function is called before the
component is instantiated. The function returns true if the
component can be instantiated, or false if not.
The component might need to do some extra work after the component
has been instantiated. This should be done when called via the
post_instantiate function.
The create_cell function returns true if the
configuration system can create a default cell object for the
component, or false if not. Both
pre_instantiate and create_cell typically
return true.
Component has slots. A slot has key and value. The key is the slot
name as a string. The value is a conf object, a pre conf object, or
None, or nested lists of such types.
Slots are either defined in the component or added after the
component has been created. Slots defined in the component are
static slots which can not be deleted, but the slot value can be
changed. Slots added to the component after creation are
dynamic slots and they can be removed when wanted.
The get_slots function returns a dictionary with slot
names as dictionary keys and slot values as dictionary values.
The get_slot_objects function returns a list of all conf
objects and pre conf objects extracted from all slot values.
The get_slot_value returns the slot value. The slot name
is passed as slot argument. A slot value is set using
the set_slot_value function. The value
argument should be a conf object, pre conf object, or None, or
nested lists of such types. The get function returns NULL on failure.
The set function does not return anything to indicate failure.
The has_slot function returns true if the
slot exists, otherwise false. The slot can
either be a static slot or a dynamic slot. The add_slot
function adds the slot named slot. Adding a slot can
fail if the slot already exist. The added slot will be a dynamic
slot. A dynamic slot can be deleted. The del_slot
function deletes a dynamic slot. Deleting a slot will fail if the
slot does not exist or if the slot is static. Both
add_slot and del_slot returns true
on success or false on failure.
SIM_INTERFACE(component) {
bool (*pre_instantiate)(conf_object_t *obj);
void (*post_instantiate)(conf_object_t *obj);
bool (*create_cell)(conf_object_t *obj);
attr_value_t (*get_slots)(conf_object_t *obj);
attr_value_t (*get_slot_objects)(conf_object_t *obj);
attr_value_t (*get_slot_value)(conf_object_t *obj,
const char *NOTNULL slot);
void (*set_slot_value)(conf_object_t *obj,
const char *NOTNULL slot,
attr_value_t value);
bool (*has_slot)(conf_object_t *obj,
const char *NOTNULL slot);
bool (*add_slot)(conf_object_t *obj,
const char *NOTNULL slot);
bool (*del_slot)(conf_object_t *obj,
const char *NOTNULL slot);
};
#define COMPONENT_INTERFACE "component"
- Execution Context
| post_instantiate | Global Context
|
| pre_instantiate | Global Context
|
| create_cell | Global Context |
| get_slots | Cell Context |
| get_objects | Cell Context |
| get_slot_value | Global Context |
| set_slot_value | Global Context |
| add_slot | Global Context |
| del_slot | Global Context |
- Description
- The
component_connector is implemented by components
that use connector objects for handling connections between components.
The connection setup is made in two stages, the check stage and the
connect stage. The check stage is often not needed, but it can be
used to make sure that the later connect step will not fail. Each
connection is handled by a connector object. The connector object
will both handle the connection in both direction, i.e. sending
connect information and receiving connector information. Two
components that should be connected must implement one connector
object each.
The get_check_data and get_connect_data will
be called from the connector object to get connection data to send
to the other part of the connection, i.e. to the destination. The
data sent must be an attr_value_t type.
The check, connect, and disconnect
functions are called from the connector object when another
connector wants to connect to this connection. The connection data
is passed as the attr argument.
SIM_INTERFACE(component_connector) {
attr_value_t (*get_check_data)(conf_object_t *obj,
conf_object_t *NOTNULL connector);
attr_value_t (*get_connect_data)(conf_object_t *obj,
conf_object_t *NOTNULL connector);
bool (*check)(conf_object_t *obj, conf_object_t *NOTNULL connector,
attr_value_t attr);
void (*connect)(conf_object_t *obj, conf_object_t *NOTNULL connector,
attr_value_t attr);
void (*disconnect)(conf_object_t *obj,
conf_object_t *NOTNULL connector);
};
#define COMPONENT_CONNECTOR_INTERFACE "component_connector"
- Execution Context
- Global Context for all methods.
- Description
- The
concurrency_group interface is used to ensure
that groups of objects are placed in the same thread domain.
The serialized_memory_group method returns a list with objects
that should be placed in the same thread domain when the models
run in Sim_Concurrency_Mode_Serialized_Memory.
The execution_group method returns a list with objects that
should always be placed in the same thread domain.
Both methods take a group_index argument, allowing
multiple lists to be returned. The index argument is 0-based,
and a nil attribute for the first unsupported index. Note that
returned lists do not necessarily contain the object implementing
the interface; the interface can be used to group other objects.
When Simics forms the thread domain groups, all objects implementing the
concurrency_group are queried, and the constraints
are combined. For instance, the groups [A, B] and [A, C]
are combined into the group [A, B, C]. That is, the objects
A, B and C will be put in the same thread domain.
Refer to the threading chapter in the API Reference Manual
for more details.
SIM_INTERFACE(concurrency_group) {
attr_value_t (*serialized_memory_group)(conf_object_t *NOTNULL obj,
unsigned group_index);
attr_value_t (*execution_group)(conf_object_t *NOTNULL obj,
unsigned group_index);
};
#define CONCURRENCY_GROUP_INTERFACE "concurrency_group"
- Execution Context
- Global Context for all methods.
- Description
-
The concurrency_mode interface allows a model to
support a concurrency mode other than the default
Sim_Concurrency_Mode_Serialized.
The supported_modes method returns a bitmask
with all the supported modes.
The current_mode method returns the currently active
mode. Note that the model should normally checkpoint this setting.
The switch_mode method is invoked by Simics to notify
a model that a different concurrency mode has been selected by the user.
This typically happens when the user switches threading mode using
the set-threading-mode command. The object will typically
be placed in a different thread domain shortly after the call to this
method.
A model will be placed in the cell thread domain if it uses
the Sim_Concurrency_Mode_Serialized mode and
in a separate thread domain otherwise. The concurrency_group
interface can be used to ensure that multiple objects are placed in the
same thread domain.
Refer to the chapter about threading in the
API Reference Manual for details about thread domains,
the Standard Device Model and the Threaded Device Model.
typedef enum {
/* Model uses the Standard Device Model */
Sim_Concurrency_Mode_Serialized = 1,
/* Model uses the Threaded Device Model.
Direct memory pages are protected against concurrency. */
Sim_Concurrency_Mode_Serialized_Memory = 2,
/* Model uses the Threaded Device Model.
Concurrency can be observed on direct memory pages */
Sim_Concurrency_Mode_Full = 4,
} concurrency_mode_t;
SIM_INTERFACE(concurrency_mode) {
concurrency_mode_t (*supported_modes)(conf_object_t *NOTNULL obj);
concurrency_mode_t (*current_mode)(conf_object_t *NOTNULL obj);
void (*switch_mode)(conf_object_t *NOTNULL obj,
concurrency_mode_t mode);
};
#define CONCURRENCY_MODE_INTERFACE "concurrency_mode"
- Execution Context
- Global Context for all methods.
- Description
- The
connector interface must be implemented by
connector objects. The interface describes the connector and how it
can be connected to other connectors. A connector is used for
connecting component objects. The connector is just a proxy for the
connection, the connector uses the component_connector
interface in the components to setup the connection.
The type function returns the connector type as a
string. Two connectors can only be connected if the type is
identical.
A hotpluggable connector returns true when calling the
hotpluggable function, otherwise false. A
hotpluggable connector can be connected before or after the
component is instantiated, an non hotpluggable connector must be
connected before the component is instantiated.
The required function returns true if the
connector must be connected before instantiated, otherwise
false.
A connector can be connected to many connectors, but it is only
supported if the multi function return true. It
is not recommended that a connector support multi connections. A
component can instead dynamically create connectors when needed.
A connector has a direction; up, down or
any. The direction decides in which order the connectors
in a component tree are connected and the structure of the tree.
Connections are setup in two steps. The first step is to add the
connection, which is done using the add_destination
function. Adding a connection can fail for several reasons and it
is implementation dependent how the connection can fail. A
connection can for instance fail because the destination object
requires something that the source component did not pass when
checking the connection. Just adding a connection does not mean
that the components actually connect. The components have to save
the data given with the add_destination function. The
actual setup of the connection is made in the second step when the
update function is called, which finalizes the
connection.
The add_destination and remove_destination
functions sets the state of the connection. It is first when the
update function is called when the connection is
finalized. Both add_destination and
remove_destination returns true if the call was
successful otherwise they return false.
Parameters to the add_destination function are the own
object obj and the destination object
dst_obj. The destination object must be a port
object and it must implement the connector
interface.
The update function is called when the component should
update its current connection status. The status of the connection
has previously been set using the add_destination
or/and remove_destination functions.
The destination function returns a list of port objects
that the its connected to. The destination function
returns the state of the connection not the finalized state,
i.e. the state of the connection before update
functional call.
The check, connect, and disconnect
functions initiates a connection setup via the connector object. The
connector will forward the setup to the components affected by the
connection via the component_connector interface.
The deletion_requested function is called after disconnecting
components. A dynamic connector might want to return True in order to be
deleted just after the disconnection.
typedef enum {
Sim_Connector_Direction_Up,
Sim_Connector_Direction_Down,
Sim_Connector_Direction_Any
} connector_direction_t;
SIM_INTERFACE(connector) {
char *(*type)(conf_object_t *obj);
bool (*hotpluggable)(conf_object_t *obj);
bool (*required)(conf_object_t *obj);
bool (*multi)(conf_object_t *obj);
connector_direction_t (*direction)(conf_object_t *obj);
bool (*add_destination)(conf_object_t *obj, conf_object_t *connector);
bool (*remove_destination)(conf_object_t *obj,
conf_object_t *connector);
attr_value_t (*destination)(conf_object_t *obj); /* list of
connector objects */
void (*update)(conf_object_t *obj);
bool (*check)(conf_object_t *obj, attr_value_t attr);
void (*connect)(conf_object_t *obj, attr_value_t attr);
void (*disconnect)(conf_object_t *obj);
bool (*deletion_requested)(conf_object_t *obj);
};
#define CONNECTOR_INTERFACE "connector"
- Execution Context
- Global Context for all methods.
- Description
- This interface allows registration of callbacks for individual instructions,
i.e., instructions at a specific address. This interface can only be used
inside a
cpu_cached_instruction_cb_t callback where there is a
valid ci_handle. The callback is installed by calling the
register_cached_instruction_cb method in the
cpu_instrumentation_subscribe interface. The signature of the
callback function looks like this:
typedef void (*cpu_cached_instruction_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
cached_instruction_handle_t *ci_handle,
instruction_handle_t *iq_handle,
lang_void *user_data);
When the callback is installed Simics will call it every time an instruction
is put into the internal instruction cache, which might have different
entries for different execution modes. For example, in an unlikely case
where the same instruction is executed in 32-bit mode and later in 64-bit
mode (running an x86 processor for instance), this callback will be called
twice, one time for each mode. This allows the user to install specific
callbacks for this specific instruction and apply filtering based on
instruction types, etc. This approach is more efficient than doing dynamic
filtering in the instruction and read/write callbacks installed by the
cpu_instrumentation_subscribe interface.
The iq_handle together with the
cpu_instruction_query interface let a user examine
instruction properties. The user_data is the user data for the
callback.
SIM_INTERFACE(cpu_cached_instruction) {
void (*register_instruction_before_cb)(
conf_object_t *cpu,
cached_instruction_handle_t *ci_handle,
cpu_instruction_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_instruction_after_cb)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
cpu_instruction_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_read_before_cb)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
cpu_memory_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_read_after_cb)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
cpu_memory_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_write_before_cb)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
cpu_memory_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_write_after_cb)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
cpu_memory_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
#ifndef PYWRAP
void (*add_counter)(
conf_object_t *obj,
cached_instruction_handle_t *ci_handle,
uint64 *counter,
bool use_atomic_increment);
#endif
};
#define CPU_CACHED_INSTRUCTION_INTERFACE "cpu_cached_instruction"
The method register_instruction_before_cb installs a callback
that is called before the cached instruction is executed. The
ci_handle is used to bind the callback to the cached instruction.
The user_data is the callback's user data, and a callback for
freeing the data is also available. The free_cb looks like this:
typedef void (*cpu_callback_free_user_data_cb_t)(
conf_object_t *obj, conf_object_t *cpu, lang_void *user_data);
It is called when Simics wants to free cached instructions, which can happen
in various situations. obj is the connection object that should
free the data. The callback may be NULL if not needed.
The cb callback type is the same as used for instructions in the
cpu_instrumentation_subscribe interface:
typedef void (*cpu_instruction_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
instruction_handle_t *handle,
lang_void *user_data);
The object obj is the user object that registers the callback and
cpu is the processor object executing the instruction. The
handle can be used to query more data about the instruction. See
the cpu_instruction_query interface for more information. The
user_data is the user data associated with the callback.
The user data is a convenient location for storing information about the
instruction, such as user specific decode information, etc. The user data is
private for each installed callback.
The cached information about the instruction is bound to its physical
address so the logical address cannot typically be saved since it may vary
between calls (if the MMU-mapping has changed).
register_instruction_after_cb installs a callback that is called
after a cached instruction is executed. Otherwise it works in the same as
the before variant.
However, reading the program counter register for a control flow instruction
in this callback will reflect the new location, whereas using the
cpu_instruction_query for reading out the instruction address
will still return the address of the control flow instruction.
register_read_before_cb installs a callback that is called before
each read operation in the cached instruction. The callback is the
same as used for read and writes in the
cpu_instrumentation_subscribe interface:
typedef void (*cpu_memory_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
memory_handle_t *handle,
lang_void *user_data);
As for instructions, obj is the object that registered the
callback and cpu is the processor doing the access. The
handle can be used to further operate on the access by using the
cpu_memory_query interface. The
user_data and the free_cb arguments to
register_read_before_cb can be used to store user data for the
read operations in the cached instruction. The user data is private for each
installed callback but is shared between all read before operations in the
instruction.
register_read_after_cb installs a callback that is called after
each read operation in the cached instruction. The user data is private for
each installed callback but is shared between all read after operations in
the instruction. Otherwise it works in the same way as the before variant.
register_write_before_cb and register_write_after_cb
installs callbacks that is called before and after each write operation in
the cached instructions. Otherwise they work in the same way as the read
variants.
Note that installing a read or write callback on an instruction without any
memory operations will be useless.
The add_counter method can be used to add simple counters for
this particular instruction. The counter argument is a pointer to
a 64 bit counter value that will be incremented each time the instruction is
executed. This is the same thing (but more efficient) as registering a
callback through the register_instruction_before_cb method and
increasing the counter each time it is called.
Passing true for the argument use_atomic_increment makes the
increment of the counter atomic, which may be useful if the tool cannot have
an instrumentation connection per processor. This will however be slower due
to the nature of atomic instructions.
The location of the counter value can only be removed/deallocated after a
call to either the remove_callback method (passing the
cpu_cb_handle_t returned by
register_cached_instruction_cb), or to the
remove_connection_callbacks method (with the connection object as
the argument) in the cpu_instrumentation_subscribe interface.
This method is not available in Python.
The instrumentation_order interface cannot be used to
reorder callbacks installed with the cpu_cached_instruction
interface. The cached callbacks are always called in same order as the
cpu_cached_instruction_cb_t callback that installed them,
and before any callback installed by the corresponding methods in the
cpu_instrumentation_subscribe.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
registered by the register_cached_instruction_cb method in the
cpu_instrumentation_subscribe interface.
- Description
- This interface extends the
cpu_cached_instruction interface
and allows callbacks to be installed that trigger only once, i.e., after
the first time they have been invoked they are automatically
removed. Otherwise they are identical to the corresponding methods in the
cpu_cached_instruction interface.
SIM_INTERFACE(cpu_cached_instruction_once) {
void (*register_instruction_before_once_cb)(
conf_object_t *cpu,
cached_instruction_handle_t *ci_handle,
cpu_instruction_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
void (*register_instruction_after_once_cb)(
conf_object_t *cpu,
cached_instruction_handle_t *ci_handle,
cpu_instruction_cb_t cb,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
};
#define CPU_CACHED_INSTRUCTION_ONCE_INTERFACE "cpu_cached_instruction_once"
- Execution Context
- Threaded Context for all methods, but must be called from a callback
registered by the register_cached_instruction_cb method in the
cpu_instrumentation_subscribe interface.
- Description
- This interface is internal.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
registered by the register_cached_instruction_cb method in the
cpu_instrumentation_subscribe interface.
- Description
- The
cpu_exception_query interface is used to query information
about an exception for the a generic cpu architecture and should be used from
a cpu_exception_cb_t callback.
SIM_INTERFACE(cpu_exception_query) {
int (*exception_number)(conf_object_t *cpu, exception_handle_t *handle);
logical_address_t (*fault_pc)(conf_object_t *cpu,
exception_handle_t *handle);
};
#define CPU_EXCEPTION_QUERY_INTERFACE "cpu_exception_query"
exception_number is used to get the vector for the exception.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
receiving a handle of type
exception_handle_t.
- Description
- This interface is used to replace an existing instruction with a user
defined one or add new instructions to the simulation. The interface can
only be used from a cpu_instruction_decoder_cb_t callback
registered by the register_instruction_decoder_cb method in the
cpu_instrumentation_subscribe interface.
The interface consist of just one method and looks like this:
SIM_INTERFACE(cpu_instruction_decoder) {
void (*register_emulation_cb)(conf_object_t *cpu,
cpu_emulation_cb_t cb,
decoder_handle_t *handle,
lang_void *user_data,
cpu_callback_free_user_data_cb_t free_cb);
};
#define CPU_INSTRUCTION_DECODER_INTERFACE "cpu_instruction_decoder"
register_emulation_cb is used to set a callback function that
implements the semantics of the new or changed instruction. Every time the
instructions is executed on the cpu this function will be called
instead of the build-in implementation. The handle is the
decoder_handle_t handle passed to the
cpu_instruction_decoder_cb_t callback. The user_data
argument is user data for the callback. The free_cb is a clean-up
callback function that Simics calls when the instruction is overwritten or
if Simics wants to flush decoding caches. This function should deallocate
any the user data if present. Can be NULL if not used.
The signature of the emulation callback looks like this:
typedef cpu_emulation_t (*cpu_emulation_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
lang_void *user_data);
obj is the connection object, the same object as passed to the
cpu_instruction_decoder_cb_t callback. cpu is the processor
executing the replaced instruction. user_data is user data for
the emulation callback. This is a useful place for storing immediate or
register values for the new instruction. In the emulation function the whole
Cell Context API is available for use.
CPU_Emulation_Fall_Through should be returned from the emulation
callback if replaced one is a fall through instruction. The program counter
does not need to be updated. If the replaced instruction is doing any
control flow then CPU_Emulation_Control_Flow should be returned and
the program counter should be set to the destination address. This can be
done for fall through instruction as well but is less efficient.
CPU_Emulation_Default_Semantics can also be returned to indicate that
the default semantics should be used instead of the user defined. This can
be useful if the instruction only should be replaced under certain
circumstances.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
registered by the register_instruction_decoder_cb method in the
cpu_instrumentation_subscribe interface.
- Description
- The
cpu_instruction_query interface can be used in functions
of the following types:
cpu_instruction_cb_t
cpu_cached_instruction_cb_t
cpu_instruction_decoder_cb_t
where an instruction_handle_t pointer is available. The
handle is only valid in the callback. The interface is used to request
information about the instruction being executed by the processor
cpu.
SIM_INTERFACE(cpu_instruction_query) {
logical_address_t (*logical_address)(
conf_object_t *cpu, instruction_handle_t *handle);
physical_address_t (*physical_address)(
conf_object_t *cpu, instruction_handle_t *handle);
cpu_bytes_t (*get_instruction_bytes)(
conf_object_t *cpu, instruction_handle_t *handle);
bool (*is_existing_instruction)(
conf_object_t *cpu, instruction_handle_t *handle);
};
#define CPU_INSTRUCTION_QUERY_INTERFACE "cpu_instruction_query"
The logical_address and physical_address is used to
get the different addresses of the instruction being executed.
Note that if the instruction crosses a page boundary the last part of the
instruction will have a different mapping for the physical address than
returned by physical_address. To get hold of the physical address
on the second page, use the logical_to_physical method of the
processor_info(_v2) and provide the logical address of the
first byte on the second page.
The get_instruction_bytes method is used to read the instruction
bytes. The returned data is of a cpu_bytes_t type that contains the data and
the size. The data member is only available during the execution of the
callback. The data cannot be changed. Corresponding type in Python is a
string of bytes.
typedef struct cpu_bytes {
size_t size;
#ifndef PYWRAP
const uint8 *data;
#endif
} cpu_bytes_t;
The is_existing_instruction method is used to determine if Simics
managed to decode the instruction bytes. Note that despite this method
returning false could imply that the instruction is implemented using a user
supplied implementation through the
x86_instrumentation_subscribe interface.
Additional information can be read out with an architectural specific query
interface, see x86_instruction_query for details.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
receiving a handle of type
instruction_handle_t.
- Description
- The
cpu_instrumentation_subscribe interface is implemented by
processor classes that support CPU instrumentation. The interface can be
used to monitor and instrument various actions through callbacks. It is
designed for being more efficient than haps and will not synchronize any
threads. This means that any user of the interface must assume that
registered callbacks can be called in parallel by multiple threads if any of
the multi-threaded execution modes are used in Simics.
A processor implementing the interface is regarded as a provider of
instrumentation and is typically used by an instrumentation tool object. The
tool object is supposed to register callbacks in this interface and act when
they are called. To handle different threads it is recommended that the
tools uses a connection object (a sub-object created by the tool) that
registers these callbacks for each processor that it monitors. Then, any
data collected can be stored in these connection objects and will thus not
be subject to concurrent access from different threads that hosts the
processors. The data can than be aggregated by the tool when
appropriate. This approach needs no synchronization locks and allows for
efficient simulation.
See instrumentation_order interface for more details on the
callback order.
The cpu argument in all methods below is the processor object
implementing this interface.
The connection argument is the "user" object of this interface,
typically a connection object as described above. However, it can be any
object and even NULL if there is no suitable object to pass. For instance,
if the callback is registered by a Python script. In this case
synchronization will be handled by the Python layer.
All registration methods in the interface install at least one callback, the
cb argument, that will be called at a particular instrumentation
point in the processor object. The Simics Cell Context API is
available for use in these callbacks. The callbacks have different
signatures depending on their use case. The data
argument is user defined data that can be associated with each
callback. Every time the callback is called this data will be passed as an
argument to the callback. The data can be unique for each registration, even
though the same callback pointer is used.
Note:
Note, not all CPU models implement all parts of the instrumentation API.
Register methods not implemented in this interface will be NULL.
SIM_INTERFACE(cpu_instrumentation_subscribe) {
/* Callback specific methods */
void (*remove_callback)(
conf_object_t *NOTNULL cpu,
cpu_cb_handle_t *handle);
void (*enable_callback)(
conf_object_t *NOTNULL cpu,
cpu_cb_handle_t *handle);
void (*disable_callback)(
conf_object_t *NOTNULL cpu,
cpu_cb_handle_t *handle);
/* Callback groups methods, operating on several callbacks
associated to a connection. */
void (*remove_connection_callbacks)(
conf_object_t *NOTNULL cpu,
conf_object_t *NOTNULL connection);
void (*enable_connection_callbacks)(
conf_object_t *NOTNULL cpu,
conf_object_t *NOTNULL connection);
void (*disable_connection_callbacks)(
conf_object_t *NOTNULL cpu,
conf_object_t *NOTNULL connection);
/* Subscribe methods */
cpu_cb_handle_t *(*register_instruction_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_instruction_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_instruction_after_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_instruction_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_read_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_access_scope_t scope,
cpu_memory_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_read_after_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_access_scope_t scope,
cpu_memory_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_write_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_access_scope_t scope,
cpu_memory_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_write_after_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_access_scope_t scope,
cpu_memory_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_address_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_address_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_cached_instruction_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_cached_instruction_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_instruction_decoder_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_instruction_decoder_cb_t cb,
cpu_instruction_disassemble_cb_t disass_cb,
lang_void *data);
cpu_cb_handle_t *(*register_exception_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
int exception_number,
cpu_exception_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_exception_after_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
int exception_number,
cpu_exception_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_exception_return_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_exception_return_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_exception_return_after_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_exception_return_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_mode_change_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
cpu_mode_change_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_control_register_read_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
int register_number,
cpu_control_register_read_cb_t cb,
lang_void *data);
cpu_cb_handle_t *(*register_control_register_write_before_cb)(
conf_object_t *NOTNULL cpu,
conf_object_t *connection,
int register_number,
cpu_control_register_write_cb_t cb,
lang_void *data);
};
#define CPU_INSTRUMENTATION_SUBSCRIBE_INTERFACE \
"cpu_instrumentation_subscribe"
Callback Related Methods
Every function in this interface that registers a callback returns a unique
handle of type cpu_cb_handle_t. The remove_callback
method removes the callback associated with the handle. The
enable_callback and disable_callback methods can be
used to temporarily enable and disable a callback.
The remove_connection_callbacks removes all callbacks associated
with a connection object, i.e., all the callbacks that was registered with
the same connection object. The enable_connection_callbacks and
disable_connection_callbacks enables and disables all callbacks
associated with a connection object. NULL cannot be passed to these methods
to handle callbacks installed without any connection object.
The design philosophy is that registering and removing a callback can be
relatively expensive, whereas enable and disable a callback should be
cheap. On the other hand, a disabled callback can slow down the simulation
speed a bit more compared to running without callbacks.
Instruction Related Methods
The method register_instruction_before_cb installs a callback
that is called before an instruction is executed. The callback type is as
follows:
typedef void (*cpu_instruction_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
instruction_handle_t *handle,
lang_void *user_data);
The object obj is the connection or the user object that
registers the callback (or NULL if there is no object) and cpu is
the processor object executing the instruction. If a dedicated connection
object associated with each processor is used, the object's private data can
store the interface pointers needed to access processor state. This is a
useful trick to speed up the simulation speed. Otherwise such interface
pointers need to be acquired each time the callback is called. If no
connection object is used the pointers can be saved in the callback's user
data. The handle can be used to query more data about
the instruction, using the cpu_instruction_query
interface. The user_data is the user data associated with the
callback.
The registered callback is called for every instruction type. Use the
register_cached_instruction_cb method to control which type
of instructions that should be instrumented.
register_instruction_after_cb installs a callback that is called
after an instruction is executed. The callback is of the same type as for
the before variant and is called for every instruction type. Use the
register_cached_instruction_cb method to control which type
of instructions that should be instrumented. Reading the program counter
register for a control flow instruction in this callback will reflect the
new location, whereas using the cpu_instruction_query for
reading out the instruction address will still return the address of the
control flow instruction.
None: When an exception occurs the instruction is aborted and any
installed callbacks by the register_instruction_after_cb method
are not called.
Memory Related Methods
register_read_before_cb installs a callback that is called before
a memory read operation is performed. The callback type is as follows:
typedef void (*cpu_memory_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
memory_handle_t *handle,
lang_void *user_data);
As for instructions, obj is the object that registered the
callback and cpu is the processor doing the access. The
handle can be used to further operate on the
access by using the cpu_memory_query interface. The interface
can for instance be used to read the data of the memory operation. For more
information, see the documentation for the cpu_memory_query
interface.
The scope argument defines the access scope for the
callback. There are two defined scopes: CPU_Access_Scope_Explicit
and CPU_Access_Scope_Implicit. The explicit scope installs a
callback for every operation done explicitly by an instruction, such as
loading or storing a value. The implicit scope installs a callback for every
implicit access, such as table walks or memory accesses performed by
exception and interrupt handling. If all accesses are requested the same
callback function can be registered for both scopes by registering the
callback twice, one for each scope.
If a memory access crosses a page boundary the access will be split into two
separate calls, one for the first part covering the first page, and one for
the second part covering the second page. See the get_page_crossing_info
method in the cpu_memory_query interface for a way to
distinguish the different cases.
The user_data is the data associated with the callback.
Similar to register_read_before_cb, the following three methods
work in the same way:
register_read_after_cb installs a callback that is called after
a memory read operation is performed.
register_write_before_cb installs a callback that is called before
a memory write operation is performed.
register_write_after_cb installs a callback that is called after
a memory write operation is performed.
Memory accesses of prefetch types or any other control operation calls the
read callbacks. To distinguish them from reads an architecture specific
interface can be used to lookup the access type. See the
x86_memory_query interface for example.
None: When an exception occurs the instruction is aborted and any
installed memory callbacks after this point are not called.
Addresses
Note:
Only available on x86 targets.
register_address_before_cb can be used to register a callback
that will be called each time a logical address is generated by an
instruction for an explicit read or a write operation. This occurs before
the actual memory operation takes place. This allows a user to inspect and
change the target address for the operation. The callback has the following
signature:
typedef logical_address_t (*cpu_address_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
logical_address_t address,
address_handle_t *handle,
lang_void *user_data);
The argument obj is the object installing the callback and the
cpu is the processor generating the logical
address. The handle can be used to
extract more information about the address by using an architecture specific
interface. See the x86_address_query for details.
The new logical address should be returned by the callback.
Cached Instructions
register_cached_instruction_cb is used for installing a callback
that is called every time Simics inserts the instruction into an internal
instruction cache, i.e., executing from a specific address with a specific
execution mode for the first time. Executing the instruction again will
typically not invoke the callback since the instruction is already placed in
the instruction cache. However, if the cache is flushed and the instruction
is executed again the callback will once again be called. The callback has
the following signature:
typedef void (*cpu_cached_instruction_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
cached_instruction_handle_t *ci_handle,
instruction_handle_t *iq_handle,
lang_void *user_data);
From this callback one can use the cpu_cached_instruction
interface and ci_handle to register instrumentation callbacks for
this specific instruction alone. The installed callbacks will be called
every time the instruction is executed (even the first time just after the
cpu_cached_instruction_cb_t callback has returned).
This means that the
user can filter out certain instructions of interest and instrument only
those. The iq_handle and the cpu_instruction_query
interface can be use to do the filtering by examining the instruction. The
user_data is the callback user data for the callback.
For callbacks registered for memory operations only those in the explicit
scope issued by the instruction will be instrumented, e.g., hardware table
walks and exceptions will not be considered by this method. To instrument
these operations use the register_(read/write)_(before/after)_cb
with the implicit scope instead.
If no callbacks are registered by calling the
cpu_cached_instruction interface, the instruction will not be
instrumented.
Instruction Set Augmentation
register_instruction_decoder_cb lets the user redefine
instruction semantics in Simics, or implement new instructions. The
cb argument is a callback function that will be called every time
Simics decodes an instruction. From this callback the user can accept the
instruction or deny it. In most cases this only happens once per instruction
address since Simics usually caches decoding results in the internal
instruction cache. If the cache is flushed the callback may be called again.
The callback signature looks like this:
typedef int (*cpu_instruction_decoder_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
decoder_handle_t *decoder_handle,
instruction_handle_t *iq_handle,
lang_void *user_data);
The instruction bytes are read by using the get_instruction_bytes
method of the cpu_instruction_query interface together with
the iq_handle. The returned value is of a
cpu_bytes_t type. To access the bytes use the data and
the size members in the returned value.
If the decoder requires more bytes (i.e., because the new instruction is
longer), a negative integer value should be returned by the cb
function, indicating the number of bytes needed. For example, if the
available bytes are 3 but the decoder need at least 4 bytes, -4 should be
returned. The callback will then be called again with more available bytes
(this can be repeated if the new instruction requires even more bytes at
this point). Note that requesting more data than actual needed can cause
spurious page faults if the data crosses a page boundary.
If the instruction is accepted by the callback a positive integer number
should be returned corresponding to the length of the instruction. In this
case the register_emulation_cb method of the
cpu_instruction_decoder interface should be called to set the
actual (user) function that Simics will call each time the instruction is
executed.
If the cb callback should ignore the instruction the number 0
should be returned. This means that any other registered decoder will have a
chance to decode the instruction. If no decoder accepts it, Simics' default
implementation will be used.
The register_emulation_cb method also needs the
decoder_handle which is available in the dedoder callback. For
more information, see the documentation of the
cpu_instruction_decoder interface.
A disass_cb argument should also be passed to the
register_instruction_decoder_cb method. This function is called
every time Simics wants to disassemble an instruction. For every accepted
instruction a corresponding disassembly string should be returned by this
function. It has the following signature:
typedef tuple_int_string_t (*cpu_instruction_disassemble_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
generic_address_t addr,
cpu_bytes_t bytes);
obj is the object registering the
register_instruction_decoder_cb and cpu is the
processor disassembling the instruction. addr is the address of
the instruction in a generic form. This means that it is typically a
physical address or a logical address depending on the context of the
disassembling. The address can be used for offset calculations, i.e.,
displaying an absolute address instead of a relative one, for example in a
branch instruction. The bytes argument should be used to read
instruction bytes. The return value is of type
tuple_int_string_t and should be filled with the instruction
length and an allocated (e.g., malloc) string representing the disassembly
of the instruction. The ownership of the string is transferred to the
calling environment which will free it when it is no longer needed.
If too few bytes are passed for the instruction to be disassembled a
negative value should be returned for the length indicating the needed
bytes. The disass_cb is then called again with more bytes. If the
instruction is rejected a length of 0 should be returned and the string
should be set to NULL.
Exception Related Methods
register_exception_before_cb is used to register a callback that
will be called before an exception or interrupt is taken. The
exception_number can be used to select a callback on a specific
exception, with the same number as used in the exception
interface. If all exceptions should be subscribed to, the
CPU_Exception_All constant can be used.
The callback signature looks like this:
typedef void (*cpu_exception_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
exception_handle_t *exception_handle,
lang_void *user_data);
The obj is the object registering the callback and cpu
is the processor that takes the exception or receives the interrupt. The
handle is used to get more architectural information about the exception,
for example, see the x86_exception_query for details. The
user_data is the callback user data.
No architectural state has been changed in this callback to reflect the
exception or interrupt, e.g., the program counter will still be at the
faulting instruction. Since an exception can occur while handling an
exception it is not always the case that this callback corresponds to the
final taken exception. Recursive exception will result in another call to
this callback.
register_exception_after_cb is used to register a callback that
will be called after an exception was taken. It takes the same arguments as
register_exception_before_cb. In this callback the architectural
state has been updated, e.g., the program counter points to the first
instruction of the exception handler. The callback is of the same type as
for the before variant.
register_exception_return_before_cb is used to register a
callback that will be called just before an exception handler is done and
resumes execution of the normal program code. The callback signature looks
like this:
typedef void (*cpu_exception_return_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
exception_return_handle_t *exception_handle,
lang_void *user_data);
The obj is the object registering the callback and cpu
is the processor that takes the exception or receives an interrupt. The
handle is used to get more architectural information about the
exception. Currently there is no interface available for this.
register_exception_return_after_cb is used to register a callback
that will be called after an exception has been executed, e.g., the program
counter points to the normal program where execution will continue.
Execution Mode
register_mode_change_cb is used to register a callback that will
be called every time the processor changes mode. The supported modes are:
user, supervisor, and hypervisor.
The callback signature looks lite this:
typedef void (*cpu_mode_change_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
processor_mode_t old_mode, processor_mode_t new_mode,
lang_void *user_data);
The obj is the object registering the callback and cpu
is the processor that changes mode. The old_mode is the mode
before the change and new_mode is the mode after the change.
Control Registers
register_control_register_read_before_cb is used to register a
callback that will be called before every control register read. The
register_number is the control register number to install the
callback on. It is the same number which is used in the
int_register interface. The constant
CPU_Control_Register_All can be used to subscribe to all control
registers.
The callback signature looks like this:
typedef void (*cpu_control_register_read_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
int register_number,
lang_void *user_data);
The obj is the object registering the callback and cpu
is the processor that reads the control register register_number.
The user_data is the user data for the callback.
register_control_register_write_before_cb is used to register a
callback that will be called before every control register write. The
register_number is the control register number to install the
callback on. It is the same number which is used in the
int_register interface. The constant
CPU_Control_Register_All can be used to subscribe to all control
registers.
The callback signature looks like this:
typedef void (*cpu_control_register_write_cb_t)(
conf_object_t *obj, conf_object_t *cpu,
int register_number,
uint64 value,
lang_void *user_data);
The obj is the object registering the callback and cpu
is the processor that writes to the control register
register_number. The value is the value that will be
written. The user_data is the user data for the callback.
- Execution Context
- Global Context for all methods.
- Description
- The
cpu_memory_query interface is used by
callbacks of the cpu_memory_cb_t type and requires a
valid memory_handle_t handle. The handle is only valid during
the call of the callback. It is used to request information about the memory
operation being issued by the processor cpu.
SIM_INTERFACE(cpu_memory_query) {
logical_address_t (*logical_address)(
conf_object_t *cpu, memory_handle_t *handle);
physical_address_t (*physical_address)(
conf_object_t *cpu, memory_handle_t *handle);
#ifndef PYWRAP
void (*set_host_ptr)(
conf_object_t *cpu, memory_handle_t *handle,
void *p);
#endif
cpu_bytes_t (*get_bytes)(conf_object_t *cpu,
memory_handle_t *handle);
void (*set_bytes)(
conf_object_t *cpu, memory_handle_t *handle,
cpu_bytes_t bytes);
bool (*atomic)(
conf_object_t *obj, memory_handle_t *handle);
ini_type_t (*arch)(
conf_object_t *obj, memory_handle_t *handle);
page_crossing_info_t (*get_page_crossing_info)(
conf_object_t *obj, memory_handle_t *handle);
buffer_t (*get_surrounding_bytes)(
conf_object_t *cpu, memory_handle_t *handle,
unsigned granularity_log2);
};
#define CPU_MEMORY_QUERY_INTERFACE "cpu_memory_query"
The logical_address and physical_address methods are
used to get the different addresses of the memory operation.
Below, callbacks registered by the register_read_before_cb or the
register_write_before_cb in the
cpu_instrumentation_subscribe interface or in the
cpu_cached_instruction interface are referred to as being
in before context. Callbacks registered by the
register_read_after_cb or the register_write_after_cb
in the cpu_instrumentation_subscribe interface or in the
cpu_cached_instruction interface are referred to as being
in after context.
The set_host_ptr method can be used to redirect where data should
be read from or written to depending on if it is a read or a write
operation. The method is only useful for callbacks registered in
before context. The data pointer p needs to be valid
during the execution of the instruction and must point to enough space to
carry out the operation. This method is not available in Python.
The get_bytes method is used to retrieve the bytes that is going
to be read/written if called in a before context and is used to read
out value that was read/written in after context. The value is
returned as cpu_bytes_t:
typedef struct cpu_bytes {
size_t size;
#ifndef PYWRAP
const uint8 *data;
#endif
} cpu_bytes_t;
The member data contains the data pointer, and the member
size contains tha size of the data. It is illegal to access beyond
the limit. For such access, see the get_surrounding_bytes below.
The read value in before context may not be
available (a device access for example) and in this case the data member
will be NULL.
The set_bytes method is used to override the bytes to be read or
written. The method is only valid in the before context. This method
can be used instead of the set_host_ptr to change the value of
the operation. The value is passed as cpu_bytes_t and the
supplied data in the data member need not to be valid after the callback
returns since the data is copied. The length of the data cannot be changes
and must be the same as returned by the get_bytes method.
The atomic method returned true if the operation is considered
atomic, false otherwise.
The arch method returns the ini_type_t of the memory
operation.
Accesses that cross a page boundary are split into two subsequent accesses,
one for the first page and one for the second page. The
get_page_crossing_info method can be used to distinguish the
different cases from each other. The returned value from the method is of
type page_crossing_info_t and can be one of:
Sim_Page_Crossing_None (no crossing access),
Sim_Page_Crossing_First (first part of a crossing access), or
Sim_Page_Crossing_Second (second part of a crossing access).
The get_surrounding_bytes method provides quick access to the
data surrounding the access. The granularity_log2 specifies the
size and alignment of the buffer being returned. For example using 6 for
granularity_log2, will fetch 64 aligned bytes around the
address of the access. Typically, the largest supported granularity_log2
size is 12, meaning a 4 KiB page. The returned value is of type buffer_t and
is only valid in the cpu_memory_cb_t callback. The
data can be accessed by using the buffer_t.data member in the
returned value. Data can only be read up to the size of the buffer, which is
stored in the buffer_t.len member. Valid memory is only returned if
the access terminates in simulator cached memory. If not, the
buffer_t.len will be is 0, buffer_t.data cannot be used.
Additional information can be read out with an architectural specific
query interface, see x86_memory_query interface for details.
- Execution Context
- Threaded Context for all methods, but must be called from a callback
receiving a handle of type
memory_handle_t.
- Description
- Interface Methods
- The
cycle interface is typically implemented by
processors, but can be implemented by other objects as well. Its purpose is
to handle events based on time. The cycle queue has a cycle as the smallest
time unit. The cycle queue also has an associated frequency which makes it
possible to define events based on seconds or picoseconds.
The get_frequency function returns the frequency in Hertz for
the queue. Most objects implementing cycle also
have a notification mechanism for frequency changes through the
simple_dispatcher interface in the cpu_frequency
port. It is recommended that such a notification mechanism is used to get
updates rather than polling with get_frequency.
The current number of cycles executed by the queue is returned
by get_cycle_count. Time elapsed since the queue was created is
returned by get_time (in seconds) and get_time_in_ps
(in picoseconds); this will be equal to the value returned
by get_cycle_count divided by the value returned
by get_frequency if the frequency has been constant since time
zero.
The cycles_delta function returns the highest number of cycles
obj can run before it passes the absolute local time
when, assuming no frequency change occurs in the
meantime. Note that cycles_delta can raise an exception if
when was too far ahead in the future. The
cycles_delta_from_ps function performs the same function, for an
absolute local time expressed in picoseconds.
The post_cycle function will schedule an event that will occur
after cycles counted from local current time at
queue. The post_time function is similar but takes
seconds as argument, while post_time_in_ps takes
a number of picoseconds. The arguments
cycles, seconds and
picoseconds must be nonnegative.
An event previously posted can be removed by calling cancel. The
cancel function takes a function pred as argument
which is called when a matching event is found. The event is only removed if
pred returns 1.
The find_next_cycle, find_next_time and
find_next_time_as_ps functions take the same arguments as
cancel but only return the number of cycles, seconds or
picoseconds before the event occur. The evclass is the event
class, obj is the object posting the event, and
user_data is pointer to data used as a parameter when calling
the callback function defined in the evclass.
If no matching event was found, find_next_cycle and
find_next_time return −1;
find_next_time_as_ps returns ILLEGAL_DURATION.
The events method returns a list of all pending events in
expiration order. Each element is a four-element list containing the event
object, the event class name, the expiration time counted in cycles as an
integer and the event description as given by the event class
describe method, or NIL for events whose event class does not
define that method.
What happens to already posted events when a frequency change occurs is
implementation dependent. Simics processors will scale the cycle queue to
keep the time left before triggering events equal across the frequency
change. Note that the new times will be rounded to entire cycles during the
scaling, so approximations may occur when switching between high and low
frequencies.
- Implementation
- It is implementation dependent how the queue is implemented, whether
cycles or seconds are used as underlying time unit, and what happens when the
frequency is changed.
Objects implementing the cycle interface are usually meant to be scheduled by
Simics itself. For this to happen, a number of conditions must be fulfilled:
- Each schedulable object implementing the
cycle interface
must be controlled by an object implementing the execute
interface. It can be the same object that implements the
execute interface. The object implementing the
execute interface points to the object implementing the
cycle interface via its queue attribute.
- Any schedulable object implementing the
cycle interface
must inform Simics about changes in frequency by calling the
VT_clock_frequency_change function. That also applies to the
initial frequency set when the object is created.
- For schedulable objects, the
cycle interface must be
registered with SIM_register_clock, which will also add some
Simics specific attributes to the corresponding class. Beyond those, the
implementor of the cycle can use any checkpoint
representation. The name field in the event class data
structure is unique, and the attribute setter function for checkpoint restore
can use SIM_get_event_class to get the event class structure
corresponding to an event class name.
SIM_INTERFACE(cycle) {
cycles_t (*get_cycle_count)(conf_object_t *queue);
double (*get_time)(conf_object_t *queue);
cycles_t (*cycles_delta)(conf_object_t *NOTNULL clock,
double when);
uint64 (*get_frequency)(conf_object_t *queue);
void (*post_cycle)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
cycles_t cycles,
lang_void *user_data);
void (*post_time)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
double seconds,
lang_void *user_data);
void (*cancel)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
cycles_t (*find_next_cycle)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
double (*find_next_time)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
attr_value_t (*events)(conf_object_t *NOTNULL obj);
/* new picoseconds based functions */
local_time_t (*get_time_in_ps)(conf_object_t *queue);
cycles_t (*cycles_delta_from_ps)(conf_object_t *NOTNULL clock,
local_time_t when);
void (*post_time_in_ps)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
duration_t picoseconds,
lang_void *user_data);
duration_t (*find_next_time_in_ps)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
};
#define CYCLE_INTERFACE "cycle"
- Execution Context
- Cell Context for all methods.
- Description
- The
cycle_control interface is typically for
controlling a cycle counter with event posting capabilities.
The initiator object should call start or
stop to start/stop the counting of cycles. And use
set_cycle_count is used to configure the current
cycle count at the target object.
SIM_INTERFACE(cycle_control) {
void (*stop)(conf_object_t *NOTNULL obj);
void (*start)(conf_object_t *NOTNULL obj);
void (*set_cycle_count)(conf_object_t *NOTNULL obj,
cycles_t cycle_count);
};
#define CYCLE_CONTROL_INTERFACE "cycle_control"
- Execution Context
- Cell Context for all methods.
- Description
- TODO: document the
cycle_event interface.
SIM_INTERFACE(cycle_event) {
cycles_t (*cycles)(conf_object_t *NOTNULL obj);
void (*post)(conf_object_t *NOTNULL obj,
const event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL ev_obj,
cycles_t cycles,
lang_void *param);
void (*cancel)(conf_object_t *NOTNULL obj,
const event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL ev_obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
cycles_t (*lookup)(conf_object_t *NOTNULL obj,
const event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL ev_obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
attr_value_t (*events)(conf_object_t *NOTNULL obj);
};
#define CYCLE_EVENT_INTERFACE "cycle_event"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is internal.
- Execution Context
- Global Context.
- Description
-
SIM_INTERFACE(decoder) {
void (*register_decoder)(conf_object_t *obj,
decoder_t *NOTNULL decoder);
void (*unregister_decoder)(conf_object_t *obj,
decoder_t *NOTNULL decoder);
};
The decoder interface is implemented by processors
that allows connecting user decoders. This allows a user to
implement the semantics of instructions that are not available in
the standard Simics model or change the semantics of instructions
implemented by Simics. This interface replaces
SIM_register_arch_decoder and
SIM_unregister_arch_decoder functions.
The register_decoder function adds a decoder and
unregister_decoder removes a decoder.
The decoder is installed/removed for every object of the same class as the
obj argument which must be the same object from
which the interface was fetched.
When Simics decodes an instruction, it will first see if any
instruction decoders are registered for the current CPU class.
For any decoders it finds, Simics will let it try to decode the
instruction. The decoders are called in order, starting with the
last registered decoder, and if one decoder accepts the instruction,
the rest of the decoders will not be called.
The decoder is specified by the decoder_t data structure that the
user supplies:
typedef struct {
void *user_data;
int (*NOTNULL decode)(uint8 *code,
int valid_bytes,
conf_object_t *cpu,
instruction_info_t *ii,
void *user_data);
tuple_int_string_t (*NOTNULL disassemble)(uint8 *code,
int valid_bytes,
conf_object_t *cpu,
void *user_data);
int (*NOTNULL flush)(instruction_info_t *ii,
void *user_data);
} decoder_t;
The decode function is called to decode an instruction
pointed to by code. The first byte corresponds to
the lowest address of the instruction in the simulated
memory. valid_bytes tells how many bytes can be
read. The CPU is given in the cpu parameter. When
the decoder has successfully decoded an instruction, it should set
the ii_ServiceRoutine, the ii_Arg, and the
ii_Type members of the ii structure (see
below), and returns the number of bytes used in the decoding. If
it does not apply to the given instruction, it should return zero.
If the decoder needs more data than valid_bytes it
should return a negative number corresponding to the total number
of bytes it will need to continue the decoding. The underlying
architecture limits the number of bytes that can be requested,
e.g. no more than 4 bytes can be requested on most RISC
architectures. Simics will call the decoder again when more bytes
are available. This process is repeated until the decoder accepts
or rejects the instruction. A decoder should never request more
data than it needs. For example, if an instructions can be rejected
by looking at the first byte, the decoder should never ask for more
bytes.
The instruction_info_t is defined as follows:
typedef struct instruction_info {
service_routine_t ii_ServiceRoutine;
uint64 ii_Arg;
unsigned int ii_Type;
lang_void *ii_UserData;
logical_address_t ii_LogicalAddress;
physical_address_t ii_PhysicalAddress;
} instruction_info_t;
ii_ServiceRoutine is a pointer to a function that will
be called by Simics every time the instruction is executed. It has
the following prototype:
typedef exception_type_t (*service_routine_t)(conf_object_t *cpu,
uint64 arg,
lang_void *user_data);
The service routine function should return an exception when it is
finished to signal its status. If no exception occurs
Sim_PE_No_Exception should be returned.
See exception_type_t in
src/include/simics/base/memory.h for the different
exceptions available.
A special return value, Sim_PE_Default_Semantics, can be
returned; this signals Simics to run the default semantics for the
instruction. This is useful if the semantics of an instruction
should be changed but the user routine does not want to handle it all
the time.
Note that in a shared memory multiprocessor, the CPU
used in decoding may differ from the CPU that executes the
instruction, since the decoded instructions may be cached.
ii_Arg is the argument arg that will be
passed on to the service routine function. Op code bit-fields for
the instruction such as register numbers or intermediate values can
be stored here. The ii_UserData field can also be used
to pass information to the service routine if more data is needed.
ii_Type is either UD_IT_SEQUENTIAL or
UD_IT_CONTROL_FLOW. A sequential type means that the
instruction does not perform any branches and the update of the
program counter(s) is handled by Simics. In a control flow
instruction on the other hand it is up to the user to set the
program counter(s).
ii_LogicalAddress and ii_PhysicalAddress
holds the logical and physical addresses of the instruction to be
decoded.
The disassemble function is called to disassemble an
instruction. It uses the same code,
valid_bytes, and cpu parameters as
the decode function. If the disassembly is valid, then
the string part of the returned tuple_int_string_t struct
should be a MALLOCed string with the disassembly and the integer
part should be its length in bytes. The caller is responsible for
freeing the disassembly string. The string member should be NULL
and the integer part should be zero if the disassembly is not
valid. If the disassemble function needs more data than
valid_bytes it should return a negative number in
the integer part in the same way as the decode function,
and set the string part to NULL.
The flush function is called to free any memory
allocated when decoding an instruction and any user data associated
with the instruction. It should return zero if it does not
recognize the instruction, and non-zero if it has accepted it.
Usually, the way to recognize if a decoded instruction is the right
one to flush is to compare ii->ii_ServiceRoutine with the
function that was set in the decode function. Note
that the cpu parameter is the processor that caused
the flush. It is more or less an arbitrary processor and should be
ignored.
In addition to the function pointers, the
decoder_t structure contains a
user_data pointer that is passed to all the
functions. This can be used for passing any data to the decoder
functions.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used by the Simics debugger to get certain information from
a processor.
The first_child function returns the first description in the
sequence of child descriptions of parent or NULL if parent has no
children. Groups can have both registers and groups as children, registers
can only have fields as children and fields cannot have any children. If
parent is NULL, return the first description in the sequence of top-level
descriptions.
Use next_description to deallocate the previous description and
return the next description in the sequence or NULL if there are no more
descriptions in the current sequence.
The free_description function is used to free the description
without returning the next one in the sequence.
The first_named_value function returns the first named value in
the sequence of named values for parent or NULL if there are no named values
for parent. Only fields and registers can have named values.
Use next_named_value to deallocate the previous named value and
return the next named value or NULL if there are no more named values in this
sequence.
Use free_named_value to free the named value without returning the
next one in the sequence.
The get and set functions are used to get and set the
value of the register. To set the value pass in a bytes_t for the value. The
value passed in must be long enough to contain the full value of the
register. If the bytes_t is too long it will be truncated. To get the value
pass in a buffer_t which is long enough to contain the register's value. The
value is encoded in little endian byte order.
typedef enum {
Description_Type_Group,
Description_Type_Int_Reg,
Description_Type_Float_Reg,
Description_Type_Fields_Reg,
Description_Type_Int_Field,
Description_Type_Float_Field,
} description_type_t;
typedef enum {
Reg_Role_None, /* No special role for the register. */
Reg_Role_Program_Counter /* The register is the program counter. */
} reg_role_t;
typedef enum {
Reg_Bitorder_Little_Endian,
Reg_Bitorder_Big_Endian
} reg_bitorder_t;
typedef struct {
const char *name;
const char *description;
const bytes_t value; /* Little endian byte order */
} named_value_t;
typedef struct {
/* Common fields */
description_type_t type;
const char *name;
const char *description;
/* Register and field fields */
int16 dwarf_id; /* id used by dwarf for this register
or -1 if no such id is defined. This
is ABI specific, but the CPU will
give the ids for the most common ABI
for that architecture. */
reg_bitorder_t bitorder; /* Bitorder convention used in the
documentation for this register or
field. */
reg_role_t role; /* Role of this register in the ABI/HW. */
bool memory_mapped; /* True if the register is memory mapped. */
uint64 offset; /* Offset into the bank for memory mapped
registers. */
bool catchable; /* True if Core_Control_Register_Write and
Core_Control_Register_Read are triggered
when this register is written or read. */
int msb, lsb; /* Most and least significant bit of the
register or field. Always given in le
bitorder. For groups msb == -1 and
lsb == 0. */
int regsize; /* Number of bits in the register, or the
register this field is a part of. */
int reg_id; /* For registers and fields the id to pass
to the get and set methods to access the
register's value. Fields have the same
reg_id as the register they are a part
of. Not valid for groups.*/
} description_t;
SIM_INTERFACE(describe_registers) {
const description_t *(*first_child)(
conf_object_t *NOTNULL obj, const description_t *parent);
const description_t *(*next_description)(
conf_object_t *NOTNULL obj, const description_t *prev);
void (*free_description)(conf_object_t *NOTNULL obj,
const description_t *desc);
const named_value_t *(*first_named_value)(
conf_object_t *NOTNULL obj, const description_t *parent);
const named_value_t *(*next_named_value)(
conf_object_t *NOTNULL obj, const named_value_t *prev);
void (*free_named_value)(conf_object_t *NOTNULL obj,
const named_value_t *nv);
void (*get)(conf_object_t *NOTNULL obj, int reg_id, buffer_t dest);
void (*set)(conf_object_t *NOTNULL obj, int reg_id, bytes_t value);
};
#define DESCRIBE_REGISTERS_INTERFACE "describe_registers"
- Execution Context
- Cell Context for all methods.
- Description
- The
device_identification interface is used to identify device
type such as product, stepping etc.
get_id returns the identifier for the given key.
Existing keys can be retrieved using the get_key function. All
existing keys should return a valid identifier string. For unknown keys the
returned value is NULL.
get_key returns the key at the specified index or NULL
starting at 0, to get the key at that index. At the index where
NULL is returned there are no more keys.
get_key returns the key at the specified index, or
NULL if the index does not correspond to a key. To get the
complete list of keys, call get_key using an index
starting at zero, and increase the index for each call until
get_key returns NULL.
SIM_INTERFACE(device_identification) {
const char *(*get_id)(conf_object_t *NOTNULL obj, const char *key);
const char *(*get_key)(conf_object_t *NOTNULL obj, unsigned int index);
};
#define DEVICE_IDENTIFICATION_INTERFACE "device_identification"
- Execution Context
- Cell Context for all methods.
- Description
-
The direct_memory interface is implemented by objects that
model memory, such as RAM and ROM objects. These are called direct-memory
objects. A user of the interface is called a memory user and is
typically a processor that wants to do fast accesses to memory. The
direct-memory object corresponding to a particular physical address
can be obtained using the lookup method of the
direct_memory_lookup interface.
See the documentation for the
direct_memory_lookup interface for more information.
A memory user using the direct_memory interface
must implement the direct_memory_update interface.
The get_handle method is used by a memory user
to create or retrieve a handle to the memory region starting
at offset offs with size size.
The handle is typically used later on to request access permissions
and to retrieve a direct pointer to the region.
The handle returned by get_handle is private to the
memory user specified in the requester parameter.
If get_handle is invoked multiple times for the same
range, and with identical requester and
subsystem arguments, then the same handle will
be returned each time, assuming the original handle is still valid.
Note that the original handle is only returned if the range
matches exactly. A single memory user can obtain multiple
distinct handles for the same memory range by using different values for the
subsystem parameter.
For RAM and ROM, offs and size must
specify a region which does not intersect a naturally aligned
8192 byte boundary, or the request will fail with a NULL return
value. Other direct-memory objects might have different requirements.
The request method is used to request a host pointer to simulated
memory. This pointer can be used to carry out fast memory operations without
having to involve the Simics API. The handle argument is the
handle obtained using get_handle.
Both the permission argument and the inhibit argument
are access_t type bit fields. The permission
argument is used to specify what kind of memory operations the memory user
will perform. For example, if a memory user wants to read memory, the
permission argument must include the Sim_Access_Read value. The
inhibit argument specifies what other memory users are not
allowed to do. For example, if inhibit is set to Sim_Access_Write
other memory users are not allowed to write to the memory range. This
protection mechanism can be used to create caches of simulated memory,
request exclusive permissions to a memory range in order to carry out atomic
operations, and similar. When a memory user is requesting permission to a
memory range that another memory user has protected with conflicting inhibit
bits, the direct-memory object will inform the other memory user of
the lost permissions and protection through the
direct_memory_update interface. A user can lose both the
permission and protection for a memory range in this way. When this happens,
a memory user may re-request permissions and inhibit protection.
Note: if a memory user has multiple handles which overlaps, then
each handle is considered to be a distinct memory user. For example,
if a memory user holds two handles, and requests write inhibit on
one of them, then write permission will be revoked from the second
handle (if such permission had been granted).
The request method returns a direct_memory_t value
with information about the retrieved permissions and inhibit bits. These
bits can be a super set of the bits that actually were requested. The
returned data pointer can be used to access the memory range. Accesses are
valid from the data pointer and up to the end of the range, i.e., addresses
up to data pointer + size - 1, where size is the size valid for
the handle. A call to request always succeeds and the
corresponding memory range is valid until the permissions or the handle are
revoked by the direct_memory_update interface. Note that the
data pointer may change each time request is called (with the
same handle) since Simics may move simulated memory. If the pointer
changes, then the old pointer must not be used.
With set_user_data, a memory user can associate
a user-defined pointer with a specific handle. The pointer can
be retrieved using the get_user_data method, which takes
a handle as an argument.
A memory user can use the release function to notify the
direct-memory object when it is no longer interested in the memory
region corresponding to handle. The handle is invalid
and must not be used for anything after being released.
The ack method is used by a memory user to inform the
direct-memory object that it has given up the corresponding permission and
inhibit rights for a memory range when called by a method in the
direct_memory_update interface.
Permissions can be revoked from all memory users by invoking the
revoke method. The permission parameter
specifies the permissions which will be revoked from all memory users.
Similarly, inhibit specifies the inhibit privileges which
will be revoked. For instance, calling revoke with
permission
set to Sim_Access_Write will ensure that nobody has
write permissions to the direct-memory object.
typedef granted_mem_t *direct_memory_handle_t;
typedef struct {
#ifndef PYWRAP
uint8 *data;
#endif
access_t permission;
access_t inhibit;
} direct_memory_t;
typedef uint64 direct_memory_ack_id_t;
SIM_INTERFACE(direct_memory) {
direct_memory_handle_t (*get_handle)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL requester,
uint64 subsystem,
uint64 offs,
unsigned size);
direct_memory_t (*request)(conf_object_t *NOTNULL obj,
direct_memory_handle_t handle,
access_t permission,
access_t inhibit);
void (*revoke)(conf_object_t *NOTNULL obj,
access_t access,
access_t permission,
access_t inhibit);
#ifndef PYWRAP
void *(*get_user_data)(conf_object_t *NOTNULL obj,
direct_memory_handle_t handle);
void (*set_user_data)(conf_object_t *NOTNULL obj,
direct_memory_handle_t handle,
void *user_data);
#endif
void (*release)(conf_object_t *NOTNULL obj,
direct_memory_handle_t handle);
void (*ack)(conf_object_t *NOTNULL obj,
direct_memory_ack_id_t id);
};
#define DIRECT_MEMORY_INTERFACE "direct_memory"
- Execution Context
- Cell Context for all methods.
- Description
- The
direct_memory_flush interface is implemented by objects
that model memory, such as RAM and ROM objects, and is used for flushing
granted rights and for managing access rights.
The revoke method revokes granted access, permissions and
inhibit rights from memory-user regions intersecting
[base, base + size).
The set_access_bits method grants access rights
access for the region [base,
base + size) to the memory user
requester. If requester is NULL, then
access rights are granted to all memory users. If the set succeeds, true is
returned, otherwise false.
SIM_INTERFACE(direct_memory_flush) {
void (*revoke)(conf_object_t *NOTNULL obj,
uint64 base, uint64 size,
access_t access, access_t perm, access_t inhibit);
bool (*set_access_bits)(conf_object_t *NOTNULL obj,
conf_object_t *requester,
uint64 base, uint64 size,
access_t access);
};
#define DIRECT_MEMORY_FLUSH_INTERFACE "direct_memory_flush"
- Execution Context
- Cell Context for all methods.
- Description
-
The direct_memory_lookup interface is implemented by Simics
memory-spaces. The interface is used by simulator objects that want to do
fast accesses to memory and/or want to build up a cached representation of
memory. These objects are referred to as memory users, e.g., processors.
Fast accesses are done via host pointers to simulated memory. The
direct_memory_lookup interface is used in conjunction with
the direct_memory interface which is implemented by objects
that own the actual data storage, e.g., RAM/ROM objects. These objects are
called direct-memory objects.
To access data, a memory-user object first calls the lookup
method on the memory space obj. The
requester is the memory-user doing the lookup.
The lookup method traces the range specified by
addr and size
through memory spaces and translators until a direct-memory object
is reached. The direct-memory object is returned in the
target field and the offset into this object
corresponding to addr is returned in the
offs field.
The call to lookup fails if the specified range does
not map continuously to a direct-memory object. A lookup failure
is indicated by returning NULL in the target field.
The access argument is a bit field of at least one
access_t value specifying what kind of accesses the memory user
is interested in. All specified access types must reach the same
direct-memory object and range for the lookup to succeed. If the memory
space, for example, redirects reads and writes to different memory ranges or
direct-memory objects, a lookup would fail if access
specified both read and write. Note that the actual access permissions
needed to access the real data must be requested from
the direct-memory object using the request method of
the direct_memory interface. The access
argument is only used to locate the direct-memory object.
The return field access contains at least the access
bits requested used in the lookup request, but may as an optimization
contain a superset, indicating that the lookup result is valid for this
superset. However, there is no guarantee that this optimization
takes place.
Once a direct-memory object has been found, the direct_memory
interface can be used to obtain a direct pointer to the contents
of the direct-memory object.
The tracers and breakpoints fields in the
return value contain information about installed tracers and breakpoints
that intersect the range. Examples of tracers are timing models
and snoop objects. In order to trigger breakpoints and invoke any tracers,
the memory user should perform memory operations using the
memory_space interface. Only breakpoints and tracers that
overlap (binary and) with the provided access argument need to be
considered.
typedef struct {
conf_object_t *target;
uint64 offs;
access_t breakpoints; // conflicting breakpoints
access_t tracers; // conflicting tracers
access_t access; // handle valid for access
} direct_memory_lookup_t;
SIM_INTERFACE(direct_memory_lookup) {
direct_memory_lookup_t (*lookup)(conf_object_t *NOTNULL obj,
conf_object_t *requester,
physical_address_t addr,
unsigned size,
access_t access);
};
#define DIRECT_MEMORY_LOOKUP_INTERFACE "direct_memory_lookup"
The direct_memory_lookup and direct_memory
interfaces replace the memory_page interface of Simics 4.8.
- Execution Context
- Cell Context for all methods.
- Description
-
The direct_memory_lookup_v2 interface is implemented by
Simics memory-spaces. Its functionality is identical to the
direct_memory_lookup interface except that it takes a
transaction_t argument instead of a requester object and
size. It must be used instead of direct_memory_lookup in
cases when memory mappings may depend on atoms of the transaction in
addition to the physical address.
SIM_INTERFACE(direct_memory_lookup_v2) {
direct_memory_lookup_t (*lookup)(conf_object_t *NOTNULL obj,
transaction_t *NOTNULL transaction,
physical_address_t addr,
access_t access);
};
#define DIRECT_MEMORY_LOOKUP_V2_INTERFACE "direct_memory_lookup_v2"
- Execution Context
- Cell Context for all methods.
- Description
-
The direct_memory_tags interface is implemented by objects
that model RAM memory with support for auxiliary RAM bits.
The get_tags_data method returns a
direct_memory_tags_t value which contains
a direct pointer to the memory used to store the tags bits.
The handle argument should be a handle for a region of memory
previously obtained from the get_handle method of
the direct_memory interface.
NOTE: The memory region specified indirectly by the handle
argument will be enlarged, if necessary, to have a natural 128-byte
alignment. This is done to ensure that the tags mapping is unambiguous.
The returned data pointer points to tag bits for the region
specified by handle. The least significant bit of the
first byte corresponds to the first 16 bytes of the (aligned) region.
The len field is set to the number of bytes holding
tags data that may be accessed and it equals the size of the
(aligned) region divided by 128.
The augmented memory bits may be read or modified using the
returned pointer, provided that the user has corresponding
read or write permissions to the region specified by handle.
The returned pointer will remain valid until the corresponding
permissions to the direct memory region are lost, which usually
happens through a call to the update_permission method of the
direct_memory_update interface. The returned pointer
must also be considered invalid when additional permissions
for the region are requested using the request method of
the direct_memory interface. This is necessary since
e.g. a write request could trigger copy-on-write behavior and
reallocation of the underlying storage.
typedef struct {
#ifndef PYWRAP
uint8 *data;
#endif
unsigned len;
} direct_memory_tags_t;
SIM_INTERFACE(direct_memory_tags) {
direct_memory_tags_t (*get_tags_data)(conf_object_t *NOTNULL obj,
direct_memory_handle_t handle);
};
#define DIRECT_MEMORY_TAGS_INTERFACE "direct_memory_tags"
- Execution Context
- Cell Context for all methods.
- Description
- The
direct_memory_update interface must be implemented by
memory-user objects that use the direct_memory interface.
The direct_memory_update interface replaces the
memory_page_update interface from Simics 4.8.
Accesses to memory are controlled by a handle that the memory-user object
requests by calling the get_handle method of the
direct_memory interface. The object implementing the
direct_memory interface through which the handle was
established is passed to the functions in
direct_memory_update as target.
If the release method is called, the corresponding
handle and all the permissions and inhibit protections are
recalled. The memory-user object must stop using the handle and
associated data pointers and then call the acknowledge method
ack in the direct_memory interface from
which the handle was granted.
A call to the update_permission method revokes earlier requested
rights for a handle. The lost_access argument recalls rights to
use the handle for the given access bits. This means that the handle needs
to be re-fetched (by a call to the lookup method of the
direct_memory_lookup interface followed by a call to the
get_handle method of the direct_memory interface)
before the handle can be used again for the particular access. This typically
happens if a new breakpoint is inserted or a remap of the memory system is
done. In case of a remap it is possible that the same handle will never be
returned again which means that any user data associated with the handle
should be reclaimed.
The lost_permission and the lost_inhibit arguments
describe which permission rights and inhibit protection that are
revoked. However, in contrast to the lost_access, the
handle is still valid and can be used to re-request permission
rights and inhibit protection.
A call to the conflicting_access method informs a memory-user
object that a conflicting memory operation will be performed. Hence, if the
memory-user object have some protected representation of memory (such as
decoded instructions in an internal cache), that representation of memory
has to be flushed (or written back to memory in case of dirty data). Note
however that the memory-user object does not lose any permission rights or
any inhibit protection.
There is no mechanism for locking simulated memory in host memory.
All methods in this interface receive a direct_memory_ack_id_t
value as an argument. The ack method of the
direct_memory interface must be called with this
id as an argument when the corresponding operation has been
carried out. The ack method may be called after the
direct_memory_update interface function has returned, which
allows for queueing of update requests. This may be valuable if multiple
simulator threads are used.
An exception to the allowed queueing of update requests is for update
requests that are received while calling request in the
direct_memory interface. Such requests must be handled
immediately with ack being called before the return of the
direct_memory_update interface function. This requirement
avoids a dead-lock that would otherwise happen if request would
wait for ack before returning, but ack is
queued to be handled at some time after request has returned.
SIM_INTERFACE(direct_memory_update) {
void (*release)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL target,
direct_memory_handle_t handle,
direct_memory_ack_id_t id);
void (*update_permission)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL target,
direct_memory_handle_t handle,
access_t lost_access,
access_t lost_permission,
access_t lost_inhibit,
direct_memory_ack_id_t id);
void (*conflicting_access)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL target,
direct_memory_handle_t handle,
access_t conflicting_permission,
direct_memory_ack_id_t id);
};
#define DIRECT_MEMORY_UPDATE_INTERFACE "direct_memory_update"
- Execution Context
- Cell Context for all methods.
- Description
- The
disk_component interface is implemented by components
that provide disk storage. The size() member function should
return the total disk size provided by the component, once configured.
SIM_INTERFACE(disk_component) {
uint64 (*size)(conf_object_t *obj);
};
#define DISK_COMPONENT_INTERFACE "disk_component"
- Execution Context
- Global Context for all methods.
- Description
- The
event_delta interface is implemented by CPUs and
clocks that advance time.
The set_delta method notifies the CPU about
the number of cycles the CPU should run before the next event
should be dispatched by a call to the handle_event
method of the event_handler interface.
The get_delta queries the CPU for the current count
of remaning cycles to the next event. The returned number should
always be smaller or equal to the number of cycles established by
a previous call to set_delta.
SIM_INTERFACE(event_delta) {
uint64 (*set_delta)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL event_handler_obj,
const event_class_t *next_event_ec,
uint64 delta);
uint64 (*get_delta)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL event_handler_obj);
};
#define EVENT_DELTA_INTERFACE "event_delta"
- Execution Context
- Cell Context for all methods.
- Description
- The
event_handler interface is implemented by
the vtime port object and is invoked by clocks or CPUs
implementing the event_delta interface.
The handle_event method should be called when the number
of cycles to the next event has reached zero. The method
invokes the next event and notifies the CPU or clock about the cycle count
to the next pending event by invoking the set_delta method.
The stop method should be called if a dispatched
event requests the simulation to be stopped. The method is typically
called from the stop method of the execute
interface. If the stop method is not called, then time may be
advanced by a fraction of a cycle after an event has been dispatched.
SIM_INTERFACE(event_handler) {
bool (*handle_event)(conf_object_t *NOTNULL obj);
void (*stop)(conf_object_t *NOTNULL obj);
};
#define EVENT_HANDLER_INTERFACE "event_handler"
- Execution Context
- Cell Context for all methods.
- Description
- =============================================
TECH-PREVIEW
This interface may change without notice.
=============================================
The event_provider interface is used internally in between
ISIM modules.
The method event_name returns name of event with index
n or NULL if there is no event with that index.
The method event_value returns accumulated value for event
with index n. Output is undefined if there is no event with
that index.
Events must de indexed from 0 to last without gaps.
To use the event-provider add the following
EXTRA_MODULE_VPATH := event-provider-interface
to the modules Makefile.
SIM_INTERFACE(event_provider) {
const char *(*event_name)(conf_object_t *obj, unsigned n);
uint64 (*event_value)(conf_object_t *obj, unsigned n);
};
#define EVENT_PROVIDER_INTERFACE "event_provider"
- Execution Context
- Called from performance models.
- Description
- The
exception interface is used to translate
exception numbers, as received by the Core_Exception hap, to names,
and vice versa.
The get_number function returns the number associated
with an exception name, or -1 if the no exception with the given
name exist. The get_name returns the name
associated with an exception number. The get_source
function is only used on X86 targets and returns the source for an
exception, as an exception number can be raised from different
sources. The all_exceptions function returns a list of
all exceptions numbers.
The exception numbers are architecturally defined, while their
names are defined by the model.
SIM_INTERFACE(exception) {
int (*get_number)(conf_object_t *NOTNULL obj,
const char *NOTNULL name);
const char *(*get_name)(conf_object_t *NOTNULL obj, int exc);
int (*get_source)(conf_object_t *NOTNULL obj, int exc);
attr_value_t (*all_exceptions)(conf_object_t *NOTNULL obj);
};
#define EXCEPTION_INTERFACE "exception"
- Execution Context
- Cell Context for all methods.
- Description
- The
exec_trace interface is implemented by processor models
that support tracing. A trace listener registers itself with the
register_tracer call. The tracer callback will be
called by the processor model
when each instruction is just about to be executed, passing the
tracer_data as passed to the register_tracer function
in addition to information about the instruction that is executed.
Invoke unregister_tracer with the same two pointers to deregister
the listener.
typedef void (*instruction_trace_callback_t)(lang_void *tracer_data,
conf_object_t *cpu,
linear_address_t la,
logical_address_t va,
physical_address_t pa,
byte_string_t opcode);
The pa parameter to the callback will always be valid, but some
CPU architectures may not support la or va. The
la argument is typically only valid for x86 CPUs. Lastly, the
opcode of the instruction is passed in opcode. The
opcode is passed without endian conversion, meaning that byte X in
opcode corresponds to the byte at pa + X.
SIM_INTERFACE(exec_trace) {
void (*register_tracer)(conf_object_t *NOTNULL cpu_obj,
instruction_trace_callback_t tracer,
lang_void *tracer_data);
void (*unregister_tracer)(conf_object_t *NOTNULL cpu_obj,
instruction_trace_callback_t tracer,
lang_void *tracer_data);
};
#define EXEC_TRACE_INTERFACE "exec_trace"
- Execution Context
- Global Context for both methods.
Cell Context for the callback.
- Description
- The
execute interface is implemented by objects that
drive a simulation, which is often processor models. The object
does not have to implement cycle or
step.
An object implementing the execute interface must be
coupled with one object implementing the cycle
interface. It can be the same object that implements the
cycle interface.
The run function is called when the simulator starts or
restarts the execution.
By default the Simics scheduler will assume that the object being called in
with the execute interface also implements the corresponding
processor_info and step interfaces.
If this assumption is incorrect, the implementation of the run
function is responsible for maintaining the simulators view of the current
objects implementing the processor_info and
step interfaces. It does that by using the appropriate
functions in the cell_inspection interface. The current
objects must always be correctly set when either the run function
returns, when any API method is called, or when any other object is called
through an interface. Several Simics features, such as CLI commands, device
logging, and hap handling make use of the current objects.
To handle asynchronous events, and thus allow for reasonable interactive
performance, the implementor of execute needs to either make
sure that run returns after not having run for too long, or
preferably regularly call the VT_check_async_events method. In
the Simics library CPU models, VT_check_async_events is called
after servicing events from the cycle or step
interfaces.
The simulator core will call stop when it detects a
condition that should interrupt the simulation. The callee should
stop as soon as possible when in a stable state, typically when the
current executing instruction is finished after getting a request
to stop. In some cases the callee might receive multiple stop
requests in a rapid sequence. Conditions leading to a stop request
include SIM_break_simulation being called from a device
or hap-handler, breakpoint triggered, low-memory situations, the
user interrupting the simulation with Ctrl-C, and the Simics core
halting the object when it is at the end of the allowed time window
in temporal decoupled simulation. It is forbidden to do anything in
the stop function that can lead to a new stop request,
this includes posting events, printing SIM_log-messages,
etc. Before returning from the run method, the
VT_stop_event_processing function should be called. The
requirement to call VT_stop_event_processing is likely
to be lifted in future versions of Simics.
The switch_in function is called whenever the
execute object is about to gain control of the simulation
from some other execute object in the cell. Similarly,
switch_out is invoked before control is relinquished.
It should be noted that these functions are called in a
deterministic manner which is not true for run.
The switch_in and switch_out functions
are not called at simulation start (or checkpoint load), in
general.
SIM_INTERFACE(execute) {
void (*run)(conf_object_t *obj);
void (*stop)(conf_object_t *obj);
void (*switch_in)(conf_object_t *obj);
void (*switch_out)(conf_object_t *obj);
};
#define EXECUTE_INTERFACE "execute"
- Execution Context
- Cell Context for all methods.
- Description
- The
execute_control interface is implemented by CPUs
and devices that support threading.
Warning: This interface is currently considered tech-preview and
can be changed at any time.
SIM_INTERFACE(execute_control) {
void (*message_pending)(conf_object_t *obj);
void (*yield_request)(conf_object_t *obj);
};
#define EXECUTE_CONTROL_INTERFACE "execute_control"
- Execution Context
- Threaded Context
- Description
- The
freerun interface is provided by
the freerun-extension extension class. The extension
class augments CPU models with support for freerunning mode. The
freerun interface is used by CPU models to
interface with the extension class.
The enabled member returns true if
freerunning mode is enabled and false otherwise.
The notifier Sim_Notifier_Freerunning_Mode_Change is
triggered for the object whenever freerunning mode is enabled or disabled.
The advance_clock is used by the CPU model to
calculate how much its virtual time should be advanced in freerunning mode.
The ps_limit argument is the maximal number of pico-seconds
virtual time can be advanced. The next CPU event typically occurs
at this time. The steps argument should be set to the number
of elapsed instructions since the last call to advance_clock.
The idle parameter should be set to true if
the CPU is idle. The function returns the number of pico-seconds
the virtual time of the CPU should be advanced. The returned value
is proportional to the time spent simulating the model, but is also
subject to configurable freerunning restrictions which ensures that
the instruction rate is kept in an acceptable range.
The start_clock function should be called when
the CPU model starts instruction simulation. It is used to measure
the amount of time used to simulate the model.
The stop_clock function should be called when
the CPU model stops instruction simulation.
The current_itime function returns a prediction of the amount
of time needed to simulate an instruction, in pico-seconds. The
estimate is based on historic data and will always be in an interval
which does not conflict with configured freerunning restrictions.
The value can be used to estimate how many instructions
can be executed until the next time event.
Note:
The freerun interface is experimental and may
change without notice.
SIM_INTERFACE(freerun) {
bool (*enabled)(conf_object_t *NOTNULL obj);
int64 (*advance_clock)(conf_object_t *NOTNULL obj,
int64 ps_limit, int64 steps, bool idle);
void (*start_clock)(conf_object_t *NOTNULL obj);
void (*stop_clock)(conf_object_t *NOTNULL obj);
uint64 (*current_itime)(conf_object_t *NOTNULL obj);
};
#define FREERUN_INTERFACE "freerun"
- Execution Context
- Cell Context for all methods.
- Description
- The
gfx_con is implemented by graphics consoles of class
graphcon and is used by attached video devices to update the
screen.
The set_color method sets the specified indexed palette
color. The return value has no meaning.
The set_size method sets the size of the displayed screen.
The put_pixelmethod sets the pixel at (x,
y) to the specified palette color. The change will only be
visible after the next call to redraw.
The put_pixel_rgb method sets the pixel at (x,
y) to the color rgb, which should be in
GFX_xRGB_8888 format. The change will only be visible after the
next call to redraw.
The put_pixel_col method sets the pixel at (x,
y) to the color defined by r, g and
b. The change will only be visible after the next call to
redraw.
The put_block method draws pixels from a memory block to the
screen rectangle described by (minx, miny,
maxx, maxy); the upper bounds are inclusive. The
block parameter refers to the source memory block, whose rows
should be src_stride bytes long. Memory on each row outside the
rectangle is not accessed. The src_fmt parameter specifies the
pixel format in block. The change will only be visible
after the next call to redraw.
The redraw method updates the changed parts of the console screen
window, so should typically be called at the end of every frame update.
The update_keyboard_leds method changes the keyboard LEDs.
The led_change parameter must be one of the KBD_
constants from simics/model-iface/sim-keys.h.
SIM_INTERFACE(gfx_con) {
int (*set_color)(conf_object_t *obj,
uint8 index, uint8 r, uint8 g, uint8 b);
void (*set_size)(conf_object_t *obj, int width, int height);
void (*put_pixel)(conf_object_t *obj, int x, int y, uint8 index);
void (*put_pixel_rgb)(conf_object_t *obj, int x, int y, uint32 rgb);
#ifndef PYWRAP
void (*put_block_old)(conf_object_t *obj,
uint8 *src, int minx, int miny,
int maxx, int maxy, int src_fmt,
int src_stride, int unused);
#endif
void (*redraw)(conf_object_t *obj);
void (*update_keyboard_leds)(conf_object_t *obj, int led_change);
void (*put_pixel_col)(conf_object_t *obj, int x, int y,
int r, int g, int b);
void (*put_block)(conf_object_t *obj, bytes_t block, int minx, int miny,
int maxx, int maxy, gfx_con_pixel_fmt_t src_fmt,
int src_stride);
};
#define GFX_CON_INTERFACE "gfx_con"
- Execution Context
- Cell Context for all methods
- Description
- With the
hap_listen interface, objects can pick up
haps and process then as they wish, including re-raising the haps.
SIM_INTERFACE(hap_listen) {
void (*occurred)(conf_object_t *obj, conf_object_t *origin,
hap_type_t hap, int64 value, va_list ap, bool always);
};
#define HAP_LISTEN_INTERFACE "hap_listen"
- Execution Context
-
- Description
- This interface is used for handling big data images.
read and write access a chunk of data at a time.
Only accesses within the bounds of the image are allowed.
clear_range fills an interval with null bytes,
fill with any byte value.
size returns the image size.
get and set work like read
and write but pass the data using a bytes_t instead,
and can be used from Python.
flush_writable writes out all unwritten changes to a writable
backing file if one exists; otherwise, does nothing.
Other methods are not currently for public use.
SIM_INTERFACE(image) {
#if !defined(PYWRAP)
void (*read)(conf_object_t *img, void *NOTNULL to_buf, uint64 start,
size_t length);
void (*write)(conf_object_t *img, const void *NOTNULL from_buf,
uint64 start, size_t length);
int (*for_all_spages)(conf_object_t *img,
int (*NOTNULL f)(image_spage_t *NOTNULL p,
uint64 ofs, void *arg),
void *arg);
#endif /* not PYWRAP */
void (*set_persistent)(conf_object_t *obj);
void (*save_to_file)(conf_object_t *NOTNULL obj,
const char *NOTNULL file,
uint64 start, uint64 length, save_flags_t flags);
void (*save_diff)(conf_object_t *NOTNULL obj,
const char *NOTNULL file, save_flags_t flags);
void (*clear_range)(conf_object_t *NOTNULL obj,
uint64 start, uint64 length);
void (*fill)(conf_object_t *NOTNULL obj,
uint64 start, uint64 length, uint8 value);
uint64 (*size)(conf_object_t *NOTNULL obj);
void (*set)(conf_object_t *NOTNULL obj, uint64 ofs, bytes_t b);
bytes_t (*get)(conf_object_t *NOTNULL obj, uint64 ofs, size_t size);
void (*flush_writable)(conf_object_t *NOTNULL obj);
};
#define IMAGE_INTERFACE "image"
- Execution Context
| read | Cell Context |
| write | Cell Context |
| for_all_spages | Cell Context |
| set_persistent | Cell Context |
| save_to_file | Cell Context |
| save_diff | Cell Context |
| clear_range | Cell Context |
| fill | Cell Context |
| size | Cell Context |
| set | Cell Context |
| get | Cell Context |
| flush_writable | Cell Context |
- Description
- The image snoop interface is used to get
information about when image pages are written to. Note that with the
addition of inhibit bits in the
direct_memory interface, the
image snoop interface is rarely needed for model functionality.
The page_modified function is always called the first time a page
is written to. It may also be called additional times even if a page has
already been written to. A user of the image snoop interface can at any time
reset this mechanism so that all pages are considered not written to and
therefore the page_modified function will be called again on
future writes. The reset can be accomplished either through the memory page
update interface or through the pool protect interface.
The image snoop interface can, for example, be used by frame
buffer devices to efficiently keep track of areas of the frame buffer to
redraw, or for a CPU module that builds cached representations of code pages
to invalidate such caches when memory is modified.
Listeners using this interface are installed with the
image_snoop_devices attribute in the
image class.
SIM_INTERFACE(image_snoop) {
void (*page_modified)(conf_object_t *obj, conf_object_t *img,
uint64 offset, uint8 *page_data,
image_spage_t *spage);
};
#define IMAGE_SNOOP_INTERFACE "image_snoop"
- Execution Context
- Cell Context for all methods.
- Description
- The
instruction_fetch interface is implemented by
processors. The interface controls how instruction fetches should
be modeled.
The get_mode and set_mode functions get and
set the instruction fetch mode. There are three available
modes. All modes are not supported by all processor types. The
instruction_fetch_none mode is the least accurate but the
fastest mode. The other modes are more accurate but slower.
The get_line_size and set_line_size functions
get and set the fetch size on each instruction fetch. This is often
related to cache line size or similar. The line size must be power
of 2.
typedef enum {
/* No instruction fetch sent to memory hierarchy */
Instruction_Fetch_None = 0,
/* Memory hierarchy gets fetch for each cache line access */
Instruction_Fetch_Cache_Access_Trace = 1,
/* Memory hierarchy gets fetch for each instruction fetch. Only
x86/x86-64 */
Instruction_Fetch_Trace = 2
} instruction_fetch_mode_t;
SIM_INTERFACE(instruction_fetch) {
instruction_fetch_mode_t (*get_mode)(conf_object_t *obj);
void (*set_mode)(conf_object_t *obj, instruction_fetch_mode_t mode);
int (*get_line_size)(conf_object_t *obj);
void (*set_line_size)(conf_object_t *obj, int size);
};
#define INSTRUCTION_FETCH_INTERFACE "instruction_fetch"
- Execution Context
| get_mode | Cell Context |
| set_mode | Global Context |
| get_line_size | Cell Context |
| set_line_size | Global Context |
- Description
- This interface is used to control the dispatch order of connected
instrumentation. It is implemented by instrumentation providers that have
the ability to change the order in which instrumentation events occur. This
works by associating every instrumentation event with a connection
object. It is up to the provider to supply a way to do this. See the
cpu_instrumentation_subscribe interface for an example. Most
users of any instrumentation will only be observing the state of the
provider, in which case the order is unimportant. However, if users
of instrumentation may change the behavior of the provider, this interface
may be useful.
The default order for callbacks that should be honored by all providers,
where possible, regardless if they implement the
instrumentation_order interface or not is:
- all anonymous connections, i.e. NULL connections, in registration order
- connection order, which if not re-ordered will be the connection
registration order
- callback registration order
The get_connections method should return an
attr_value_t list with connection objects that represent the
current order. The first element in the list is the first object in the
dispatch order, etc.
The move_before method moves the connection given by the
connection argument before the connection given by the
anchor argument. If the anchor is NULL the connection
will be moved last. The given connection objects must be present in the
current dispatch order for this to succeed.
SIM_INTERFACE(instrumentation_order) {
// Returns an object list in the connection order
attr_value_t (*get_connections)(conf_object_t *obj);
bool (*move_before)(conf_object_t *self, conf_object_t *connection,
conf_object_t *before);
};
#define INSTRUMENTATION_ORDER_INTERFACE "instrumentation_order"
- Execution Context
- Global Context for all methods, but must be called from a callback
receiving a handle of type
instruction_handle_t.
- Description
- The
int_register
interface is used for access to registers in a processor. It
can be used to access any kind of integer register, not only the
"normal" registers. This includes all kinds of control registers,
hidden registers and anything else that might be useful to access as
a register. The only limitation is that the register value should
be representable as a 64-bit unsigned integer.
This interface can be implemented by other classes than processors,
but it is likely to be found mostly in processors.
Registers are identified by a number, and there are two functions
to translate from register names to register numbers and back. The
translation need not be one-to-one, which means that one register
can have several names. A register name can, however, only
translate to a single register number.
Often, registers are grouped in register banks, where
registers in the bank are numbered from 0 up. Registers in a bank
should have consecutive numbers (unless their numbering is very sparse).
This allows a user to deduce register numbers by calling
get_number for the first register only.
The first register numbers should be used for the general-purpose integer
registers, if possible (so that integer register rN has number N).
Using this interface to read or write registers does not cause any
side effects, such as triggering interrupts or signalling haps.
get_number translates a register name to its number. Returns -1 if
the register does not exist.
get_name translates a register number to its canonical name.
read reads a register value.
write writes a new register value.
all_registers returns a list of all register numbers that can
be used for this object.
register_info returns information about a single register.
The information return depends on the info parameter.
- Sim_RegInfo_Catchable
- Return 1 if
Core_Control_Register_Write and
Core_Control_Register_Read are triggered when this
register is written or read. Return 0 otherwise.
typedef enum {
Sim_RegInfo_Catchable
} ireg_info_t;
SIM_INTERFACE(int_register) {
int (*get_number)(conf_object_t *NOTNULL obj,
const char *NOTNULL name);
const char *(*get_name)(conf_object_t *NOTNULL obj, int reg);
uint64 (*read)(conf_object_t *NOTNULL obj, int reg);
void (*write)(conf_object_t *NOTNULL obj, int reg, uint64 val);
attr_value_t (*all_registers)(conf_object_t *NOTNULL obj);
int (*register_info)(conf_object_t *NOTNULL obj, int reg,
ireg_info_t info);
};
#define INT_REGISTER_INTERFACE "int_register"
- Execution Context
- Cell Context for all methods, except for write where the
register is a program counter; Global Context in that case.
- Description
- Interface implemented by keyboard controllers. Used by consoles to send
keyboard events to the controller.
The function keyboard_event() takes the keyboard controller as
its first argument obj. The key_up argument specifies
whether the event is a key release (1) or a key press (0). The
key argument is the Simics internal keycode, as defined in
the sim_key_t enum.
If the return value is 1 the keyboard controller accepted the event. If
return value is 0 the keyboard controller did not accept the event, and the
console should buffer the event until it gets a keyboard_ready()
call from the keyboard controller.
SIM_INTERFACE(keyboard) {
int (*keyboard_event)(conf_object_t *obj, int key_up, uint8 key);
};
#define KEYBOARD_INTERFACE "keyboard"
- Execution Context
- Cell Context for all methods.
- Description
- Interface implemented by consoles, to receive notifications from keyboard
controllers.
The function keyboard_ready(), which takes the console as its
first argument obj, must be called by the keyboard controller
when it is ready to receive keyboard events again after having rejected a
keyboard event. Note that this function may be called even though no
keyboard event has been rejected, and that the console must not assume that
keyboard controller will accept an event just because the
keyboard_ready() function has been called.
keyboard_ready must not be called while the keyboard controller
is handling a keyboard_event() call.
SIM_INTERFACE(keyboard_console) {
void (*keyboard_ready)(conf_object_t *obj);
};
#define KEYBOARD_CONSOLE_INTERFACE "keyboard_console"
- Execution Context
- Cell Context for all methods.
- Description
Note:
This interface is an experimental feature. It is excluded from
the standard support program, and is subject to change or removal
without notice.
The linear_image interface permits direct access to the
data in image objects by requesting a linear allocation
for the contents. Doing so is not recommended for very large images,
since there must be space for all data in memory as a contiguous
block.
get_base returns the linear allocation block if one has
already been set. Otherwise, a block of the correct size is allocated,
set and returned. In the latter case, the block is owned by the image
object and should not be freed by the user. If retsize
is non-null, it is used to return the size of the image.
set_base specifies an existing memory block to be used for
the image contents. The block must be at least the size of the image,
and should be aligned to a multiple of 4096 bytes. The caller is
responsible for the allocation of the block, which must remain
allocated for the remaining lifetime of the image object.
prepare_range must be called, with the matching access type,
before any direct access to data in a linear block by user code.
It is then permitted to access bytes in the range
[offs, offs + size)
. For type = Sim_RW_Write, the
permission to modify data in that range only extends until any other
objects using the image have the opportunity to do so (typically, when
the modelling function returns control to the simulator).
set_base and get_base cannot be called after
image data has been accessed (read or written) for the first time.
SIM_INTERFACE(linear_image) {
#if !defined(PYWRAP)
uint8 *(*get_base)(conf_object_t *obj, size_t *retsize);
void (*set_base)(conf_object_t *obj, uint8 *NOTNULL base);
#endif /* not PYWRAP */
void (*prepare_range)(conf_object_t *NOTNULL obj,
read_or_write_t type, size_t offs, size_t size);
};
#define LINEAR_IMAGE_INTERFACE "linear_image"
- Execution Context
| set_base |
Global Context |
| get_base |
Global Context |
| prepare_range |
Cell Context |
- Description
- An interface for reading received data from a magic pipe application running
in the target system. This interface is called by a simics extension running
in the host system communicating with a target application via a magic
pipe. The communication is identified by a magic number. These numbers are
acquired or reserved in the magic_pipe_setup_interface.
The magic pipe library on the target system allocates a page-locked pipe
buffer for the target application, which uses the buffer to communicate data
to and from the host system. That buffer is fragmented when read by the host
system and therefore copied into a new unfragmented buffer, which is used for
all read accesses in this interface. All C-code readewr callback functions
are allowed direct access to this memory area, while Python reader callback
functions require another copy for ownership reasons.
This interface does not modify the pipe buffer data in any way, and the
callers are not allowed to do that neither. It is therefore safe for several
readers to subscribe to the same data.
Note:
This interface is an experimental feature. It is excluded from
the standard support program, and is subject to change or removal
without notice.
SIM_INTERFACE(magic_pipe_reader) {
/* Query whether the byte-order of the simulated target system differs
from that of the simulator host system. */
bool (*is_byte_swap_needed)(conf_object_t *obj, uintptr_t buf);
/* Query the amount of used pipe buffer space. This value is always
less than the allocated buffer size because it does not count the
internal pipe buffer header. */
size_t (*read_buffer_size)(conf_object_t *obj, uintptr_t buf);
#ifndef PYWRAP
/* Get direct read-only access to the incoming pipe buffer data, at the
desired offset. The function returns a pointer to, and the remaining
used size from, the specified offset.
This function gives a direct pointer into internal memory and
therefore cannot be used by Python code. */
bytes_t (*read_data_direct)(conf_object_t *obj, uintptr_t buf,
size_t offs);
#endif
/* Get a copy the pipe buffer data, at the specified offset with the
specified length. If the length argument is zero, then the length of
the remaining space from the offset is assumed.
This function will allocate a new data buffer to hold the desired
amount of data and return it to the caller, who is responsible to
deallocating it once it has served its purpose. */
bytes_t (*read_data_copy)(conf_object_t *obj, uintptr_t buf,
size_t offs, size_t len);
};
#define MAGIC_PIPE_READER_INTERFACE "magic_pipe_reader"
- Execution Context
- Cell Context for all methods.
- Description
- The magic pipe setup interface is
used to establish connections between an application running in the simulated
target system and a Simics extension executing on the simulator host.
Magic numbers are used to identify and isolate connections, called
pipes. Typically a well-known value is used to perform a handshake and then
assign a new and unique value, which is used in all successive correspondence
between the end-points.
The Simics extension is responsible for assigning these new and unique magic
numbers, and to subscribe to them. This interface provides the necessary
facilities to either get a new random number or reserve a range for the
service to distribute on its own.
An example of a common communication flow can be divided into two phases,
first the initial handshake phase where some information about each other is
exchanged, followed by the duty phase where the target system application is
communicating back and forth with the host system Simics extension to fulfill
their purpose.
The handshake is initiated from the target application, which sends a
handshake request to the host system extension containing some information
about itself. The host system extension receives the request and replies with
a new magic number and some information about itself. The new magic number is
to be used in all further communication between the parties, to isolate the
communications pipe from other users of the magic pipe.
In the duty phase the common communication flow may look like this. The
target system application starts by allocating a pipe buffer from the magic
pipe library. Then writes its data to the buffer and sends it to the host
system extension. The extension handles the data and reuses the same buffer
to write something back to the application. This means that the buffer size
is fixed and limits the amount of data that can be returned. Because of this
it is common for the application to allocate more space than needed for its
sent data. Once the application returns from its send call, the same buffer
it allocated earlier is filled with data coming from the extension. This data
is handled by the application and then the buffer is freed. This duty cycle
is then repeated as many times as needed.
Each magic number may have more than one subscribers, therefore reading and
writing is divided into two phases, where all readers are allowed access
first. Then comes the writer phase and the subscribers are called in the
order they registered. This also means that later writer subscribers are
limited to writing only the remaining amount of data to the buffer.
There is no on or off setting for a pipe to enable or disable the
communication. The only option is to unregister from the magic number to
suspend the communication and then to register again to resume.
The registered subscribers should unregister when they are no longer
interested in receiving any data. This will also allow the magic pipe to stop
listening to haps when there is no one to receive them. The magic pipe will
automatically resume listening once there are subscribers again.
Note:
This interface is an experimental feature. It is excluded from the
standard support program, and is subject to change or removal without
notice.
SIM_INTERFACE(magic_pipe_setup) {
/* Register a subscriber for a new magic number, which is returned by
this function. The number is guaranteed to be unused and unreserved.
The reader and writer call-backs will be called in turn for each
message with the new magic number. Unless they are NULL or None. */
uint64 (*register_new_pipe)(
conf_object_t *obj, conf_object_t *cpu, conf_object_t *user,
pipe_func_t reader, pipe_func_t writer);
/* Register a subscriber for a range of reserved magic numbers.
The min_magic argument must be greater than zero and max_magic equal
to or greater than that. */
void (*register_pipe_range)(conf_object_t *obj, conf_object_t *user,
uint64 min_magic, uint64 max_magic,
pipe_func_t rd, pipe_func_t wr);
/* Register a subscriber for a reserved magic number.
The reader and writer call-backs will be called in turn for each
message with the reserved magic number, unless NULL or None.
The magic number zero is reserved for a catch-all handler,
where any message that is unsubscribed will trigger the
call-backs. */
void (*register_reserved_pipe)(
conf_object_t *obj, conf_object_t *user, uint64 magic,
pipe_func_t reader, pipe_func_t writer);
/* Unregister the subscription of a magic number for this user. This
will unregister both the reader and writer callback functions. If
the user registered a whole range, then any number in the range will
do, to unsubscribe to the whole range. */
void (*unregister_pipe)(conf_object_t *obj, conf_object_t *user,
uint64 magic);
/* Get a list of the subscribers for a magic number. The list can be
filtered to include only readers or writers or both. If neither is
specified only reservations are listed. */
attr_value_t (*get_pipe_subscribers)(conf_object_t *obj, uint64 magic,
bool readers, bool writers);
/* Get a list of the used or reserved magic numbers. Each entry is a
list of 5 items: minimum magic number, maximum magic number,
registered subscriber object, reader callback present and writer
callback present.
EXAMPLE:
[[0, 0, "fault_handler", TRUE, FALSE],
[1, 1, "handshake", TRUE, TRUE],
[0x10, 0x20, "my_magics", FALSE, FALSE],
[0x4711, 0x4711, "cool_user", TRUE, TRUE]]
The exact same information is available in the map attribute of the
magic-pipe object. Most of the same information is also printed by
the status command. */
attr_value_t (*get_magic_map)(conf_object_t *obj);
};
#define MAGIC_PIPE_SETUP_INTERFACE "magic_pipe_setup"
- Execution Context
- Cell Context for all methods.
- Description
- An interface for writing transmit data to a magic pipe application running in
the target system. This interface is called by a simics extension running in
the host system which communicates with a target application through a magic
pipe. The communication is identified by a magic number. These numbers are
acquired or reserved in the magic_pipe_setup_interface.
The write functions operate on an unfragmented host system buffer. All C-code
writer callback functions are allowed direct access to the unfragmented host
buffer, while Python callback functions require the data to be copied from a
Python owned data buffer.
The target system pipe buffer is not modified until all writer callbacks for
its magic number have returned. Then the pipe buffer header is updated and
the whole unfragmented host buffer is copied into the target pipe buffer
fragments.
Note:
This interface is an experimental feature. It is excluded from
the standard support program, and is subject to change or removal
without notice.
SIM_INTERFACE(magic_pipe_writer) {
/* Query whether the simulated target system has a different byte-order
than the simulator host system. */
bool (*is_byte_swap_needed)(conf_object_t *obj, uintptr_t buf);
/* Query how much unused space is available in the pipe buffer. This
value is decreased by each call to either write_data_add or
write_data_copy. */
size_t (*write_buffer_left)(conf_object_t *obj, uintptr_t buf);
/* Query the allocated pipe buffer size. This value includes both the
pipe buffer header and payload data. */
size_t (*write_buffer_size)(conf_object_t *obj, uintptr_t buf);
#ifndef PYWRAP
/* Get direct write access to the outgoing pipe buffer data. This call
returns a pointer to the write position in the pipe buffer and its
remaining unused size.
If the caller writes to the pipe buffer, then the write_data_add
function must be called also to update the amount of used data in
the pipe buffer and advance the write position.
The write position is also advanced by calls to the write_data_copy
function. In case neither write_data_add nor write_data_copy
function is called, this function will return the exact same pointer
address and size all the time.
This function gives a direct pointer into internal memory and
therefore cannot be used by Python code. */
buffer_t (*write_data_direct)(conf_object_t *obj, uintptr_t buf);
/* Increase the amount of used data in the pipe buffer. When a caller
to the write_data_direct function has written to the pipe buffer,
the caller must also call this function to declare the amount of
data written to the fragment. This will cause the write position to
be moved to the next available space in the pipe buffer.
If the length argument exceeds the available unused space. It is
assumed that all the remaining space is used. */
void (*write_data_add)(conf_object_t *obj, uintptr_t buf, size_t len);
#endif
/* Append the data from the caller buffer to the outgoing pipe
buffer. This function will copy as much of the data contents from
the supplied buffer argument to the end of the pipe buffer as fits.
The function will return the amount of data from the caller buffer
that does not fit in the pipe buffer. If the return value is zero,
then all data was copied. Otherwise the copied data was truncated
and the remaining uncopied size is returned.
Be sure to use the write_buffer_left function to determine the
amount of remaining space, unless truncated data is desired and
properly handled.
This call will automatically advance the write position to the next
unused space. */
size_t (*write_data_copy)(conf_object_t *obj, uintptr_t buf,
bytes_t data);
/* Change the magic number in the pipe buffer. This is used to assign a
new magic number to the target magic pipe application. Typically
this is done only on the first exchange with a new target
application, to give it a unique identifier, which is then
subscribed to by the simics extension, and used throughout all
further communication.
The magic number to pick is typically returned by the
register_new_pipe function in the setup interface. However, the
simics extension may choose to reserve a range of magic numbers and
provide its own scheme for assigning these to new target
applications. */
void (*write_buffer_magic)(conf_object_t *obj, uintptr_t buf,
uint64 magic);
};
#define MAGIC_PIPE_WRITER_INTERFACE "magic_pipe_writer"
- Execution Context
- Cell Context for all methods.
- Description
- The
memory_profiler interface is implemented by
processors that support memory profiling. The get
function returns the active profiler for the type of access
specified in the access argument. NULL or None is
returned if there is no active profiler for that type of access.
The set function installs prof as a profiler
for the accesses of type access. The set
functions returns true if the setting was successful, and false
otherwise.
The get_granularity_log2 gets the 2 logarithm of the
profiling granularity in bytes, for example it returns 10 if the
granularity for profiling is 1 KiB.
SIM_INTERFACE(memory_profiler) {
conf_object_t *(*get)(conf_object_t *obj, read_or_write_t access);
bool (*set)(conf_object_t *obj, read_or_write_t access,
conf_object_t *prof);
int (*get_granularity_log2)(conf_object_t *obj);
};
#define MEMORY_PROFILER_INTERFACE "memory_profiler"
- Execution Context
- Cell Context for all methods.
- Description
#define MMC_INTERFACE "mmc"
SIM_INTERFACE(mmc) {
#if !defined(PYWRAP)
int (*send_command)(conf_object_t *obj, uint8 cmd, uint32 args,
buffer_t response);
int (*read_data)(conf_object_t *obj, buffer_t data);
#endif
int (*write_data)(conf_object_t *obj, bytes_t data);
};
Interface that should be implemented by all MMC/SD/SDHC/SDIO card models.
send_command: sends a 5-byte command to the card (1-byte command index and
4 bytes command arguments).
Caller provides the response length. Card fills in actual
response data. The response data is 0, 6 or 17 bytes,
in big-endian (see the MMC/SD specification for details).
Return value: number of response bytes, -1 if the command
wasn't accepted (e.g. command is not supported or illegal in
current state, or command is not supported or illegal for
current card type).
read_data: reads data. Caller provides the length.
Return value: the card fills in the provided buffer, and returns
the number of bytes actually read, which might be less than the
buffer length in case of error.
write_data: writes data. Caller provides in both length and data.
Return value: number of bytes actually written, which might be
less than the provided data length in case of error.
- Execution Context
- Cell Context for all methods.
- Description
- Interface used to send mouse events to a mouse device. The function
mouse_event() takes the destination device as first argument
in obj. The xmicro and ymicro arguments
specified the relative mouse movement in micro-meters. If the mouse
supports a wheel, the wheel movement is supplied in z, as
number of steps up or down. The last argument buttons is a
bit-mask with the state of the mouse buttons. The mapping of mouse
buttons to bits is defined in the header file
<simics/model-iface/sim-keys.h>.
SIM_INTERFACE(mouse) {
void (*mouse_event)(conf_object_t *obj,
int xmicro,
int ymicro,
int z,
int buttons);
};
#define MOUSE_INTERFACE "mouse"
- Execution Context
- Cell Context for all methods.
- Description
- The
opcode_info interface is implemented by
processors that need to communicate information about the encoding
of instructions to the GUI.
The get_opcode_length function returns information about
instruction encoding in the current operating mode of the
processor. The min_alignment field indicates the
smallest allowed alignment of instructions, typically 4 for regular
RISC architectures. The max_length field specifies the
maximum instruction length in bytes. The avg_length is
an approximation of the average instruction size.
typedef struct {
int min_alignment;
int max_length;
int avg_length;
} opcode_length_info_t;
SIM_INTERFACE(opcode_info) {
opcode_length_info_t (*get_opcode_length_info)(conf_object_t *obj);
};
#define OPCODE_INFO_INTERFACE "opcode_info"
- Execution Context
- Cell Context for all methods.
- Description
- This interface extends the
cpu_instrumentation_subscribe
interface and allows a user to observe and change the bytes in the
instruction stream before the target processor tries to decode them. This
can be used to model data encryption of memory or instruction caches with
different content than the memory.
It is currently offered as a separate interface for backwards compatibility,
and only available for C/C++ development, i.e., no Python mapping exists.
The interface is only implemented for x86 target processors.
The register_pre_decoder_cb method registers a callback,
cb of type pre_decoder_cb_t, which is called before
an instruction is decoded an put into Simics internal decode cache. This
means that this callback is called only the first time an instruction is
executed (unless it is evicted from the decode cache).
The cpu is the processor that decodes the instructions, and
connection is the instrumentation connect object that receives
the callback. The connection can be NULL, if no connection is available. The
data is the callback data for the callback.
See the documentation for the pre_decoder_cb_t for more
information.
To remove the callback use either remove_callback or
remove_connection_callbacks methods in the
cpu_instrumentation_subscribe interface. To identify the
callback to remove, pass the return value, a cpu_cb_handle_t
handle, from the register method or the connection object used. The
callback cannot be disabled.
SIM_INTERFACE(pre_decoder) {
cpu_cb_handle_t *(*register_pre_decoder_cb)(
conf_object_t *cpu,
conf_object_t *connection,
pre_decoder_cb_t cb,
lang_void *data);
};
#endif
#define PRE_DECODER_INTERFACE "pre_decoder"
- Execution Context
- Global context.
- Description
- Some commands and features in the CLI use the
processor_cli interface. Those commands will have
limited functionality if the interface is not fully implemented.
The first argument to each function is the object to act on. This object
should implement both the processor_info interface and the
processor_cli interface.
The get_disassembly function is used for the
disassemble command as well as to disassemble the next
instruction to be executed, when control is returned to the CLI prompt. For
most architectures, get_disassembly can be set to NULL, in which
case the command will use other interfaces to provide a generic
disassembly. The get_disassembly function should return a tuple
with the length of the instruction in bytes and the disassembly string. The
addr_prefix parameter selects the address type of the address
parameter, whether it is a physical address ("p"), a linear address ("l") or
a virtual address ("v"), just as returned from
get_address_prefix. The address parameter is the
program counter for the instruction to disassemble. If
print_cpu is non-zero, then the name of the processor should
be included first in the disassembly line. If mnemonic is not
NULL, then it should be output instead of the instruction disassemble. The
mnemonic is used to print exception or interrupt information as returned by
the get_pending_exception_string function.
get_pregs returns the string to output in the CLI for the
print-processor-registers command. The all
parameter is a boolean corresponding to the -all switch to the
print-processor-registers command.
The diff_regs function is used by the stepi
command when the -r flag is used. The
diff_regs function returns a list of register names,
where each register in that list will be read through the
int_register interface before and after an
instruction.
When returning to the CLI prompt, information about the next
instruction or step to execute is printed. Normally, that is the
disassemble of the instruction at the current program counter. The
get_pending_exception_string function is called before
the disassembly to find out if the next step will not be an
instruction, but rather a taken exception or interrupt. The
function should inspect the given cpu (an object
implementing processor_info and
processor_cli) and return NULL if the next step will
be the execution of the instruction at the current program
counter. If the next step will instead be the handling of an
exception or interrupt, then a string saying that should be
returned.
The get_address_prefix function returns a string with
the default address prefix for memory related commands. Simics
defines the generic prefixes "v" for virtual addresses, "l" for
linear addresses, and "p" for physical addresses. The default if
get_address_prefix is NULL is "v" for virtual addresses.
translate_to_physical translates an address to a
physical address. If translate_to_physical is NULL, then
the only allowed address prefixes are "v" (virtual) and "p"
(physical), and the logical_to_physical function in the
processor_info interface will be used to translate
virtual addresses.
SIM_INTERFACE(processor_cli) {
tuple_int_string_t (*get_disassembly)(conf_object_t *obj,
const char *addr_prefix,
generic_address_t address,
bool print_cpu,
const char *mnemonic);
char *(*get_pregs)(conf_object_t *cpu,
bool all);
attr_value_t (*get_diff_regs)(conf_object_t *obj);
char *(*get_pending_exception_string)(conf_object_t *obj);
char *(*get_address_prefix)(conf_object_t *obj);
physical_block_t (*translate_to_physical)(conf_object_t *obj,
const char *prefix,
generic_address_t address);
};
#define PROCESSOR_CLI_INTERFACE "processor_cli"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is used for retrieving endianness and amends to the
processor_info_v2 interface.
Many modern processors support mixed endian as well as separate data
and instruction endianness. This interface reports endianness separately
for data and instructions dynamically, not just the default as for the
processor_info_v2. Previously endianness has been static,
with only one endianness. With newer ARM processors this may cause issues
for some Big Endian use cases since Little Endian is assumed throughout.
Primarily due to the fact that they can have separate data and instruction
endianness. Modifying the existing processor_info_v2 easily
gets complicated due to dependencies, so a new interface
processor_endian was created.
The processor_endian_interface_t interface can be
implemented by processors models and returns the current endianness
of the system.
The function get_instruction_endian returns the active instruction
endianness of the processor.
The function get_data_endian returns endianness of data.
SIM_INTERFACE(processor_endian) {
cpu_endian_t (*get_instruction_endian)(conf_object_t *obj);
cpu_endian_t (*get_data_endian)(conf_object_t *obj);
};
#define PROCESSOR_ENDIAN_INTERFACE "processor_endian"
- Execution Context
| get_instruction_endian | Cell Context |
| get_data_endian | Cell Context |
- Description
- The
processor_gui interface is implemented by
processors that support displays in the Simics native GUI. It is
only registered to indicate support for the displays, and does not
contain any actual functionality.
SIM_INTERFACE(processor_gui) {
void (*dummy)(conf_object_t *obj);
};
#define PROCESSOR_GUI_INTERFACE "processor_gui"
- Execution Context
- There are no methods in this interface.
- Description
- An older version of the processor_info_v2 interface. See processor_info_v2
for more information.
SIM_INTERFACE(processor_info) {
tuple_int_string_t (*disassemble)(conf_object_t *obj,
generic_address_t address,
attr_value_t instruction_data,
int sub_operation);
void (*set_program_counter)(conf_object_t *obj,
logical_address_t pc);
logical_address_t (*get_program_counter)(conf_object_t *obj);
physical_block_t (*logical_to_physical)(conf_object_t *obj,
logical_address_t address,
access_t access_type);
int (*enable_processor)(conf_object_t *obj);
int (*disable_processor)(conf_object_t *obj);
int (*get_enabled)(conf_object_t *obj);
cpu_endian_t (*get_endian)(conf_object_t *obj);
conf_object_t *(*get_physical_memory)(conf_object_t *obj);
int (*get_logical_address_width)(conf_object_t *obj);
int (*get_physical_address_width)(conf_object_t *obj);
const char *(*architecture)(conf_object_t *obj);
};
#define PROCESSOR_INFO_INTERFACE "processor_info"
- Execution Context
- Cell Context for all methods.
- Description
- The
processor_info_v2 interface is implemented by
processors models. The interface has processor generic functions
that are architecture independent.
The disassemble function returns the disassemble string for an
instruction at address with opcode according to
instruction_data. The instruction_data is an
attr_value_t value of data type with the bytes of the
opcode. The bytes are in the same order as they are stored in memory. For
VLIW architectures, sub_operation is used to select which
sub-operation to disassemble. The sub-operations start at zero, and a
request for the entire unit including all sub-operations is encoded with
sub-operation -1. A request for a sub-operation that is not present (for
example when sub-operation is neither 0 nor -1 for non-VLIW
architectures) results in the integer part of the return tuple being set to
zero. If successful, the function should return a tuple with the size of the
instruction in bytes and the disassembly string. The disassembly string
should be allocated with MM_MALLOC or similar and is to be freed by the
caller. If more bytes are needed, then the function should indicate that by
returning a negative number in the tuple where the absolute value of the
number is the required number of bytes. The string should be NULL if more
bytes are needed. The implementor of processor_info_v2 is
allowed to request one additional byte at a time until enough bytes are
passed to determine what the instruction is. Illegal instructions should
still result in a valid returned tuple, where the integer part will be used
by the disassemble command to skip that many bytes before disassembling the
next instruction. The address can be used to display absolute
destinations of program counter relative branches.
The set_program_counter function sets the program
counter in the processor. The get_program_counter
function returns the current program counter.
The logical_to_physical function translates a logical
address to a physical address of the type defined by
access_type. The function returns a physical_block_t
struct with valid bit and the address. The
address is valid when the valid bit is not 0. The
logical_to_physical function also returns
block_start and block_end. The start and end
of a block has the same logical to physical transformation as the translated
address. The range is inclusive, so block_end should be the
address of the last byte of the block.
This information can be used to figure out how often the
logical_to_physical function needs to be called. An implementation would
typically return the page start and end here, but it is free to return any
power of 2 sized block as long as it includes the translated address.
The current operating mode of the processor is returned with
get_processor_mode.
The processor can be enabled or disabled with the
enable_processor or disable_processor
functions. The functions should return 0 if the processor
changed from enabled to disabled or from disabled to enabled, and
1 if the processor did not change state. The current state
is returned by the get_enabled function. Enabled or
disabled here refers to the state that the user of the model has
put the processor into. In particular, it is independent of the
power mode of the processor. A processor that has powered down does
not count as disabled in this sense, nor does the
enable_processor wake up a processor that is in
a power-saving sleep state.
The endianness of the processor is returned by the
get_endian function.
The physical memory object is returned by the
get_physical_memory function. The object returned by
get_physical_memory is used to set breakpoints by the
global break command, and to read and write physical
memory through set, get,
load-binary, load-file, and the default
implementation of disassemble. The object returned
implements the memory_space and
breakpoint interfaces. The
memory_space interface for the returned object is
only be used in inquiry mode corresponding to actions by the
simulator itself rather than by the simulated software. An
implementation may return NULL from this method, which will lead to
the command listed above not being supported when such a processor
is selected.
The get_logical_address_width function returns the
number of logical/virtual address bits and the
get_physical_address_width function returns the number
of physical address bits.
The processor architecture is returned by calling the
architecture function. The architecture should be one of
arm, mips32,
mips64, ppc32, ppc64, sparc-v8,
sparc-v9, x86, x86-64, or something else
if none of the listed is a good match.
All functions in the interface are optional. Each function can be
set to NULL if it is not supported.
SIM_INTERFACE(processor_info_v2) {
tuple_int_string_t (*disassemble)(conf_object_t *obj,
generic_address_t address,
attr_value_t instruction_data,
int sub_operation);
void (*set_program_counter)(conf_object_t *obj,
logical_address_t pc);
logical_address_t (*get_program_counter)(conf_object_t *obj);
physical_block_t (*logical_to_physical)(conf_object_t *obj,
logical_address_t address,
access_t access_type);
processor_mode_t (*get_processor_mode)(conf_object_t *obj);
int (*enable_processor)(conf_object_t *obj);
int (*disable_processor)(conf_object_t *obj);
int (*get_enabled)(conf_object_t *obj);
cpu_endian_t (*get_endian)(conf_object_t *obj);
conf_object_t *(*get_physical_memory)(conf_object_t *obj);
int (*get_logical_address_width)(conf_object_t *obj);
int (*get_physical_address_width)(conf_object_t *obj);
const char *(*architecture)(conf_object_t *obj);
};
#define PROCESSOR_INFO_V2_INTERFACE "processor_info_v2"
Note that the original version of this interface
(processor_info) must also be implemented. The only
difference between the two interfaces is that the original version lacks the
get_processor_mode function.
- Execution Context
| disassemble | Cell Context |
| set_program_counter |
Global Context (with some additions; see below) |
| get_program_counter | Cell Context |
| logical_to_physical | Cell Context |
| get_processor_mode | Cell Context |
| enable_processor | Cell Context |
| disable_processor | Cell Context |
| get_enabled | Cell Context |
| get_endian | Cell Context |
| get_physical_memory | Cell Context |
| get_logical_address_width |
Cell Context |
| get_physical_address_width |
Cell Context |
| architecture | Cell Context |
It is explicitly permitted to call set_program_counter from
inside an execution breakpoint handler.
- Description
-
This interface is used to register callbacks to instrument ram/rom accesses.
The register_access_before_cb method registers a callback that is
called before any memory access reached the backing storage in a ram/rom
image. This makes it possible to modify the transaction before it reaches
its destination. See the documentation of the ram_access_cb_t
type for more information. A ram_cb_handle_t pointer is
returned as a reference to the callback.
The register_access_after_cb method registers a callback that is
called after any memory access has reached the backing storage in a ram/rom
image. This makes it possible to modify the transaction after the access is
completed. See the documentation of the ram_access_cb_t
type for more information. A ram_cb_handle_t pointer is
returned as a reference to the callback.
Both of these register callbacks above will receive all types of accesses,
read, write, or execute, from any initiator hitting any address range. It is
up to the callback to filter the information if needed, e.g., to only trace
read accesses. Normally, ram/rom pages can be cached in object using them by
using the direct_memory_lookup interface. This caching must
be blocked by this interface to allow the callbacks to be called. This has
severe impact on simulation speed. However, the following method should be
used to allow caching for accesses that the callbacks have no interest in.
The register_access_filter_cb method can be used to register a
function callback that allows ram/rom pages to be cached by a user of the
direct_memory_lookup interface. If caching is allowed the
access may be invisible to the callbacks installed by
register_access_before_cb and register_access_after_cb
methods above. Even if an access is allowed to be cached it does not mean
that it will be, which means that the callbacks can be called anyway.
See the documentation of the access_filter_cb_t type for more
information about the callback and how to allow caching. A
ram_cb_handle_t pointer is returned as a reference to the
callback.
The remove_callback method removes an earlier installed
callback. The handle is used to identify the callback to be removed. All
register function above returns such handle.
The enable_callback and disable_callback methods
temporarily enables and disables a previously installed
callback. The handle is used to identify the callback. All
register function above returns such handle.
SIM_INTERFACE(ram_access_subscribe) {
void (*remove_callback)(conf_object_t *NOTNULL obj,
ram_cb_handle_t *handle);
void (*enable_callback)(conf_object_t *NOTNULL obj,
ram_cb_handle_t *handle);
void (*disable_callback)(conf_object_t *NOTNULL obj,
ram_cb_handle_t *handle);
ram_cb_handle_t *(*register_access_before_cb)(
conf_object_t *NOTNULL obj,
conf_object_t *conn_obj,
ram_access_cb_t cb,
lang_void *data);
ram_cb_handle_t *(*register_access_after_cb)(
conf_object_t *NOTNULL obj,
conf_object_t *conn_obj,
ram_access_cb_t cb,
lang_void *data);
ram_cb_handle_t *(*register_access_filter_cb)(
conf_object_t *NOTNULL obj,
conf_object_t *connection,
access_filter_cb_t cb,
lang_void *data);
};
#define RAM_ACCESS_SUBSCRIBE_INTERFACE "ram_access_subscribe"
- Execution Context
- Global Context for all methods.
- Description
- =============================================
TECH-PREVIEW
This interface may change without notice.
=============================================
The simple_timing_v2 interface is used to send information
about timing, instructions executed and activity factor from timing models
to power and temperature models. It should be implemented by the consumer
of the data.
The period that is covered by a call is called a heartbeat. The length of
that period may vary between calls.
When a core has completed a heartbeat new_active_data is called
and when a period of idleness has passed new_idle_data is called.
The core argument is the core the performance data comes from.
The time argument is the virtual time of the core at the end of
the heartbeat.
The frequency argument is what the core frequency was set to at
the time of the call.
The cycles argument is the number of cycles in the heartbeat.
The ipc argument is average ipc during this heartbeat.
The cdyn argument is average activity factor during the heartbeat.
The version_data argument can be a NULL or a pointer to
simple json-string that can contain information about the performance model.
Note:
Temporal decoupling may cause calls regarding different cores to come
out of order with regards to virtual time.
Time during heartbeat may not add up with time passed since last call on a
particular core, especially when cores goes in and out of idle-mode.
To use the simple_timing_v2 add the following
EXTRA_MODULE_VPATH := simple-timing-interface
to the modules Makefile.
#define SIMPLE_TIMING_V2_MAX_NR_EVENTS 120
SIM_INTERFACE(simple_timing_v2) {
bool (*new_active_data)
(conf_object_t *obj,
double time,
conf_object_t *core,
uint64 frequency,
cycles_t cycles,
double ipc,
double cdyn,
char const *version_data);
bool (*new_idle_data)
(conf_object_t *obj,
double time,
conf_object_t *core,
uint64 frequency,
cycles_t cycles);
};
#define SIMPLE_TIMING_V2_INTERFACE "simple_timing_v2"
- Execution Context
- Called from performance models.
- Description
- The
simulator_cache interface is optionally
implemented by processors. The interface can be used for
translate objects to force a flush of the internal
caches in a processor model, if a memory area that it previously
allowed for caching is not valid anymore.
SIM_INTERFACE(simulator_cache) {
void (*flush)(conf_object_t *obj);
};
#define SIMULATOR_CACHE_INTERFACE "simulator_cache"
- Execution Context
-
- Description
- This interface is described with the
timing_model
interface.
- Execution Context
- Cell Context for all methods.
- Description
- The
stall interface can be implemented by objects that also
implement the cycle and step interfaces. The
stall interface controls the addition of extra cycles between
steps.
The get_stall_cycles function returns the remaining number of
stall cycles. The object will advance that number of cycles before starting
with the next step.
The set_stall_cycles function is used to change the number of
stall cycles before the next step. It is legal to first call this function
with a large value for cycles and then at a later point reduce the
cycle count is resume execution earlier than indicated by the first call.
The get_total_stall_cycles returns the total accumulated number of
stall cycles.
SIM_INTERFACE(stall) {
cycles_t (*get_stall_cycles)(conf_object_t *obj);
void (*set_stall_cycles)(conf_object_t *obj, cycles_t cycles);
cycles_t (*get_total_stall_cycles)(conf_object_t *obj);
};
#define STALL_INTERFACE "stall"
- Execution Context
- Cell Context for all methods.
- Description
- The
step interface is typically implemented by
processors, but can be implemented by other objects as well. Its
purpose is to handle step events using a queue.
The current number of steps for the queue is returned
when calling get_step_count.
The post_step function will schedule an event that will
occur after steps (which must be nonnegative)
counted from local current step at
queue. An event previously posted can be removed by
calling cancel_step. The cancel_step function takes a
function pred as argument which is called when a matching
event is found. The event is only removed if pred returns
1. The find_next_step takes the same arguments
as cancel_step but only returns the number of cycles before
the event will occur. The evclass is the event class,
obj is the object posting the event, and
user_data is pointer to data used as a parameter when
calling the callback function defined in the evclass.
If no matching event was found, find_next_step returns
−1.
The events method returns a list of all pending events in
expiration order. Each element is a four-element list containing the event
object, the event class name, the expiration time counted in steps as an
integer and the event description as given by the event class
describe method, or nil for events whose event class do
not define that method.
The advance function will increment the number of steps
for the queue, decrementing the number of steps to the first event
to the value defined by steps. The number of steps remaining
to the next event is returned. It is an error to advance beyond the
next pending event, so the return value is never negative.
The implementor of the step interface can use any
checkpoint representation. The name field in the
event class data structure is unique, and the attribute setter
function for checkpoint restore can use
SIM_get_event_class to get the event class structure
corresponding to an event class name.
SIM_INTERFACE(step) {
pc_step_t (*get_step_count)(conf_object_t *NOTNULL queue);
void (*post_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
pc_step_t steps,
lang_void *user_data);
void (*cancel_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
pc_step_t (*find_next_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
attr_value_t (*events)(conf_object_t *NOTNULL obj);
pc_step_t (*advance)(conf_object_t *queue, pc_step_t steps);
};
#define STEP_INTERFACE "step"
- Execution Context
- Cell Context for all methods.
- Description
- The
step_cycle_ratio interface is implemented by
processors that support a changeable ratio between steps and
cycles. The set-step-rate command uses this interface to
set the ratio between steps and cycles.
The set_ratio sets the ratio between steps and
cycles. Note that the introduction of stall cycles can
skew the ratio. The get_ratio simply returns the current
ratio.
The cycles and step arguments must be in the range
[1..128] and cycles must be a power of two. Implementers of this
interface may choose to ignore other values of cycles and
step and may log an error.
typedef struct {
uint32 steps;
uint32 cycles;
} step_cycle_ratio_t;
SIM_INTERFACE(step_cycle_ratio) {
step_cycle_ratio_t (*get_ratio)(conf_object_t *obj);
void (*set_ratio)(conf_object_t *obj, uint32 steps, uint32 cycles);
};
#define STEP_CYCLE_RATIO_INTERFACE "step_cycle_ratio"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is internal.
- Execution Context
- Global Context.
- Description
- The
step_info interface can be implemented by
processors that optimize the execution by advancing the step count
using special instructions or processor modes.
The get_halt_steps and set_halt_steps
functions are used to get and set the number of steps that have been
advanced using special features in the architecture. Examples; X86
processor it is the number of halt instructions executed, PPC
processors it is the number of steps spent in sleep mode, ARM
processors it is the number of steps spent in the "wait for
interrupt" state.
The get_ffwd and set_ffwd_steps functions are
used to get and set the number of steps that the processor have
optimized the execution by advancing time that is not
architectural. This can for instance be execution loops that does
not affect the processor state.
SIM_INTERFACE(step_info) {
pc_step_t (*get_halt_steps)(conf_object_t *obj);
void (*set_halt_steps)(conf_object_t *obj, pc_step_t steps);
pc_step_t (*get_ffwd_steps)(conf_object_t *obj);
void (*set_ffwd_steps)(conf_object_t *obj, pc_step_t steps);
pc_step_t (*get_ma_steps)(conf_object_t *obj);
void (*set_ma_steps)(conf_object_t *obj, pc_step_t steps);
};
#define STEP_INFO_INTERFACE "step_info"
- Execution Context
- Cell Context for all methods.
- Description
- Experimental, may change without notice.
SIM_INTERFACE(synchronous_mode) {
int (*enter)(conf_object_t *NOTNULL obj);
int (*leave)(conf_object_t *NOTNULL obj);
};
#define SYNCHRONOUS_MODE_INTERFACE "synchronous_mode"
- Execution Context
- Cell Context
- Description
- Deprecated interface. Use global notifiers and/or attributes instead.
This interface was used to save micro checkpoints for reverse execution.
It remains in 7, but is only used to get notifications when an
object's state is about to be restored, or has just been restored.
All functions in this interface are optional.
The save and merge functions are never called.
The function prepare_restore is called when a saved state
is about to be loaded, before any attributes have been set.
The finish_restore function is called when all
attributes have been set. The state argument is
always NULL.
SIM_INTERFACE(temporal_state) {
lang_void *(*save)(conf_object_t *obj);
void (*merge)(conf_object_t *obj, lang_void *prev, lang_void *killed);
void (*prepare_restore)(conf_object_t *obj);
void (*finish_restore)(conf_object_t *obj, lang_void *state);
};
#define TEMPORAL_STATE_INTERFACE "temporal_state"
- Execution Context
- Cell Context for all methods.
- Description
- The
timing_model interface is used to communicate
stall times for memory accesses. It is typically exported by cache
models. The operate() function is then called on every
memory access that misses in the STC, and the return value from the
call is the number of cycles to stall.
The snoop_memory interface has the exact same layout
as the timing_model interface, but its
operate() function is called after the memory access has
been performed. The return value from the operate()
function of a snoop_memory interface is ignored.
The operate function is invoked via the timing_model
attribute of the memory-space where the STC miss happens.
See the Model Builder User's Guide for more information on
how to use these interfaces.
SIM_INTERFACE(timing_model) {
cycles_t (*operate)(conf_object_t *NOTNULL mem_hier,
conf_object_t *NOTNULL space,
map_list_t *map_list,
generic_transaction_t *NOTNULL mem_op);
};
#define TIMING_MODEL_INTERFACE "timing_model"
SIM_INTERFACE(snoop_memory) {
cycles_t (*operate)(conf_object_t *NOTNULL mem_hier,
conf_object_t *NOTNULL space,
map_list_t *map_list,
generic_transaction_t *NOTNULL mem_op);
};
#define SNOOP_MEMORY_INTERFACE "snoop_memory"
- Execution Context
- Cell Context for all methods.
- Description
-
The transaction interface is implemented by devices that
can be mapped into address spaces. The issue method is called
when a memory transaction t is issued to the object.
The return value of the issue function is normally
Sim_PE_No_Exception, but other pseudo exception_type_t
values can be used to signal error conditions. The value
Sim_PE_Deferred must be used when the transaction has been
deferred using SIM_defer_transaction for completion at
some later time.
SIM_INTERFACE(transaction) {
exception_type_t (*issue)(
conf_object_t *NOTNULL obj,
transaction_t *NOTNULL t,
uint64 addr);
};
#define TRANSACTION_INTERFACE "transaction"
- Execution Context
- Cell Context for all methods.
- Description
-
Note: this interface is internal and may change without notice.
This interface is used to register callbacks to instrument transactions
issued through a map target by the SIM_issue_transaction API call. This
includes all memory_space objects handling transactions.
The interface is only implemented by the sim.transactions
object which serves all transactions.
The register_issue_cb method registers a callback that is
called whan a transaction is passed to a map target. This makes it
possible to modify or replace the transaction before it reaches its
destination. See the documentation of the
transaction_issue_cb_t type for more information on now to
handle the transaction.
A transaction_cb_handle_t pointer is returned as a reference to
the callback.
The registered callbacks above will receive all types of accesses,
read, write, or execute, from any initiator hitting any address range. It is
up to the callback to filter the information if needed, e.g., to only trace
read accesses.
If more than one cell is used and multithreading is enabled, more that one
callback can be issued at the same time.
Normally, for transactions to ram/rom, these accesses can be bypassed by
caching the destination object by using the
direct_memory_lookup interface. Then these accesses cannot be
monitored by the transaction_subscribe interface. However, it
is possible to block this caching by using the
register_access_filter_cb method of the
ram_access_subscribe interface. This has typically severe
impact on simulation speed, but allows user to monitor all transactions in
the system. Note however that a real systems also reduces the transactions to
memory by using caches, which normally is not modeled by
Simics,
The remove_callback method removes an earlier installed
callback. The handle is used to identify the callback to be removed. The
register functions above return such handle.
The enable_callback and disable_callback methods
temporarily enables and disables a previously installed callback. Note that
this will not necessary speed up the simulation, since the caching may be
blocked anyway. The handle is used to identify the callback. The register
functions above return such handle.
SIM_INTERFACE(transaction_subscribe) {
void (*remove_callback)(conf_object_t *NOTNULL obj,
transaction_cb_handle_t *handle);
void (*enable_callback)(conf_object_t *NOTNULL obj,
transaction_cb_handle_t *handle);
void (*disable_callback)(conf_object_t *NOTNULL obj,
transaction_cb_handle_t *handle);
transaction_cb_handle_t *(*register_issue_cb)(
conf_object_t *NOTNULL obj,
conf_object_t *conn_obj,
transaction_issue_cb_t cb,
lang_void *data);
};
#define TRANSACTION_SUBSCRIBE_INTERFACE "transaction_subscribe"
- Execution Context
- Outside execution context for all methods.
- Description
- The methods allow to update/overwrite Time Stamp Counter with values coming
from PUnit and measured in different units.
load_tsc_from_xtal sets TSC to an absolute value scaled from
the xtal_value. The latter value is measured in units of always
running timer clocks.
SIM_INTERFACE(tsc_update) {
void (*load_tsc_from_xtal)(conf_object_t *obj, uint64 xtal_value);
};
- Execution Context
- Cell Context for all methods.
- Description
- Interface to transfer a state representable in an uint64 from one device to
another. Examples of what the state might represent includes:
- a fixed-point value representing the level of an analog signal
- an integer representing a counter
- an integer representing an enum value
The initiator should call set when the value changes, and after a
new target is connected. The object implementing
uint64_state should accept multiple calls to set
with the same level, and may let this trigger side-effects. Therefore, any
repeated calls must be deterministic; in particular, set must not
be called while restoring a checkpoint.
A device implementing this interface may choose to only accept a certain set
of integer values; it is then an error to send any other values to the
set method. A user must therefore be careful to read the
documentation of both the source and destination object to make sure they
are compatible.
No interface call needs to be done after disconnecting a target; the target
needs to be notified of this through some other channel (typically via a
connector)
Note:
The uint64_state interface should be used instead of
the deprecated multi_level_signal interface when writing new
models.
SIM_INTERFACE(uint64_state) {
void (*set)(conf_object_t *NOTNULL obj, uint64 level);
};
#define UINT64_STATE_INTERFACE "uint64_state"
Execution ContextCell Context for all methods.
- Description
- The
vga_text_info interface facilitates the graphics console
to obtain information about displayed text from its attached VGA device,
when the video mode is a VGA text mode. This interface must be implemented
by VGA devices that are attached to the graphics console.
The text_mode method indicates whether the current video mode is
a VGA text mode.
If the current video mode is not a VGA text mode, all other methods have no
effect, and will return false. Otherwise they return true
and behaves as follows:
The font_size method sets width and height
to the current font size.
The screen_size method sets columns and
rows to the current screen size.
The text method retrieves the screen text data and line
lengths. The text parameter must be a buffer with size at least
columns * rows, as given by screen_size. Similarly, the
line_length parameter must be a buffer of length rows.
SIM_INTERFACE(vga_text_info) {
bool (*text_mode)(conf_object_t *NOTNULL obj);
bool (*font_size)(conf_object_t *NOTNULL obj, int *width, int *height);
bool (*screen_size)(conf_object_t *NOTNULL obj,
int *columns, int *rows);
bool (*text)(conf_object_t *NOTNULL obj,
uint8 *text, uint8 *line_lengths);
};
#define VGA_TEXT_INFO_INTERFACE "vga_text_info"
- Execution Context
- Cell Context
for all methods.
- Description
- The
vga_text_update interface facilitates defining an input
character stream for graphics consoles. The video device associated to a
graphics console can use this interface to send a stream of characters to
the console. This stream is used by the graphics console break strings. The
stream should match the displayed VGA text whenever possible.
SIM_INTERFACE(vga_text_update) {
void (*write)(conf_object_t *NOTNULL obj, char value);
};
#define VGA_TEXT_UPDATE_INTERFACE "vga_text_update"
- Execution Context
- Cell Context
- Description
- The
vga_update interface facilitates the graphics console to
request screen redraw from its attached video device, which typically
happens on every frame update event. This interface must be implemented by
video devices that are attached to the graphics console. The implementation
should call functions in the gfx_con interface, e.g. a
sequence of put_block() calls followed by redraw(), which is implemented by
the graphics console.
The refresh method requests the video device to redraw dirty
parts of the screen. The refresh_all method requests the video
device to redraw the whole screen.
SIM_INTERFACE(vga_update) {
void (*refresh)(conf_object_t *NOTNULL obj);
void (*refresh_all)(conf_object_t *NOTNULL obj);
};
#define VGA_UPDATE_INTERFACE "vga_update"
- Execution Context
- Cell Context for
all methods
- Description
- Add and remove virtual-address (and, on x86, linear-address) read and
write breakpoints. On every read access that intersects a read
breakpoint's interval, the registered callback function is called with the
object that initiated the read, and the address and size of the read. (The
interval includes both endpoints; first must be less than
or equal to last.) Write breakpoints work exactly the same,
except that the callback is given the actual value being written, not just
its size.
The callback is called before the read or write has taken place, but may
not intervene. If one or more breakpoint callbacks stop the simulation,
the current instruction is completed before the stop takes effect. If more
than one breakpoint is triggered by the same read or write, the
implementation may call their callbacks in any order.
On x86, the Virtual_Breakpoint_Flag_Linear flag causes the
breakpoint to use linear rather than virtual addresses. (Adding a
breakpoint with unsupported flags is illegal.)
Note:
This interface is preliminary and may change without prior notice.
typedef enum {
Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;
SIM_INTERFACE(virtual_data_breakpoint) {
virtual_data_bp_handle_t *NOTNULL (*add_read)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
void (*NOTNULL callback)(
cbdata_call_t data, conf_object_t *NOTNULL initiator,
generic_address_t address, unsigned size),
cbdata_register_t data, uint32 flags);
virtual_data_bp_handle_t *NOTNULL (*add_write)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
void (*NOTNULL callback)(
cbdata_call_t data, conf_object_t *NOTNULL initiator,
generic_address_t address, bytes_t value),
cbdata_register_t data, uint32 flags);
void (*remove)(conf_object_t *NOTNULL obj,
virtual_data_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_DATA_BREAKPOINT_INTERFACE "virtual_data_breakpoint"
- Execution Context
- Cell Context for all methods.
- Description
- Add and remove virtual-address (and, on x86, linear-address) instruction
breakpoints. Every time the processor executes an instruction that
intersects the breakpoint's interval, the callback function is called with
the processor, and the address and size of the instruction. (The interval
includes both endpoints; first must be less than or equal
to last.)
The callback is called before the instruction is executed. If one or more
breakpoint callbacks stop the simulation, the stop takes effect before
the instruction is run. (This means that once the simulation starts
again, the same breakpoints will trigger immediately again. The callback
can use VT_step_stamp to detect re-triggering.) If more than
one breakpoint is triggered by the same instruction, the implementation
may call their callbacks in any order.
If the filter function is non-null and returns false, the callback is not
called. The filter function is supplied with the instruction opcode (the
raw bytes of the instruction) and a processor (which may not be the same
processor that the breakpoint is set on, but is guaranteed to be of the
same class). The filter may base its decision only on the opcode bytes and
the string obtained by asking the processor to disassemble the
instruction; this allows the implementation to cache the result and omit
future calls to the filter function where the opcode and disassembly
string would be the same.
On x86, the Virtual_Breakpoint_Flag_Linear flag causes the
breakpoint to use linear rather than virtual addresses. Calling with
unsupported flags is illegal.
Note:
This interface is preliminary and may change without prior notice.
typedef enum {
Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;
SIM_INTERFACE(virtual_instruction_breakpoint) {
virtual_instr_bp_handle_t *NOTNULL (*add)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
bool (*filter)(cbdata_call_t filter_data,
conf_object_t *NOTNULL cpu, bytes_t opcode),
cbdata_register_t filter_data,
void (*NOTNULL callback)(
cbdata_call_t callback_data, conf_object_t *NOTNULL cpu,
generic_address_t address, unsigned size),
cbdata_register_t callback_data, uint32 flags);
void (*remove)(conf_object_t *NOTNULL obj,
virtual_instr_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_INSTRUCTION_BREAKPOINT_INTERFACE \
"virtual_instruction_breakpoint"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is meant to be implemented by an uncore device to support
implementation of MONITOR/MWAIT instruction pair. A listener (e.g. a cpu)
uses this interface to setup monitored write-back memory range.
All listeners subscribed to a particular write-back memory range will be
notified via x86_monitor_notification_interface when a memory write
transaction hits the monitored memory range.
This interface is internal and may change without notice.
The arm method is to subscribe for notifications about writes to
a write-back memory range starting from start_address up to
start_address + length - 1 , returns true on success.
The disarm unsubscribes listener, so the latter won't be
notified about writes to a monitored memory range, returns true on success.
SIM_INTERFACE(x86_monitor) {
bool (*arm)(conf_object_t *obj, conf_object_t *listener,
physical_address_t start_address, physical_address_t length);
bool (*disarm)(conf_object_t *obj, conf_object_t *listener);
};
#define X86_MONITOR_INTERFACE "x86_monitor"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is meant to be implemented by a processor to support
complex cases of MONITOR/MWAIT instruction pair. A processor will be
notified about writes to the monitored write-back memory range through the
notify method. The return value indicates whether to unsubscribe from
notifications or not. See x86_monitor_interface_t to find out how to
subscribe for write notifications to a write-back memory range.
SIM_INTERFACE(x86_monitor_notification) {
bool (*notify)(conf_object_t *obj);
};
#define X86_MONITOR_NOTIFICATION_INTERFACE "x86_monitor_notification"
- Execution Context
- Cell Context.
- Description
- Methods of this interface are used to provide CPU with
information about RAR interrupt status from APIC
The is_rar_requested method returns whether a RAR event is pending.
The ack_rar method acknowledges RAR interrupt.
SIM_INTERFACE(x86_rar_interrupt) {
bool (*is_rar_requested)(conf_object_t *obj);
int (*ack_rar)(conf_object_t *obj);
};
#define X86_RAR_INTERRUPT_INTERFACE "x86_rar_interrupt"
- Execution Context
- Cell Context for all methods.
- Description
- Objects registered in processor's smm_listeners attribute will
be called via the notification method whenever the CPU's enters
and leaves SMI handler. SMI handler entry occurs on SMI processing. SMI
handler exit occurs by RSM instruction execution. Please note that for both
SMI handler entry and SMI handler exit notification method will be
invoked twice: at the beginning of the entry/exit and at the end when CPU
state was already modified. event argument says if entry/exit is
performed, phase argument equals to X86_Smm_Phase0 for
the beginning of the event and to X86_Smm_Phase1 for the end.
typedef enum x86_smm_event_type {
X86_Smm_Enter,
X86_Smm_Leave
} x86_smm_event_type_t;
typedef enum x86_smm_phase_type {
X86_Smm_Phase0,
X86_Smm_Phase1
} x86_smm_phase_type_t;
SIM_INTERFACE(x86_smm_notification) {
void (*notification)(conf_object_t *listener, conf_object_t *cpu,
x86_smm_event_type_t event,
x86_smm_phase_type_t phase);
};
#define X86_SMM_NOTIFICATION_INTERFACE "x86_smm_notification"
- Execution Context
- Cell Context.
- Description
- The methods of the interface are intended to be used
by a platform to unplug (and optionally re-plug) CPU cores/threads,
effectively hiding them from the #RESET/INIT signals.
This interface is internal and may change without notice.
The unplug_core method is to disable an operating core with all
threads on it.
The replug_core method is to enable a core previously unplugged
with all threads on it.
The disable_ht_package method is to disable every secondary thread.
The enable_ht_package method is to enable every secondary thread.
Values returned from these methods indicate success (1) or failure (0).
SIM_INTERFACE(x86_unplug) {
int (*unplug_core)(conf_object_t *obj);
int (*replug_core)(conf_object_t *obj);
int (*disable_ht_package)(conf_object_t *obj);
int (*enable_ht_package)(conf_object_t *obj);
};
#define X86_UNPLUG_INTERFACE "x86_unplug"
- Execution Context
- Cell Context for all methods.
- Description
- The methods of the interface are intended to be used
by a platform to unplug (and optionally re-plug) CPU cores/threads,
effectively hiding them from the #RESET/INIT signals.
This interface is internal and may change without notice.
The unplug_core method is to disable an operating core with all
threads on it.
The replug_core method is to enable a core previously unplugged
with all threads on it.
The disable_core_ht method is to disable HT in the core (not the package).
The enable_core_ht method is to enable HT in the core (not the package).
The core_is_plugged method returns true if core is plugged.
The core_ht_is_enabled method returns true if HT is enabled in the core (not the package).
The set_alive_logical_processors method updates number of alive processors reported through CPUID.
The get_alive_logical_processors method returns number of alive processors reported through CPUID.
Values returned from enable and disable methods indicate success (1) or failure (0).
SIM_INTERFACE(x86_unplug_v2) {
int (*unplug_core)(conf_object_t *obj);
int (*replug_core)(conf_object_t *obj);
int (*disable_core_ht)(conf_object_t *obj);
int (*enable_core_ht)(conf_object_t *obj);
bool (*core_is_plugged)(conf_object_t *obj);
bool (*core_ht_is_enabled)(conf_object_t *obj);
void (*set_alive_logical_processors)(conf_object_t *obj, int count);
int (*get_alive_logical_processors)(conf_object_t *obj);
};
#define X86_UNPLUG_V2_INTERFACE "x86_unplug_v2"
- Execution Context
- Cell Context for all methods.
The Simics Simulator API completes the Device API defined in the Model
Builder product to give full access to the Simics API from user-written
extensions, in DML, Python or C/C++. The Simulator API is the same in all
languages but the syntax of the types and functions declarations will of
course differ.
- NAME
-
addr_prof_iter_t
- SYNOPSIS
-
typedef struct addr_prof_iter {
uint64 (*next)(struct addr_prof_iter *i);
void (*destroy)(struct addr_prof_iter *i);
generic_address_t addr;
} addr_prof_iter_t;
- DESCRIPTION
-
An address profile iterator will iterate over a specified portion of the
address space in some unspecified order, and return every nonzero counter
value exactly once. When done, it will return 0.
- NAME
-
SIM_break_cycle — insert breakpoint in time queue
- SYNOPSIS
-
void
SIM_break_cycle(conf_object_t *NOTNULL obj, int64 cycles);
- DESCRIPTION
-
Insert a breakpoint event at cycles clock cycles from now,
causing simulation to stop when reached by obj.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_break_step — set a step breakpoint
- SYNOPSIS
-
void
SIM_break_step(conf_object_t *NOTNULL obj, int64 steps);
- DESCRIPTION
-
Sets a step breakpoint on a processor. The steps
argument is the number of instructions until the break occurs.
- EXCEPTIONS
-
SimExc_InterfaceNotFound Thrown if the obj object
doesn't implement the
step interface.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_breakpoint — set breakpoint
- SYNOPSIS
-
breakpoint_id_t
SIM_breakpoint(conf_object_t *NOTNULL obj,
breakpoint_kind_t kind,
access_t access,
uint64 address,
uint64 length,
breakpoint_flag_t flags);
- DESCRIPTION
-
Add breakpoint on an object implementing
the
breakpoint interface. This is typically
a memory space object such as physical memory.
Please note that breakpoints set by this function may not appear in
the output from bp.list. It's recommended to use the
bp.memory.break command to set breakpoints.
The kind argument sets what type of address to break on:
typedef enum {
Sim_Break_Physical = 0,
Sim_Break_Virtual = 1,
Sim_Break_Linear = 2 /* x86 only */
} breakpoint_kind_t;
The access argument is a bit-field setting the type of
access. Any combination of the three alternatives can be given (added
together).
typedef enum {
Sim_Access_Read = 1,
Sim_Access_Write = 2,
Sim_Access_Execute = 4
} access_t;
The address is the start of the breakpoint range and
length is its length in bytes. This range will be truncated
as necessary to fit in the address space. An access intersecting the given
range will trigger the breakpoint. If length is zero, the
breakpoint range will be the entire address space.
The flags argument should be the sum of
zero or more enumeration constants from
breakpoint_flag_t:
typedef enum breakpoint_flag {
Sim_Breakpoint_Temporary = 1,
Sim_Breakpoint_Simulation = 2,
Sim_Breakpoint_Private = 4
} breakpoint_flag_t;
If the Sim_Breakpoint_Temporary bit is set, the breakpoint
is automatically disabled when triggered the first time.
If the Sim_Breakpoint_Simulation bit is set, the breakpoint
will not show up in the bp.list command, nor can
it be removed by the bp.delete command. Also,
there will be no message printed on the Simics console when this breakpoint
is triggered. This bit should be set when using breakpoints to simulate the
target system.
If the Sim_Breakpoint_Private bit is set, the breakpoint will
not show up in the bp.list command, nor can it be
removed by the bp.delete command.
The default action for a triggered breakpoint is to return to the frontend
(this can be changed by using haps). On execution breakpoints Simics will
return to the frontend before the instructions is executed, while
instructions triggering read or write breakpoints will complete before
control is returned to the frontend.
Several breakpoints can be set on the same address and Simics will break on
them in turn. If hap handlers are connected to the breakpoints they will
also be executed in turn. Hap handlers are called before the access is
performed, allowing the user to read a memory value that may be overwritten
by the access. See the Simics Reference Manual for a description of hap
handlers.
Several attributes can be set for a breakpoint for breaking only when some
conditions are true. See the breakpoints attribute in the
sim class.
This function returns the breakpoint id which is used for further reference
to the breakpoint:
typedef int breakpoint_id_t;
Breakpoints can be removed using SIM_delete_breakpoint.
- EXCEPTIONS
-
SimExc_General Thrown if the type or access arguments are
illegal. Also thrown if obj cannot handle breakpoints of the given kind.
- RETURN VALUE
-
Breakpoint id, -1 on exception.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_breakpoint_remove, SIM_delete_breakpoint
- NAME
-
SIM_breakpoint_remove — delete breakpoint range
- SYNOPSIS
-
void
SIM_breakpoint_remove(int id,
access_t access,
generic_address_t address,
generic_address_t length);
- DESCRIPTION
-
Deletes a breakpoint range from an existing breakpoint. Can thus be used to
create holes in the breakpoint range. id is the breakpoint
to operate on, as returned by SIM_breakpoint. A value of zero
will operate on all breakpoints that were not set using the
Sim_Breakpoint_Simulation flag.
access is a bitfield describing the type of breakpoint to
remove using the enumeration constants of the access_t enum.
address is the start address of the range and
length is the length of the range in bytes.
- EXCEPTIONS
-
SimExc_Index Thrown if illegal breakpoint
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_breakpoint, SIM_delete_breakpoint
- NAME
-
SIM_delete_breakpoint — delete breakpoint
- SYNOPSIS
-
void
SIM_delete_breakpoint(breakpoint_id_t id);
- DESCRIPTION
-
Deletes breakpoint id as returned by
SIM_breakpoint. A value of zero will delete all breakpoints
that were set without the
Sim_Breakpoint_Simulation flag.
- EXCEPTIONS
-
SimExc_Index Thrown if no breakpoint with the id is found.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_disable_breakpoint, SIM_enable_breakpoint — disable breakpoint
- SYNOPSIS
-
void
SIM_disable_breakpoint(breakpoint_id_t id);
void
SIM_enable_breakpoint(breakpoint_id_t id);
- DESCRIPTION
-
Enables and disables breakpoint id, as returned by
SIM_breakpoint.
- EXCEPTIONS
-
SimExc_Index Thrown if no breakpoint with the id is found.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_add_configuration — set configuration from Python
- SYNOPSIS
-
void
SIM_add_configuration(pre_conf_object_set_t *NOTNULL set,
const char *file);
- DESCRIPTION
-
This function creates objects from the parse objects in set
and adds the initialized objects to the current configuration (creating one
if necessary).
When called from Python (which is the intended usage), the configuration
set is a sequence (list or tuple) of pre_conf_object Python
objects, or a dictionary of the form
{name : pre_conf_object}.
The file argument is the name of the file that a configuration
was read from, and should be set to None/NULL if not used.
The following examples are written in Python. As they do not map any devices
in phys_mem, they will not work as stand-alone simulations.
Example when set is a sequence:
clock = pre_conf_object('timer', 'clock')
clock.freq_mhz = 20
space = pre_conf_object('phys_mem', 'memory-space')
space.queue = clock
SIM_add_configuration([clock, space], None)
Example when set is a dictionary:
objects = {}
objects['clock'] = pre_conf_object('timer', 'clock')
objects['clock'].freq_mhz = 20
objects['space'] = pre_conf_object('phys_mem', 'memory-space')
objects['space'].queue = objects['clock']
SIM_add_configuration(objects, None)
- EXCEPTIONS
-
SimExc_General Thrown if Simics fails to initialize all objects.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_create_object, SIM_set_configuration,
SIM_read_configuration
- NAME
-
SIM_class_has_attribute — check if class implements attribute
- SYNOPSIS
-
bool
SIM_class_has_attribute(conf_class_t *NOTNULL cls, const char *NOTNULL attr);
- DESCRIPTION
-
Returns true if the class cls implements an attribute with
the name attr.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_attribute,
SIM_get_attribute
- NAME
-
SIM_create_object — create and initialize object
- SYNOPSIS
-
conf_object_t *
SIM_create_object(conf_class_t *NOTNULL cls, const char *name,
attr_value_t attrs);
- DESCRIPTION
-
Creates a new instance of the configuration class cls.
name must consist of a letter followed by letters, digits
or underscores (
_). A unique name will be created if name
is an empty string or NULL. For backward compatibility, hyphens (-)
are allowed instead of underscores but their use is deprecated.
The new object is initialized with attributes from
attrs, which must be a list of (attribute-name,
value) pairs, where each pair is a two-element list. All
required attributes for the class cls must be present in
attrs. In Python, attrs can be omitted (if no
attributes are required), it can be normal lists:
[['attribute1', value1], ['attribute2', value2]]
or keyword arguments: attribute1=value1, attribute2=value2.
Attributes in ports of the cls class can be initialized by
prefixing the attribute name with the port name,
e.g. ['p.portname.attr', value].
The argument value may be modified, but the caller is still responsible for
freeing it. Neither point applies when the function is called from
Python.
- RETURN VALUE
-
The new object, or
NULL on
error (in which case an exception is raised).
- EXCEPTIONS
-
SimExc_General Thrown if the name is not well-formed, if an object
named name already exists, or if the initialisation failed.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_add_configuration, SIM_set_configuration
- NAME
-
SIM_current_checkpoint_dir — directory of checkpoint being loaded
- SYNOPSIS
-
char *
SIM_current_checkpoint_dir();
- DESCRIPTION
-
If called during the loading of a checkpoint, this function returns the
checkpoint (bundle) directory. Otherwise, the return value is NULL. The
directory can be absolute or relative, and may be the empty string if the
checkpoint directory is the current working directory.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_read_configuration,
SIM_add_configuration
- NAME
-
SIM_delete_objects, SIM_delete_object — delete a list of objects
- SYNOPSIS
-
int
SIM_delete_objects(attr_value_t val);
int
SIM_delete_object(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Delete the list of objects val (or the single object
obj) passed as argument, provided that no reference to these
objects is left in the rest of the configuration. Descendant objects of an
object being deleted will also be deleted.
Some specific objects in Simics, such as sim, are protected
against deletion and will be ignored by this function.
If Simics finds references to the objects in the rest of the configuration,
a warning will be printed and the operation will be aborted. Note that in
this case, the deletion process has started and the objects may already have
began their clean-up routines. The safest action at this point is to fix the
dangling references and to try to delete the objects once again.
Events posted by the objects in cycle queues or step queues will be
automatically removed. Hap callbacks and script branches waiting on deleted
objects will be interrupted as well.
- RECURSION
-
While removing the listed objects,
SIM_delete_objects
will call various callbacks (
Core_Conf_Object_Pre_Delete and
Core_Conf_Object_Delete haps, as well as
pre_delete_instance and delete_instance for each
object). Recursive calls to SIM_delete_objects are allowed
during the pre-delete phase (Pre_Delete hap and
pre_delete_instance callback), and the new objects will be
added to the current list of objects to delete. Recursive calls after this
stage will fail.
This limited recursion is meant to let objects that "own" other objects
destroy them automatically if they themselves are to be deleted. This is
used for example by the standard Simics components.
- BUGS
-
Note that for successful deletion of objects, each class
should implement the proper deletion methods called by
SIM_delete_objects. If the methods are not present,
SIM_delete_objects
will simply remove any reference to the object, but this may leave memory
and resources unrecoverable.
- RETURN VALUE
-
Returns zero if successful. Throws an exception and
returns non-zero otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if an error occurred or a reference to the
objects is left in the rest of the configuration.
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
The following line at the Simics prompt:
@SIM_delete_objects(list(SIM_object_iterator(None)))
will delete all unprotected objects in the configuration, leaving the Simics
session empty.
- NAME
-
SIM_delete_snapshot — delete a snapshot
- SYNOPSIS
-
snapshot_error_t
SIM_delete_snapshot(const char *name);
- DESCRIPTION
-
Deletes an in-memory snapshot.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_take_snapshot, SIM_restore_snapshot, SIM_list_snapshots
- NAME
-
SIM_get_all_classes — get list of all loaded classes
- SYNOPSIS
-
attr_value_t
SIM_get_all_classes();
- DESCRIPTION
-
Return an unordered list of the names of all configuration classes loaded
into simulation.
The Python function cli.global_cmds.list_classes can be used to
get class names, by default including not-loaded classes.
- RETURN VALUE
-
List of class names.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_all_objects — get list of all objects
- SYNOPSIS
-
attr_value_t
SIM_get_all_objects();
- DESCRIPTION
-
The function is going to be deprecated. Please use
SIM_object_iterator instead.
Return a list of all configuration objects.
The order is unspecified and may vary between calls to this function.
This function is deprecated and should not be used.
- RETURN VALUE
-
List of objects.
- SEE ALSO
-
SIM_object_iterator
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_attribute, SIM_get_attribute_idx — get attribute
- SYNOPSIS
-
attr_value_t
SIM_get_attribute(conf_object_t *NOTNULL obj, const char *NOTNULL name);
attr_value_t
SIM_get_attribute_idx(conf_object_t *NOTNULL obj, const char *NOTNULL name,
attr_value_t *NOTNULL index);
- DESCRIPTION
-
Extracts the attribute specified by name parameter from
obj. If an error occurs, an invalid value is returned. The
_idx version of the function can be used to get a single entry in a list or
data attribute. The attribute must support indexing for this to work.
The caller is as usual responsible for freeing the returned value by
calling SIM_attr_free.
- RETURN VALUE
-
Attribute value. An attribute of Invalid type
is returned if the attribute could not be read.
- EXCEPTIONS
-
- SimExc_AttrNotFound If the object did not have the specified
attribute.
- SimExc_AttrNotReadable If the attribute cannot be read.
- SimExc_Type If the index has the wrong type.
- SimExc_General If SIM_attribute_error or
SIM_c_attribute_error was called inside the getter function.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_attr_free,
SIM_set_attribute, SIM_attribute_error
- NAME
-
SIM_get_attribute_attributes — get attribute flags
- SYNOPSIS
-
attr_attr_t
SIM_get_attribute_attributes(conf_class_t *NOTNULL cls,
const char *NOTNULL attr);
- DESCRIPTION
-
Returns the attribute flags of the attr attribute of the
class cls.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_register_attribute
- NAME
-
SIM_get_class_attribute, SIM_get_class_attribute_idx — get class attribute
- SYNOPSIS
-
attr_value_t
SIM_get_class_attribute(conf_class_t *NOTNULL cls, const char *NOTNULL name);
attr_value_t
SIM_get_class_attribute_idx(conf_class_t *NOTNULL cls,
const char *NOTNULL name,
attr_value_t *NOTNULL index);
- DESCRIPTION
-
Extracts the class attribute specified by name from the class
cls. If an error occurs, an invalid value is returned. The
_idx version of the function can be used to get a single entry in a list or
data attribute. The attribute must support indexing for this to work.
The caller is as usual responsible for freeing the returned value by
calling SIM_attr_free.
- RETURN VALUE
-
Attribute value. A value of Invalid type is
returned if the attribute could not be read.
- EXCEPTIONS
-
- SimExc_AttrNotFound If the class did not have the specified
attribute.
- SimExc_AttrNotReadable If the attribute cannot not be
read.
- SimExc_Type If the index has the wrong type.
- SimExc_General Other errors.
- EXECUTION CONTEXT
-
Global Context, unless the attribute
documentation says otherwise.
- SEE ALSO
-
SIM_attr_free, SIM_set_class_attribute
- NAME
-
SIM_get_object — get object
- SYNOPSIS
-
conf_object_t *
SIM_get_object(const char *NOTNULL name);
- DESCRIPTION
-
Returns the object with name name.
The function does an object look-up in the order; object ID,
object name, and hierarchical location for all objects in
the simulation. The function returns the first match from the look-up or
NULL if there was no object match.
The object ID is a unique name that never changes and is returned
by the SIM_object_id function. The object name is the
name of the object, used for instance when printing log messages and is
returned by the SIM_object_name function. The hierarchical
location is the absolute location of the object in the component
hierarchy. The object name and the hierarchical location
is the same.
Please note that in Python Simics objects are available directly
as attributes of the conf module. For example, one can access
the sim object like this:
conf.sim
.
- RETURN VALUE
-
Object, or NULL if not found.
- EXCEPTIONS
-
SimExc_General Thrown if the object can not be found.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_object_name,
SIM_object_id, SIM_object_parent, SIM_object_descendant
- NAME
-
SIM_get_python_interface_type — get Python interface type
- SYNOPSIS
-
PyObject *
SIM_get_python_interface_type(const char *NOTNULL name);
- DESCRIPTION
-
Returns the Python data type for the name interface, or NULL
if not available from Python.
If necessary, will try to load modules registering the Python translation
for this interface.
- NAME
-
SIM_get_snapshot_info — get information about a snapshot
- SYNOPSIS
-
attr_value_t
SIM_get_snapshot_info(const char *NOTNULL name);
- DESCRIPTION
-
Returns a dictionary of information about a snapshot.
The currently defined keys in the dictionary are:
- name
- The name of the snapshot
- pages
- The number of non-zero image pages in the snapshot
- previous
- The name of the latest snapshot taken or restored
before this snapshot was taken.
nil if there was no
such snapshot, or if that snapshot has been deleted.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_list_snapshots, SIM_take_snapshot, SIM_restore_snapshot,
SIM_delete_snapshot
- NAME
-
SIM_is_restoring_snapshot — check if a snapshot is currently being restored
- SYNOPSIS
-
bool
SIM_is_restoring_snapshot();
- DESCRIPTION
-
Returns
true if an in-memory snapshot is currently being
restored.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_list_snapshots — list snapshots
- SYNOPSIS
-
attr_value_t
SIM_list_snapshots();
- DESCRIPTION
-
Returns a list of the names of the currently taken snapshots.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_take_snapshot, SIM_restore_snapshot, SIM_delete_snapshot,
SIM_get_snapshot_info
- NAME
-
SIM_object_class — get object class
- SYNOPSIS
-
FORCE_INLINE conf_class_t *
SIM_object_class(const conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the class of an object.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_class
- NAME
-
SIM_object_descendant — return a descendant of the specified object
- SYNOPSIS
-
conf_object_t *
SIM_object_descendant(conf_object_t *obj, const char *NOTNULL relname);
- DESCRIPTION
-
This function returns the descendant object of obj
which has the relative name relname, or NULL if
no such object exists.
It is legal for the relative name to contain multiple components,
like "device.p.RESET".
If obj is NULL, then the object lookup is performed
relative the object hierarchy root.
If obj is instantiated at the same time as the descendant,
then the function is guaranteed to succeed if called after the
alloc_object phase of object initialization; i.e., it is safe for
obj to invoke the function from its init_object
method.
- RETURN VALUE
-
Object, or NULL if the object has no
hierarchical descendant with the specified relative name.
- SEE ALSO
-
SIM_object_parent
SIM_register_port
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_object_is_processor — test if object is a processor
- SYNOPSIS
-
bool
SIM_object_is_processor(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns non-zero if obj is a processor.
- EXECUTION CONTEXT
-
All contexts (including Threaded Context)
- NAME
-
SIM_object_iterator — start object iteration
- SYNOPSIS
-
object_iter_t
SIM_object_iterator(conf_object_t *obj);
- DESCRIPTION
-
The SIM_object_iterator function returns an
iterator for the descendants of the object obj.
If obj is NULL, then the returned iterator
will iterate over all objects in the configuration.
The iterator returns objects sorted by name,
with parents before children.
- RETURN VALUE
-
Object iterator
- EXAMPLE
-
Sample C code to find all objects implementing
signal interface:
#include <simics/util/vect.h>
#include <simics/devs/signal.h>
...
VECT(conf_object_t *) v = VNULL;
object_iter_t it = SIM_object_iterator(NULL);
conf_object_t *obj;
while ((obj = SIM_object_iterator_next(&it)) != NULL) {
if (SIM_C_GET_INTERFACE(obj, signal) != NULL)
VADD(v, obj);
}
... // any code using 'v' vector here
VFREE(v);
Sample Python code to find all objects implementing
signal interface:
v = []
for obj in SIM_object_iterator(None):
if hasattr(obj.iface, simics.SIGNAL_INTERFACE):
v.append(obj)
The simics.SIGNAL_INTERFACE constant from the above
example holds
"signal"
string. Such constants are
available for some interfaces. One can safely use string literals instead.
- SEE ALSO
-
SIM_object_iterator_next,
SIM_shallow_object_iterator,
SIM_object_iterator_for_class,
SIM_object_iterator_for_interface
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_object_iterator_for_class — start class instance iteration
- SYNOPSIS
-
object_iter_t
SIM_object_iterator_for_class(conf_class_t *cls);
- DESCRIPTION
-
The SIM_object_iterator_for_class function returns an iterator
for the instances of the class cls. See
SIM_object_iterator for examples on how to use the iterator.
- RETURN VALUE
-
Object iterator
- SEE ALSO
-
SIM_object_iterator_next,
SIM_object_iterator,
SIM_object_iterator_for_interface
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_object_iterator_for_interface — start class instance iteration
- SYNOPSIS
-
object_iter_t
SIM_object_iterator_for_interface(attr_value_t ifaces);
- DESCRIPTION
-
The SIM_object_iterator_for_interface function returns an
iterator for the objects that implement all interfaces in ifaces
(i.e. all objects if ifaces is empty), which must be a list of
strings of length at most 16. See SIM_object_iterator for
examples on how to use the iterator.
- RETURN VALUE
-
Object iterator
- SEE ALSO
-
SIM_object_iterator_next,
SIM_object_iterator,
SIM_object_iterator_for_class
- EXCEPTIONS
-
SimExc_General Thrown if the ifaces argument does not
conform to the above requirements.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_object_iterator_next — get next object
- SYNOPSIS
-
conf_object_t *
SIM_object_iterator_next(object_iter_t *iter);
- DESCRIPTION
-
The SIM_object_iterator_next function returns the next
object from an iterator obtained from SIM_object_iterator
or SIM_shallow_object_iterator. If there are no more
objects in the sequence, then NULL is returned.
It is illegal to call SIM_object_iterator_next using
an iterator which has reached the end of its sequence.
- RETURN VALUE
-
Next object or NULL
- SEE ALSO
-
SIM_object_iterator_next,
SIM_object_iterator
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_object_parent — get object parent
- SYNOPSIS
-
conf_object_t *
SIM_object_parent(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the hierarchical parent of the specified object.
- RETURN VALUE
-
Object, or NULL if the object has no
hierarchical parent.
- SEE ALSO
-
SIM_object_descendant, SIM_port_object_parent
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_port_object_parent — get object parent
- SYNOPSIS
-
conf_object_t *
SIM_port_object_parent(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Returns the parent of the specified port object.
- RETURN VALUE
-
Object, or NULL if the object is not
a port object.
- SEE ALSO
-
SIM_object_parent, SIM_object_descendant
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_printf_error, SIM_printf_error_vararg — print error message
- SYNOPSIS
-
void
SIM_printf_error(const char *format, ...);
void
SIM_printf_error_vararg(const char *format, va_list ap);
- DESCRIPTION
-
This can be used to print an error message during the simulation. It is
analogous to log error messages, but for non-device code. I.e. it should be
used for errors that prevents the simulation from continuing.
- SEE ALSO
-
SIM_printf_warning
- NAME
-
SIM_printf_warning, SIM_printf_warning_vararg — print warning message
- SYNOPSIS
-
void
SIM_printf_warning(const char *format, ...);
void
SIM_printf_warning_vararg(const char *format, va_list ap);
- DESCRIPTION
-
This can be used to print a warning message during the simulation. It is
analogous to log warning messages, but for non-device code. I.e. it should be
used for problems that do not prevent the simulation from continuing.
- SEE ALSO
-
SIM_printf_error
- NAME
-
SIM_read_configuration — read configuration
- SYNOPSIS
-
void
SIM_read_configuration(const char *NOTNULL file);
- DESCRIPTION
-
Read configuration from filename and create a machine
accordingly.
- EXCEPTIONS
-
SimExc_General Thrown if the file could not be opened, the machine
was already initialized, or if an error in the configuration file was
detected.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_register_context_handler — register mandatory interface and attribute for context handler
objects
- SYNOPSIS
-
int
SIM_register_context_handler(conf_class_t *NOTNULL cls,
const context_handler_interface_t *NOTNULL iface);
- DESCRIPTION
-
Register the cls class as a class for context handler
objects. This includes registering the
context_handler
interface (iface), in addition to which
SIM_register_context_handler registers a
current_context attribute which will hold the current context.
The context_handler interface will be wrapped by standard
functions so that standard context change behavior is taken care off
automatically. This includes, among other things, making sure that the
context is valid, and triggering the correct haps on context changes. Thus
the context_handler implementation need only care about the effect of the
change on the context_handler object itself (virtual
breakpoints present in the context, cache flushing, etc.).
The return value is 0 if everything works, and non-zero if something
fails. SIM_register_context_handler will return the error value
provided by SIM_register_interface.
- RETURN VALUE
-
Returns non-zero on failure, 0 otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if the
context_handler interface
has already been registered for this class.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_register_interface
- NAME
-
SIM_restore_snapshot — restore a snapshot of the configuration state
- SYNOPSIS
-
snapshot_error_t
SIM_restore_snapshot(const char *name);
- DESCRIPTION
-
Restores the state of the configuration to a previously taken snapshot.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_take_snapshot, SIM_delete_snapshot, SIM_list_snapshots
- NAME
-
SIM_set_attribute, SIM_set_attribute_idx — set attribute
- SYNOPSIS
-
set_error_t
SIM_set_attribute(conf_object_t *NOTNULL obj,
const char *NOTNULL name,
attr_value_t *NOTNULL value);
set_error_t
SIM_set_attribute_idx(conf_object_t *NOTNULL obj,
const char *NOTNULL name,
attr_value_t *NOTNULL index,
attr_value_t *NOTNULL value);
- DESCRIPTION
-
Set the name attribute in obj to value.
The _idx version of the function can be used to get a
single entry in a list or data attribute. For this to work, the
attribute must support indexing.
After the call the value is still owned by the caller.
If the attribute setter function calls SIM_attribute_error or
SIM_c_attribute_error and returns Sim_Set_Ok, it is treated like
Sim_Set_IllegalValue.
- RETURN VALUE
-
The return value is from the
set_error_t enum, with Sim_Set_Ok indicating
success.
- EXCEPTIONS
-
- SimExc_AttrNotFound If the object did not have the specified
attribute
- SimExc_AttrNotWritable if the attribute cannot not be
written
- SimExc_Type if the index has the wrong type, the value to be set
does not match the type specified by the attribute or the setter function
returned Sim_Set_Illegal_Type
- SimExc_IllegalValue if the setter function returned
Sim_Set_Illegal_Value
- SimExc_Index if the setter function returned
Sim_Set_Illegal_Index
- SimExc_InterfaceNotFound if the setter function returned
Sim_Set_Interface_Not_Found
- SimExc_General if the setter function returned something else than
Sim_Set_Ok, Sim_Set_Illegal_Type, Sim_Set_Illegal_Value,
Sim_Set_Illegal_Index or Sim_Set_Interface_Not_Found.
- EXECUTION CONTEXT
-
Global Context in general; individual attributes may be less
constrained.
- SEE ALSO
-
SIM_get_attribute,
SIM_attribute_error,
set_error_t
- NAME
-
SIM_set_class_attribute, SIM_set_class_attribute_idx — set class attribute
- SYNOPSIS
-
set_error_t
SIM_set_class_attribute(conf_class_t *NOTNULL cls,
const char *NOTNULL name,
attr_value_t *NOTNULL value);
set_error_t
SIM_set_class_attribute_idx(conf_class_t *NOTNULL cls,
const char *NOTNULL name,
attr_value_t *NOTNULL index,
attr_value_t *NOTNULL value);
- DESCRIPTION
-
Set the name attribute in cls to value.
The _idx version of the function can be used to set a
single entry in a list or data attribute. For this to work, the
attribute must support indexing.
After the call the value is still owned by the caller.
- RETURN VALUE
-
The return value is from the
set_error_t enum, with Sim_Set_Ok indicating
success.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_get_attribute, set_error_t
- NAME
-
SIM_set_configuration — set configuration from data
- SYNOPSIS
-
void
SIM_set_configuration(attr_value_t conf);
- DESCRIPTION
-
Note:
It is recommended that the SIM_add_configuration function is
used instead of SIM_set_configuration.
This function is an alternative to reading the configuration
from a file. A configuration is an attr_value_t
which should have the following structure.
(("name", "class", ("attr_name", attr_val) ... ), ... )
That is a list of object specifiers containing name, class,
and a list of attribute specifiers. An attribute specifier is
a list of length 2 containing the attribute name and its
value. SIM_set_configuration allows an easy way
of parameterizing the configuration, especially if called from
Python.
The argument value may be modified, but the caller is still responsible for
freeing it. Neither point applies when the function is called from
Python.
- EXAMPLE
-
The following is a Python example:
from configuration import OBJ
from simics import SIM_set_configuration
SIM_set_configuration([
["cpu0", "x86",
["queue", OBJ("cpu0")],
["freq_mhz", 20],
["physical_memory", OBJ("phys_mem0")]],
["phys_mem0", "memory-space",
["map", [[0xa0000, OBJ("vga0"), 1, 0, 0x20000],
[0x00000, OBJ("mem0"), 0, 0x00000, 0xA0000],
[0xc0000, OBJ("mem0"), 0, 0xc0000, 0x8000],
[0xc8000, OBJ("setmem0"), 0, 0, 0x28000],
[0xf0000, OBJ("mem0"), 0, 0xf0000, 0x10000],
[0x100000, OBJ("mem0"), 0, 0x100000, 0x3ff00000],
[0xfee00000, OBJ("apic0"), 0, 0, 0x4000]]]],
... ])
- EXCEPTIONS
-
SimExc_Attribute Thrown if malformed configuration list.
SimExc_General Thrown if Simics fails to initialize all objects.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_add_configuration, SIM_create_object
- NAME
-
SIM_shallow_object_iterator — start object iteration
- SYNOPSIS
-
object_iter_t
SIM_shallow_object_iterator(conf_object_t *obj);
- DESCRIPTION
-
The SIM_shallow_object_iterator function returns an
iterator for the direct children of the object obj.
If obj is NULL, then the returned iterator
will iterate over objects on the root level.
The iterator returns objects sorted by name.
- RETURN VALUE
-
Object iterator
- SEE ALSO
-
SIM_object_iterator_next,
SIM_object_iterator
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_take_snapshot — take snapshot of the current configuration
- SYNOPSIS
-
snapshot_error_t
SIM_take_snapshot(const char *name);
- DESCRIPTION
-
Takes an in-memory snapshot of the state of all objects.
Objects whose
class_kind_t is equal to
Sim_Class_Kind_Pseudo are not saved.
This also holds for attributes (in all objects) of type
Sim_Attr_Pseudo.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_restore_snapshot, SIM_delete_snapshot, SIM_list_snapshots
- NAME
-
SIM_write_configuration_to_file — write configuration
- SYNOPSIS
-
void
SIM_write_configuration_to_file(const char *NOTNULL file, save_flags_t flags);
- DESCRIPTION
-
Saves all objects to filename. Objects whose
class_kind_t is equal to Sim_Class_Kind_Session
or Sim_Class_Kind_Pseudo are not saved. This also holds for
attributes (in all objects) of type Sim_Attr_Pseudo.
The flags argument should be 0.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_write_persistent_state — save persistent state
- SYNOPSIS
-
void
SIM_write_persistent_state(const char *file, conf_object_t *root,
save_flags_t flags);
- DESCRIPTION
-
Saves the persistent state to a file. Persistent
data typically includes disk images, NVRAM and flash memory contents
and clock settings, i.e data that survives reboots. The Persistent
state is saved as a standard simics configuration.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_get_init_arg_string, SIM_get_init_arg_boolean — get an argument that the Simics core was initialized with
- SYNOPSIS
-
const char *
SIM_get_init_arg_string(const char *name, const char *default_value);
bool
SIM_get_init_arg_boolean(const char *name, bool default_value);
- DESCRIPTION
-
Returns the value of init argument name previously supplied
to Simics using SIM_init_simulator2. Arguments are either strings
(
char *) or booleans (bool).
This function is only needed when directly embedding
libsimics-common in another application, which is deprecated.
- RETURN VALUE
-
The argument value or
default_value if the argument was not supplied to
SIM_init_simulator2 or if the argument value was NULL.
- EXCEPTIONS
-
SimExc_General Thrown if the argument is of the wrong type.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_init_simulator2
- NAME
-
SIM_init_command_line — initialize the Simics command line
- SYNOPSIS
-
void
SIM_init_command_line();
- DESCRIPTION
-
SIM_init_command_line initializes the Simics command line used
when running from a Linux shell or the Windows Command Prompt.
This function must be called after the Simics Python module has been loaded
and should only be called when embedding Simics in another application.
- EXCEPTIONS
-
SimExc_General Thrown if the function already has been called once.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_main_loop
- NAME
-
SIM_init_environment — perform early initialization of the simulator
- SYNOPSIS
-
void
SIM_init_environment(char **NOTNULL argv,
bool handle_signals, bool allow_core_dumps);
- DESCRIPTION
-
The SIM_init_environment function should be called as early as
possible when Simics is embedded in another application, before any other
Simics API function. It will initialize Simics dynamic memory handling
VTMEM, set up signal handling and perform some other early
initialization.
The argv argument is a NULL terminated list of strings. It must
not be NULL. It must contain at least one element, which will be used as
the program name. Often you can use the argv that main receives as the value of this argument.
If handle_signals is true, Simics will install its handler for
Control-C, e.g. the SIGINT signal on Linux and ConsoleCtrlHandler on
Windows. Set this value to false if the embedding application handles
signals itself.
If allow_core_dumps is true, Simics will not install handlers for
fatal signals but instead let the application crash possibly generating a
core dump on Linux systems. If the argument is false, no core
dump is generated and Simics will try to catch fatal signals and return
control to the command line again.
This function is only needed when directly embedding
libsimics-common in another application, which is deprecated.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_init_simulator2 — perform initialization of the simulator
- SYNOPSIS
-
void
SIM_init_simulator2(init_arg_t *NOTNULL init_args);
- DESCRIPTION
-
SIM_init_simulator2 initializes the simulator core and should
only be called when embedding Simics in another application. It has to be
called after SIM_init_environment but before using most other
parts of the Simics API. The init_args argument is an array with
init_arg_t structs, where the last entry has NULL in the
name field.
Each entry in the init_args array contains an argument name
and an associated value that is either a string or a boolean. Simics has a
number of pre-defined arguments that are used to configure the simulator.
It is possible to provide additional arguments in the call to
SIM_init_simulator2. Such arguments are ignored by Simics and
assumed to be used-defined. Their values can be obtained using the
SIM_get_init_arg_string and SIM_get_init_arg_boolean
functions in the Simics API.
List of pre-defined parameters and their types:
| batch-mode | bool |
See -batch-mode command line flag. |
| deprecation-level | char * |
One of 0, 1 and 2.
See the sim.deprecation_level attribute. |
| gui-mode | char * |
One of gui, mixed and no-gui |
| fail-on-warnings | bool |
See -werror command line flag. |
| log-enable | bool |
Deprecated. |
| log-file | char * |
See -log-file command line flag. |
| no-settings | bool |
See -no-settings command line flag. |
| no-windows | bool |
See -no-win command line flag. |
| python-verbose | bool |
Legacy flag; does nothing. |
| project | char * |
See -project command line flag. |
| quiet | bool |
See -quiet command line flag. |
| script-trace | bool |
Show when a Simics script is entered/exited, along with any parameters
passed to it and result variables returned from it. |
| verbose | bool |
See --verbose command line flag. |
| Internal or deprecated: | | |
| alt-settings-dir | char * | |
| application-mode | char * | |
| check-ifaces | bool | |
| disable-dstc | bool | |
| disable-istc | bool | |
| package-list | char * | |
| py-import-all | bool | |
| use-module-cache | bool | |
This function is only needed when directly embedding
libsimics-common in another application, which is deprecated.
- EXCEPTIONS
-
None
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_init_environment,
SIM_get_init_arg_string, SIM_get_init_arg_boolean.
- NAME
-
SIM_main_loop — run the Simics main loop
- SYNOPSIS
-
void
SIM_main_loop();
- DESCRIPTION
-
SIM_main_loop enters the main loop of Simics and never returns.
It should only be called when embedding Simics in another application that
wishes to transfer full control of the simulation to Simics.
The main loop waits for work requests to be posted by notifiers,
SIM_thread_safe_callback and SIM_realtime_event. If
the command line has been initialized it will be active as well.
If the embedding application do not wish to transfer the control to Simics
while the simulation is not advancing should use the
SIM_process_work or SIM_process_pending_work to make
sure that Simics can process any pending idle work.
- EXCEPTIONS
-
SimExc_General Thrown if the function is called recursively.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_init_command_line,
SIM_realtime_event, SIM_thread_safe_callback,
SIM_process_work
- NAME
-
SIM_process_work, SIM_process_pending_work — run the Simics main loop
- SYNOPSIS
-
int
SIM_process_work(int (*done)(lang_void *done_data), lang_void *done_data);
int
SIM_process_pending_work();
- DESCRIPTION
-
SIM_process_work and SIM_process_pending_work
processes work posted by SIM_register_work,
SIM_thread_safe_callback and SIM_realtime_event and
related functions to be run in Global Context. They do not process
work posted with run_in_thread set. Such work is processed
in worker threads.
These process work functions are typically called when embedding Simics in
another application to allow periodic and asynchronous Simics work to run
while the simulation is not advancing. They can also be used as part of
running the simulation to wait for events coming from external sources.
SIM_process_pending_work runs all work that has been queued up
since the last call and returns immediately after.
SIM_process_work is similar but waits for new work to arrive.
Each time all work that has been queued up has been processed the supplied
done callback, which must be non-NULL, is called with
done_data as its only argument. A return value of 1 tells
SIM_process_work to stop processing work and return control to
the caller again while 0 tells it to continue.
The SIM_process_work functions return -1 if the user has pressed
the interrupt key before or while they were running, provided that the
simulator core was initialized to catch signals. Otherwise the return value
is 0. The function checks for user interrupt at the same time as it checks
the done predicate and only if such a predicate is provided.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_main_loop,
SIM_realtime_event, SIM_thread_safe_callback
- NAME
-
SIM_set_frontend_context — register a stack context buffer for Simics to longjmp back to
- SYNOPSIS
-
void
SIM_set_frontend_context(void *context);
- DESCRIPTION
-
When Simics encounters a fatal error that it cannot handle, it uses
longjmp() to give control back to the main loop. The longjmp
destination depends on the stack context buffer registered by the embedding
application using SIM_set_frontend_context.
The main loop run by SIM_main_loop already sets up the stack
context. You only need to set up the stack context manually if you write
your own main loop.
A stack context buffer is created by calling sigsetjmp() on Linux
and setjmp() on Windows.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_main_loop,
SIM_process_work
- NAME
-
SIM_get_all_hap_types — get list of all hap types
- SYNOPSIS
-
attr_value_t
SIM_get_all_hap_types();
- DESCRIPTION
-
Get a list of the names of all registered hap types.
- RETURN VALUE
-
Attribute list of strings.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_hap_get_number,
SIM_hap_add_type
- NAME
-
SIM_hap_add_callback, SIM_hap_add_callback_index, SIM_hap_add_callback_range, SIM_hap_add_callback_obj, SIM_hap_add_callback_obj_index, SIM_hap_add_callback_obj_range — install callback on a hap
- SYNOPSIS
-
hap_handle_t
SIM_hap_add_callback(const char *NOTNULL hap,
NOTNULL obj_hap_func_t func,
lang_void *user_data);
hap_handle_t
SIM_hap_add_callback_index(const char *NOTNULL hap,
NOTNULL obj_hap_func_t func,
lang_void *user_data,
int64 index);
hap_handle_t
SIM_hap_add_callback_range(const char *NOTNULL hap,
NOTNULL obj_hap_func_t func,
lang_void *user_data,
int64 start,
int64 end);
hap_handle_t
SIM_hap_add_callback_obj(const char *NOTNULL hap,
conf_object_t *NOTNULL obj,
int flags,
NOTNULL obj_hap_func_t func,
lang_void *user_data);
hap_handle_t
SIM_hap_add_callback_obj_index(const char *NOTNULL hap,
conf_object_t *NOTNULL obj,
int flags,
NOTNULL obj_hap_func_t func,
lang_void *user_data,
int64 index);
hap_handle_t
SIM_hap_add_callback_obj_range(const char *NOTNULL hap,
conf_object_t *NOTNULL obj,
int flags,
NOTNULL obj_hap_func_t func,
lang_void *user_data,
int64 start,
int64 end);
- DESCRIPTION
-
Registers a function, pointed to by func, to be called
when hap occurs for object obj.
If a hap add function that
does not have the obj argument is used, then the callback
function will be called regardless of what object that triggers
the hap. The user_data argument is the callback-specific
data, and it will be passed as first argument to the installed callback
function.
Some hap add functions also take a flags argument. This flag
is currently Simics internal and should be set to 0.
The hap callback functions should not return any data. In C, the functions
are declared to have a void return type and in Python, any
return value is ignored. Since callback functions with different arguments
may be installed using the same API function, the compiler may warn about a
type mismatch. The solution is to cast the callback function pointer to the
obj_hap_func_t type.
The callback will be called in Cell Context, unless the
documentation for the hap states otherwise.
In hap functions, the execution can be interrupted by calling
SIM_break_simulation. If a frontend or Python exception is
raised, an error message will be printed including a stack trace if the
callback is written in Python.
The _index_ and _range_ versions will install callbacks
that only trigger for a specified index, or range of indices. The index
is specific for each hap type, see the hap documentation. The index and
range must be non-negative and the end of the range must not be lower than
the start.
typedef int hap_handle_t;
- RETURN VALUE
-
The return value is a hap callback handle (identifier) of the type
hap_handle_t, or -1 on error. This handle can be used to remove
the installed callback with SIM_hap_delete_callback_id.
- EXCEPTIONS
-
SimExc_Lookup Thrown if the hap does not exist.
SimExc_Attribute Thrown if the index is negative or if the range is
negative in value or size.
- EXECUTION CONTEXT
-
Cell Context for hap callbacks tied to
an object, and Global Context for hap callbacks not tied to an
object. An exception is made for callbacks on Core_Breakpoint_Memop, which
can be installed with SIM_hap_add_callback_index even in Cell Context.
- NAME
-
SIM_hap_delete_callback, SIM_hap_delete_callback_obj, SIM_hap_delete_callback_id, SIM_hap_delete_callback_obj_id — delete installed hap callback
- SYNOPSIS
-
void
SIM_hap_delete_callback(const char *NOTNULL hap,
NOTNULL obj_hap_func_t func, lang_void *user_data);
void
SIM_hap_delete_callback_obj(const char *NOTNULL hap,
conf_object_t *NOTNULL obj,
NOTNULL obj_hap_func_t func, lang_void *user_data);
void
SIM_hap_delete_callback_id(const char *NOTNULL hap, hap_handle_t handle);
void
SIM_hap_delete_callback_obj_id(const char *NOTNULL hap,
conf_object_t *NOTNULL obj, hap_handle_t handle);
- DESCRIPTION
-
Removes a callback for a hap type specified by the
hap argument.
The SIM_hap_delete_callback_obj... functions will remove a
callback that is installed on the specified object obj.
SIM_hap_delete_callback removes a callback not associated with
any object, with the callback function func and the same
user_data.
The SIM_hap_delete_callback_..._id functions take a hap handle
argument instead, as returned by the SIM_hap_add_callback...
functions.
These functions will trigger the Core_Hap_Callback_Removed hap
for each removed callback.
- EXCEPTIONS
-
SimExc_Lookup Thrown if the specified hap does not exist.
- EXECUTION CONTEXT
-
Cell Context for callbacks tied to an
object. Global Context for callbacks not tied to an object.
- NAME
-
SIM_get_quiet — return setting of the quiet flag
- SYNOPSIS
-
bool
SIM_get_quiet();
- DESCRIPTION
-
This function returns the current value of Simics's quiet flag.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_verbose — get the verbose flag
- SYNOPSIS
-
bool
SIM_get_verbose();
- DESCRIPTION
-
This function returns the value of Simics's verbosity flag
(corresponding to the
--verbose command line argument).
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_quiet — enable/disable quiet mode
- SYNOPSIS
-
void
SIM_set_quiet(bool quiet);
- DESCRIPTION
-
Calling this function with an argument of
true will enable the
quiet mode, whereas an argument of false will disable it. Any other
arguments will cause a frontend exception. Please note that enabling the
quiet mode will disable verbose mode.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_set_verbose — enable/disable verbose mode
- SYNOPSIS
-
void
SIM_set_verbose(bool verbose);
- DESCRIPTION
-
This function sets Simics's internal verbosity flag (corresponding to the
--verbose command line argument). The verbose argument can
be either true or false. Note that setting this flag will
disable quiet mode.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_load_binary — read an executable file into memory
- SYNOPSIS
-
physical_address_t
SIM_load_binary(conf_object_t *NOTNULL obj, const char *NOTNULL file,
physical_address_t offset, bool use_pa, bool verbose);
- DESCRIPTION
-
Read a binary file (ELF, Motorola S-Record, PE32, PE32+,
or TI COFF format) into memory and return the code entry point.
The file will be loaded at the address formed by adding
the virtual load address from the file, with the offset
offset. If the flag use_pa is set, the ELF
physical load address is used instead. The verbose flag
will cause Simics to print info about the binary to the console.
The memory space to load into is given in the obj
parameter. If the given space is a CPU object, its current virtual
address space will be used, and addresses will be translated before
writing to the physical memory space attached to the CPU.
If the file is not found in the current directory, the search path (see
add-directory) is used to find the file.
- EXCEPTIONS
-
SimExc_IOError Thrown if there was a problem reading the
file.
SimExc_General Thrown if binary cannot be read into
memory.
- RETURN VALUE
-
The code entry address.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_load_file — read a file into memory
- SYNOPSIS
-
void
SIM_load_file(conf_object_t *NOTNULL obj, const char *NOTNULL file,
physical_address_t base_address, bool verbose);
- DESCRIPTION
-
Loads the contents of file into memory starting at address
base_address. The obj argument can either be
a processor, a memory-space, or an image object. In case of a processor,
the address is interpreted as a virtual address.
The file can be either a raw binary file or a file in the craff
format.
The verbose flag will cause Simics to print some information
about the load.
- EXCEPTIONS
-
SimExc_IOError Thrown if there was a problem reading the file.
SimExc_General Thrown if file cannot be read into memory.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_read_byte, SIM_write_byte — read/write byte from a memory space
- SYNOPSIS
-
uint8
SIM_read_byte(conf_object_t *NOTNULL obj, generic_address_t paddr);
void
SIM_write_byte(conf_object_t *NOTNULL obj,
generic_address_t paddr, uint8 value);
- DESCRIPTION
-
Read or write a byte from a given address in the memory space obj.
- EXCEPTIONS
-
SimExc_Memory Thrown if the memory space threw an exception
SimExc_General Thrown if the object does not implement the memory
space interface.
- RETURN VALUE
-
The byte read.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_read_phys_memory — read data from a physical address
- SYNOPSIS
-
uint64
SIM_read_phys_memory(conf_object_t *NOTNULL cpu,
physical_address_t paddr,
int length);
- DESCRIPTION
-
Reads length bytes from address paddr in the physical
memory space associated with the processor cpu.
Up to 8 bytes can be read in one call. The memory access will be of
inquiry type, i.e. no timing-model or snoop device will be called.
For non-inquiry accesses, use the memory_space
interface directly.
- EXCEPTIONS
-
SimExc_Memory Thrown if no memory defined at paddr.
SimExc_Attribute Thrown if length is out of range.
SimExc_General Thrown if the processors physical memory does not
implement the necessary interface methods.
- RETURN VALUE
-
The read data, zero-extended.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_read_phys_memory_tags, SIM_write_phys_memory_tags — access auxiliary bits in physical memory
- SYNOPSIS
-
uint64
SIM_read_phys_memory_tags(conf_object_t *NOTNULL mem_space,
physical_address_t paddr, unsigned ntags);
void
SIM_write_phys_memory_tags(conf_object_t *NOTNULL mem_space,
physical_address_t paddr,
uint64 tag_bits, unsigned ntags);
- DESCRIPTION
-
Reads or writes ntags auxiliary bits starting at paddr
in the physical memory space mem_space.
Up to 64 bits can be accessed at once. The bits are specified and returned
right-aligned, least significant bit corresponding to the lowest address.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_write_phys_memory — write data to a physical address
- SYNOPSIS
-
void
SIM_write_phys_memory(conf_object_t *NOTNULL cpu,
physical_address_t paddr,
uint64 value, int length);
- DESCRIPTION
-
Writes length bytes to address paddr in the physical
memory space associated with the processor cpu.
Up to 8 bytes can be written in one call. The memory access will be of
inquiry type, i.e. no timing-model or snoop device will be called.
- EXCEPTIONS
-
SimExc_Memory Thrown if no memory defined at paddr.
SimExc_Attribute Thrown if length is out of range.
SimExc_General Thrown if the processors physical memory does not
implement the necessary interface methods.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_add_module_dir — add loadable module search path
- SYNOPSIS
-
void
SIM_add_module_dir(const char *path);
- DESCRIPTION
-
Add given path to the list of paths where Simics searches for loadable
modules. The function SIM_module_list_refresh has to be called
after calling this function, for the change to take effect.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_get_all_failed_modules — return a list of all modules that failed to load
- SYNOPSIS
-
attr_value_t
SIM_get_all_failed_modules();
- DESCRIPTION
-
A failed module is a module that is not loadable by the current version
of Simics. The list returned contains information about why the module
failed. Each list entry is another list with module specific information.
The layout of this sub-list is described below. The list may change
in future Simics versions.
- name - Module name (string).
- path - File system path to the module (string).
- duplicate - Flag indicating a duplicate module
(boolean).
- linker - Flag indicating a linker error (boolean).
- version - Simics ABI version that the module was built for
(integer).
- build_id - Simics build number when the module was built
(integer).
- build_date - When the module was built, in seconds from epoch
(integer).
- user version - User version of the module (string).
- error - Error message, typically from the linker
(string or nil).
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_all_modules
- NAME
-
SIM_get_all_modules — return a list of all modules
- SYNOPSIS
-
attr_value_t
SIM_get_all_modules();
- DESCRIPTION
-
The list returned contains information about all modules that can be loaded
into Simics. Each list entry is another list with module specific
information. The layout of this sub-list is described below. The list may
grow in future Simics version, but the currently defined fields will not
change.
- name - Module name (string).
- path - File system path to the module (string).
- loaded - Flag indicating that the module is already loaded
(boolean).
- version - Oldest Simics ABI version that the module was built for
(integer).
- user version - User version of the module (string).
- build-id - Simics build-id that indicates in which Simics
build this module was created (integer).
- build-date - Build date of the module, in seconds
(integer).
- classes - Classes this module claims to implement.
- thread-safe - If the module is thread-safe.
- components - Components this module claims to implement.
- user path - Module was loaded from path provided by user.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_all_failed_modules
- NAME
-
SIM_load_module — load a module
- SYNOPSIS
-
void
SIM_load_module(const char *NOTNULL module);
- DESCRIPTION
-
Load a Simics module. Normally, modules are loaded automatically
as needed for the configuration classes they implement, and there is
rarely any need to call this function explicitly.
The module argument is the name of the module (not
file name) to be loaded.
- EXCEPTIONS
-
SimExc_License Thrown if the module requires a non-existing
license feature.
SimExc_General Thrown if the module failed to load for other
reasons.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_module_list_refresh — refresh list of loadable modules
- SYNOPSIS
-
void
SIM_module_list_refresh();
- DESCRIPTION
-
Simics maintains a list of all modules that can be loaded successfully. If a
module is changed or added, the list has to be refreshed before Simics can
load this module.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_ASSERT_CELL_CONTEXT — assert Cell Context
- SYNOPSIS
-
SIM_ASSERT_CELL_CONTEXT(obj);
- DESCRIPTION
-
The SIM_ASSERT_CELL_CONTEXT function verifies that cell
thread domain associated with obj is held by the calling thread
and raises a hard failure if this is not the case.
In other worlds, the macro ensures that the execution context is either
Cell Context or Global Context.
- NAME
-
SIM_ASSERT_OBJECT_LOCK — assert thread domain is held
- SYNOPSIS
-
SIM_ASSERT_OBJECT_LOCK(obj);
- DESCRIPTION
-
The SIM_ASSERT_OBJECT_LOCK function checks that the
thread domain associated with obj is held. A hard failure
is raised if the thread domain is not held.
- NAME
-
SIM_acquire_cell, SIM_release_cell, SIM_ACQUIRE_CELL, SIM_RELEASE_CELL — enter Cell Context
- SYNOPSIS
-
domain_lock_t *
SIM_acquire_cell(conf_object_t *NOTNULL obj,
const char *NOTNULL function_name,
const char *NOTNULL source_location);
void
SIM_release_cell(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_CELL(obj, lockp);
SIM_RELEASE_CELL(obj, lockp);
- DESCRIPTION
-
Enters Cell Context for the cell associated with the
object obj.
As part of entering Cell Context, the cell thread domain
for the cell associated with obj is acquired.
Entering Cell Context multiple times is allowed, but
acquired thread domains must be released in strict reverse order.
This function will block until the cell is available if another
thread is currently holding the cell thread domain.
While blocking, any previously held domains can be acquired by
the thread already in Cell Context. Thus, the caller must
be prepared to handle e.g. incoming interface calls.
In Cell Context, API functions marked with Cell Context
or Global Context can be called safely, and interfaces
on objects belonging to the same cell can be called directly. More
generally, the full Standard Device Model applies in Cell Context.
Refer to the chapter about threading in the API Reference Manual for more
details.
The macro version of this API call sets the
function_name and source_location arguments
automatically with the information where the API call was made. This data
is used when lock statistics collection is enabled
through the enable-object-lock-stats command.
- SEE ALSO
-
SIM_acquire_object,
SIM_acquire_target
- RETURN VALUE
-
SIM_acquire_cell returns a domain lock handle which should
be passed as an argument to SIM_release_cell when the
lock is released. SIM_ACQUIRE_CELL does not return
anything but instead stores the domain lock handle in the pointer
passed as the second argument.
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_acquire_object, SIM_release_object, SIM_ACQUIRE_OBJECT, SIM_RELEASE_OBJECT — acquire thread domain
- SYNOPSIS
-
domain_lock_t *
SIM_acquire_object(conf_object_t *NOTNULL obj,
const char *NOTNULL function_name,
const char *NOTNULL source_location);
void
SIM_release_object(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_OBJECT(obj, lockp);
SIM_RELEASE_OBJECT(obj, lockp);
- DESCRIPTION
-
Acquires the thread domain associated with the object obj.
A particular thread domain can only be held by a single thread at a time,
and this function blocks until the domain is available. Once the domain
is held, the thread can safely access state protected
by the domain.
While blocking, any previously held domains can be acquired by
threads with higher priority, such as a thread running in
Cell Context.
More than one thread domain can be held simultaneously, and the same
thread domain may be acquired multiple times.
However, domains must be released in strict reverse order.
This function is typically used by models using the Threaded Device Model
to acquire the model's own thread domain from its interface methods.
In this case, obj is set to the model itself.
The macro version of this API call sets the
function_name and source_location arguments
automatically with the information where the API call was made. This data
is used when lock statistics collection is enabled
through the enable-object-lock-stats command.
More details about thread domains and the threading model are
available in the chapter about threading in the API Reference Manual.
- SEE ALSO
-
SIM_acquire_target,
SIM_acquire_cell
- RETURN VALUE
-
SIM_acquire_object returns a domain lock handle which should
be passed as an argument to SIM_release_object when the
lock is released. SIM_ACQUIRE_OBJECT does not return
anything but instead stores the domain lock handle in the pointer
passed as the second argument.
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_acquire_object_for_execution — acquire object lock for execution
- SYNOPSIS
-
domain_lock_t *
SIM_acquire_object_for_execution(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Acquire the thread domain lock associated with object arg.
Note: This API function is considered tech-preview and may
change without notice.
- RETURN VALUE
-
Domain lock handle which should be passed as
an argument to SIM_release_object when the lock is released.
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_acquire_target, SIM_release_target, SIM_ACQUIRE_TARGET, SIM_RELEASE_TARGET — conditionally enter Cell Context
- SYNOPSIS
-
domain_lock_t *
SIM_acquire_target(conf_object_t *NOTNULL obj,
const char *NOTNULL function_name,
const char *NOTNULL source_location);
void
SIM_release_target(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_TARGET(obj, lockp);
SIM_RELEASE_TARGET(obj, lockp);
- DESCRIPTION
-
Enters Cell Context if the specified object
obj uses the Standard Device Model.
The function does nothing if obj is a thread-aware object,
i.e., if the object belongs to a thread-domain other than the cell.
The intended use for this function is ensuring that Cell Context
is entered before a code running in Threaded Context invokes an
interface on some external object. If the external object is thread aware,
and does not require Cell Context, this function avoids entering
Cell Context as an optimization.
The macro version of this API call sets the
function_name and source_location arguments
automatically with the information where the API call was made. This data
is used when lock statistics collection is enabled
through the enable-object-lock-stats command.
- RETURN VALUE
-
SIM_acquire_target returns a domain lock handle which should
be passed as an argument to SIM_release_target when the
lock is released. SIM_ACQUIRE_TARGET does not return
anything but instead stores the domain lock handle in the pointer
passed as the second argument.
- SEE ALSO
-
SIM_acquire_object,
SIM_acquire_cell
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_drop_thread_domains, SIM_reacquire_thread_domains, SIM_DROP_THREAD_DOMAINS, SIM_REACQUIRE_THREAD_DOMAINS — temporarily release all held thread domains
- SYNOPSIS
-
domain_lock_t *
SIM_drop_thread_domains();
void
SIM_reacquire_thread_domains(domain_lock_t *dl);
SIM_DROP_THREAD_DOMAINS(obj, lockp);
SIM_REACQUIRE_THREAD_DOMAINS(obj, lockp);
- DESCRIPTION
-
Temporarily releases all held thread domains and enters
Threaded Context.
This function is intended to use before blocking is initiated on an
external synchronization mechanism, like a condition variable.
Releasing thread domains before blocking is often necessary
to avoid deadlock situations where other threads get stuck
trying to acquire thread domains held by the blocking thread.
Each call to SIM_drop_thread_domains must be
followed with a call to SIM_reacquire_thread_domains
to reacquire the released thread domains. This must
be done from the same thread.
If the purpose of the call is just to provide other threads
an opportunity to acquire held domains, then the more efficient
SIM_yield_thread_domains should be used instead.
The macro versions of the API calls are currently wrappers of
the corresponding SIM-function. In the future, they might collect
extra information about where in the code the domain locks are
reacquired.
- RETURN VALUE
-
SIM_drop_thread_domains returns a domain lock handle
which should be passed as an argument to
SIM_reacquire_thread_domains_object.
The SIM_DROP_THREAD_DOMAINS does not return
anything but instead stores the domain lock handle in the pointer
passed as the second argument.
- SEE ALSO
-
SIM_yield_thread_domains
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_yield_thread_domains — yield held thread domains
- SYNOPSIS
-
void
SIM_yield_thread_domains();
- DESCRIPTION
-
Yields held thread domains if there are other threads waiting to
acquire them.
The function blocks until all threads waiting for one of the
held domains have had the opportunity to acquire the domain in question,
and then resumes execution with the domains held again.
One example usage of this function is when a CPU model is notified
through the execute_control interface that another
thread wants to acquire the CPU's thread domain. Then the CPU
function should call this function as quickly as possible,
preferably before starting the simulation of the next instruction.
- SEE ALSO
-
SIM_drop_thread_domains,
SIM_acquire_object
- EXECUTION CONTEXT
-
Any
- NAME
-
SIM_add_output_handler, SIM_remove_output_handler — add or remove output handler
- SYNOPSIS
-
void
SIM_add_output_handler(void (*NOTNULL f)(lang_void *user_data,
const char *text,
size_t length),
lang_void *user_data);
void
SIM_remove_output_handler(void (*NOTNULL f)(lang_void *user_data,
const char *text,
size_t length),
lang_void *user_data);
- DESCRIPTION
-
SIM_add_output_handler registers
f(user_data, text, length)
to be called whenever there is text output from Simics.
text contains length bytes of output data.
user_data is passed unchanged to the output handler.
SIM_remove_output_handler removes f as an output
recipient. If user_data is NULL, all output
handlers with the same function will be removed; otherwise, only those with
equal user_data will be removed.
Output handlers must be thread-safe in order to handle output from different
threads properly. There will only be one activation of each handler at a
given instant so strict re-entrancy is not required, but proper locking
around resources shared with other code should be in place.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_write
- NAME
-
SIM_write, SIM_flush, SIM_putchar, SIM_puts, SIM_printf_vararg, SIM_printf — text output routines
- SYNOPSIS
-
int
SIM_write(const void *NOTNULL src, int length);
int
SIM_flush();
int
SIM_putchar(int c);
int
SIM_puts(const char *NOTNULL s);
int
SIM_printf_vararg(const char *NOTNULL format, va_list ap);
int
SIM_printf(const char *NOTNULL format, ...);
- DESCRIPTION
-
These are the Simics versions of the write,
putchar, puts, printf,
vprintf, and fflush C library functions.
The arguments and return values
are the same as for the library functions, except for
SIM_write which does not take any file argument.
The output will be sent to stdout, but more output recipients
can be added using the SIM_add_output_handler function.
Output is line buffered. SIM_flush will force output of an
unterminated line.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_add_output_handler
- NAME
-
SIM_add_directory — add directory to search path
- SYNOPSIS
-
void
SIM_add_directory(const char *NOTNULL directory, bool prepend);
- DESCRIPTION
-
Adds a directory to Simics's search path. This is a list of directories
which Simics uses when searching for files such as disk dumps, kernel
images, etc.
The directory argument is first converted using
SIM_native_path, to yield a path on host native form.
If the path does not exist, a frontend exception is raised.
If prepend is true, the directory is inserted first in the
list of directories.
This list of directories is saved as the attribute
simics_path when doing write-configuration.
Each directory is first converted to absolute form if relative.
- EXCEPTIONS
-
SimExc_General Thrown if the directory does not exist.
- SEE ALSO
-
SIM_lookup_file, SIM_clear_directories
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_clear_directories — clear the search path
- SYNOPSIS
-
void
SIM_clear_directories();
- DESCRIPTION
-
Deletes all directories from the search path.
- SEE ALSO
-
SIM_add_directory, SIM_lookup_file
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_get_directories — get the current search path
- SYNOPSIS
-
attr_value_t
SIM_get_directories();
- DESCRIPTION
-
Returns the current value of the directory search path.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_lookup_file — find a file using simics search path
- SYNOPSIS
-
char *
SIM_lookup_file(const char *file);
- DESCRIPTION
-
Searches for a file in the Simics search path.
The returned path will always be in host native format, so it will not need
to be converted. See SIM_native_path for more details on what
"host native format" means.
NULL is returned if file cannot be found.
The search algorithm is as follows.
- If file is
NULL or an empty string,
the function returns NULL.
- If file exists and is an absolute path, it is
converted to host native form and returned.
- If file starts with
%simics%, the rest of the
path is looked up first in the current Simics project, and then in
all configured Simics packages. If a match is found, the native form
of the file found will be returned.
- If file exists in or relative to the current
directory, it is returned without using the Simics search path. This
is more or less equivalent of always having "." first in the
search path.
- For each directory in Simics search path: The directory and the file
is concatenated and converted to host native format. Each such file
is looked up first in the current Simics project, and then in all
Simics packages. If a match is found, the native form of the file
found will be returned.
If the file was found, a pointer to the full path to the file is returned.
The ownership of the string is passed to the caller.
- SEE ALSO
-
SIM_add_directory, SIM_clear_directories
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_native_path — convert path to its native form
- SYNOPSIS
-
char *
SIM_native_path(const char *NOTNULL path);
- DESCRIPTION
-
Translates a path to its host native form. This functions is a no-op on all
platforms except Windows.
The value returned by this function is allocated and owned by the caller.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_clear_augmentation_bit, SIM_get_augmentation_bit, SIM_set_augmentation_bit — convenience functions to work with augmented memory bits
- SYNOPSIS
-
FORCE_INLINE void
SIM_clear_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
FORCE_INLINE int
SIM_get_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
FORCE_INLINE void
SIM_set_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
- DESCRIPTION
-
The SIM_clear_augmentation_bit,
SIM_get_augmentation_bit,
and SIM_set_augmentation_bit functions are used to modify
and read augmented memory bits. The
direct_memory_tags
interface supports augmented memory through the data
field in the direct_memory_tags_t struct.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_disassemble_address — disassemble address
- SYNOPSIS
-
tuple_int_string_t
SIM_disassemble_address(conf_object_t *NOTNULL cpu, generic_address_t address,
int logical, int sub_operation);
- DESCRIPTION
-
This function disassembles the instruction at the given
address. Address is either a physical address (logical == 0) or a
logical address (logical == 1). For VLIW architectures,
sub_operation is used to select which sub-operation
to disassemble. A request for a not present sub-operation (for
example sub-operation != 0 for non-VLIW
architectures) results in the int part of the return tuple being
set to zero.
A tuple_int_string_t is returned which contains the
disassembly string as well as the length of the instruction in
bytes. tuple_int_string_t is defined like this:
typedef struct {
int integer;
char *string;
} tuple_int_string_t;
For the Sparc and PowerPC
targets the length is always 4 bytes.
This function can be more convenient to use than the
disassemble function in the
processor_info interface.
- EXCEPTIONS
-
SimExc_General Thrown if arguments are invalid.
SimExc_Memory Thrown if the address is undefined or not mapped in the
MMU (for logical addresses).
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_all_processors — get list of all processors
- SYNOPSIS
-
attr_value_t
SIM_get_all_processors();
- DESCRIPTION
-
Return a list of all processor objects.
- RETURN VALUE
-
List of processors.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_processor — get processor pointer from number
- SYNOPSIS
-
conf_object_t *
SIM_get_processor(int proc_no);
- DESCRIPTION
-
Converts processor id number to processor pointer. This function cannot be
used until a configuration had been loaded successfully.
- EXCEPTIONS
-
SimExc_Index Thrown if no processor with number proc_no
exists.
- RETURN VALUE
-
The processor pointer, NULL on failure.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_number_processors
- NAME
-
SIM_get_processor_number — get the number of a processor
- SYNOPSIS
-
int
SIM_get_processor_number(const conf_object_t *NOTNULL cpu);
- DESCRIPTION
-
Returns the global processor number for a processor in Simics.
- RETURN VALUE
-
The processor number
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_number_processors — number of processors
- SYNOPSIS
-
int
SIM_number_processors();
- DESCRIPTION
-
Returns the current total number of processors in the system.
- RETURN VALUE
-
Number of processors.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_get_processor
- NAME
-
SIM_processor_privilege_level — return the current privilege level for a processor
- SYNOPSIS
-
int
SIM_processor_privilege_level(conf_object_t *NOTNULL cpu);
- DESCRIPTION
-
Return the current privilege level for a processor. The definition
of privilege levels depends on the processor type.
- RETURN VALUE
-
For SPARC, and PowerPC, and ARM processors: 0 for User mode, and
1 for Supervisor mode.
For x86 and IA-64 processors: 0-3, where 0 is the most privileged.
For MIPS processors: 0
- EXCEPTIONS
-
SimExc_General Thrown if cpu does not implement the privilege
level interface function.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_reset_processor — reset the processor
- SYNOPSIS
-
void
SIM_reset_processor(conf_object_t *NOTNULL cpu, int hard_reset);
- DESCRIPTION
-
Performs a reset on the processor, causing a System Reset exception to be
taken when execution continues. cpu is the processor that should be
reset.
hard_reset indicates if a soft (0) or hard (1) (power-on type) reset
should be performed. If a hard reset is requested, a number of register are
initiated with default values.
- EXCEPTIONS
-
SimExc_General Thrown if cpu does not implement reset.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_iter_next, SIM_iter_addr, SIM_iter_free — Iterate over address profile counters
- SYNOPSIS
-
FORCE_INLINE uint64
SIM_iter_next(addr_prof_iter_t *iter);
FORCE_INLINE generic_address_t
SIM_iter_addr(addr_prof_iter_t *iter);
FORCE_INLINE void
SIM_iter_free(addr_prof_iter_t *iter);
- DESCRIPTION
-
EXPERIMENTAL. While this functionality is expected to be retained in
future releases, the interface is likely to change.
An address profile iterator visits some of the counters of an address
profiler in some order. It is obtained from the iter function of
the address_profiler interface.
SIM_iter_next advances the address profile iterator
iter to the next nonzero counter and returns the count. It
will return 0 when there are no more counters to visit. Note that the order
in which the counters are visited is unspecified.
SIM_iter_addr returns the address of the counter returned by the
most recent call to iter_next.
When you are done with the iterator, deallocate it with
SIM_iter_free.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_break_message — stop the simulation
- SYNOPSIS
-
void
SIM_break_message(const char *msg);
- DESCRIPTION
-
Display the reason why Simics will stop simulation.
This is similar to SIM_break_simulation, with the
difference that it doesn't actually break the simulation. It can be
used by code that wants to display a break message and stop the
simulation by some other means.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_break_simulation
- NAME
-
SIM_break_simulation — stop the simulation
- SYNOPSIS
-
void
SIM_break_simulation(const char *msg);
- DESCRIPTION
-
Ask Simics to stop the simulation as soon as possible, displaying the
supplied message.
Simics will normally stop before the next instruction is executed.
If this function is called when an instruction has started
executing, and the instruction can be aborted, it will rewind to
before the instruction. This might leave the simulation in a state
where some repeatable part of the instruction is already executed.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_break_message
- NAME
-
SIM_continue — run the simulation
- SYNOPSIS
-
pc_step_t
SIM_continue(int64 steps);
- DESCRIPTION
-
Run the simulation. In typical usage with steps being 0, the
simulation will run forward until it is stopped, either by a breakpoint,
internal event, or through the user interface.
With a non-zero steps, Simics will make sure that at least
one processor runs steps steps and then stop the
simulation. As with steps being 0, the function can also
return early if other break criteria are met.
In order to properly control when simulation stops in time, it is advisable
to use step or cycle breakpoints on one or more objects.
The function returns non-zero if the simulation was started, and 0 otherwise.
- EXCEPTIONS
-
SimExc_General Thrown if the simulation could not be started. Check
the exception message for more information.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_current_clock — return current clock
- SYNOPSIS
-
conf_object_t *
SIM_current_clock();
- DESCRIPTION
-
Returns the clock (an object implementing the
cycle
interface) that is driving the simulation in the current cell and current
thread. In Global Context, NULL is returned.
Please note that typically model code would use SIM_object_clock
to obtain the clock used for posting events. Another alternative for models
is to get the initiator of a memory transaction from the memory transaction
itself with the functions like SIM_transaction_initiator and
SIM_get_mem_op_initiator and use that for event posting.
The currently running clock returned by this function can be used, for
example, to post events right after the current instruction finishes. But,
as it is pointed out above, there are other alternatives for getting a clock
for posting events. The use of this function is generally discouraged.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_object_clock, SIM_transaction_initiator,
SIM_get_mem_op_initiator
- NAME
-
SIM_simics_is_running — check if simulation is running
- SYNOPSIS
-
bool
SIM_simics_is_running();
- DESCRIPTION
-
Returns true if the simulation is running, e.g. if it has been started using
SIM_continue, or false otherwise. It also returns true when the
simulation is reversing.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_cancel_realtime_event — cancel callback in host time
- SYNOPSIS
-
int
SIM_cancel_realtime_event(int64 id);
- DESCRIPTION
-
Cancel a callback registered by SIM_realtime_event, whose
return value is specified as id.
Returns 0 if the callback existed and was cancelled, or -1 if no callback
with that identifier existed. (No exception is raised.)
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_realtime_event
- NAME
-
SIM_notify_on_socket, SIM_notify_on_object, SIM_notify_on_descriptor — register notification on host I/O events
- SYNOPSIS
-
void
SIM_notify_on_socket(socket_t sock, notify_mode_t mode, int run_in_thread,
void (*callback)(lang_void *data), lang_void *data);
void
SIM_notify_on_object(HANDLE obj, int run_in_thread,
void (*callback)(lang_void *data), lang_void *data);
void
SIM_notify_on_descriptor(int fd, notify_mode_t mode, int run_in_thread,
void (*callback)(lang_void *data),
lang_void *data);
- DESCRIPTION
-
These functions allow the function callback to be called
with argument data whenever a specific I/O event occurs on
the host machine. If callback is a null function pointer,
a previously installed notification is removed.
If run_in_thread is 1, the callback function may be run
in a thread where it cannot access or call anything in Simics except for
these functions and SIM_thread_safe_callback. If
run_in_thread is zero, the callback function is always run in
Global Context. This may incur a small penalty in latency (time
between the occurrence of the host event and execution of
callback).
Values other than 0 and 1 for run_in_thread are reserved.
Notification on a specific event will be blocked during the execution of
its callback function.
SIM_notify_on_socket will call a registered callback depending
on mode:
| mode |
condition |
Sim_NM_Read |
Socket is readable, closed, or incoming connection accepted |
Sim_NM_Write |
Socket is writeable, or outgoing connection has completed |
Socket notifiers of the mode Sim_NM_Write are not guaranteed
to be called again unless a previous attempt to send data to the socket
failed for flow control reasons (that is, it would have blocked).
This means that notifiers of that mode should only be enabled for waiting on
the completion of a nonblocking outgoing connection or for a previously
"full" socket to accept data again.
Linux only: SIM_notify_on_descriptor will call a
registered callback depending on mode for a given file
descriptor in a way similar to SIM_notify_on_socket.
Windows only: SIM_notify_on_object will call a registered
callback when object (which must be a waitable object) is in
signalled state. The signalling object is modified in the same way as
the Windows wait functions (WaitForMultipleObjects etc).
Note:
A notification should be removed before its socket or descriptor is
closed.
Note:
On Windows, sockets registered for notification become nonblocking and
must remain so for as long as they are registered. This is a limitation of
the underlying Win32 API.
- EXECUTION CONTEXT
-
Cell Context (call);
Threaded Context (callback with nonzero run_in_thread);
Global Context (callback otherwise)
- SEE ALSO
-
SIM_thread_safe_callback
- NAME
-
SIM_realtime_event — schedule callback in host time
- SYNOPSIS
-
int64
SIM_realtime_event(unsigned delay, void (*NOTNULL callback)(lang_void *data),
lang_void *data, int run_in_thread, const char *desc);
- DESCRIPTION
-
Register callback to be run in delay ms, with
argument data. The delay is in real time (on the host
machine), and the actual delay may be somewhat larger because of host
scheduling.
If run_in_thread is 1, the callback may be run in a
thread where it cannot access or call anything in Simics except for
SIM_thread_safe_callback. If run_in_thread is
zero, the callback function is always run in Global Context,
with the simulation temporarily suspended and the entire Simics API
available. This may cause the call to occur slightly later than requested,
depending on what Simics is doing at the time.
Values other than 0 and 1 for run_in_thread are reserved.
The desc parameter is only present for debugging and has no
other effect; it should be a static string describing the callback but may
also be left NULL if desired.
The callback is only called once.
The return value is a non-zero identifier that can be used to cancel the
callback using SIM_cancel_realtime_event.
- EXECUTION CONTEXT
-
Cell Context. The callback is called in
Threaded Context if run_in_thread is nonzero,
in Global Context otherwise.
- SEE ALSO
-
SIM_cancel_realtime_event, SIM_thread_safe_callback
- NAME
-
SIM_register_work, SIM_thread_safe_callback, SIM_run_alone — register function to be called in Global Context
- SYNOPSIS
-
void
SIM_register_work(void (*NOTNULL f)(lang_void *data), lang_void *data);
void
SIM_thread_safe_callback(void (*NOTNULL f)(lang_void *data), lang_void *data);
void
SIM_run_alone(void (*NOTNULL f)(lang_void *data), lang_void *data);
- DESCRIPTION
-
SIM_register_work and SIM_thread_safe_callback
register work to be done in Global Context as soon as
possible, (but not during the call to SIM_register_work or
SIM_thread_safe_callback itself).
SIM_run_alone also registers work to be done in Global Context
and if called from Cell Context the callback is executed before the next
instruction is dispatched in the cell. If this isn't used the cell may
execute several instructions before the callback is executed.
If SIM_run_alone is used while an instruction is being emulated
then the callback will be invoked when the current instruction has completed
and before the next instruction is dispatched.
No other execution threads are running when the callback is invoked,
but their exact position in simulated time may vary between runs. If
the callback accesses objects in cells other than the one that
SIM_run_alone was called from, then care must be taken to
preserve determinism.
When the callback is run, it is executed in Global Context,
which means that it is safe to call any API functions from
it. Another thread in the module may at this time also call API
functions, if it synchronizes correctly with the callback
function. For example, the callback function might just signal to the
foreign thread to do its Simics API calls, wait for the thread to
signal that it has finished, and then return.
- EXECUTION CONTEXT
-
Threaded context (call);
Global Context (callback)
- SEE ALSO
-
SIM_run_unrestricted
- NAME
-
SIM_run_async_work — launch asynchronous work in a separate thread
- SYNOPSIS
-
void
SIM_run_async_work(lang_void *(*NOTNULL async_call)(lang_void *arg),
void (*async_ready)(lang_void *async_ret, lang_void *arg),
lang_void *arg);
- DESCRIPTION
-
SIM_run_async_work creates a new thread, running in parallel with
the Simics main thread, where the async_call function will be
called. Since the function runs in Threaded Context, most Simics API
functions are not available. Once the async_call function has
run, its return value is passed to async_ready, if supplied,
that will be called in Global Context, i.e. in the Simics main thread.
The user supplied arg parameter is passed unmodified to both
callback functions.
SIM_run_async_work is typically used when calling functions that
would block the main thread for a long time while obtaining their result.
If the result of SIM_run_async_work is used in the simulation, it
should be sent through a recorder to make sure that the session can be
replayed. See the recorder module and the recorder_v2
interface for more information.
- EXAMPLE
-
import socket
def async_call(arg):
# runs in separate thread without blocking Simics
return socket.gethostbyname(arg)
def async_ready(ret, arg):
# runs in Simics main thread with access to the full Simics API
print("Host %s has IP address %s" % (arg, ret))
simics.SIM_run_async_work(async_call, async_ready, "www.intel.com")
- EXECUTION CONTEXT
-
Cell Context (call);
Threaded Context (async_call callback);
Global Context (async_ready callback)
- SEE ALSO
-
SIM_notify_on_descriptor, SIM_notify_on_object,
SIM_notify_on_socket, SIM_thread_safe_callback,
SIM_run_alone, SIM_run_unrestricted
- NAME
-
SIM_run_in_thread — run function in a separate thread
- SYNOPSIS
-
void
SIM_run_in_thread(void (*NOTNULL f)(lang_void *arg), lang_void *arg);
- DESCRIPTION
-
SIM_run_in_thread schedules the callback f to run
on a separate thread. The callback will run in Threaded Context
and must observe the associated restrictions.
Simics maintains a pool of worker threads used by this function, and hence
the callback can typically be started quickly.
The callback is allowed to block or otherwise run for a long time.
The user supplied arg parameter is passed unmodified to the
callback.
- EXECUTION CONTEXT
-
Any thread context (call);
Threaded Context (callback);
- SEE ALSO
-
SIM_run_async_work, SIM_run_alone
- NAME
-
SIM_STC_flush_cache, SIM_flush_I_STC_logical, SIM_flush_D_STC_logical, SIM_flush_I_STC_physical, SIM_flush_D_STC_physical — flush or remove entries in the STCs of a cpu
- SYNOPSIS
-
void
SIM_STC_flush_cache(conf_object_t *NOTNULL cpu);
void
SIM_flush_I_STC_logical(conf_object_t *NOTNULL cpu,
logical_address_t vaddr,
logical_address_t length);
void
SIM_flush_D_STC_logical(conf_object_t *NOTNULL cpu,
logical_address_t vaddr,
logical_address_t length);
void
SIM_flush_I_STC_physical(conf_object_t *NOTNULL cpu,
physical_address_t paddr,
physical_address_t length);
void
SIM_flush_D_STC_physical(conf_object_t *NOTNULL cpu,
physical_address_t paddr,
physical_address_t length,
read_or_write_t read_or_write);
- DESCRIPTION
-
These functions remove entries from the Simics internal caches (STCs) or
completely flushes the STCs contents. Memory mappings which have been
cached in the STCs will be faster for Simics to execute. Simics
extensions such as a cache model will need to flush entries in the STC
when a cache line is replaced, in order to be called when a cache line
is used again.
SIM_STC_flush_cache flushes the entire contents of the STCs
(both instruction and data) from the specified cpu.
The SIM_flush_xxx functions removes specified memory
ranges in the instruction or data STC. The address range is either the
logical or the physical address. The read_or_write parameter
specifies whether the read or the write D-STC should be flushed. If the
function doesn't have such a parameter, both read and write D-STCs are
flushed. The flushed address range is at least [ vaddr
... (vaddr + length − 1) ], but may be larger.
SIM_flush_D_STC_logical currently always flushes an entire
page.
The SIM_flush_xxx functions can only be used on CPUs
that implement the internal stc interface; hence, they can
not be used on user-defined CPU models.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_flush_all_caches — clear Simics's internal caches
- SYNOPSIS
-
void
SIM_flush_all_caches();
- DESCRIPTION
-
Clears Simics's internal caches such as STC contents and intermediate code.
This function is mainly for internal use (for debugging purposes)
and may be removed in the future.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_flush_cell_caches — clear internal caches for a given cell
- SYNOPSIS
-
void
SIM_flush_cell_caches(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
Clears internal caches in Simics for a given cell, such as STC contents and
intermediate code.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_stall_count — get number of cycles a processor has been stalled
- SYNOPSIS
-
cycles_t
SIM_stall_count(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
SIM_stall_count returns the total number of cycles the
processor associated to obj has been stalled.
- RETURN VALUE
-
Returns the total number of cycles the processor associated with
obj has been stalled.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_stall_cycle, SIM_stall — stall execution a specified number of cycles
- SYNOPSIS
-
void
SIM_stall_cycle(conf_object_t *NOTNULL obj, cycles_t cycles);
void
SIM_stall(conf_object_t *NOTNULL obj, double seconds);
- DESCRIPTION
-
SIM_stall_cycle and SIM_stall set the stall duration
of the processor obj. The stall duration is given in clock
cycles or seconds and is how long obj will stall before
resuming its normal activity. If obj was already stalling,
the time remaining is changed. A zero stall duration is a request to cease
stalling immediately.
The specified duration is interpreted as relative the local time of
obj.
obj must implement the stall and
cycle interfaces.
- EXECUTION CONTEXT
-
Cell Context
- EXCEPTIONS
-
SimExc_General Thrown if cycles or seconds is negative.
- SEE ALSO
-
SIM_stalled_until, SIM_stall_count
- NAME
-
SIM_stalled_until — query how many cycles that remains of stall
- SYNOPSIS
-
cycles_t
SIM_stalled_until(conf_object_t *NOTNULL obj);
- DESCRIPTION
-
SIM_stalled_until returns how many more cycles the
processor will stall before the associated processor starts to
execute instructions again.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_global_message — obtain current global message
- SYNOPSIS
-
const char *
SIM_get_global_message(void *ref);
- DESCRIPTION
-
Return the global message currently being triggered, if ref
does not match the reference of the source trigger, otherwise return
NULL.
This function must only be called from a callback of the global notifier
Sim_Global_Notify_Message.
- EXECUTION CONTEXT
-
Global Context
- SEE ALSO
-
SIM_trigger_global_message
- NAME
-
SIM_trigger_global_message — queue up a global message
- SYNOPSIS
-
void
SIM_trigger_global_message(const char *msg, void *ref);
- DESCRIPTION
-
This queues up a global message, which will be dispatched shortly in
global context, to all listeners of the Sim_Global_Notify_Message
global notifier. The ref parameter is the reference of the
source, or
NULL to dispatch to all listeners.
The notifier callbacks should use SIM_get_global_message to
retrieve the message. Only callbacks that provide a NULL reference
or a reference different from ref will obtain the message.
- EXECUTION CONTEXT
-
All contexts including Threaded Context
- SEE ALSO
-
SIM_get_global_message
- NAME
-
SIM_call_python_function — call a Python named function
- SYNOPSIS
-
attr_value_t
SIM_call_python_function(const char *NOTNULL func, attr_value_t *NOTNULL args);
- DESCRIPTION
-
Calls the Python function named func with arguments in
args, which must be a list.
The namespace searched for func is the same as the Simics
commands @ and python use; i.e., the Python module
__main__. You may want to use a module-relative name for
func such as __builtin__.repr when calling functions
not defined at the Simics command-line. This avoids calling any local
redefinition of that function.
- EXCEPTIONS
-
SimExc_Type Thrown if args is not list or cannot be
converted to Python or if func is not callable or if the
return value cannot be converted to an
attr_value_t.
SimExc_Lookup Thrown if func does not exist.
SimExc_General Thrown if there was an error executing
Python code.
SimExc_Break Thrown on user interrupt.
- RETURN VALUE
-
Return value of the Python function
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIM_make_attr_list, SIM_run_python
- NAME
-
SIM_get_api_function — return an API function by name
- SYNOPSIS
-
api_function_t
SIM_get_api_function(const char *function);
- DESCRIPTION
-
Looks up a C function in the Simics API based on its name and returns a
pointer to it. Typically used to access a function added to the Simics API
in an update release (minor version) while remaining binary compatible with
older versions of Simics.
The pre-processor macro GET_API_FUNCTION provides
wrapping of SIM_get_api_function for simpler type casting.
SIM_get_api_function is neither available nor needed in Python.
Code examples showing how to access a new function in a backward compatible
in Python are provided below.
- EXAMPLE
-
A new function SIM_foo is introduced in the
Simics release with build id 5234. Since older versions of Simics
do not have this function, a module writer that wants to use it while
remaining compatible with old Simics versions, can write the following:
GET_API_FUNCTION(tmp_SIM_foo, SIM_foo);
if (tmp_SIM_foo != NULL)
tmp_SIM_foo(1);
else
// code for older versions
Once compatibility with versions before build id 5234 can be dropped, the
code in the example is simply replaced with a direct call to
SIM_foo.
In Python, one can check whether the function is present like this:
if hasattr(simics, 'SIM_foo'):
simics.SIM_foo(1)
else:
# code for older versions
Another alternative for Python code is to check the build id value:
if conf.sim.build_id >= 5234:
simics.SIM_foo(1)
else:
# code for older versions
- RETURN VALUE
-
Returns a pointer to the API function if it exists
or zero. The return type
api_function_t is defined as:
typedef void (*api_function_t)(void);
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_batch_mode — return setting of the batch-mode
- SYNOPSIS
-
bool
SIM_get_batch_mode();
- DESCRIPTION
-
This function returns the current value of Simics's batch-mode flag.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_get_debugger — return the debugger object
- SYNOPSIS
-
conf_object_t *
SIM_get_debugger();
- DESCRIPTION
-
Returns the Simics Debugger. The returned object is the object which
implements the Simics Debugger API. The debugger object is created if it
does not already exist. Returns NULL and signals an exception if the
debugger could not be created.
- RETURN VALUE
-
Returns the debugger object
- EXCEPTIONS
-
SimExc_General Thrown if the debugger could not be created.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_load_target — load Simics target from file
- SYNOPSIS
-
attr_value_t
SIM_load_target(const char *NOTNULL target,
const char *ns, attr_value_t presets,
attr_value_t cmdline_args);
- DESCRIPTION
-
Load the target target into Simics. This can either be a
file name or a target name, as returned by the list-targets
command.
This function is functionally equivalent to invoking the script by passing
it as a command line argument or to running the script with the
load-target or run-script command, with the
local flag set.
The ns and presets arguments have the same
semantics as namespace and presets arguments to the
run-script command.
The cmdline_args argument should be a list of 2-element lists
of target parameters [name, value].
- EXCEPTIONS
-
SimExc_Break Thrown if the script was interrupted by the user.
SimExc_General Thrown if the script was interrupted by an error.
SimExc_IOError Thrown if the script file could not be opened.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_quit — quit Simics
- SYNOPSIS
-
void
SIM_quit(int exit_code);
- DESCRIPTION
-
Quit Simics in an orderly fashion. The Simics process will return the value
exit_code & 0xFF, since the exit(3) call from the C standard
library is used (see its man page). See the Core_Clean_At_Exit and
Core_At_Exit haps for ways to run user code when Simics exits. Callbacks for
the Core_Clean_At_Exit hap will only run if SIM_quit is called
from Global Context, while Core_At_Exit is always called
- EXECUTION CONTEXT
-
Cell Context. Global Context if possible.
- NAME
-
SIM_run_command — evaluate a CLI command
- SYNOPSIS
-
attr_value_t
SIM_run_command(const char *NOTNULL line);
- DESCRIPTION
-
Runs a CLI command and returns the value, if any, as an attr_value_t.
- EXCEPTIONS
-
SimExc_General Thrown if there was an error executing the CLI
command.
SimExc_Type Thrown if the return value could not be converted
to an attr_value_t.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_run_command_file, SIM_run_command_file_params — read CLI commands from file
- SYNOPSIS
-
void
SIM_run_command_file(const char *NOTNULL file, bool local);
void
SIM_run_command_file_params(const char *NOTNULL file, bool local,
attr_value_t params);
- DESCRIPTION
-
Read and execute the script file file; i.e., execute each line
in the file as if it was typed at the Simics prompt.
This function is functionally equivalent to invoking the script by
passing it as a command line argument or to running the script with
the run-command-file command.
If local is true, the script will run with its own
copy of all global CLI variables. When the script has finished executing,
the previous variable set is restored.
The params argument can be used to pass parameters to the
script. It must be a list of name-value pairs of strings, for example, from
Python it could be [["num_cores", "4"], ["memory_megs", "1024"]].
- EXCEPTIONS
-
SimExc_Break Thrown if the script was interrupted by the user.
SimExc_General Thrown if the script was interrupted by an error.
SimExc_IOError Thrown if the script file could not be opened.
- EXECUTION CONTEXT
-
Global Context
- NAME
-
SIM_run_python — run a Python expression
- SYNOPSIS
-
attr_value_t
SIM_run_python(const char *NOTNULL line);
- DESCRIPTION
-
SIM_run_python runs a Python expression or statement. The
return value, if any, is converted to a Simics attribute value. If
line is a statement, a NIL attribute is returned.
- EXCEPTIONS
-
SimExc_General Thrown if there was an error executing
Python code.
SimExc_Type Thrown if the return value could not be converted
to an attr_value_t.
SimExc_Break Thrown on user interrupt.
- SEE ALSO
-
SIM_call_python_function
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
SIM_shutdown — shutdown Simics
- SYNOPSIS
-
void
SIM_shutdown();
- DESCRIPTION
-
Perform the same clean up as SIM_quit, but do not exit the
process. After having called this function, no Simics API function can be
called.
- EXECUTION CONTEXT
-
Cell Context. Global Context
if possible.
- NAME
-
SIM_source_python, SIM_source_python_in_module — execute Python source file
- SYNOPSIS
-
void
SIM_source_python(const char *NOTNULL file);
void
SIM_source_python_in_module(const char *NOTNULL file,
const char *NOTNULL module);
- DESCRIPTION
-
SIM_source_python executes Python from file in the
global Python scope. SIM_source_python_in_module is similar
but executes the file contents in a named Python module.
- EXCEPTIONS
-
SimExc_General Thrown if there was an error executing
Python code.
SimExc_IOError Thrown if there was an error opening the file.
SimExc_Break Thrown on user interrupt.
- EXECUTION CONTEXT
-
Global Context
- Description
- Interface for getting statistics out of profilers. The target is some kind
of profiler whose data can be meaningfully viewed as counts per address.
The function num_views returns the number k of
different ways you can view the data of this object. The view selection
parameter view to all other functions in the interface
accepts values between 0 and k − 1.
description returns a short string that explains what the data
means. physical_addresses returns true if the profiler works with
physical addresses, or false if it uses virtual addresses.
address_bits returns the number of bits in an address.
granularity_log2 returns the base 2 logarithm of the size, in
bytes, of the address intervals that the counters are associated to. For
example, if the data is instruction execution count and each instruction is
4 bytes long, one would expect the granularity to be at least 4 bytes since
that is the smallest interval containing a whole instruction (but it might
be more, if the profiler is less fine-grained for some reason). And for a
4-byte granularity, granularity_log2 would return 2.
sum returns the sum of all counters between start
and stop, inclusive. max returns the maximum value
of any counter in the range.
iter returns an address profile iterator that will visit all
nonzero counters in the range precisely once, in some order. In C, you can
use the functions SIM_iter_next, SIM_iter_addr and
SIM_iter_free to operate the iterator. In Python, it works just
like any other iterator, and returns (count, address) pairs. Note that you
may not continue to use the iterator after the underlying address profiler
has been modified.
SIM_INTERFACE(address_profiler) {
addr_prof_iter_t *(*iter)(conf_object_t *prof_obj, unsigned view,
generic_address_t start,
generic_address_t stop);
uint64 (*sum)(conf_object_t *prof_obj, unsigned view,
generic_address_t start, generic_address_t end);
uint64 (*max)(conf_object_t *prof_obj, unsigned view,
generic_address_t start, generic_address_t end);
unsigned (*granularity_log2)(conf_object_t *prof_obj, unsigned view);
int (*address_bits)(conf_object_t *prof_obj, unsigned view);
int (*physical_addresses)(conf_object_t *prof_obj, unsigned view);
const char *(*description)(conf_object_t *prof_obj, unsigned view);
unsigned (*num_views)(conf_object_t *prof_obj);
};
#define ADDRESS_PROFILER_INTERFACE "address_profiler"
- Execution Context
- Cell Context for all methods.
- Description
-
Interface for getting branch arcs out profilers. The target is some kind of
profiler whose data can be meaningfully viewed as branch arcs (usually a
branch profiler).
iter returns a branch arc iterator that will visit all branch
arcs in the range precisely once, in order of selected address (to or from,
selected with dir), other address and type. In Python, it
works just like any other iterator, and returns (from, to, counter, type)
tuples. Note that you may not continue to use the iterator after the
underlying profiler has been modified.
branch_arc_type_t defines the branch types returned by a branch
arc iterator.
Branch_Arc_Branch- Normal branch operation
Branch_Arc_Exception- Branch because an exception
was encountered
Branch_Arc_Exception_Return- Branch to finish an
exception handler
typedef enum {
Branch_Arc_Branch,
Branch_Arc_Exception,
Branch_Arc_Exception_Return,
Branch_Arc_Max
} branch_arc_type_t;
typedef enum {
BR_Direction_From,
BR_Direction_To
} branch_recorder_direction_t;
SIM_INTERFACE(branch_arc) {
branch_arc_iter_t *(*iter)(conf_object_t *prof_obj,
generic_address_t start,
generic_address_t stop,
branch_recorder_direction_t dir);
};
#define BRANCH_ARC_INTERFACE "branch_arc"
- Execution Context
- Cell Context for all methods.
- Description
- The
break_strings_v2 interface facilitates management of
string breakpoints. It is implemented by the text console and the graphics
console (but will only function when in text mode).
The text console tries to match each break string on the stream of
characters coming from the attached serial device, and if a match occurs,
the given callback function will be called. If no callback is given, the
simulation will be stopped. The graphics console behaves in the same way,
but in this case the character stream is defined by what is sent to the
console via the vga_text_update interface. Break strings
only lives during a single Simics session, they are not checkpointed.
The add method registers a breakpoint string str, and
returns a breakpoint ID, unique during the Simics session, which is also
passed to cb when the breakpoint matches. If cb is not
NULL, then this function will be called on breakpoint match,
otherwise a match stops the simulation.
The add_single method is similar to add, but the
breakpoint is removed automatically after the first match.
The add_regexp method is similar to add, but the given
string is interpreted as a regular expression. The support regular
expression syntax is that of the Hyperscan library
https://hyperscan.io.
The remove method deactivates a previously activated breakpoint.
SIM_INTERFACE(break_strings_v2) {
int64 (*add)(conf_object_t *NOTNULL obj, const char *str,
break_string_cb_t cb, lang_void *arg);
int64 (*add_single)(conf_object_t *NOTNULL obj, const char *str,
break_string_cb_t cb, lang_void *arg);
int64 (*add_regexp)(conf_object_t *NOTNULL obj, const char *str,
break_string_cb_t cb, lang_void *arg);
void (*remove)(conf_object_t *NOTNULL obj, int64 bp_id);
};
#define BREAK_STRINGS_V2_INTERFACE "break_strings_v2"
- Execution Context
- Global Context
for all methods
- Description
- An internal interface used by the breakpoint manager. Can be changed
at any time.
- Execution Context
- Internal.
- Description
- The
breakpoint_type interface is implemented by the
breakpoint manager and facilitates registering breakpoint types.
This interface is currently a tech preview and can be changed at any time.
The register_type method registers a breakpoint type and creates
CLI commands for this type. The name parameter should be the
unique name for the type, which is also used in the names of any commands
registered on interfaces or class. The provider parameter should
be the provider object, which must implement the
breakpoint_type_provider interface.
The registered commands are break, run-until,
wait-for, trace and untrace, which are
registered on the provider class. If cls or iface are
non-NULL, commands are also registered on that class or interface. These
commands are bp-break-{name}, bp-run-until-{name},
bp-wait-for-{name}, bp-trace-{name} and
bp-untrace-{name}, where {name} is the name parameter.
The cls and iface parameters cannot both be non-NULL.
The args parameter is a list that defines the CLI command
arguments. It should be a list of lists where each inner list contains the
name of the cli.Arg_type subclass, such as str_t, flag_t
etc, and then all parameters to its constructor (including values for
parameters that have default values).
The docs parameter should be an 8-element list with short and
long command documentation texts for the four commands break,
run-until, wait-for and trace.
The object_required parameter indicates if the commands
registered on the provider class (as opposed to the commands on the class or
interface) should require an object (or if the command can use a default
object). Note that there will only be an object parameter if cls
or iface are non-NULL.
The temporary_default parameter indicates if the breakpoints of
this type should be temporary by default. This also results in the generated
break command not having a -once flag.
Setting recursive to true will append a '-recursive' flag to both
global and object commands, and for the global command, the 'object'
argument will have no specified class or iface.
The trigger method must be called by the provider every time a
breakpoint triggers, both breakpoints added with register_bp
method and those added with add_bp method of the
breakpoint_type_provider interface.
SIM_INTERFACE(breakpoint_type) {
/* Returns false if type is already registered. */
bool (*register_type)(conf_object_t *NOTNULL mgr,
const char *NOTNULL name,
conf_object_t *NOTNULL provider,
/* CLI command arguments as a list */
attr_value_t args,
/* Class and/or iface for command */
const char *cls,
const char *iface,
/* 8-element list with short and long
command help texts */
attr_value_t docs,
/* Is an object required
(or can it default to something) */
bool object_required,
/* Should breakpoints be temporary by default? */
bool temporary_default,
/* Set to true to allow all objects in 'object' argument */
bool recursive);
/* Notify manager that breakpoint has triggered, given ID returned by
add_bp. Returns true if simulation was stopped or otherwise the
breakpoint action happened. Optionally provide trigger object and
message, used if the simulation is stopped. */
bool (*trigger)(conf_object_t *NOTNULL mgr,
conf_object_t *NOTNULL provider, uint64 bp_id,
conf_object_t *trigger, const char *msg);
/* Return provider ID from breakpoint manager ID. */
uint64 (*get_break_id)(conf_object_t *NOTNULL mgr, uint64 bm_id);
uint64 (*get_manager_id)(conf_object_t *NOTNULL mgr,
conf_object_t *NOTNULL provider, uint64 bp_id);
};
#define BREAKPOINT_TYPE_INTERFACE "breakpoint_type"
- Execution Context
- Global Context
- Description
- The
breakpoint_type_provider interface should be implemented
by objects that wish to act as breakpoint type providers towards the
breakpoint manager. An object that is passed to the breakpoint manager via
the register_type method in the breakpoint_type
interface must implement breakpoint_type_provider.
This interface is currently a tech preview and can be changed at any time.
The register_bp and add_bp methods receives the
command arguments, corresponding to what the breakpoint manager received in
the register_type. The register_bp method should set
up a breakpoint, register it with the breakpoint manager via the
breakpoint_registration interface, and return the breakpoint
manager ID for that breakpoint. The add_bp method should set up
an internal breakpoint, which is not registered with the breakpoint manager,
and return a provider-specific ID for this breakpoint. The breakpoint
manager will use this ID to remove the breakpoint via the
remove_bp method, and this ID should also be used when calling
the trigger method in the breakpoint_type
interface.
The register_bp and add_bp methods should return 0 to
indicate an error in setting up the breakpoint.
The break_msg method should return the message that should be
printed by the bp.break command after the breakpoint is set
up. It receives the breakpoint manager ID for the breakpoint.
The trace_msg method should return the message that should be
printed when an (internal) trace breakpoint has hit. It receives the
provider specific ID for the breakpoint.
The wait_msg method should return the message that is attached to
the script branch while waiting for a breakpoint to hit (displayed by
e.g. list-script-branches). It receives the provider specific ID
for the breakpoint.
The optional method break_data can be implemented to make the
wait-for and run-until commands return something. It
receives the provider specific ID for the breakpoint.
The method values must be implemented if the provider has
specified that CLI command expanders should be used, when registering the
breakpoint type. Otherwise the method is not called by the breakpoint
manager. It should return the possible values for the command argument
arg, which will be one of the argument names used when
registering the type. The parameter prev_args will be the list of
preceding argument values.
The deleted method is typically optional. If implemented, it is
called by the deleted function of
the breakpoint_registration interface. Normally,
breakpoint manager
registered breakpoints are deleted using the function that was given
to the register_breakpoint method of the
breakpoint_registration interface, which is used by the
bp.delete, but if the breakpoint can be removed by other means,
then this method can be implemented.
SIM_INTERFACE(breakpoint_type_provider) {
/* Register breakpoint in manager.
Return breakpoint manager ID, or 0 on error. */
uint64 (*register_bp)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Add breakpoint and return provider specific ID, or 0 on error. */
uint64 (*add_bp)(conf_object_t *NOTNULL obj,
int flags, attr_value_t data);
/* Remove breakpoint, given ID returned by add_bp. */
void (*remove_bp)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Return trace message, given ID returned by add_bp. */
char *(*trace_msg)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Message returned by break command, given ID returned by add_bp. */
char *(*break_msg)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Script branch wait message, given ID returned by add_bp. */
char *(*wait_msg)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Optional return value from wait-for and run-until commands,
given ID returned by add_bp. */
attr_value_t (*break_data)(conf_object_t *NOTNULL obj, uint64 bp_id);
/* Return possible values for command argument.
Optional unless expanders used. */
attr_value_t (*values)(conf_object_t *NOTNULL obj,
const char *arg, attr_value_t prev_args);
/* Optional trace output function. The default is to log on the
provider with level 1 and group 0. */
void (*trace)(conf_object_t *NOTNULL obj, const char *msg);
};
#define BREAKPOINT_TYPE_PROVIDER_INTERFACE "breakpoint_type_provider"
- Execution Context
- Global Context
- Description
- The save function in this interface is called when a checkpoint
is saved, right before the attributes of an object is read. If defined,
it should prepare the object for checkpointing, saving any state to
path that is not directly included in the attributes.
Default behavior is image to be compressed craff and config to be compressed
too. Errors are signalled through exceptions.
The save_v2 function is same as save but take an extra
parameter with the type of save_flags_t to control format of files in the
checkpoint other than defaults.
The path argument may be the empty string, which indicates
that the checkpoint bundle directory is the same as the current working
directory while the checkpoint is being saved.
The finish function is called after the checkpoint has been
saved, for all objects that save was called for. If
success is nonzero, the checkpoint was saved successfully;
otherwise there was a failure. This permits the object to clean up temporary
data structures and files in either case. In particular, any files written
to path in the save method must be removed in
finish if success is zero.
The function has_persistent_data, if implemented, should return
0 if the object only has volatile attributes, 1 otherwise. This overrides
Sim_Attr_Persistent on individual attributes.
SIM_INTERFACE(checkpoint) {
void (*save)(conf_object_t *obj, const char *NOTNULL path);
void (*finish)(conf_object_t *obj, int success);
int (*has_persistent_data)(conf_object_t *obj);
void (*save_v2)(conf_object_t *obj, const char *NOTNULL path,
save_flags_t flags);
};
#define CHECKPOINT_INTERFACE "checkpoint"
- Execution Context
- Global Context for all methods.
- Description
- The
con_input interface facilitates sending simulated input
to the target system. It is implemented by the text console.
Simulated input is passed through the associated recorder
object and then sent to the serial device connected to the console. The
console will not perform VT100 input handling or BS/DEL conversion.
The input_str method allows input of a NUL-terminated string. The
input_data allows sending a buffer, which can include NUL
characters.
SIM_INTERFACE(con_input) {
void (*input_str)(conf_object_t *NOTNULL obj, const char *str);
void (*input_data)(conf_object_t *NOTNULL obj, bytes_t data);
};
#define CON_INPUT_INTERFACE "con_input"
- Execution Context
- Global Context
- Description
- The
con_input_code interface facilitates sending simulated
key events to the simulation. It is implemented by the graphics console.
Simulated key events are passed through the associated
recorder object and then sent to the keyboard connected to the
console.
The input method sends the key code, either a key
press or a release, depending on the down parameter.
SIM_INTERFACE(con_input_code) {
void (*input)(conf_object_t *NOTNULL obj, sim_key_t code, bool down);
};
#define CON_INPUT_CODE_INTERFACE "con_input_code"
- Execution Context
- Global Context
- Description
Note:
This interface is not supported, and may change in the future.
Get and set current context. The set_current_context function
returns zero if the passed object is not of the context class, otherwise
one is returned.
SIM_INTERFACE(context_handler) {
conf_object_t *(*get_current_context)(conf_object_t *obj);
int (*set_current_context)(conf_object_t *obj, conf_object_t *ctx);
};
#define CONTEXT_HANDLER_INTERFACE "context_handler"
- Execution Context
- Cell Context for all methods.
- Description
-
This interface is used to get notifications from events in the
debugger. Examples of events are when certain functions, addresses or code
lines are hit.
In order to be able to get notifications for symbols, the symbol file
containing the debug information must have been added using the
debug_setup interface or in some other way.
All notifications take callback functions that are called when the debugger
event occurs. The notifications will not stop the simulation, to do so
SIM_break_simulation can be called in the callback.
For all functions that return an attr_value_t, that return value
will consists of a list with two elements. The first element is an error code
of debugger_error_t type (see debug_query
interface documentation for definition). The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
notify_context_creation provides a callback when a new context
that matches the context query query is created or renamed. The
callback will also be triggered when a context is renamed, so if the context
query matches both the name before and after the context was renamed then
there will be two creation callbacks for the same context. When the callback
is triggered because of a rename the updated argument of the
callback will be true, otherwise if it is triggered because a new context
was created the updated argument will be false.
notify_context_destruction provides a callback when a context
that matches the context query query is destroyed.
The callbacks for notify_context_creation and
notify_context_destruction will contain an ID to the context that
was created, updated or destroyed, ctx_id, the tcf_agent object
obj and some custom data.
Note:
The notify_context_creation and
notify_context_destruction callbacks will only trigger for
contexts that have state, this is most commonly the leaf nodes in an OS
Awareness node tree.
notify_location will give a callback when a memory access of type
access is done at the address specified by location,
for contexts matching query. The size argument is used
to specify the width of the symbol provided by location. For
execution notifications a size of 1 is usually used. The maximum
value of size is 0x7fffffff. Notifying on location will only work
for global symbols. For symbols that are not global, no errors will be given,
and no callback will be triggered.
notify_address will provide a callback when an address
is hit with a certain access type for contexts matching
query. The size argument specifies the width of the
breakpoint for the notification, with a maximum value of 0x7fffffff.
The notification can be set to notify on physical breakpoints
instead of virtual, but for that to work a processor or memory space context
must be covered by the query. For process related contexts
physical should be false.
notify_line will provide a callback when a specific
line and column in a specific source file
for a context matching query is executed. The column
argument can be set to 0 to not care about column.
The notification functions notify_location,
notify_address and notify_line will all provide
callbacks on the same format. They will pass the context ID,
ctx_id, for which the access occurred. A processor,
cpu, which did the access is provided. The
instruction_address is the address of the instruction that
performed the access. For execution callbacks the callback will occur before
the instruction has run, but for read or write accesses the callback will
occur after the instruction has run. The data_address will
provide which data address was accesses, for execution accesses this is the
same as instruction_address but for read or write accesses this
is where the actual access was. And size specifies the actual
size of the access that was made to trigger the notification, for execution
this size is 1.
notify_activated and notify_deactivated are used to
notify when a context, that matches the query, gets activated or
deactivated. The callback for this will include which context,
ctx_id, was (de)activated and on what processor, cpu.
For all notifications functions in this interface, on success, the returned
value of a notification function will be a cancel ID which can be used to
cancel the notification.
If several callbacks occur on the same cycle, then the order for which the
callbacks are called is not determined. This means that a
notify_activated callback for one processor can occur before a
notify_deactivated callback on the same processor.
notify_callbacks_done will be called once all other callbacks
that happen because of the same event are done. For example when a move to
and a move from is done in the same step then this callback can be used to
keep grouped notifications together that occurred at the same time. This
will always be called after one or more callbacks have been called.
cancel is used to cancel a notification by providing it with a
cancel ID, cid, that was returned from the notification function.
When this goes well the returned value will be nil.
Errors specific to this function:
- Debugger_Unknown_Id - The cancel ID, cid, is
unknown.
All callbacks except notify_location, notify_address,
and notify_line, with execution access, will occur after the
instruction triggering the callbacks has executed. For the callbacks
specified here, when using execution access, the callback will occur before
the instruction at that location, address or line has executed.
Note:
In order to get contexts for processes, OS Awareness with a properly
configured tracker has to exist. A context will then be created for each OS
Awareness node. Without any OS Awareness tracker enabled for the system,
contexts will only be available for processors and some memory spaces. The
notify_activated and notify_deactivated functions will
only give callbacks when a tracker is used, because processor contexts are
always active. More information about configuring and using OS Awareness and
trackers can be found in the Analyzer User's Guide
Note:
For functions that take query as argument, having this set
to nil will work the same way as for "*". A bad context query will
result in a Debugger_Incorrect_Context_Query error.
SIM_INTERFACE(debug_notification) {
attr_value_t (*notify_context_creation)(
conf_object_t *NOTNULL obj, const char *query,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, bool updated),
cbdata_register_t data);
attr_value_t (*notify_context_destruction)(
conf_object_t *NOTNULL obj, const char *query,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id), cbdata_register_t data);
attr_value_t (*notify_location)(
conf_object_t *NOTNULL obj, const char *query,
const char *NOTNULL location, unsigned size, access_t access,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, conf_object_t *cpu,
uint64 instruction_address, uint64 data_address,
unsigned size), cbdata_register_t data);
attr_value_t (*notify_address)(
conf_object_t *NOTNULL obj, const char *query, uint64 address,
unsigned size, access_t access, bool physical,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, conf_object_t *cpu,
uint64 instruction_address, uint64 data_address,
unsigned size), cbdata_register_t data);
attr_value_t (*notify_line)(
conf_object_t *NOTNULL obj, const char *query,
const char *NOTNULL file, unsigned line, unsigned column,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, conf_object_t *cpu,
uint64 instruction_address, uint64 data_address,
unsigned size), cbdata_register_t data);
attr_value_t (*notify_activated)(
conf_object_t *NOTNULL obj, const char *query,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, conf_object_t *cpu),
cbdata_register_t data);
attr_value_t (*notify_deactivated)(
conf_object_t *NOTNULL obj, const char *query,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
const char *ctx_id, conf_object_t *cpu),
cbdata_register_t data);
attr_value_t (*notify_callbacks_done)(
conf_object_t *NOTNULL obj,
void (*cb)(cbdata_call_t data, conf_object_t *obj),
cbdata_register_t data);
attr_value_t (*cancel)(conf_object_t *NOTNULL obj,
debug_cancel_id_t cid);
};
#define DEBUG_NOTIFICATION_INTERFACE "debug_notification"
- Execution Context
- Global Context for all methods.
- Description
-
This interface provides functions for querying the debugger for contexts and
their information. Functions here will be used to find specific contexts or
to create context-queries, that can be used with other functions in debugger
interfaces.
Most functions in this interface take a Context ID, ctx_id, as
argument. This ID is passed as an argument to most callback functions in the
debug_notification interface and returned by some functions
in this interface.
All functions return an attr_value_t consisting of a list with
two elements. The first element is an error code of
debugger_error_t type. The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
matching_contexts returns a list of context IDs matching the
specified context-query, query. The returned list can be empty if
there are no matching contexts.
get_context_group returns a context ID for the context marked
as the group leader for the specified context, ctx_id. As example
in a Linux tracker the process node will be the group leader for all threads
belonging to that process. A context that lacks a specific group leader will
return itself.
get_context_parent returns an ID to the parent context for the
specified context.
Errors specific to this function:
- Debugger_Not_Supported_For_Context - The context does not have
a parent.
get_context_children returns a list of context IDs for the
children of the specified context. This list can be empty if the context has
no children.
query_for_context_group, query_for_context_id and
query_for_context_tree will return context-queries which can be
used for matching all contexts in a group, the context that matches an ID or
contexts in the tree that starts with the specified context. The latter
context-query will match the context itself plus all its child contexts, the
children of those contexts and so on. The result of these functions should
be used with functions that take a context-query as argument.
context_name
returns the name of the specified context.
Errors specific to this function:
- Debugger_Not_Supported_For_Context - If the he context lacks a
name.
context_id_for_object returns a context ID for the specified
Simics object, ctx_obj, if that has an associated context. In
general, processors and some memory spaces usually have contexts associated
with them.
Errors specific to this function:
- Debugger_No_Context_For_Object - The object does not have any
associated context.
context_has_state returns a boolean that tells whether the
specified context has state or not. That a context has state will mean that
callbacks in the debug_notification will trigger for this
context. The contexts that have state are usually leaf nodes in the OS
Awareness node tree.
object_for_context is used to get a Simics object that matches
the context for ctx_id, if such an object exists.
Errors specific to this function:
- Debugger_Missing_Object - The context does not match a Simics
object.
get_active_processor is used check if a context is active and in
that case return the Simics processor object that the node is active on.
Errors specific to this function:
- Debugger_Context_Is_Not_Active - Context is not active.
Note:
For functions that take query as argument, having this set
to nil will work the same way as for "*". A bad context query will
result in a Debugger_Incorrect_Context_Query error.
SIM_INTERFACE(debug_query) {
attr_value_t (*matching_contexts)(conf_object_t *NOTNULL obj,
const char *query);
attr_value_t (*get_context_group)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*get_context_parent)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*get_context_children)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*query_for_context_group)(conf_object_t *NOTNULL obj,
const char *ctx_id);
attr_value_t (*query_for_context_id)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*query_for_context_tree)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*context_name)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*context_id_for_object)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL ctx_obj);
attr_value_t (*object_for_context)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*context_has_state)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*get_active_processor)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
};
#define DEBUG_QUERY_INTERFACE "debug_query"
typedef enum {
Debugger_No_Error = 0,
Debugger_Not_Allowed_In_Execution_Context,
Debugger_Unknown_Context,
Debugger_Not_Supported_For_Context,
Debugger_Context_Does_Not_Have_State,
Debugger_Context_Is_Not_Active,
Debugger_Lookup_Failure,
Debugger_Failed_To_Get_Stack_Frame,
Debugger_Failed_To_Get_PC,
Debugger_Failed_To_Read,
Debugger_Failed_To_Write,
Debugger_Frame_Outside_Of_Known_Stack,
Debugger_Failed_To_Evaluate_Expression,
Debugger_Incorrect_Type,
Debugger_Incorrect_Size,
Debugger_Incorrect_Context_Query,
Debugger_Unknown_Id,
Debugger_Source_Not_Found,
Debugger_File_Not_Found,
Debugger_Unrecognized_File_Format,
Debugger_Unsupported_For_File_Format,
Debugger_Failed_To_Open_File,
Debugger_Not_Relocatable,
Debugger_Segment_Info_Missing,
Debugger_Section_Info_Missing,
Debugger_Segment_Not_Found,
Debugger_Section_Not_Found,
Debugger_Already_Running,
Debugger_Failed_To_Continue,
Debugger_No_Context_For_Object,
Debugger_Invalid_Path,
Debugger_Missing_Object,
Debugger_Unexpected_Error,
Debugger_Step_Interrupted,
} debugger_error_t;
- Execution Context
- Global Context for all methods.
- Description
-
Functions in the debug_setup interfaces are used to provide
the debugger with symbol files and paths. There are also functions for
listing what symbol files and paths have been added.
For all functions that return an attr_value_t, that return value
will consists of a list with two elements. The first element is an error code
of debugger_error_t type (see debug_query
interface documentation for definition). The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
Upon success, all functions for adding symbols will return an id
that can be used with remove_symbol_file.
add_symbol_file adds a symbol file, symbol_file, used
for debugging contexts that match the context-query query. The
address argument specifies the address that the file should be
mapped to. If absolute_address is set then the given
address will be the absolute address of the first relocatable
segment and other segments will be added with their given offsets to that
segment.
Errors specific to this function:
- Debugger_Failed_To_Open_File - File cannot be opened.
- Debugger_Unrecognized_File_Format - The file format is not
recognized.
- Debugger_Segment_Info_Missing - If an ELF file is being added,
but no valid segments can be found.
add_symbol_segment adds symbols from the specified
segment of an ELF symbol file. Other arguments are the same as
for add_symbol_file. The address of the segment is specified with
the address argument. If absolute_address is set this
address will be an absolute address otherwise it will be an
offset to the address found in the symbol file for that segment.
Errors specific to this function:
- Debugger_Segment_Not_Found - Segment not found when adding a
segment.
- Debugger_Segment_Info_Missing - Segment information is missing
or incomplete.
- Debugger_Not_Relocatable - The segment is not relocatable.
- Debugger_Unsupported_For_File_Format - File format is not
ELF.
add_symbol_section adds symbols from the specified
section of an ELF symbol file. Other arguments are the same as
for add_symbol_file. The address of the section is specified with
the address argument. If absolute_address is set this
address will be an absolute address otherwise it will be an
offset to the address found in the symbol file for that section.
Errors specific to this function:
- Debugger_Section_Not_Found - Section not found when adding a
section.
- Debugger_Section_Info_Missing - Section information is missing
or incomplete.
- Debugger_Not_Relocatable - The section is not relocatable.
- Debugger_Unsupported_For_File_Format - File format is not
ELF.
Note:
Adding the same symbol file, section or segment more than once might
result in unexpected behavior and is not supported.
remove_symbol_file removes the debugger's knowledge of symbols
that was added with any of the functions for adding symbols. The
id argument is the id returned from the add function.
Errors specific to this function:
- Debugger_Unknown_Id - The id is unknown.
clear_symbol_files removes the debugger's knowledge about all
symbol files added by add_symbol_file.
symbol_files
lists all added symbol files. A dictionary, with id as key will be
returned. An id is always bound to one query and one symbol file, but it can
contain several memory maps. The listed id is the argument passed
to remove_symbol_file. The dictionary values have the following
format:
- query
(string) - The context query the symbol is
valid for.
- relocation
(uint64) - The relocation address
provided when the symbol file was added.
- symbol-file
(string) - The file containing the
symbol information.
- memory-maps
([<dict>, ...]) - A list of
memory maps that are added togheter as the same id, see format
below:
The dictionary describing a memory map has the following format:
- address
(uint64) - The address of the section in
memory.
- size
(uint64) - The section size in memory.
- flags
(uint64) - Format specific flags describing
the section.
- section
(string) - The name of the section.
- file-offset
(uint64) - Offset in symbol file for
the section.
- file-size
(uint64) - Size of the section in the
symbol file.
symbol_files_for_ctx is the same as symbol_files
except that it only returns symbol files that are valid for the given
context id, ctx_id.
list_all_mappings lists all symbol mappings for a certain context
ctx_id. This will be all mappings from symbol files added by
users plus any symbol mappings added elsewhere, from trackers for example.
The returned value is a dictionary on the following format:
- filename
(string) - The file backing the memory
map.
- query
(string) - The query the map is valid
for.
- address
(uint64) - The map's address in context
memory.
- size
(uint64) - The size of the map in
memory.
- flags
(uint64) - Read, write, and execute flags,
bit 0 is set if readable, bit 1 if writeable and bit 2 if executable. If this
value is 0 this is the same as if all flags are set.
- section-name
(string) - The section name, or
NIL.
- file-offset
(int64) - Offset into the backing
file.
- file-size
(uint64) - Size of the map in the
backing file.
- relocation
(uint64) - The offset from the address
in the symbol file to where the mappings is actually loaded in memory. This
is not always present in the dictionary.
Some other internal entries could possibly also be present in the
dictionary.
add_path_map_entry adds a path math entry that maps a source
file from the source in the symbol file to the actual
destination, dest, where it is located on disk. The
query argument specifies for which context-queries the mapping
should apply. The returned id can be used with
remove_path_map_entry to remove the added path map. The source
path may not be empty or be just "." or "./".
Errors specific to this function:
- Debugger_Invalid_Path - The source path is not valid.
remove_path_map_entry removes an entry that was added with
add_path_map_entry. The id is the value returned from
the add function.
Errors specific to this function:
- Debugger_Unknown_Id - The provided id is
unknown.
clear_path_map_entries removes all knowledge about all path map
entries added with add_path_map_entry.
path_map_entries lists all path map entries that have been added
with add_path_map_entry, that matches the given context id. If
the context id is nil, then all path maps will be listed. The format of the
entries in the returned list are dictionaries, with an id of type
debug_setup_id_t as key:
- query
(string) - The context query the path map
is valid for.
- source
(string) - The source to translate
from.
- destination
(string) - The destination to
translate to.
path_map_entries_for_ctx is the same as
path_map_entries except that it only lists path maps that are
valid for the given context id, ctx_id.
apply_path_map applies any added path map to a file path,
filename, for a given context with ID ctx_id. The path
with the path map applied will be returned. The path map will only apply if
the destination file exists and if the path given in filename
does not, otherwise the provided file will be returned. The returned path
will always contain forward slashes as path separator, regardless of what
the host system uses, or if any path map was applied or not.
Note:
For functions that take query as argument, having this set
to nil will work the same way as for "*". A bad context query will
result in a Debugger_Incorrect_Context_Query error.
typedef int64 debug_setup_id_t;
SIM_INTERFACE(debug_setup) {
attr_value_t (*add_symbol_file)(conf_object_t *NOTNULL obj,
const char *query,
const char *NOTNULL symbol_file,
uint64 address, bool absolute_address);
attr_value_t (*add_symbol_segment)(conf_object_t *NOTNULL obj,
const char *query,
const char *NOTNULL symbol_file,
unsigned segment, uint64 address,
bool absolute_address);
attr_value_t (*add_symbol_section)(conf_object_t *NOTNULL obj,
const char *query,
const char *NOTNULL symbol_file,
const char *NOTNULL section,
uint64 address,
bool absolute_address);
attr_value_t (*remove_symbol_file)(conf_object_t *NOTNULL obj,
debug_setup_id_t id);
void (*clear_symbol_files)(conf_object_t *NOTNULL obj);
attr_value_t (*symbol_files)(conf_object_t *NOTNULL obj);
attr_value_t (*symbol_files_for_ctx)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*list_all_mappings)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*add_path_map_entry)(conf_object_t *NOTNULL obj,
const char *query,
const char *NOTNULL source,
const char *NOTNULL dest);
attr_value_t (*remove_path_map_entry)(conf_object_t *NOTNULL obj,
debug_setup_id_t id);
void (*clear_path_map_entries)(conf_object_t *NOTNULL obj);
attr_value_t (*path_map_entries)(conf_object_t *NOTNULL obj);
attr_value_t (*path_map_entries_for_ctx)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*apply_path_map)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
const char *NOTNULL filename);
};
#define DEBUG_SETUP_INTERFACE "debug_setup"
- Execution Context
- Global Context for all methods.
- Description
-
This interface is used to perform stepping with the debugger, on a specified
debug context.
For all functions that return an attr_value_t, that return value
will consists of a list with two elements. The first element is an error code
of debugger_error_t type (see debug_query
interface documentation for definition). The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
instruction_into and instruction_over runs one step
forward for the specified context. instruction_into will enter
subroutine calls while instruction_over will step over subroutine
calls.
into and over will run one
source line forward for the specified context. into will enter
function calls while over will skip over functions.
out will run until the currently active function returns.
All function take a context ID, ctx_id, as argument. This context
ID is passed as an argument to callbacks for functions in the
debug_notification interface. The context, that is passed to
functions in this interface, has to have state (see
context_has_state in the debug_query interface)
otherwise a Debugger_Context_Does_Not_Have_State error will be
returned.
Calling functions in this interface can only be done when simulation is
stopped, otherwise a Debugger_Already_Running error will be
returned.
For all functions in this interface, if another stop reason occurs before a
function finishes the simulation will stop at that point instead.
Stepping for a context that is not active will run until that context
becomes active and then take the step.
SIM_INTERFACE(debug_step) {
attr_value_t (*instruction_into)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*into)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*instruction_over)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*over)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*out)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*reverse_instruction_into)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*reverse_into)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*reverse_instruction_over)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*reverse_over)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*reverse_out)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
};
#define DEBUG_STEP_INTERFACE "debug_step"
- Execution Context
- Global Context for all methods.
- Description
-
This interface contains functions for retrieving various symbol information
for a debug context, ctx_id. There are also a few functions for
updating symbol information.
Prior to using functions in this interface, symbol file(s) containing symbol
information should have been added using the debug_setup
interface, for a context-query that matches the context ID provided to the
function here. Symbol files can also be added in other ways such as from a
tracker or from Eclipse.
Some functions, that do read values or stack, can also be used directly with
symbol files opened with the debug_symbol_file interface.
All functions in this interface take a context ID ctx_id as
argument. This is the ID passed as an argument to
debug_notification callbacks or returned from some
debug_query interface functions.
For all functions that return an attr_value_t, that return value
will consists of a list with two elements. The first element is an error code
of debugger_error_t type (see debug_query
interface documentation for definition). The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
All addresses used in this interface are virtual addresses.
For functions that take frame as argument, providing
frame = -1 means no frame. This can be used when finding symbols
for functions or global variables. When using other frame than -1
the context has to be active, otherwise no frame will exists and a
Debugger_Context_Is_Not_Active error will be returned. If the
specified frame cannot be found, then error code
Debugger_Frame_Outside_Of_Known_Stack will be returned.
Functions that handle stack can only be used with an active context,
otherwise error code Debugger_Context_Is_Not_Active or
Debugger_Context_Does_Not_Have_State will be returned depending
on if the context has state or not.
address_source will provide callbacks, cb, with source
information for the range specified by address and
size. The range must not wrap around the 64-bit limit. Source
information will be provided as code areas, which is the source information
for a range of continuous addresses matching the same file and line. User
data can be passed to the callback using the data argument and
will be passed as the first argument in the callback. Each code area
matching the range will get a callback with information about the code area
in the code_area argument, which is a dictionary with the
following elements:
- filename
(string) - File name of the source file
where the specified address is found.
- start-line, end-line
(int64) -
Starting and ending lines in the source file for the address.
end-line is inclusive so if the address just matches
one source line start-line and end-line will be the
same.
- start-column, end-column
(int64) -
Starting and ending columns on the line for address. If column
information is not available in debug information the value will be 0.
end-column is inclusive so the column is included for
address.
- start-address, end-address
(uint64) -
Starting and ending addresses that correspond to the returned line and
column information. end-address is inclusive so this matches the
last byte of the last instruction of this code area. If the code area is
empty then, then end-address will not be present. This can happen
when asking for a line prior to the first executable line.
Errors specific to this function:
- Debugger_Source_Not_Found - There are no matching code
areas.
- Debugger_Incorrect_Size - Incorrect size
provided. The size cannot be zero and it cannot make the end address exceed
64 bits.
- Debugger_Lookup_Failure Address lookup failure. Can occur if
the address is not in the debug information or the lookup failed for some
other reason. The error message explains more what went wrong.
source_address will provide callbacks, with source information
for the line specified by filename, line and
column. The column argument will only be useful for
binaries with column information in the debug information.
One call to this function will provide as many callbacks as there are code
areas matching that source information. The code_area provided to
the callback is a dictionary with the same format as for the callback from
address_source.
Errors specific to this function:
- Debugger_File_Not_Found - There is no matching source file,
filename, in the debug information.
- Debugger_Source_Not_Found - The line or
column is not found in the debug information.
- Debug_Lookup_Failure - Some problem with the lookup other than
that file, line or column was not found. Error described in error
message.
For binaries without column information, a line is executable if
the start-line in the callback matches the asked line.
For binaries with column information one can say that the line is
executable if any code area can be found with start-line matching
the asked line. When asking for a line and column and
the start-line matches a previous line, but the
end-line matches the asked line, then one should ask for the
column just after end-column to see if the
start-line of that code area matches the asked line and if it
does then the asked line is considered executable.
stack_depth returns the current stack depth.
Errors specific to this function:
- Debugger_Failed_To_Get_Stack_Frame - Failed to get stack
frames.
stack_frames returns a list of dictionaries with information
about each frame. The executing frame is at position zero in the list. The
elements of the stack frame dictionary are:
- address
(uint64) - For the executing frame this
is the address of the program counter, for all other frames this is the
address that the function will return to.
- source-file
(string) - The source file for the
frame. Can be nil if no matching file is found.
- source-line
(uint64) - The source line in the
file for the frame. Will be nil if source-file is nil.
- function-name
(string) - The function that is
executing in the frame. Can be nil if no function is found.
Errors specific to this function:
Debugger_Failed_To_Get_Stack_Frame - If there are problems
getting stack depth or getting frame info.
Debugger_Failed_To_Read - If a register cannot be read for
some frame.
Debugger_Failed_To_Get_PC - If the program counter
definition cannot be found for the context.
local_variables returns a list of names for local variables in
the specified frame.
local_arguments returns a list of names of arguments to the
function in the specified frame.
Both local_variables and local_arguments can return an
empty list if no local variables or arguments are found. If something goes
wrong while looking up variables or arguments they will return a
Debugger_Lookup_Failure with more information in the error
string.
expression_value returns the value of an expression,
expr, in the specified frame. See note about
address_scope further down. The returned value will be of integer
type if the expression is of integer type, including if it is an
address. Floating-point types will be returned as such. If the expression is
a structure, union, class or an array a list containing the elements of that
type will be returned.
Errors specific to this function:
- Debugger_Failed_To_Evaluate_Expression - The expression could
not be evaluated, more information in the error message.
expression_type returns the type of an expression,
expr, in the specified frame. See note about
address_scope further down. For most types the return value will
be a string containing the type, for example 'int',
'double', 'char' or 'my_own_type_t.
For pointers the return value will be a list with '*' as the
first argument followed by the type of the pointer, for example ['*',
'void'] or ['*', ['*', 'char']].
For qualifiers ('const', 'volatile' or 'restrict') these will be added as an
element to the list, such as ['const', 'char'] or ['volatile',
['*', 'int']].
Functions are returned with a '()' string as the first element of
a list, followed by the return type, followed by a list of arguments to the
function. Example: ['*', ['()', 'int', ['int', ['*', ['*',
'char']]]]] for a function of type int (*)(int, char **).
A struct or union will return a string
'struct', followed by the struct name, if available, then
followed by a list of lists containing the struct member type and name
['struct', 'my_struct', [['int', 'i'], ['float', 'f']]] as
example. If the struct has been assigned a type with typedef then
the output will be 'typedef' followed by the name of the
assigned type, then the list of members. An example: ['typedef',
'mytype_t', [['int', 'age'], [['*', 'char'], 'name']]]. For unions the
string 'struct' will be replace with the string
'union'.
A bit field will return a list containing a string
'bitfield' followed by the basic type of the bit field,
followed by the size of the bit field. An example: ['bitfield', 'int',
5] for a variable declared as int var:5.
For array types expression_type will return a list, ['[]',
array size, array type], where the array type is of the same format as
other types for this function. An example: ['[]', 10, 'char'] for a
variable declared as char x[10];
Enumerations will be displayed as a list: ['enum', enum name,
members]. The enum name is the declared name for the
enumeration, if no such name exists this list field will be left out. The
members field will contain a list of [name, value] lists for all
the members of the enumeration. An example: ['enum, 'my_enum',
[['My_Val_0', 0], [My_Val_1, 1]]].
Note:
There are some limitations for symbols from PE files that can depend
on the version of
dbghelp.dll.
- Type defined types might get shown as the
base type instead of the
'typedef' type.
- Variables with a
const qualifier might be shown without
that qualifier.
- Members of anonymous structures within a base structure are shown as
being part of the base structure.
Errors specific to this function:
- Debugger_Failed_To_Evaluate_Expression - Could not evaluate the
expression, more information in the error message.
type_info
returns information about what base type a type that has been added with
typedef has. See note about address_scope further
down. The returned value will be a list on the same format as for
expression_value.
Errors specific to this function:
- Debugger_Incorrect_Type - If the type asked for is
not a valid type.
- Debugger_Lookup_Failure - Finding the symbol failed or the type
of symbol cannot be retrieved. More information in the error string.
type_to_string converts the return value from
expression_type or type_info to a readable string and
returns that.
Errors specific to this function:
- Debugger_Incorrect_Type - The format of type is
incorrect.
symbol_address takes a frame and a symbol
as arguments and returns a list of addresses that matches that symbol name.
If a single symbol address is wanted near a provided instruction pointer
then the expression_value function can be used with the
expression set as &<symbol>.
Errors specific to this function:
- Debugger_Lookup_Failure - The address for the symbol cannot be
found. This can be because the symbol was not found or if evaluation
failed. More information will be found in the error message.
address_string returns the string at the specified
address. The maxlen is used to specify the maximum
length of a string to read from memory. If the string at address
exceeds the given length the truncated string will be returned, and a
terminating null character will be added if needed. A maxlen
value of zero means no maximum string length.
Errors specific to this function:
- Debugger_Failed_To_Read - Failed to read memory at
address.
lvalue_write writes a value to a symbol in
the specified frame. The value can be of
integer types or floating-point type if the type
of the lvalue is of floating-point type. The returned value
when the write goes well is nil.
Errors specific to this function:
- Debugger_Incorrect_Type - The type of value is
incorrect.
- Debugger_Failed_To_Evaluate_Expression - The provided
symbol could not be found or evaluated as an expression.
- Debugger_Failed_To_Write - Failed to write to
symbol.
address_write writes an attr_value_t of
data type, value, to the specified
address. Returned value is nil when the write goes well.
Errors specific to this function:
- Debugger_Incorrect_Type - The type of value is
incorrect.
- Debugger_Failed_To_Write - The memory at address
cannot be written to.
address_read reads size number of bytes from the
specified address. The read data is returned as an
attr_value_t of data type.
Errors specific to this function:
- Debugger_Failed_To_Read - The address cannot be
read.
struct_members returns a list of all members of a struct,
struct_name. See note about address_scope further
down. Each element of the returned list will be on the format [name,
offset, size]. The size and offset elements are
usually integers representing the offset into the struct and the size of the
variable. If the struct member is a bit field then size will be a
list on the format [base size, bits], where base size is
the number of bytes for the declared base type and bits is the
number of bits the declared for the bit field. For bit fields
offset will be a list on the format [byte offset, bit
offset], where byte offset is the offset of in bytes into
the structure and bit offset is the offset in bits from the byte
offset to where the bit field starts. If some member, size or offset cannot
be retrieved then that element will be set as nil. This can for example
occur if a struct member is an anonymous struct or union.
Errors specific to this function:
- Debugger_Incorrect_Type - The provided symbol,
struct_name, is not a structure.
- Debugger_Lookup_Failure - Failed to find the symbol or its
type.
struct_field returns a list of [offset, size] for a
field of a given structure, struct_name. The
offset and size are usually integers, but if the
field is a bit field then the returned size and
offset will be on the same format as for
struct_members. See note about address_scope below.
This function can return the same error codes, for the same reasons, as
the struct_members function.
The address_scope argument that is provided for several functions
can be used to specify where to find the symbol if there are several matches
for the provided symbol name or expression. This argument is used to provide
an address that tells the function in which scope to search for the symbol.
This is only taken in account when no frame (-1) is given as frame. This
address can be an address that belongs to a loaded symbol file to prioritize
finding symbols from that symbol file.
list_functions and list_global_variables lists all
function or global variable symbols that are known for the given
context. The symbols shown are the ones that have been added with the
add_symbol_file function of the debug_setup
interface. The returned format is a list of dictionaries with the dictionary
elements on the format:
- symbol
(string) - The name of the symbol.
- address
(uint64) - The address in memory of the
symbol.
- size
(uint64) - The size of the symbol in
memory.
list_source_files lists all source files provided by the debug
information of the symbol files for the given context.
SIM_INTERFACE(debug_symbol) {
attr_value_t (*address_source)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address, uint64 size,
void (*cb)(cbdata_call_t data,
attr_value_t code_area),
cbdata_register_t data);
attr_value_t (*source_address)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
const char *NOTNULL filename,
uint32 line, uint32 column,
void (*cb)(cbdata_call_t data,
attr_value_t code_area),
cbdata_register_t data);
attr_value_t (*address_symbol)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address);
attr_value_t (*stack_depth)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*stack_frames)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, int min,
int max);
attr_value_t (*local_variables)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, int frame);
attr_value_t (*local_arguments)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, int frame);
attr_value_t (*expression_value)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
int32 frame, uint64 address_scope,
const char *NOTNULL expr);
attr_value_t (*expression_type)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
int32 frame, uint64 address_scope,
const char *NOTNULL expr);
attr_value_t (*type_info)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address_scope,
const char *NOTNULL type);
attr_value_t (*type_to_string)(conf_object_t *NOTNULL obj,
attr_value_t type);
attr_value_t (*symbol_address)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, int32 frame,
const char *NOTNULL symbol);
attr_value_t (*address_string)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address, int maxlen);
attr_value_t (*lvalue_write)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, int32 frame,
const char *NOTNULL symbol,
attr_value_t value);
attr_value_t (*address_write)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address, attr_value_t value);
attr_value_t (*address_read)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id, uint64 address,
unsigned size);
attr_value_t (*struct_members)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address_scope,
const char *NOTNULL struct_name);
attr_value_t (*struct_field)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id,
uint64 address_scope,
const char *NOTNULL struct_name,
const char *NOTNULL field);
attr_value_t (*list_functions)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*list_global_variables)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*list_source_files)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
};
#define DEBUG_SYMBOL_INTERFACE "debug_symbol"
- Execution Context
- Global Context for all methods.
- Description
-
This interface has functions for operating directly on symbol files, instead
of using contexts related to processes or processors. Files opened with this
interface can be used together with functions in the
debug_symbol interface that do not require any stack or
location information. There are also functions for getting information about
the symbol file, such as listing sections or segments.
For all functions that return an attr_value_t, that return value
will consists of a list with two elements. The first element is an error code
of debugger_error_t type (see debug_query
interface documentation for definition). The second element depends on the
first. If the first element is Debugger_No_Error, meaning that
the function went well, then the second element will contain the expected
return value that is specified per function below. If the first element is
another error code, then the second element will be a string describing the
error that occurred.
All function but open_symbol_file has to act on a context id,
ctx_id, that has been returned by open_symbol_file,
otherwise a Debugger_Not_Supported_For_Context error will be
returned.
open_symbol_file opens a symbol file, specified by the
filename argument, as a context so that this can be used with
many of the symbol lookup functions in the debug_symbol
interface. The address is the offset for which to load the symbol
file if absolute_address is false. If absolute_address
is true, address will instead be the absolute address to load the
symbol file on. The returned value will be a context id that can be used as
argument where a ctx_id is required. Functions that take a stack
frame can only be accessed with no stack (value -1) when used with a symbol
file context. Files that read or write memory cannot be used.
Errors specific to this function:
- Debugger_Unrecognized_File_Format - The file format of the file
is not ELF or PE.
- Debugger_Unsupported_For_File_Format - If the symbol file is of
PE format then the address cannot be 0 as the internal handling
does not support that.
open_symbol_section opens a symbol file in the same way as
open_symbol_file, but only adds symbols from the specified
section. Other arguments and return value are as for
open_symbol_file. The symbol section is closed using
close_symbol_file. This method can only handle ELF binaries. In
addition to errors reported by open_symbol_file this function can
report Debugger_Section_Not_Found if the section cannot
be found.
close_symbol_file closes a symbol file that was opened with
open_symbol_file. The ctx_id should be the context id
returned from that function. The returned value will just be nil when this
goes well.
symbol_file_info returns a list containing a string describing
the file format and a dictionary with information about the file. The
ctx_id argument should be the context id returned from the
open_symbol_file. The returned information depends on which file
format the file has. For ELF files the string is "ELF" and the returned
entries are:
- big-endian
(uint64) - Set to 1 if the binary is
built for big endian, otherwise 0.
- elf-machine-id
(uint64) - The ELF machine
identifier number (e_machine) in the ELF header. This is usually
prefixed with EM_ in headers. For example EM_386 = 3 and
EM_X86_64 = 62.
For PE files the string is "PE" and the returned entries are:
- image-size
(uint64) - The size of the PE image in
memory.
- image-base
(uint64) - The recommended address for
the image to be loaded at.
Both PE and ELF files will include the following entries:
- entry-address
(uint64) - The program counter for
where the execution in the file should begin.
- file-size
(uint64) - The file size in bytes.
- machine
(string) - The type of machine the binary
is built for, for example "X86-64", "X86" or "ARM".
- address-width
(uint64) - The address width the
file was built for, should be 32 or 64, but 0 specifies unknown.
sections_info provides information about the sections in the
symbol file. The ctx_id must be an id for a file opened with
open_symbol_file or open_symbol_section in this
interface. The returned result is a list with two elements, the first a
string specifying the format of the file, "ELF" or "PE", and the second a
list of dictionaries where each dictionary contains information about the
section. If an id from open_symbol_section is used then only the
opened section will be included in the list. The following keys exist in the
dictionary:
- name
(string) - The name of the section. This key
could potentially be left out if the sections does not have a name.
- address
(uint64) - The address in memory.
- offset
(uint64) - The offset in the file.
- size
(uint64) - The section size in the file
image.
- executable
(boolean) - A boolean telling if the
section is executable or not.
- index
(uint64) - Only available for ELF
files. The section index.
- flags
(uint64) - Only available for ELF
files. The value of sh_flags in the ELF section header.
- characteristics
(uint64) - Only available for PE
files. The value of Characteristics in the PE section
IMAGE_SECTION_HEADER structure.
segments_info provides information about the segments in the
symbol file, this is only supported for ELF. The ctx_id must be
an id for a file opened with open_symbol_file in this
interface. The returned result is a list where each entry represent a
segment. Each entry is in turn a dictionary with the following keys:
- address
(uint64) - Virtual address in
memory.
- size
(uint64) - The segment size in
memory, specified in bytes.
- offset
(uint64) - Offset into the segment
location on file.
- flags
(uint64) - Flags, depending on segment
type, corresponds to p_flags in the ELF program header table.
- type
(uint64) - The type of the segment,
corresponds to p_type in the ELF program header table.
- physical-address
(uint64) - Physical address in
memory, if applicable.
- file-size
(uint64) - The size of the segment in
file.
- sections
([string,...]) - A list of sections
included in the segment, presented by the section name.
SIM_INTERFACE(debug_symbol_file) {
attr_value_t (*open_symbol_file)(conf_object_t *NOTNULL obj,
const char *NOTNULL filename,
uint64 address, bool absolute_address);
attr_value_t (*close_symbol_file)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*symbol_file_info)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*sections_info)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*segments_info)(conf_object_t *NOTNULL obj,
const char *NOTNULL ctx_id);
attr_value_t (*open_symbol_section)(conf_object_t *NOTNULL obj,
const char *NOTNULL filename,
const char *NOTNULL section,
uint64 address,
bool absolute_address);
};
#define DEBUG_SYMBOL_FILE_INTERFACE "debug_symbol_file"
- Execution Context
- Global Context for all methods.
- Description
- The disassemble interface can be used to disassemble code from a
buffer in memory. It is typically used to disassemble code for the
host architecture independent of the target architecture
implemented in a particular version of Simics.
SIM_INTERFACE(disassemble) {
/* Set up new block to disassemble */
void (*init)(conf_object_t *obj, uint8 *buff,
int buff_len, uint64 address);
/* Disassemble the next instruction */
disasm_instr_t (*next)(conf_object_t *obj);
};
#define DISASSEMBLE_INTERFACE "disassemble"
init() is used to initialize a new disassemble
session. You should provide a buffer in buff, the buffer
length in bytes in buff_len and the base address for this
chunk in address. The address parameter is used
to calculate program counter relative offsets (for branches and
other program counter relative constructs).
typedef struct {
int start; /* Where the instructions starts in the buffer */
int length; /* Length of instruction, or -1 if incomplete */
char *string; /* Disassembly string (allocated) */
} disasm_instr_t;
next() returns a structure with the next disassembled
instruction. Repeated use of next() will disassemble
additional instructions.
- Execution Context
- Cell Context for all methods.
- Description
- This interface is intended to be implemented by a follower agent to accept
data from the follower.
The accept method delivers a deterministic message from the
follower to the agent.
The accept_async method delivers an asynchronous
(non-deterministic) message from the follower to the agent.
SIM_INTERFACE(follower_agent) {
void (*accept)(conf_object_t *obj, bytes_t msg);
void (*accept_async)(conf_object_t *obj, bytes_t msg);
};
#define FOLLOWER_AGENT_INTERFACE "follower_agent"
- Execution Context
- Cell Context for all methods.
- Description
- The
gfx_break interface facilitates management of graphical
breakpoints. It is implemented by the graphics console.
A graphical breakpoint is defined by an image patch and a location on the
screen, stored in a file using a bespoke format. Such a file can be created
using the store method.
A breakpoint can then be activated using the add method.
The console will check if the breakpoint matches the screen data
every interval seconds in virtual time, using the clock that
is associated to the console. Graphical breakpoints
are therefore deterministic.
Note that the coordinates of the image patch is stored in the graphical
breakpoint, and the breakpoint will only match on those coordinates.
The store method stores the specified rectangle on the screen in
the given file. It returns false if the rectangle is invalid or on
I/O error.
The add method activates a previously stored graphical
breakpoint, and returns a breakpoint ID, which is also passed to
cb when the breakpoint matches. The parameter name is
the breakpoint name that will appear in log messages. If name is
NULL then the file name is used. If oneshot is true, the
breakpoint will be removed automatically after the first match. The
interval parameter specifies how often the breakpoint is tested,
in seconds of simulated time. If cb is not NULL, then
this function will be called on breakpoint match, otherwise a match stops
the simulation. If the breakpoint file cannot be loaded, the method returns
-1.
The remove method deactivates a previously activated breakpoint.
The match method determines if a stored graphical breakpoint
matches the current screen. It returns -1 if the breakpoint could not be
loaded, 1 on match or 0 otherwise.
The info method returns the header of a stored graphical
breakpoint, including the image patch coordinates. If the given file cannot
be read or has invalid data, then a header containing all 0's is returned.
The export_png method converts the image data in a graphical
breakpoint file to PNG format.
The add_bytes method behaves as add but reads the
breakpoint data from memory instead of a file.
SIM_INTERFACE(gfx_break) {
bool (*store)(conf_object_t *NOTNULL obj,
const char *file,
int minx, int miny, int maxx, int maxy);
int64 (*add)(conf_object_t *NOTNULL obj,
const char *file, const char *name,
bool oneshot, double interval,
gfx_break_cb_t cb, lang_void *arg);
bool (*remove)(conf_object_t *NOTNULL obj, int64 break_id);
int (*match)(conf_object_t *NOTNULL obj, const char *file);
gbp_header_t (*info)(conf_object_t *NOTNULL obj, const char *file);
bool (*export_png)(conf_object_t *NOTNULL obj, const char *file,
const char *png_file);
int64 (*add_bytes)(conf_object_t *NOTNULL obj,
bytes_t data, const char *name,
bool oneshot, double interval,
gfx_break_cb_t cb, lang_void *arg);
};
#define GFX_BREAK_INTERFACE "gfx_break"
- Execution Context
- Global Context
for all methods
- Description
- The
host_serial interface is used to control the text
console host serial connection.
The setup method will set up a host serial connection on a pty
(Linux) or COM port (Windows). On Linux, name can be
NULL in which case a new pty is opened.
The name method returns the name of any opened pty or COM port,
or NULL.
The shutdown closes any opened pty or COM port.
SIM_INTERFACE(host_serial) {
bool (*setup)(conf_object_t *NOTNULL obj, const char *name);
const char *(*name)(conf_object_t *NOTNULL obj);
void (*shutdown)(conf_object_t *NOTNULL obj);
};
#define HOST_SERIAL_INTERFACE "host_serial"
- Execution Context
- Global Context
for all methods
- Description
- This interface is intended to be implemented by instrumentation connections
using the instrumentation framework. This interface is used to request that
instrumentation should be temporarily disabled and then re-enabled. That is,
the connection should not collect any data when it is being disabled. How
this is achieved is up to the tool, it could tell the provider to stop
sending information, or simply throw away anything it sends.
This interface can be used with high frequency while simulation is running,
so it should be implemented with performance in mind.
SIM_INTERFACE(instrumentation_connection) {
void (*enable)(conf_object_t *obj);
void (*disable)(conf_object_t *obj);
};
#define INSTRUMENTATION_CONNECTION_INTERFACE "instrumentation_connection"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is intended to be implemented by instrumentation filters.
Instrumentation filters should enable the associated slaves, which
themselves are associated with instrumentation connections.
The set_source_id method supplies the filter with an unique
source number for the filter. This function should only be called once,
the filter needs to store this number so it can be used when
calling the instrumentation_filter_slave interface
methods.
The add_slave method informs the filter that it should enable or
disable this slave too. The slave object should implement the
instrumentation_filter_slave interface which should be
used. The provider_obj parameter is the provider object that
is located behind the slave and its connection. Depending on how the filter
works, it may or may not make use of this parameter. For example, the
process-filter might detect that the filtered process is now running on a
particular processor, then it can enable this particular connection only,
given that it can match the provider_obj with the processor
currently running the tracked process.
The remove_slave method removes a slave from the filter, so
it should not call it anymore.
The short_filter_config method should return a short textual
description on how the filter is currently set up. This information
is used in various print commands.
SIM_INTERFACE(instrumentation_filter_master) {
void (*set_source_id)(conf_object_t *obj, unsigned source_id);
bool (*add_slave)(conf_object_t *obj, conf_object_t *slave,
conf_object_t *provider_obj);
void (*remove_slave)(conf_object_t *obj, conf_object_t *slave,
conf_object_t *provider_obj);
char *(*short_filter_config)(conf_object_t *obj);
};
#define INSTRUMENTATION_FILTER_MASTER_INTERFACE "instrumentation_filter_master"
- Execution Context
- Global Context for all methods.
- Description
- This interface is implemented by the
instrumentation_filter_aggregator class objects,
here referred to as "aggregator". The interface should be
called by instrumentation filters to enable or disable a connection.
The aggregator object is located between the filters and the connection,
keeping the connections unaware of multiple filters that might
be disabling them.
The disable method tells the aggregator that the unique
source_id currently wants to disable the connection.
As long as there is one source_id that is disabled,
the connection is disabled. Only when all sources are enabled
the connection is enabled.
Similarly, the enable enables the connection. That
is, the filter is now in a state when it thinks the connection
should be enabled.
SIM_INTERFACE(instrumentation_filter_slave) {
void (*disable)(conf_object_t *obj, unsigned source_id);
void (*enable)(conf_object_t *obj, unsigned source_id);
};
#define INSTRUMENTATION_FILTER_SLAVE_INTERFACE "instrumentation_filter_slave"
- Execution Context
- Cell Context for all methods.
- Description
- This interface is implemented by the
instrumentation_filter_aggregator class objects. This
interface should only be used by Simics instrumentation framework itself.
The get_disabled_sources method returns an
attr_value_t list of integers representing the source_ids that
currently causing the connection to be disabled.
SIM_INTERFACE(instrumentation_filter_status) {
attr_value_t (*get_disabled_sources)(conf_object_t *obj);
};
#define INSTRUMENTATION_FILTER_STATUS_INTERFACE "instrumentation_filter_status"
- Execution Context
- Global Context for all methods.
- Description
- This interface is intended to be implemented by instrumentation tools using
the instrumentation framework. The instrumentation framework handles setting
up, controlling and removing the connection between providers and tools, but
the actual communication is handled by instrumentation specific interfaces.
When a connection with a provider is being established, the
connect method is called. The provider argument
specifies the provider which should be connected. The args
are tool specific arguments that can be used allowing the connection
to be configured a certain way. The tool should create a new
dedicated connection object, which register itself with the provider
using the dedicated interface. The connection object created
is returned by the connect function.
If, for any reason, the tool cannot successfully connect
to the provider, NULL should be returned to indicate failure.
If a connection should be removed, the disconnect method
is called. The conn_obj argument is the connection object
returned earlier in connect.
It is up to the tool to delete the created object which should
unregister itself from the provider.
SIM_INTERFACE(instrumentation_tool) {
conf_object_t *(*connect)(
conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL provider,
attr_value_t args);
void (*disconnect)(
conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL conn_obj);
};
#define INSTRUMENTATION_TOOL_INTERFACE "instrumentation_tool"
- Execution Context
- Global Context for all methods.
- Description
- This interface is implemented by the leader, and is used from a follower
agent to send data to the follower.
The send method sends a deterministic message to the follower to
be delivered at time. If several messages will be delivered at
same time, an increasing skey determines the sort order.
The send_async method sends a non-deterministic (asynchronous)
message to the follower to be delivered as soon as possible.
SIM_INTERFACE(leader_message) {
void (*send)(conf_object_t *obj,
follower_time_t time, uint64 skey, bytes_t msg);
void (*send_async)(conf_object_t *obj, bytes_t msg);
};
#define LEADER_MESSAGE_INTERFACE "leader_message"
- Execution Context
- Cell Context for all methods.
- Description
-
get_admin returns the osa_admin object associated
with the component.
get_root_node returns a maybe_node_id_t with the valid
field set to true and id set to the current root node if a root
node exists. If no root node exists the valid field will be set
to false.
It is only valid to call get_admin or get_root_node on
instantiated components.
notify_tracker registers a callback function cb that
will be called when a tracker is added to the component using the
insert-tracker command. Returns a cancel id that can be used to
cancel the callback using cancel_notify. It is a one time
notification and will automatically be canceled once it has been called. The
data argument will be passed on to the callback.
cancel_notify cancels a callback made by
notify_tracker.
has_tracker returns true if the component has a tracker inserted,
otherwise false.
get_processors returns a list of processors to use for the
software domain.
SIM_INTERFACE(osa_component) {
conf_object_t *(*get_admin)(conf_object_t *NOTNULL obj);
maybe_node_id_t (*get_root_node)(conf_object_t *NOTNULL obj);
cancel_id_t (*notify_tracker)(conf_object_t *NOTNULL obj,
void (*cb)(cbdata_call_t data),
cbdata_register_t data);
void (*cancel_notify)(conf_object_t *NOTNULL obj,
cancel_id_t cancel_id);
bool (*has_tracker)(conf_object_t *NOTNULL obj);
attr_value_t (*get_processors)(conf_object_t *NOTNULL obj);
};
#define OSA_COMPONENT_INTERFACE "osa_component"
- Execution Context
- Cell Context for all methods.
- Description
-
request is used
to register clients that are interested in using the tracker framework and
activates the tracker framework if it is not already activated. The
initiator argument is a string which should describe the client
that requests to activate the OS Awareness framework. The return value is an
ID that should be passed to the release function to signal that
the client no longer needs the OS Awareness framework.
Upon a failure while initializing the OS Awareness framework,
OSA_Request_Error_ID will be returned.
release removes a
client that has previously requested to use the tracker framework. The
id argument is the returned value from request. The
tracker framework will be disabled when there are no more registered users.
SIM_INTERFACE(osa_control) {
request_id_t (*request)(conf_object_t *NOTNULL obj,
const char *initiator);
void (*release)(conf_object_t *NOTNULL obj, request_id_t id);
};
#define OSA_CONTROL_INTERFACE "osa_control"
- Execution Context
- Global Context for all methods.
- Description
-
request is
used to register clients that are interested in using the tracker framework
and activates the tracker framework if it is not already activated. The
initiator argument is a string which should describe the client
that requests to activate the OS Awareness framework. The return format is
[bi|s]. If the first element is True, then the second element will contain
the request_id, which can be passed to the release
function to signal that the client no longer needs the OS Awareness
framework. If the first element is False, the second element will be an
error message.
release
removes a client that has previously requested to use the tracker
framework. The id argument is the returned value from
request. The tracker framework will be disabled when there are no
more registered users.
clear_state can be called to clear the state in the tracker
framework that could exist after loading a checkpoint. This can only be
called while the tracker is disabled. The return value will be on the format
[bi|s]. If the first element is True then clearing state succeeded and the
second element can be ignored. If the first element is False then clearing
state failed and the second element will contain a string with a message of
what went wrong.
SIM_INTERFACE(osa_control_v2) {
attr_value_t (*request)(conf_object_t *NOTNULL obj,
const char *initiator);
void (*release)(conf_object_t *NOTNULL obj, request_id_t id);
attr_value_t (*clear_state)(conf_object_t *NOTNULL obj);
};
#define OSA_CONTROL_V2_INTERFACE "osa_control_v2"
- Execution Context
- Global Context for all methods.
- Description
-
notify_mode_change registers a callback function that will be
called when processor cpu changes processor mode. The
callback function will be called with the processor that changed mode
cpu, the mode previous to the change old_mode and
the mode after the change new_mode.
notify_exception registers a callback function that will be
called when processor cpu takes an exception with exception
number exc_num. The callback function cb will be
called with the processor cpu causing the exception and
exception number exc_num of that exception.
notify_control_reg registers a callback function that will be
called when a control register, with register number reg_num, in
processor cpu is updated. The callback function cb
will be called with the processor cpu, register number
reg_num and the written register value (see
Core_Control_Register_Write documentation for more details) as
arguments. The register number for a certain register can be retrieved with
the get_register_number function.
notify_control_reg_read registers a callback function that will
be called when a control register, with register number reg_num,
in processor cpu is read. The callback function cb
will be called with the processor cpu and register number
reg_num as arguments. The register number for a certain register
can be retrieved with the get_register_number function.
notify_exec_breakpoint,
notify_read_breakpoint and
notify_write_breakpoint plant breakpoints of length
len for processor cpu on address.
The breakpoint is of type execution, read, write respectively. The
virt argument specifies if address is a virtual
or physical address. The callback function cb is called when
the breakpoint is hit.
The arguments of the callback functions are the processor that the
breakpoint hit on cpu and the address
(virtual or physical depending on what the breakpoint was registered as)
that was hit.
Callbacks functions for notify_read_breakpoint and
notify_write_breakpoint also gets the access size len
of the read or write.
The callback function for notify_write_breakpoint additionally
has the previous value old_val at the address written and the new
value new_val that is being written passed as arguments. Reading
the actual memory from the callback will result in reading the new value that
has been written as the callback is called after the write is done.
On x86 virtual breakpoints use linear addresses (as opposed to logical
addresses).
For all functions, the tracker argument should be the tracker
calling this interface. This makes it possible for a hypervisor tracker to
handle guests differently.
All methods that register a notification callback take data as an
argument which will be passed on to callback function. These methods return
a cancel ID to be used with the cancel method to cancel the
callback. A returned value of 0 means that an error occurred and no callback
was registered, in which case the caller is responsible for freeing the
callback data.
cancel cancels the callback function with ID cancel_id
and will free the callback data associated with the
notification. This ID will have been returned from the function that
registered the callback.
typedef enum {
OSA_Read_One_Byte = 1,
OSA_Read_Two_Byte = 2,
OSA_Read_Four_Byte = 4,
OSA_Read_Eight_Byte = 8,
} osa_read_len_t;
SIM_INTERFACE(osa_machine_notification) {
cancel_id_t (*notify_mode_change)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu,
void (*cb)(cbdata_call_t data, conf_object_t *cpu,
processor_mode_t old_mode,
processor_mode_t new_mode),
cbdata_register_t data);
cancel_id_t (*notify_exception)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, int exc_num,
void (*cb)(cbdata_call_t data, conf_object_t *cpu, int exc_num),
cbdata_register_t data);
cancel_id_t (*notify_control_reg)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, int reg_num,
void (*cb)(cbdata_call_t data, conf_object_t *cpu, int reg_num,
uint64 value),
cbdata_register_t data);
cancel_id_t (*notify_exec_breakpoint)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, uint64 address, uint64 len,
bool virt,
void (*cb)(cbdata_call_t data, conf_object_t *cpu,
uint64 address),
cbdata_register_t data);
cancel_id_t (*notify_read_breakpoint)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, uint64 address, unsigned len,
bool virt,
void (*cb)(cbdata_call_t data, conf_object_t *NOTNULL cpu,
uint64 address, unsigned len),
cbdata_register_t data);
cancel_id_t (*notify_write_breakpoint)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, uint64 address, unsigned len,
bool virt,
void (*cb)(cbdata_call_t data, conf_object_t *NOTNULL cpu,
uint64 address, unsigned len, uint64 old_val,
uint64 new_val),
cbdata_register_t data);
void (*cancel)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker, cancel_id_t cancel_id);
cancel_id_t (*notify_control_reg_read)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, int reg_num,
void (*cb)(cbdata_call_t data, conf_object_t *cpu, int reg_num),
cbdata_register_t data);
};
#define OSA_MACHINE_NOTIFICATION_INTERFACE "osa_machine_notification"
- Execution Context
- Cell Context for all methods.
- Description
-
read_register reads the register with number reg
(number can be retrieved with get_register_number) from processor
cpu and returns the value of that register.
get_register_number returns the register number of the register
with name reg from processor cpu or -1 upon error.
read_phys_memory reads len bytes of memory from
physical address addr of processor cpu. The returned
value is an uint64 with the value if the read succeeded, otherwise nil. The
len argument should use one of the lengths declared in the
osa_read_len_t enum.
read_phys_bytes reads len bytes of memory from
physical address addr. The length to read can be up to 1024
bytes. The returned value is of data type containing the bytes read upon
success or nil otherwise.
virtual_to_physical translates the virtual address
vaddr of processor cpu to a physical address as
translation would be for a data read. The returned value is the physical
address as an uint64 upon success, otherwise nil. For x86 this uses linear
to physical translation (as opposed to the logical to physical variant).
cpu_mode returns the current processor mode of cpu.
get_all_processors returns all available processors. For example,
when detecting parameters, a tracker should use its known processors if the
system is enabled, otherwise it can get them via get_all_processors. For
hypervisor configurations, the tracker framework must be enabled in order to
detect parameters for a guest.
get_exception_number returns the exception number of the
exception with name name from processor cpu.
Returns -1 if no exception with the given name exists.
For all functions, the tracker argument should be the tracker
calling this interface. This makes it possible for a hypervisor tracker to
handle guests differently.
SIM_INTERFACE(osa_machine_query) {
uint64 (*read_register)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, int reg);
int (*get_register_number)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, const char *reg);
attr_value_t (*read_phys_memory)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, physical_address_t addr,
osa_read_len_t len);
attr_value_t (*read_phys_bytes)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, physical_address_t paddr,
unsigned len);
attr_value_t (*virtual_to_physical)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, uint64 vaddr);
processor_mode_t (*cpu_mode)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu);
attr_value_t (*get_all_processors)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker);
int (*get_exception_number)(
conf_object_t *NOTNULL obj, conf_object_t *NOTNULL tracker,
conf_object_t *NOTNULL cpu, const char *name);
};
#define OSA_MACHINE_QUERY_INTERFACE "osa_machine_query"
- Execution Context
- Cell Context for all methods.
- Description
-
tracker_updated is called from the node tree when entities are
added, modified or removed. To receive such an update, the mapper must
subscribe to tracker updates by calling subscribe_tracker in
the osa_tracker_state_notification interface. The
initiator argument is the processor object that initiated the
transaction. This can be nil if the transaction was not initiated by a
processor (for example, enable or disable tracker). The format of
changeset is a dictionary with tracker objects that were updated
as keys and other dictionaries as values.
The dictionary that is set as the value for each tracker contains the
following keywords: "added", "modified",
"removed" and "events".
The value for "added" is a dictionary which contains the added
entity IDs as keys and the attributes of those entities as values.
An example of "added" where two entities were added:
"added": {0x1000: {"name": "task1", "pid": 1},
0x2000: {"name": "task2", "pid": 2}}
The value for "modified" is a dictionary which contains the
modified entity IDs as keys and a dictionary with the attribute name
as key and a list of old and new values for that attribute as its value.
Only the attributes that have changed will be included. If an attribute
is removed that will be set so that it changed to nil. If an attribute was
added that will be set so that it changed from nil.
An example of "modified", entity 0x1000 had "name"
changed and entity 0x2000 had "tgid" added and "pid"
removed:
"modified": {0x1000: {"name": ["task1", "new_name"]},
0x2000: {"tgid": [None, 4], "pid": [2, None]}}
The value for "removed" is a list which contains the entity IDs
for the entities that have been removed.
The value for "events" is a dictionary indexed by the entity
id. Each value is a list of lists, each inner list is an event. The first
element of the inner list is the event name and the second element is user
defined data associated with the event.
An example of "events" where entity 0x1000 has two associated
events and entity 0x2000 has one associated event:
"events": {0x1000: [["event1", {}], ["event2", {}]],
0x2000: [["syscall", {'sys_num': 0x10, 'sys_name': "open"}]]}
An example of how the complete changeset might look like:
{<the tracker 'tracker1_obj'>: {"added": {0x1000: {"name": "task"}},
"modified": {0x2000: {"dummy": [1, 2]}},
"removed": [0x3000, 0x3100]},}
SIM_INTERFACE(osa_mapper_admin) {
void (*tracker_updated)(conf_object_t *NOTNULL obj,
conf_object_t *initiator,
attr_value_t changeset);
};
#define OSA_MAPPER_ADMIN_INTERFACE "osa_mapper_admin"
- Execution Context
- Cell Context for all methods.
- Description
-
The
disable function is called when the mapper should be
disabled. The mapper should then clean-up the node tree and stop listening
to changes from trackers.
The
enable function is called when the mapper should be enabled. The
mapper should then create the node tree and start listening to changes from
trackers.
The
clear_state is called to clear the mapper's state. The mapper
should clear all its internal data when this is called, so that
enable can be called again. This call can only occur while
the mapper is disabled.
SIM_INTERFACE(osa_mapper_control) {
void (*disable)(conf_object_t *NOTNULL obj);
bool (*enable)(conf_object_t *NOTNULL obj);
void (*clear_state)(conf_object_t *NOTNULL obj);
};
#define OSA_MAPPER_CONTROL_INTERFACE "osa_mapper_control"
- Execution Context
- Cell Context for all methods.
- Description
-
The optional
get_process_list function provides data for the 'list'
command. It should return a two-element list, where the first element is a
list of column headers, and the second element is a list of (row, subtable)
two-element lists. All rows should have the same number of elements as the
header list (this is the number of columns in the resulting table).
The elements of the header list and row lists---that is, the individual
elements in the table---should be of type string or integer. Integers will
be formatted by the system, so in order to force a specific base, such as
decimal or hexadecimal, convert them to strings.
The subtables paired with each row should either be None (meaning no
subtable) or a nested list such as that returned by get_process_list(), in
which case that list will be printed, slightly indented, below the row. This
makes it possible for the list command to handle stacked trackers. An
example of how a complete return value from get_process_list
function can look like:
[["Process", "Pid"], [[["ls", 1], None], [["cat", 2], None]]]
If the function is not implemented, the function pointer should be set to
NIL.
The optional
get_mapper function returns the mapper that is responsible for
the given node. A mapper that has guest mappers should forward the request
to the guests as well if the node belongs to one of the guests. If the
function is not implemented by the mapper, it is assumed that the node is
owned by the mapper.
If this function is not implemented, the function pointer should be set to
NIL. Stacked trackers, which support guest trackers must implement this
function.
SIM_INTERFACE(osa_mapper_query) {
attr_value_t (*get_process_list)(conf_object_t *NOTNULL obj);
conf_object_t *(*get_mapper)(conf_object_t *NOTNULL obj,
node_id_t node_id);
};
#define OSA_MAPPER_QUERY_INTERFACE "osa_mapper_query"
- Execution Context
- Global Context for all methods.
- Description
-
This interface is used to get information when micro checkpointing (for
reverse execution) starts and stops. The functions will only be called
when the tracker framework is enabled.
started is called when a saved state is about to be loaded,
before any attributes have been set.
finished is called once all attributes have been set for all
objects. At this point callbacks calls to the machine interfaces can be
done.
It is allowed to implement only one of these functions if notification are
only wanted before or after setting attributes of a micro checkpoint.
This interface is optional and can be implemented by either a tracker or a
mapper.
SIM_INTERFACE(osa_micro_checkpoint) {
void (*started)(conf_object_t *NOTNULL obj);
void (*finished)(conf_object_t *NOTNULL obj);
};
#define OSA_MICRO_CHECKPOINT_INTERFACE "osa_micro_checkpoint"
- Execution Context
- Global Context for all methods.
- Description
-
matching_nodes function returns a list of all nodes rooted at
root_id that matches the given node_path_pattern. The
node_path_pattern should be either an integer representing a node id or a
string, see Analyzer User's Guide for more details.
Upon success, the return value is a list where the first entry is true and
the second entry is a list containing all the matching node ids.
Upon failure, the return value is a list where the first entry is false and
the second entry is a string describing the error.
node_path
function translates a node id into a fully qualified node path string. See
Analyzer User's Guide for more details.
Upon success, the return value is a list where the first entry is true and
the second entry is the node path string.
Upon failure, the return value is a list where the first entry is false and
the second entry is a string describing the error.
SIM_INTERFACE(osa_node_path) {
attr_value_t (*matching_nodes)(conf_object_t *NOTNULL obj,
node_id_t root_id,
attr_value_t node_path_pattern);
attr_value_t (*node_path)(conf_object_t *NOTNULL obj,
node_id_t node_id);
};
#define OSA_NODE_PATH_INTERFACE "osa_node_path"
- Execution Context
- Global Context for all methods.
- Description
-
begin is
called from the mapper to start a transaction when adding, updating or
removing nodes in the node tree. The initiator argument specifies
the initiator processor, this can be nil if the transaction is not initiated
by a processor. The initiator will be passed as cpu
argument to callback functions in the
osa_node_tree_notification interface. The function returns an
ID to be used when calling end.
end is called
from the mapper to end a transaction. This should be called at the end of a
transaction when all modifications to the node tree are complete. The
transaction_id argument should be the value returned from the
begin method that started the transaction. Stacked calls to
begin and end are possible, then the transaction will
be ended when the first begin is ended. The begin
methods must be ended in the opposite order that they were called. For
stacked calls to begin only the initiator of the first call to
begin will be used.
create creates a new node tree and associates mapper
with it. The properties of the root node for the new tree are set through
props which is a dictionary. The returned value is the node ID
of the created root node.
add adds a new node rooted at parent_id. The new
node gets the properties specified by props which is a
dictionary. The returned value is the node ID of the newly added node.
update updates the properties of a node in the node tree.
node_id specifies the node to be updated and props
is a dictionary of the properties that should be updated.
set_property updates one property of a node in the node tree.
This is similar to update but there is no need to build up a
dictionary. node_id specifies the node to be updated,
key the key of the property to be updated and value
the value to update the property with.
reset resets a node, node_id, to the properties
specified by props. All the children for the node will be removed
and all properties except the ones in props will be removed. If
the reset node was previously active it will be deactivated.
All methods have the limitation that data and dictionary types are not
supported as the value of a property. The keys of the props
dictionary must all be of string type.
remove removes the node with the ID specified by
node_id from the node tree.
event registers a new event, associated with the given
node_id. The event_name argument is the name of the
event, this name can also be used by a user to only listen to a specific
event type per node tree. The event_data argument is the data
associated with the event and it is up to the responsible tracker to
document its exact form. An event differes from other properties in the way
that they are not persistent.
activate sets node_id as the active node for
processor cpu in the node tree where node_id exists.
All the ancestors of node_id will also be set as active. Any
previously active node for cpu will be deactivated.
deactivate deactivates processor cpu in the node tree
where node_id exists. The node_id argument should be
set to the node that was previously active on cpu in the node
tree.
register_formatter registers a callback function which will be
called when the property specified by the key argument should be
formatted in a specific way. This is typically called from
"get_formatted_properties" in the
osa_node_tree_query interface. This is useful for
systems where an integer property should be formatted in hexadecimal to make
a closer match to the target OS mapper of that property. For example, a node
with the following properties:
{"name": "foo", "tid": 4711}
could then be formatted as:
{"name": "foo", "tid": "0x1267"}
The function itself must return a string, given as an attr_value_t. The
mapper must have been registered by calling the create function
in the osa_node_tree_admin interface before registering a
formatter.
The register_formatter function returns a cancel id that can be
passed to the unregister_formatter function to unregister the
formatting function. Registering a new formatter on the same
node_id and key as a previous formatter will override
the previous formatter with the new one. This is useful when dealing with
stacked trackers and a sub-tracker needs to register a formatter for a node
that already have a registered formatter.
unregister_formatter unregisters a previously registered
formatter function using the register_formatter function.
SIM_INTERFACE(osa_node_tree_admin) {
transaction_id_t (*begin)(conf_object_t *NOTNULL obj,
conf_object_t *initiator);
void (*end)(conf_object_t *NOTNULL obj,
transaction_id_t transaction_id);
node_id_t (*create)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL mapper, attr_value_t props);
node_id_t (*add)(conf_object_t *NOTNULL obj,
node_id_t parent_id, attr_value_t props);
void (*update)(conf_object_t *NOTNULL obj, node_id_t node_id,
attr_value_t props);
void (*remove)(conf_object_t *NOTNULL obj, node_id_t node_id);
void (*event)(conf_object_t *NOTNULL obj, node_id_t node_id,
const char *event_name, attr_value_t event_data);
void (*activate)(conf_object_t *NOTNULL obj, node_id_t node_id,
conf_object_t *NOTNULL cpu);
void (*deactivate)(conf_object_t *NOTNULL obj, node_id_t node_id,
conf_object_t *NOTNULL cpu);
cancel_id_t (*register_formatter)(
conf_object_t *NOTNULL obj, node_id_t node_id,
const char *NOTNULL key,
bool recursive, attr_value_t (*formatter)(attr_value_t val));
void (*unregister_formatter)(
conf_object_t *NOTNULL obj, cancel_id_t node_id);
void (*reset)(conf_object_t *NOTNULL obj,
node_id_t node_id, attr_value_t props);
void (*set_property)(conf_object_t *NOTNULL obj, node_id_t node_id,
const char *key, attr_value_t value);
};
#define OSA_NODE_TREE_ADMIN_INTERFACE "osa_node_tree_admin"
- Execution Context
- Cell Context for all methods.
- Description
-
notify_create and
notify_destroy register callbacks to be
called when the node is created and destroyed, respectively. The
node_id argument specifies for which node the callback should be
installed. By specifying both the node_id and the
recursive arguments it is possible to get notifications for all
nodes in a subtree. It is safe to read the node with get_node in
the osa_node_tree_query interface from within the callback
function.
Calling notify_create without recursive being set is
only useful when used together with reverse execution, as only then can the
node ID of a node that is to be created later be known.
notify_property_change registers a callback that is
triggered when the given property key changes on the node (or any
property, if key is nil). The callback function will receive the
name of the property that was changed in the key argument and the
old and new values of that property in the old_val and
new_val arguments.
notify_event register a callback cb to be called when
an event occurs for the given node_id. If the
event_name argument is nil the callback will be associated with
all events, by providing a specific event name instead the callback will
only trigger for that particular event type. The event_data
argument passed to the callback contains tracker specific data associated
with the event. See specific tracker documentation for details.
If recursive, the callback will be triggered for the given node's
descendants as well as the node itself.
Most callbacks have cpu and obj arguments. The
cpu argument specifies the processor that caused the event, but
may be nil if the event was not caused by a processor. The obj
will contain the object that implements the interface. The
node_id argument passed to the callback specifies the node ID for
the node that has been created, destroyed, modified or has triggered an
event.
notify_cpu_move_from and
notify_cpu_move_to register callbacks that are triggered when
a processor moves from one node path to another—but only if either
path lies in the subtree rooted at the given node node_id.
Since a single update to the node tree can result in several different
callbacks being triggered, reading nodes with get_node from a
callback function may yield a result containing updates whose callbacks have
not yet been run. For example, if two nodes change their name
attributes simultaneously, the final state of both nodes may be visible to
both property change callbacks. With
notify_callbacks_done, you can register a callback that will run
when all other callbacks pertaining to a particular change in the node tree
are finished.
notify_enable register a callback cb to be called when
the tracker framework is enabled.
notify_disable register a callback cb to be called when
the tracker framework is disabled.
The functions that install callbacks return an integer ID. This ID can be
passed to cancel_notify
in
order to uninstall the callback. In case of error in a notification function
the returned cancel ID from that function will be 0.
New callbacks registered inside a registered callback will not be called
until the next transaction they trigger for. Canceled callbacks are canceled
immediately.
SIM_INTERFACE(osa_node_tree_notification)
{
cancel_id_t (*notify_create)(conf_object_t *NOTNULL obj,
node_id_t node_id, bool recursive,
void (*cb)(cbdata_call_t data,
conf_object_t *obj,
conf_object_t *cpu,
node_id_t node_id),
cbdata_register_t data);
cancel_id_t (*notify_destroy)(conf_object_t *NOTNULL obj,
node_id_t node_id, bool recursive,
void (*cb)(cbdata_call_t data,
conf_object_t *obj,
conf_object_t *cpu,
node_id_t node_id),
cbdata_register_t data);
cancel_id_t (*notify_property_change)(
conf_object_t *NOTNULL obj, node_id_t node_id,
const char *key, bool recursive,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
conf_object_t *cpu, node_id_t node_id,
const char *key, attr_value_t old_val,
attr_value_t new_val),
cbdata_register_t data);
cancel_id_t (*notify_cpu_move_from)(
conf_object_t *NOTNULL obj, node_id_t node_id,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
conf_object_t *cpu, attr_value_t node_path),
cbdata_register_t data);
cancel_id_t (*notify_cpu_move_to)(
conf_object_t *NOTNULL obj, node_id_t node_id,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
conf_object_t *cpu, attr_value_t node_path),
cbdata_register_t data);
cancel_id_t (*notify_event)(
conf_object_t *NOTNULL obj, node_id_t node_id,
const char *event_name, bool recursive,
void (*cb)(cbdata_call_t data, conf_object_t *obj,
conf_object_t *cpu, node_id_t node_id,
const char *event_name, attr_value_t event_data),
cbdata_register_t data);
cancel_id_t (*notify_enable)(
conf_object_t *NOTNULL obj,
void (*cb)(cbdata_call_t data, conf_object_t *obj),
cbdata_register_t data);
cancel_id_t (*notify_disable)(
conf_object_t *NOTNULL obj,
void (*cb)(cbdata_call_t data, conf_object_t *obj),
cbdata_register_t data);
void (*cancel_notify)(conf_object_t *NOTNULL obj,
cancel_id_t cancel_id);
cancel_id_t (*notify_callbacks_done)(
conf_object_t *NOTNULL obj, uint64 node_id,
void (*cb)(cbdata_call_t data, conf_object_t *obj),
cbdata_register_t data);
};
#define OSA_NODE_TREE_NOTIFICATION_INTERFACE "osa_node_tree_notification"
- Execution Context
- Cell Context for all methods.
- Description
-
get_root_nodes returns a list of node IDs for the root nodes.
get_node returns a dictionary for a given node, containing all
the node's properties; or nil if no such node exists.
get_current_nodes returns the current node path of the given
processor. That is, a list of node IDs of all nodes that are currently
running on the processor, the first node being the root node, and every
subsequent node a child of the node before it. If the tracker is not
tracking the given processor, the return value is nil.
get_current_processors returns a list of processors that are
currently active on the given node, or one of it's descendants. The list
will be empty if there is no active processor. Nil will be returned if the
given node does not exist.
get_all_processors returns a list of all processors that are
available for the OS Awareness framework.
get_parent returns the node ID of the specified node's parent;
or nil if the node has no parent.
get_children returns a list of node IDs for the children of
the specified node, this will be an empty list if the node does not have
any children. The method will return nil if the node does not exist.
The get_formatted_properties function returns a dictionary
containing all properties for a node, formatted as strings or integers. It
will return nil upon a failure. For example, a tracker could format the
value of property pid to show the value in hexadecimal form.
{'name': "Our OS", 'pid': "0x1234"}
SIM_INTERFACE(osa_node_tree_query) {
attr_value_t (*get_root_nodes)(conf_object_t *NOTNULL obj);
attr_value_t (*get_node)(conf_object_t *NOTNULL obj, node_id_t node_id);
attr_value_t (*get_current_nodes)(conf_object_t *NOTNULL obj,
node_id_t base_id,
conf_object_t *cpu);
attr_value_t (*get_current_processors)(conf_object_t *NOTNULL obj,
node_id_t node_id);
attr_value_t (*get_all_processors)(conf_object_t *NOTNULL obj);
conf_object_t *(*get_mapper)(conf_object_t *NOTNULL obj,
node_id_t node_id);
attr_value_t (*get_parent)(conf_object_t *NOTNULL obj,
node_id_t node_id);
attr_value_t (*get_children)(conf_object_t *NOTNULL obj,
node_id_t node_id);
attr_value_t (*get_formatted_properties)(conf_object_t *NOTNULL obj,
uint64 node_id);
};
#define OSA_NODE_TREE_QUERY_INTERFACE "osa_node_tree_query"
- Execution Context
- Cell Context for all methods.
- Description
-
Interface implemented by tracker components that support getting and setting
their parameters.
If either method fails it returns a (false, error-string) pair. If
get_parameters succeed it returns (true, parameters). If set_parameters
succeed it returns (true, nil).
The parameters you pass to set_parameters and thare are returned by
get_parameters should be a pair (tracker-kind, parameters-value), where
tracker-kind is a string identifying the kind of tracker and parameters-value
is the parameters for that kind of tracker. The parameters for an
unconfigured tracker are (tracker-kind, nil).
The include_children argument of get_parameters is
only used for stacked tracker and specifies if parameters for guest trackers
should be included or filtered out.
The is_kind_supported method returns true if the tracker-kind in a parameter
set is of the right kind for the tracker. This is no guarantee that setting
these parameters will succeed. If the method returns false the parameters
will not work.
SIM_INTERFACE(osa_parameters) {
attr_value_t (*get_parameters)(conf_object_t *NOTNULL obj,
bool include_children);
attr_value_t (*set_parameters)(conf_object_t *NOTNULL obj,
attr_value_t parameters);
bool (*is_kind_supported)(conf_object_t *NOTNULL obj,
const char *kind);
};
#define OSA_PARAMETERS_INTERFACE "osa_parameters"
- Execution Context
- Global Context for all methods.
- Description
-
get_tracker returns the tracker object associated with the
component or nil if no such tracker exists.
get_mapper returns the mapper object associated with the
component or nil if no such mapper exists.
SIM_INTERFACE(osa_tracker_component) {
conf_object_t *(*get_tracker)(conf_object_t *NOTNULL obj);
conf_object_t *(*get_mapper)(conf_object_t *NOTNULL obj);
};
#define OSA_TRACKER_COMPONENT_INTERFACE "osa_tracker_component"
- Execution Context
- Cell Context for all methods.
- Description
-
enable and
disable are called from the OS Awareness framework,
for all trackers that have been set in the top_trackers
attribute for the node_tree object, when OS Awareness is
enabled or disabled, respectively.
clear_state is called to clear the trackers state. The tracker
should clear all its internal data and its data in the node tree when this
is called. This call can only occur while the tracker is disabled.
add_processor and
remove_processor are called to add or remove a processor
cpu to/from the tracker which the tracker should start/stop
tracking. If the tracker is registered as a top level tracker these methods
will be called by the OS Awareness framework for all processors available
to the framework when it is enabled or disabled. If the tracker is a guest
under a hypervisor the hypervisor should call these methods when a
processor becomes available or unavailable to the guest.
These functions should return true if a processor was successfully added or
removed, otherwise the function should return false.
SIM_INTERFACE(osa_tracker_control) {
void (*disable)(conf_object_t *NOTNULL obj);
bool (*enable)(conf_object_t *NOTNULL obj);
void (*clear_state)(conf_object_t *NOTNULL obj);
bool (*add_processor)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL cpu);
bool (*remove_processor)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL cpu);
};
#define OSA_TRACKER_CONTROL_INTERFACE "osa_tracker_control"
- Execution Context
- Global Context for enable, disable and
clear_state.
Cell Context for add_processor and
remove_processor.
- Description
-
begin
is called from the tracker to start a transaction when modifying an entity in
the node tree. The tracker argument specifies the tracker object
for which the updates are done for. The initiator argument
specifies the processor that initiated the transaction, this can be nil if
it was not a processor that caused the transaction to begin, when enabling
the tracker as an example. The initiator is passed as an argument
to the tracker_updated function in the
osa_mapper_admin interface. The function returns an ID that
is used when calling end.
end is
called from the tracker to end a transaction. This should be called at the
end of a transaction when all entity modifications are done. The
transaction_id argument should be the value returned from
begin that started the transaction. Stacked calls to
begin and end are possible, then the transaction will
be ended when the first begin is ended. The begin
methods must be ended in the opposite order that they were called. For
stacked calls to begin only the initiator of the first call to
begin will be used.
add adds a new entity with ID entity_id to the node
tree. The new entity's attributes are set in the attributes
argument, which is a dictionary.
remove removes the entity with ID entity_id for the
current tracker from the node tree.
remove_all removes all entities for the current tracker from
the node tree.
set_attribute adds or updates an attribute key for
the entity with ID entity_id. The new value is specified in
val.
update updates or adds one or more attributes for the entity with
ID entity_id. The attributes argument is a dictionary
with the attributes to be updated.
In order to remove a property, set the property value to nil when calling
update or set_attribute.
event registers a new event, associated with the given
entity_id argument. The event_name argument is the
name of the event. The event_data argument is the data associated
with the event and it is up to the responsible tracker to document its exact
form. An event differes from other properties in the way that they are not
persistent.
Entity attributes have the limitation that the value of the attribute can
not be of type data or dictionary. The keys of entity attributes must be of
string type.
SIM_INTERFACE(osa_tracker_state_admin) {
transaction_id_t (*begin)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker,
conf_object_t *initiator);
void (*end)(conf_object_t *NOTNULL obj, transaction_id_t txid);
void (*add)(conf_object_t *NOTNULL obj, entity_id_t entity_id,
attr_value_t attributes);
void (*remove)(conf_object_t *NOTNULL obj, entity_id_t entity_id);
void (*remove_all)(conf_object_t *NOTNULL obj);
void (*set_attribute)(conf_object_t *NOTNULL obj, entity_id_t entity_id,
const char *key, attr_value_t val);
void (*update)(conf_object_t *NOTNULL obj, entity_id_t entity_id,
attr_value_t attributes);
void (*event)(conf_object_t *NOTNULL obj, entity_id_t entity_id,
const char *event_name, attr_value_t event_data);
};
#define OSA_TRACKER_STATE_ADMIN_INTERFACE "osa_tracker_state_admin"
- Execution Context
- Cell Context for all methods.
- Description
-
subscribe_tracker is called to make mapper receive
updates for entities of tracker. When such an update occurs, the
function tracker_updated in interface
osa_mapper_admin will be called.
unsubscribe_tracker cancels a subscription of entity
updates to mapper> that was started by
subscribe_tracker for the specified tracker. A tracker
without guest trackers does not need to call this, as it will be
automatically done when the framework is disabled. However, a tracker with
guest trackers, must call this function when a guest is removed.
SIM_INTERFACE(osa_tracker_state_notification) {
void (*subscribe_tracker)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL mapper,
conf_object_t *NOTNULL tracker);
void (*unsubscribe_tracker)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL mapper,
conf_object_t *NOTNULL tracker);
};
#define OSA_TRACKER_STATE_NOTIFICATION_INTERFACE \
"osa_tracker_state_notification"
- Execution Context
- Cell Context for all methods.
- Description
-
get_entities returns a dictionary of entities that are stored for
tracker. The dictionary maps entity id to properties, which in
turn is a dictionary, mapping property name to property value. Returns nil
if tracker is not known.
get_entity returns the properties for the given entity
id and tracker, as a dictionary that maps property
name to property value. Returns nil if the entity can not be found.
SIM_INTERFACE(osa_tracker_state_query) {
attr_value_t (*_deprecated)(conf_object_t *NOTNULL obj);
attr_value_t (*get_entities)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker);
attr_value_t (*get_entity)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL tracker,
entity_id_t id);
};
#define OSA_TRACKER_STATE_QUERY_INTERFACE "osa_tracker_state_query"
- Execution Context
- Cell Context for all methods.
- Description
-
The preference interface is implemented by objects that store preferences
on the behalf of other modules. Preferences are settings that are persistent
between sessions. Typically there is a single object implementing the
preference interface.
SIM_INTERFACE(preference) {
attr_value_t
(*get_preference_for_module_key)(conf_object_t *NOTNULL prefs,
const char *NOTNULL module,
const char *NOTNULL key);
void (*set_preference_for_module_key)(conf_object_t *NOTNULL prefs,
attr_value_t value,
const char *NOTNULL module,
const char *NOTNULL key);
};
#define PREFERENCE_INTERFACE "preference"
get_preference_for_module_key is called to retrieve a preference for
a specified module and key. If no value has been set
an invalid attribute is returned.
set_preference_for_module_key is called to store a preference for
a specified module and key. Any attribute type is
allowed for the value, including nested types. However, the value may no
contain any invalid attributes.
- Execution Context
- Global Context for all methods.
- Description
- This interface defines a probe in the system. A probe is a mechanism that
lets a model expose values of interest to a user. By using this interface,
generic tools can extract these values and present them in different forms,
like tables and graphs. A probe should always have a meaningful value that
can be read at any time during the simulation.
Probes should be used for user observable values and are not intended for
model to model communication.
The properties() method is typically called once for each tool
or use-case to get information about the probe. It should return a key/value
attr_value_t list, i.e., list of lists of two values, with
probe specific properties. The first value of the inner list represents the
property key as an Sim_Val_Integer using the enum probe_key_t
type, and the second value is a key specific data item described below. The
probe_key_t is defined as:
typedef enum {
Probe_Key_Kind = 0, /* Identifier of the probe */
Probe_Key_Name = 0, /* Old name of Probe_Key_Kind,
kept for compatibility */
Probe_Key_Type = 1, /* string, any of: {
"int", "float, "fraction",
"histogram", "int128", "string"
} */
Probe_Key_Categories = 2, /* list of strings */
Probe_Key_Cause_Slowdown = 3, /* bool */
Probe_Key_Owner_Object = 4, /* object: owner object */
Probe_Key_Display_Name = 5, /* string: short narrow name */
Probe_Key_Description = 6, /* string */
Probe_Key_Float_Percent = 7,
Probe_Key_Float_Decimals = 8,
Probe_Key_Metric_Prefix = 9,
Probe_Key_Unit = 10,
Probe_Key_Binary_Prefix = 11,
Probe_Key_Time_Format = 12,
Probe_Key_Width = 13,
Probe_Key_Value_Notifier = 14,
Probe_Key_Aggregates = 17, /* Defines new probes which aggregate
over this probe:
[list of [list properties]]
Invalid for Type: "string"
*/
Probe_Key_Aggregate_Scope = 18, /* Aggregate over all probes in the
cells or all probes in the system.
String and of ["global", "cell"] */
Probe_Key_Aggregate_Function = 19, /* How the aggregation should be
done:
"sum",
"weighted-arith-mean",
- only fractions
*/
Probe_Key_Definition = 20, /* string: how the probe is
calculated */
} probe_key_t;
The value() method should return the data for the probe as an
attr_value_t in accordance of how the property type has been
defined. This method is called each time a tool/user wants to read the latest
probe value.
The property keys are describes here as follows:
Probe_Key_Kind- Sets the kind of the probe, as a string (Sim_Val_String).
The probe-kinds are what uniquely define the probes in the system.
There can be many probes associated with the same kind,
but they should all represent the same type of measured data.
The kind should be named so it is humanly possible to understand what
you get back when you read it.
To avoid conflicts, the kind should be an hierarchical name where each level
is separated with a dot. Probes falling into the same domain should have
logical names according to this. Currently, there are some defined names on
the first level that can be used to build the hierarchy. Among them are:
cpu. that collects probes related to a CPU, dev. that collects
probes for devices, cell. that collects probes related to cells,
host. collects probes related to the host environment, and
sim. that collects probes having to do with the overall simulation
environment.
Some examples, include: cpu.cycles,
cpu.exec_mode.jit_steps, dev.io_access_count,
cell.steps, host.swap.used, and sim.slowdown.
Several objects implementing this interface can use the same probe-kind,
for similar probe values. The probe's unique identifier is a string
containing the object name then a colon, followed by the probe-kind, e.g.,
"board.mb.cpu0.cpu[0][0]:cpu.cycles".
Probe_Key_Display_Name- Sets a display name for the probe as a string (Sim_Val_String). This is
a more human friendly name than the probe name, and a tool can use this name
in table headings or graph legends.
Probe_Key_Type- Sets the type of the probe as a string (Sim_Val_String). The following
types are defined: "int", "float", "string", "fraction", "int128" and
"histogram". The
attr_value_t value that should be returned by
the value method for these types are as follows:
For the int type, an attr_value_t of type Sim_Val_Integer
should be returned.
For the float type, return a Sim_Val_Floating value.
The string type is returned by a Sim_Val_String value. The string typically
represents some momentarily state. Due to nature of a string, a tool cannot do
any calculation on the probe value, only show the current string content.
The fraction type should use a attr_value_t list of two
Sim_Val_Integer or Sim_Val_Floating values. This represent a mathematical
fraction value, where the first one is the numerator and and the second
value is the denominator value. Note however that a float value can be used
for both of them. To get the proper value for this probe the tool/user
should divide the numerator with the denominator. Using fraction makes it
possible for the tool to calculate a mean value for this probe between any
point in time where the probe was read, e.g., say you have a probe that
reads the frequency of a simulated processor that varies over time. Then
this probe can be defined as a fraction between the cycle count and the
elapsed virtual time (cycles/time = frequency). If the tool saves the cycle
difference and the time difference between to points in time, it can
calculate the mean frequency between those point by dividing the
differences.
For very large numbers the int128 type can be used, the type is represented
as a attr_value_t list of two value; the high 64-bit number
followed by the low 64-bit number.
The histogram type is represented by a attr_value_t list of
lists of two values. Where the inner list is used as a tuple of a named
group as a Sim_Val_String, and its corresponding value as a Sim_Val_Integer
or Sim_Val_Floating. A tool can then display an histogram of these groups
and/or calculate the difference between two histograms over time and display
that.
.
Probe_Key_Categories- The key is a list of string that defines some categories for the
probe. This information can be used to search for probes of a specific use
case.
Probe_Key_Cause_Slowdown- The value for this key is a Sim_Val_Boolean. True means that using the
probe can cause a significant slowdown of the simulation. False means it does
not cause any particular slowdown.
Probe_Key_Owner_Object- The value for this key is a Sim_Val_Object that should be regarded as
the owner of the probe instead of the object that implements this interface
(which is default). This can be useful if some other objects implements
functionality for the main object.
Probe_Key_Description- The value for this key is a Sim_Val_String that documents this
probe in details.
Probe_Key_Definition- "Function" definition string, explaining how the probe is
being calculated out from other probes. This is automatically created for
probe aggregates and derivatives. Default is an empty string.
Probe_Key_Float_Decimals- The value for this key is a Sim_Val_Integer that sets the preferred
number of decimals of this is float probe when a value is displayed.
Probe_Key_Float_Percent- The value for this key is a Sim_Val_Boolean that sets the preferred
representation of a float probe as a percent representation, e.g., a value
of 0.176 will be displayed as 17.6% if the number of decimals are one.
Probe_Key_Metric_Prefix- The value for this key is a Sim_Val_String describing a unit name. This
sets the preferred representation of a float probe to be displayed with a
metric prefix for the unit given. Supported metric prefixes are: k, M, G, T,
P, E, Z, Y, for values > 1 and m, µ, n, p, f, a, z, y for values <
1. For example if the unit is set to "s" (seconds) and the float value is
0.0000347, then the displayed representation should be "34.7 µs". To
omit the unit in the output use the empty string, "", as the unit. If the
value is outside the prefix ranges, an scientific E notation will be used.
Probe_Key_Binary_Prefix- The value for this key is a Sim_Val_String describing a unit name. This
sets the preferred representation of an integer probe to be displayed with a
binary prefix for the unit given. Supported prefixes are: ki, Mi, Gi, Ti,
Pi, Ei, Zi, and Yi. For example if the unit is set to "B" (representing
bytes), and the integer value is 10485760 (10*1024*1024), then the displayed
representation should be "10 MiB".
.
Probe_Key_Unit- The value for this key is a Sim_Val_String that sets the unit for the
value. A tool can use this to display the unit for the value.
Probe_Key_Time_Format- The value for this key is a Sim_Val_Boolean that sets the preferred
representation for a float value to a time format, hh:mm:ss.d, where h is
hours, m minutes, s seconds, and d is fractions of a seconds. The raw value
returned by the value method is the number of seconds. The
Probe_Key_Float_Decimals key/value pair controls the number of digits in the
fraction. If the number of seconds represents more than 99 hours, it should
continue adding digits for the hours, e.g., 100:44:10.123
Probe_Key_Width- The value for this key is a Sim_Val_Integer that sets the preferred
width of a probe value in characters. This can be used to determine the best
width of columns in a table tool, for instance.
Probe_Key_Value_Notifier- The value for this key is a Sim_Val_String that describes a notifier
that is triggered when the value changes. This can be used by a tool to
track all changes of the value. For performance reasons the value should be
changes infrequently.
Probe_Key_Global_Sum- Deprecated, use
Probe_Key_Aggregates instead. Probe_Key_Cell_Sum- Deprecated, use
Probe_Key_Aggregates instead. Probe_Key_Aggregates- Defines lists of new probes which are aggregates of the probe defined.
Each list-element defines a new probe, specified as a list of the key-value
properties for the aggregate probe. All properties are inherited from
the probe being aggregated, except the new name of the aggregate probe which
must be defined. Probe keys can be redefined if they appear in the
aggregate scope. For example, it is advisable to change the description
making it clear what value that is being returned by the aggregate.
Only in the aggregate scope, the Probe_Key_Aggregate_Scope
and Probe_Key_Aggregate_Function key-value pairs are used to further
define how the aggregation is done.
Note that aggregates depend on the the type of the underlying probe.
Some probe types can only be aggregated with certain functions.
Probe_Key_Aggregate_Scope- Defines the scope for the aggregate probe. That is, which objects that
implements the probe, should be part of the aggregation.
Valid values are "cell" or "global". Default is "global",
which means that all objects which implements the probe will be part of
the aggregate and put in the singleton owner object, such as the 'sim' or
'host' objects.
Cell-aggregates are put under the available cell objects
and will aggregate the probe which belongs to the respective cell object.
Probe_Key_Aggregate_Function- Defines how the aggregate should be generated.
Valid values are "sum", "min", "max", "arith-mean", "weighted-arith-mean"
and "median". Default is "sum".
For probes of the fraction type, if any denominator contains a zero value
(division by zero), the calculated value is undefined and [0, 0] is
returned. This applies to all fraction aggregates except weighted-arith-mean,
where the zero denominator can be handled.
sum- All probe values are summed together. Not supported on "string" probes.
min- The lowest value among the probe values is returned. Not supported on "string"
and "histogram" probes.
For fraction-probes, if any denominator contains a zero value, the calculated sum
returned is [0, 0].
max- The highest value among probe values is returned. Not supported on "string"
and "histogram" probes.
arith-mean- The arithmetic mean is calculated for all the probe values.
Not supported on "string" and "histogram" probes.
weighted-arith-mean- Only supported in fraction type probes.
The denominators are used as weights.
Using these weights implies that the weighted arithmetic mean can be
calculated by adding all numerators and denominators, producing a new
fraction of these sums.
For example, when calculating the mean instruction per cycles (IPC)
on all processors (where the IPC per processor is represented as a
fraction: instructions / cycles).
With two processors having [20/30] and [40/50], the total IPC
becomes [(20+40)/(30+50)] or [60/80] and the IPC value of 0.75.
median- The median among the probe values is returned.
Not supported on "fraction", "string" and "histogram" probes.
object-histogram- A histogram probe is created using the probe-owner-objects as key
and their probe-values value. The type of this aggregate probe
must be set to "histogram".
Only supported on "int" and "float" probes types.
class-histogram- Similar to the object-histogram, but here the histogram uses
the classname of the owner-object as key, and the value is the
sum of the probe-values with the same class. The type of this aggregate
probe must be set to "histogram".
Only supported on "int" and "float" probes types.
All key/value pairs except the Probe_Key_Kind and Probe_Key_Type are
optional.
SIM_INTERFACE(probe) {
attr_value_t (*value)(conf_object_t *obj);
attr_value_t (*properties)(conf_object_t *obj);
};
#define PROBE_INTERFACE "probe"
Execution ContextGlobal Context for all methods.
- Description
- This interface is similar to the
probe_index interface, except
that an additional all_values() method returns an
attr_value_t list of values as individually returned when calling
value(idx) on each indexed probe. Using all_values()
instead of looping over value(idx) can provide a significant
improvement in performance, depending on the number of probes whose values
need to be read, starting from a couple of probes.
The probe_sampler objects, provided in the probe-monitor
extension, make use of the all_values() method to boost their
performance when sampling probes implemented with the probe_array
interface.
SIM_INTERFACE(probe_array) {
int (*num_indices)(conf_object_t *obj);
attr_value_t (*value)(conf_object_t *obj, int idx);
attr_value_t (*all_values)(conf_object_t *obj);
attr_value_t (*properties)(conf_object_t *obj, int idx);
};
#define PROBE_ARRAY_INTERFACE "probe_array"
- Execution Context
- Global Context for all methods.
- Description
- This interface is similar to the
probe interface, except that
the indexed version allows multiple probes to be defined with a single
interface. The same index corresponds to the same probe for value
and properties methods. The amount of probes that the interfaces
supports is returned through the num_indices() method, which should
be static.
SIM_INTERFACE(probe_index) {
int (*num_indices)(conf_object_t *obj);
attr_value_t (*value)(conf_object_t *obj, int idx);
attr_value_t (*properties)(conf_object_t *obj, int idx);
};
#define PROBE_INDEX_INTERFACE "probe_index"
- Execution Context
- Global Context for all methods.
- Description
- This interface is implemented by the singleton probes
object. The interface is expected to be used by either probe-samplers
(enable, disable or by a probe
which supports caching (get_generation_id).
When a probe-sampler calls the enable method,
caching can start. Caching depends on a generation id, this is
automatically increased by enable.
With caching enabled, probes can return the previous value back,
avoiding expensive calculation, if they are read multiple times
(either directly, or indirectly from other probes). It can also be
used to avoid probe values to return a slightly different value the
next time in the same sample, such as wallclock time.
A probe which wants to use caching needs to call the
get_generation_id method. As long as the generation id is the same
as the last time the probe-value was returned, the same probe-value can be
returned. Otherwise a new value needs to be returned.
Generation id zero, is special, it means that caching is not currently enabled.
When sampling is finished the probe_sampler calls the disable
which will cause the generation id zero to be returned until the
next sample begins again.
SIM_INTERFACE(probe_sampler_cache) {
void (*enable)(conf_object_t *obj);
void (*disable)(conf_object_t *obj);
uint64 (*get_generation)(conf_object_t *obj);
};
#define PROBE_SAMPLER_CACHE_INTERFACE "probe_sampler_cache"
- Execution Context
- Global Context for all methods.
- Description
- This is an optional additional probe interface.
This interface should be implemented to prevent any slowdown or unwanted
side-effects if there are no listener on the probe.
The subscribe() method should increment a reference count on
how many subscribers there are, and do any kind of preparation to
activate the probe when it is being used.
Similarly, the unsubscribe() method should decrement the
reference count and disable the feature when there is no subscribers
left.
The num_subscribers() method should return the current
reference count.
SIM_INTERFACE(probe_subscribe) {
void (*subscribe)(conf_object_t *obj);
void (*unsubscribe)(conf_object_t *obj);
int (*num_subscribers)(conf_object_t *obj);
};
#define PROBE_SUBSCRIBE_INTERFACE "probe_subscribe"
- Execution Context
- Global Context for all methods.
- Description
- The
recorder_v2 interface is implemented by the recorder, and
can be used by any object interacting with the outside world in order to
make re-runs of the same simulation behave identically. This is a
requirement for reverse execution to work. Objects using this interface must
implement the recorded interface themselves.
An object uses it by calling the record method with itself and
the data it wishes to record as parameters. The recorder will then save
the data and call the input method in the recorded
interface on the object.
The playback method returns whether the recorder is currently
playing back recorded data. It may be used by the object to determine if
output to the outside world should be dropped or not.
SIM_INTERFACE(recorder_v2) {
void (*record)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL sender, bytes_t data);
bool (*playback)(conf_object_t *NOTNULL obj);
};
#define RECORDER_V2_INTERFACE "recorder_v2"
The recorded interface is implemented by objects that wish to
use the recorder_v2 interface.
The input method is called with data that has been recorded.
The playback parameter is set if the data came from a
previous recording, and clear if the data came directly from a call to
record in recorder_v2 with live data.
SIM_INTERFACE(recorded) {
void (*input)(conf_object_t *NOTNULL obj, bytes_t data, bool playback);
};
#define RECORDED_INTERFACE "recorded"
- Execution Context
- Cell Context for all methods.
- Description
- This is an optional CPU interface
allowing the execution to break upon any register change, both explicit by
the software and implicit changes by the model itself.
The add_breakpoint function adds a new breakpoint. The
reg_name is the register name. When register becomes the
value, simulator will stop. The break_upon_change
means whether simulator should stop upon change of the register value. In
this case, value is not used. The mask can be used
when only certain bits are of interest.
The remove_breakpoint function removes a breakpoint with a given
id. If the id is -1, then all breakpoints are removed.
The function get_breakpoints returns a list of defined
breakpoints. Each breakpoint in the list is described by a tuple:
(breakpoint_id, register_name, break_value, mask). If the breakpoint is
triggered upon every register value change, then break_value is NIL.
SIM_INTERFACE(register_breakpoint) {
int (*add_breakpoint)(conf_object_t *obj, const char *reg_name,
uint64 value, uint64 mask,
bool break_upon_change);
bool (*remove_breakpoint)(conf_object_t *obj, int id);
attr_value_t (*get_breakpoints)(conf_object_t *obj);
};
#define REGISTER_BREAKPOINT_INTERFACE "register_breakpoint"
- Execution Context
- Global Context for all methods.
- Description
- The
screenshot interface facilitates storing screenshots. It
is implemented by the graphics console.
All screenshots store current screen data, using 24-bit RGB pixel format.
SIM_INTERFACE(screenshot) {
bool (*save_png)(conf_object_t *NOTNULL obj, const char *filename);
bool (*save_bmp)(conf_object_t *NOTNULL obj, const char *filename);
};
#define SCREENSHOT_INTERFACE "screenshot"
- Execution Context
- Global Context
for all methods
- Description
- The
serial_console_frontend interface can be implemented by
devices that want to retrieve the character stream passing through the text
console. Objects implementing this interface can be attached to a text
console and will receive output in the same way as a telnet connection.
SIM_INTERFACE(serial_console_frontend) {
void (*write)(conf_object_t *NOTNULL obj, uint8 value);
};
#define SERIAL_CONSOLE_FRONTEND_INTERFACE "serial_console_frontend"
- Execution Context
- Cell Context
- Description
- The table interface can be implemented by objects holding data
which can be presented in a table by the user interface (through
Simics CLI command outputs, Eclipse etc.)
By properly implementing the table interface, less object specific code
is needed to provide the data to the user. Generic Simics commands
(associated with the table interface) allows the data to sorted on
the desired column and printed in a uniform way.
Similarly, the data can be exported to a comma separated value (.csv)
file, making it possible to process the result in a spreadsheet program.
The data() method returns the data as an
attr_value_t array where the outer list contains each row and
the inner list contains the columns for that row. The number of columns in
each row must be exactly the same. The data only holds the actual data, not
the headers for each column, which instead is specified in the
properties() method. The data can be unsorted, it is up to the
user of the interface to sort it in a suitable way.
The data itself is sufficient for producing a table, but to customize
the table layout the properties method can return hints on
how the table should be presented more in detail. For example, specifying
which column the table should be sorted on by default, or if a column
preferably should be printed with hexadecimal numbers instead of decimals.
In addition, the properties also contains the name of the columns
as well as additional meta-data such as what each column represents, or
what the entire table represents.
The properties also returns an attr_value_t type
as a list of key/value pairs. Thus, each list-entry should be exactly
two elements long, but the value part can itself be a new list of key/value
pairs for some keys.
The table property keys are of table_key_t type:
typedef enum {
/* Table property keys */
Table_Key_Name = 1,
Table_Key_Description,
Table_Key_Default_Sort_Column,
Table_Key_Columns,
Table_Key_Extra_Headers,
Table_Key_Stream_Header_Repeat,
/* Additional properties might be added in the future.
Thus, unknown values should be silently ignored. */
} table_key_t;
This is the definition for each table property:
Table_Key_Name String- A short description of what the table represents.
Table_Key_Description String- A longer description what the table represents.
Table_Key_Default_Sort_Column String- References the Column_Key_Name (inside the Table_Key_Columns) to tell
which column that should be used when sorting the table by
default. If the Column_Key_Name contains new-line characters,
replace those with spaces. If not specified, the table will
be unsorted by default.
- In addition to the column-headers printed, this property allows
additional header rows to be presented before the column headers. These
additional header rows can span over multiple columns, providing additional
explanation and grouping of columns.
The format is: list of additional header rows, each identified as a
Extra_Header_Key_Row.
Each row is defined by a list of the header-elements where each element
is a list of the header's key/value pair properties.
The header property keys are of extra_header_key_t type,
this is the definition for each extra header property:
typedef enum {
/* Header property keys */
Extra_Header_Key_Row = 2000,
Extra_Header_Key_Name,
Extra_Header_Key_Description,
Extra_Header_Key_First_Column,
Extra_Header_Key_Last_Column,
} extra_header_key_t;
- Identifies a new header row.
- The name printed for the extra header element.
- Optional additional text describing the header.
Extra_Header_Key_First_Column String- A reference to the column the additional header spans from.
Extra_Header_Key_Last_Column String- A reference to the column the additional header spans to.
If there is only one header element on a row, and neither
Extra_Header_Key_First_Column and
Extra_Header_Key_Last_Column are set, the header will span the
entire table, even if additional columns has been added by the system. In
all other cases first/last column always needs to be specified.
Table_Key_Columns List of columns, with key/value pairs
- A list of the columns, where each element consists of key/value pairs
defining each column with various properties.
The column properties are named with Column_Key_* which are listed below.
The list size should match the number of columns in the data. List item 1,
represents key/value definitions for column 1 etc.
The column property keys are of column_key_t type:
typedef enum {
/* Column property keys */
Column_Key_Name = 1000, /* Other number series than table-keys */
Column_Key_Description,
Column_Key_Alignment,
Column_Key_Int_Radix,
Column_Key_Float_Percent,
Column_Key_Float_Decimals,
Column_Key_Sort_Descending,
Column_Key_Hide_Homogeneous,
Column_Key_Generate_Percent_Column,
Column_Key_Generate_Acc_Percent_Column,
Column_Key_Footer_Sum,
Column_Key_Footer_Mean,
Column_Key_Int_Grouping,
Column_Key_Int_Pad_Width,
Column_Key_Metric_Prefix,
Column_Key_Binary_Prefix,
Column_Key_Time_Format,
Column_Key_Unique_Id,
Column_Key_Width,
Column_Key_Word_Delimiters,
/* Additional properties might be added in the future.
Thus, unknown values should be silently ignored. */
} column_key_t;
This is the definition for each column property:
Column_Key_Name String- The name for the column, displayed on the first row of the table.
Preferably these should be as short as possible while still being
descriptive.
It is possible to break longer strings with a newline character (\n)
Column_Key_Description String- A longer descriptive text describing the column content.
Column_Key_Alignment String: ["left", "right", "center"]
- Specifies if the column data should be aligned to the left, right
or centered for the entire table data. If not specified strings are
left-aligned and numbers right-aligned.
Column_Key_Word_Delimiters String- Overrides the default set of character that will be used for word
wrapping of long lines. Default is
" -_:,.". Column_Key_Int_Radix Integer: [2,10,16]]- Specifies the default radix which should be used for when displaying
integers numbers, 2 means binary, 10 decimal and 16 hexadecimal.
If not specified, the integers will be displayed in the default radix,
selectable by the output-radix command.
Column_Key_Int_Grouping Boolean- If False, the current user preferences for integer grouping will be
ignored. For example, instead of 12_345 the output will read 12345. If not
specified, default grouping is respected. Grouping is set by the
output-radix command.
Column_Key_Pad_Width Integer- Zero-extends values up to N characters. This allows similar width of
the column data regardless of the value in each cell. For example,
with hexadecimal output and 64-bits value printed, the column might
be easier to read with a pad-width of 16.
If not specified, the default size used 1 (no-padding).
Column_Key_Float_Percent Boolean- If True, any float data in the column will be printed as a
percent value. For example, 0.1234 will be printed as 12.34%.
Column_Key_Float_Decimals Integer- Specifies how many decimal digit that should be printed for
any floating point values in the column. If not specified 2 decimals
are printed by default.
Column_Key_Metric_Prefix String- A metric prefix
(m, µ, n, p, f, a, z, y, k, M, G, T, P, E, Z, Y) will be added to the value
and the value will be adjusted accordingly. If the string is non-empty the
string will be interpreted as a unit that will be added after the prefix for
each value.
Column_Key_Binary_Prefix String- A binary prefix
(ki, Mi, Gi, Ti, Pi, Ei, Zi, Yi) will be added to the value
and the value will be adjusted accordingly. If the string is non-empty the
string will be interpreted as a unit that will be added after the prefix for
each value.
Column_Key_Time_Format Boolean- If True
the value (in seconds) will be formatted as
HH:MM:SS.ss,
where only the used parts are shown.
The number of seconds decimals formatted is can be controlled by
Column_Key_Float_Decimals property.
To compact the width, decimals are dropped when hours are displayed.
Column_Key_Unique_Id String- If the same name is set for multiple columns in a table, this
property sets a unique name for a specific column, needed when
referencing the column from extra headers.
Column_Key_Sort_Descending Boolean- If True, specifies if a column should be sorted with the
highest values first. If not specified, this is automatically
set to True for any numbers and False for other types.
Column_Key_Hide_Homogeneous Integer/Float/String- If this property is specified and the column consists entirely of the
given data, the column will not be shown. For example, if the table has a
column which only consists of empty strings (""), the column can be
discarded from the resulting table.
Column_Key_Footer_Sum Boolean- If True, all columns values are summed up and displayed in
a footer row, below the actual table.
Column_Key_Footer_Mean Boolean- If True, an arithmetic mean of the column values are calculated
and displayed in a footer row, below the actual table.
Column_Key_Generate_Percent_Column
List of key/value pairs for new column.- If this property is set, an additional column will be created
(to the right of this column) showing the percent values for each row.
The list of key/value pairs allows to the created column to be
customized, however just giving an empty list should give
understandable default values.
Column_Key_Generate_Acc_Percent_Column
List of key/value pairs for new column.- If this property is set, an additional column will be created
(to the right of this column) showing the accumulated percent values for
each row.
The list of key/value pairs allows to the created column to be
customized, however just giving an empty list should give
understandable default values.
SIM_INTERFACE(table) {
/* Returns all rows and columns in the following format:
[[[i|f|s|o|n*]*]] where the outer list is the row
and the inner list is the data for each column. */
attr_value_t (*data)(conf_object_t *obj);
/* Defines the table structure and meta-data for the table
using a list of key/value pairs.
[[[ia]*]*] where the integer is the key taken from the
table_properties_t. The value is key-specific. */
attr_value_t (*properties)(conf_object_t *obj);
};
#define TABLE_INTERFACE "table"
- Execution Context
- Global Context for all methods.
- Description
- The
telnet_connection_v2 interface is used to control the text
console telnet server.
The text console has a built-in telnet server.
The listening method indicates whether the server is listening
for connections.
The connected method indicates whether there is a connected
telnet client.
The disconnect method forcibly disconnects any connected client.
SIM_INTERFACE(telnet_connection_v2) {
bool (*listening)(conf_object_t *NOTNULL obj);
bool (*connected)(conf_object_t *NOTNULL obj);
void (*disconnect)(conf_object_t *NOTNULL obj);
};
#define TELNET_CONNECTION_V2_INTERFACE "telnet_connection_v2"
- Execution Context
- Global Context
for all methods
- Description
- The
vnc_server_v2 interface is used to control the graphics
console VNC server.
The graphics console has a built-in VNC server, supporting any number of
connected clients.
The listening method indicates whether the server is listening
for connections.
The num_clients method returns the number of connected clients.
The disconnect method forcibly disconnects any connected client.
SIM_INTERFACE(vnc_server_v2) {
bool (*listening)(conf_object_t *NOTNULL obj);
int (*num_clients)(conf_object_t *NOTNULL obj);
void (*disconnect)(conf_object_t *NOTNULL obj);
};
#define VNC_SERVER_V2_INTERFACE "vnc_server_v2"
- Execution Context
- Global Context
for all methods
This chapter contains all the types and functions provided by the
link library. Please see the Link Library Programming Guide for
more information about the link library and how it works.
- NAME
-
SIMLINK_config_remove_value — remove a link configuration parameter
- SYNOPSIS
-
void
SIMLINK_config_remove_value(conf_object_t *link, const char *key);
- DESCRIPTION
-
Make sure that all link objects representing link in the
simulation receive a configuration message to remove the configuration
parameter key.
Note that this function may delay the transmission if it is not possible
to send the configuration message yet. The message will be buffered and
send when possible. The ordering of configuration messages is kept when
buffering them.
All link objects representing link in the simulation will
be called via the remove_config_value() function declared in
link_type_t, including the one initiating the message.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link, where the ID of the endpoints
present on the link is kept as a configuration parameter:
static void
ser_link_ep_pre_delete_instance(conf_object_t *ep)
{
char ep_id[19];
snprintf(ep_id, sizeof(ep_id), "ep%llx", SIMLINK_endpoint_id(ep));
SIMLINK_config_remove_value(SIMLINK_endpoint_link(ep), ep_id);
SIMLINK_endpoint_disconnect(ep);
}
- SEE ALSO
-
SIMLINK_config_update_value, link_type_t
- NAME
-
SIMLINK_config_update_value — update a link configuration parameter
- SYNOPSIS
-
void
SIMLINK_config_update_value(conf_object_t *link, const char *key,
const frags_t *value);
- DESCRIPTION
-
Make sure that all link objects representing link in the
simulation will receive a configuration message for the new
value of the configuration parameter
key. Both key and value are
completely link-specific and transported as-is to all objects.
Note that this function may delay the transmission if it is not possible
to send the configuration message yet. The message will be buffered and
send when possible. The ordering of configuration messages is kept when
buffering them.
All link objects representing link in the simulation will
be called via the update_config_value() function declared in
link_type_t, including the one initiating the message.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ethernet_switch, where the ID of all snooper
endpoints present on the link are sent as a configuration parameter so
they are included even when a packet can be sent directly to the
receiver.
static void
snoop_ep_finalize_instance(conf_object_t *ep)
{
ep_finalize_instance(ep);
/* Tell all endpoints that there's a new snoop in town. */
char ep_id[17];
snprintf(ep_id, sizeof(ep_id), "%llx", SIMLINK_endpoint_id(ep));
frags_t value;
frags_init(&value); /* empty value, just to put the
key in the database */
SIMLINK_config_update_value(
SIMLINK_endpoint_link(ep), ep_id, &value);
}
- SEE ALSO
-
SIMLINK_config_remove_value, link_type_t
- NAME
-
SIMLINK_endpoint_clock — return endpoint's clock
- SYNOPSIS
-
conf_object_t *
SIMLINK_endpoint_clock(const conf_object_t *ep_obj);
- DESCRIPTION
-
Return the endpoint ep's associated clock object. It will
be either the clock object corresponding to the device connected to the
endpoint, or the clock chosen when using the endpoint for snooping.
- RETURN VALUE
-
The associated clock object. This function might return
NULL if the device associated to an endpoint does not
have its queue attribute set. This indicates a configuration problem, as
the device would be unable to send or receive link messages.
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIMLINK_endpoint_device
- NAME
-
SIMLINK_endpoint_dev_name — return the name of the device or snooper to which an endpoint
is connected
- SYNOPSIS
-
const char *
SIMLINK_endpoint_dev_name(const conf_object_t *ep_obj, buffer_t scratch);
- DESCRIPTION
-
Return the name of the device or snooper to which the endpoint
ep is connected. This function takes an additional
scratch parameter that is meant to provide space for
putting together the answer when necessary, without allocating any
memory. If scratch is used by
SIMLINK_endpoint_dev_name() but is not long enough, the name
will be truncated.
This function is provided for logging purposes.
- RETURN VALUE
-
The name of the device or snooper the endpoint is
connected to
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from ethernet_hub, to print the name of the
device or snooper to which a frame is delivered:
#define BUFFER_T(buf) (buffer_t){ .len = sizeof(buf), .data = buf }
static void
deliver_hub(conf_object_t *ep, const link_message_t *msgdata)
{
uint8 buf[1000];
SIM_LOG_INFO(3, ep, 0, "delivering to %s",
SIMLINK_endpoint_dev_name(ep, BUFFER_T(buf)));
- SEE ALSO
-
SIMLINK_endpoint_is_device, SIMLINK_endpoint_device
- NAME
-
SIMLINK_endpoint_device — return the device to which an endpoint is connected
- SYNOPSIS
-
conf_object_t *
SIMLINK_endpoint_device(const conf_object_t *ep_obj);
- DESCRIPTION
-
Return the device to which the endpoint ep is connected. If
the endpoint is not connected to a device, this function will trigger an
assertion failure. This can be checked with
SIMLINK_endpoint_is_device().
- RETURN VALUE
-
The device to which the endpoint is connected
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from datagram_link:
static void
deliver(conf_object_t *ep, const link_message_t *lm)
{
const datagram_link_message_t *m =
(const datagram_link_message_t *)lm;
conf_object_t *dev = SIMLINK_endpoint_device(ep);
const char *port = SIMLINK_endpoint_port(ep);
const datagram_link_interface_t *dli =
SIM_c_get_port_interface(dev, "datagram_link", port);
if (dli)
dli->receive(dev, m->payload);
else
SIM_LOG_ERROR(ep, 0, "Device does not implement"
" datagram_link interface");
}
- SEE ALSO
-
SIMLINK_endpoint_is_device,
SIMLINK_endpoint_dev_name
- NAME
-
SIMLINK_endpoint_disconnect — disconnect an endpoint object
- SYNOPSIS
-
void
SIMLINK_endpoint_disconnect(conf_object_t *ep_obj);
- DESCRIPTION
-
Disconnect the endpoint object ep_obj from its link. This
function is intended to be called in the pre_delete_instance()
method of an endpoint class. It should never be called in other
circumstances, as endpoint objects should not be reused. Note
that once the endpoint has been disconnected, it cannot be used for calls
to Link Library API functions that takes an endpoint as argument.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
static void
ser_link_ep_pre_delete_instance(conf_object_t *ep)
{
char ep_id[19];
snprintf(ep_id, sizeof(ep_id), "ep%llx", SIMLINK_endpoint_id(ep));
SIMLINK_config_remove_value(SIMLINK_endpoint_link(ep), ep_id);
SIMLINK_endpoint_disconnect(ep);
}
- NAME
-
SIMLINK_endpoint_finalize — finalize an endpoint object
- SYNOPSIS
-
void
SIMLINK_endpoint_finalize(conf_object_t *ep_obj);
- DESCRIPTION
-
Finalize the endpoint object ep_obj. This function is
intended to be called in the finalize_instance() method of an
endpoint class.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
static void
ser_link_ep_finalize_instance(conf_object_t *ep)
{
SIMLINK_endpoint_finalize(ep);
}
- SEE ALSO
-
SIMLINK_endpoint_init
- NAME
-
SIMLINK_endpoint_id — return endpoint's ID
- SYNOPSIS
-
uint64
SIMLINK_endpoint_id(const conf_object_t *ep);
- DESCRIPTION
-
Return the endpoint ep's ID.
- RETURN VALUE
-
The endpoint ID
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
In ser_link, the endpoints IDs are kept as configuration
values so they are known in all link objects:
static void
ser_link_ep_pre_delete_instance(conf_object_t *ep)
{
char ep_id[19];
snprintf(ep_id, sizeof(ep_id), "ep%llx", SIMLINK_endpoint_id(ep));
SIMLINK_config_remove_value(SIMLINK_endpoint_link(ep), ep_id);
SIMLINK_endpoint_disconnect(ep);
}
- SEE ALSO
-
SIMLINK_find_endpoint_by_id
- NAME
-
SIMLINK_endpoint_init — initialize an endpoint object
- SYNOPSIS
-
void
SIMLINK_endpoint_init(conf_object_t *obj, bool snoop);
- DESCRIPTION
-
Initialize the endpoint object obj. Whether the endpoint is
connected to a device or a snooper function is determined by the
snoop parameter. This function is intended to be called in
the init_object() method of an endpoint class.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from datagram_link:
static void *
datagram_link_endpoint_init_object(conf_object_t *obj, void *data)
{
datagram_link_endpoint_t *dlep =
(datagram_link_endpoint_t *)obj;
SIMLINK_endpoint_init(&dlep->obj, false);
return dlep;
}
- SEE ALSO
-
SIMLINK_register_endpoint_class, SIMLINK_register_snoop_endpoint_class,
SIMLINK_endpoint_finalize
- NAME
-
SIMLINK_endpoint_is_device — return whether an endpoint is connected to a device
- SYNOPSIS
-
bool
SIMLINK_endpoint_is_device(const conf_object_t *ep);
- DESCRIPTION
-
Return whether the endpoint ep is connected to a device
(as opposed to a link snooper).
- RETURN VALUE
-
true if the endpoint is connected
to a device, false otherwise
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from ethernet_switch, where frames are delivered
either to a device endpoint or to a snoop endpoint, using different
methods:
static void
switch_deliver_frame(conf_object_t *link, conf_object_t *ep,
vlan_tag_t vlan_tag, uint64 src_epid,
const frags_t *frame)
{
eth_frame_crc_status_t crc_status = Eth_Frame_CRC_Match;
if (SIMLINK_endpoint_is_device(ep)) {
switch_ep_t *swep = (switch_ep_t *)ep;
if (frags_len(frame) > 12) {
uint8 src_mac[6];
frags_extract_slice(frame, src_mac, 6, 6);
learn(link, swep, vlan_tag, src_mac, src_epid);
}
swep->cep.ifc->frame(SIMLINK_endpoint_device(ep), frame,
crc_status);
} else {
snoop_ep_t *snoop = (snoop_ep_t *)ep;
deliver_to_snoop(snoop->snoop_fun, snoop->user_data,
SIMLINK_endpoint_clock(ep), frame,
crc_status);
}
}
- SEE ALSO
-
SIMLINK_endpoint_device, SIMLINK_endpoint_port
- NAME
-
SIMLINK_endpoint_link — return endpoint's link
- SYNOPSIS
-
conf_object_t *
SIMLINK_endpoint_link(const conf_object_t *ep);
- DESCRIPTION
-
Return the link object to which the endpoint ep is
connected.
- RETURN VALUE
-
The link object
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
In ser_link, an endpoint needs to check the maximum size
of its buffer by querying its link object:
static void
deliver(conf_object_t *ep, const link_message_t *msgd)
{
ser_link_endpoint_t *slep = (ser_link_endpoint_t *)ep;
ser_link_impl_t *slink = (ser_link_impl_t *)SIMLINK_endpoint_link(ep);
ser_link_message_t *msg = (ser_link_message_t *)msgd;
switch (msg->msgtype) {
case MSG_Char:
- NAME
-
SIMLINK_endpoint_port — return the device's port to which an endpoint is connected
- SYNOPSIS
-
const char *
SIMLINK_endpoint_port(const conf_object_t *ep_obj);
- DESCRIPTION
-
Return the device's port to which the endpoint ep is
connected. If the endpoint is not connected to a device, this function
will trigger an assertion failure. This can be checked with
SIMLINK_endpoint_is_device().
The port returned might be NULL, which means that the
device is implementing a classic interface rather than a port interface.
- RETURN VALUE
-
The device's port to which the endpoint is
connected, or
NULL if no port is used
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from ser_link, where a pointer to the interface
to call for delivery is kept in the endpoint structure:
static void
ser_link_ep_finalize_instance(conf_object_t *ep)
{
SIMLINK_endpoint_finalize(ep);
}
- SEE ALSO
-
SIMLINK_endpoint_is_device,
SIMLINK_endpoint_device
- NAME
-
SIMLINK_finalize — finalize a link object
- SYNOPSIS
-
void
SIMLINK_finalize(conf_object_t *obj);
- DESCRIPTION
-
Finalize the link object obj. This function is intended to
be called in the finalize_instance() method of a link class.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
static void
datagram_link_finalize_instance(conf_object_t *obj)
{
SIMLINK_finalize(obj);
}
- SEE ALSO
-
SIMLINK_init
- NAME
-
SIMLINK_find_endpoint_by_id — return an endpoint object given its ID
- SYNOPSIS
-
conf_object_t *
SIMLINK_find_endpoint_by_id(conf_object_t *link, uint64 id);
- DESCRIPTION
-
Return the endpoint object with the ID id if the endpoint
is connected to the link link, or
NULL
otherwise.
- RETURN VALUE
-
Endpoint object, or
NULL if not
found
- EXECUTION CONTEXT
-
Cell Context
- SEE ALSO
-
SIMLINK_endpoint_id
- NAME
-
SIMLINK_init — initialize a link object
- SYNOPSIS
-
void
SIMLINK_init(conf_object_t *obj, const link_type_t *type);
- DESCRIPTION
-
Initialize the link object obj. The link specific functions
that will be called from the link library are gathered in the
link_type_t type argument. This function is
intended to be called in the init_object() method of a link.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
static const link_type_t ser_link_type = {
.msg_to_attr = msg_to_attr,
.msg_from_attr = msg_from_attr,
.free_msg = free_message,
.marshal = marshal,
.unmarshal = unmarshal,
.deliver = deliver,
.update_config_value = link_config_value_updated,
.remove_config_value = link_config_value_removed,
.device_changed = ser_link_ep_device_changed
};
static conf_object_t *
ser_link_alloc_object(void *arg)
{
ser_link_impl_t *slink = MM_ZALLOC(1, ser_link_impl_t);
return &slink->obj;
}
static void *
ser_link_init_object(conf_object_t *obj, void *arg)
{
ser_link_impl_t *slink = (ser_link_impl_t *)obj;
SIMLINK_init(&slink->obj, &ser_link_type);
slink->buffer_size = 10; /* a reasonable default value? */
return obj;
}
- SEE ALSO
-
SIMLINK_register_class, SIMLINK_finalize, link_type_t
- NAME
-
SIMLINK_init_library — initialize the link library
- SYNOPSIS
-
void
SIMLINK_init_library();
- DESCRIPTION
-
Initialize the link library. This function is meant to be called in the
init_local() function of a module linked to the library.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from datagram_link:
void
init_local()
{
/* The link library must always be initialised first. */
SIMLINK_init_library();
- NAME
-
SIMLINK_init_message — initialize a link message
- SYNOPSIS
-
void
SIMLINK_init_message(link_message_t *msg);
- DESCRIPTION
-
Initialize the generic part of a link message.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from datagram_link:
static link_message_t *
new_datagram_message(const uint8 *data, size_t len)
{
datagram_link_message_t *m = MM_MALLOC(1, datagram_link_message_t);
SIMLINK_init_message(&m->common);
uint8 *d = MM_MALLOC(len, uint8);
memcpy(d, data, len);
m->payload = (bytes_t){.data = d, .len = len};
return &m->common;
}
- SEE ALSO
-
link_type_t
- NAME
-
SIMLINK_pre_delete — clean-up before link deletion
- SYNOPSIS
-
void
SIMLINK_pre_delete(conf_object_t *obj);
- DESCRIPTION
-
Performs clean-up operations before a link object can be safely
deleted. This function is intended to be called in the
pre_delete_instance() method of a link class.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
static void
ser_link_pre_delete_instance(conf_object_t *obj)
{
SIMLINK_pre_delete(obj);
}
- NAME
-
SIMLINK_register_class — register a link class
- SYNOPSIS
-
void
SIMLINK_register_class(conf_class_t *cls);
- DESCRIPTION
-
Complete the class cls with the necessary attributes and
interfaces to be a usable link class. This function is meant to be called
after cls has been obtained from
SIM_register_class.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
void
init_local()
{
SIMLINK_init_library();
const class_data_t link_cls_funcs = {
.alloc_object = ser_link_alloc_object,
.init_object = ser_link_init_object,
.finalize_instance = ser_link_finalize_instance,
.pre_delete_instance = ser_link_pre_delete_instance,
.delete_instance = ser_link_delete_instance,
.class_desc = "model of serial link",
.description = "Serial link"
};
conf_class_t *link_cls = SIM_register_class("ser-link-impl",
&link_cls_funcs);
SIMLINK_register_class(link_cls);
SIM_register_typed_attribute(
link_cls, "buffer_size", get_link_buffer_size, NULL,
set_link_buffer_size, NULL, Sim_Attr_Optional, "i", NULL,
"The number of characters that the link may buffer. Must"
" be at least one.");
const class_data_t ep_cls_funcs = {
.alloc_object = ser_link_ep_alloc_object,
.init_object = ser_link_ep_init_object,
.finalize_instance = ser_link_ep_finalize_instance,
.pre_delete_instance = ser_link_ep_pre_delete_instance,
.delete_instance = ser_link_ep_delete_instance,
.class_desc = "serial link endpoint",
.description = "Serial link endpoint"
};
conf_class_t *ep_cls = SIM_register_class("ser-link-endpoint",
&ep_cls_funcs);
SIMLINK_register_endpoint_class(ep_cls, "[s]|[si]");
- SEE ALSO
-
SIMLINK_init, SIMLINK_finalize
- NAME
-
SIMLINK_register_endpoint_class — register a link endpoint class
- SYNOPSIS
-
void
SIMLINK_register_endpoint_class(conf_class_t *cls, const char *msg_type);
- DESCRIPTION
-
Complete the class cls with the necessary attributes and
interfaces to be a usable link endpoint class. This function is meant to
be called after cls has been obtained from
SIM_register_class.
msg_type is a string defining the type of the attribute
representing a link message, as returned by msg_to_attr() in
link_type_t.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from ser_link:
void
init_local()
{
SIMLINK_init_library();
const class_data_t link_cls_funcs = {
.alloc_object = ser_link_alloc_object,
.init_object = ser_link_init_object,
.finalize_instance = ser_link_finalize_instance,
.pre_delete_instance = ser_link_pre_delete_instance,
.delete_instance = ser_link_delete_instance,
.class_desc = "model of serial link",
.description = "Serial link"
};
conf_class_t *link_cls = SIM_register_class("ser-link-impl",
&link_cls_funcs);
SIMLINK_register_class(link_cls);
SIM_register_typed_attribute(
link_cls, "buffer_size", get_link_buffer_size, NULL,
set_link_buffer_size, NULL, Sim_Attr_Optional, "i", NULL,
"The number of characters that the link may buffer. Must"
" be at least one.");
const class_data_t ep_cls_funcs = {
.alloc_object = ser_link_ep_alloc_object,
.init_object = ser_link_ep_init_object,
.finalize_instance = ser_link_ep_finalize_instance,
.pre_delete_instance = ser_link_ep_pre_delete_instance,
.delete_instance = ser_link_ep_delete_instance,
.class_desc = "serial link endpoint",
.description = "Serial link endpoint"
};
conf_class_t *ep_cls = SIM_register_class("ser-link-endpoint",
&ep_cls_funcs);
SIMLINK_register_endpoint_class(ep_cls, "[s]|[si]");
- SEE ALSO
-
SIMLINK_endpoint_finalize
- NAME
-
SIMLINK_register_snoop_endpoint_class — register a link snoop endpoint class
- SYNOPSIS
-
void
SIMLINK_register_snoop_endpoint_class(conf_class_t *cls);
- DESCRIPTION
-
Complete the class cls with the necessary attributes and
interfaces to be a usable link snoop endpoint class. This function is
meant to be called after cls has been obtained from
SIM_register_class().
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from the new Ethernet links:
void
init_local()
{
SIMLINK_init_library();
init_eth_hub_link();
init_eth_cable_link();
init_eth_switch_link();
init_ethernet_crc_table();
const class_data_t snoop_ep_cls_funcs = {
.alloc_object = snoop_ep_alloc_object,
.init_object = snoop_ep_init_object,
.finalize_instance = ep_finalize_instance,
.pre_delete_instance = snoop_ep_pre_delete_instance,
.delete_instance = snoop_ep_delete_instance,
.description = "Ethernet link snoop endpoint",
.class_desc = "an Ethernet link snoop endpoint",
.kind = Sim_Class_Kind_Pseudo,
};
snoop_ep_cls = SIM_register_class("eth-link-snoop-endpoint",
&snoop_ep_cls_funcs);
SIMLINK_register_snoop_endpoint_class(snoop_ep_cls);
}
- SEE ALSO
-
SIMLINK_endpoint_finalize
- NAME
-
SIMLINK_send_message — send a link message
- SYNOPSIS
-
void
SIMLINK_send_message(conf_object_t *src_ep_obj,
uint64 dst_id, link_message_t *msg);
- DESCRIPTION
-
Send a message msg from the endpoint
src_ep_obj to the destination ID dst_id.
The destination may be any valid endpoint ID on the link or
LINK_BROADCAST_ID, which will send the message to all
endpoints on the link except the sender.
It is important to note that the ownership of the message
msg is passed to the link library when calling
SIMLINK_send_message(). When returning, msg may
have been already deallocated and should not be used anymore.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from datagram_link:
static void
receive(conf_object_t *NOTNULL ep, bytes_t msg)
{
SIMLINK_send_message(ep, LINK_BROADCAST_ID,
new_datagram_message(msg.data, msg.len));
}
- SEE ALSO
-
SIMLINK_send_message_multi, link_message_t, link_type_t
- NAME
-
SIMLINK_send_message_multi — send a link message to multiple recipients
- SYNOPSIS
-
void
SIMLINK_send_message_multi(conf_object_t *src_ep_obj, unsigned num_dsts,
const uint64 *dst_ids, link_message_t *msg);
- DESCRIPTION
-
Send a message msg from the endpoint
src_ep_obj to the destinations IDs dst_ids.
The length of the dst_ids list is provided by
num_dsts. Each destination should be a valid endpoint ID on
the link. It is not allowed to be
LINK_BROADCAST_ID.
It is important to note that the ownership of the message
msg is passed to the link library when calling
SIMLINK_send_message_multi(). When returning,
msg may have been already deallocated and should not be
used anymore.
- RETURN VALUE
-
None
- EXECUTION CONTEXT
-
Cell Context
- EXAMPLE
-
Example from signal_link, which keeps a list of endpoints
to send to and specifically directs its messages to the appropriate
endpoints:
static void
send_message(signal_link_endpoint_t *slep, link_message_t *msg)
{
signal_link_t *slink =
(signal_link_t *)SIMLINK_endpoint_link(&slep->obj);
int num_dsts = ht_num_entries_int(&slink->receivers);
uint64 dst_ids[num_dsts];
memset(dst_ids, 0, num_dsts * sizeof(uint64));
int i = 0;
HT_FOREACH_INT(&slink->receivers, it)
dst_ids[i++] = ht_iter_int_key(it);
SIMLINK_send_message_multi(&slep->obj, num_dsts, dst_ids, msg);
}
- SEE ALSO
-
SIMLINK_send_message, link_message_t, link_type_t
- NAME
-
SIMLINK_snoop_endpoint_create — create a snoop endpoint object
- SYNOPSIS
-
conf_object_t *
SIMLINK_snoop_endpoint_create(conf_class_t *cls, conf_object_t *link,
conf_object_t *clock,
attr_value_t attrs);
- DESCRIPTION
-
This method returns an already created snoop endpoint object. It is meant
to be used when implementing a
snoop_attach interface,
where endpoints can not be created using components as it is usually done.
SIMLINK_snoop_endpoint_create() takes as arguments the class of
the snoop endpoint object cls, the link object
link, and a list of attributes to set, in the same form as
provided to SIM_create_object().
- RETURN VALUE
-
A snoop endpoint object
- EXECUTION CONTEXT
-
Global Context
- EXAMPLE
-
Example from the new Ethernet links:
static conf_object_t *
default_attach_snoop(conf_object_t *obj, conf_object_t *clock,
ethernet_link_snoop_t snoop_fun, lang_void *user_data)
{
common_link_t *clink = (common_link_t *)obj;
attach_snoop_helper(clink, clock);
attr_value_t attrs = SIM_make_attr_list(0);
snoop_ep_t *snoop = (snoop_ep_t *)SIMLINK_snoop_endpoint_create(
snoop_ep_cls, &clink->obj, clock, attrs);
SIM_attr_free(&attrs);
snoop->snoop_fun = snoop_fun;
snoop->user_data = user_data;
return &snoop->cep.obj;
}
- NAME
-
link_message_t
- SYNOPSIS
-
typedef struct link_message link_message_t;
- DESCRIPTION
-
Generic part of a link message. This structure should always be the
first member of the link message data structure, so that the link
library can access the generic part with a simple cast.
- EXAMPLE
-
The datagram_link example defines its link message in
the following way:
typedef struct {
link_message_t common; /* should always be first */
/* The actual data in the message - in our case an allocated
byte string owned by this structure. */
bytes_t payload;
} datagram_link_message_t;
- SEE ALSO
-
link_type_t,
SIMLINK_init_message
- NAME
-
link_type_t
- SYNOPSIS
-
typedef struct {
attr_value_t (*msg_to_attr)(conf_object_t *link,
const link_message_t *msg);
link_message_t *(*msg_from_attr)(conf_object_t *link,
attr_value_t attr);
void (*free_msg)(conf_object_t *link, link_message_t *msg);
void (*marshal)(conf_object_t *link, const link_message_t *msg,
void (*finish)(void *data, const frags_t *msg),
void *finish_data);
link_message_t *(*unmarshal)(conf_object_t *link,
const frags_t *msg);
void (*deliver)(conf_object_t *ep, const link_message_t *msg);
void (*update_config_value)(conf_object_t *link, const char *key,
const frags_t *value);
void (*remove_config_value)(conf_object_t *link, const char *key);
void (*device_changed)(conf_object_t *ep, conf_object_t *old_dev);
} link_type_t;
- DESCRIPTION
-
Functions to be defined by the specific link implementation.
These functions can be classified in four groups:
- Message Links Manipulation
- The first five functions are related to the link-specific
messages.
All five functions can be called in any execution context and should
be thread-safe. They all take the link object as argument, in case it
contains information necessary to perform the operation. As the link
object is shared between the cells in which it is connected, it
should not be modified during execution. Mutable state should be kept
in the endpoint objects instead.
msg_to_attr() transforms the message msg
into an attr_value_t value. It is used to checkpoint
in-flight messages waiting to be delivered. The value returned will
be passed unchanged as argument attr to
msg_from_attr() when loading a checkpoint with pending
link messages. Neither function is expected to return an error,
although msg_from_attr() is allowed to return NULL when
translating a message it does not care to restore. This can be useful
to keep checkpoint compatibility with older versions of the same link
that do not always have the same message protocol.
Using the datagram_link as an example, the
datagram-link message is defined as:
typedef struct {
link_message_t common; /* should always be first */
/* The actual data in the message - in our case an allocated
byte string owned by this structure. */
bytes_t payload;
} datagram_link_message_t;
msg_to_attr() and msg_from_attr() are thus
defined as:
static attr_value_t
msg_to_attr(conf_object_t *link, const link_message_t *lm)
{
const datagram_link_message_t *m =
(const datagram_link_message_t *)lm;
return SIM_make_attr_data(m->payload.len, m->payload.data);
}
static link_message_t *
msg_from_attr(conf_object_t *link, attr_value_t attr)
{
return new_datagram_message(SIM_attr_data(attr),
SIM_attr_data_size(attr));
}
free_msg() is called when the message msg
has been delivered to all its destinations and is no longer
needed. All memory allocated for msg is expected to be
freed, including msg itself. The
datagram_link defines free_msg() as:
static void
free_msg(conf_object_t *link, link_message_t *lm)
{
datagram_link_message_t *m = (datagram_link_message_t *)lm;
MM_FREE((uint8 *)m->payload.data);
m->payload.data = NULL;
MM_FREE(m);
}
marshal() is called when the message msg
should be transmitted over a distributed simulation. Its purpose is
to serialize the message into a frags_t
representation. Rather than returning the marshaled message,
marshal() takes the finish and
finish_data arguments, that it is expected to call
once the message has been marshaled.
The reason behind this mechanism is that it allows
marshal() to perform its operations with a
frags_t variable allocated on the stack, and thus to
skip any heap allocation when sending the message. In case memory was
allocated anyway, it should be freed just after finish
has returned.
static void
marshal(conf_object_t *link, const link_message_t *lm,
void (*finish)(void *data, const frags_t *msg),
void *finish_data)
{
const datagram_link_message_t *m =
(const datagram_link_message_t *)lm;
/* Our message just consists of a byte string,
so this is very easy. */
frags_t buf;
frags_init_add(&buf, m->payload.data, m->payload.len);
finish(finish_data, &buf);
}
unmarshal() does the opposite of marshal(): it
takes a serialized frags_t representation of the message
called data and returns a newly allocated link
message.
static link_message_t *
unmarshal(conf_object_t *link, const frags_t *data)
{
size_t len = frags_len(data);
uint8 bytes[len];
frags_extract(data, bytes);
return new_datagram_message(bytes, len);
}
- Endpoint Configuration
- Link endpoints are created as needed by the link
component. Depending on how they are created, they may not know yet
which device they are connected to, so it might not be possible yet,
for example, to cache the device's communication interface in the
endpoint's finalize() function. Additionally, there are
cases where the device the endpoint talks to may be changed, such as
when inserting a probe object to listen to the traffic.
In all of these cases, the device_changed() callback will
be called when the endpoint's device attribute is changed
and the endpoint has reached to finalize phase. In that
callback, the new device can be obtained via
SIMLINK_endpoint_device() and additional operations, such
as interface caching, can be safely performed. The old device the
endpoint was connected to is provided for convenience as an argument
to device_changed().
Note that if no device related operations are necessary, this
callback may be left unimplemented.
The ser_link implementation of
device_changed is the following:
static void
ser_link_ep_device_changed(conf_object_t *ep, conf_object_t *old_dev)
{
ser_link_endpoint_t *slep = (ser_link_endpoint_t *)ep;
slep->serial_ifc = SIM_c_get_port_interface(
SIMLINK_endpoint_device(ep), SERIAL_DEVICE_INTERFACE,
SIMLINK_endpoint_port(ep));
if (!old_dev) {
char ep_id[19];
snprintf(ep_id, sizeof(ep_id), "ep%llx",
SIMLINK_endpoint_id(ep));
frags_t value;
frags_init(&value);
SIMLINK_config_update_value(SIMLINK_endpoint_link(ep),
ep_id, &value);
}
}
- Message Delivery
- Messages are delivered to the link by calling the
deliver() function. The arguments of deliver()
are the endpoint ep that received the message and the
message msg itself. The implementation of
deliver() is expected to call the correct device's
function to deliver the message.
Note that deliver() can be called in any execution context
and should be thread-safe. The link object is shared between the
cells in which it is connected, and should not be modified during
execution. Mutable state should be kept in the endpoint objects
instead.
The datagram_link implementation of
deliver() is the following:
static void
deliver(conf_object_t *ep, const link_message_t *lm)
{
const datagram_link_message_t *m =
(const datagram_link_message_t *)lm;
conf_object_t *dev = SIMLINK_endpoint_device(ep);
const char *port = SIMLINK_endpoint_port(ep);
const datagram_link_interface_t *dli =
SIM_c_get_port_interface(dev, "datagram_link", port);
if (dli)
dli->receive(dev, m->payload);
else
SIM_LOG_ERROR(ep, 0, "Device does not implement"
" datagram_link interface");
}
- Configuration
- The last two functions of
link_type_t are taking
care of the link configuration itself. In the same way messages needs
to be marshaled when sent over a network, the global link
configuration needs to be agreed upon when running the simulation in
several processes.
update_config_value() is called whenever a configuration
parameter has been added or updated. The configuration parameter's
name is provided as key and its new value as
value, encoded as a frags_t.
remove_config_value() is called whenever the configuration
value key has been removed.
The interpretation of the link configuration messages is link
specific. The only configuration parameter that is defined by the
link library itself is goal_latency. This is handled
entirely internally, although with the same mechanism as exposed
here. Configuration changes are initiated by the link objects
themselves with the Link Library API functions
SIMLINK_config_update_value() and
SIMLINK_config_remove_value().
Note that the link object that initiates the configuration change is
also called back via update_config_value() and
remove_config_value(). Note also that the configuration
changes may be buffered and sent later if they are initiated too soon
for the configuration message to propagate.
Configuration changes should only be initiated while in Global
Context, so the two configuration functions above will only be called
in Global Context. This allows them to modify properties of
the link object itself without needing to care about thread safety.
As an example, here is how ser_link defines these two
functions. The serial link keeps track of all endpoints connected to
it by saving their ID as a configuration parameter. It also uses a
configurable buffer size.
Finally, it is important to note that these two callbacks may be
called from a non-execution thread. They should call the Simics API
only via SIM_thread_safe_callback(). This includes calling
the SIM_log_* functions.
static void
link_config_value_updated(conf_object_t *link, const char *key,
const frags_t *msg)
{
ser_link_impl_t *slink = (ser_link_impl_t *)link;
if (strncmp(key, "ep", 2) == 0) {
uint64 ep_id = strtoull(key + 2, NULL, 16);
SIM_LOG_INFO(4, &slink->obj, 0,
"Add endpoint: 0x%llx", ep_id);
ht_update_int(&slink->endpoints, ep_id, NULL);
} else if (strcmp(key, "buffer_size") == 0) {
slink->buffer_size = frags_extract_be32(msg, 0);
} else {
ASSERT(false);
}
}
static void
link_config_value_removed(conf_object_t *link, const char *key)
{
ser_link_impl_t *slink = (ser_link_impl_t *)link;
if (strncmp(key, "ep", 2) == 0) {
uint64 ep_id = strtoull(key + 2, NULL, 16);
SIM_LOG_INFO(4, &slink->obj, 0,
"Remove endpoint: 0x%llx", ep_id);
ht_remove_int(&slink->endpoints, ep_id);
} else {
ASSERT(false);
}
}
- SEE ALSO
-
link_message_t,
SIMLINK_init
- NAME
-
create_simple — create a simple link component class
- SYNOPSIS
-
create_simple(link_class, endpoint_class, connector_type,
class_desc, basename = None, help_categories = [])
- DESCRIPTION
-
Create a simple link component class based on the following parameters:
- link_class
- Name of the link implementation class
- endpoint_class
- Name of the link endpoint class
- connector_type
- Name of the connector type for component
connections
- class_desc
- Component description
- basename
- Prefix used to create new component names when none
is provided
- RETURN VALUE
-
A new component class from which to inherit
- EXAMPLE
-
from link_components import create_simple
class datagram_link(
create_simple(link_class = 'datagram_link_impl',
endpoint_class = 'datagram_link_endpoint',
connector_type = 'datagram-link',
class_desc = "datagram link",
basename = 'datagram_link')):
"""The datagram link component creates a datagram-link, which is a simple
broadcast bus forwarding messages (as sequences of bytes) from a sender
device to all other devices present of the link. The datagram-link is both
an example of how to build a link with the Simics Link Library, and a
simple broadcast link that can be reused when multi-cell communication
between devices is necessary. Refer to the <cite>Link Library Programming
Guide</cite> for more information."""
- NAME
-
link_component — link components base class
- DESCRIPTION
-
Class from which to inherit when creating a new custom link component.
- EXAMPLE
-
class ethernet_switch(link_components.link_component):
"""Ethernet switch: this component represents a switched Ethernet network,
allowing any number of devices to connect and optimizing the packet routing
according to what is learned about the MAC addresses talking on the link."""
_class_desc = 'an Ethernet switch component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_switch'
def create_unconnected_endpoint(self, cnt):
return create_vlan_switch_endpoint(self.get_slot('link'), None,
None, True)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-switch-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
- NAME
-
add_link_connector — add a new initial connector
- SYNOPSIS
-
add_link_connector(self, slot_template, cnt_tmpl)
- DESCRIPTION
-
Add a new initial connector. The slot_template
argument is the name of the connector in the component. The
cnt_tmpl argument is the template used for the
connector, previously registered with
add_connector_template().
- RETURN VALUE
-
None
- EXAMPLE
-
class ethernet_switch(link_components.link_component):
"""Ethernet switch: this component represents a switched Ethernet network,
allowing any number of devices to connect and optimizing the packet routing
according to what is learned about the MAC addresses talking on the link."""
_class_desc = 'an Ethernet switch component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_switch'
def create_unconnected_endpoint(self, cnt):
return create_vlan_switch_endpoint(self.get_slot('link'), None,
None, True)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-switch-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
- NAME
-
add_link_connector_template — add a link connector template
- SYNOPSIS
-
add_link_connector_template(self, name, type, growing,
create_unconnected_endpoint,
get_check_data = None,
get_connect_data = None,
check = None,
connect = None,
disconnect = None,
allow_new_cnt = lambda: True,
allow_destroy_cnt = lambda: True)
- DESCRIPTION
-
This function registers a new connector template for the component.
From this template, connectors will be created either statically, via
the add_objects() function, or dynamically if requested.
Component templates can be customized through the parameters of
add_link_connector_template():
- name
- is the name of the template, which will be saved in
each connector, so that they can find out from which template they
were created.
- type
- is the connector type.
- growing
- indicates whether the connector is static, or
should grow dynamically as connections are made. Static connectors
must be created in add_objects(), and will act as classic
component connectors. A dynamic connector will make sure that there
is always a free connector of that template available, by increasing
or decreasing the number of connectors of this template in the link.
Note that several templates can have the same connector type. Each
template will make sure that its connectors grow or shrink
separately.
- create_unconnected_endpoint
- is the function to call when
a new endpoint pre-conf-object must be created. This endpoint is not
yet connected to a device.
- get_check_data
- (optional) is called whenever the
standard get_check_data() is called. It may return any
additional data necessary for the check() call. The standard
get_check_data() will already return the endpoint
object.
- get_connect_data
- (optional) is similar to
get_check_data, but for the connect()
call.
- check
- (optional) is called whenever the standard
check() is called. It may return
True
(connection accepted) or False (connection refused).
The standard implementation returns always True. - connect
- (optional) is called whenever the standard
connect() is called. The standard connect()
will set the device attribute in the endpoint. connect may
take any additional action it deems necessary.
- disconnect
- (optional) is called whenever the standard
disconnect() is called. The standard
disconnect() does not do anything as the endpoint object
will be destroyed soon after. disconnect() may take any
additional action for the disconnection to succeed.
- allow_new_nct
- (optional) is used only for growing
connectors. It is called every time a new connection is made to ask
if creating a new empty connector is allowed. It may return
True (new connector allowed) or False
(no new connector). The default function always returns
True (unlimited number of connectors allowed, with
always one free). - allow_destroy_cnt
- (optional) is used only for growing
connectors. It is called every time a connection is severed to ask if
the connector being disconnected should be destroyed. It may return
True (destroy the connector) or False
(let the connector). The endpoint object associated will be
automatically destroyed with the connector, or replaced if the
connector is left. The default function returns always
True (unlimited number of connectors allowed, with
always one free).
- RETURN VALUE
-
The registered connector template
- EXAMPLE
-
class ethernet_cable(link_components.link_component):
"""Ethernet cable: this component represents a two-points Ethernet cable,
allowing two devices to connect to each other."""
_class_desc = 'an Ethernet cable component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_cable'
class connector_count(SimpleAttribute(0, 'i')):
"""Total number of occupied connectors"""
def allow_new_connector(self):
if self.connector_count.val == 2:
# all connectors are occupied
return False
elif self.connector_count.val == 1:
# there is already one free connector
self.connector_count.val += 1
return False
else:
self.connector_count.val += 1
return True
def allow_destroy_connector(self):
if self.connector_count.val == 2:
# two connectors occupied, so let one become free
self.connector_count.val -= 1
return False
else:
# one connector was occupied, one free, so destroy one
self.connector_count.val -= 1
return True
def create_unconnected_endpoint(self, cnt):
return create_cable_endpoint(self.get_slot('link'), None)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'single-ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint,
allow_new_cnt = self.allow_new_connector,
allow_destroy_cnt = self.allow_destroy_connector)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-cable-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
- NAME
-
add_objects — add link object and initial connectors
- SYNOPSIS
-
add_objects(self)
- DESCRIPTION
-
This function should be overridden when inheriting from
link_component. It is expected to create a
pre-conf-object for the link and to add the initial connectors of the
component using link_component.add_link_connector().
add_objects() is only called when creating a component from
scratch; when restoring a checkpoint, objects are assumed to have
already been created.
- RETURN VALUE
-
None
- EXAMPLE
-
class ethernet_switch(link_components.link_component):
"""Ethernet switch: this component represents a switched Ethernet network,
allowing any number of devices to connect and optimizing the packet routing
according to what is learned about the MAC addresses talking on the link."""
_class_desc = 'an Ethernet switch component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_switch'
def create_unconnected_endpoint(self, cnt):
return create_vlan_switch_endpoint(self.get_slot('link'), None,
None, True)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-switch-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
- NAME
-
get_link_object_name — return a unique link object name
- SYNOPSIS
-
get_link_object_name(self)
- DESCRIPTION
-
Return a unique link object name based on the link component name.
This is useful for ensuring that all link components with the same name
in a distributed simulation will indeed represent the same link.
- RETURN VALUE
-
A unique link name
- EXAMPLE
-
class ethernet_switch(link_components.link_component):
"""Ethernet switch: this component represents a switched Ethernet network,
allowing any number of devices to connect and optimizing the packet routing
according to what is learned about the MAC addresses talking on the link."""
_class_desc = 'an Ethernet switch component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_switch'
def create_unconnected_endpoint(self, cnt):
return create_vlan_switch_endpoint(self.get_slot('link'), None,
None, True)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-switch-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
- NAME
-
register_connector_templates — register connector templates
- SYNOPSIS
-
register_connector_templates(self)
- DESCRIPTION
-
This function should be overridden when inheriting from
link_component. It is expected to register the connector
templates that will be used in add_objects(). Unlike
add_objects(), this function is always called when creating
the component, either from scratch or when restoring a checkpoint.
- RETURN VALUE
-
None
- EXAMPLE
-
class ethernet_switch(link_components.link_component):
"""Ethernet switch: this component represents a switched Ethernet network,
allowing any number of devices to connect and optimizing the packet routing
according to what is learned about the MAC addresses talking on the link."""
_class_desc = 'an Ethernet switch component'
_help_categories = ['Networking']
class basename(link_components.link_component.basename):
val = 'ethernet_switch'
def create_unconnected_endpoint(self, cnt):
return create_vlan_switch_endpoint(self.get_slot('link'), None,
None, True)
def register_connector_templates(self):
self.eth_tmpl = self.add_link_connector_template(
name = 'ethernet-link-connector',
type = 'ethernet-link',
growing = True,
create_unconnected_endpoint = self.create_unconnected_endpoint)
def add_objects(self):
self.add_pre_obj_with_name('link', 'eth-switch-link',
self.get_link_object_name(),
goal_latency = self.goal_latency.val,
global_id = self.global_id.val)
self.add_link_connector('device', self.eth_tmpl)
Refer to the Processor Model Integration Guide for
more information.
This section lists the interfaces that can be implemented by the
processor model to enable certain Simics features. They are not required,
but implementing them will allow user defined processor models to
support the same generic feature set as Simics standard processor
models. If you intend to plug your model into an existing
Simics-provided platform, then many of these interfaces are actually
required for such a platform to function.
The processor_info_v2 interface is implemented by
processors models. The interface has processor generic functions
that are architecture independent.
The disassemble function returns the disassemble string for an
instruction at address with opcode according to
instruction_data. The instruction_data is an
attr_value_t value of data type with the bytes of the
opcode. The bytes are in the same order as they are stored in memory. For
VLIW architectures, sub_operation is used to select which
sub-operation to disassemble. The sub-operations start at zero, and a
request for the entire unit including all sub-operations is encoded with
sub-operation -1. A request for a sub-operation that is not present (for
example when sub-operation is neither 0 nor -1 for non-VLIW
architectures) results in the integer part of the return tuple being set to
zero. If successful, the function should return a tuple with the size of the
instruction in bytes and the disassembly string. The disassembly string
should be allocated with MM_MALLOC or similar and is to be freed by the
caller. If more bytes are needed, then the function should indicate that by
returning a negative number in the tuple where the absolute value of the
number is the required number of bytes. The string should be NULL if more
bytes are needed. The implementor of processor_info_v2 is
allowed to request one additional byte at a time until enough bytes are
passed to determine what the instruction is. Illegal instructions should
still result in a valid returned tuple, where the integer part will be used
by the disassemble command to skip that many bytes before disassembling the
next instruction. The address can be used to display absolute
destinations of program counter relative branches.
The set_program_counter function sets the program
counter in the processor. The get_program_counter
function returns the current program counter.
The logical_to_physical function translates a logical
address to a physical address of the type defined by
access_type. The function returns a physical_block_t
struct with valid bit and the address. The
address is valid when the valid bit is not 0. The
logical_to_physical function also returns
block_start and block_end. The start and end
of a block has the same logical to physical transformation as the translated
address. The range is inclusive, so block_end should be the
address of the last byte of the block.
This information can be used to figure out how often the
logical_to_physical function needs to be called. An implementation would
typically return the page start and end here, but it is free to return any
power of 2 sized block as long as it includes the translated address.
The current operating mode of the processor is returned with
get_processor_mode.
The processor can be enabled or disabled with the
enable_processor or disable_processor
functions. The functions should return 0 if the processor
changed from enabled to disabled or from disabled to enabled, and
1 if the processor did not change state. The current state
is returned by the get_enabled function. Enabled or
disabled here refers to the state that the user of the model has
put the processor into. In particular, it is independent of the
power mode of the processor. A processor that has powered down does
not count as disabled in this sense, nor does the
enable_processor wake up a processor that is in
a power-saving sleep state.
The endianness of the processor is returned by the
get_endian function.
The physical memory object is returned by the
get_physical_memory function. The object returned by
get_physical_memory is used to set breakpoints by the
global break command, and to read and write physical
memory through set, get,
load-binary, load-file, and the default
implementation of disassemble. The object returned
implements the memory_space and
breakpoint interfaces. The
memory_space interface for the returned object is
only be used in inquiry mode corresponding to actions by the
simulator itself rather than by the simulated software. An
implementation may return NULL from this method, which will lead to
the command listed above not being supported when such a processor
is selected.
The get_logical_address_width function returns the
number of logical/virtual address bits and the
get_physical_address_width function returns the number
of physical address bits.
The processor architecture is returned by calling the
architecture function. The architecture should be one of
arm, mips32,
mips64, ppc32, ppc64, sparc-v8,
sparc-v9, x86, x86-64, or something else
if none of the listed is a good match.
All functions in the interface are optional. Each function can be
set to NULL if it is not supported.
SIM_INTERFACE(processor_info_v2) {
tuple_int_string_t (*disassemble)(conf_object_t *obj,
generic_address_t address,
attr_value_t instruction_data,
int sub_operation);
void (*set_program_counter)(conf_object_t *obj,
logical_address_t pc);
logical_address_t (*get_program_counter)(conf_object_t *obj);
physical_block_t (*logical_to_physical)(conf_object_t *obj,
logical_address_t address,
access_t access_type);
processor_mode_t (*get_processor_mode)(conf_object_t *obj);
int (*enable_processor)(conf_object_t *obj);
int (*disable_processor)(conf_object_t *obj);
int (*get_enabled)(conf_object_t *obj);
cpu_endian_t (*get_endian)(conf_object_t *obj);
conf_object_t *(*get_physical_memory)(conf_object_t *obj);
int (*get_logical_address_width)(conf_object_t *obj);
int (*get_physical_address_width)(conf_object_t *obj);
const char *(*architecture)(conf_object_t *obj);
};
#define PROCESSOR_INFO_V2_INTERFACE "processor_info_v2"
Note that the original version of this interface
(processor_info) must also be implemented. The only
difference between the two interfaces is that the original version lacks the
get_processor_mode function.
Some commands and features in the CLI use the
processor_cli interface. Those commands will have
limited functionality if the interface is not fully implemented.
The first argument to each function is the object to act on. This object
should implement both the processor_info interface and the
processor_cli interface.
The get_disassembly function is used for the
disassemble command as well as to disassemble the next
instruction to be executed, when control is returned to the CLI prompt. For
most architectures, get_disassembly can be set to NULL, in which
case the command will use other interfaces to provide a generic
disassembly. The get_disassembly function should return a tuple
with the length of the instruction in bytes and the disassembly string. The
addr_prefix parameter selects the address type of the address
parameter, whether it is a physical address ("p"), a linear address ("l") or
a virtual address ("v"), just as returned from
get_address_prefix. The address parameter is the
program counter for the instruction to disassemble. If
print_cpu is non-zero, then the name of the processor should
be included first in the disassembly line. If mnemonic is not
NULL, then it should be output instead of the instruction disassemble. The
mnemonic is used to print exception or interrupt information as returned by
the get_pending_exception_string function.
get_pregs returns the string to output in the CLI for the
print-processor-registers command. The all
parameter is a boolean corresponding to the -all switch to the
print-processor-registers command.
The diff_regs function is used by the stepi
command when the -r flag is used. The
diff_regs function returns a list of register names,
where each register in that list will be read through the
int_register interface before and after an
instruction.
When returning to the CLI prompt, information about the next
instruction or step to execute is printed. Normally, that is the
disassemble of the instruction at the current program counter. The
get_pending_exception_string function is called before
the disassembly to find out if the next step will not be an
instruction, but rather a taken exception or interrupt. The
function should inspect the given cpu (an object
implementing processor_info and
processor_cli) and return NULL if the next step will
be the execution of the instruction at the current program
counter. If the next step will instead be the handling of an
exception or interrupt, then a string saying that should be
returned.
The get_address_prefix function returns a string with
the default address prefix for memory related commands. Simics
defines the generic prefixes "v" for virtual addresses, "l" for
linear addresses, and "p" for physical addresses. The default if
get_address_prefix is NULL is "v" for virtual addresses.
translate_to_physical translates an address to a
physical address. If translate_to_physical is NULL, then
the only allowed address prefixes are "v" (virtual) and "p"
(physical), and the logical_to_physical function in the
processor_info interface will be used to translate
virtual addresses.
SIM_INTERFACE(processor_cli) {
tuple_int_string_t (*get_disassembly)(conf_object_t *obj,
const char *addr_prefix,
generic_address_t address,
bool print_cpu,
const char *mnemonic);
char *(*get_pregs)(conf_object_t *cpu,
bool all);
attr_value_t (*get_diff_regs)(conf_object_t *obj);
char *(*get_pending_exception_string)(conf_object_t *obj);
char *(*get_address_prefix)(conf_object_t *obj);
physical_block_t (*translate_to_physical)(conf_object_t *obj,
const char *prefix,
generic_address_t address);
};
#define PROCESSOR_CLI_INTERFACE "processor_cli"
The processor_gui interface is implemented by
processors that support displays in the Simics native GUI. It is
only registered to indicate support for the displays, and does not
contain any actual functionality.
SIM_INTERFACE(processor_gui) {
void (*dummy)(conf_object_t *obj);
};
#define PROCESSOR_GUI_INTERFACE "processor_gui"
The step interface is typically implemented by
processors, but can be implemented by other objects as well. Its
purpose is to handle step events using a queue.
The current number of steps for the queue is returned
when calling get_step_count.
The post_step function will schedule an event that will
occur after steps (which must be nonnegative)
counted from local current step at
queue. An event previously posted can be removed by
calling cancel_step. The cancel_step function takes a
function pred as argument which is called when a matching
event is found. The event is only removed if pred returns
1. The find_next_step takes the same arguments
as cancel_step but only returns the number of cycles before
the event will occur. The evclass is the event class,
obj is the object posting the event, and
user_data is pointer to data used as a parameter when
calling the callback function defined in the evclass.
If no matching event was found, find_next_step returns
−1.
The events method returns a list of all pending events in
expiration order. Each element is a four-element list containing the event
object, the event class name, the expiration time counted in steps as an
integer and the event description as given by the event class
describe method, or nil for events whose event class do
not define that method.
The advance function will increment the number of steps
for the queue, decrementing the number of steps to the first event
to the value defined by steps. The number of steps remaining
to the next event is returned. It is an error to advance beyond the
next pending event, so the return value is never negative.
The implementor of the step interface can use any
checkpoint representation. The name field in the
event class data structure is unique, and the attribute setter
function for checkpoint restore can use
SIM_get_event_class to get the event class structure
corresponding to an event class name.
SIM_INTERFACE(step) {
pc_step_t (*get_step_count)(conf_object_t *NOTNULL queue);
void (*post_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
pc_step_t steps,
lang_void *user_data);
void (*cancel_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
pc_step_t (*find_next_step)(
conf_object_t *NOTNULL queue,
event_class_t *NOTNULL evclass,
conf_object_t *NOTNULL obj,
int (*pred)(lang_void *data, lang_void *match_data),
lang_void *match_data);
attr_value_t (*events)(conf_object_t *NOTNULL obj);
pc_step_t (*advance)(conf_object_t *queue, pc_step_t steps);
};
#define STEP_INTERFACE "step"
The step_cycle_ratio interface is implemented by
processors that support a changeable ratio between steps and
cycles. The set-step-rate command uses this interface to
set the ratio between steps and cycles.
The set_ratio sets the ratio between steps and
cycles. Note that the introduction of stall cycles can
skew the ratio. The get_ratio simply returns the current
ratio.
The cycles and step arguments must be in the range
[1..128] and cycles must be a power of two. Implementers of this
interface may choose to ignore other values of cycles and
step and may log an error.
typedef struct {
uint32 steps;
uint32 cycles;
} step_cycle_ratio_t;
SIM_INTERFACE(step_cycle_ratio) {
step_cycle_ratio_t (*get_ratio)(conf_object_t *obj);
void (*set_ratio)(conf_object_t *obj, uint32 steps, uint32 cycles);
};
#define STEP_CYCLE_RATIO_INTERFACE "step_cycle_ratio"
The stall interface can be implemented by objects that also
implement the cycle and step interfaces. The
stall interface controls the addition of extra cycles between
steps.
The get_stall_cycles function returns the remaining number of
stall cycles. The object will advance that number of cycles before starting
with the next step.
The set_stall_cycles function is used to change the number of
stall cycles before the next step. It is legal to first call this function
with a large value for cycles and then at a later point reduce the
cycle count is resume execution earlier than indicated by the first call.
The get_total_stall_cycles returns the total accumulated number of
stall cycles.
SIM_INTERFACE(stall) {
cycles_t (*get_stall_cycles)(conf_object_t *obj);
void (*set_stall_cycles)(conf_object_t *obj, cycles_t cycles);
cycles_t (*get_total_stall_cycles)(conf_object_t *obj);
};
#define STALL_INTERFACE "stall"
The int_register
interface is used for access to registers in a processor. It
can be used to access any kind of integer register, not only the
"normal" registers. This includes all kinds of control registers,
hidden registers and anything else that might be useful to access as
a register. The only limitation is that the register value should
be representable as a 64-bit unsigned integer.
This interface can be implemented by other classes than processors,
but it is likely to be found mostly in processors.
Registers are identified by a number, and there are two functions
to translate from register names to register numbers and back. The
translation need not be one-to-one, which means that one register
can have several names. A register name can, however, only
translate to a single register number.
Often, registers are grouped in register banks, where
registers in the bank are numbered from 0 up. Registers in a bank
should have consecutive numbers (unless their numbering is very sparse).
This allows a user to deduce register numbers by calling
get_number for the first register only.
The first register numbers should be used for the general-purpose integer
registers, if possible (so that integer register rN has number N).
Using this interface to read or write registers does not cause any
side effects, such as triggering interrupts or signalling haps.
get_number translates a register name to its number. Returns -1 if
the register does not exist.
get_name translates a register number to its canonical name.
read reads a register value.
write writes a new register value.
all_registers returns a list of all register numbers that can
be used for this object.
register_info returns information about a single register.
The information return depends on the info parameter.
- Sim_RegInfo_Catchable
- Return 1 if
Core_Control_Register_Write and
Core_Control_Register_Read are triggered when this
register is written or read. Return 0 otherwise.
typedef enum {
Sim_RegInfo_Catchable
} ireg_info_t;
SIM_INTERFACE(int_register) {
int (*get_number)(conf_object_t *NOTNULL obj,
const char *NOTNULL name);
const char *(*get_name)(conf_object_t *NOTNULL obj, int reg);
uint64 (*read)(conf_object_t *NOTNULL obj, int reg);
void (*write)(conf_object_t *NOTNULL obj, int reg, uint64 val);
attr_value_t (*all_registers)(conf_object_t *NOTNULL obj);
int (*register_info)(conf_object_t *NOTNULL obj, int reg,
ireg_info_t info);
};
#define INT_REGISTER_INTERFACE "int_register"
SIM_INTERFACE(decoder) {
void (*register_decoder)(conf_object_t *obj,
decoder_t *NOTNULL decoder);
void (*unregister_decoder)(conf_object_t *obj,
decoder_t *NOTNULL decoder);
};
The decoder interface is implemented by processors
that allows connecting user decoders. This allows a user to
implement the semantics of instructions that are not available in
the standard Simics model or change the semantics of instructions
implemented by Simics. This interface replaces
SIM_register_arch_decoder and
SIM_unregister_arch_decoder functions.
The register_decoder function adds a decoder and
unregister_decoder removes a decoder.
The decoder is installed/removed for every object of the same class as the
obj argument which must be the same object from
which the interface was fetched.
When Simics decodes an instruction, it will first see if any
instruction decoders are registered for the current CPU class.
For any decoders it finds, Simics will let it try to decode the
instruction. The decoders are called in order, starting with the
last registered decoder, and if one decoder accepts the instruction,
the rest of the decoders will not be called.
The decoder is specified by the decoder_t data structure that the
user supplies:
typedef struct {
void *user_data;
int (*NOTNULL decode)(uint8 *code,
int valid_bytes,
conf_object_t *cpu,
instruction_info_t *ii,
void *user_data);
tuple_int_string_t (*NOTNULL disassemble)(uint8 *code,
int valid_bytes,
conf_object_t *cpu,
void *user_data);
int (*NOTNULL flush)(instruction_info_t *ii,
void *user_data);
} decoder_t;
The decode function is called to decode an instruction
pointed to by code. The first byte corresponds to
the lowest address of the instruction in the simulated
memory. valid_bytes tells how many bytes can be
read. The CPU is given in the cpu parameter. When
the decoder has successfully decoded an instruction, it should set
the ii_ServiceRoutine, the ii_Arg, and the
ii_Type members of the ii structure (see
below), and returns the number of bytes used in the decoding. If
it does not apply to the given instruction, it should return zero.
If the decoder needs more data than valid_bytes it
should return a negative number corresponding to the total number
of bytes it will need to continue the decoding. The underlying
architecture limits the number of bytes that can be requested,
e.g. no more than 4 bytes can be requested on most RISC
architectures. Simics will call the decoder again when more bytes
are available. This process is repeated until the decoder accepts
or rejects the instruction. A decoder should never request more
data than it needs. For example, if an instructions can be rejected
by looking at the first byte, the decoder should never ask for more
bytes.
The instruction_info_t is defined as follows:
typedef struct instruction_info {
service_routine_t ii_ServiceRoutine;
uint64 ii_Arg;
unsigned int ii_Type;
lang_void *ii_UserData;
logical_address_t ii_LogicalAddress;
physical_address_t ii_PhysicalAddress;
} instruction_info_t;
ii_ServiceRoutine is a pointer to a function that will
be called by Simics every time the instruction is executed. It has
the following prototype:
typedef exception_type_t (*service_routine_t)(conf_object_t *cpu,
uint64 arg,
lang_void *user_data);
The service routine function should return an exception when it is
finished to signal its status. If no exception occurs
Sim_PE_No_Exception should be returned.
See exception_type_t in
src/include/simics/base/memory.h for the different
exceptions available.
A special return value, Sim_PE_Default_Semantics, can be
returned; this signals Simics to run the default semantics for the
instruction. This is useful if the semantics of an instruction
should be changed but the user routine does not want to handle it all
the time.
Note that in a shared memory multiprocessor, the CPU
used in decoding may differ from the CPU that executes the
instruction, since the decoded instructions may be cached.
ii_Arg is the argument arg that will be
passed on to the service routine function. Op code bit-fields for
the instruction such as register numbers or intermediate values can
be stored here. The ii_UserData field can also be used
to pass information to the service routine if more data is needed.
ii_Type is either UD_IT_SEQUENTIAL or
UD_IT_CONTROL_FLOW. A sequential type means that the
instruction does not perform any branches and the update of the
program counter(s) is handled by Simics. In a control flow
instruction on the other hand it is up to the user to set the
program counter(s).
ii_LogicalAddress and ii_PhysicalAddress
holds the logical and physical addresses of the instruction to be
decoded.
The disassemble function is called to disassemble an
instruction. It uses the same code,
valid_bytes, and cpu parameters as
the decode function. If the disassembly is valid, then
the string part of the returned tuple_int_string_t struct
should be a MALLOCed string with the disassembly and the integer
part should be its length in bytes. The caller is responsible for
freeing the disassembly string. The string member should be NULL
and the integer part should be zero if the disassembly is not
valid. If the disassemble function needs more data than
valid_bytes it should return a negative number in
the integer part in the same way as the decode function,
and set the string part to NULL.
The flush function is called to free any memory
allocated when decoding an instruction and any user data associated
with the instruction. It should return zero if it does not
recognize the instruction, and non-zero if it has accepted it.
Usually, the way to recognize if a decoded instruction is the right
one to flush is to compare ii->ii_ServiceRoutine with the
function that was set in the decode function. Note
that the cpu parameter is the processor that caused
the flush. It is more or less an arbitrary processor and should be
ignored.
In addition to the function pointers, the
decoder_t structure contains a
user_data pointer that is passed to all the
functions. This can be used for passing any data to the decoder
functions.
The exception interface is used together with the
Core_Exception hap to enable inspection abilities for triggered
exceptions.
The exception interface is used to translate
exception numbers, as received by the Core_Exception hap, to names,
and vice versa.
The get_number function returns the number associated
with an exception name, or -1 if the no exception with the given
name exist. The get_name returns the name
associated with an exception number. The get_source
function is only used on X86 targets and returns the source for an
exception, as an exception number can be raised from different
sources. The all_exceptions function returns a list of
all exceptions numbers.
The exception numbers are architecturally defined, while their
names are defined by the model.
SIM_INTERFACE(exception) {
int (*get_number)(conf_object_t *NOTNULL obj,
const char *NOTNULL name);
const char *(*get_name)(conf_object_t *NOTNULL obj, int exc);
int (*get_source)(conf_object_t *NOTNULL obj, int exc);
attr_value_t (*all_exceptions)(conf_object_t *NOTNULL obj);
};
#define EXCEPTION_INTERFACE "exception"
Note:
This interface is not supported, and may change in the future.
Get and set current context. The set_current_context function
returns zero if the passed object is not of the context class, otherwise
one is returned.
SIM_INTERFACE(context_handler) {
conf_object_t *(*get_current_context)(conf_object_t *obj);
int (*set_current_context)(conf_object_t *obj, conf_object_t *ctx);
};
#define CONTEXT_HANDLER_INTERFACE "context_handler"
The exec_trace interface is implemented by processor models
that support tracing. A trace listener registers itself with the
register_tracer call. The tracer callback will be
called by the processor model
when each instruction is just about to be executed, passing the
tracer_data as passed to the register_tracer function
in addition to information about the instruction that is executed.
Invoke unregister_tracer with the same two pointers to deregister
the listener.
typedef void (*instruction_trace_callback_t)(lang_void *tracer_data,
conf_object_t *cpu,
linear_address_t la,
logical_address_t va,
physical_address_t pa,
byte_string_t opcode);
The pa parameter to the callback will always be valid, but some
CPU architectures may not support la or va. The
la argument is typically only valid for x86 CPUs. Lastly, the
opcode of the instruction is passed in opcode. The
opcode is passed without endian conversion, meaning that byte X in
opcode corresponds to the byte at pa + X.
SIM_INTERFACE(exec_trace) {
void (*register_tracer)(conf_object_t *NOTNULL cpu_obj,
instruction_trace_callback_t tracer,
lang_void *tracer_data);
void (*unregister_tracer)(conf_object_t *NOTNULL cpu_obj,
instruction_trace_callback_t tracer,
lang_void *tracer_data);
};
#define EXEC_TRACE_INTERFACE "exec_trace"
The opcode_info interface is implemented by
processors that need to communicate information about the encoding
of instructions to the GUI.
The get_opcode_length function returns information about
instruction encoding in the current operating mode of the
processor. The min_alignment field indicates the
smallest allowed alignment of instructions, typically 4 for regular
RISC architectures. The max_length field specifies the
maximum instruction length in bytes. The avg_length is
an approximation of the average instruction size.
typedef struct {
int min_alignment;
int max_length;
int avg_length;
} opcode_length_info_t;
SIM_INTERFACE(opcode_info) {
opcode_length_info_t (*get_opcode_length_info)(conf_object_t *obj);
};
#define OPCODE_INFO_INTERFACE "opcode_info"
Add and remove virtual-address (and, on x86, linear-address) read and
write breakpoints. On every read access that intersects a read
breakpoint's interval, the registered callback function is called with the
object that initiated the read, and the address and size of the read. (The
interval includes both endpoints; first must be less than
or equal to last.) Write breakpoints work exactly the same,
except that the callback is given the actual value being written, not just
its size.
The callback is called before the read or write has taken place, but may
not intervene. If one or more breakpoint callbacks stop the simulation,
the current instruction is completed before the stop takes effect. If more
than one breakpoint is triggered by the same read or write, the
implementation may call their callbacks in any order.
On x86, the Virtual_Breakpoint_Flag_Linear flag causes the
breakpoint to use linear rather than virtual addresses. (Adding a
breakpoint with unsupported flags is illegal.)
Note:
This interface is preliminary and may change without prior notice.
typedef enum {
Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;
SIM_INTERFACE(virtual_data_breakpoint) {
virtual_data_bp_handle_t *NOTNULL (*add_read)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
void (*NOTNULL callback)(
cbdata_call_t data, conf_object_t *NOTNULL initiator,
generic_address_t address, unsigned size),
cbdata_register_t data, uint32 flags);
virtual_data_bp_handle_t *NOTNULL (*add_write)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
void (*NOTNULL callback)(
cbdata_call_t data, conf_object_t *NOTNULL initiator,
generic_address_t address, bytes_t value),
cbdata_register_t data, uint32 flags);
void (*remove)(conf_object_t *NOTNULL obj,
virtual_data_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_DATA_BREAKPOINT_INTERFACE "virtual_data_breakpoint"
Add and remove virtual-address (and, on x86, linear-address) instruction
breakpoints. Every time the processor executes an instruction that
intersects the breakpoint's interval, the callback function is called with
the processor, and the address and size of the instruction. (The interval
includes both endpoints; first must be less than or equal
to last.)
The callback is called before the instruction is executed. If one or more
breakpoint callbacks stop the simulation, the stop takes effect before
the instruction is run. (This means that once the simulation starts
again, the same breakpoints will trigger immediately again. The callback
can use VT_step_stamp to detect re-triggering.) If more than
one breakpoint is triggered by the same instruction, the implementation
may call their callbacks in any order.
If the filter function is non-null and returns false, the callback is not
called. The filter function is supplied with the instruction opcode (the
raw bytes of the instruction) and a processor (which may not be the same
processor that the breakpoint is set on, but is guaranteed to be of the
same class). The filter may base its decision only on the opcode bytes and
the string obtained by asking the processor to disassemble the
instruction; this allows the implementation to cache the result and omit
future calls to the filter function where the opcode and disassembly
string would be the same.
On x86, the Virtual_Breakpoint_Flag_Linear flag causes the
breakpoint to use linear rather than virtual addresses. Calling with
unsupported flags is illegal.
Note:
This interface is preliminary and may change without prior notice.
typedef enum {
Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;
SIM_INTERFACE(virtual_instruction_breakpoint) {
virtual_instr_bp_handle_t *NOTNULL (*add)(
conf_object_t *NOTNULL obj,
generic_address_t first, generic_address_t last,
bool (*filter)(cbdata_call_t filter_data,
conf_object_t *NOTNULL cpu, bytes_t opcode),
cbdata_register_t filter_data,
void (*NOTNULL callback)(
cbdata_call_t callback_data, conf_object_t *NOTNULL cpu,
generic_address_t address, unsigned size),
cbdata_register_t callback_data, uint32 flags);
void (*remove)(conf_object_t *NOTNULL obj,
virtual_instr_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_INSTRUCTION_BREAKPOINT_INTERFACE \
"virtual_instruction_breakpoint"
This interface is used by the Simics debugger to get certain information from
a processor.
The first_child function returns the first description in the
sequence of child descriptions of parent or NULL if parent has no
children. Groups can have both registers and groups as children, registers
can only have fields as children and fields cannot have any children. If
parent is NULL, return the first description in the sequence of top-level
descriptions.
Use next_description to deallocate the previous description and
return the next description in the sequence or NULL if there are no more
descriptions in the current sequence.
The free_description function is used to free the description
without returning the next one in the sequence.
The first_named_value function returns the first named value in
the sequence of named values for parent or NULL if there are no named values
for parent. Only fields and registers can have named values.
Use next_named_value to deallocate the previous named value and
return the next named value or NULL if there are no more named values in this
sequence.
Use free_named_value to free the named value without returning the
next one in the sequence.
The get and set functions are used to get and set the
value of the register. To set the value pass in a bytes_t for the value. The
value passed in must be long enough to contain the full value of the
register. If the bytes_t is too long it will be truncated. To get the value
pass in a buffer_t which is long enough to contain the register's value. The
value is encoded in little endian byte order.
typedef enum {
Description_Type_Group,
Description_Type_Int_Reg,
Description_Type_Float_Reg,
Description_Type_Fields_Reg,
Description_Type_Int_Field,
Description_Type_Float_Field,
} description_type_t;
typedef enum {
Reg_Role_None, /* No special role for the register. */
Reg_Role_Program_Counter /* The register is the program counter. */
} reg_role_t;
typedef enum {
Reg_Bitorder_Little_Endian,
Reg_Bitorder_Big_Endian
} reg_bitorder_t;
typedef struct {
const char *name;
const char *description;
const bytes_t value; /* Little endian byte order */
} named_value_t;
typedef struct {
/* Common fields */
description_type_t type;
const char *name;
const char *description;
/* Register and field fields */
int16 dwarf_id; /* id used by dwarf for this register
or -1 if no such id is defined. This
is ABI specific, but the CPU will
give the ids for the most common ABI
for that architecture. */
reg_bitorder_t bitorder; /* Bitorder convention used in the
documentation for this register or
field. */
reg_role_t role; /* Role of this register in the ABI/HW. */
bool memory_mapped; /* True if the register is memory mapped. */
uint64 offset; /* Offset into the bank for memory mapped
registers. */
bool catchable; /* True if Core_Control_Register_Write and
Core_Control_Register_Read are triggered
when this register is written or read. */
int msb, lsb; /* Most and least significant bit of the
register or field. Always given in le
bitorder. For groups msb == -1 and
lsb == 0. */
int regsize; /* Number of bits in the register, or the
register this field is a part of. */
int reg_id; /* For registers and fields the id to pass
to the get and set methods to access the
register's value. Fields have the same
reg_id as the register they are a part
of. Not valid for groups.*/
} description_t;
SIM_INTERFACE(describe_registers) {
const description_t *(*first_child)(
conf_object_t *NOTNULL obj, const description_t *parent);
const description_t *(*next_description)(
conf_object_t *NOTNULL obj, const description_t *prev);
void (*free_description)(conf_object_t *NOTNULL obj,
const description_t *desc);
const named_value_t *(*first_named_value)(
conf_object_t *NOTNULL obj, const description_t *parent);
const named_value_t *(*next_named_value)(
conf_object_t *NOTNULL obj, const named_value_t *prev);
void (*free_named_value)(conf_object_t *NOTNULL obj,
const named_value_t *nv);
void (*get)(conf_object_t *NOTNULL obj, int reg_id, buffer_t dest);
void (*set)(conf_object_t *NOTNULL obj, int reg_id, bytes_t value);
};
#define DESCRIBE_REGISTERS_INTERFACE "describe_registers"
This section lists Simics API functions that a processor model may
need to use beyond what is described in other parts of this document.
Simics API SIM_register_clock is described in
API Reference Manual.
- NAME
-
VT_check_async_events — check for asynchronous events
- SYNOPSIS
-
bool
VT_check_async_events();
- DESCRIPTION
-
Check if any async events are pending and if so, make the current
executing object exit in order for them to be handled. Return nonzero
if there are pending events.
The Simics platform will check for asynchronous events between invocations
of the run method in the execute. If significant
time passes between such invocations, which will typically be the case
unless there are multiple simulated CPUs that are switched between, then the
implementor of execute needs to either call this method or
exit pre-maturely from run to allow asynchronous events to be
handled. If neither is performed, then interactive performance will suffer
as user input would be waiting significant time before being processed.
If only the async event state is requested, the faster
VT_async_events_pending should be used instead.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
VT_new_code_block — inform platform of new code block
- SYNOPSIS
-
void
VT_new_code_block(void *start, size_t len);
- DESCRIPTION
-
This function informs the Simics platform that there is a len
bytes block at start that can be executed from. The call should
be made before the passed code area is executed from. This information is
used by Simics to communicate with systems like Pin or Valgrind that do not
automatically detect run-time generated code. If modifications are done to a
block, then a new call to this function is needed to inform the platform of
that.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
VT_set_object_clock — set clock association for object
- SYNOPSIS
-
void
VT_set_object_clock(conf_object_t *NOTNULL obj, conf_object_t *clock);
- DESCRIPTION
-
The simulation infrastructure keeps track of clock associations for every
object. For most objects, this is initialized through the queue attribute.
An object that is itself a clock needs to call this function to initialize
the clock coupling to itself. The call to initialize the coupling should be
made from the init method registered for the class in its
class_info_t (or init_object if registered using
class_data_t).
- EXECUTION CONTEXT
-
Global Context
- NAME
-
VT_clock_frequency_about_to_change — inform before clock frequency change
- SYNOPSIS
-
void
VT_clock_frequency_about_to_change(conf_object_t *obj);
- DESCRIPTION
-
To be called by a clock prior to a clock frequency change, with
events and cycles reflecting the frequency before the change.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
VT_clock_frequency_change — inform after clock frequency change
- SYNOPSIS
-
void
VT_clock_frequency_change(conf_object_t *obj, uint64 cycles_per_second);
- DESCRIPTION
-
To be called by a clock when the clock frequency has changed, with
events and cycles reflecting the frequency after the change.
- EXECUTION CONTEXT
-
Cell Context
- NAME
-
VT_stop_event_processing — stop event processing
- SYNOPSIS
-
void
VT_stop_event_processing(conf_object_t *clock);
- DESCRIPTION
-
This method is to be called by a clock when it has received a stop request
through the execute interface and the clock is about to return from the run
method in the execute interface.
In the future, the simulation framework may keep track of this thus
relieving the clock from the duty of having to call this method.
- EXECUTION CONTEXT
-
Cell Context
This chapter contains a description of the part of the Simics API that is
available in Python only. The Python modules described here may contain
functions, classes, types and similar than are not documented although
visible when inspecting the modules. If not documented, they are internal
to Simics and not part of the supported API.
When writing code in Python, almost all Simics API functions can be
used. Since not all C/C++ types are available in Python, Simics supplies
the following special type mappings.
| C/C++ |
Python |
attr_value_t (string) |
str (a Python string) |
attr_value_t (integer) |
int or long |
attr_value_t (floating) |
float |
attr_value_t (list) |
list |
attr_value_t (data) |
tuple of integers (bytes) |
attr_value_t (nil) |
None |
attr_value_t (object) |
An object from the conf namespace. |
attr_value_t (dict) |
dict |
attr_value_t (boolean) |
bool |
conf_class_t * |
A conf_class_t object |
conf_object_t * |
An object from the conf namespace |
Accepts a target machine address, optionally with an address space
prefix, such as v: for virtual addresses or p: for
physical.
Generator function for boolean arguments. A boolean argument accepts
the strings "TRUE" and "FALSE", as well as boolean integers (that
is, the values 0 and 1). In addition, if the optional strings
true_str and false_str are given, the boolean
argument will accept them as well. The argument passes True or
False to the command function depending on which string (or value)
was given.
Generator function for filename arguments. If the dirs
argument is false (which is default), no directories will be
accepted. The exist flag, when set, forces the file to
actually exist. If simpath is true, files will be checked for
existence using SIM_lookup_file(), searching the Simics
search path. simpath implies exist. On Windows, if Cygwin path
conversion is performed (see SIM_native_path() for details), the
filename will be converted to host native format.
The checkpoint flag will constrain the argument to checkpoints,
and treat existing checkpoints as opaque entities.
Passes True to command function when flag is provided, False
when flag is not provided.
Accepts floating-point numbers.
Accepts any unsigned integer that fits in 16 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 32 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 64 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 8 bits, modulo-reducing values
outside into that range.
Accepts any integer (regardless of size).
Accepts any unsigned integer that fits in 64 bits, modulo-reducing values
outside into that range.
Accepts integers that are valid IP port numbers (that is, integers
between 0 and 65535 inclusive).
Accepts a comma separated list of CLI types. Can also be given to
any CLI argument that accepts more than one value as input.
Nil argument. Accepts NIL, zero or the empty string, and passes None to
the command function. Not so usable by itself, but see e.g.
poly_t.
Returns an argument which accepts any object.
desc is the string returned as a description of the argument.
kind can be used to limit the accepted objects to only allow
objects of a certain kind. This parameter can either be a class
name that the object should be an instance of, or the name of an
interface that the object must implement, or a tuple of
kinds. want_port indicates whether it should be allowed to
specify an object and a port name, separated with a colon. If a
port is wanted, the argument will be a list [obj, port] instead of
only the object.
Generates an argument with the given description that will match any
of the given types; they will be tried one by one, in the order
specified, and the first one that accepts the input will be used.
Returns an argument which accepts any integer x between
min and max inclusively. desc is the string
returned as a description of the argument.
Values outside the interval cause an error to be signalled if
modulo is false, and a modulo-reduction to the specified
interval otherwise.
Accepts any signed integer that fits in 16 bits, modulo-reducing values
outside into that range.
Accepts any signed integer that fits in 32 bits, modulo-reducing values
outside into that range.
Accepts any signed integer that fits in 64 bits, modulo-reducing values
outside into that range.
Accepts any signed integer that fits in 8 bits, modulo-reducing values
outside into that range.
Accepts any one word or quoted string.
Accepts only strings from the given set. strings can be any
iterable, such as a tuple, list, or set, in which case the return
value is the exact string the user gave; or a dictionary mapping
acceptable user input strings to return values.
The optional parameter visible is a list of strings. If
given, only strings in this list will be suggested by the expander.
Accepts any unsigned integer that fits in 16 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 32 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 64 bits, modulo-reducing values
outside into that range.
Accepts any unsigned integer that fits in 8 bits, modulo-reducing values
outside into that range.
Accepts any unsigned (that is, non-negative) integer (regardless of
size).
- NAME
-
CliError — error in CLI command
- SYNOPSIS
-
CliError(args)
- DESCRIPTION
-
This exception can be raised whenever a command can
not complete successfully.
- NAME
-
arg — class defining a command argument
- SYNOPSIS
-
arg(handler, name = "", spec = "1", default = None,
data = None, doc = "", expander = None, pars = [])
- DESCRIPTION
-
Define a CLI command argument when using new_command. A
complete explanation of new_command and arg is
available in Simics Model Builder User's Guide, in the
Adding New Commands chapter.
- NAME
-
command_quiet_return — suppress interactive messages from commands
- SYNOPSIS
-
command_quiet_return(value)
- DESCRIPTION
-
Use this class to return from a command that returns a value but should
not print anything when used interactively.
value should either be the value returned, or a function
taking no arguments that returns the actual value.
Note that value can only be of types directly supported by
CLI.
- SEE ALSO
-
cli.command_return
- NAME
-
command_return — return interactive messages from commands
- SYNOPSIS
-
command_return(message = None, value = None)
- DESCRIPTION
-
Use this class to return from a command that returns one value
(value) but (may) print something else
(message) when run interactive.
message and value may both be functions that
take no arguments and return the message (a string) or a value,
respectively.
If it is a function, message is only evaluated if needed.
Note that value (or, when a function, its return value) can
only be of types directly supported by CLI.
- SEE ALSO
-
cli.command_quiet_return, cli.command_verbose_return
- NAME
-
command_verbose_return — always print return messages from commands
- SYNOPSIS
-
command_verbose_return(message = None, value = None)
- DESCRIPTION
-
Use this class to return from a command that returns a value or message
that should be printed even when used non-interactively, but not when used
in an expression.
The value and message parameters are
identical to the same as for cli.command_return.
- SEE ALSO
-
cli.command_return
- NAME
-
get_available_object_name — return a non-allocated object name
- SYNOPSIS
-
get_available_object_name(prefix)
- DESCRIPTION
-
Return an object name suitable for creating a new object (i.e., that has
not been used yet) by adding a suffix to prefix.
- NAME
-
get_component_object — return an object in a component
- SYNOPSIS
-
get_component_object(cmp_obj, slot)
- DESCRIPTION
-
Return the object named slot inside the
cmp_obj component. The slot parameter is
the name by which the component knows the object, not the global name of
the object.
The function will raise a CliError if the object can not be found
in the component.
- RETURN VALUE
-
object or pre-object
- NAME
-
global_cmds — Namespace with functions to run global CLI commands
- SYNOPSIS
-
global_cmds.wrapper_function(...)
- DESCRIPTION
-
The namespace provides wrapper Python functions to run global
Simics CLI commands. A wrapper function name
is usually the same as a name of the command it executes
with hyphens replaced with underscores. The parameters of
the wrapper functions are the same as of the corresponding command (again,
with hyphens replaced with underscores). Command flags (the names of
the corresponding function parameters start with an underscore)
could be passes as Python Boolean values. In the rare cases that a wrapper
function name or a wrapper function parameter name turns out to be
a Python keyword, the
_cmd suffix is added
to the wrapper function name
and the function parameter gets the _ suffix.
Wrapper functions return the value returned by the command
which they execute.
Please consult the docstring
of the wrapper function and the respective command documentation
for the information about function arguments and the returned value.
- NAME
-
interactive_command — check if current command is run interactively
- SYNOPSIS
-
interactive_command()
- DESCRIPTION
-
Returns true if the current command was run interactively by the user
and false if run from a script. This function may only be called by CLI
commands.
- NAME
-
new_command — define a new CLI command
- SYNOPSIS
-
new_command(name, fun, args = [], **kwargs)
- DESCRIPTION
-
Define a new CLI command. A complete explanation of
new_command and its parameters is available in
Simics Model Builder User's Guide, in the
Adding New Commands chapter.
- NAME
-
new_info_command — define a new info command
- SYNOPSIS
-
new_info_command(cls, get_info, ctype = None, doc = None)
- DESCRIPTION
-
Define a new info command for a given object.
cls is the class for which the info command
should be registered. get_info is a function returning the
information to be printed. get_info() should return a data
structure of the following kind:
[(SectionName1, [(DataName1.1, DataValue1.1),
(DataName1.2, DataValue1.2), ...]),
(SectionName2, [(DataName2.1, DataValue2.1),
(DataName2.2, DataValue2.2), ...]),
...]
Each section will be printed separately. Each piece of data will be printed
on one line. If no sections are necessary, just provide None as
the only section's name, followed by the list of data.
- SEE ALSO
-
cli.new_status_command
- NAME
-
new_status_command — define a new status command
- SYNOPSIS
-
new_status_command(cls, get_status, ctype = None, doc = None)
- DESCRIPTION
-
Define a new status command for a given object.
cls is the class for which the status command
should be registered. get_status is a function returning the
information to be printed. get_status() should return a data
structure of the same kind as in new_info_command().
- SEE ALSO
-
cli.new_info_command
- NAME
-
new_tech_preview_command — define a new CLI tech preview command
- SYNOPSIS
-
new_tech_preview_command(name, feature, fun, args=[], doc="", **kwargs)
- DESCRIPTION
-
Define a new tech preview CLI command.
- NAME
-
new_unsupported_command — define a new unsupported CLI command
- SYNOPSIS
-
new_unsupported_command(name, feature, fun, args = [], doc = "", **kwargs)
- DESCRIPTION
-
Define a new unsupported CLI command.
- NAME
-
number_str — return a ready-to-print representation of a number
- SYNOPSIS
-
number_str(val, radix=None, group=None, use_prefix=True, precision=1)
- DESCRIPTION
-
Return a ready-to-print representation of the number
val in a given base (radix) or the
current base by default, using the current settings for number
representation as set by the output-radix and
digit-grouping commands.
The default digit grouping can be overridden with the
group parameter, where 0 means no grouping.
The radix prefix can be removed
by specifying use_prefix as False.
The minimum number of digits to be printed is specified by
precision. If precision is negative,
the precision is taken to be zero. Regardless of the radix, a
value of zero with zero precision will always return the empty
string.
Negative numbers that fit in a signed 64-bit integer are treated
as such. Other negative numbers are prefixed with a minus
("-").
- RETURN VALUE
-
A string representing the number.
- SEE ALSO
-
cli.str_number
- NAME
-
object_expander — standard expander for an object argument
- SYNOPSIS
-
object_expander(kind)
- DESCRIPTION
-
For command writing: standard expander that can be use to provide
argument completion on all objects of a given class or matching a given
interface (kind).
For example, to expand a string with the list of processor available in the
machine, you would write:
arg(str_t, "cpu", expander = object_expander("processor_info"))
To expand a string to all gcache objects:
arg(str_t, "cache", expander = object_expander("gcache"))
- NAME
-
quiet_run_command — run a CLI command and return output
- SYNOPSIS
-
quiet_run_command(text, output_mode = output_modes.formatted_text)
- DESCRIPTION
-
Runs a CLI command, or a CLI expression, as if it has been
entered at the prompt. Errors are reported using CliError
exception.
The quiet_run_command function is similar to
run_command but returns a tuple with the command
return value as first entry, and the command output text as the second.
Please note that sometimes unrelated output might be included, e.g.,
for commands that advance the virtual time or in some other way may allow
other commands to run in parallel with them.
Set 'output_mode' to one of the output modes:
- output_modes.regular
- formatted text with Simics-internal markup
- output_modes.formatted_text
- formatted text without markup
- output_modes.unformatted_text
- unformatted text without markup
- NAME
-
register_command_category — register a command category
- SYNOPSIS
-
register_command_category(name = None)
- DESCRIPTION
-
Register a command category for the 'type' argument given to the
new_command function. Command categories are optional but may
be useful if many commands are defined for a particular use case that is
of general interest.
name should be at least 3 characters long and preferably
just one capitalized word, a noun.
Notice: Do not register any command category for a class, as those
are listed on the class itself.
Invoke this function without any argument to print the standard
categories, assuming no modules or targets have been loaded.
- NAME
-
run_command — run a CLI command
- SYNOPSIS
-
run_command(text)
- DESCRIPTION
-
Runs a CLI command, or a CLI expression, as if it has been entered at the
prompt. Errors are reported using CliError exception, and any return value
from the command is returned by this function to Python.
Use quiet_run_command if you need to suppress or catch
messages printed.
- NAME
-
simenv — CLI variable namespace
- SYNOPSIS
-
simenv.variable
- DESCRIPTION
-
The simenv namespace provides access to the CLI variables
in the Simics Python interpreter. If the variable $foo was
defined in CLI, simenv.foo will represent the same variable in
Python.
Running del simenv.foo will unset that variable. The return value
from the dir function will also include defined variables. The
repr function will return the dictionary of variable and value
pairs as a string.
- NAME
-
str_number — convert a string to a number
- SYNOPSIS
-
str_number(text)
- DESCRIPTION
-
Converts a string returned from number_str back to
an integer.
Raises ValueError for invalid arguments.
- RETURN VALUE
-
A number representing the string.
- SEE ALSO
-
cli.number_str
- NAME
-
Attribute — a Simics attribute
- DESCRIPTION
-
The pyobj.Attribute class defines an attribute that will
be registered for the containing ConfObject class. The
attribute will be registered with Simics using the
SIM_register_attribute function. See documentation for
SIM_register_attribute for detailed information about
attributes.
The arguments to SIM_register_attribute is taken from the
class members. The attrattr member is an
attr_attr_t type and its default value is
Sim_Attr_Optional. The attrtype member is a string
defining the type of the attribute, default value is 'a'.
The class methods named getter and setter will be
used as get_attr and set_attr functions when
registering the attribute. The methods are optional. An attribute without a
getter can not be read. An attribute without a setter
can not be written.
The attribute description is the same as the Python class description.
The _initialize method can be defined if special initialization
behavior is required. This can for instance be used to set the default
value.
- EXAMPLE
-
class wee(pyobj.Attribute):
"""Documentation for the attribute goes here."""
attrattr = simics.Sim_Attr_Pseudo
attrtype = 'i'
def _initialize(self):
self.val = 4711
def getter(self):
self.val += 3
return self.val
def setter(self, val):
self.val = val
- SEE ALSO
-
pyobj.SimpleAttribute, pyobj.ClassAttribute, pyobj.ConfObject
- NAME
-
ClassAttribute — a Simics class attribute
- DESCRIPTION
-
The pyobj.ClassAttribute class defines an attribute that
will be registered for the containing ConfObject class. The
attribute will be registered with Simics using the
SIM_register_class_attribute function. See documentation
for SIM_register_class_attribute for detailed information
about class attributes.
The value stored in the class should always be stored in the
attribute named val. This is to avoid problems when a
class that defines a pyobj.Attribute class is
inherited by more than one class.
The pyobj.ClassAttribute class is very similar to the
pyobj.Attribute class. See the documentation for the
pyobj.Attribute class for how to use this class.
- EXAMPLE
-
class wee(pyobj.ClassAttribute):
"""Documentation for the attribute goes here."""
attrtype = 'i'
val = 4711
@classmethod
def getter(cls): return cls.val
@classmethod
def setter(cls, val): cls.val = val
- SEE ALSO
-
pyobj.Attribute, pyobj.ConfObject
- NAME
-
ConfObject — a Simics configuration object
- DESCRIPTION
-
The pyobj.ConfObject class defines a new Simics class
using the SIM_register_class function. You could call
SIM_register_class and all the related functions for
attribute and interface registration yourself, but
ConfObject will make your code much more concise.
The name of the Simics class is identical to the Python
class. The class description is the same as the Python class
description.
The class implements the methods _initialize,
_finalize, _pre_delete, _info, and
_status. All of these methods can be overridden if
required.
The _initialize method is called when an object of the
class is instantiated. The _finalize method is called
when the object is finalized. The _pre_delete method is
called right before an object of the class is deleted.
The _info and _status methods provide data for
the class's info and status commands; the
format of their return value is documented with
cli.new_info_command and
cli.new_status_command.
If you need to get hold of the Simics conf_object_t object
associated with a ConfObject instance—for
example, in order to call a Simics API function—you can find
it in the obj member.
The pyobj.ConfObject class can contain inner classes
that define attributes, interfaces, etc. See
pyobj.Port, pyobj.Attribute,
pyobj.ClassAttribute, and
pyobj.Interface for more documentation. An inner
class has a reference to the class that contains it in its
_up member.
By default, a Simics class is registered automatically whenever a
subclass of pyobj.ConfObject is declared. Sometimes
this is not desirable; e.g., the class may be a base class, or you
may want to allow importing the containing Python file without
side-effects. The automatic registration of a Simics class can
then be suppressed by setting the member _do_not_init to
object(). That will cause it to not be registered as a
Simics class (but its subclasses will be, unless they too employ
the same trick).
The class method register may be called once on each
pyobj.ConfObject subclass, to register the Simics
class. For a class that doesn't suppress automatic registration, the
method currently does nothing.
In future Simics versions, a Simics class will no longer be
registered automatically, and an explicit call to the
register method will be required for that.
The _class_kind member tells Simics whether objects of
this class should be saved when a checkpoint is created.
The value is passed to SIM_register_class, as the
kind field of the class_data_t structure.
The default value is Sim_Class_Kind_Vanilla.
See the documentation of SIM_register_class for details.
- EXAMPLE
-
class foo(pyobj.ConfObject):
"""This is the long-winded documentation for this Simics class.
It can be as long as you want."""
_class_desc = 'One-line doc for the class'
def _initialize(self):
super()._initialize()
self.my_val = 4711
def _info(self):
return [("Python device info", [("my_val", self.my_val)])]
def _status(self):
return [("Python device status",
[("woot", self.woot.val),
("signal", self.signal.val)])]
class woot(pyobj.SimpleAttribute(0, 'i|n')):
"""A four-letter attribute"""
class lost(pyobj.Attribute):
"""A pseudo attribute"""
attrattr = simics.Sim_Attr_Pseudo
def getter(self):
return self._up.my_val
class signal(pyobj.Interface):
def signal_raise(self): self.val = True
def signal_lower(self): self.val = False
def _initialize(self): self.val = False
- NAME
-
Event — a Simics event
- DESCRIPTION
-
pyobj.Event defines an event that will be registered
for the containing ConfObject class. Internally,
registration is done with SIM_register_event; see the
documentation for that API function for detailed information.
Events are posted with the post(clock, data,
<duration>) method. clock determines which
clock the event is posted on, and data is the event
data. The duration is the number of seconds,
cycles, or steps until the event triggers,
specified with the appropriate keyword argument:
ev.post(a_clock, some_data, seconds=4.711)
ev.post(a_clock, some_data, cycles=4711)
ev.post(a_clock, some_data, steps=4711)
Events can be cancelled before they trigger with either
cancel_time(clock, match_fun) or cancel_step(clock,
match_fun) (depending on whether the event duration was
specified in steps or not). The match_fun argument is
optional: if given, it should be a function that accepts an event
data parameter, and returns true for the events that should be
cancelled; if not given, all events are cancelled.
A subclass may define the following methods:
- callback(data)
- Called when the event
triggers. Overriding this method is not optional.
- destroy(data)
- Called when the event is
removed from the queue without being called. The method is not
allowed to use any event API calls; it is mainly intended for
freeing event data.
- get_value(data) and set_value(val)
- Converts the given event data to an
attr_value_t value,
and the other way around. If the event carries no data that needs
checkpointing, you may omit these methods. - describe(data)
- Called to generate a
human-readable description of the event to be used in the
print-event-queue command. If you do not supply this method, the
event's name will be used.
Additionally, it may set the flags parameter to
Sim_EC_Notsaved, if the event should not be checkpointed.
In this case, neither get_value nor set_value
should be defined.
- EXAMPLE
-
class foo(pyobj.ConfObject):
class ev1(pyobj.Event):
def callback(self, data):
do_something(data)
class ev2(pyobj.Event):
def callback(self, data):
self.do_something_else(data)
def get_value(self, data):
return str(data)
def set_value(self, val):
return int(val)
def describe(self, data):
return 'ev2 with %s' % data
class ev3(pyobj.Event):
flags = simics.Sim_EC_Notsaved
def callback(self, data):
self._up.do_this_third_thing(data)
- SEE ALSO
-
SIM_register_event, pyobj.ConfObject
- NAME
-
Interface — a Simics interface
- DESCRIPTION
-
The pyobj.Interface class implements a Simics
interface for the containing ConfObject class. The
interface is registered using the SIM_register_interface
function. The interface name is taken from the class name.
The _initialize method can be overridden if special
initialization behavior is required.
To implement port interfaces instead of regular interfaces, place
one or more pyobj.Interface subclasses inside a
pyobj.Port class.
- EXAMPLE
-
class signal(pyobj.Interface):
def signal_raise(self): self.val = True
def signal_lower(self): self.val = False
def _initialize(self): self.val = False
- SEE ALSO
-
pyobj.Port, pyobj.ConfObject
- NAME
-
Port — a Simics port
- DESCRIPTION
-
To have your ConfObject-based Simics object implement
port interfaces, put a subclass of pyobj.Port as an inner
class of your ConfObject, and put one or more
pyobj.Interface subclasses inside it. The
pyobj.Interface subclasses will work just as if they were at
the top level, except that they will be registered with
SIM_register_port_interface instead of
SIM_register_interface.
The _initialize method can be overridden if special
initialization behavior is required.
- EXAMPLE
-
class wee(pyobj.Port):
class signal(pyobj.Interface):
def signal_raise(self): self.val = 2
def signal_lower(self): self.val = 1
def _initialize(self): self.val = 0
- SEE ALSO
-
pyobj.Interface, pyobj.ConfObject
- NAME
-
PortObject — a Simics port object
- DESCRIPTION
-
The pyobj.PortObject class defines a port object class
that will be registered as a port object for the containing
ConfObject class.
The port object will be registered with the name "port.<name>",
but this can be changed by defining namespace to something other
than "port". One possibility is the empty string.
If classname is set, then the port object will be
an instance of this external class rather than defining the class
locally. The external class cannot be modified by adding e.g.
an interface definition inside the PortObject definition.
- EXAMPLE
-
class portname(pyobj.PortObject):
"""Documentation for the port object goes here."""
class signal(pyobj.Interface):
def signal_raise(self): self.val = 2
def signal_lower(self): self.val = 1
def _initialize(self): self.val = 0
- SEE ALSO
-
pyobj.ConfObject
- NAME
-
SimpleAttribute — a simple Simics attribute
- SYNOPSIS
-
SimpleAttribute(init, type = 'a', attr = simics.Sim_Attr_Optional)
- DESCRIPTION
-
The pyobj.SimpleAttribute function returns a new subclass of
pyobj.Attribute, with predefined getter and setter functions
that simply store and retrieve the value without further side effects. The
value is stored in the
val member.
The init argument is the initial value, type is the
attribute type string, attr is the attribute type. If
init is callable, it will be called, and the return value is the
initial value; otherwise, init itself is the initial value.
The attribute value is stored in the val member of the class.
- RETURN VALUE
-
pyobj.Attribute class
- EXAMPLE
-
class wee(pyobj.SimpleAttribute(17, 'i')):
"""Documentation for the attribute goes here."""
- SEE ALSO
-
pyobj.Attribute, pyobj.ConfObject
- NAME
-
ConfigAttribute — component configuration attribute
- DESCRIPTION
-
The ConfigAttribute class inherits the
pyobj.Attribute class. The
ConfigAttribute class just adds the special property
to the pyobj.Attribute class that it is a config
attribute.
A config attribute defines how the component should be
configured. Therefore, all config attributes are also arguments to the
new- and create- commands that are used to
instantiate the component.
Because of this, the config attribute must always be documented
and the default value of the attrattr member is
Sim_Attr_Optional.
The ConfigAttribute class contains the
valid member, which is a list of valid values for the
config attribute. The list gives the user a hint about valid
values when creating a component. There is no check that the value
written to the attribute is a value in the list of valid values.
The list of valid value(s) does not need to contain the default
initial value for the config attribute, but it usually does. The
valid list should at least contain one valid value even if several
values are valid.
- EXAMPLE
-
class foo(ConfigAttribute):
"""The foo attribute."""
valid = [667, 4711]
def _initialize(self): self.val = 4711
def getter(self): return self.val
def setter(self, val): self.val = val
- SEE ALSO
-
pyobj.Attribute
- NAME
-
SimpleConfigAttribute — simple component configuration attribute
- SYNOPSIS
-
SimpleConfigAttribute(init, type, attr = simics.Sim_Attr_Optional, val = [])
- DESCRIPTION
-
The pyobj.SimpleConfigAttribute method creates an
attribute using the comp.ConfigAttribute class. The
purpose of the method is to make it easier and faster to create a
simple config attribute.
A config attribute defines how the component should be
configured. Therefore, all config attributes are also arguments to the
new- and create- commands that are used to
instantiate the component.
The init argument is the initial value for the
attribute. The type of the attribute is defined by the
type string (currently objects 'o' and dictionaries 'D'
are not supported). The attr argument sets the
attribute kind. The default value for attr is
Sim_Attr_Optional.
The valid value(s) for the
comp.ConfigAttribute class is set by the
val argument. See the documentation for
SIM_register_attribute for more information about
the arguments.
- RETURN VALUE
-
comp.ConfigAttribute class
- EXAMPLE
-
class cpu_frequency(SimpleConfigAttribute(
None, 'i', simics.Sim_Attr_Required)):
"""Processor frequency in MHz."""
- SEE ALSO
-
pyobj.Attribute, pyobj.ConfObject
- NAME
-
StandardComponent — base class for components
- DESCRIPTION
-
The StandardComponent class is the base class for
components written in Python. It is a subclass of
pyobj.ConfObject.
The class will automatically register the
required component attributes. Any attribute may be overridden;
however, overriding the internal attributes is not recommended.
The automatically registered attributes are:
- basename
- String to prepend to component name when creating
components when not specifying name.
- component_icon
- String with the name of the component
icon.
- component_queue
- The default queue object for this
component.
- top_level
- Default set to
False. - system_icon
- The system icon.
- machine_icon
- The machine icon.
- cpu_list
- List of processors in the component tree.
- static_slots
- Internal.
- dynamic_slots
- Internal.
- object_list
- Internal.
- object_prefix
- Internal.
- top_component
- Internal.
- instantiated
- Internal.
- pending_cell_object_factories
- Internal.
- config_attributes
- Internal.
- system_info
- Internal.
- components
- Internal.
- domain
- Internal.
The class will automatically implement the component
interface. The individual methods of this interface are user-overridable.
Components will automatically get new- and create-
commands that can be used to create and instantiate the component. It is
possible to override this by setting _no_create_command or
_no_new_command to object() to avoid to automatically get
create- or new- commands.
- EXAMPLE
-
class my_comp(StandardComponent):
"""The my_comp component."""
_class_desc = "my_comp"
class bar(SimpleConfigAttribute(
None, 'i', simics.Sim_Attr_Required)):
"""My favorite bar."""
class my_comp(StandardComponent):
"""The my_comp component."""
_class_desc = "my_comp"
_no_create_command = object()
- SEE ALSO
-
pyobj.ConfObject
- NAME
-
add_component — add sub component to component
- SYNOPSIS
-
add_component(self, slot, cls, attr, name = '')
- DESCRIPTION
-
Add a subcomponent or arrays of subcomponents to the
component. The subcomponent(s) will be created immediately when
the method is called.
The slot argument is the slot name concatenated with
a nested array string, defining the number of subcomponents to
create. Setting slot to foo will create one
subcomponent in the slot foo, setting slot
to foo[3] will create an array of three subcomponents
in the slot foo, setting slot to
foo[3][2] will create an array of three arrays of two
arrays with subcomponents in the slot foo.
The cls is the component class, attr is
arguments to the component, and name is an optional
name.
- RETURN VALUE
-
arrays of conf_object_t component object
- NAME
-
add_connector — add connector to component
- SYNOPSIS
-
add_connector(self, slot, type, hotpluggable, required,
multi, direction)
- DESCRIPTION
-
Add a connector or nested array of connectors to the component. The
connector(s) will be created immediately when the method is called.
The slot argument is the slot name concatenated with a
nested array string, defining the number of connectors to create.
Setting slot to foo will create one connector in
the slot foo, setting slot to foo[3] will
create an array of three connectors in the slot foo, setting
slot to foo[3][2] will create an array of three
arrays of two arrays with connectors in the slot foo.
The type is the type of connection as a string,
hotpluggable is True or False depending on
whether the connector is hot-pluggable, required is
True if the connector must be connected before the component
is instantiated, multi is True if the connector
supports multiple connections, direction is a
connector_direction_t which is up, down,
or any.
- RETURN VALUE
-
arrays of conf_object connector objects
- SEE ALSO
-
comp.StandardComponent.get_slot
- NAME
-
add_pre_obj — add pre_conf_obj to component
- SYNOPSIS
-
add_pre_obj(self, slot, cls, name = '', **attr)
- DESCRIPTION
-
Add pre conf objects to the component. The pre conf objects will
be converted to regular conf objects when the component is
instantiated.
The slot argument is the slot name concatenated with
a nested array string, defining the number of pre objects to
create. Setting slot to foo will create one
pre object in the slot foo, setting slot to
foo[3] will create an array of three pre objects in
the slot foo, setting slot to
foo[3][2] will create an array of three arrays of two
arrays with pre objects in the slot foo. The
cls argument is the type of object class to
create. The name argument is deprecated. The
attr argument is optional attribute values for the
object(s).
- RETURN VALUE
-
arrays of pre conf objects
- NAME
-
add_slot — add slot to component
- SYNOPSIS
-
add_slot(self, slot, val)
- DESCRIPTION
-
Add a slot to the component. slot is the slot name and
val is the value. The value must be a conf object,
a pre conf object, or None, or nested lists of these types.
- RETURN VALUE
-
new slot value, i.e. val
- NAME
-
connect — connect connectors
- SYNOPSIS
-
connect(self, cnt0, cnt1)
- DESCRIPTION
-
Connect two connectors cnt0 and cnt1. The
connectors must be connector objects. A
CompException
exception will be raised if the connection failed.
- NAME
-
copy_connector — copy connector to component
- SYNOPSIS
-
copy_connector(self, slot, src)
- DESCRIPTION
-
Copy connectors from another component. The slot argument
is the new slot name for the connector in this component. The
src argument is the name of the slot with connectors to
copy. The src can be a relative slot name, see the
get_slot method.
- RETURN VALUE
-
arrays of conf_object connector objects
- SEE ALSO
-
comp.StandardComponent.get_slot
- NAME
-
del_slot — delete slot in component
- SYNOPSIS
-
del_slot(self, slot)
- DESCRIPTION
-
Delete slot in component. The slot argument is the
slot name. The function returns the slot value if the slot
exists. All connectors in the slot will be converted to pre conf
objects and the original connectors will be deleted when
returning the slot value. A
CompException exception
will be raised if the slot does not exist, the slot contains
non connector conf objects, or the slot contains connectors that
have been copied with the copy_connector
method. Slots with sub components can not be deleted.
- NAME
-
get_slot — get slot from component
- SYNOPSIS
-
get_slot(self, slot)
- DESCRIPTION
-
Get a slot from the component. slot is the slot name.
slot can be a slot in this component or a
hierarchical slot; e.g., looking up foo.bar will
return the slot bar from the component in slot
foo from this component. If the lookup fails, a
CompException exception will be raised.
- RETURN VALUE
-
slot value
- NAME
-
StandardConnectorComponent — convenience class for connector components
- DESCRIPTION
-
The StandardConnectorComponent is a convenience class for
connector components. It is a subclass of
comp.StandardComponent and implements the
component_connector interface.
- SEE ALSO
-
comp.StandardComponent
- NAME
-
add_connector — create a connector component
- SYNOPSIS
-
add_connector(self, slot, cls)
- DESCRIPTION
-
Create a connector component.
The slot argument is the slot name for the connector.
The cls argument is an instance of a connector class.
- RETURN VALUE
-
the conf_object connector component
- NAME
-
SIM_register_class_update — register a class update function
- SYNOPSIS
-
SIM_register_class_update(build_id, classname, function)
- DESCRIPTION
-
Register the class update function function for class
classname, to be run when updating a checkpoint to build-id
build_id.
The function acts on a single object of a given class. It
will be called for all matching objects with the current object as
argument. It doesn't need to return anything, however it can't create or
destroy objects, only change the attributes of the object it got as
parameter, except the object name.
- NAME
-
SIM_register_generic_update — register a generic update function
- SYNOPSIS
-
SIM_register_generic_update(build_id, function)
- DESCRIPTION
-
Register the generic update function function to be run
when updating a checkpoint to build-id build_id. The
function acts on one or several objects of various classes,
and may rename, create or destroy objects. When the checkpoint reaches the
required build-id, the function will be called once with the
complete set of objects that constitute the checkpoint as a parameter. It
is expected to return three lists of pre_conf_objects: (deleted objects,
changed objects, added objects). Deleted objects must have been removed
from the configuration, changed objects can have any attribute changed
(including their class or their name). Added objects must have been added
to the configuration.
When renaming an object, the function is expected to remove
the object from the checkpoint set under its old name and to add it again
under its new name. The object should be reported in the changed object
list.
- NAME
-
SIM_register_post_update — register a generic update function
- SYNOPSIS
-
SIM_register_post_update(function)
- DESCRIPTION
-
Register the generic update function function to be run
when updating a checkpoint to build-id build_id. after all
build-id based update functions have run, but before the checkpoint is
loaded. The function should behave as functions added with
SIM_register_generic_update.
- NAME
-
all_objects — return all objects of a given class
- SYNOPSIS
-
all_objects(set, classname)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
Return a list of all objects of class classname present in
the checkpoint set.
- NAME
-
for_all_objects — apply a function on all objects of a given class
- SYNOPSIS
-
for_all_objects(set, classname, function)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
Apply the function function on all objects of class
classname present in set.
function is defined as:
function(config, object)
where config is the Python dictionary containing all
objects, and object is an object of class classname.
- NAME
-
remove_attr — remove an attribute
- SYNOPSIS
-
remove_attr(obj, name)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
Remove the attribute name from the object
obj.
- NAME
-
remove_class — remove all instances of a class
- SYNOPSIS
-
remove_class(set, classname)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
In the checkpoint set, remove all objects of class
classname.
- NAME
-
remove_class_attr — remove a class attribute
- SYNOPSIS
-
remove_class_attr(set, classname, name)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
In the checkpoint set, remove the class attribute
name from all objects of class classname.
- NAME
-
rename_attr — rename an attribute
- SYNOPSIS
-
rename_attr(obj, new_attr, old_attr)
- DESCRIPTION
-
This function should only be used while updating checkpoints, as
described in Model Builder User's Guide, in the
Checkpoint Compatibility chapter.
Rename the attribute old_attr to new_attr in
the object obj.
- NAME
-
OBJ — class for referring to another object, existing or not
- SYNOPSIS
-
OBJ(name)
- DESCRIPTION
-
OBJ is only used together with the
SIM_set_configuration API function. OBJ is
used when a configuration attribute needs to refer to another
object. The other object can either be present in an existing
configuration, or it can be an object that will be created as a
result of the same call to SIM_set_configuration. See
SIM_set_configuration for an example.
- SEE ALSO
-
SIM_set_configuration
- NAME
-
pre_conf_object — class for Simics configuration object to instantiate
- SYNOPSIS
-
pre_conf_object(object_name, class_name, build_id = None)
- DESCRIPTION
-
A class representing a future Simics configuration object named
object_name, of class class_name. If
object_name is
None, a unique name will be
generated.
The build-id of the object can be specified when using the
pre_conf_object class during checkpoints update. Refer to
Model Builder User's Guide for more information.
Future configuration attributes are set using normal Python class members:
a = pre_conf_object("test_object", "test-class")
a.value = 42
After using a pre_conf_object object to create a
configuration object, the created object can be obtained by passing the
pre_conf_object's name member to
SIM_get_object().
- NAME
-
add — register a hypersim-pattern
- SYNOPSIS
-
add(name, arch,
target_list = None,
own_info_cmd = False,
own_status_cmd = False)
- DESCRIPTION
-
The simics_start.py script for all pattern modules should call
this function to register its pattern classes. The patterns will
be automatically installed on the processor types it supports.
Function arguments:
- name
- class name
- arch
- architecture it supports (cpu->architecture ppc32, ppc64)
- target_list
- optional list of classnames that are supported.
If target_list is omitted or None, the pattern will be used by all
CPUs of arch architecture.
- own_info_cmd
- Legacy parameter, must always be overridden to True
- own_status_cmd
- Legacy parameter, must always be overridden to True
- NAME
-
register_std_info_command — register standard info command
- SYNOPSIS
-
register_std_info_command(cls)
- DESCRIPTION
-
Register a basic info command implementation for the hypersim
pattern class named cls
- NAME
-
register_std_status_command — register standard status command
- SYNOPSIS
-
register_std_status_command(cls)
- DESCRIPTION
-
Register a basic status command implementation for the hypersim
pattern class named cls
- NAME
-
flash_add_model — add a new flash model
- SYNOPSIS
-
flash_add_model(product_no, config, complete_func)
- DESCRIPTION
-
Adds a new flash model. Instances of the new flash can then be created
with the flash_create_memory and
flash_create_memory_anon functions.
These are the arguments:
- product_no
- Product number; e.g., "28F___C3_". Underscores act as wild cards
and will match any character.
- config
- Dictionary containing attribute: value pairs. These
attributes are generic-flash-memory attributes;
information on available attributes and how to configure them can
be found in the reference manual.
- complete_fun
- Function of type complete_fun(product_no, config) that
will be called just before a flash memory is instantiated.
product_no is the product number specified by the
user. config is the same config
dictionary as passed to the flash_add_model function.
The complete_fun can modify the attribute values, add
new attributes or remove attributes from the configuration, based
on e.g. the product_no. The complete_fun
should return either an error message (i.e. a string), or a tuple
(updated_config, size) where
size is the size of one flash chip, in bytes.
- RETURN VALUE
-
True if the flash model was successfully added,
or False if it failed.
- NAME
-
flash_create_memory — create a list of objects representing a flash memory
- SYNOPSIS
-
flash_create_memory(name, product_no, interleave, bus_width,
files = [],
queue = None,
accept_smaller_reads = 1,
accept_smaller_writes = 0,
big_endian = 0)
- DESCRIPTION
-
Returns a list of pre_objects suitable as input for
SIM_add_configuration and the total size in bytes of the flash
memory. The list and the size is returned as a tuple.
The flash objects will be named, which makes them suitable for use in legacy
components. New components should use the function
flash_create_memory_anon instead.
Function arguments:
- name
- Base name for all objects (flash, ram, and image).
- product_no
- Product name; e.g., "28F160C3T".
- interleave
- Byte interleaving; one of 1, 2, 4, and 8.
- bus_width
- Bus width; one of 8, 16, 32, and 64.
- files
- Same as the file attribute of image
objects. Defaults to the empty list.
- queue
- Queue object to use.
- accept_smaller_reads
- If 1 (default), the flash device will accept reads smaller than
the bus width. if 0, the flash device will complain when receiving
smaller reads.
- accept_smaller_writes
- If 1, the flash device will accept writes smaller than the bus
width. If 0 (default), the flash device will complain when
receiving smaller writes.
- big_endian
- If set, the flash device will behave as a big endian device. If
not set (default), it will behave as a little endian device.
- RETURN VALUE
-
tuple(object dict, total size in bytes)
- NAME
-
flash_create_memory_anon — create a list of objects representing a flash memory
- SYNOPSIS
-
flash_create_memory_anon(product_no, interleave, bus_width,
files = [],
queue = None,
accept_smaller_reads = 1,
accept_smaller_writes = 0,
big_endian = 0)
- DESCRIPTION
-
Returns an list of pre_objects suitable as input for
SIM_add_configuration and the total size in bytes of the flash
memory. The list and the size is returned as a tuple.
The flash objects will be anonymous, which makes them suitable for use in
new components. Legacy components should use the function
flash_create_memory instead.
Function arguments:
- product_no
- Product name; e.g., "28F160C3T".
- interleave
- Byte interleaving; one of 1, 2, 4, and 8.
- bus_width
- Bus width; one of 8, 16, 32, and 64.
- files
- Same as the file attribute of image
objects. Defaults to the empty list.
- queue
- Queue object to use.
- accept_smaller_reads
- If 1 (default), the flash device will accept reads smaller than
the bus width. if 0, the flash device will complain when receiving
smaller reads.
- accept_smaller_writes
- If 1, the flash device will accept writes smaller than the bus
width. If 0 (default), the flash device will complain when
receiving smaller writes.
- big_endian
- If set, the flash device will behave as a big endian device. If
not set (default), it will behave as a little endian device.
- RETURN VALUE
-
tuple(object list, total size in bytes)
The System Panel API is a set of Python functions and classes that is used to
create system panels. Further documentation can be found in the Model
Builder User's Guide, chapter Creating a System Panel.
The API section covers the generic API for the system panel
infrastructure and a couple of helper functions; the Widget Types
section describes the specifics of each type of widget that can be included
in a panel.
- NAME
-
standard color names
- NAMESPACE
-
systempanel.widgets
- DESCRIPTION
-
The standard widgets colors are used for creating LED widgets with
different colors.
- SYNOPSIS
-
systempanel.widgets.BLUE
systempanel.widgets.GREEN
systempanel.widgets.PURPLE
systempanel.widgets.RED
systempanel.widgets.WHITE
systempanel.widgets.YELLOW
- SEE ALSO
-
systempanel.widgets.Led
- NAME
-
SystemPanel — Base class for system panel components
- DESCRIPTION
-
A base class for system panels. A system panel class should
inherit from this and set the 'layout' class variable to describe
the contents of the panel.
- NAME
-
SystemPanelException — System panel error
- DESCRIPTION
-
Exception thrown for various errors in the system_panel module
- NAME
-
BitfieldImageOutput — Multiple two-state image outputs driven by a single integer state
- SYNOPSIS
-
BitfieldImageOutput(obj_name, contents)
- DESCRIPTION
-
An output consisting of multiple two-state images, driven by a
single integer state. such that each two-state image is driven by
a single bit in the integer. Useful e.g. when creating 7-segment
displays.
The contents parameter is a list of tuples (mask, x, y,
[off_filename, on_filename]), where the integer mask is a
power of two, x and y are integer offsets, and
off_filename and on_filename are file names given on the
same form as in the Image class. The off_filename
image is shown at the given offset whenever the bit indicated by
mask is 0; on_filename is shown otherwise.
- NAME
-
BitmapButton — A bitmap-based button
- SYNOPSIS
-
BitmapButton(obj_name, off_bitmap, on_bitmap)
- DESCRIPTION
-
A bitmap-based button. Similar to the standard Button
class, but can be put inside a Canvas, and the appearance is
based on custom images. The bitmap parameters are filenames of the same
type as in the Image class.
- NAME
-
BitmapLed — A bitmap-based LED
- SYNOPSIS
-
BitmapLed(obj_name, off_bitmap, on_bitmap)
- DESCRIPTION
-
A bitmap-based LED. Same as the standard Led class, but
can be put inside a Canvas, and custom images can be
supplied. The bitmap constructor parameters are file names of the same
type as in the Image class.
- NAME
-
BitmapToggleButton — A bitmap-based toggle button
- SYNOPSIS
-
BitmapToggleButton(obj_name, off_bitmap, on_bitmap)
- DESCRIPTION
-
A bitmap-based toggle button. Similar to the standard
ToggleButton class, but can be put inside a
Canvas, and the appearance is based on custom images. The
bitmap parameters are file names of the same type as in the
Image class.
- NAME
-
Button — A standard button
- SYNOPSIS
-
Button(obj_name, label)
- DESCRIPTION
-
A button, that can be pressed. The button state is propagated using the
signal interface, and can be raised or lowered. Raising and
lowering the signal is frontend specific.
- NAME
-
Canvas — A canvas (i.e bitmap container)
- SYNOPSIS
-
Canvas(contents)
- DESCRIPTION
-
A canvas for painting bitmap-based widgets. A canvas contains multiple
bitmap-based widgets, each drawn at a specified offset. The
contents parameter is a list of elements on the form
(x, y, widget). Here x and y
are integers, and widget is an instance of one of
Image, BitmapLed, BitmapButton,
BitmapToggleButton,
MultiImageOutput, Canvas, or a subclass
thereof. The items are rendered in the same order as they appear in the
list; this means that if any widgets overlap, the last one will be drawn on
top.
- NAME
-
Column — A one-dimensional widget container
- SYNOPSIS
-
Column(contents)
- DESCRIPTION
-
A container for normal (non bitmap-based) widgets. The
Column container is a special case of Grid
container; the contained widgets are laid out vertically.
- NAME
-
Empty — An empty widget
- SYNOPSIS
-
Empty()
- DESCRIPTION
-
An empty widget, used to fill containers for layout purposes.
- NAME
-
Grid — A two-dimensional widget container
- SYNOPSIS
-
Grid(contents, columns)
- DESCRIPTION
-
A two-dimensional widget container. Containers are used to group other
widgets, and enforce a specific layout scheme. The contents
constructor parameter is a list of widget objects; it can contain any other
widget except for bitmap-based ones. Widgets are laid out from left to
right, top to bottom. Use the Empty class to fill empty
cells. The number of rows in a Grid container is implicitly
defined by the length of the contents list and the number of
columns specified when creating the container. See also the
Column and Row containers, which are
convenience classes for the one-dimensional cases. Containers can contain
other containers.
- NAME
-
Image — An image
- SYNOPSIS
-
Image(filename)
- DESCRIPTION
-
An image, that can be put inside a Canvas
class. Currently the only supported file format is PNG, but with full
support for transparency. See Canvas class for more
information.
- NAME
-
Label — An label
- SYNOPSIS
-
Label(label)
- DESCRIPTION
-
A label, used to present static text.
- NAME
-
LabeledBox — A container with a label and box drawn around it
- SYNOPSIS
-
LabeledBox(label, container)
- DESCRIPTION
-
A single-element container with a text label and a box drawn around
it. The single widget given by the container parameter can
be of any widget type, but it is typically of a container type.
- NAME
-
Led — A standard LED
- SYNOPSIS
-
Led(obj_name, color=None)
- DESCRIPTION
-
A LED, which can be on or off. Driven by the
signal
interface. The parameter color specifies the color of
the LED, all supported colors are described in Standard Widgets
Colors. The look-and-feel of the LED is frontend specific.
- SEE ALSO
-
Standard Widgets Colors
- NAME
-
MultiImageOutput — A bitmap-based output that toggles between multiple images
- SYNOPSIS
-
MultiImageOutput(obj_name, images)
- DESCRIPTION
-
An output that toggles between multiple custom images. This
can be used, among other things, for multi-coloured LEDs or
seven-segment display elements. The images
parameter is a list of paths to image filenames, each one given on
the same form as in the Image class. Numeric input
to the panel object via the
uint64_state interface
is used as a 0-based index in the image list.
- NAME
-
NumberInput — An input text field for integer numbers
- SYNOPSIS
-
NumberInput(obj_name)
- DESCRIPTION
-
An input text field for integer numbers, provided by the panel user. The
value is propagated to the model using the
uint64_state
interface.
- NAME
-
NumberOutput — An output text field for integer numbers
- SYNOPSIS
-
NumberOutput(obj_name)
- DESCRIPTION
-
An output text field for integer numbers, presenting integer state from
the model. Driven by the
uint64_state interface.
- NAME
-
Row — A one-dimensional widget container
- SYNOPSIS
-
Row(contents)
- DESCRIPTION
-
A container for normal (non bitmap-based) widgets. The
Row container is a special case of Grid
container; the contained widgets are laid out horizontally.
- NAME
-
ToggleButton — A toggle button
- SYNOPSIS
-
ToggleButton(obj_name, label)
- DESCRIPTION
-
A toggle button, that can be pressed or released. The button state is
propagated using the
signal interface. When button is
pressed, signal is raised. When button is released, signal is lowered. The
button must have a label indicating its purpose.
Utilities for testing simics.
- Synopsis
fail(msg)
- Description
- Signal a failure in a test.
Takes a string describing the failure as its single argument.
If called in collect failures mode this will collect the failure for later
checking with check_failures. If called outside collect failures
mode it will immediately raise a TestFailure exception
instead.
- Synopsis
collect_failures()
- Description
- Change the behavior of stest to collect failures instead of terminating on
the first failure detected.
If you use this you have to call check_failures at the end of
your test script to check if it signaled any failures.
- Synopsis
check_failures()
- Description
- Check if any failures have occurred and leave collect failures mode.
If any failures have occurred this function will report the failures and
raise a TestFailure exception.
If called outside collect failures mode this function will fail.
- Synopsis
trap_log(logtype, obj = None)
- Description
- Configure Simics to trap a type of log messages, and cause Simics
to quit with a test failure on any such log message.
By default the stest trap 'error' and 'spec-viol' log messages.
trap_log without an object sets the default handling for the
given log type. Object specific settings always take precedence over
the default handling.
Arguments:
- logtype
- the type of log messages to trap, one of 'info', 'error', 'undef',
'spec-viol', and 'unimpl'
- obj
- the configuration object whose log messages to trap, defaults to None,
which means that all log messages of the right type are trapped
- Synopsis
untrap_log(logtype, obj = None)
- Description
- Explicitly allow messages of a given log type. Can be used to undo
a previous trap_log or to filter objects from a default
trap.
untrap_log without an object sets the default behavior for the
given log type. Object specific settings always take precedence over
the default handling.
Arguments:
- logtype
- the type of log messages to untrap, one of 'info', 'error', 'undef',
'spec-viol', and 'unimpl'
- obj
- the configuration object whose log messages to untrap, defaults to None,
which means that all log messages of the right type are untrapped
- Synopsis
expect_true(cond, msg = 'expectation failed')
- Description
- Check if a condition is true and cause a test failure if it is not.
Arguments:
- cond
- the condition to test
- msg
- a message explaining the failure
- Synopsis
expect_false(cond, msg = 'expectation failed')
- Description
- Check if a condition is false and cause a test failure if it is not.
Arguments:
- cond
- the condition to test
- msg
- a message explaining the failure
- Synopsis
expect_equal(got, expected, msg = 'expectation failed')
- Description
- Checks if a value is equal to an expectation and cause a test failure if it
is not.
Arguments:
- got
- the value to check
- expected
- what to compare the value with
- msg
- a message explaining the failure
- Synopsis
expect_different(got, unexpected, msg = 'expectation failed')
- Description
- Checks if a value is different to an expectation and cause a test failure if
it is not.
Arguments:
- got
- the value to check
- unexpected
- what to compare the value with
- msg
- a message explaining the failure
- Synopsis
expect_log(fun, args = [], obj = None, log_type = 'error', msg = None, regex = '', with_log_level = None)
- Description
- Call a function and verify that a particular log message is emitted.
Returns the called function's return value.
Arguments:
- fun
- the function to be called
- args
- the arguments with which to call fun
All other arguments are identical to expect_log_mgr
- Synopsis
expect_log_mgr(*args, **kwds)
- Description
- Context manager, verifying that, on exit from the with-statement, a
particular log message has been emitted.
Arguments:
- obj
- optional object from which a log is expected,
default is None which accepts any object
- log_type
- optional log type which the emitted log must belong to,
one of "error" (default), "unimpl", "info", "spec-viol"
or "undefined"
- msg
- optional message emitted on failure
- regex
- optional regular expression object or a string
containing a regular expression suitable for use by
re.search(), which the emitted log must match
- with_log_level
- optional log level to apply inside the context
Example usage:
with stest.expect_log_mgr(log_type="spec-viol",
msg="Check warning on read-only fields"):
reg_compute_units.write(0xffff_ffff_ffff_ffff)
- Synopsis
expect_exception(fun, args, exc, regex = '')
- Description
- Call function fun with arguments args, and verify that it raises an
exception of type exc. If fun does not raise exc, cause a failure.
- Synopsis
expect_exception_mgr(*args, **kwds)
- Description
- Context manager verifying that the body of with-statement throws an
exception of the specified type.
Arguments:
- exc
- exception type
- regex
- optional regular expression object or a string
containing a regular expression suitable for use by
re.search(), which the string representation of raised exception
must match
Example usage:
with stest.expect_exception_mgr(simics.SimExc_AttrNotWritable):
dev.read_only_attribute = False
- Synopsis
deprecation_level(*args, **kwds)
- Description
- Context manager for temporarily setting a deprecation level and restore it
when exiting the context.
Arguments:
- level
- deprecation level in context
Example usage:
with stest.deprecation_level(2)
stest.expect_equal(conf.sim.deprecation_level, 2)
- Superclasses
- builtins.Exception
- Description
- Exception class used to signal failures in Simics tests.
Use the fail function instead of raising this exception yourself.
A Python module for writing device model tests. Has three major
parts: classes for accessing device registers, classes for writing
device stubs, and classes for handling simulated memory and data
structures in it. It also contains some auxiliary utilities.
It uses the Simics API and can only be used by Python code running
in Simics.
- Synopsis
bank_regs(bank, inquiry = False, prefix = '')
- Description
- Given a bank object, return a structure containing
objects to access its registers. The returned structure can be a
hierarchy of objects; e.g., if a register instance is named
"g[2][3].r[1]", and the returned structure is o,
then the corresponding register object can be obtained as
o.g[2][3].g[1]. The set of registers is extracted using
the register_view interface, and uses offsets and
bitfields as returned by that interface.
The inquiry argument is deprecated and should not be used.
If prefix is
given, then the returned structure will only contain registers whose
full name matches this prefix.
The returned register objects have methods read() and
write() that work like their AbstractRegister
counterparts, reading and writing the register with side-effects.
The register value can be read and written without side-effects
objects by getting and setting a property .val, or by
calling a method set(). The latter accepts keyword
arguments for fields just like the write() method; bits not
covered by fields are retrieved by reading .val. The
positional argument of the write() method is required and
may be either an integer, or READ to denote that previous
values are retrieved using read(), or VAL to denote that
they are retrieved using .val.
In addition to the val property and set,
read and write methods mentioned above, register
objects also have the following properties:
bank: The Simics configuration object of the bank
size, offset: the register's location within
the bank
bitfield: a dev_util.Bitfield describing the
name: the name of the register, relative to the bank.
Objects that represent the fields of a register can be retrieved as
reg.field.FIELDNAME; e.g., if a register reg has a
field named "a.b[2]" then the field object is accessed as
reg.field.a.b[2]. The field object has one method
read() for performing a full-register read with
side-effects and returning the bits corresponding to the field, and
a property .val that allows side-effect free access to the
field's bits. Field objects provide a read method, which reads
the parent register and returns the bits corresponding to the field,
but it does not have a write method;
writes must be done from the register object to ensure that
remaining bits are explicitly specified. Field objects also provide
the following properties:
reg: The parent register object
lsb, bits: the bit range within the parent register
name: the name of the field, relative to the parent register
- Synopsis
iface(name)
- Description
- Deprecated.
- Synopsis
value_to_tuple_be(val, bytes)
- Description
- Deprecated, use
tuple(val.to_bytes(bytes, 'big')) instead.
- Synopsis
value_to_tuple_le(val, bytes)
- Description
- Deprecated, use
tuple(val.to_bytes(bytes, 'little')) instead.
- Synopsis
tuple_to_value_be(t)
- Description
- Deprecated, use
int.from_bytes(t, 'big') instead.
- Synopsis
tuple_to_value_le(t)
- Description
- Deprecated, use
int.from_bytes(t, 'little') instead.
- Superclasses
- builtins.Exception
- Description
- Baseclass of all exceptions specified in this module.
- Superclasses
- dev_util.Error
- Description
- Signals that a bitfield's parameters are invalid.
- Superclasses
- dev_util.Error
- Constructor
RangeError(msg, re = None)
- Description
- Signals that a value is out of range for a bitfield.
- Superclasses
- dev_util.Error
- Description
- Signals that a memory operation failed.
- Superclasses
- builtins.object
- Constructor
Bitfield(fields = None, ones = 0, little_endian = True, bits = None, **kwargs)
- Description
- Utility for bitfield manipulations.
Constructor arguments:
- fields
- a dict on the following format,
where sub-field is of type fields:
{'field-name' : bit-number,
'field-name' : (start-bit, stop-bit),
'field-name' : (start-bit, sub-field)
}
- ones
- a bitmask that will be OR:ed in the complete bitfield value
- little-endian
- set to True for a little-endian bitorder field and False for
big-endian bitorder fields
- bits
- the total size (in bits) of the fields; required by, as well as
only allowed for, big-endian fields
- **kwargs
- as fields, but specified using keyword arguments
- Synopsis
obj.fields(value)
- Description
- Returns a dict consisting of all fields and their values,
taken from the value argument.
- Synopsis
obj.mask(**dict)
- Description
- Returns a mask from the fields in dict.
- Synopsis
obj.mk_bitfield_map(m, prefix = '', oset = 0)
- Description
- Convert a nested layout type to a map suitable for construction
of a dev_util.Bitfield object.
- Synopsis
obj.value(*args, **kwargs)
- Description
- Returns the value of the
fields given by **kwargs. For example, pass
foo=5 to
return the value when field "foo" is 5. If the value is
a list or dict rather than an integer, then a field array is
assumed; e.g. foo=[1,2] is a shorthand for setting
field "foo[0]" to 1 and field "foo[1]" to 2,
and foo={1:4} is a shorthand for setting field
"foo[1]" to 4.
An optional positional argument can be
supplied, to provide the values of bits not covered by the given
fields.
- Superclasses
- dev_util.Bitfield
- Constructor
Bitfield_LE(fields = None, ones = 0, **kwargs)
- Description
- Constructor arguments:
- fields
- a dict on the following format,
where sub-field is of type fields:
{'field-name' : bit-number,
'field-name' : (start-bit, stop-bit),
'field-name' : (start-bit, sub-field)
}
- ones
- a bitmask that will be OR:ed in the complete bitfield value
- **kwargs
- as fields, but specified using keyword arguments
- Superclasses
- dev_util.Bitfield
- Constructor
Bitfield_BE(fields = None, ones = 0, bits = None, **kwargs)
- Description
- Bit-endian bitfield.
Constructor arguments:
- fields
- a dict on the following format,
where sub-field is of type fields:
{'field-name' : bit-number,
'field-name' : (start-bit, stop-bit),
'field-name' : (start-bit, sub-field)
}
- ones
- a bitmask that will be OR:ed in the complete bitfield value
- bits
- the total size (in bits) of the fields; required by big-endian
fields
- **kwargs
- as fields, but specified using keyword arguments
- Superclasses
- builtins.object
- Constructor
AbstractRegister(size = 4, bitfield = None, little_endian = True)
- Description
- Abstract register class.
This class handles generic register stuff, like bitfield mapping
and value construction/deconstruction. It depends on a subclass to
implement the backend for data storage.
Subclasses are expected to implement two functions:
- raw_read(self)
- should return a byte string from storage
- raw_write(self, bytes)
- should write the bytes byte string to storage
Optionally, a bitfield can be applied to a register. For such a register,
a specific field can be read through reg.field.FIELDNAME.read(). The
write() method also has support for bitfields. Please see the
documentation for write() for more information.
There is an alternative deprecated shorthand for accessing fields:
reg.FIELDNAME triggers a read that filters out the given
field, and similarly, reg.FIELDNAME = value reads the
field, adjusts the given field, and writes back the value. This
syntax is deprecated, because it is not consistent with the API
exposed by register objects that both support accesses with and
without side-effects.
Constructor arguments:
- size
- the size in bytes of the register
- bitfield
- optional, if set should be an instance of Bitfield
- little_endian
- should be set to True for a little-endian byte-order
register, or False for a big-endian register
- Synopsis
obj.fields()
- Description
- Shortcut to read the bitfield representation of a device register.
- Synopsis
obj.read()
- Description
- Read value.
- Synopsis
obj.write(*args, **fields)
- Description
- Write value. The value will be truncated to the register size.
You can either pass a single integer, or pass the fields as
arguments, i.e., write(field0=1, field1=23). For field
arrays, the syntax write(field=[1,23]) or
write(field={0: 1, 1: 23}) can be used to set the fields named
field[0] and field[1].
If only a subset of fields is given, a positional arg should
also be passed for the base value, which defines what to write to
remaining bits. The value READ denotes that the read() method is
called to retrieve the base value.
- Superclasses
- dev_util.AbstractRegister
- Constructor
Register(*args, **kwargs)
- Description
- This class allows you to easily access a device register.
The bank argument is normally the bank object. However, for
backward compatibility it can also be a tuple (obj, bank, ofs);
in this case the offset argument should be left
out. The tuple denotes:
- obj
- the (simics) object implementing the register
- bank
- the port-name or function number of the bank containing the
register (function 0 if omitted).
- offset
- the register offset in said bank
The tuple syntax was useful in old Simics versions where
banks were not separate objects. It should be avoided in new versions.
The initiator argument denotes the initiator of transactions
accessing the register.
See the AbstractRegister documentation for information about the rest
of the parameters.
- Synopsis
obj.raw_read()
- Description
- Read raw data from the register.
- Synopsis
obj.raw_write(val)
- Description
- Write raw data to the register.
- Superclasses
- dev_util.Register
- Constructor
Register_LE(*args, **kwargs)
- Description
- Little-endian device register.
All arguments have the same semantics as in dev_util.Register.
- Superclasses
- dev_util.Register
- Constructor
Register_BE(*args, **kwargs)
- Description
- Big-endian device register.
All arguments have the same semantics as in dev_util.Register.
- Superclasses
- dev_util.AbstractRegister
- Constructor
GRegister(size = 4, bitfield = None, init = 0)
- Description
- This class allows provides a standalone register.
- Synopsis
obj.raw_read()
- Description
- Reads the raw contents of the register.
- Synopsis
obj.raw_write(value)
- Description
- Write the raw contents of the register.
- Superclasses
- dev_util.AbstractRegister
- Constructor
IRegister(data, size = None, bitfield = None)
- Description
- This class allows you to easily access registers through the
int_register interface. If the object obj does
not implement the processor_info you have to specify the
size in size.
- Synopsis
obj.raw_read()
- Description
- Reads the raw contents of the register.
- Synopsis
obj.raw_write(value)
- Description
- Write the raw contents of the register.
- Superclasses
- builtins.object
- Constructor
Dev(iface_list = [], create_sim_obj = True, name = None)
- Description
- A Simics class with a single instance.
Implements zero or more interfaces based on instances of
Iface. Presents zero or
more ports, implementing one or more interfaces each.
The obj attribute contains the instance of the Simics
class, and the cls_name attribute contains the name of
the Simics class.
Constructor arguments:
- iface_list
- a list of interface classes or pairs of
(port, interface-class)
- create_sim_obj
- if False, no Simics object will be created, but the
class will be registered along with all the interfaces, useful
e.g. when loading a checkpoint containing fake objects
- name
- if given, specifies the name to use for the fake class and
the fake object; otherwise a name will be guessed based on the
implemented interfaces
Each interface will be instantiated and can be accessed through
dev.iface-name,
or dev.port.iface-name.
Example:
dev = Dev([SimpleInterrupt,
('sreset', Signal),
('hreset', Signal)])
dev.simple_interrupt
dev.sreset.signal
dev.hreset.signal
- Synopsis
obj.configure_pre_object(pre_obj)
- Description
- Called before SIM_add_configuration.
Override to e.g. set attributes.
- Synopsis
obj.finalize()
- Description
- Called after the Simics object has been instantiated.
- Synopsis
obj.register_simics_class()
- Description
- Register the Simics class created by this object.
- Superclasses
- dev_util_internal.BasicIface
- Constructor
Iface()
- Description
- Base class for fake interfaces. To create an interface, inherit
this class, define a class variable iface to the interface name, and
define all methods that the interface defines.
- Synopsis
obj.fail(msg)
- Description
- Signal a failure when running an interface method.
Called by the default method stubs.
- Superclasses
- builtins.object
- Constructor
Memory()
- Description
- Deprecated.
Legacy wrapper around an instance of the
sparse-memory class.
Provides an interface compatible with the deprecated Memory class.
The obj attribute contains an instance of memory-space,
mapping to the memory. The real_obj attribute contains
an instance of the 'sparse-memory' class. The mem
attribute is an alias to the mem attribute of
real_obj.
- Synopsis
obj.clear(*args)
- Description
- Clear the contents of the memory.
- Synopsis
obj.is_range_touched(start, length)
- Description
- Return True if any of this memory's slots in the range contain data.
- Synopsis
obj.read(addr, n)
- Description
- Read bytes from this memory.
Arguments:
- addr
- the start address of the range to read
- n
- length in bytes of the range to read
Throws an exception if any byte in the read range is empty.
- Synopsis
obj.write(addr, data)
- Description
- Write bytes to this memory.
Arguments:
- addr
- the start address of the range to write
- data
- the bytes to write
Fills in empty slots in the memory and overwrites already existing data.
- Superclasses
- builtins.object
- Constructor
Layout(mem, ofs, regs, little_endian)
- Description
- This class implements a memory layout.
Testing devices that does DMA transfers usually requires setting up
DMA descriptors. These can often be seen as register sets located in
memory. This class allows you to define the layout of those registers,
including bitfields within the registers.
Registers without bitfields can be accessed through:
layout.reg-name
while registers with bitfields can be accessed through:
layout.reg-name.field-name
or
layout.reg-name.read(),
layout.reg-name.write()
Layouts are mapped ontop of Memory, i.e. NOT ontop of normal Simics RAM.
Constructor arguments:
- mem
- An object that is a valid "map target"
- ofs
- the byte offset (i.e. the location of the layout)
- little_endian
- determines the byte order of the registers in the layout
- regs
- a dictionary on the following form:
{'reg-name' : (offset, size),
'reg-name' : (offset, size, bitfield)}
- offset
- the register offset into the layout
- size
- the size in bytes of the register
- bitfield
- optional and should be an instance of Bitfield
- Synopsis
obj.clear()
- Description
- Set all of the fields in this layout to 0.
- Synopsis
obj.read(ofs, size)
- Description
- Returns the value at ofs.
- Synopsis
obj.write(ofs, value, size)
- Description
- Writes value to ofs.
- Superclasses
- dev_util.Layout
- Constructor
Layout_LE(mem, ofs, regs)
- Description
- Little-endian layout.
- Superclasses
- dev_util.Layout
- Constructor
Layout_BE(mem, ofs, regs)
- Description
- Big-endian layout.
Internal and/or legacy classes removed from dev_util.py
- Synopsis
iface(name)
- Description
- Returns an Iface subclass which implements the interface name.
All the interface methods in the class will raise an exception when
called. Convenient when creating a fake device that is required to
implement an interface, but you know that the interface should be
unused in the given test.
- Superclasses
- builtins.object
- Constructor
Dev(iface_list = [], create_sim_obj = True, name = None)
- Description
- A Simics class with a single instance.
Implements zero or more interfaces based on instances of
Iface. Presents zero or
more ports, implementing one or more interfaces each.
The obj attribute contains the instance of the Simics
class, and the cls_name attribute contains the name of
the Simics class.
Constructor arguments:
- iface_list
- a list of interface classes or pairs of
(port, interface-class)
- create_sim_obj
- if False, no Simics object will be created, but the
class will be registered along with all the interfaces, useful
e.g. when loading a checkpoint containing fake objects
- name
- if given, specifies the name to use for the fake class and
the fake object; otherwise a name will be guessed based on the
implemented interfaces
Each interface will be instantiated and can be accessed through
dev.iface-name,
or dev.port.iface-name.
Example:
dev = Dev([SimpleInterrupt,
('sreset', Signal),
('hreset', Signal)])
dev.simple_interrupt
dev.sreset.signal
dev.hreset.signal
- Synopsis
obj.configure_pre_object(pre_obj)
- Description
- Called before SIM_add_configuration.
Override to e.g. set attributes.
- Synopsis
obj.finalize()
- Description
- Called after the Simics object has been instantiated.
- Synopsis
obj.register_simics_class()
- Description
- Register the Simics class created by this object.
- Superclasses
- dev_util_internal.BasicIface
- Constructor
Iface()
- Description
- Base class for fake interfaces. To create an interface, inherit
this class, define a class variable iface to the interface name, and
define all methods that the interface defines.
- Synopsis
obj.fail(msg)
- Description
- Signal a failure when running an interface method.
Called by the default method stubs.
- Superclasses
- dev_util_internal.Dev
- Constructor
Memory(test = False)
- Description
- A Simics memory space in which every slot can contain a byte, or be empty.
Each byte sized slot in this memory can either contain a byte of data or
be empty. Empty slots cannot be read.
The obj attribute contains the object implementing the Simics
interface to the memory. It implements the memory_space
interface.
Constructor arguments:
- test
- set to True to not create any Simics objects, optional,
defaults to False
- Synopsis
obj.clear()
- Description
- Clear the contents of the memory.
- Synopsis
obj.is_range_touched(start, length)
- Description
- Return True if any of this memory's slots in the range contain data.
- Synopsis
obj.read(addr, n)
- Description
- Read bytes from this memory.
Arguments:
- addr
- the start address of the range to read
- n
- length in bytes of the range to read
This method throws an exception if any byte in the read range is empty.
- Synopsis
obj.write(addr, bytes)
- Description
- Write bytes to this memory.
Arguments:
- addr
- the start address of the range to write
- n
- the bytes to write
Fills in empty slots in the memory and overwrites already existing data.
The Script Branch API is a set of Python functions for controlling
script branches. This API is used when implementing CLI commands that
make use of script branches, and also when waiting for simulator
events via corresponding wait-for- CLI commands. See
the Simics User's Guide for an introduction and examples
of using the API.
- NAME
-
sb_create — create a script branch
- SYNOPSIS
-
sb_create(func, desc = None)
- DESCRIPTION
-
Create a script branch that will start executing func
(which should not take any arguments). The sb_create
function returns a unique script-branch identifier, that can be
used with sb_interrupt_branch. It may be called from a
script branch to create a new parallel branch. The current branch
will resume execution when the new script branch is suspended.
The optional desc argument will be displayed by
list-script-branches as a description of the script
branch.
- RETURN VALUE
-
script-branch identifier
- SEE ALSO
-
script_branch.sb_wait, script_branch.sb_interrupt_branch, script_branch.sb_run_in_main_branch
- EXECUTION CONTEXT
-
Global Context
- NAME
-
sb_get_wait_id — obtain script branch wait ID
- SYNOPSIS
-
sb_get_wait_id()
- DESCRIPTION
-
Return a new unique script-branch wait-identifier that can be
used when suspending a script-branch using sb_wait.
- RETURN VALUE
-
script branch wait-identifier
- SEE ALSO
-
script_branch.sb_wait, script_branch.sb_signal_waiting
- NAME
-
sb_in_main_branch — indicate if the main branch is running
- SYNOPSIS
-
sb_in_main_branch()
- DESCRIPTION
-
Return
true if the main branch is currently active, and not
one of the script branches.
- SEE ALSO
-
script_branch.sb_run_in_main_branch
- NAME
-
sb_interrupt_branch — interrupt suspended script branch
- SYNOPSIS
-
sb_interrupt_branch(branch_id)
- DESCRIPTION
-
Interrupt a script branch that is currently suspended. The
branch_id should be the script-branch identifier
(returned by sb_create) of a suspended script branch,
otherwise an exception is raised.
As a side effect, the sb_wait function called in the
script branch will raise a CliQuietError exception.
- SEE ALSO
-
script_branch.sb_create, script_branch.sb_wait
- NAME
-
sb_run_in_main_branch — run function in the main thread
- SYNOPSIS
-
sb_run_in_main_branch(command, func)
- DESCRIPTION
-
Schedule func (which should not take
any arguments) to run in the main thread and block the calling script-branch
thread until the function has run. A
CliError exception will
be raised if an error occurs while running func, otherwise
its return value is returned.
- RETURN VALUE
-
return value of func
- SEE ALSO
-
script_branch.sb_create, script_branch.sb_in_main_branch
- NAME
-
sb_signal_waiting — wake up a suspended script branch
- SYNOPSIS
-
sb_signal_waiting(wait_id)
- DESCRIPTION
-
Wake up a suspended script-branch, with wait_id as wait
identifier, letting it run again.
- SEE ALSO
-
script_branch.sb_wait, script_branch.sb_get_wait_id
- NAME
-
sb_wait — suspend a script branch
- SYNOPSIS
-
sb_wait(command, wait_id, reverse=None, always=None, wait_data=None,
use_obj=None)
- DESCRIPTION
-
Suspend a script branch in the command command (a
descriptive string) until sb_signal_waiting is called
with wait_id as argument. The reverse and
always should not be used. The wait_data argument
is a string describing the data being waited for, or
None. The use_obj argument is deprecated and
should never be specified.
- SEE ALSO
-
script_branch.sb_create, script_branch.sb_get_wait_id, script_branch.sb_signal_waiting
The probes Python package allows convenient methods for accessing
all probes which has been registered in Simics.
When probes are enabled with the enable-probes command the probe
framework will create Python ProbeProxy objects for all existing
probes in the system. Any additional created objects with probes will
also automatically get ProbeProxy objects.
- NAME
-
CellFormatter — helper object for various format properties
- DESCRIPTION
-
Helper Class for summary-probe formatting. Simply holds various
formatting properties together, in one class object.
- NAME
-
ProbeProxy — wrapper class of probes that exists in Simics
- DESCRIPTION
-
The ProbeProxy class represents a Python object for the detected
probes in the system. The object wrapping allows easier access
to the probe objects through the different probe interfaces.
Object implementing the indexed probe interface, will get a
dedicated ProbeProxy object per index.
The formatting of the different types of probes are also
automatically handled by this class.
- NAME
-
get_all_probe_kinds — get all registered probe-kinds in the system
- SYNOPSIS
-
get_all_probe_kinds()
- DESCRIPTION
-
Returns all registered probe-kinds in the system. The probe-kind is
the unique probe identifier, not including the objects associated
with it.
- SEE ALSO
-
probes.get_probes, probes.get_all_probes
- NAME
-
get_all_probes — get all ProbeProxy instances
- SYNOPSIS
-
get_all_probes()
- DESCRIPTION
-
Returns all Python 'ProbeProxy' objects that exists currently.
These objects can be used to access the probe interfaces in a
convenient way by using methods in them.
- SEE ALSO
-
probes.get_all_probe_kinds, probes.get_probes
- NAME
-
get_probe_by_object — get the ProbeProxy instance for an object
- SYNOPSIS
-
get_probe_by_object(kind, obj)
- DESCRIPTION
-
Returns the 'ProbeProxy' Python object for a probe-kind in a
specific conf object.
- SEE ALSO
-
probes.get_all_probe_kinds, probes.get_probes
- NAME
-
get_probes — get hold of all ProbeProxy instances implementing a specific probe-kind
- SYNOPSIS
-
get_probes(kind)
- DESCRIPTION
-
Returns the Python 'ProbeProxy' objects, for probes matching the specific
probe-kind.
These objects can be used to access the probe interfaces in a
convenient way by using methods in them.
- SEE ALSO
-
probes.get_all_probe_kinds, probes.get_all_probes
- NAME
-
register_probe_delete_cb — request a callback when a probe is deleted
- SYNOPSIS
-
register_probe_delete_cb(cb)
- DESCRIPTION
-
Register a function which will be called when a probe is deleted from
the system. The function only takes a single argument; the ProbeProxy
instances that is about to be deleted.
- SEE ALSO
-
probes.unregister_probe_delete_cb
- NAME
-
unregister_probe_delete_cb — cancel a callback for probe deletion
- SYNOPSIS
-
unregister_probe_delete_cb(cb)
- DESCRIPTION
-
Unregister a function callback when probes are deleted.
Typically needed when a python module itself is removed.
- SEE ALSO
-
probes.register_probe_delete_cb
- NAME
-
CriticalErrors — represents critical errors caused by C code called from Python
- SYNOPSIS
-
CriticalErrors(args)
- DESCRIPTION
-
This exception is raised when returning to Python from a C function
that directly or indirectly caused one or more serious, but
recoverable, errors. Elaborate error descriptions are
printed when the errors occur, but because of error recovery, the
C function will be able to continue without being aware of the error.
A C function can cause more than one error; all these are combined
into a single Python exception. The main purpose of the exception
is to aid debugging, usually by providing a nice Python traceback.
- NAME
-
column_names — get hold of column names from a property list
- SYNOPSIS
-
column_names(prop_list)
- DESCRIPTION
-
Help function to retrieve the column names embedded in
the list of table properties.
- SEE ALSO
-
table.show
- NAME
-
default_table_args — get default table arguments
- SYNOPSIS
-
default_table_args(set_dict={})
- DESCRIPTION
-
Return the tuple representing the default table arguments. The
set_dict can contain key/value elements overriding the default
value. The key is the same as the name of the table argument in
the command.
- SEE ALSO
-
table.new_table_command, table.get
- NAME
-
get — fetch the formatted table
- SYNOPSIS
-
get(properties, data, *table_args)
- DESCRIPTION
-
Similar to the table.show but this function returns the
table as a multi-line string.
- SEE ALSO
-
table.new_table_command, table.get
- NAME
-
get_table_arg_value — retrieve the value for a table command argument
- SYNOPSIS
-
get_table_arg_value(arg, table_values)
- DESCRIPTION
-
Allows the user command to look at a certain named parameter to get
its value. For example, to internally make use of the
-verbose flag.
The arg argument specifies the argument to fetch the
value of. The table_values argument is the tuple of table
arguments received in the table.new_table_command()
callback function.
- NAME
-
new_table_command — register a new command which prints a table
- SYNOPSIS
-
new_table_command(command_name,
cmd_func,
args = None,
doc = "",
sortable_columns = None,
**kwargs)
- DESCRIPTION
-
Register a specific command for printing the table, with
all the command arguments from the <table>.print-table
commands, but extendable with personalized argument handling.
For example, a dedicated command could print out additional data, or
filter out certain rows from the table and only print those.
All arguments here are similar to the cli.new_command() function
except the sortable_columns argument.
The cmd_func function will be called with additional table
argument last. The function should use the table.show()
to produce the table output according to the user arguments.
If the sortable_columns argument is supplied, it should contain
a list of the column namnes which can be used for sorting. This is
only used for the expander function. If this argument is not set, the
default expander will try to use the table interface to retrieve the
column names.
- SEE ALSO
-
cli.new_command, table.show
- NAME
-
show — format and print the table
- SYNOPSIS
-
show(properties, data, *table_args)
- DESCRIPTION
-
This function should be used from a command function registered
through the table.new_table_command() function to
print out the table according to the user arguments.
The properties argument is a list of key/value pairs
setting table properties for the table.
The data argument contains the two-dimensional data
to be printed where the inner list contains the columns and the
outer list the rows of the table.
See the
table interface for more information.
The *table_args argument represents the standard table
arguments, received last in the table.new_table_command()
callback function.
- SEE ALSO
-
table.new_table_command, table.get
- Description
- This hap is triggered on every word sent on a arinc429_bus object. In the hap handler, the last_word attribute can be read or modified. Setting it to -1 will drop the packet.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a CLI command is defined.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *command_name);
- Description
- Internal: Similar to Component_Hierarchy_Change but also triggered for components that are not part of any complete hierarchy including non-instantiated components.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Internal: Triggered when an instantiated component hierarchy is modified. The hap is associated with the top-level component of the modified hierarchy.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
conf_object_t *top_level_component);
- Description
- Triggered when the output matches a string set to break on. The break_id is the number associated with the string breakpoint.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *break_string);
- Index
- break_id
- Description
- Triggered when an access to a memory-space has no target and the access does not match any entry in the outside_memory_whitelist CPU attribute. The default handler for this hap will signal an error and stop the simulation.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
int64 physical_address, int64 access_type,
int64 size);
- Description
- SPARC: Triggered when an asynchronous trap occurs. This is either an external interrupt trap number == 0x60 or interrupt level n trap number 0x41 - 0x4F, or an asynchronous trap initiated by the user calling trap_cpu in the sparc-interrupt interface. The Core_External_Interrupt can also be used to catch interrupts, the difference is that Core_Asynchronous_Trap is only triggered if interrupts are enabled.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 trap_number);
- Index
- trap_number
- Description
- Triggered, typically by SIM_quit, when Simics exits. The Simics API is not allowed to be used in the hap callbacks (see the Core_Clean_At_Exit hap description if access to the Simics API is needed).
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered on an object when breakpoints attached to that object are inserted, deleted or changed in any way.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a breakpoint is triggered. breakpoint_number is the breakpoint number (as returned by SIM_breakpoint). If there are multiple breakpoints on an instruction then all installed haps will be run before control is transferred to the frontend (when applicable). The supplied memop can be used to figure out details about the transaction.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
int64 breakpoint_number,
generic_transaction_t *memop);
- Index
- breakpoint_number
- Description
- Triggered, typically by SIM_quit, if Simics exits cleanly, i.e. in Global Context. The Simics API is available. Cleanup code should typically run in the Core_At_Exit hap callbacks instead if possible.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a new configuration class has been registered. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *class_name);
- Description
- Triggered when a configuration class has been unregistered. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *class_name);
- Description
- Triggered when a clock object changes cell
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
conf_object_t *old_cell, conf_object_t *new_cell);
- Description
- Triggered when an object's reference clock is changed
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
conf_object_t *old_clock,
conf_object_t *new_clock);
- Description
- Triggered when a new configuration object's init_object method returns successfully, but before the object's attributes are set and before the object's finalize_instance method is called. Since the object is not fully created hap callbacks must not access any of the object's attributes or call any methods on the object's interfaces. Callbacks are called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a configuration object has been created and finalized. This hap will always be followed by a Core_Conf_Objects_Created hap, but this hap can be triggered for more than one object before the Core_Conf_Objects_Created hap.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered after a configuration object has been deleted. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *object_name);
- Description
- Triggered just before a configuration object is deleted. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered after an object's name has changed. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *old_name);
- Description
- Triggered if and only if at least one Core_Conf_Object_Created hap has been triggered.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when one or more objects have been deleted from the configuration after the Core_Conf_Object_Delete hap has been triggered for all of the objects. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a configuration has been loaded. This hap can be triggered several times during a session since it is possible to append a new configuration to the existing one. In most cases it is better to use the finalize_instance function in the
class_data_t instead. That function is called when the object creation is finished. Callbacks are called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when this context replaces another context as the current context of a processor.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
conf_object_t *other_ctx, conf_object_t *cpu);
- Description
- Triggered when the context is set to the current context for a processor.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, conf_object_t *cpu);
- Description
- Triggered when another context replaces this context as the current context of a processor.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
conf_object_t *other_ctx, conf_object_t *cpu);
- Description
- Triggered when the context is updated in some way.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered at the (re)start of the simulation. The
Core_Simulation_Stopped hap is called when the simulation is stopped. Callbacks are called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a control register is read. The hap is called before the read is performed; thus no registers have been modified.
Note that if the callback routine breaks to the frontend by raising an exception, the instruction will be replayed possibly causing repeated memory operations.
For x86 processors, this hap is triggered when a control register is read using a mov or smsw instruction (i.e. only explicit reads). Also the hap is triggered when MSRs are read with rdmsr, rdtsc or rdtscp instructions.
For PowerPC processors, this hap is triggered by the mfspr, mfmsr mfsr and mfsrin instructions (i.e. only explicit reads).
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 register_number);
- Index
- register_number
- Description
- Triggered when a control register is written. Note that value is not (necessarily) the final contents in the register. When the callback is called, the processor register has not yet been updated with the new value.
If the callback routine breaks to the frontend by raising an exception, the instruction will be replayed possibly causing repeated memory operations.
For x86 processors, this hap is triggered by clts, lmsw, and mov. Also the hap is triggered when MSRs are written with wrmsr instruction. Page fault updates of CR2 should be caught with the Core_Exception hap.
For PowerPC processors, this hap is triggered by the mtspr, mtmsr, mtsr and mtsrin instructions (i.e. only explicit writes).
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 register_number,
int64 value);
- Index
- register_number
- Description
- Triggered when a device access is performed.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
generic_transaction_t *memop);
- Description
- Triggered when the DSTC flushes a line's hit counter. It reports how many hits the STC recorded since the line was inserted.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 type,
int64 virtual_address, int64 physical_address,
int64 counter);
- Description
- Triggered when an exception/trap is taken by a processor. The hap occurs before side-effects, control transfers included, have taken place.
Interrupting the simulation by calling SIM_break_simulation inside the hap will cause the simulation to stop right before the exception (and the trapping instruction, if any). The simulation state will then be as it was prior to the execution of the instruction or exception. Continuing the simulation will then re-run the exception, this time without calling hap functions.
Depending on the processor model, some state may actually have changed in an idempotent way when the hap occurs, but this should not be relied upon.
The exact meaning of the exception number depends on the simulated processor architecture. The exception interface can be used to translate the number to an exception name.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
int64 exception_number);
- Index
- exception_number
- Description
- Triggered when an exception/trap handler finishes execution. The hap is triggered before any processor state has changed.
The following instructions trigger this hap (by processor class):
MIPS: eret and deret
PowerPC (32): rfi and rfci
PowerPC (64): rfi, rfid and hrfid
SH: rte
SPARC: done and retry
x86/x86-64: The iret family.
The exception_number parameter is only valid for SPARC processors.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
int64 exception_number);
- Index
- exception_number
- Description
- (SPARC only) Triggered when a processor receives an external interrupt. The trigger object is the receiving cpu, and source_mid is the mid of the sending cpu/device. The hap will be triggered even if interrupts are disabled, but not if the interrupt logic is busy.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 source_mid);
- Index
- source_mid
- Description
- Triggered when the frequency of a cycle queue has changed. Parameters are the old and new frequencies in Hz.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 old_freq,
int64 new_freq);
- Description
- Triggered before a callback is installed. The callback called by this hap is not allowed to install any hap callbacks.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 hap_number,
int64 range_low, int64 range_high);
- Index
- hap_number
- Description
- Triggered after a callback has been unregistered. The callback called by this hap is not allowed to remove any hap callbacks.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 hap_number,
int64 range_low, int64 range_high);
- Index
- hap_number
- Description
- Triggered when a new hap type is added to the simulator. The hap is not triggered for the initial set of core haps. Callbacks called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *hap_name);
- Description
- Triggered on I/O activity in an image object.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int type, int onoff);
- Description
- Triggered when the active log groups of an object changes
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int log_group_mask);
- Description
- Triggered when the log level of an object changes
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int new_log_level);
- Description
- Triggered when a log message is registered that is supposed to be logged, i.e. with matching type and group(s) and level.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int type,
char *message);
- Index
- log type
- Description
- Triggered always when a log message is registered regardless of the current log level
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int type,
char *message, int level, int64 group);
- Description
- Triggered when a log message is registered that is supposed to be logged according to the log level.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int type,
char *message, int level, int64 group);
- Description
- Triggered when a log message is registered that is supposed to be logged, i.e. with matching type and group(s) and level.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int type,
char *message, int level, int64 group);
- Description
- Triggered when Simics executes a magic instruction. The parameter is taken from the instruction and is architecture-dependent.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 parameter);
- Index
- parameter
- Description
- Experimental
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a processor changes privilege mode for whatever reason; usually an exception or return from an exception. The hap occurs after the processor has changed mode but before any instructions have been executed in the new mode.
For x86 processors, the modes are Sim_CPU_Mode_User for CPL 3, and Sim_CPU_Mode_Supervisor for CPL 0-2.
For other processors, the modes are Sim_CPU_Mode_User or Sim_CPU_Mode_Supervisor. Some processors also has the Sim_CPU_Mode_Hypervisor mode.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 old_mode,
int64 new_mode);
- Description
- Triggered when a module is loaded into Simics. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *module_name);
- Description
- Triggered when the multicore-accelerator feature is enabled or disabled.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int on/off);
- Description
- Triggered when multithreaded simulation is enabled or disabled.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int on/off);
- Description
- Triggered when the simulator encounters unimplemented functionality.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int line, char *file,
char *rcsid, char *message, int64 data);
- Description
- Triggered when an attribute in the prefs object is written. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when the scheduling order of the processors has changed. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a new Simics project directory is selected. Called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when the simulation mode for the processor has changed.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int simulation_mode);
- Index
- simulation_mode
- Description
- Triggered when the simulation stops. The exception argument will always be
SimExc_No_Exception, and error_string will always be NULL. After this hap, simulation will not advance (triggering Core_Continuation) until SIM_continue is called again. Callbacks are called in Global Context.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 exception,
char *error_string);
- Index
- exception
- Description
- Triggered when an synchronizing instruction is executed. The type parameter describe what kind of instruction is executing. Its encoding is specific to each architecture.
For SH, this hap is triggered when a synco instruction is executed. The type contains 0.
For SPARC-V9, this hap is triggered when a membar or stbar instruction is executed. For membar, the type contains the 7-bit field cmask|mmask specified in the instruction. For stbar, the type is 8 (equivalent to membar #StoreStore).
For x86, this hap is triggered when a fence instruction is executed. The type is set from the list provided by the x86_sync_instruction_type_t enum.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 type);
- Index
- type
- Description
- Triggered on an object when a timing model or snoop device is inserted, deleted, or changed.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered by the eth_injector object when all contents of the pcap file has been sent. The callback function will have the pcap file name, next packet index, total number of packets in the pcap file, and auto-restart as arguments.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *pcap_file,
int num_injected, int pcap_num_pkgs,
int auto_restart);
- Description
- Triggered when the bus is reset. It is invoked after calculating the default topology. During the hap the self_ids attribute can be used to change the self id packets sent to the devices on the bus. The connected_devices attribute can also be changed to modify the mapping from physical id to device.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when an packet travels through a firewire bus. During the hap handler the current_transfer attribute of the bus can be used to inspect and/or change the current transfer. If you set it to NULL the transfer is aborted and Firewire_V2_Ack_No_Ack is returned to the initiator of the transfer.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Triggered when a graphical breakpoint matches the screen. break_id is the number returned when a breakpoint is set.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 gfx_break);
- Index
- break_id
- Description
- Simics internal. Triggered on a break-io access.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int break-id);
- Description
- Simics internal. Triggered on an access to a device register traced with trace-io command.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj,
generic_transaction_t *memop, char *port, int idx,
int func, int64 offset);
- Description
- Simics internal
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Index
- id
- Description
- Simics internal. Triggered when the time quantum has changed. The hap is supported in Simics 5 even though it is marked as internal.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);
- Description
- Internal: Notifies change of realtime enabled status
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int enabled);
- Description
- This hap is triggered when the DS12887-c NVRAM memory is changed.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 index,
int64 old_value, int64 new_value);
- Index
- index
- Description
- Triggered when a SCSI command is received by a SCSI device. The parameters start and len are only used for read and write commands.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 command_number,
int64 start, int64 len);
- Index
- command_number
- Description
- Triggered when NAPT is enabled or disabled in a service-node.The argument is 0 when disabled and 1 when enabled.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int enabled);
- Description
- Triggered when a TLB entry is filled after a table walk. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- Triggered when a TLB entry is filled after a table walk. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- Triggered when a TLB entry is invalidated. The invalidation can be caused by an INVLPG instruction, a write to CR3, or by changes to paging bits in CR0 and CR4. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- Triggered when a TLB entry is invalidated. The invalidation can be caused by an INVLPG instruction, a write to CR3, or by changes to paging bits in CR0 and CR4. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- Triggered when a DTLB miss occurs.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear_address);
- Index
- linear_address
- Description
- Triggered when an ITLB miss occurs.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear_address);
- Index
- linear_address
- Description
- This hap is triggered when a TLB entry is replaced by another. The parameters relate to the old entry, and the insertion of the new entry will trigger a fill hap. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- This hap is triggered when a TLB entry is replaced by another. The parameters relate to the old entry, and the insertion of the new entry will trigger a fill hap. Page size encoding: 0==4k, 1==2M, 2==4M, 3==1G.
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, int64 linear,
int64 physical, int64 page_size);
- Index
- page_size
- Description
- Triggered when the run state changes; not triggered in batch mode. The argument is one of:
"Stopped"- simulation stopped and may not run
"Stopped_Fwd"- stopped and may run forward
"Forwarding"- simulation is running forward
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj, char *state);
- Description
- Triggered before picture on screen is updated
- Callback Type
void (*)(lang_void *callback_data,
conf_object_t *trigger_obj);