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_parent
to retrieve the port object parent instead of relying on SIM_object_parent
. The main reason for this is that the former will always return the correct object, whereas the later will return the hierarchical parent, which sometimes is not the desired object. As an example, if SIM_object_parent
is applied to the objects myobj.port.RESET
, myobj.port.signal[2]
and myobj.bus_clock
, then the return value will be myobj.port
, myobj.port.signal
and myobj
respectively. The SIM_port_object_parent
function, on the other hand, consistently returns the wanted myobj
object in all three cases.