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 = simics.pre_conf_object('testbench', 'namespace')
image = simics.pre_conf_object('testbench.ram.image', 'image', size = 0x1000)
ram = simics.pre_conf_object('testbench.ram', 'ram')
ram(image = image)
simics.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 = simics.pre_conf_object('testbench2', 'namespace')
tb2.image = simics.pre_conf_object('image', size = 0x1000)
tb2.image.ram = simics.pre_conf_object('ram')
tb2.image.ram(image = tb2.image)
simics.SIM_add_configuration([tb2], None)
Hierarchical object names can also be passed directly to e.g.
SIM_create_object:
simics.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 = simics.pre_conf_object('array', 'index-map')
array[0] = simics.pre_conf_object('memory-space')
array[1] = simics.pre_conf_object('memory-space')
simics.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.