Get Port stuff working with full-system scripts.

Key was adding support for cloning port references (trickier than it sounds).
Got rid of class/instance thing and go back to instance cloning...
still don't allow changing SimObject parameters/children after a
class (instance) has been subclassed or instantiated (or cloned), which
should avoid bizarre unintended behavior.

configs/test/fs.py:
    Add ".port" to busses to get a port reference.
    Get rid of commented-out code.
src/python/m5/__init__.py:
    resolveSimObject should call getCCObject() instead of createCCObject()
    to avoid cycles in recursively creating objects.
src/python/m5/config.py:
    Get rid of class/instance thing and go back to instance cloning.
    Deep copy has to happen only on instance cloning then (and not on subclassing).
    Add getCCObject() method to force creation of C++ SimObject without
    recursively creating its children.
    Add support for cloning port references (trickier than it sounds).
    Also clean up some very obsolete comments.
src/python/m5/objects/Bridge.py:
src/python/m5/objects/Device.py:
    Add ports.

--HG--
extra : convert_revision : 4816d05ead0de520748aace06dbd1911a33f0af8
This commit is contained in:
Steve Reinhardt 2006-06-15 11:45:51 -04:00
parent 185ec39f79
commit 88e22ee081
5 changed files with 223 additions and 293 deletions

View file

