void SIM_break_cycle(conf_object_t *NOTNULL obj, int64 cycles);
void SIM_break_step(conf_object_t *NOTNULL obj, int64 steps);
step
interface.
breakpoint_id_t SIM_breakpoint(conf_object_t *NOTNULL obj, breakpoint_kind_t kind, access_t access, uint64 address, uint64 length, breakpoint_flag_t flags);
breakpoint
interface. This is typically
a memory space object such as physical memory.
Please note that breakpoints set by this function may not appear in the results from <bp-manager>.list . It's recommended to use the bp.memory.break command.
The kind argument sets what type of address to break on:
typedef enum { Sim_Break_Physical = 0, Sim_Break_Virtual = 1, Sim_Break_Linear = 2 /* x86 only */ } breakpoint_kind_t;
The access argument is a bit-field setting the type of access. Any combination of the three alternatives can be given (added together).
typedef enum { Sim_Access_Read = 1, Sim_Access_Write = 2, Sim_Access_Execute = 4 } access_t;
The address is the start of the breakpoint range and length is its length in bytes. This range will be truncated as necessary to fit in the address space. An access intersecting the given range will trigger the breakpoint. If length is zero, the breakpoint range will be the entire address space.
The flags argument should be the sum of
zero or more enumeration constants from
breakpoint_flag_t
:
typedef enum breakpoint_flag { Sim_Breakpoint_Temporary = 1, Sim_Breakpoint_Simulation = 2, Sim_Breakpoint_Private = 4 } breakpoint_flag_t;
If the Sim_Breakpoint_Temporary
bit is set, the breakpoint
is automatically disabled when triggered the first time.
If the Sim_Breakpoint_Simulation
bit is set, the breakpoint
will not show up in the <bp-manager>.list command, nor can
it be removed by the <bp-manager>.delete command. Also,
there will be no message printed on the Simics console when this breakpoint
is triggered. This bit should be set when using breakpoints to simulate the
target system; it will prevent Simics from temporarily disabling the
breakpoint as an optimization measure. This could otherwise happen during
certain reverse execution operations.
If the Sim_Breakpoint_Private
bit is set, the breakpoint will
not show up in the <bp-manager>.list command, nor can it be
removed by the <bp-manager>.delete command.
The default action for a triggered breakpoint is to return to the frontend (this can be changed by using haps). On execution breakpoints Simics will return to the frontend before the instructions is executed, while instructions triggering read or write breakpoints will complete before control is returned to the frontend.
Several breakpoints can be set on the same address and Simics will break on them in turn. If hap handlers are connected to the breakpoints they will also be executed in turn. Hap handlers are called before the access is performed, allowing the user to read a memory value that may be overwritten by the access. See the Simics Reference Manual for a description of hap handlers.
Several attributes can be set for a breakpoint for breaking only when some conditions are true. See the breakpoints attribute in the sim class.
This function returns the breakpoint id which is used for further reference to the breakpoint:
typedef int breakpoint_id_t;
Breakpoints can be removed using SIM_delete_breakpoint.
void SIM_breakpoint_remove(int id, access_t access, generic_address_t address, generic_address_t length);
Sim_Breakpoint_Simulation
flag.
access is a bitfield describing the type of breakpoint to
remove using the enumeration constants of the access_t
enum.
address is the start address of the range and length is the length of the range in bytes.
void SIM_delete_breakpoint(breakpoint_id_t id);
Sim_Breakpoint_Simulation
flag.
void SIM_disable_breakpoint(breakpoint_id_t id);
void SIM_enable_breakpoint(breakpoint_id_t id);
void SIM_add_configuration(pre_conf_object_set_t *NOTNULL set, const char *file);
{
name :
pre_conf_object}
The file argument is the name of the file that a configuration was read from, and should be set to None/NULL if not used.
The following examples are written in Python. As they do not map any devices
in phys_mem
, they will not work as stand-alone simulations.
Example when set is a sequence:
clock = pre_conf_object('timer', 'clock') clock.freq_mhz = 20 space = pre_conf_object('phys_mem', 'memory-space') space.queue = clock SIM_add_configuration([clock, space], None)
Example when set is a dictionary:
objects = {} objects['clock'] = pre_conf_object('timer', 'clock') objects['clock'].freq_mhz = 20 objects['space'] = pre_conf_object('phys_mem', 'memory-space') objects['space'].queue = objects['clock'] SIM_add_configuration(objects, None)
bool SIM_class_has_attribute(conf_class_t *NOTNULL cls, const char *NOTNULL attr);
conf_object_t * SIM_create_object(conf_class_t *NOTNULL cls, const char *name, attr_value_t attrs);
_
). A unique name will be created if name
is an empty string or NULL. For backward compatibility, hyphens (-
)
are allowed instead of underscores but their use is deprecated.
The new object is initialized with attributes from
attrs, which must be a list of (attribute-name,
value) pairs, where each pair is a two-element list. All
required attributes for the class cls must be present in
attrs. In Python, attrs can be omitted (if no
attributes are required), it can be normal lists:
[['attribute1', value1], ['attribute2', value2]]
or keyword arguments: attribute1=value1, attribute2=value2
.
Attributes in ports of the cls class can be initialized by
prefixing the attribute name with the port name,
e.g. ['p.portname.attr', value]
.
The argument value may be modified, but the caller is still responsible for freeing it. Neither point applies when the function is called from Python.
NULL
on
error (in which case an exception is raised).
char * SIM_current_checkpoint_dir(void);
int SIM_delete_objects(attr_value_t val);
int SIM_delete_object(conf_object_t *NOTNULL obj);
Some specific objects in Simics, such as sim, are protected against deletion and will be ignored by this function.
If Simics finds references to the objects in the rest of the configuration, a warning will be printed and the operation will be aborted. Note that in this case, the deletion process has started and the objects may already have began their clean-up routines. The safest action at this point is to fix the dangling references and to try to delete the objects once again.
Events posted by the objects in cycle queues or step queues will be automatically removed. Hap callbacks and script branches waiting on deleted objects will be interrupted as well.
Core_Conf_Object_Pre_Delete
and
Core_Conf_Object_Delete
haps, as well as
pre_delete_instance and delete_instance for each
object). Recursive calls to SIM_delete_objects are allowed
during the pre-delete phase (Pre_Delete hap and
pre_delete_instance callback), and the new objects will be
added to the current list of objects to delete. Recursive calls after this
stage will fail.
This limited recursion is meant to let objects that "own" other objects destroy them automatically if they themselves are to be deleted. This is used for example by the standard Simics components.
@SIM_delete_objects(list(SIM_object_iterator(None)))
will delete all unprotected objects in the configuration, leaving the Simics session empty.
attr_value_t SIM_get_all_classes(void);
The Python function cli.global_cmds.list_classes can be used to get class names, by default including not-loaded classes.
attr_value_t SIM_get_all_objects(void);
Return a list of all configuration objects. The order is unspecified and may vary between calls to this function.
attr_value_t SIM_get_attribute(conf_object_t *NOTNULL obj, const char *NOTNULL name);
attr_value_t SIM_get_attribute_idx(conf_object_t *NOTNULL obj, const char *NOTNULL name, attr_value_t *NOTNULL index);
The caller is as usual responsible for freeing the returned value by calling SIM_attr_free.
attr_attr_t SIM_get_attribute_attributes(conf_class_t *NOTNULL cls, const char *NOTNULL attr);
attr_value_t SIM_get_class_attribute(conf_class_t *NOTNULL cls, const char *NOTNULL name);
attr_value_t SIM_get_class_attribute_idx(conf_class_t *NOTNULL cls, const char *NOTNULL name, attr_value_t *NOTNULL index);
The caller is as usual responsible for freeing the returned value by calling SIM_attr_free.
conf_object_t * SIM_get_object(const char *NOTNULL name);
The function does an object look-up in the order; object ID, object name, and hierarchical location for all objects in the simulation. The function returns the first match from the look-up or NULL if there was no object match.
The object ID is a unique name that never changes and is returned by the SIM_object_id function. The object name is the name of the object, used for instance when printing log messages and is returned by the SIM_object_name function. The hierarchical location is the absolute location of the object in the component hierarchy. The object name and the hierarchical location is the same.
Please note that in Python Simics objects are available directly
as attributes of the conf
module. For example, one can access
the sim object like this:
conf.sim
.
PyObject * SIM_get_python_interface_type(const char *NOTNULL name);
If necessary, will try to load modules registering the Python translation for this interface.
FORCE_INLINE conf_class_t * SIM_object_class(const conf_object_t *NOTNULL obj);
conf_object_t * SIM_object_descendant(conf_object_t *obj, const char *NOTNULL relname);
It is legal for the relative name to contain multiple components, like "device.p.RESET".
If obj is NULL, then the object lookup is performed relative the object hierarchy root.
If obj is instantiated at the same time as the descendant, then the function is guaranteed to succeed if called after the alloc_object phase of object initialization; i.e., it is safe for obj to invoke the function from its init_object method.
bool SIM_object_is_processor(conf_object_t *NOTNULL obj);
object_iter_t SIM_object_iterator(conf_object_t *obj);
The iterator returns objects sorted by name, with parents before children.
signal
interface:#include <simics/util/vect.h> #include <simics/devs/signal.h> ... VECT(conf_object_t *) v = VNULL; object_iter_t it = SIM_object_iterator(NULL); conf_object_t *obj; while ((obj = SIM_object_iterator_next(&it)) != NULL) { if (SIM_C_GET_INTERFACE(obj, signal) != NULL) VADD(v, obj); } ... // any code using 'v' vector here VFREE(v);
Sample Python code to find all objects implementing
signal
interface:
v = [] for obj in SIM_object_iterator(None): if hasattr(obj.iface, simics.SIGNAL_INTERFACE): v.append(obj)
The simics.SIGNAL_INTERFACE
constant from the above
example holds
"signal"
string. Such constants are available for some interfaces. One can safely use string literals instead.
conf_object_t * SIM_object_iterator_next(object_iter_t *iter);
It is illegal to call SIM_object_iterator_next using an iterator which has reached the end of its sequence.
conf_object_t * SIM_object_parent(conf_object_t *NOTNULL obj);
conf_object_t * SIM_port_object_parent(conf_object_t *NOTNULL obj);
void SIM_read_configuration(const char *NOTNULL file);
int SIM_register_context_handler(conf_class_t *NOTNULL cls, const context_handler_interface_t *NOTNULL iface);
context_handler
interface (iface), in addition to which
SIM_register_context_handler registers a
current_context attribute which will hold the current context.
The context_handler
interface will be wrapped by standard
functions so that standard context change behavior is taken care off
automatically. This includes, among other things, making sure that the
context is valid, and triggering the correct haps on context changes. Thus
the context_handler implementation need only care about the effect of the
change on the context
_handler object itself (virtual
breakpoints present in the context, cache flushing, etc.).
The return value is 0 if everything works, and non-zero if something fails. SIM_register_context_handler will return the error value provided by SIM_register_interface.
context_handler
interface
has already been registered for this class.
set_error_t SIM_set_attribute(conf_object_t *NOTNULL obj, const char *NOTNULL name, attr_value_t *NOTNULL value);
set_error_t SIM_set_attribute_idx(conf_object_t *NOTNULL obj, const char *NOTNULL name, attr_value_t *NOTNULL index, attr_value_t *NOTNULL value);
The _idx
version of the function can be used to get a
single entry in a list or data attribute. For this to work, the
attribute must support indexing.
After the call the value is still owned by the caller.
If the attribute setter function calls SIM_attribute_error or SIM_c_attribute_error and returns Sim_Set_Ok, it is treated like Sim_Set_IllegalValue.
set_error_t
enum, with Sim_Set_Ok
indicating
success.
set_error_t SIM_set_class_attribute(conf_class_t *NOTNULL cls, const char *NOTNULL name, attr_value_t *NOTNULL value);
set_error_t SIM_set_class_attribute_idx(conf_class_t *NOTNULL cls, const char *NOTNULL name, attr_value_t *NOTNULL index, attr_value_t *NOTNULL value);
The _idx
version of the function can be used to set a
single entry in a list or data attribute. For this to work, the
attribute must support indexing.
After the call the value is still owned by the caller.
set_error_t
enum, with Sim_Set_Ok
indicating
success.
void SIM_set_configuration(attr_value_t conf);
attr_value_t
which should have the following structure.
(("name", "class", ("attr_name", attr_val) ... ), ... )
That is a list of object specifiers containing name, class, and a list of attribute specifiers. An attribute specifier is a list of length 2 containing the attribute name and its value. SIM_set_configuration allows an easy way of parameterizing the configuration, especially if called from Python.
The argument value may be modified, but the caller is still responsible for freeing it. Neither point applies when the function is called from Python.
from configuration import OBJ from simics import SIM_set_configuration SIM_set_configuration([ ["cpu0", "x86", ["queue", OBJ("cpu0")], ["freq_mhz", 20], ["physical_memory", OBJ("phys_mem0")]], ["phys_mem0", "memory-space", ["map", [[0xa0000, OBJ("vga0"), 1, 0, 0x20000], [0x00000, OBJ("mem0"), 0, 0x00000, 0xA0000], [0xc0000, OBJ("mem0"), 0, 0xc0000, 0x8000], [0xc8000, OBJ("setmem0"), 0, 0, 0x28000], [0xf0000, OBJ("mem0"), 0, 0xf0000, 0x10000], [0x100000, OBJ("mem0"), 0, 0x100000, 0x3ff00000], [0xfee00000, OBJ("apic0"), 0, 0, 0x4000]]]], ... ])
SimExc_General Thrown if Simics fails to initialize all objects.
object_iter_t SIM_shallow_object_iterator(conf_object_t *obj);
The iterator returns objects sorted by name.
void SIM_write_configuration_to_file(const char *NOTNULL file, save_flags_t flags);
class_kind_t
is equal to Sim_Class_Kind_Session
or Sim_Class_Kind_Pseudo
are not saved. This also holds for
attributes (in all objects) of types Sim_Attr_Session and Sim_Attr_Pseudo.
The flags argument should be 0.
const char * SIM_get_init_arg_string(const char *name, const char *default_value);
bool SIM_get_init_arg_boolean(const char *name, bool default_value);
char *
) or booleans (bool
).
void SIM_init_command_line(void);
This function must be called after SIM_init_simulator2 and should only be called when embedding Simics in another application.
void SIM_init_environment(char **NOTNULL argv, bool handle_signals, bool allow_core_dumps);
VTMEM
, set up signal handling and perform some other early
initialization.
The argv argument is a NULL terminated list of strings. It must not be NULL. It must contain at least one element, which will be used as the program name. Often you can use the argv that main receives as the value of this argument.
If handle_signals is true, Simics will install its handler for Control-C, e.g. the SIGINT signal on Linux and ConsoleCtrlHandler on Windows. Set this value to false if the embedding application handles signals itself.
If allow_core_dumps is true, Simics will not install handlers for fatal signals but instead let the application crash possibly generating a core dump on Linux systems. If the argument is false, no core dump is generated and Simics will try to catch fatal signals and return control to the command line again.
void SIM_init_simulator2(init_arg_t *NOTNULL init_args);
init_arg_t
structs, where the last entry has NULL in the
name
field.
Each entry in the init_args array contains an argument name and an associated value that is either a string or a boolean. Simics has a number of pre-defined arguments that are used to configure the simulator.
It is possible to provide additional arguments in the call to SIM_init_simulator2. Such arguments are ignored by Simics and assumed to be used-defined. Their values can be obtained using the SIM_get_init_arg_string and SIM_get_init_arg_boolean functions in the Simics API.
List of pre-defined parameters and their types:
batch-mode | bool | See -batch-mode command line flag. |
deprecation-level | char * | One of 0 , 1 and 2 .
See the sim.deprecation_level attribute. |
expire-time | char * | See -expire command line flag. |
gui-mode | char * | One of gui , mixed and no-gui |
fail-on-warnings | bool | See -werror command line flag. |
license-file | char * | License file to use, overriding any preference setting. |
log-enable | bool | Deprecated. |
log-file | char * | See -log-file command line flag. |
no-settings | bool | See -no-settings command line flag. |
no-windows | bool | See -no-win command line flag. |
python-verbose | bool | Run the Python interpreter in verbose mode. |
project | char * | See -project command line flag. |
quiet | bool | See -quiet command line flag. |
script-trace | bool | Show when a Simics script is entered/exited, along with any parameters passed to it and result variables returned from it. |
verbose | bool | See -verbose command line flag. |
Internal or deprecated: | ||
allow-license-gui | bool | |
alt-settings-dir | char * | |
application-mode | char * | |
check-ifaces | bool | |
disable-dstc | bool | |
disable-istc | bool | |
eclipse-params | char * | |
package-list | char * | |
py3k-warnings | bool | |
sign-module | bool | |
as-py-module | bool | |
py-import-all | bool | |
use-module-cache | bool |
void SIM_main_loop(void);
The main loop waits for work requests to be posted by notifiers, SIM_thread_safe_callback and SIM_realtime_event. If the command line has been initialized it will be active as well.
If the embedding application do not wish to transfer the control to Simics while the simulation is not advancing should use the SIM_process_work or SIM_process_pending_work to make sure that Simics can process any pending idle work.
int SIM_process_work(int (*done)(lang_void *done_data), lang_void *done_data);
int SIM_process_pending_work(void);
SIM_process_pending_work runs all work that has been queued up since the last call and returns immediately after.
SIM_process_work is similar but waits for new work to arrive. Each time some work has been processed, the supplied done callback is called with done_data as its only argument. A return value of 1 tells SIM_process_work to stop processing work and return control to the caller again while 0 tells it to continue.
The done predicate is only evaluated between callbacks that are run in Global Context, that is, not registered with the run_in_thread parameter set).
The process work functions return -1 if the user has pressed the interrupt key before or while they were running, provided that the simulator core was initialized to catch signals. Otherwise the return value is 0.
void SIM_set_frontend_context(void *context);
longjmp()
to give control back to the main loop. The longjmp
destination depends on the stack context buffer registered by the embedding
application using SIM_set_frontend_context.
If the embedding application uses Simics's own main loop to control the simulation, i.e., by running SIM_main_loop, then there is no need to register any stack context buffer.
A stack context buffer is created by calling sigsetjmp()
on Linux
and setjmp()
on Windows.
attr_value_t SIM_get_all_hap_types(void);
hap_handle_t SIM_hap_add_callback(const char *NOTNULL hap, NOTNULL obj_hap_func_t func, lang_void *user_data);
hap_handle_t SIM_hap_add_callback_index(const char *NOTNULL hap, NOTNULL obj_hap_func_t func, lang_void *user_data, int64 index);
hap_handle_t SIM_hap_add_callback_range(const char *NOTNULL hap, NOTNULL obj_hap_func_t func, lang_void *user_data, int64 start, int64 end);
hap_handle_t SIM_hap_add_callback_obj(const char *NOTNULL hap, conf_object_t *NOTNULL obj, hap_flags_t flags, NOTNULL obj_hap_func_t func, lang_void *user_data);
hap_handle_t SIM_hap_add_callback_obj_index(const char *NOTNULL hap, conf_object_t *NOTNULL obj, hap_flags_t flags, NOTNULL obj_hap_func_t func, lang_void *user_data, int64 index);
hap_handle_t SIM_hap_add_callback_obj_range(const char *NOTNULL hap, conf_object_t *NOTNULL obj, hap_flags_t flags, NOTNULL obj_hap_func_t func, lang_void *user_data, int64 start, int64 end);
Some hap add functions also take a flags argument. This flag is currently Simics internal and should be set to 0.
The hap callback functions should not return any data. In C, the functions
are declared to have a void
return type and in Python, any
return value is ignored. Since callback functions with different arguments
may be installed using the same API function, the compiler may warn about a
type mismatch. The solution is to cast the callback function pointer to the
obj_hap_func_t
type.
The callback will be called in Cell Context, unless the documentation for the hap states otherwise.
In hap functions, the execution can be interrupted by calling SIM_break_simulation. If a frontend or Python exception is raised, an error message will be printed including a stack trace if the callback is written in Python.
The _index_
and _range_
versions will install callbacks
that only trigger for a specified index, or range of indices. The index
is specific for each hap type, see the hap documentation. The index and
range must be non-negative and the end of the range must not be lower than
the start.
typedef int hap_handle_t;
hap_handle_t
, or -1 on error. This handle can be used to remove
the installed callback with SIM_hap_delete_callback_id.
SimExc_Attribute Thrown if the index is negative or if the range is negative in value or size.
void SIM_hap_delete_callback(const char *NOTNULL hap, NOTNULL obj_hap_func_t func, lang_void *user_data);
void SIM_hap_delete_callback_obj(const char *NOTNULL hap, conf_object_t *NOTNULL obj, NOTNULL obj_hap_func_t func, lang_void *user_data);
void SIM_hap_delete_callback_id(const char *NOTNULL hap, hap_handle_t handle);
void SIM_hap_delete_callback_obj_id(const char *NOTNULL hap, conf_object_t *NOTNULL obj, hap_handle_t handle);
hap
argument.
The SIM_hap_delete_callback_obj... functions will remove a callback that is installed on the specified object obj.
SIM_hap_delete_callback removes a callback not associated with
any object, with the callback function func
and the same
user_data
.
The SIM_hap_delete_callback_..._id functions take a hap handle
argument instead, as returned by the SIM_hap_add_callback...
functions.
These functions will trigger the Core_Hap_Callback_Removed
hap
for each removed callback.
bool SIM_get_quiet(void);
bool SIM_get_verbose(void);
-verbose
command line argument).
void SIM_set_quiet(bool quiet);
true
will enable the
quiet mode, whereas an argument of false
will disable it. Any other
arguments will cause a frontend exception. Please note that enabling the
quiet mode will disable verbose mode.
void SIM_set_verbose(bool verbose);
-verbose
command line argument). The verbose
argument can
be either true
or false
. Note that setting this flag will
disable quiet mode.
physical_address_t SIM_load_binary(conf_object_t *NOTNULL obj, const char *NOTNULL file, physical_address_t offset, bool use_pa, bool verbose);
The file will be loaded at the address formed by adding the virtual load address from the file, with the offset offset. If the flag use_pa is set, the ELF physical load address is used instead. The verbose flag will cause Simics to print info about the binary to the console.
The memory space to load into is given in the obj parameter. If the given space is a CPU object, its current virtual address space will be used, and addresses will be translated before writing to the physical memory space attached to the CPU.
If the file is not found in the current directory, the search path (see add-directory) is used to find the file.
SimExc_IOError
Thrown if there was a problem reading the
file.SimExc_General
Thrown if binary cannot be read into
memory.
void SIM_load_file(conf_object_t *NOTNULL obj, const char *NOTNULL file, physical_address_t base_address, bool verbose);
The file can be either a raw binary file or a file in the craff format.
The verbose flag will cause Simics to print some information about the load.
uint8 SIM_read_byte(conf_object_t *NOTNULL obj, generic_address_t paddr);
void SIM_write_byte(conf_object_t *NOTNULL obj, generic_address_t paddr, uint8 value);
SimExc_General Thrown if the object does not implement the memory space interface.
uint64 SIM_read_phys_memory(conf_object_t *NOTNULL cpu, physical_address_t paddr, int length);
Up to 8 bytes can be read in one call. The memory access will be of inquiry type, i.e. no timing-model or snoop device will be called.
For non-inquiry accesses, use the memory_space
interface directly.
SimExc_Attribute Thrown if length is out of range.
SimExc_General Thrown if the processors physical memory does not implement the necessary interface methods.
uint64 SIM_read_phys_memory_tags(conf_object_t *NOTNULL mem_space, physical_address_t paddr, unsigned ntags);
void SIM_write_phys_memory_tags(conf_object_t *NOTNULL mem_space, physical_address_t paddr, uint64 tag_bits, unsigned ntags);
void SIM_write_phys_memory(conf_object_t *NOTNULL cpu, physical_address_t paddr, uint64 value, int length);
Up to 8 bytes can be written in one call. The memory access will be of inquiry type, i.e. no timing-model or snoop device will be called.
SimExc_Attribute Thrown if length is out of range.
SimExc_General Thrown if the processors physical memory does not implement the necessary interface methods.
void SIM_add_module_dir(const char *path);
attr_value_t SIM_get_all_failed_modules(void);
attr_value_t SIM_get_all_modules(void);
void SIM_load_module(const char *NOTNULL module);
The module argument is the name of the module (not file name) to be loaded.
SimExc_General Thrown if the module failed to load for other reasons.
void SIM_module_list_refresh(void);
SIM_ASSERT_CELL_CONTEXT(obj);
In other worlds, the macro ensures that the execution context is either Cell Context or Global Context.
SIM_ASSERT_OBJECT_LOCK(obj);
domain_lock_t * SIM_acquire_cell(conf_object_t *NOTNULL obj, const char *NOTNULL function_name, const char *NOTNULL source_location);
void SIM_release_cell(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_CELL(obj, lockp);
SIM_RELEASE_CELL(obj, lockp);
As part of entering Cell Context, the cell thread domain for the cell associated with obj is acquired.
Entering Cell Context multiple times is allowed, but acquired thread domains must be released in strict reverse order.
This function will block until the cell is available if another thread is currently holding the cell thread domain. While blocking, any previously held domains can be acquired by the thread already in Cell Context. Thus, the caller must be prepared to handle e.g. incoming interface calls.
In Cell Context, API functions marked with Cell Context or Global Context can be called safely, and interfaces on objects belonging to the same cell can be called directly. More generally, the full Standard Device Model applies in Cell Context. Refer to the chapter about threading in the API Reference Manual for more details.
The macro version of this API call sets the function_name and source_location arguments automatically with the information where the API call was made. This data is used when lock statistics collection is enabled through the enable-object-lock-stats command.
domain_lock_t * SIM_acquire_object(conf_object_t *NOTNULL obj, const char *NOTNULL function_name, const char *NOTNULL source_location);
void SIM_release_object(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_OBJECT(obj, lockp);
SIM_RELEASE_OBJECT(obj, lockp);
A particular thread domain can only be held by a single thread at a time, and this function blocks until the domain is available. Once the domain is held, the thread can safely access state protected by the domain.
While blocking, any previously held domains can be acquired by threads with higher priority, such as a thread running in Cell Context.
More than one thread domain can be held simultaneously, and the same thread domain may be acquired multiple times. However, domains must be released in strict reverse order.
This function is typically used by models using the Threaded Device Model to acquire the model's own thread domain from its interface methods. In this case, obj is set to the model itself.
The macro version of this API call sets the function_name and source_location arguments automatically with the information where the API call was made. This data is used when lock statistics collection is enabled through the enable-object-lock-stats command.
More details about thread domains and the threading model are available in the chapter about threading in the API Reference Manual.
domain_lock_t * SIM_acquire_object_for_execution(conf_object_t *NOTNULL obj);
Note: This API function is considered tech-preview and may change without notice.
domain_lock_t * SIM_acquire_target(conf_object_t *NOTNULL obj, const char *NOTNULL function_name, const char *NOTNULL source_location);
void SIM_release_target(conf_object_t *NOTNULL obj, domain_lock_t *lock);
SIM_ACQUIRE_TARGET(obj, lockp);
SIM_RELEASE_TARGET(obj, lockp);
The intended use for this function is ensuring that Cell Context is entered before a code running in Threaded Context invokes an interface on some external object. If the external object is thread aware, and does not require Cell Context, this function avoids entering Cell Context as an optimization.
The macro version of this API call sets the function_name and source_location arguments automatically with the information where the API call was made. This data is used when lock statistics collection is enabled through the enable-object-lock-stats command.
domain_lock_t * SIM_drop_thread_domains(void);
void SIM_reacquire_thread_domains(domain_lock_t *dl);
SIM_DROP_THREAD_DOMAINS(obj, lockp);
SIM_REACQUIRE_THREAD_DOMAINS(obj, lockp);
This function is intended to use before blocking is initiated on an external synchronization mechanism, like a condition variable. Releasing thread domains before blocking is often necessary to avoid deadlock situations where other threads get stuck trying to acquire thread domains held by the blocking thread.
Each call to SIM_drop_thread_domains must be followed with a call to SIM_reacquire_thread_domains to reacquire the released thread domains. This must be done from the same thread.
If the purpose of the call is just to provide other threads an opportunity to acquire held domains, then the more efficient SIM_yield_thread_domains should be used instead.
The macro versions of the API calls are currently wrappers of the corresponding SIM-function. In the future, they might collect extra information about where in the code the domain locks are reacquired.
void SIM_yield_thread_domains(void);
The function blocks until all threads waiting for one of the held domains have had the opportunity to acquire the domain in question, and then resumes execution with the domains held again.
One example usage of this function is when a CPU model is notified
through the execute_control
interface that another
thread wants to acquire the CPU's thread domain. Then the CPU
function should call this function as quickly as possible,
preferably before starting the simulation of the next instruction.
void SIM_add_output_handler(void (*NOTNULL f)(lang_void *user_data, const char *text, size_t length), lang_void *user_data);
void SIM_remove_output_handler(void (*NOTNULL f)(lang_void *user_data, const char *text, size_t length), lang_void *user_data);
text contains length bytes of output data. user_data is passed unchanged to the output handler.
SIM_remove_output_handler removes f as an output
recipient. If user_data is NULL
, all output
handlers with the same function will be removed; otherwise, only those with
equal user_data will be removed.
Output handlers must be thread-safe in order to handle output from different threads properly. There will only be one activation of each handler at a given instant so strict re-entrancy is not required, but proper locking around resources shared with other code should be in place.
int SIM_write(const void *NOTNULL src, int length);
int SIM_flush(void);
int SIM_putchar(int c);
int SIM_puts(const char *NOTNULL s);
int SIM_printf_vararg(const char *NOTNULL format, va_list ap);
int SIM_printf(const char *NOTNULL format, ...);
The output will be sent to stdout, but more output recipients can be added using the SIM_add_output_handler function. Output is line buffered. SIM_flush will force output of an unterminated line.
void SIM_add_directory(const char *NOTNULL directory, bool prepend);
The directory argument is first converted using SIM_native_path, to yield a path on host native form. If the path does not exist, a frontend exception is raised.
If prepend is true, the directory is inserted first in the list of directories.
This list of directories is saved as the attribute simics_path when doing write-configuration. Each directory is first converted to absolute form if relative.
void SIM_clear_directories(void);
attr_value_t SIM_get_directories(void);
char * SIM_lookup_file(const char *file);
The returned path will always be in host native format, so it will not need to be converted. See SIM_native_path for more details on what "host native format" means.
NULL
is returned if file cannot be found.
The search algorithm is as follows.
NULL
or an empty string,
the function returns NULL
. %simics%
, the rest of the
path is looked up first in the current Simics project, and then in
all configured Simics packages. If a match is found, the native form
of the file found will be returned.If the file was found, a pointer to the full path to the file is returned. The ownership of the string is passed to the caller.
char * SIM_native_path(const char *NOTNULL path);
The value returned by this function is allocated and owned by the caller.
FORCE_INLINE void SIM_clear_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
FORCE_INLINE int SIM_get_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
FORCE_INLINE void SIM_set_augmentation_bit(uint8 *tag_page_data, unsigned pofs);
direct_memory_tags
interface supports augmented memory through the data
field in the direct_memory_tags_t
struct.
tuple_int_string_t SIM_disassemble_address(conf_object_t *NOTNULL cpu, generic_address_t address, int logical, int sub_operation);
A tuple_int_string_t
is returned which contains the
disassembly string as well as the length of the instruction in
bytes. tuple_int_string_t is defined like this:
typedef struct { int integer; char *string; } tuple_int_string_t;
For the Sparc and PowerPC targets the length is always 4 bytes.
This function can be more convenient to use than the
disassemble function in the
processor_info
interface.
SimExc_Memory Thrown if the address is undefined or not mapped in the MMU (for logical addresses).
attr_value_t SIM_get_all_processors(void);
conf_object_t * SIM_get_processor(int proc_no);
int SIM_get_processor_number(const conf_object_t *NOTNULL cpu);
int SIM_number_processors(void);
int SIM_processor_privilege_level(conf_object_t *NOTNULL cpu);
void SIM_reset_processor(conf_object_t *NOTNULL cpu, int hard_reset);
FORCE_INLINE uint64 SIM_iter_next(addr_prof_iter_t *iter);
FORCE_INLINE generic_address_t SIM_iter_addr(addr_prof_iter_t *iter);
FORCE_INLINE void SIM_iter_free(addr_prof_iter_t *iter);
An address profile iterator visits some of the counters of an address
profiler in some order. It is obtained from the iter function of
the address_profiler
interface.
SIM_iter_next advances the address profile iterator iter to the next nonzero counter and returns the count. It will return 0 when there are no more counters to visit. Note that the order in which the counters are visited is unspecified.
SIM_iter_addr returns the address of the counter returned by the most recent call to iter_next.
When you are done with the iterator, deallocate it with SIM_iter_free.
void SIM_break_message(const char *msg);
This is similar to SIM_break_simulation, with the difference that it doesn't actually break the simulation. It can be used by code that wants to display a break message and stop the simulation by some other means.
void SIM_break_simulation(const char *msg);
Simics will normally stop before the next instruction is executed. If this function is called when an instruction has started executing, and the instruction can be aborted, it will rewind to before the instruction. This might leave the simulation in a state where some repeatable part of the instruction is already executed.
pc_step_t SIM_continue(int64 steps);
With a non-zero steps, Simics will make sure that at least one processor runs steps steps and then stop the simulation. As with steps being 0, the function can also return early if other break criteria are met.
In order to properly control when simulation stops in time, it is advisable to use step or cycle breakpoints on one or more objects.
The function returns non-zero if the simulation was started, and 0 otherwise.
conf_object_t * SIM_current_clock(void);
cycle
interface) that is driving the simulation in the current cell and current
thread. In Global Context, NULL
is returned.
Normally, one uses SIM_object_clock to obtain the clock used for posting events. E.g. when a device processes a transaction it typically takes the clock from the initiator.
This function can instead be used in situations where it is important to know the currently running clock, e.g. to post events right after the current instruction finishes.
bool SIM_simics_is_running(void);
int SIM_cancel_realtime_event(int64 id);
Returns 0 if the callback existed and was cancelled, or -1 if no callback with that identifier existed. (No exception is raised.)
void SIM_notify_on_socket(socket_t sock, notify_mode_t mode, int run_in_thread, void (*callback)(lang_void *data), lang_void *data);
void SIM_notify_on_object(HANDLE obj, int run_in_thread, void (*callback)(lang_void *data), lang_void *data);
void SIM_notify_on_descriptor(int fd, notify_mode_t mode, int run_in_thread, void (*callback)(lang_void *data), lang_void *data);
If run_in_thread is 1, the callback function may be run in a thread where it cannot access or call anything in Simics except for these functions and SIM_thread_safe_callback. If run_in_thread is zero, the callback function is always run in Global Context. This may incur a small penalty in latency (time between the occurrence of the host event and execution of callback).
Values other than 0 and 1 for run_in_thread are reserved.
Notification on a specific event will be blocked during the execution of its callback function.
SIM_notify_on_socket will call a registered callback depending on mode:
mode | condition |
Sim_NM_Read |
Socket is readable, closed, or incoming connection accepted |
Sim_NM_Write |
Socket is writeable, or outgoing connection has completed |
Socket notifiers of the mode Sim_NM_Write
are not guaranteed
to be called again unless a previous attempt to send data to the socket
failed for flow control reasons (that is, it would have blocked).
This means that notifiers of that mode should only be enabled for waiting on the completion of a nonblocking outgoing connection or for a previously "full" socket to accept data again.
Linux only: SIM_notify_on_descriptor will call a registered callback depending on mode for a given file descriptor in a way similar to SIM_notify_on_socket.
Windows only: SIM_notify_on_object will call a registered callback when object (which must be a waitable object) is in signalled state. The signalling object is modified in the same way as the Windows wait functions (WaitForMultipleObjects etc).
int64 SIM_realtime_event(unsigned delay, void (*NOTNULL callback)(lang_void *data), lang_void *data, int run_in_thread, const char *desc);
If run_in_thread is 1, the callback may be run in a thread where it cannot access or call anything in Simics except for SIM_thread_safe_callback. If run_in_thread is zero, the callback function is always run in Global Context, with the simulation temporarily suspended and the entire Simics API available. This may cause the call to occur slightly later than requested, depending on what Simics is doing at the time.
Values other than 0 and 1 for run_in_thread are reserved.
The desc parameter is only present for debugging and has no other effect; it should be a static string describing the callback but may also be left NULL if desired.
The callback is only called once.
The return value is a non-zero identifier that can be used to cancel the callback using SIM_cancel_realtime_event.
void SIM_register_work(void (*NOTNULL f)(lang_void *data), lang_void *data);
In general, the function SIM_run_alone should be used instead of this function when a callback is posted from Cell Context. The reason is that SIM_run_alone, but not SIM_register_work, guarantees that the callback is executed before the next instruction is dispatched.
void SIM_run_async_work(lang_void *(*NOTNULL async_call)(lang_void *arg), void (*async_ready)(lang_void *async_ret, lang_void *arg), lang_void *arg);
The user supplied arg parameter is passed unmodified to both callback functions.
SIM_run_async_work is typically used when calling functions that would block the main thread for a long time while obtaining their result.
If the result of SIM_run_async_work is used in the simulation,
it should be sent through a recorder to make sure that the session can be
replayed. This is needed for features such as reverse execution to work.
See the recorder module and the recorder_v2
interface for
more information.
import socket def async_call(arg): # runs in separate thread without blocking Simics return socket.gethostbyname(arg) def async_ready(ret, arg): # runs in Simics main thread with access to the full Simics API print("Host %s has IP address %s" % (arg, ret)) simics.SIM_run_async_work(async_call, async_ready, "www.intel.com")
void SIM_run_in_thread(void (*NOTNULL f)(lang_void *arg), lang_void *arg);
Simics maintains a pool of worker threads used by this function, and hence the callback can typically be started quickly.
The callback is allowed to block or otherwise run for a long time.
The user supplied arg parameter is passed unmodified to the callback.
void SIM_thread_safe_callback(void (*NOTNULL f)(lang_void *data), lang_void *data);
When the callback is run, it is executed in Global Context, which means that it is safe to call any API functions from it. Another thread in the module may at this time also call API functions, if it synchronizes correctly with the callback function. For example, the callback function might just signal to the foreign thread to do its Simics API calls, wait for the thread to signal that it has finished, and then return.
void SIM_STC_flush_cache(conf_object_t *NOTNULL cpu);
void SIM_flush_I_STC_logical(conf_object_t *NOTNULL cpu, logical_address_t vaddr, logical_address_t length);
void SIM_flush_D_STC_logical(conf_object_t *NOTNULL cpu, logical_address_t vaddr, logical_address_t length);
void SIM_flush_I_STC_physical(conf_object_t *NOTNULL cpu, physical_address_t paddr, physical_address_t length);
void SIM_flush_D_STC_physical(conf_object_t *NOTNULL cpu, physical_address_t paddr, physical_address_t length, read_or_write_t read_or_write);
SIM_STC_flush_cache flushes the entire contents of the STCs (both instruction and data) from the specified cpu.
The SIM_flush_xxx functions removes specified memory
ranges in the instruction or data STC. The address range is either the
logical or the physical address. The read_or_write
parameter
specifies whether the read or the write D-STC should be flushed. If the
function doesn't have such a parameter, both read and write D-STCs are
flushed. The flushed address range is at least [ vaddr
... (vaddr + length − 1) ], but may be larger.
SIM_flush_D_STC_logical currently always flushes an entire
page.
The SIM_flush_xxx functions can only be used on CPUs
that implement the internal stc
interface; hence, they can
not be used on user-defined CPU models.
void SIM_flush_all_caches(void);
void SIM_flush_cell_caches(conf_object_t *NOTNULL obj);
cycles_t SIM_stall_count(conf_object_t *NOTNULL obj);
void SIM_stall_cycle(conf_object_t *NOTNULL obj, cycles_t cycles);
void SIM_stall(conf_object_t *NOTNULL obj, double seconds);
The specified duration is interpreted as relative the local time of obj.
obj must implement the stall
and
cycle
interfaces.
cycles_t SIM_stalled_until(conf_object_t *NOTNULL obj);
const char * SIM_get_global_message(void *ref);
NULL
.
This function must only be called from a callback of the global notifier
Sim_Global_Notify_Message
.
void SIM_run_alone(void (*NOTNULL f)(lang_void *data), lang_void *data);
If the callback is posted while an instruction is being emulated then the callback be invoked when the current instruction has completed and before the next instruction is dispatched.
Although no other execution threads are running when the callback is invoked, their exact position in simulated time may vary between runs. If the callback accesses objects in cells other than the one that SIM_run_alone was called from, then care must be taken to preserve determinism.
void SIM_trigger_global_message(const char *msg, void *ref);
NULL
to dispatch to all listeners.
The notifier callbacks should use SIM_get_global_message to
retrieve the message. Only callbacks that provide a NULL
reference
or a reference different from ref will obtain the message.
attr_value_t SIM_call_python_function(const char *NOTNULL func, attr_value_t *NOTNULL args);
The namespace searched for func is the same as the Simics
commands @ and python use; i.e., the Python module
__main__
. You may want to use a module-relative name for
func such as __builtin__.repr
when calling functions
not defined at the Simics command-line. This avoids calling any local
redefinition of that function.
attr_value_t
.
SimExc_Lookup Thrown if func does not exist.
SimExc_General Thrown if there was an error executing
Python code.
SimExc_Break Thrown on user interrupt.
api_function_t SIM_get_api_function(const char *function);
The pre-processor macro GET_API_FUNCTION
provides
wrapping of SIM_get_api_function for simpler type casting.
SIM_get_api_function is neither available nor needed in Python. To access a new function in a backward compatible way there, the build id can be used to write conditional code, see example below.
GET_API_FUNCTION(tmp_SIM_foo, SIM_foo); if (tmp_SIM_foo != NULL) tmp_SIM_foo(1); else // code for older versions
Once compatibility with versions before build id 5234 can be dropped, the code in the example is simply replaced with a direct call to SIM_foo.
The corresponding implementation in Python is:
if hasattr(simics, 'SIM_foo'): SIM_foo(1) else: # code for older versions
Or alternatively:
if conf.sim.build_id >= 5234: SIM_foo(1) else: # code for older versions
api_function_t
is defined as:
typedef void (*api_function_t)(void);
bool SIM_get_batch_mode(void);
conf_object_t * SIM_get_debugger(void);
attr_value_t SIM_load_target(const char *NOTNULL target, const char *ns, attr_value_t presets, attr_value_t cmdline_args);
This function is functionally equivalent to invoking the script by passing
it as a command line argument or to running the script with the
load-target or run-script command, with the
local
flag set.
The ns and presets arguments have the same semantics as namespace and presets arguments to the run-script command.
The cmdline_args argument should be a list of 2-element lists
of target parameters [name, value]
.
SimExc_General Thrown if the script was interrupted by an error.
SimExc_IOError Thrown if the script file could not be opened.
void SIM_quit(int exit_code);
attr_value_t SIM_run_command(const char *NOTNULL line);
SimExc_Type Thrown if the return value could not be converted
to an attr_value_t
.
void SIM_run_command_file(const char *NOTNULL file, bool local);
void SIM_run_command_file_params(const char *NOTNULL file, bool local, attr_value_t params);
This function is functionally equivalent to invoking the script by passing it as a command line argument or to running the script with the run-command-file command.
If local is true, the script will run with its own copy of all global CLI variables. When the script has finished executing, the previous variable set is restored.
The params argument can be used to pass parameters to the
script. It must be a list of name-value pairs of strings, for example, from
Python it could be [["num_cores", "4"], ["memory_megs", "1024"]]
.
SimExc_General Thrown if the script was interrupted by an error.
SimExc_IOError Thrown if the script file could not be opened.
attr_value_t SIM_run_python(const char *NOTNULL line);
SimExc_Type Thrown if the return value could not be converted
to an attr_value_t
.
SimExc_Break Thrown on user interrupt.
void SIM_shutdown(void);
void SIM_source_python(const char *NOTNULL file);
void SIM_source_python_in_module(const char *NOTNULL file, const char *NOTNULL module);
SimExc_IOError Thrown if there was an error opening the file.
SimExc_Break Thrown on user interrupt.