Ports in groups - intel/device-modeling-language GitHub Wiki
We want to permit group g { port p { port q; } }
; here's some design sketches for how to do this.
Initial attempts
We have some different options, which I have parameterized by how you expect the port
prefix to appear in the port object name.
dev.port.g.p.q
The idea is that all ports appear under the dev.port
namespace, so the g
prefix appears after that.
A sibling bank b
would appear as a second cousin, in dev.bank.g.b
. For this reason, we need two params to define prefix, param port_portname
and bank_portname
, defaulting to parent.objkind == "device" #? "port." + name : name
(s/port/bank/ for bank_portname
). Both params are available on groups, banks and ports, and the full name of a port is the sum of obj.port_portname for all objects in the hierarchy, so in:
group g {
port_portname = "x.g";
bank b {
param port_portname = "y.b";
port p {
param port_portname = "z.p";
}}}
... you will get dev.x.g.y.b.z.p
and dev.bank.g.b
.
We have largely dismissed this idea, since it gets too complicated in practice (tried a few different approaches and the above sketch is the simplest we could find). Including it here for completeness.
dev.g.p.q
The idea here is that the port
prefix only appears directly under dev, as a common special case for top-level port
objects. No prefix is added for any other objects; you generally create group indirections to control the namespace.
A single param portname
is available, in port
, bank
and group
objects (not strictly necessary in groups). Its primary purpose is to suppress port.
on top level, and defaults to parent.objkind == "device" #? "port." + name #: name
in ports, the same with s/port/bank/ in banks, and name
in groups.
group g {
param portname = "x.g";
bank b {
param portname = "y.b";
port p {
param portname = "z.p";
}}}
then the bank's name is dev.x.g.y.b
and the port's name is dev.x.g.y.b.z.p
.
A problem with this approach is that we stop encouraging the .port
naming convention in subobjects; it's up to each modeler how to apply .port
naming conventions which leads to inconsistency.
dev.g.port.p.port.q
The idea here is to have an easy-to-explain rule that "all ports are prefixed with 'port.' by default". I.e., the portname
param works as in the previous design, but the default value is "port." + name
in ports, "bank." + name
in banks, and name
in groups. This is a simple rule that arguably is a natural generalization of current behaviour, but it's probably seldom what you want so it will be common to override the param with name
.
dev.g.port.p.q
The idea here is that any port should generally be marked as such using a port
prefix, but you can put a port in a group
to group it with other ports as a subsystem of a device, and you can also create a hierarchy of groups by putting a port in a port. The default value of portname
is _nongroup_parent.objtype == "device" #? "port." + name #: name
, where _nongroup_parent
is an existing internal param.
This approach is rather nice, but the g
subsystem is represented in Simics as a naked namespace
object, so if it contains an attribute g.a
for configuration or state, then that will be available only as dev.g_a
; if you want the attribute to be exposed as dev.g.a
, then you need to write port g { param portname = name; port p { param portname = "port.p"; { port q;
, i.e. override portname both in g
and g.p
.
We could help this use case by instead defining a non-overrideable param portname = add_portname_prefix #? "port." + name #: name;
and say that add_portname_prefix
defaults to true iff it's false for all ancestor port
and bank
objects. I.e., the port.
prefix is added automatically but never more than once in the hierarchy. However, this adds even more complexity to the definition.
Conclusion
The above designs are essentially heuristics to guess whether a port object represents a physical port to connect with other hardware (and deserves a .prefix), or if it primarily represents some sort of subdevice. Perhaps the best is to view subdevice and port as different kinds of object, i.e. subdevice d { port b; }
gives a.port.b
, and differs from group
in that subdevice d { saved int a; }
creates an attribute dev.d.a
instead of dev.d_a
.
With this kind of object, dev.g.port.p.port.q
is the clear winner of the above alternatives: port.p.port.q
may look strange, but that's because you probably wanted to write something like group g { subdevice p { port q
.
Adding a new object type is a rather big change; this hasn't happened since around 2007. So, as a first step, I propose to add a template template subdevice_port is port
that, when instantiated, suppresses the .port
portion of the portname. Once this is proven commonly useful in real code, we can add a subdevice
object type.