abs_pointer_activate — interface used with tablet devices
#include <simics/model-iface/abs-pointer.h> // in C
import "simics/model-iface/abs-pointer.dml"; // in DML
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"
import simics
class simics.abs_pointer_activate_interface_t(enable=None, disable=None)
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.
Cell Context for all methods.
abs_pointer_buttons_t, abs_pointer_state_t, abs_pointer — interface and types used with tablet devices
#include <simics/model-iface/abs-pointer.h> // in C
import "simics/model-iface/abs-pointer.dml"; // in DML
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"
import simics
simics.Abs_Pointer_Button_Right
simics.Abs_Pointer_Button_Middle
simics.Abs_Pointer_Button_Left
class simics.abs_pointer_state_t(buttons=0, x=0, y=0, z=0)
class simics.abs_pointer_interface_t(set_state=None)
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.
Cell Context for all methods.
arm_external_debug — arm_external_debug interface used for external debug feature
#include <simics/arch/arm.h> // in C
import "simics/arch/arm.dml"; // in DML
SIM_INTERFACE(arm_external_debug) {
void (*handle_semihosting)(conf_object_t *obj);
uint64 (*read_reg)(conf_object_t *obj, int offset);
void (*write_reg)(conf_object_t *obj, int offset, uint64 v);
};
#define ARM_EXTERNAL_DEBUG_INTERFACE "arm_external_debug"
import simics
class simics.arm_external_debug_interface_t(handle_semihosting=None,
read_reg=None, write_reg=None)
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.
Cell Context for all methods.
bank_after_read — Used from callback registered with bank_instrumentation_subscribe interface
#include <simics/model-iface/bank-instrumentation.h> // in C
import "simics/model-iface/bank-instrumentation.dml"; // in DML
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"
import simics
class simics.bank_after_read_interface_t(offset=None, size=None, missed=None,
value=None, set_missed=None, set_value=None, initiator=None)
The bank_after_read interface is used to monitor and modify the state of read accesses from the after_read_callback_t callback.
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.
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.
bank_after_write — Used from callback registered with bank_instrumentation_subscribe interface
#include <simics/model-iface/bank-instrumentation.h> // in C
import "simics/model-iface/bank-instrumentation.dml"; // in DML
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"
import simics
class simics.bank_after_write_interface_t(offset=None, size=None, missed=None,
set_missed=None, initiator=None)
The bank_after_write interface is used to monitor and modify the state of write accesses from the after_write_callback_t callback.
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.
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.
bank_before_read — Used from callback registered with bank_instrumentation_subscribe interface
#include <simics/model-iface/bank-instrumentation.h> // in C
import "simics/model-iface/bank-instrumentation.dml"; // in DML
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"
import simics
class simics.bank_before_read_interface_t(offset=None, size=None, set_offset=None,
inquire=None, initiator=None)
The bank_before_read interface is used to monitor and modify the state of read accesses from the before_read_callback_t callback.
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.
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.
bank_before_write — Used from callback registered with bank_instrumentation_subscribe interface
#include <simics/model-iface/bank-instrumentation.h> // in C
import "simics/model-iface/bank-instrumentation.dml"; // in DML
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"
import simics
class simics.bank_before_write_interface_t(offset=None, size=None, value=None,
suppress=None, set_offset=None, set_value=None, initiator=None)
The bank_before_write interface is used to monitor and modify the state of write accesses from the before_write_callback_t callback.
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.
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.
bank_instrumentation_subscribe — interface for bank instrumentation
#include <simics/model-iface/bank-instrumentation.h> // in C
import "simics/model-iface/bank-instrumentation.dml"; // in DML
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"
import simics
class simics.bank_instrumentation_subscribe_interface_t(register_before_read=None,
register_after_read=None, register_before_write=None,
register_after_write=None, remove_callback=None,
remove_connection_callbacks=None, enable_connection_callbacks=None,
disable_connection_callbacks=None)
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_subscribe 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.
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.
A registered callback is allowed to call remove_callback but not remove_connection_callbacks.
Callback functions registered through the bank_instrumentation_subscribe interface are called before or after read and write accesses, and they are of the types before_read_callback_t, after_read_callback_t, before_write_callback_t and, after_write_callback_t.
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.
Global Context for remove_connection_callbacks, Cell Context for other methods.
breakpoint_change — interface that provides callbacks when breakpoints are added or removed
#include <simics/device-api.h> // in C
// always available in DML
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"
import simics
class simics.breakpoint_change_interface_t(breakpoint_added=None,
breakpoint_removed=None)
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.
Cell Context for all methods.
breakpoint — interface for adding and removing breakpoints
#include <simics/device-api.h> // in C
// always available in DML
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"
import simics
class simics.breakpoint_interface_t(insert_breakpoint=None,
remove_breakpoint=None, get_breakpoint=None)
The breakpoint interface is implemented by any object that supports breaking on an address range.
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.
Cell Context for all methods.
breakpoint_query_v2 — interface for getting all breakpoints
#include <simics/device-api.h> // in C
// always available in DML
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"
import simics
class simics.breakpoint_query_v2_interface_t(get_breakpoints=None)
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 function 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.
Cell Context for all methods.
breakpoint_trigger — interface that allows triggering of breakpoints
#include <simics/device-api.h> // in C
// always available in DML
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"
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.
Cell Context for all methods.
callback_info — interface for instrumentation callbacks
#include <simics/model-iface/instrumentation-provider.h> // in C
import "simics/model-iface/instrumentation-provider.dml"; // in DML
SIM_INTERFACE(callback_info) {
attr_value_t (*get_callbacks)(conf_object_t *obj);
};
#define CALLBACK_INFO_INTERFACE "callback_info"
import simics
class simics.callback_info_interface_t(get_callbacks=None)
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:
Cell Context for all methods, but must be called from a callback receiving a handle of type instruction_handle_t.
cell_inspection — interface used by processor models to update current cpu
#include <simics/model-iface/execute.h> // in C
import "simics/model-iface/execute.dml"; // in DML
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"
import simics
class simics.cell_inspection_interface_t(set_current_processor_obj=None,
set_current_step_obj=None)
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.
Cell Context
co_execute — experimental interface
#include <simics/model-iface/co-execute.h> // in C
import "simics/model-iface/co-execute.dml"; // in DML
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"
import simics
class simics.co_execute_interface_t(start_thread=None, yield=None)
Experimental, may change without notice.
Cell Context
component_connector — interface that must be implemented by a connector
#include <simics/model-iface/components.h> // in C
import "simics/model-iface/components.dml"; // in DML
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"
import simics
class simics.component_connector_interface_t(get_check_data=None,
get_connect_data=None, check=None, connect=None, disconnect=None)
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.
Global Context for all methods.
component — interface implemented by component classes
#include <simics/model-iface/components.h> // in C
import "simics/model-iface/components.dml"; // in DML
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"
import simics
class simics.component_interface_t(pre_instantiate=None, post_instantiate=None,
create_cell=None, get_slots=None, get_slot_objects=None,
get_slot_value=None, set_slot_value=None, has_slot=None,
add_slot=None, del_slot=None)
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.
| Function | Context |
|---|---|
add_slot | Global Context |
create_cell | Global Context |
del_slot | Global Context |
get_objects | Cell Context |
get_slot_value | Global Context |
get_slots | Cell Context |
post_instantiate | Global Context |
pre_instantiate | Global Context |
set_slot_value | Global Context |
concurrency_group — concurrency group interface
#include <simics/model-iface/concurrency.h> // in C
import "simics/model-iface/concurrency.dml"; // in DML
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"
import simics
class simics.concurrency_group_interface_t(serialized_memory_group=None,
execution_group=None)
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 Model in the API Reference Manual for more details.
Global Context for all methods.
concurrency_mode — concurrency mode interface
#include <simics/model-iface/concurrency.h> // in C
import "simics/model-iface/concurrency.dml"; // in DML
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"
import simics
class simics.concurrency_mode_interface_t(supported_modes=None, current_mode=None,
switch_mode=None)
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 Threading Model chapter in the API Reference Manual for details about thread domains, the Standard Device Model and the Threaded Device Model.
Global Context for all methods.
connector_direction_t, connector — interface that must be implemented by a connector
#include <simics/model-iface/components.h> // in C
import "simics/model-iface/components.dml"; // in DML
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"
import simics
simics.Sim_Connector_Direction_Up
simics.Sim_Connector_Direction_Down
simics.Sim_Connector_Direction_Any
class simics.connector_interface_t(type=None, hotpluggable=None, required=None,
multi=None, direction=None, add_destination=None,
remove_destination=None, destination=None, update=None, check=None,
connect=None, disconnect=None, deletion_requested=None)
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.
Global Context for all methods.
cpu_cached_instruction — interface for regestering instrumentation for cached instructions
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
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"
import simics
class simics.cpu_cached_instruction_interface_t(register_instruction_before_cb=None,
register_instruction_after_cb=None, register_read_before_cb=None,
register_read_after_cb=None, register_write_before_cb=None,
register_write_after_cb=None)
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 method register_instruction_before_cb installs a cpu_instruction_cb_t callback function that is called before the cached instruction is executed. The ci_handle is used to bind the callback to the cached instruction.
The cb callback type is the same as used for instructions in the cpu_instrumentation_subscribe interface.
The user_data is the callback’s user data, and a callback for freeing the data is also available. The free_cb should be of type cpu_callback_free_user_data_cb_t. 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 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 cpu_memory_cb_t callback function 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.
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.
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.
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.
cpu_cached_instruction_once — interface for regestering cached instrumentation callbacks
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
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"
import simics
class simics.cpu_cached_instruction_once_interface_t(register_instruction_before_once_cb=None,
register_instruction_after_once_cb=None)
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.
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.
exception_handle_t, cpu_exception_query — query interface for exception information
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
typedef struct cpu_exception_info exception_handle_t;
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"
import simics
class simics.exception_handle_t
class simics.cpu_exception_query_interface_t(exception_number=None, fault_pc=None)
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.
exception_number is used to get the vector for the exception.
Threaded Context for all methods, but must be called from a callback receiving a handle of type exception_handle_t.
decoder_handle_t, cpu_instruction_decoder — interface used with replacing instruction operation
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
typedef struct cpu_replace_info decoder_handle_t;
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"
import simics
class simics.decoder_handle_t
class simics.cpu_instruction_decoder_interface_t(register_emulation_cb=None)
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:
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 emulation callback function is of type cpu_emulation_cb_t.
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.
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.
instruction_handle_t, cpu_instruction_query — query interface for instruction information
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
typedef struct cpu_instrumentation_info instruction_handle_t;
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);
bool (*is_jit_mode)(conf_object_t *cpu, instruction_handle_t *handle);
};
#define CPU_INSTRUCTION_QUERY_INTERFACE "cpu_instruction_query"
import simics
class simics.instruction_handle_t
class simics.cpu_instruction_query_interface_t(logical_address=None,
physical_address=None, get_instruction_bytes=None,
is_existing_instruction=None, is_jit_mode=None)
The cpu_instruction_query interface can be used in functions of the following types:
where an instruction_handle_t handle 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.
The logical_address and physical_address is used to get the different addresses of the instruction being executed.
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 or 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.
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.
The is_jit_mode method can be used to determine if the instruction is being executed by the JIT engine.
Additional information can be read out with an architectural specific query interface, see x86_instruction_query for details.
Threaded Context for all methods, but must be called from a callback receiving a handle of type instruction_handle_t.
cpu_cb_handle_t, cpu_instrumentation_subscribe — interface used with CPU instrumentation
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
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"
import simics
class simics.cpu_instrumentation_subscribe_interface_t(remove_callback=None,
enable_callback=None, disable_callback=None,
remove_connection_callbacks=None, enable_connection_callbacks=None,
disable_connection_callbacks=None,
register_instruction_before_cb=None,
register_instruction_after_cb=None, register_read_before_cb=None,
register_read_after_cb=None, register_write_before_cb=None,
register_write_after_cb=None, register_address_before_cb=None,
register_cached_instruction_cb=None,
register_instruction_decoder_cb=None,
register_exception_before_cb=None, register_exception_after_cb=None,
register_exception_return_before_cb=None,
register_exception_return_after_cb=None,
register_mode_change_cb=None,
register_control_register_read_before_cb=None,
register_control_register_write_before_cb=None)
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, not all CPU models implement all parts of the instrumentation API. Register methods not implemented in this interface will be NULL.
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.
The method register_instruction_before_cb installs a callback that is called before an instruction is executed. The callback type is cpu_instruction_cb_t.
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.
When an exception occurs the instruction is aborted and any installed callbacks by the
register_instruction_after_cbmethod are not called.
register_read_before_cb installs a callback that is called before a memory read operation is performed. The callback function is of type cpu_memory_cb_t.
The scope argument of type cpu_access_scope_t 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.
When an exception occurs the instruction is aborted and any installed memory callbacks after this point are not called.
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 type of cpu_address_cb_t.
The new logical address should be returned by the callback.
register_cached_instruction_cb is used for installing a cpu_cached_instruction_cb_t callback that is called every time Simics inserts an 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.
From the cpu_cached_instruction_cb_t callback one can use the supplied ci_handle and the cpu_cached_instruction interface 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 methods with the implicit scope instead.
If no callbacks are registered by calling the cpu_cached_instruction interface, the instruction will not be instrumented.
register_instruction_decoder_cb lets the user redefine instruction semantics in Simics, or implement new instructions. The cb argument is a cpu_instruction_decoder_cb_t 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.
An implementation of cpu_instruction_disassemble_cb_t should be passed in the disass_cb argument 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.
register_exception_before_cb is used to register a cpu_exception_cb_t callback function 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.
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 cpu_exception_return_cb_t callback function that will be called just before an exception handler is done and resumes execution of the normal program code.
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.
register_mode_change_cb is used to register a cpu_mode_change_cb_t callback function that will be called every time the processor changes mode. The supported modes are: user, supervisor, and hypervisor.
register_control_register_read_before_cb is used to register a cpu_control_register_read_cb_t callback function 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.
register_control_register_write_before_cb is used to register a cpu_control_register_write_cb_t callback function 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.
Global Context for all methods.
memory_handle_t, page_crossing_info_t, cpu_memory_query — query interface for memory access information
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
typedef struct cpu_memory_info memory_handle_t;
typedef enum {
Sim_Page_Crossing_None,
Sim_Page_Crossing_First,
Sim_Page_Crossing_Second,
} page_crossing_info_t;
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"
import simics
class simics.memory_handle_t
simics.Sim_Page_Crossing_First
simics.Sim_Page_Crossing_None
simics.Sim_Page_Crossing_Second
class simics.cpu_memory_query_interface_t(logical_address=None,
physical_address=None, get_bytes=None, set_bytes=None, atomic=None,
arch=None, get_page_crossing_info=None, get_surrounding_bytes=None)
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.
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. 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 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.
Threaded Context for all methods, but must be called from a callback receiving a handle of type memory_handle_t.
cycle_control — interface for controlling a cycle counter with events
#include <simics/model-iface/cycle-event.h> // in C
import "simics/model-iface/cycle-event.dml"; // in DML
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"
import simics
class simics.cycle_control_interface_t(stop=None, start=None,
set_cycle_count=None)
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.
Cell Context
cycle_event_instrumentation — internal interfaces
This interface is exported for Simics internal use.
Global Context.
cycle_event — -
#include <simics/model-iface/cycle-event.h> // in C
import "simics/model-iface/cycle-event.dml"; // in DML
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"
import simics
class simics.cycle_event_interface_t(cycles=None, post=None, cancel=None,
lookup=None, events=None)
TODO: document the cycle_event interface.
Cell Context
cycle — interface used to handle events based on time
#include <simics/device-api.h> // in C
// always available in DML
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"
import simics
class simics.cycle_interface_t(get_cycle_count=None, get_time=None,
cycles_delta=None, get_frequency=None, post_cycle=None,
post_time=None, cancel=None, find_next_cycle=None,
find_next_time=None, events=None, get_time_in_ps=None,
cycles_delta_from_ps=None, post_time_in_ps=None,
find_next_time_in_ps=None)
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.
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 cyclecycle_interface_t 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 cyclecycle_interface_t 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.
Cell Context
decoder — interface and type used with user decoder
#include <simics/model-iface/decoder.h> // in C
import "simics/model-iface/decoder.dml"; // in DML
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);
};
#define DECODER_INTERFACE "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.
Cell Context for all methods.
describe_registers — used by the Simics debugger to get register information
#include <simics/model-iface/describe-registers.h> // in C
import "simics/model-iface/describe-registers.dml"; // in DML
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"
import simics
simics.Description_Type_Int_Reg
simics.Description_Type_Group
simics.Description_Type_Float_Reg
simics.Description_Type_Float_Field
simics.Description_Type_Fields_Reg
simics.Description_Type_Int_Field
simics.Reg_Role_None
simics.Reg_Role_Program_Counter
simics.Reg_Bitorder_Little_Endian
simics.Reg_Bitorder_Big_Endian
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.
Cell Context for all methods.
device_identification — interface used to provide product information on a device
#include <simics/model-iface/device-identification.h> // in C
import "simics/model-iface/device-identification.dml"; // in DML
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"
import simics
class simics.device_identification_interface_t(get_id=None, get_key=None)
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 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.
Cell Context
direct_memory_flush — used to flush granted rights and for managing access rights
#include <simics/model-iface/direct-memory.h> // in C
import "simics/model-iface/direct-memory.dml"; // in DML
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"
import simics
class simics.direct_memory_flush_interface_t(revoke=None, set_access_bits=None)
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.
Cell Context for all methods.
direct_memory — implemented to provide direct access to memory
#include <simics/device-api.h> // in C
// always available in DML
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;
#include <simics/model-iface/direct-memory.h> // in C
import "simics/model-iface/direct-memory.dml"; // in DML
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"
import simics
class simics.direct_memory_t
class simics.direct_memory_interface_t(get_handle=None, request=None, revoke=None,
release=None, ack=None)
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.
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.
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.
Cell Context for all methods.
direct_memory_lookup, direct_memory_lookup_v2 — lookup direct memory providers in a memory-space
#include <simics/device-api.h> // in C
// always available in DML
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;
#include <simics/model-iface/direct-memory.h> // in C
import "simics/model-iface/direct-memory.dml"; // in DML
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"
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"
import simics
class simics.direct_memory_lookup_t
class simics.direct_memory_lookup_interface_t(lookup=None)
class simics.direct_memory_lookup_v2_interface_t(lookup=None)
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.
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.
The direct_memory_lookup and direct_memory interfaces replace the memory_page interface of Simics 4.8.
Cell Context for all methods.
direct_memory_tags — implemented by objects that model RAM with auxiliary RAM bits
#include <simics/device-api.h> // in C
// always available in DML
typedef struct {
#ifndef PYWRAP
uint8 *data;
#endif
unsigned len;
} direct_memory_tags_t;
#include <simics/model-iface/direct-memory.h> // in C
import "simics/model-iface/direct-memory.dml"; // in DML
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"
import simics
class simics.direct_memory_tags_t
class simics.direct_memory_tags_interface_t(get_tags_data=None)
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.
The memory region specified indirectly by the
handleargument 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.
Cell Context for all methods.
direct_memory_update — implemented by objects that use the direct_memory interface
#include <simics/model-iface/direct-memory.h> // in C
import "simics/model-iface/direct-memory.dml"; // in DML
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"
import simics
class simics.direct_memory_update_interface_t(release=None,
update_permission=None, conflicting_access=None)
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.
Cell Context for all methods.
disk_component — interface that should be implemented by disk components
#include <simics/model-iface/components.h> // in C
import "simics/model-iface/components.dml"; // in DML
SIM_INTERFACE(disk_component) {
uint64 (*size)(conf_object_t *obj);
};
#define DISK_COMPONENT_INTERFACE "disk_component"
import simics
class simics.disk_component_interface_t(size=None)
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.
Global Context for all methods.
event_delta — interface implemented by objects that advance time
#include <simics/model-iface/event-delta.h> // in C
import "simics/model-iface/event-delta.dml"; // in DML
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"
import simics
class simics.event_delta_interface_t(set_delta=None, get_delta=None)
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
Cell Context
event_handler — interface used to
#include <simics/model-iface/event-delta.h> // in C
import "simics/model-iface/event-delta.dml"; // in DML
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"
import simics
class simics.event_handler_interface_t(handle_event=None, stop=None)
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.
Cell Context
event_provider — Internal interface for ISIM modules
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"
This is a tech-preview interface that 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.
Called from performance models.
exception — interface used with exception haps
#include <simics/model-iface/exception.h> // in C
import "simics/model-iface/exception.dml"; // in DML
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"
import simics
class simics.exception_interface_t(get_number=None, get_name=None,
get_source=None, all_exceptions=None)
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.
Cell Context
execute_control — interface implemented by CPUs and devices that support threading
#include <simics/model-iface/execute.h> // in C
import "simics/model-iface/execute.dml"; // in DML
SIM_INTERFACE(execute_control) {
void (*message_pending)(conf_object_t *obj);
void (*yield_request)(conf_object_t *obj);
};
#define EXECUTE_CONTROL_INTERFACE "execute_control"
import simics
class simics.execute_control_interface_t(message_pending=None, yield_request=None)
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.
Threaded Context
execute — interface implemented by objects that can drive simulation
#include <simics/model-iface/execute.h> // in C
import "simics/model-iface/execute.dml"; // in DML
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"
import simics
class simics.execute_interface_t(run=None, stop=None, switch_in=None,
switch_out=None)
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.
Cell Context
external_connection_ctl — interface used in external communication
#include <simics/model-iface/external-connection.h> // in C
import "simics/model-iface/external-connection.dml"; // in DML
SIM_INTERFACE(external_connection_ctl) {
void (*accept)(conf_object_t *NOTNULL obj,
uint64 id, ext_con_cookie_t *cookie,
bool blocking);
ssize_t (*read)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie,
buffer_t buffer);
ssize_t (*write)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie,
bytes_t bytes);
void (*write_async)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie,
bytes_t bytes);
bool (*has_error)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie);
void (*notify)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie,
notify_mode_t notify_mode, exec_mode_t exec_mode,
bool active);
void (*close)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie);
};
#define EXTERNAL_CONNECTION_CTL_INTERFACE "external_connection_ctl"
import simics
class simics.external_connection_ctl_interface_t(accept=None, read=None,
write=None, write_async=None, has_error=None, notify=None,
close=None)
This interface is implemented by external connection server classes in the external-connection module.
The accept method must be called on every incoming connection, generally in the on_accept method of the external_connection_events, to indicate to the server whether a connection is accepted. The value of id must be the value given to the on_accept method. The value of the cookie argument will be used in all other methods of external_connection_ctl and external_connection_events to identify the connection. Its value is defined by the caller and opaque to the server. Use the value NULL to specify that the connection is not accepted. If the blocking argument is set to true, then the read and write methods will have blocking semantics for this connection.
The read method reads bytes from the connection identified by cookie into the caller-allocated buffer, whose size defines an upper bound on the number of bytes read. The method returns the number of bytes read (which may be less than the size of buffer), or -1 on error. If blocking semantics was turned on for the connection, in the accept method call, then the read method call will block until there is some data to return. Otherwise it will return -2 immediately in that case.
The write method writes bytes to the connection identified by cookie from the buffer bytes. If blocking semantics was turned on for the connection, in the accept method call, then the write method call will block until some data has been written. Otherwise it will return -2 immediately in that case.
The write_async method queues up the data in bytes and sends it as soon as possible on the connection identified by cookie. The method makes a copy of the data and returns immediately.
The has_error method returns true if and only if there has been an error on the connection identified by cookie.
The notify method activates or deactivates read or write notifications on the connection identified by cookie. The active argument specifies if the call is an activation or a deactivation and the notify_mode argument specifies if read (Sim_NM_Read) or write (Sim_NM_Write) notifications should be affected. Activating read notifications means that the on_input method in the external_connection_events interface may be called on this connection at any time after the call to notify. Activating write notifications means that the can_write method in the external_connection_events interface may be called on this connection at any time after the call to notify. If exec_mode is set to Sim_EM_Global, the call to on_input or can_write will be done in GLobal Context and if exec_mode is set to Sim_EM_Thread, the call will be in done in Threaded Context.
The close method closes the connection identified by cookie. After this call, it is is illegal to call any other method using this value of cookie.
Global Context for accept and notify, Threaded Context for other methods.
external_connection_events — interface used in communication with external communication servers
#include <simics/model-iface/external-connection.h> // in C
import "simics/model-iface/external-connection.dml"; // in DML
SIM_INTERFACE(external_connection_events) {
void (*on_accept)(conf_object_t *NOTNULL obj,
conf_object_t *NOTNULL server, uint64 id);
void (*on_input)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie);
void (*can_write)(conf_object_t *NOTNULL obj,
ext_con_cookie_t *NOTNULL cookie);
};
#define EXTERNAL_CONNECTION_EVENTS_INTERFACE "external_connection_events"
import simics
class simics.external_connection_events_interface_t(on_accept=None, on_input=None,
can_write=None)
This interface must be implemented by objects communicating with external connection servers.
The on_accept method is called on every incoming connection, when it is being set up. The server argument is the server object that is handling the connection. The id value identifies this connection in the server object. This value must be passed in the call to accept in the external_connection_ctl interface.
The on_input method is called on the connection identified by cookie when there is some data available to read on it.
The can_write method is called on the connection identified by cookie when some data can be written to it.
Global Context for on_accept, Threaded or Global Context for the others, depending on how notify was called.
freerun — interface used to extend cpu model with freerunning capability
#include <simics/model-iface/freerun.h> // in C
import "simics/model-iface/freerun.dml"; // in DML
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"
import simics
class simics.freerun_interface_t(enabled=None, advance_clock=None,
start_clock=None, stop_clock=None, current_itime=None)
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.
The
freeruninterface is experimental and may change without notice.
Cell Context for all methods.
gfx_con_pixel_fmt_t, gfx_con — interface used in communication with graphic consoles
#include <simics/model-iface/gfx-console.h> // in C
import "simics/model-iface/gfx-console.dml"; // in DML
typedef enum {
GFX_8BIT_INDEXED = 8, /* 0xII */
GFX_RGB_565 = 16, /* 0bRRRRRGGGGGGBBBBB */
GFX_RGB_888 = 24, /* 0xRRGGBB */
GFX_xRGB_8888 = 32, /* 0xXXRRGGBB (X=unused) */
} gfx_con_pixel_fmt_t;
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"
import simics
simics.GFX_RGB_565
simics.GFX_RGB_888
simics.GFX_8BIT_INDEXED
simics.GFX_xRGB_8888
class simics.gfx_con_interface_t(set_color=None, set_size=None, put_pixel=None,
put_pixel_rgb=None, redraw=None, update_keyboard_leds=None,
put_pixel_col=None, put_block=None)
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_pixel method 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>.
The gfx_con_pixel_fmt_t enumeration is used when calling the put_block method, to specify the pixel format of the provided buffer.
Specifying GFX_8BIT_INDEXED means that the buffer uses VGA style 8-bit per pixel indexed colors, and that the console palette, specified by the set_color method, should be used.
Specifying GFX_RGB_565 means that the buffer uses 16 bits per pixel, with format 0bRRRRRGGGGGGBBBBB (in little endian).
Specifying GFX_RGB_888 means that the buffer uses 24 bits per pixel, with format 0xRRGGBB (in little endian).
Specifying GFX_xRGB_8888 means that the buffer uses 32 bits per pixel, with format 0xXXRRGGBB (in little endian), where X is unused.
Cell Context
hap_listen — interface used to be notified abd haps
#include <simics/model-iface/hap-listen.h> // in C
// not available in DML
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"
With the hap_listen interface, objects can pick up haps and process then as they wish, including re-raising the haps.
Cell Context
image — interface used for handling big data images
#include <simics/model-iface/image.h> // in C
import "simics/model-iface/image.dml"; // in DML
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"
import simics
class simics.image_interface_t(set_persistent=None, save_to_file=None,
save_diff=None, clear_range=None, fill=None, size=None, set=None,
get=None, flush_writable=None)
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.
Cell Context
image_snoop — interface used to snoop om changes to pages within an image
#include <simics/model-iface/image.h> // in C
import "simics/model-iface/image.dml"; // in DML
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"
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.
Cell Context
instruction_fetch_mode_t, instruction_fetch — interface to control how instruction fetches should be modelled
#include <simics/model-iface/instruction-fetch.h> // in C
import "simics/model-iface/instruction-fetch.dml"; // in DML
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"
import simics
simics.Instruction_Fetch_Trace
simics.Instruction_Fetch_Cache_Access_Trace
simics.Instruction_Fetch_None
class simics.instruction_fetch_interface_t(get_mode=None, set_mode=None,
get_line_size=None, set_line_size=None)
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.
set_modeset_line_size Cell Contextget_modeget_line_sizeinstrumentation_order — interface for instrumentation order
#include <simics/model-iface/instrumentation-provider.h> // in C
import "simics/model-iface/instrumentation-provider.dml"; // in DML
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"
import simics
class simics.instrumentation_order_interface_t(get_connections=None,
move_before=None)
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:
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.
Global Context for all methods, but must be called from a callback receiving a handle of type instruction_handle_t.
keyboard_console — interface implemented by consoles
#include <simics/model-iface/kbd-interface.h> // in C
import "simics/model-iface/kbd-interface.dml"; // in DML
SIM_INTERFACE(keyboard_console) {
void (*keyboard_ready)(conf_object_t *obj);
};
#define KEYBOARD_CONSOLE_INTERFACE "keyboard_console"
import simics
class simics.keyboard_console_interface_t(keyboard_ready=None)
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.
Cell Context for all methods.
keyboard — interface implemented by keyboard controllers
#include <simics/model-iface/kbd-interface.h> // in C
import "simics/model-iface/kbd-interface.dml"; // in DML
SIM_INTERFACE(keyboard) {
int (*keyboard_event)(conf_object_t *obj, int key_up, uint8 key);
};
#define KEYBOARD_INTERFACE "keyboard"
import simics
class simics.keyboard_interface_t(keyboard_event=None)
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.
Cell Context for all methods.
linear_image — experimental image access interface
#include <simics/model-iface/image.h> // in C
import "simics/model-iface/image.dml"; // in DML
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"
import simics
class simics.linear_image_interface_t(prepare_range=None)
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.
set_baseget_base Cell Contextprepare_rangemagic_pipe_reader — Interface for reading data from magic pipe
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"
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.
This interface is an experimental feature. It is excluded from the standard support program, and is subject to change or removal without notice.
Cell Context for all methods.
magic_pipe_setup — Interface for magic pipe setup
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"
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.
This interface is an experimental feature. It is excluded from the standard support program, and is subject to change or removal without notice.
Cell Context for all methods.
magic_pipe_writer — Interface magic pipe transmission
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"
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.
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.
This interface is an experimental feature. It is excluded from the standard support program, and is subject to change or removal without notice.
Cell Context for all methods.
memory_profiler — interface for processors supporting memory profiling
#include <simics/model-iface/memory-profiler.h> // in C
import "simics/model-iface/memory-profiler.dml"; // in DML
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"
import simics
class simics.memory_profiler_interface_t(get=None, set=None,
get_granularity_log2=None)
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.
Cell Context for all methods.
mmc — interface implemented by MMC/SD/SDHC/SDIO card models
#include <simics/model-iface/mmc.h> // in C
import "simics/model-iface/mmc.dml"; // in DML
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);
};
#define MMC_INTERFACE "mmc"
import simics
class simics.mmc_interface_t(write_data=None)
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.
Cell Context for all methods.
mouse — interface used to send mouse events to a mouse device
#include <simics/model-iface/kbd-interface.h> // in C
import "simics/model-iface/kbd-interface.dml"; // in DML
SIM_INTERFACE(mouse) {
void (*mouse_event)(conf_object_t *obj,
int xmicro,
int ymicro,
int z,
int buttons);
};
#define MOUSE_INTERFACE "mouse"
import simics
class simics.mouse_interface_t(mouse_event=None)
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>.
Cell Context for all methods.
opcode_length_info_t, opcode_info — interface implemented by processors
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
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"
import simics
class simics.opcode_length_info_t(min_alignment=0, max_length=0, avg_length=0)
class simics.opcode_info_interface_t(get_opcode_length_info=None)
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.
Cell Context for all methods.
pipe_func_t — Function prototype used in magic_pipe_setup
typedef void (*pipe_func_t)(conf_object_t *cpu, uintptr_t buf, uint64 magic);
The buffer handle is used in most calls to this interface to identify the buffer.
pre_decoder — interface for changing bytes going into instruction decode
#include <simics/model-iface/cpu-instrumentation.h> // in C
import "simics/model-iface/cpu-instrumentation.dml"; // in DML
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);
};
#define PRE_DECODER_INTERFACE "pre_decoder"
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.
Global context.
processor_cli — command feature interface for processor models
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
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"
import simics
class simics.processor_cli_interface_t(get_disassembly=None, get_pregs=None,
get_diff_regs=None, get_pending_exception_string=None,
get_address_prefix=None, translate_to_physical=None)
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_v2 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 step-instruction 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_v2 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_v2 interface will be used to translate virtual addresses.
Cell Context for all methods.
processor_endian — interface used for retrieving processor endianness
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
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"
import simics
class simics.processor_endian_interface_t(get_instruction_endian=None,
get_data_endian=None)
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 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.
Cell Context
processor_gui — processor interface used with Simics native GUI
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
SIM_INTERFACE(processor_gui) {
void (*dummy)(conf_object_t *obj);
};
#define PROCESSOR_GUI_INTERFACE "processor_gui"
import simics
class simics.processor_gui_interface_t(dummy=None)
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.
processor_info — older version of the processor_info_v2 interface
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
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"
import simics
class simics.processor_info_interface_t(disassemble=None,
set_program_counter=None, get_program_counter=None,
logical_to_physical=None, enable_processor=None,
disable_processor=None, get_enabled=None, get_endian=None,
get_physical_memory=None, get_logical_address_width=None,
get_physical_address_width=None, architecture=None)
An older version of the processor_info_v2 interface. See processor_info_v2 for more information.
Cell Context for all methods.
processor_info_v2 — interface with generic functions implemented by processor models
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
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"
import simics
class simics.processor_info_v2_interface_t(disassemble=None,
set_program_counter=None, get_program_counter=None,
logical_to_physical=None, get_processor_mode=None,
enable_processor=None, disable_processor=None, get_enabled=None,
get_endian=None, get_physical_memory=None,
get_logical_address_width=None, get_physical_address_width=None,
architecture=None)
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 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.
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.
Cell Context for all methods except set_program_counter which needs Global Context.
It is explicitly permitted to call set_program_counter from inside an execution breakpoint handler.
processor_memory_inspection — implemented by processor models for memory inspection
#include <simics/model-iface/processor-info.h> // in C
import "simics/model-iface/processor-info.dml"; // in DML
SIM_INTERFACE(processor_memory_inspection) {
conf_object_t *(*logical_inspection_port)(conf_object_t *obj);
conf_object_t *(*physical_inspection_port)(conf_object_t *obj);
};
#define PROCESSOR_MEMORY_INSPECTION_INTERFACE "processor_memory_inspection"
import simics
class simics.processor_memory_inspection_interface_t(logical_inspection_port=None,
physical_inspection_port=None)
The processor_memory_inspection interface is implemented by processor models for memory inspection.
Function logical_inspection_port returns a port that can be used to issue transactions from the point of view of the processor. The user is expected to use a logical/virtual address when accessing this port. The processors architectural atoms are appended to the transaction. An internal MMU lookup is performed to translate the logical/virtual address to a physical address. The transaction is then forwarded to the physical_memory attached to the processor. This will give the same access rights to the memory hierarchy as if the processor itself had issued the transaction. This function can return NULL if the processor does not support logical/virtual memory addressing.
Function physical_inspection_port returns a port that can be used to issue transactions from the point of view of the processor. The user is expected to use a physical address when accessing this port. The processors architectural atoms are appended to the transaction when using this port, before the transaction is forwarded to the physical_memory attached to the processor. This will give the same access rights to the memory hierarchy as if the processor itself had issued the transaction.
Cell Context for all methods.
ram_cb_handle_t, ram_access_subscribe — interface for ram access instrumentation
#include <simics/model-iface/ram-instrumentation.h> // in C
import "simics/model-iface/ram-instrumentation.dml"; // in DML
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"
import simics
class simics.ram_cb_handle_t
class simics.ram_access_subscribe_interface_t(remove_callback=None,
enable_callback=None, disable_callback=None,
register_access_before_cb=None, register_access_after_cb=None,
register_access_filter_cb=None)
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.
Global Context for all methods.
register_breakpoint — optional CPU interface
#include <simics/simulator-iface/register-breakpoint.h> // in C
import "simics/simulator-iface/register-breakpoint.dml"; // in DML
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"
import simics
class simics.register_breakpoint_interface_t(add_breakpoint=None,
remove_breakpoint=None, get_breakpoints=None)
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.
Global Context
simple_timing_v2 — Interface that provides execution information
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"
This interface is a tech preview and 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.
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 to the modules Makefile:
EXTRA_MODULE_VPATH := simple-timing-interface
Called from performance models.
simulator_cache — interface optionally implemented by processor models
#include <simics/model-iface/simulator-cache.h> // in C
import "simics/model-iface/simulator-cache.dml"; // in DML
SIM_INTERFACE(simulator_cache) {
void (*flush)(conf_object_t *obj);
};
#define SIMULATOR_CACHE_INTERFACE "simulator_cache"
import simics
class simics.simulator_cache_interface_t(flush=None)
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.
Cell Context
stall — optionally implemented by objects together with cycle and step interfaces
#include <simics/model-iface/step.h> // in C
import "simics/model-iface/step.dml"; // in DML
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"
import simics
class simics.stall_interface_t(get_stall_cycles=None, set_stall_cycles=None,
get_total_stall_cycles=None)
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.
Cell Context for all methods.
step_cycle_ratio_t, step_cycle_ratio — implemented by objects with changeable ratio between steps and cycles
#include <simics/model-iface/step.h> // in C
import "simics/model-iface/step.dml"; // in DML
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"
import simics
class simics.step_cycle_ratio_t
class simics.step_cycle_ratio_interface_t(get_ratio=None, set_ratio=None)
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.
Cell Context for all methods.
step_event_instrumentation — internal interfaces
This interface is exported for Simics internal use.
Global Context.
step_info — optional interface implemented by processors
#include <simics/model-iface/step.h> // in C
import "simics/model-iface/step.dml"; // in DML
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"
import simics
class simics.step_info_interface_t(get_halt_steps=None, set_halt_steps=None,
get_ffwd_steps=None, set_ffwd_steps=None, get_ma_steps=None,
set_ma_steps=None)
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.
Cell Context for all methods.
step — interface used to handle step events
#include <simics/model-iface/step.h> // in C
import "simics/model-iface/step.dml"; // in DML
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"
import simics
class simics.step_interface_t(get_step_count=None, post_step=None,
cancel_step=None, find_next_step=None, events=None, advance=None)
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.
Cell Context for all methods.
synchronous_mode — experimental interface
#include <simics/model-iface/co-execute.h> // in C
import "simics/model-iface/co-execute.dml"; // in DML
SIM_INTERFACE(synchronous_mode) {
int (*enter)(conf_object_t *NOTNULL obj);
int (*leave)(conf_object_t *NOTNULL obj);
};
#define SYNCHRONOUS_MODE_INTERFACE "synchronous_mode"
import simics
class simics.synchronous_mode_interface_t(enter=None, leave=None)
Experimental, may change without notice.
Cell Context
temporal_state — interface related to reverse execution
#include <simics/model-iface/temporal-state.h> // in C
import "simics/model-iface/temporal-state.dml"; // in DML
// only supported with SIMICS_API = 6
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"
import simics
class simics.temporal_state_interface_t(save=None, merge=None,
prepare_restore=None, finish_restore=None)
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.
Cell Context for all methods.
timing_model, snoop_memory — interfaces for stalling and snooping on memory accesses
#include <simics/model-iface/timing-model.h> // in C
import "simics/model-iface/timing-model.dml"; // in DML
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"
import simics
class simics.timing_model_interface_t(operate=None)
class simics.snoop_memory_interface_t(operate=None)
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.
Cell Context for all methods.
transaction — interface used to pass transactions
#include <simics/model-iface/transaction.h> // in C
import "simics/model-iface/transaction.dml"; // in DML
SIM_INTERFACE(transaction) {
exception_type_t (*issue)(
conf_object_t *NOTNULL obj,
transaction_t *NOTNULL t,
uint64 addr);
};
#define TRANSACTION_INTERFACE "transaction"
import simics
class simics.transaction_interface_t(issue=None)
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.
Cell Context for all methods.
transaction_cb_handle_t, transaction_subscribe — internal transaction instrumentation interface
#include <simics/model-iface/transaction-instrumentation.h> // in C
import "simics/model-iface/transaction-instrumentation.dml"; // in DML
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"
import simics
class simics.transaction_cb_handle_t
class simics.transaction_subscribe_interface_t(remove_callback=None,
enable_callback=None, disable_callback=None, register_issue_cb=None)
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.
Outside execution context for all methods.
tsc_update — Interface that allows changing Time Stamp Counter
SIM_INTERFACE(tsc_update) {
void (*load_tsc_from_xtal)(conf_object_t *obj, uint64 xtal_value);
};
#define TSC_UPDATE_INTERFACE "tsc_update"
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.
Cell Context for all methods.
vga_text_info — interface used with vga text
#include <simics/model-iface/vga-text-interface.h> // in C
import "simics/model-iface/vga-text-interface.dml"; // in DML
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"
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.
Cell Context
vga_text_update — interface used with vga text
#include <simics/model-iface/vga-text-interface.h> // in C
import "simics/model-iface/vga-text-interface.dml"; // in DML
SIM_INTERFACE(vga_text_update) {
void (*write)(conf_object_t *NOTNULL obj, char value);
};
#define VGA_TEXT_UPDATE_INTERFACE "vga_text_update"
import simics
class simics.vga_text_update_interface_t(write=None)
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.
Cell Context
vga_update — interface used with graphic consoles
#include <simics/model-iface/gfx-console.h> // in C
import "simics/model-iface/gfx-console.dml"; // in DML
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"
import simics
class simics.vga_update_interface_t(refresh=None, refresh_all=None)
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.
Cell Context
virtual_breakpoint_flags_t, virtual_breakpoint_access_t, virtual_data_breakpoint — interface for data access breakpoints on virtual addresses
#include <simics/device-api.h> // in C
// always available in DML
typedef enum {
Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;
typedef enum {
Virtual_Breakpoint_Access_Read = 1,
Virtual_Breakpoint_Access_Write = 2,
Virtual_Breakpoint_Access_Execute = 4
} virtual_breakpoint_access_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);
attr_value_t (*list)(conf_object_t *NOTNULL obj);
};
#define VIRTUAL_DATA_BREAKPOINT_INTERFACE "virtual_data_breakpoint"
import simics
simics.Virtual_Breakpoint_Flag_Linear
simics.Virtual_Breakpoint_Access_Read
simics.Virtual_Breakpoint_Access_Execute
simics.Virtual_Breakpoint_Access_Write
class simics.virtual_data_breakpoint_interface_t(add_read=None, add_write=None,
remove=None, list=None)
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.)
The list method returns the data breakpoints that are set on the object right now. The returned value is a list with one entry per breakpoint, and each entry is a list of [key, value] pairs where the key is a string:
id - the handle that add_read or add_write returned, as a number.object - the object the breakpoint is set on.access - a virtual_breakpoint_access_t value, Virtual_Breakpoint_Access_Read or Virtual_Breakpoint_Access_Write.first, last - the interval, both endpoints included.linear_address - true when the breakpoint uses linear rather than virtual addresses.callback - the callback function pointer as a number. Every breakpoint set from Python shares the same wrapper function, so this only tells breakpoints apart when they were set from C.The id is unique while the breakpoint lives, but it is reused once the breakpoint is removed, and it is not the same between runs. A breakpoint set entirely above the largest representable address is never stored, so it is not listed.
The list method is optional and may be NULL. It was added in build-id 7204, and a module built against an older header registers an interface struct that has no list member at all. So before reading list, check that the build_id attribute of the object is 7204 or later, and then that list is not NULL.
This interface is preliminary and may change without prior notice.
Cell Context for all methods.
virtual_instruction_breakpoint — interface for instruction breakpoints on virtual addresses
#include <simics/device-api.h> // in C
// always available in DML
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);
attr_value_t (*list)(conf_object_t *NOTNULL obj);
};
#define VIRTUAL_INSTRUCTION_BREAKPOINT_INTERFACE \
"virtual_instruction_breakpoint"
import simics
class simics.virtual_instruction_breakpoint_interface_t(add=None, remove=None,
list=None)
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.
The list method returns the instruction breakpoints that are set on the object right now, in the same format as the list method of virtual_data_breakpoint. Here id is the handle that add returned, access is always Virtual_Breakpoint_Access_Execute, and there is one more key:
filter - the filter function pointer as a number, 0 when there is no filter.The same rules apply as for virtual_data_breakpoint: list is optional and may be NULL, and it only exists in modules with build-id 7204 or later, so check the build_id attribute of the object before reading list.
This interface is preliminary and may change without prior notice.
Cell Context for all methods.