Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/18168
Change subject: python: Make Port roles a more generic concept.
......................................................................
python: Make Port roles a more generic concept.
A recent change got rid of the strict Master => Slave port relationship
which used to be checked in python and instead left the checking up to
C++. One major downside to this approach is that it was no longer
obvious in the configuration what was supposed to be connected to what,
and it still left the arbitrary and misleading MasterPort and SlavePort
types in the Ethernet devices which could now connect with each other
symmetrically but couldn't actually connect to an arbitrary
MasterPort/SlavePort.
This change exposes the base Port and VectorPort types, and makes them
accept a "role" parameter in __init__ which used to be set directly by
their subclasses. This role can be any string, and will be used later
to check for compatiblity and to give a hint as to what can be
connected to what in the SimObject definitions.
To make the checks work with arbitrary compatible pairs, the base Port
type now has a class method called compat() which accepts a pair of
roles which will become mutually compatible, ie any port with the first
role will be allowed to connect to any port with the second role, and
vice versa. To be self compatible, the same role should be passed in
for both parameters.
To maintain compatibility, the MasterPort and SlavePort types are
retained, but now they're nothing special and could have been set up
in any arbitrary SimObject .py file. The same is true for
MasterVectorPort and SlaveVectorPort.
Also, since we can no longer assume that all edges in the dot graph of
the config should start with a port with the MASTER role and end with
a port with the SLAVE role, Ports now track an is_source property which
says whether the arrow head should be surpressed at that end of the
edge representing the connection.
Change-Id: Ifcc6faab05e437ad87cd21f0ba613b09cf21c321
---
M src/python/m5/params.py
1 file changed, 57 insertions(+), 42 deletions(-)
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index 5236022..f03a100 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -1834,11 +1834,12 @@
# Port reference: encapsulates a reference to a particular port on a
# particular SimObject.
class PortRef(object):
- def __init__(self, simobj, name, role):
+ def __init__(self, simobj, name, role, is_source):
assert(isSimObject(simobj) or isSimObjectClass(simobj))
self.simobj = simobj
self.name = name
self.role = role
+ self.is_source = is_source
self.peer = None # not associated with another port yet
self.ccConnected = False # C++ port connection done?
self.index = -1 # always -1 for non-vector ports
@@ -1857,7 +1858,8 @@
# for config.json
def get_config_as_dict(self):
- return {'role' : self.role, 'peer' : str(self.peer)}
+ return {'role' : self.role, 'peer' : str(self.peer),
+ 'is_source' : str(self.is_source)}
def __getattr__(self, attr):
if attr == 'peerObj':
@@ -1878,15 +1880,25 @@
fatal("Port %s is already connected to %s, cannot
connect %s\n",
self, self.peer, other);
self.peer = other
+
if proxy.isproxy(other):
other.set_param_desc(PortParamDesc())
- elif isinstance(other, PortRef):
- if other.peer is not self:
- other.connect(self)
- else:
+ return
+ elif not isinstance(other, PortRef):
raise TypeError("assigning non-port reference '%s' to
port '%s'" \
% (other, self))
+ # Check if this pair of ports are compatible with each other.
+ if not self.role in Port._compat_dict:
+ fatal("Unrecognized role '%s' for port %s\n", self.role, self)
+
+ if not other.role in Port._compat_dict[self.role]:
+ fatal("Ports %s and %s with roles '%s' and '%s' "
+ "are not compatible", self, other, self.role,
other.role)
+
+ if other.peer is not self:
+ other.connect(self)
+
# Allow a master/slave port pair to be spliced between
# a port and its connected peer. Useful operation for connecting
# instrumentation structures into a system when it is necessary
@@ -1959,8 +1971,8 @@
# A reference to an individual element of a VectorPort... much like a
# PortRef, but has an index.
class VectorPortElementRef(PortRef):
- def __init__(self, simobj, name, role, index):
- PortRef.__init__(self, simobj, name, role)
+ def __init__(self, simobj, name, role, is_source, index):
+ PortRef.__init__(self, simobj, name, role, is_source)
self.index = index
def __str__(self):
@@ -1969,11 +1981,12 @@
# A reference to a complete vector-valued port (not just a single element).
# Can be indexed to retrieve individual VectorPortElementRef instances.
class VectorPortRef(object):
- def __init__(self, simobj, name, role):
+ def __init__(self, simobj, name, role, is_source):
assert(isSimObject(simobj) or isSimObjectClass(simobj))
self.simobj = simobj
self.name = name
self.role = role
+ self.is_source = is_source
self.elements = []
def __str__(self):
@@ -1991,14 +2004,16 @@
# for config.json
def get_config_as_dict(self):
return {'role' : self.role,
- 'peer' : [el.ini_str() for el in self.elements]}
+ 'peer' : [el.ini_str() for el in self.elements],
+ 'is_source' : str(self.is_source)}
def __getitem__(self, key):
if not isinstance(key, int):
raise TypeError("VectorPort index must be integer")
if key >= len(self.elements):
# need to extend list
- ext = [VectorPortElementRef(self.simobj, self.name, self.role,
i)
+ ext = [VectorPortElementRef(
+ self.simobj, self.name, self.role, self.is_source, i)
for i in range(len(self.elements), key+1)]
self.elements.extend(ext)
return self.elements[key]
@@ -2042,10 +2057,24 @@
# logical port in the SimObject class, not a particular port on a
# SimObject instance. The latter are represented by PortRef objects.
class Port(object):
+ # Port("role", "description")
+
+ _compat_dict = { }
+
+ @classmethod
+ def compat(cls, role, peer):
+ cls._compat_dict.setdefault(role, set()).add(peer)
+ cls._compat_dict.setdefault(peer, set()).add(role)
+
+ def __init__(self, role, desc, is_source=False):
+ self.desc = desc
+ self.role = role
+ self.is_source = is_source
+
# Generate a PortRef for this port on the given SimObject with the
# given name
def makeRef(self, simobj):
- return PortRef(simobj, self.name, self.role)
+ return PortRef(simobj, self.name, self.role, self.is_source)
# Connect an instance of this port (on the given SimObject with
# the given name) with the port described by the supplied PortRef
@@ -2066,52 +2095,38 @@
def cxx_decl(self, code):
code('unsigned int port_${{self.name}}_connection_count;')
+Port.compat('MASTER', 'SLAVE')
+
class MasterPort(Port):
# MasterPort("description")
- def __init__(self, *args):
- if len(args) == 1:
- self.desc = args[0]
- self.role = 'MASTER'
- else:
- raise TypeError('wrong number of arguments')
+ def __init__(self, desc):
+ super(MasterPort, self).__init__('MASTER', desc, is_source=True)
class SlavePort(Port):
# SlavePort("description")
- def __init__(self, *args):
- if len(args) == 1:
- self.desc = args[0]
- self.role = 'SLAVE'
- else:
- raise TypeError('wrong number of arguments')
+ def __init__(self, desc):
+ super(SlavePort, self).__init__('SLAVE', desc)
# VectorPort description object. Like Port, but represents a vector
# of connections (e.g., as on a XBar).
class VectorPort(Port):
- def __init__(self, *args):
+ # VectorPort("role", "description")
+ def __init__(self, role, desc, is_source=False):
+ super(VectorPort, self).__init__(role, desc, is_source)
self.isVec = True
def makeRef(self, simobj):
- return VectorPortRef(simobj, self.name, self.role)
+ return VectorPortRef(simobj, self.name, self.role, self.is_source)
class VectorMasterPort(VectorPort):
# VectorMasterPort("description")
- def __init__(self, *args):
- if len(args) == 1:
- self.desc = args[0]
- self.role = 'MASTER'
- VectorPort.__init__(self, *args)
- else:
- raise TypeError('wrong number of arguments')
+ def __init__(self, desc):
+ super(VectorMasterPort, self).__init__('MASTER', desc,
is_source=True)
class VectorSlavePort(VectorPort):
# VectorSlavePort("description")
- def __init__(self, *args):
- if len(args) == 1:
- self.desc = args[0]
- self.role = 'SLAVE'
- VectorPort.__init__(self, *args)
- else:
- raise TypeError('wrong number of arguments')
+ def __init__(self, desc):
+ super(VectorSlavePort, self).__init__('SLAVE', desc)
# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
# proxy objects (via set_param_desc()) so that proxy error messages
@@ -2145,5 +2160,5 @@
'MaxAddr', 'MaxTick', 'AllMemory',
'Time',
'NextEthernetAddr', 'NULL',
- 'MasterPort', 'SlavePort',
- 'VectorMasterPort', 'VectorSlavePort']
+ 'Port', 'MasterPort', 'SlavePort',
+ 'VectorPort', 'VectorMasterPort', 'VectorSlavePort']
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/18168
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: Ifcc6faab05e437ad87cd21f0ba613b09cf21c321
Gerrit-Change-Number: 18168
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev