Simics objects are stored in an object hierarchy. The hierarchy allows objects to be grouped logically, making it easier to navigate complex configurations. The object hierarchy also serves a secondary purpose: it allows child objects to provide functionality to parent objects.
Starting with Simics 6, objects can be created in the namespace of another object almost without restrictions. In previous versions, the object hierarchy was tightly coupled to the component concept.
Several API functions exist for querying the object hierarchy:
SIM_object_descendant
returns a specific descendant of an object.SIM_object_parent
returns the parent of an object.SIM_object_iterator
returns an iterator for all descendants of an object.SIM_shallow_object_iterator
returns an iterator for all children of an object.In Python, the root of the object hierarchy is the conf
namespace, and child objects can be specified using the dot operator, as in the example conf.parent.child
. If a child object and an attribute has the same name, then the child object has precedence. Object attributes can be accessed unambiguously using the attr
namespace, e.g. object.attr.attribute
.
Simics objects can be created in the namespace of a another object by simply providing a hierarchical name. This is illustrated in the following example which creates the objects testbench
, testbench.ram
and testbench.ram.image
.
tb = pre_conf_object('testbench', 'namespace')
image = pre_conf_object('testbench.ram.image', 'image', size = 0x1000)
ram = pre_conf_object('testbench.ram', 'ram')
ram(image = image)
SIM_add_configuration([tb, image, ram], None)
The pre_conf_object
class also allows the configuration to be built hierarchically, which is illustrated in the following example:
tb2 = pre_conf_object('testbench2', 'namespace')
tb2.image = pre_conf_object('image', size = 0x1000)
tb2.image.ram = pre_conf_object('ram')
tb2.image.ram(image = tb2.image)
SIM_add_configuration([tb2], None)
Hierarchical object names can also be passed directly to e.g. SIM_create_object
:
SIM_create_object("memory-space", "testbench.pspace", [])
There are two basic Simics classes which often are useful when building the object hierarchy. The first one is the namespace
class which basically is an "empty" Simics class without any custom attributes or interfaces. The second class is the index-map
class, which is used by Simics to represent object maps.
As an example, the objects alpha[0]
, alpha[1]
and alpha[2]
are children of the object index-map
object alpha
. Nested index maps are used to construct multi-dimensional object maps, e.g. beta[1][2][3]
.
Simics adds index-maps automatically during object creation when necessary, but sometimes it is useful to create the index map object explicitly, like in the example below:
array = pre_conf_object('array', 'index-map')
array[0] = pre_conf_object('memory-space')
array[1] = pre_conf_object('memory-space')
SIM_add_configuration([array], None)
Simics does not impose any rules how child objects should be named. It is, however, recommended that the following conventions are followed in order to make it easy for a user to understand the purpose of a particular object:
object.port
.<port>
Objects under the port
namespace should be used for objects implementing interfaces on behalf of object
.
object.bank
.<bank>
The bank
namespace is used for objects implementing register banks on behalf of object
.
object
.<name>
Used for all other kinds of objects.
The object.port
and object.bank
objects are just plain namespaces. For specific objects, there might also be other namespaces that have been assigned a special meaning:
cpu.vtime
.<clock>
All CPUs have a vtime
object which handles event dispatching. Below this objects there are objects implementing event queues used by the CPU. There are normally at least a cycles
object which contains the cycle based event queue and a ps
object which holds the pico-seconds based event queue.
The creation of Simics objects is a process which contains several distinct steps that are executed in a strict sequence. Each step is performed for all objects under construction before the next step is attempted. The sequence looks as follows:
alloc
function from the corresponding class.init
method is called for each object.Sim_Init_Phase_Pre1
are set for all objects. Attributes of this kind should only be registered by classes provided by Simics Core.Sim_Init_Phase_1
are set for all objects.finalize
method is called for each object. The object is marked as configured.objects_finalized
method is called for each object.The object ordering for each step is defined by the object hierarchy, with parents being initialized before any descendants. Siblings are ordered alphanumerically. For the last step, there can be exceptions to this rule caused by explicit usage of the SIM_require_object
function from the finalize
method.
The particulars of the object initialization sequence and initialization ordering have some implications:
SIM_object_descendant
function from its init
method to obtain a reference to a child object. This is particularly useful for obtaining references to automatically created port objects.init
method by using the SIM_port_object_parent
function.SIM_set_attribute_default
function. This can be done from the init
function but also from individual attribute setters.Important: Objects should never set attributes on other objects during object construction since this will invariably break checkpointing. Setting default attribute values, however, is permitted and useful for configuring port objects.
Each object in Simics has an associated default clock which, among other things, is used for event posting. The queue
attribute is used to explicitly select a clock for a particular object.
In Simics 6, objects without an explicitly assigned clock inherit a default one from their respective parents. Thus, in many cases it is sufficient to just set the queue
attribute for a single object and all descendants will inherit the clock implicitly.
Note that the queue
attribute reflects the explicitly assigned clock. The SIM_object_clock
function can be used to retrieve the default clock for a particular object.
Cell membership is also inherited hierarchically.