@ -129,17 +129,7 @@ class BaseTsunami(Tsunami):
ethernet = NSGigE(configdata=NSGigEPciData(),
pci_bus=0, pci_dev=1, pci_func=0)
etherint = NSGigEInt(device=Parent.ethernet)
# ethernet = Sinic(configdata=SinicPciData(),
# pci_bus=0, pci_dev=1, pci_func=0)
# etherint = SinicInt(device=Parent.ethernet)
console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk)
# bridge = PciFake(configdata=BridgePciData(), pci_bus=0, pci_dev=2, pci_func=0)
#class FreeBSDTsunami(BaseTsunami):
# disk0 = FreeBSDRootDisk(delay='0us', driveID='master')
# ide = IdeController(disks=[Parent.disk0],
# configdata=IdeControllerPciData(),
# pci_func=0, pci_dev=0, pci_bus=0)
class LinuxTsunami(BaseTsunami):
disk0 = LinuxRootDisk(driveID='master')
@ -149,45 +139,45 @@ class LinuxTsunami(BaseTsunami):
configdata=IdeControllerPciData(),
pci_func=0, pci_dev=0, pci_bus=0)
class LinuxAlphaSystem(LinuxAlphaSystem):
class MyLinuxAlphaSystem(LinuxAlphaSystem):
magicbus = Bus(bus_id=0)
magicbus2 = Bus(bus_id=1)
bridge = Bridge()
physmem = PhysicalMemory(range = AddrRange('128MB'))
bridge.side_a = magicbus
bridge.side_b = magicbus2
c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus2)
bridge.side_a = magicbus.port
bridge.side_b = magicbus2.port
physmem.port = magicbus2.port
tsunami = LinuxTsunami()
tsunami.cchip.pio = magicbus
tsunami.pchip.pio = magicbus
tsunami.pciconfig.pio = magicbus
tsunami.fake_sm_chip.pio = magicbus
tsunami.ethernet.pio = magicbus
tsunami.ethernet.dma = magicbus
tsunami.fake_uart1.pio = magicbus
tsunami.fake_uart2.pio = magicbus
tsunami.fake_uart3.pio = magicbus
tsunami.fake_uart4.pio = magicbus
tsunami.ide.pio = magicbus
tsunami.ide.dma = magicbus
tsunami.fake_ppc.pio = magicbus
tsunami.fake_OROM.pio = magicbus
tsunami.fake_pnp_addr.pio = magicbus
tsunami.fake_pnp_write.pio = magicbus
tsunami.fake_pnp_read0.pio = magicbus
tsunami.fake_pnp_read1.pio = magicbus
tsunami.fake_pnp_read2.pio = magicbus
tsunami.fake_pnp_read3.pio = magicbus
tsunami.fake_pnp_read4.pio = magicbus
tsunami.fake_pnp_read5.pio = magicbus
tsunami.fake_pnp_read6.pio = magicbus
tsunami.fake_pnp_read7.pio = magicbus
tsunami.fake_ata0.pio = magicbus
tsunami.fake_ata1.pio = magicbus
tsunami.fb.pio = magicbus
tsunami.io.pio = magicbus
tsunami.uart.pio = magicbus
tsunami.console.pio = magicbus
tsunami.cchip.pio = magicbus.port
tsunami.pchip.pio = magicbus.port
tsunami.pciconfig.pio = magicbus.port
tsunami.fake_sm_chip.pio = magicbus.port
tsunami.ethernet.pio = magicbus.port
tsunami.ethernet.dma = magicbus.port
tsunami.fake_uart1.pio = magicbus.port
tsunami.fake_uart2.pio = magicbus.port
tsunami.fake_uart3.pio = magicbus.port
tsunami.fake_uart4.pio = magicbus.port
tsunami.ide.pio = magicbus.port
tsunami.ide.dma = magicbus.port
tsunami.fake_ppc.pio = magicbus.port
tsunami.fake_OROM.pio = magicbus.port
tsunami.fake_pnp_addr.pio = magicbus.port
tsunami.fake_pnp_write.pio = magicbus.port
tsunami.fake_pnp_read0.pio = magicbus.port
tsunami.fake_pnp_read1.pio = magicbus.port
tsunami.fake_pnp_read2.pio = magicbus.port
tsunami.fake_pnp_read3.pio = magicbus.port
tsunami.fake_pnp_read4.pio = magicbus.port
tsunami.fake_pnp_read5.pio = magicbus.port
tsunami.fake_pnp_read6.pio = magicbus.port
tsunami.fake_pnp_read7.pio = magicbus.port
tsunami.fake_ata0.pio = magicbus.port
tsunami.fake_ata1.pio = magicbus.port
tsunami.fb.pio = magicbus.port
tsunami.io.pio = magicbus.port
tsunami.uart.pio = magicbus.port
tsunami.console.pio = magicbus.port
raw_image = RawDiskImage(image_file=disk('linux-latest.img'),
read_only=True)
simple_disk = SimpleDisk(disk=Parent.raw_image)
@ -196,7 +186,7 @@ class LinuxAlphaSystem(LinuxAlphaSystem):
cpu = TimingSimpleCPU()
else:
cpu = AtomicSimpleCPU()
cpu.mem = Parent.magicbus2
cpu.mem = magicbus2
cpu.itb = AlphaITB()
cpu.dtb = AlphaDTB()
sim_console = SimConsole(listener=ConsoleListener(port=3456))
@ -224,11 +214,12 @@ def DualRoot(clientSystem, serverSystem):
self.clock = '5GHz'
return self
root = DualRoot(LinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
LinuxAlphaSystem(readfile=script('netperf-server.rcS')))
root = DualRoot(
MyLinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
MyLinuxAlphaSystem(readfile=script('netperf-server.rcS')))
m5.instantiate(root)
exit_event = m5.simulate()
print 'Exiting @', m5.curTick(), 'because', exit_event.getCause()
print 'Exiting @ cycle', m5.curTick(), 'because', exit_event.getCause()

View file

@ -107,11 +107,7 @@ env.update(os.environ)
# Function to provide to C++ so it can look up instances based on paths
def resolveSimObject(name):
obj = config.instanceDict[name]
if not obj._ccObject:
obj.createCCObject()
if obj._ccObject == -1:
panic("resolveSimObject: recursive lookup error on %s" % name)
return obj._ccObject
return obj.getCCObject()
# The final hook to generate .ini files. Called from the user script
# once the config is built.

View file

