In Simics 6 there is a concept called Port Objects. A port object is a child object which is created automatically together with its parent object. The underlying idea is that a class should be able to specify a set of child objects, denoted port objects, which will be created automatically when the class is instantiated. The end user of the class does not need to explicitly create the port objects or even know about them.
Port objects are not intended as a replacement for components, but rather as a way to allow functionality to be factored out and put in separate objects residing in the namespace below the object. As the name implies, however, port objects are intended to function as a replacement for port interfaces.
Below is an example of how a port object can be registered on a class:
// Define a signal reset function
static void
signal_raise_reset(conf_object_t *port_obj)
{
conf_object_t *parent_obj = SIM_port_object_parent(port_obj);
...
}
// Create the class "myclass"
cls = SIM_create_class("myclass", &class_info);
// Register the port port.RESET
port_cls = SIM_register_simple_port(
cls, "port.RESET", "Hardware Reset Port");
// Register an interface on the created port object class
static const signal_interface_t signal_iface = {
.signal_raise = signal_raise_reset,
};
SIM_REGISTER_INTERFACE(port_cls, signal, &signal_iface);
In the example above, a port object is registered on myclass with the name
port.RESET. When the class subsequently is instantiated as an object myobj,
then the port object will be created as myobj.port.RESET. The port object will
be an instance of the class myclass.RESET with a single interface registered
on this class in this case. The port object class can be more complex than in
the simple example above; it can be defined to have attributes, multiple
interfaces or even port objects of its own.
The preceding example defined a class with a hierarchical class name,
myclass.RESET. The dot in the class name has the following meaning:
myclass.RESET it will look
for the module defining the class myclass, and myclass.RESET does not
need to be listed in the Makefile for this module.myclass.RESET and myclass.
That is, it is assumed that the port object may have direct access to the
instance data for myclass objects.It is possible to use pre-defined classes as well when port objects are defined, which is illustrated in the following example:
// Create the class "mydev"
cls = SIM_create_class("mydev", &class_methods);
// Register the port object 'bus_clock' as a 'cycle-counter' class
conf_class_t *cycle_counter_cls = SIM_get_class("cycle-counter");
SIM_register_port(cls, "bus_clock", cycle_counter_cls,
"Clock running at bus frequency");
When mydev is instantiated, then a cycle-counter instance will be created as
mydev.bus_clock. The cycle-counter class, which is included in the Simics
Base package, provides a cycle counter that runs at some user-defined frequency
and allows for event posting. In this example, the counter would typically be
used by mydev to model functionality that depends on some device specific
frequency.
For port objects that have attributes, it is often useful for the parent object to provide default values for certain attributes. Below are some examples when this is particularly useful:
The SIM_set_attribute_default function provides a way for the port object
parent to set default values. These default values take effect only if the
attribute in question is not set explicitly when the object is created. Default
attributes values can only be set from the init method or from attribute
setters of objects under construction. The later allows state to be propagated
from a port object parent to its children.
Setting attribute values directly during object construction, rather than setting attribute defaults, will invariably break checkpointing or not have the intended effect.
Below is an example showing an init method which sets a default value for the
frequency attribute of its bus_clock port object.
static lang_void *
init(conf_object_t *obj)
{
// Configure the bus_clock frequency...
conf_object_t *clock = SIM_object_descendant(obj, "bus_clock");
attr_value_t freq = SIM_make_attr_floating(1E6);
SIM_set_attribute_default(clock, "frequency", freq);
// Do other initialization as needed...
return obj;
}
The following is another example, where a bus object is propagated from the attribute setter of the parent to a port object child.
static set_error_t
attr_set_bus(conf_object_t *obj, attr_value_t *val)
{
// Propagate our configured bus as an
// attribute default for the "device" port object
if (!SIM_object_is_configured(obj)) {
conf_object_t *dev = SIM_object_descendant(obj, "device");
SIM_set_attribute_default(dev, "bus", *val);
}
// Do other things here...
return Sim_Set_Ok;
}
As a rule of thumb, it should be possible to instantiate a class without having to explicitly set attributes for any of its registered port objects.
The port object support extends to the pre_conf_object, as is illustrated in
the following example, which uses the ‘myclass’ Simics class defined previously:
simics> @myobj = pre_conf_object('myclass', 'myclass')
simics> @print(myobj.port.RESET)
pre conf object myclass.port.RESET of type myclass.RESET
That is, if a class defines port objects, then pre objects corresponding to the port objects will be created automatically.
A special function SIM_port_object_parent exists to retrieve the port object
parent from a port object. The function returns NULL if the object is not a
port object.
Use
SIM_port_object_parentto retrieve the port object parent instead of relying onSIM_object_parent. The main reason for this is that the former will always return the correct object, whereas the latter will return the hierarchical parent, which sometimes is not the desired object. As an example, ifSIM_object_parentis applied to the objectsmyobj.port.RESET,myobj.port.signal[2]andmyobj.bus_clock, then the return value will bemyobj.port,myobj.port.signalandmyobjrespectively. TheSIM_port_object_parentfunction, on the other hand, consistently returns the wantedmyobjobject in all three cases.