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

1.3 API usage rules

1.3.1 Simics API value ownership rules

The owner of a value in memory is the code or object responsible for freeing the value when it is no longer needed. Failure to do so may cause excessive memory consumption (a memory leak). Deallocation of objects that are not owned, or use of objects after they have been freed, will likely result in a crash.

The ownership rules only apply to code written in C, C++ and DML. In Python, memory management is entirely automatic.

The general rules in Simics are:

Exceptions to the rules above are documented for each interface or API call.

Each data type has its own way of deallocation. It is generally documented where objects of that type are created; see below for some specific examples.

Strings
Null-terminated strings are freed using MM_FREE in C/C++, delete in DML. They are created using MM_MALLOC, MM_STRDUP or other functions that create heap-allocated strings. (The standard C library functions malloc, free etc should not be used.)

The pointer-to-const rule applies: a string returned as char * becomes owned by the caller, but not one returned as const char *.

Attribute values
Values of type attr_value_t are freed using SIM_attr_free.

Since the values may refer to heap-allocated data, they cannot be copied by simple (shallow) assignment. To create a (deep) copy of an attr_value_t that is safe to access after the original has been freed, use SIM_attr_copy.

The attr_value_t accessor functions return values that borrow references to parts of the argument. Therefore, the returned values cannot be altered, and cannot be used beyond the life-time of the argument. (This obviously does not apply to non-allocated values such as numbers or booleans.)

Simics-managed types
Values of some types are always owned and managed by Simics itself and should never be freed by the user. Examples are conf_object_t and conf_class_t.

1.3.2 API Execution Contexts

The set of Simics API functions and interface methods that can be called at a given point depends on the state of the execution thread at the time of the call. The thread states are classified into API execution contexts. Three distinct execution contexts are defined, and they are inclusive, as illustrated in the figure below:

The execution context defines the part of the Simics API that may be used


Below is a description of the defined execution contexts:

Global Context
Previously, this context was known as Outside Execution Context (OEC).

The most permissive context. A thread running in Global Context has exclusive access to all objects in the simulation.

In Global Context, either the simulation is not running or all simulation activity has temporarily been suspended. The front-end runs in this context, as do the callbacks from SIM_run_alone, SIM_thread_safe_callback and SIM_notify_on_socket with the run_in_thread argument set to 0. Module initialisation, object creation and object destruction are also performed in this context.

The full API is available, including functions and methods documented as callable in other contexts.

Cell Context (EC/IC)
This is a single context which was introduced in Simics 6 instead of Execution Context (EC) and Instruction Context (IC) that were around before.

The context used for most device simulation. Typically used when the simulation is running.

Only functions and methods documented as callable in Cell Context or Threaded Context are available in this context.

Other objects in the simulation may be accessed or referenced, but only objects belonging to the same simulation cell. The cell concept is discussed in some detail in section 2.3, but basically it is a partitioning of the simulation into groups of objects. Cell Context is always tied to a specific cell.

Most device code run in this context, for instance when a CPU accesses a device register, as do event callbacks and many hap handlers.

Threaded Context
Previously, this context was known as Foreign Thread Context (FTC).

The most restrictive context, denoting a thread which is in neither Cell Context nor Global Context.

Manually created threads and SIM_run_in_thread callbacks are examples where this context is applicable. Thread-aware models, like a CPU with support for multicore threading, also perform most of its simulation in Threaded Context.

The available API is limited to functions explicitly declared as being available in Threaded Context, but a more permissive context can be entered when needed. For example, SIM_thread_safe_callback posts a callback which is invoked in Global Context, and Cell Context can be reached with the SIM_ACQUIRE_CELL primitive.

While objects can be accessed in this context, it is only permitted after special primitives are used to ensure single-threaded access. This usually amounts to entering Cell Context, but thread-aware models can actually access their own object state directly from Threaded Context. This is discussed in chapter 2.

The reference manuals detail the permitted API execution context for each API function and interface method. Calls are allowed in the specified and more permissive contexts.

Violations of the API execution context rules have undefined consequences. They may result in warnings or error messages, but this is not guaranteed. In particular, a class implementing an interface method is under no obligation to perform any such checks.

1.2 Simics API Information 1.4 Simics API Syntax