One advantage of a simulated target is the ability to inspect and control it in ways that are not possible on real hardware. The Simics hap system gives the user access to important events in the system and there are ways to trace all memory accesses and for processor initiated accesses even adjust their timing. Similarly, network packets and other bus traffic can be inspected. It is often also possible to inject and change data in the system, both for debugging and testing purposes, such as sending or modifying network packages, changing register values or memory contents. This chapter and the text describes some of the mechanisms available and also gives examples of how they can be used, but there are many other possibilities, such as creating real world connections, covered in more detail in chapter 44.
As described in the Simics User's Guide, a hap is an event in Simics that, when occurring, will call any callback functions installed for it. The rich collection of haps in Simics for both simulator and target related events, including new, user-defined haps, provides the user with powerful control and inspection capabilities.
Some haps are system global, such as the hap triggered when the simulator exits, but most are associated with an object. For such haps it is possible to install the callback to trigger for all objects or only for a selected one.
It is important to know that hap callbacks are run at once when the hap is triggered. For example, this may be in Cell Context, when the simulation is running and many API functions can not be run. (The API Reference Manual includes a description of all execution contexts and their restrictions and the reference manuals lists the allowed execution contexts for all API functions.) To overcome these restrictions, Simics provides several functions for posting callbacks that are run when the simulator is in a less restricted state, such as SIM_run_alone
and SIM_run_unrestricted
.
When you want your code to react to a hap occurrence, you can register a callback function for the specific hap.
# In Python
SIM_hap_add_callback(hap, func, user_data)
// In C
hap_handle_t
SIM_hap_add_callback(const char *hap, obj_hap_func_t func, lang_void *data);
The parameters of SIM_hap_add_callback()
are:
hap
—The name of the hap to install a callback function on. func
—The function to be called when the hap is triggered. The signature for this callback function differs between haps. user_data
—User data that will be passed as-is by Simics to the callback function. The function returns a handle which can be used to manipulate the hap callback later on, typically used to disable it. There are additionally several other functions that can be used to register a hap callback The _obj
kind installs a callback that only reacts on haps triggered by a specific object. The _index
and _range
kinds are used for haps that have an index associated with them, and is used to only trigger the hap for one or a range of the indexes. The names of these other functions are SIM_hap_add_callback_index()
, SIM_hap_add_callback_range()
, SIM_hap_add_callback_obj()
, SIM_hap_add_callback_obj_index()
and SIM_hap_add_callback_obj_range()
. See the API Reference Manual for more information about the differences between them.
A list of all haps can be found in the Simics Reference Manual, including the signatures for the callback functions. The list can also be retrieved on the command line using the list-haps
command. This command can also be used to print detailed information about a hap:
simics> list-haps hap = Core_Simulation_Stopped
Name
Core_Simulation_Stopped
Callback Type
void (*)(lang_void *callback_data, conf_object_t *trigger_obj,
integer_t exception, char *error_string);
Index
exception
Installed Handlers
5
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.
The following is an example of using a hap from C and from Python:
# In Python
def stopped(user_data, obj, exception, errstr):
print("Stopped")
def started(user_data, obj):
print("Started")
handle1 = SIM_hap_add_callback("Core_Continuation", started, None);
handle2 = SIM_hap_add_callback("Core_Simulation_Stopped", stopped, (2, "str"))
[…]
// In C
static void
stopped(void *user_data, conf_object_t *obj, int64 exception, char *errstr)
{
pr("Stopped\n");
}
static void
started(void *user_data, conf_object_t *obj)
{
pr("Started\n");
}
static hap_handle_t h1, h2;
void
init_local()
{
[…]
h1 = SIM_hap_add_callback("Core_Continuation", started, NULL);
h2 = SIM_hap_add_callback("Core_Simulation_Stopped", stopped, NULL);
[…]
}
When you no longer want to be notified when a hap triggers, the callback can be canceled using one of the functions SIM_hap_delete_callback()
, SIM_hap_delete_callback_obj()
, SIM_hap_delete_callback_id()
and SIM_hap_delete_callback_obj_id()
. See the API Reference Manual for the differences. The signature for SIM_hap_delete_callback()
is:
SIM_hap_delete_callback(hap, func, user_data)
Where the parameters are the same as for installing the hap callback. The exact same parameter must be used as the callback was registered with.
To continue the above example:
# In Python
def at_end():
# using the callback parameters
SIM_hap_delete_callback("Core_Simulation_Stopped", stopped, NULL);
# using the hap handle
SIM_hap_delete_callback_id("Core_Simulation_Stopped", handle2)
// In C
void
at_end()
{
// Using the callback parameters
SIM_hap_delete_callback("Core_Simulation_Stopped", stopped, NULL);
// Using the hap handle
SIM_hap_delete_callback_id("Core_Simulation_Stopped", h2);
}
Simics, when running in stall mode provides tracing mechanisms for memory accesses, both instruction fetches and data accesses. Most processor-initiated accesses can also be stalled as a way to control the timing of the memory sub-system. All of chapter 43 is dedicated to memory tracing and timing in Simics since this is an extensive subject.