@ -1,4 +1,4 @@
# Copyright (c) 2004-2005 The Regents of The University of Michigan
# Copyright (c) 2004-2006 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -27,7 +27,7 @@
# Authors: Steve Reinhardt
# Nathan Binkert
import os, re, sys, types, inspect
import os, re, sys, types, inspect, copy
import m5
from m5 import panic
@ -84,69 +84,22 @@ class Singleton(type):
#
# Once a set of Python objects have been instantiated in a hierarchy,
# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
# will generate a .ini file. See simple-4cpu.py for an example
# (corresponding to m5-test/simple-4cpu.ini).
# will generate a .ini file.
#
#####################################################################
#####################################################################
#
# ConfigNode/SimObject classes
#
# The Python class hierarchy rooted by ConfigNode (which is the base
# class of SimObject, which in turn is the base class of all other M5
# SimObject classes) has special attribute behavior. In general, an
# object in this hierarchy has three categories of attribute-like
# things:
#
# 1. Regular Python methods and variables. These must start with an
# underscore to be treated normally.
#
# 2. SimObject parameters. These values are stored as normal Python
# attributes, but all assignments to these attributes are checked
# against the pre-defined set of parameters stored in the class's
# _params dictionary. Assignments to attributes that do not
# correspond to predefined parameters, or that are not of the correct
# type, incur runtime errors.
#
# 3. Hierarchy children. The child nodes of a ConfigNode are stored
# in the node's _children dictionary, but can be accessed using the
# Python attribute dot-notation (just as they are printed out by the
# simulator). Children cannot be created using attribute assigment;
# they must be added by specifying the parent node in the child's
# constructor or using the '+=' operator.
# The SimObject parameters are the most complex, for a few reasons.
# First, both parameter descriptions and parameter values are
# inherited. Thus parameter description lookup must go up the
# inheritance chain like normal attribute lookup, but this behavior
# must be explicitly coded since the lookup occurs in each class's
# _params attribute. Second, because parameter values can be set
# on SimObject classes (to implement default values), the parameter
# checking behavior must be enforced on class attribute assignments as
# well as instance attribute assignments. Finally, because we allow
# class specialization via inheritance (e.g., see the L1Cache class in
# the simple-4cpu.py example), we must do parameter checking even on
# class instantiation. To provide all these features, we use a
# metaclass to define most of the SimObject parameter behavior for
# this class hierarchy.
#
#####################################################################
# dict to look up SimObjects based on path
instanceDict = {}
#############################
#
# Utility methods
#
#############################
def isSimObject(value):
return isinstance(value, SimObject)
def isSimObjectClass(value):
try:
return issubclass(value, SimObject)
except TypeError:
# happens if value is not a class at all
return False
def isSimObjectSequence(value):
if not isinstance(value, (list, tuple)) or len(value) == 0:
return False
@ -157,22 +110,9 @@ def isSimObjectSequence(value):
return True
def isSimObjectClassSequence(value):
if not isinstance(value, (list, tuple)) or len(value) == 0:
return False
for val in value:
if not isNullPointer(val) and not isSimObjectClass(val):
return False
return True
def isSimObjectOrSequence(value):
return isSimObject(value) or isSimObjectSequence(value)
def isSimObjectClassOrSequence(value):
return isSimObjectClass(value) or isSimObjectClassSequence(value)
def isNullPointer(value):
return isinstance(value, NullSimObject)
@ -192,41 +132,36 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs):
return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq]
# The metaclass for ConfigNode (and thus for everything that derives
# from ConfigNode, including SimObject). This class controls how new
# classes that derive from ConfigNode are instantiated, and provides
# inherited class behavior (just like a class controls how instances
# of that class are instantiated, and provides inherited instance
# behavior).
# The metaclass for SimObject. This class controls how new classes
# that derive from SimObject are instantiated, and provides inherited
# class behavior (just like a class controls how instances of that
# class are instantiated, and provides inherited instance behavior).
class MetaSimObject(type):
# Attributes that can be set only at initialization time
init_keywords = { 'abstract' : types.BooleanType,
'type' : types.StringType }
# Attributes that can be set any time
keywords = { 'check' : types.FunctionType,
'children' : types.ListType,
'ccObject' : types.ObjectType }
keywords = { 'check' : types.FunctionType }
# __new__ is called before __init__, and is where the statements
# in the body of the class definition get loaded into the class's
# __dict__. We intercept this to filter out parameter assignments
# __dict__. We intercept this to filter out parameter & port assignments
# and only allow "private" attributes to be passed to the base
# __new__ (starting with underscore).
def __new__(mcls, name, bases, dict):
if dict.has_key('_init_dict'):
# must have been called from makeSubclass() rather than
# via Python class declaration; bypass filtering process.
cls_dict = dict
else:
# Copy "private" attributes (including special methods
# such as __new__) to the official dict. Everything else
# goes in _init_dict to be filtered in __init__.
cls_dict = {}
for key,val in dict.items():
if key.startswith('_'):
cls_dict[key] = val
del dict[key]
cls_dict['_init_dict'] = dict
# Copy "private" attributes, functions, and classes to the
# official dict. Everything else goes in _init_dict to be
# filtered in __init__.
cls_dict = {}
value_dict = {}
for key,val in dict.items():
if key.startswith('_') or isinstance(val, (types.FunctionType,
types.TypeType)):
cls_dict[key] = val
else:
# must be a param/port setting
value_dict[key] = val
cls_dict['_value_dict'] = value_dict
return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
# subclass initialization
@ -236,11 +171,15 @@ class MetaSimObject(type):
super(MetaSimObject, cls).__init__(name, bases, dict)
# initialize required attributes
cls._params = multidict()
cls._values = multidict()
cls._ports = multidict()
cls._instantiated = False # really instantiated or subclassed
cls._anon_subclass_counter = 0
# class-only attributes
cls._params = multidict() # param descriptions
cls._ports = multidict() # port descriptions
# class or instance attributes
cls._values = multidict() # param values
cls._port_map = multidict() # port bindings
cls._instantiated = False # really instantiated, cloned, or subclassed
# We don't support multiple inheritance. If you want to, you
# must fix multidict to deal with it properly.
@ -249,21 +188,28 @@ class MetaSimObject(type):
base = bases[0]
# the only time the following is not true is when we define
# the SimObject class itself
# Set up general inheritance via multidicts. A subclass will
# inherit all its settings from the base class. The only time
# the following is not true is when we define the SimObject
# class itself (in which case the multidicts have no parent).
if isinstance(base, MetaSimObject):
cls._params.parent = base._params
cls._values.parent = base._values
cls._ports.parent = base._ports
cls._values.parent = base._values
cls._port_map.parent = base._port_map
# mark base as having been subclassed
base._instantiated = True
# now process the _init_dict items
for key,val in cls._init_dict.items():
if isinstance(val, (types.FunctionType, types.TypeType)):
type.__setattr__(cls, key, val)
# Now process the _value_dict items. They could be defining
# new (or overriding existing) parameters or ports, setting
# class keywords (e.g., 'abstract'), or setting parameter
# values or port bindings. The first 3 can only be set when
# the class is defined, so we handle them here. The others
# can be set later too, so just emulate that by calling
# setattr().
for key,val in cls._value_dict.items():
# param descriptions
elif isinstance(val, ParamDesc):
if isinstance(val, ParamDesc):
cls._new_param(key, val)
# port objects
@ -278,27 +224,6 @@ class MetaSimObject(type):
else:
setattr(cls, key, val)
# Pull the deep-copy memoization dict out of the class dict if
# it's there...
memo = cls.__dict__.get('_memo', {})
# Handle SimObject values
for key,val in cls._values.iteritems():
# SimObject instances need to be promoted to classes.
# Existing classes should not have any instance values, so
# these can only occur at the lowest level dict (the
# parameters just being set in this class definition).
if isSimObjectOrSequence(val):
assert(val == cls._values.local[key])
cls._values[key] = applyOrMap(val, 'makeClass', memo)
# SimObject classes need to be subclassed so that
# parameters that get set at this level only affect this
# level and derivatives.
elif isSimObjectClassOrSequence(val):
assert(not cls._values.local.has_key(key))
cls._values[key] = applyOrMap(val, 'makeSubclass', {}, memo)
def _set_keyword(cls, keyword, val, kwtype):
if not isinstance(val, kwtype):
raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
@ -328,15 +253,15 @@ class MetaSimObject(type):
self._ports[attr].connect(self, attr, value)
return
# must be SimObject param
param = cls._params.get(attr, None)
if param:
# It's ok: set attribute by delegating to 'object' class.
if isSimObjectOrSequence(value) and cls._instantiated:
raise AttributeError, \
"Cannot set SimObject parameter '%s' after\n" \
if isSimObjectOrSequence(value) and cls._instantiated:
raise RuntimeError, \
"cannot set SimObject parameter '%s' after\n" \
" class %s has been instantiated or subclassed" \
% (attr, cls.__name__)
# check for param
param = cls._params.get(attr, None)
if param:
try:
cls._values[attr] = param.convert(value)
except Exception, e:
@ -344,9 +269,9 @@ class MetaSimObject(type):
(e, cls.__name__, attr, value)
e.args = (msg, )
raise
# I would love to get rid of this
elif isSimObjectOrSequence(value):
cls._values[attr] = value
# if RHS is a SimObject, it's an implicit child assignment
cls._values[attr] = value
else:
raise AttributeError, \
"Class %s has no parameter %s" % (cls.__name__, attr)
@ -358,23 +283,7 @@ class MetaSimObject(type):
raise AttributeError, \
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
# Create a subclass of this class. Basically a function interface
# to the standard Python class definition mechanism, primarily for
# internal use. 'memo' dict param supports "deep copy" (really
# "deep subclass") operations... within a given operation,
# multiple references to a class should result in a single
# subclass object with multiple references to it (as opposed to
# mutiple unique subclasses).
def makeSubclass(cls, init_dict, memo = {}):
subcls = memo.get(cls)
if not subcls:
name = cls.__name__ + '_' + str(cls._anon_subclass_counter)
cls._anon_subclass_counter += 1
subcls = MetaSimObject(name, (cls,),
{ '_init_dict': init_dict, '_memo': memo })
return subcls
# The ConfigNode class is the root of the special hierarchy. Most of
# The SimObject class is the root of the special hierarchy. Most of
# the code in this class deals with the configuration hierarchy itself
# (parent/child node relationships).
class SimObject(object):
@ -382,83 +291,72 @@ class SimObject(object):
# get this metaclass.
__metaclass__ = MetaSimObject
# __new__ operator allocates new instances of the class. We
# override it here just to support "deep instantiation" operation
# via the _memo dict. When recursively instantiating an object
# hierarchy we want to make sure that each class is instantiated
# only once, and that if there are multiple references to the same
# original class, we end up with the corresponding instantiated
# references all pointing to the same instance.
def __new__(cls, _memo = None, **kwargs):
if _memo is not None and _memo.has_key(cls):
# return previously instantiated object
assert(len(kwargs) == 0)
return _memo[cls]
else:
# Need a new one... if it needs to be memoized, this will
# happen in __init__. We defer the insertion until then
# so __init__ can use the memo dict to tell whether or not
# to perform the initialization.
return super(SimObject, cls).__new__(cls, **kwargs)
# Initialize new instance. For objects with SimObject-valued
# children, we need to recursively clone the classes represented
# by those param values as well in a consistent "deep copy"-style
# fashion. That is, we want to make sure that each instance is
# cloned only once, and that if there are multiple references to
# the same original object, we end up with the corresponding
# cloned references all pointing to the same cloned instance.
def __init__(self, **kwargs):
ancestor = kwargs.get('_ancestor')
memo_dict = kwargs.get('_memo')
if memo_dict is None:
# prepare to memoize any recursively instantiated objects
memo_dict = {}
elif ancestor:
# memoize me now to avoid problems with recursive calls
memo_dict[ancestor] = self
# Initialize new instance previously allocated by __new__. For
# objects with SimObject-valued params, we need to recursively
# instantiate the classes represented by those param values as
# well (in a consistent "deep copy"-style fashion; see comment
# above).
def __init__(self, _memo = None, **kwargs):
if _memo is not None:
# We're inside a "deep instantiation"
assert(isinstance(_memo, dict))
assert(len(kwargs) == 0)
if _memo.has_key(self.__class__):
# __new__ returned an existing, already initialized
# instance, so there's nothing to do here
assert(_memo[self.__class__] == self)
return
# no pre-existing object, so remember this one here
_memo[self.__class__] = self
else:
# This is a new top-level instantiation... don't memoize
# this objcet, but prepare to memoize any recursively
# instantiated objects.
_memo = {}
self.__class__._instantiated = True
if not ancestor:
ancestor = self.__class__
ancestor._instantiated = True
# initialize required attributes
self._parent = None
self._children = {}
self._ccObject = None # pointer to C++ object
self._instantiated = False # really "cloned"
# Inherit parameter values from class using multidict so
# individual value settings can be overridden.
self._values = multidict(self.__class__._values)
# For SimObject-valued parameters, the class should have
# classes (not instances) for the values. We need to
# instantiate these classes rather than just inheriting the
# class object.
for key,val in self.__class__._values.iteritems():
if isSimObjectClass(val):
setattr(self, key, val(_memo))
elif isSimObjectClassSequence(val) and len(val):
setattr(self, key, [ v(_memo) for v in val ])
self._values = multidict(ancestor._values)
# clone SimObject-valued parameters
for key,val in ancestor._values.iteritems():
if isSimObject(val):
setattr(self, key, val(_memo=memo_dict))
elif isSimObjectSequence(val) and len(val):
setattr(self, key, [ v(_memo=memo_dict) for v in val ])
# clone port references. no need to use a multidict here
# since we will be creating new references for all ports.
self._port_map = {}
for key,val in ancestor._port_map.iteritems():
self._port_map[key] = applyOrMap(val, 'clone', memo_dict)
# apply attribute assignments from keyword args, if any
for key,val in kwargs.iteritems():
setattr(self, key, val)
self._ccObject = None # pointer to C++ object
self._port_map = {} # map of port connections
# Use this instance as a template to create a new class.
def makeClass(self, memo = {}):
cls = memo.get(self)
if not cls:
cls = self.__class__.makeSubclass(self._values.local)
memo[self] = cls
return cls
# Direct instantiation of instances (cloning) is no longer
# allowed; must generate class from instance first.
# "Clone" the current instance by creating another instance of
# this instance's class, but that inherits its parameter values
# and port mappings from the current instance. If we're in a
# "deep copy" recursive clone, check the _memo dict to see if
# we've already cloned this instance.
def __call__(self, **kwargs):
raise TypeError, "cannot instantiate SimObject; "\
"use makeClass() to make class first"
memo_dict = kwargs.get('_memo')
if memo_dict is None:
# no memo_dict: must be top-level clone operation.
# this is only allowed at the root of a hierarchy
if self._parent:
raise RuntimeError, "attempt to clone object %s " \
"not at the root of a tree (parent = %s)" \
% (self, self._parent)
# create a new dict and use that.
memo_dict = {}
kwargs['_memo'] = memo_dict
elif memo_dict.has_key(self):
# clone already done & memoized
return memo_dict[self]
return self.__class__(_ancestor = self, **kwargs)
def __getattr__(self, attr):
if self._ports.has_key(attr):
@ -485,10 +383,14 @@ class SimObject(object):
self._ports[attr].connect(self, attr, value)
return
if isSimObjectOrSequence(value) and self._instantiated:
raise RuntimeError, \
"cannot set SimObject parameter '%s' after\n" \
" instance been cloned %s" % (attr, `self`)
# must be SimObject param
param = self._params.get(attr, None)
if param:
# It's ok: set attribute by delegating to 'object' class.
try:
value = param.convert(value)
except Exception, e:
@ -496,7 +398,6 @@ class SimObject(object):
(e, self.__class__.__name__, attr, value)
e.args = (msg, )
raise
# I would love to get rid of this
elif isSimObjectOrSequence(value):
pass
else:
@ -535,13 +436,13 @@ class SimObject(object):
self._children[name] = value
def set_path(self, parent, name):
if not hasattr(self, '_parent'):
if not self._parent:
self._parent = parent
self._name = name
parent.add_child(name, self)
def path(self):
if not hasattr(self, '_parent'):
if not self._parent:
return 'root'
ppath = self._parent.path()
if ppath == 'root':
@ -618,13 +519,22 @@ class SimObject(object):
# Call C++ to create C++ object corresponding to this object and
# (recursively) all its children
def createCCObject(self):
if self._ccObject:
return
self._ccObject = -1
self._ccObject = m5.main.createSimObject(self.path())
self.getCCObject() # force creation
for child in self._children.itervalues():
child.createCCObject()
# Get C++ object corresponding to this object, calling C++ if
# necessary to construct it. Does *not* recursively create
# children.
def getCCObject(self):
if not self._ccObject:
self._ccObject = -1 # flag to catch cycles in recursion
self._ccObject = m5.main.createSimObject(self.path())
elif self._ccObject == -1:
raise RuntimeError, "%s: recursive call to getCCObject()" \
% self.path()
return self._ccObject
# Create C++ port connections corresponding to the connections in
# _port_map (& recursively for all children)
def connectPorts(self):
@ -723,9 +633,9 @@ class BaseProxy(object):
if self._search_up:
while not done:
try: obj = obj._parent
except: break
obj = obj._parent
if not obj:
break
result, done = self.find(obj)
if not done:
@ -841,16 +751,16 @@ Self = ProxyFactory(search_self = True, search_up = False)
#
# Parameter description classes
#
# The _params dictionary in each class maps parameter names to
# either a Param or a VectorParam object. These objects contain the
# The _params dictionary in each class maps parameter names to either
# a Param or a VectorParam object. These objects contain the
# parameter description string, the parameter type, and the default
# value (loaded from the PARAM section of the .odesc files). The
# _convert() method on these objects is used to force whatever value
# is assigned to the parameter to the appropriate type.
# value (if any). The convert() method on these objects is used to
# force whatever value is assigned to the parameter to the appropriate
# type.
#
# Note that the default values are loaded into the class's attribute
# space when the parameter dictionary is initialized (in
# MetaConfigNode._setparams()); after that point they aren't used.
# MetaSimObject._new_param()); after that point they aren't used.
#
#####################################################################
@ -1480,6 +1390,7 @@ AllMemory = AddrRange(0, MaxAddr)
# particular SimObject.
class PortRef(object):
def __init__(self, simobj, name, isVec):
assert(isSimObject(simobj))
self.simobj = simobj
self.name = name
self.index = -1
@ -1502,13 +1413,38 @@ class PortRef(object):
self.simobj._port_map[self.name] = curMap
self.peer = other
def clone(self, memo):
newRef = copy.copy(self)
assert(isSimObject(newRef.simobj))
newRef.simobj = newRef.simobj(_memo=memo)
# Tricky: if I'm the *second* PortRef in the pair to be
# cloned, then my peer is still in the middle of its clone
# method, and thus hasn't returned to its owner's
# SimObject.__init__ to get installed in _port_map. As a
# result I have no way of finding the *new* peer object. So I
# mark myself as "waiting" for my peer, and I let the *first*
# PortRef clone call set up both peer pointers after I return.
newPeer = newRef.simobj._port_map.get(self.name)
if newPeer:
if self.isVec:
assert(self.index != -1)
newPeer = newPeer[self.index]
# other guy is all set up except for his peer pointer
assert(newPeer.peer == -1) # peer must be waiting for handshake
newPeer.peer = newRef
newRef.peer = newPeer
else:
# other guy is in clone; just wait for him to do the work
newRef.peer = -1 # mark as waiting for handshake
return newRef
# Call C++ to create corresponding port connection between C++ objects
def ccConnect(self):
if self.ccConnected: # already done this
return
peer = self.peer
m5.main.connectPorts(self.simobj._ccObject, self.name, self.index,
peer.simobj._ccObject, peer.name, peer.index)
m5.main.connectPorts(self.simobj.getCCObject(), self.name, self.index,
peer.simobj.getCCObject(), peer.name, peer.index)
self.ccConnected = True
peer.ccConnected = True
@ -1528,6 +1464,9 @@ class Port(object):
# Connect an instance of this port (on the given SimObject with
# the given name) with the port described by the supplied PortRef
def connect(self, simobj, name, ref):
if not isinstance(ref, PortRef):
raise TypeError, \
"assigning non-port reference port '%s'" % name
myRef = self.makeRef(simobj, name)
myRef.setPeer(ref)
ref.setPeer(myRef)

View file

@ -3,6 +3,8 @@ from MemObject import MemObject
class Bridge(MemObject):
type = 'Bridge'
side_a = Port('Side A port')
side_b = Port('Side B port')
queue_size_a = Param.Int(16, "The number of requests to buffer")
queue_size_b = Param.Int(16, "The number of requests to buffer")
delay = Param.Latency('0ns', "The latency of this bridge")

View file

@ -4,6 +4,7 @@ from MemObject import MemObject
class PioDevice(MemObject):
type = 'PioDevice'
abstract = True
pio = Port("Programmed I/O port")
platform = Param.Platform(Parent.any, "Platform this device is part of")
system = Param.System(Parent.any, "System this device is part of")
@ -16,3 +17,4 @@ class BasicPioDevice(PioDevice):
class DmaDevice(PioDevice):
type = 'DmaDevice'
abstract = True
dma = Port("DMA port")