2006-09-04 19:52:26 +02:00
|
|
|
# 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
|
|
|
|
# modification, are permitted provided that the following conditions are
|
|
|
|
# met: redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer;
|
|
|
|
# redistributions in binary form must reproduce the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
|
|
# documentation and/or other materials provided with the distribution;
|
|
|
|
# neither the name of the copyright holders nor the names of its
|
|
|
|
# contributors may be used to endorse or promote products derived from
|
|
|
|
# this software without specific prior written permission.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#
|
|
|
|
# Authors: Steve Reinhardt
|
|
|
|
# Nathan Binkert
|
|
|
|
|
|
|
|
#####################################################################
|
|
|
|
#
|
|
|
|
# Parameter description classes
|
|
|
|
#
|
|
|
|
# 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 (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
|
|
|
|
# MetaSimObject._new_param()); after that point they aren't used.
|
|
|
|
#
|
|
|
|
#####################################################################
|
|
|
|
|
2007-01-03 19:12:55 +01:00
|
|
|
import copy
|
|
|
|
import datetime
|
|
|
|
import inspect
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
import convert
|
2006-09-05 02:14:07 +02:00
|
|
|
from util import *
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
# Dummy base class to identify types that are legitimate for SimObject
|
|
|
|
# parameters.
|
|
|
|
class ParamValue(object):
|
|
|
|
|
|
|
|
cxx_predecls = []
|
|
|
|
swig_predecls = []
|
|
|
|
|
|
|
|
# default for printing to .ini file is regular string conversion.
|
|
|
|
# will be overridden in some cases
|
|
|
|
def ini_str(self):
|
|
|
|
return str(self)
|
|
|
|
|
|
|
|
# allows us to blithely call unproxy() on things without checking
|
|
|
|
# if they're really proxies or not
|
|
|
|
def unproxy(self, base):
|
|
|
|
return self
|
|
|
|
|
|
|
|
# Regular parameter description.
|
|
|
|
class ParamDesc(object):
|
|
|
|
def __init__(self, ptype_str, ptype, *args, **kwargs):
|
|
|
|
self.ptype_str = ptype_str
|
|
|
|
# remember ptype only if it is provided
|
|
|
|
if ptype != None:
|
|
|
|
self.ptype = ptype
|
|
|
|
|
|
|
|
if args:
|
|
|
|
if len(args) == 1:
|
|
|
|
self.desc = args[0]
|
|
|
|
elif len(args) == 2:
|
|
|
|
self.default = args[0]
|
|
|
|
self.desc = args[1]
|
|
|
|
else:
|
|
|
|
raise TypeError, 'too many arguments'
|
|
|
|
|
|
|
|
if kwargs.has_key('desc'):
|
|
|
|
assert(not hasattr(self, 'desc'))
|
|
|
|
self.desc = kwargs['desc']
|
|
|
|
del kwargs['desc']
|
|
|
|
|
|
|
|
if kwargs.has_key('default'):
|
|
|
|
assert(not hasattr(self, 'default'))
|
|
|
|
self.default = kwargs['default']
|
|
|
|
del kwargs['default']
|
|
|
|
|
|
|
|
if kwargs:
|
|
|
|
raise TypeError, 'extra unknown kwargs %s' % kwargs
|
|
|
|
|
|
|
|
if not hasattr(self, 'desc'):
|
|
|
|
raise TypeError, 'desc attribute missing'
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr == 'ptype':
|
|
|
|
try:
|
2006-09-05 02:14:07 +02:00
|
|
|
ptype = eval(self.ptype_str, objects.__dict__)
|
2006-09-04 19:52:26 +02:00
|
|
|
if not isinstance(ptype, type):
|
2006-09-05 02:14:07 +02:00
|
|
|
raise NameError
|
2006-09-04 19:52:26 +02:00
|
|
|
self.ptype = ptype
|
|
|
|
return ptype
|
|
|
|
except NameError:
|
2006-09-05 02:14:07 +02:00
|
|
|
raise TypeError, \
|
|
|
|
"Param qualifier '%s' is not a type" % self.ptype_str
|
2006-09-04 19:52:26 +02:00
|
|
|
raise AttributeError, "'%s' object has no attribute '%s'" % \
|
|
|
|
(type(self).__name__, attr)
|
|
|
|
|
|
|
|
def convert(self, value):
|
|
|
|
if isinstance(value, proxy.BaseProxy):
|
|
|
|
value.set_param_desc(self)
|
|
|
|
return value
|
|
|
|
if not hasattr(self, 'ptype') and isNullPointer(value):
|
|
|
|
# deferred evaluation of SimObject; continue to defer if
|
|
|
|
# we're just assigning a null pointer
|
|
|
|
return value
|
|
|
|
if isinstance(value, self.ptype):
|
|
|
|
return value
|
2006-09-05 02:14:07 +02:00
|
|
|
if isNullPointer(value) and isSimObjectClass(self.ptype):
|
2006-09-04 19:52:26 +02:00
|
|
|
return value
|
|
|
|
return self.ptype(value)
|
|
|
|
|
|
|
|
def cxx_predecls(self):
|
|
|
|
return self.ptype.cxx_predecls
|
|
|
|
|
|
|
|
def swig_predecls(self):
|
|
|
|
return self.ptype.swig_predecls
|
|
|
|
|
|
|
|
def cxx_decl(self):
|
|
|
|
return '%s %s;' % (self.ptype.cxx_type, self.name)
|
|
|
|
|
|
|
|
# Vector-valued parameter description. Just like ParamDesc, except
|
|
|
|
# that the value is a vector (list) of the specified type instead of a
|
|
|
|
# single value.
|
|
|
|
|
|
|
|
class VectorParamValue(list):
|
|
|
|
def ini_str(self):
|
|
|
|
return ' '.join([v.ini_str() for v in self])
|
|
|
|
|
|
|
|
def unproxy(self, base):
|
|
|
|
return [v.unproxy(base) for v in self]
|
|
|
|
|
|
|
|
class SimObjVector(VectorParamValue):
|
|
|
|
def print_ini(self):
|
|
|
|
for v in self:
|
|
|
|
v.print_ini()
|
|
|
|
|
|
|
|
class VectorParamDesc(ParamDesc):
|
|
|
|
# Convert assigned value to appropriate type. If the RHS is not a
|
|
|
|
# list or tuple, it generates a single-element list.
|
|
|
|
def convert(self, value):
|
|
|
|
if isinstance(value, (list, tuple)):
|
|
|
|
# list: coerce each element into new list
|
|
|
|
tmp_list = [ ParamDesc.convert(self, v) for v in value ]
|
|
|
|
if isSimObjectSequence(tmp_list):
|
|
|
|
return SimObjVector(tmp_list)
|
|
|
|
else:
|
|
|
|
return VectorParamValue(tmp_list)
|
|
|
|
else:
|
|
|
|
# singleton: leave it be (could coerce to a single-element
|
|
|
|
# list here, but for some historical reason we don't...
|
|
|
|
return ParamDesc.convert(self, value)
|
|
|
|
|
|
|
|
def cxx_predecls(self):
|
|
|
|
return ['#include <vector>'] + self.ptype.cxx_predecls
|
|
|
|
|
|
|
|
def swig_predecls(self):
|
|
|
|
return ['%include "std_vector.i"'] + self.ptype.swig_predecls
|
|
|
|
|
|
|
|
def cxx_decl(self):
|
|
|
|
return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
|
|
|
|
|
|
|
|
class ParamFactory(object):
|
|
|
|
def __init__(self, param_desc_class, ptype_str = None):
|
|
|
|
self.param_desc_class = param_desc_class
|
|
|
|
self.ptype_str = ptype_str
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if self.ptype_str:
|
|
|
|
attr = self.ptype_str + '.' + attr
|
|
|
|
return ParamFactory(self.param_desc_class, attr)
|
|
|
|
|
|
|
|
# E.g., Param.Int(5, "number of widgets")
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
|
|
caller_frame = inspect.currentframe().f_back
|
|
|
|
ptype = None
|
|
|
|
try:
|
|
|
|
ptype = eval(self.ptype_str,
|
|
|
|
caller_frame.f_globals, caller_frame.f_locals)
|
|
|
|
if not isinstance(ptype, type):
|
|
|
|
raise TypeError, \
|
|
|
|
"Param qualifier is not a type: %s" % ptype
|
|
|
|
except NameError:
|
|
|
|
# if name isn't defined yet, assume it's a SimObject, and
|
|
|
|
# try to resolve it later
|
|
|
|
pass
|
|
|
|
return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
|
|
|
|
|
|
|
|
Param = ParamFactory(ParamDesc)
|
|
|
|
VectorParam = ParamFactory(VectorParamDesc)
|
|
|
|
|
|
|
|
#####################################################################
|
|
|
|
#
|
|
|
|
# Parameter Types
|
|
|
|
#
|
|
|
|
# Though native Python types could be used to specify parameter types
|
|
|
|
# (the 'ptype' field of the Param and VectorParam classes), it's more
|
|
|
|
# flexible to define our own set of types. This gives us more control
|
|
|
|
# over how Python expressions are converted to values (via the
|
|
|
|
# __init__() constructor) and how these values are printed out (via
|
|
|
|
# the __str__() conversion method).
|
|
|
|
#
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
# String-valued parameter. Just mixin the ParamValue class with the
|
|
|
|
# built-in str class.
|
|
|
|
class String(ParamValue,str):
|
|
|
|
cxx_type = 'std::string'
|
|
|
|
cxx_predecls = ['#include <string>']
|
|
|
|
swig_predecls = ['%include "std_string.i"\n' +
|
|
|
|
'%apply const std::string& {std::string *};']
|
|
|
|
pass
|
|
|
|
|
|
|
|
# superclass for "numeric" parameter values, to emulate math
|
|
|
|
# operations in a type-safe way. e.g., a Latency times an int returns
|
|
|
|
# a new Latency object.
|
|
|
|
class NumericParamValue(ParamValue):
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.value)
|
|
|
|
|
|
|
|
def __float__(self):
|
|
|
|
return float(self.value)
|
|
|
|
|
2006-12-03 07:24:52 +01:00
|
|
|
def __long__(self):
|
|
|
|
return long(self.value)
|
|
|
|
|
|
|
|
def __int__(self):
|
|
|
|
return int(self.value)
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
# hook for bounds checking
|
|
|
|
def _check(self):
|
|
|
|
return
|
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
newobj = self.__class__(self)
|
|
|
|
newobj.value *= other
|
|
|
|
newobj._check()
|
|
|
|
return newobj
|
|
|
|
|
|
|
|
__rmul__ = __mul__
|
|
|
|
|
|
|
|
def __div__(self, other):
|
|
|
|
newobj = self.__class__(self)
|
|
|
|
newobj.value /= other
|
|
|
|
newobj._check()
|
|
|
|
return newobj
|
|
|
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
newobj = self.__class__(self)
|
|
|
|
newobj.value -= other
|
|
|
|
newobj._check()
|
|
|
|
return newobj
|
|
|
|
|
|
|
|
# Metaclass for bounds-checked integer parameters. See CheckedInt.
|
|
|
|
class CheckedIntType(type):
|
|
|
|
def __init__(cls, name, bases, dict):
|
|
|
|
super(CheckedIntType, cls).__init__(name, bases, dict)
|
|
|
|
|
|
|
|
# CheckedInt is an abstract base class, so we actually don't
|
|
|
|
# want to do any processing on it... the rest of this code is
|
|
|
|
# just for classes that derive from CheckedInt.
|
|
|
|
if name == 'CheckedInt':
|
|
|
|
return
|
|
|
|
|
|
|
|
if not cls.cxx_predecls:
|
|
|
|
# most derived types require this, so we just do it here once
|
|
|
|
cls.cxx_predecls = ['#include "sim/host.hh"']
|
|
|
|
|
|
|
|
if not cls.swig_predecls:
|
|
|
|
# most derived types require this, so we just do it here once
|
|
|
|
cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
|
|
|
|
'%import "sim/host.hh"']
|
|
|
|
|
|
|
|
if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
|
|
|
|
if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
|
|
|
|
panic("CheckedInt subclass %s must define either\n" \
|
|
|
|
" 'min' and 'max' or 'size' and 'unsigned'\n" \
|
|
|
|
% name);
|
|
|
|
if cls.unsigned:
|
|
|
|
cls.min = 0
|
|
|
|
cls.max = 2 ** cls.size - 1
|
|
|
|
else:
|
|
|
|
cls.min = -(2 ** (cls.size - 1))
|
|
|
|
cls.max = (2 ** (cls.size - 1)) - 1
|
|
|
|
|
|
|
|
# Abstract superclass for bounds-checked integer parameters. This
|
|
|
|
# class is subclassed to generate parameter classes with specific
|
|
|
|
# bounds. Initialization of the min and max bounds is done in the
|
|
|
|
# metaclass CheckedIntType.__init__.
|
|
|
|
class CheckedInt(NumericParamValue):
|
|
|
|
__metaclass__ = CheckedIntType
|
|
|
|
|
|
|
|
def _check(self):
|
|
|
|
if not self.min <= self.value <= self.max:
|
|
|
|
raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
|
|
|
|
(self.min, self.value, self.max)
|
|
|
|
|
|
|
|
def __init__(self, value):
|
|
|
|
if isinstance(value, str):
|
2006-09-05 02:14:07 +02:00
|
|
|
self.value = convert.toInteger(value)
|
2006-12-03 07:24:52 +01:00
|
|
|
elif isinstance(value, (int, long, float, NumericParamValue)):
|
2006-09-04 19:52:26 +02:00
|
|
|
self.value = long(value)
|
2006-12-03 07:24:52 +01:00
|
|
|
else:
|
|
|
|
raise TypeError, "Can't convert object of type %s to CheckedInt" \
|
|
|
|
% type(value).__name__
|
2006-09-04 19:52:26 +02:00
|
|
|
self._check()
|
|
|
|
|
|
|
|
class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
|
|
|
|
class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
|
|
|
|
|
|
|
|
class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
|
|
|
|
class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
|
|
|
|
class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
|
|
|
|
class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
|
|
|
|
class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
|
|
|
|
class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
|
|
|
|
class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
|
|
|
|
class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
|
|
|
|
|
|
|
|
class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
|
|
|
|
class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
|
|
|
|
class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
|
|
|
|
class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
|
|
|
|
|
|
|
|
class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
|
|
|
|
|
|
|
|
class Float(ParamValue, float):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class MemorySize(CheckedInt):
|
|
|
|
cxx_type = 'uint64_t'
|
|
|
|
size = 64
|
|
|
|
unsigned = True
|
|
|
|
def __init__(self, value):
|
|
|
|
if isinstance(value, MemorySize):
|
|
|
|
self.value = value.value
|
|
|
|
else:
|
2006-09-05 02:14:07 +02:00
|
|
|
self.value = convert.toMemorySize(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
self._check()
|
|
|
|
|
|
|
|
class MemorySize32(CheckedInt):
|
|
|
|
size = 32
|
|
|
|
unsigned = True
|
|
|
|
def __init__(self, value):
|
|
|
|
if isinstance(value, MemorySize):
|
|
|
|
self.value = value.value
|
|
|
|
else:
|
2006-09-05 02:14:07 +02:00
|
|
|
self.value = convert.toMemorySize(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
self._check()
|
|
|
|
|
|
|
|
class Addr(CheckedInt):
|
|
|
|
cxx_type = 'Addr'
|
|
|
|
cxx_predecls = ['#include "targetarch/isa_traits.hh"']
|
|
|
|
size = 64
|
|
|
|
unsigned = True
|
|
|
|
def __init__(self, value):
|
|
|
|
if isinstance(value, Addr):
|
|
|
|
self.value = value.value
|
|
|
|
else:
|
|
|
|
try:
|
2006-09-05 02:14:07 +02:00
|
|
|
self.value = convert.toMemorySize(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
except TypeError:
|
|
|
|
self.value = long(value)
|
|
|
|
self._check()
|
2006-11-10 00:22:46 +01:00
|
|
|
def __add__(self, other):
|
|
|
|
if isinstance(other, Addr):
|
|
|
|
return self.value + other.value
|
|
|
|
else:
|
|
|
|
return self.value + other
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
class MetaRange(type):
|
|
|
|
def __init__(cls, name, bases, dict):
|
|
|
|
super(MetaRange, cls).__init__(name, bases, dict)
|
|
|
|
if name == 'Range':
|
|
|
|
return
|
|
|
|
cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
|
|
|
|
cls.cxx_predecls = \
|
|
|
|
['#include "base/range.hh"'] + cls.type.cxx_predecls
|
|
|
|
|
|
|
|
class Range(ParamValue):
|
|
|
|
__metaclass__ = MetaRange
|
|
|
|
type = Int # default; can be overridden in subclasses
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
def handle_kwargs(self, kwargs):
|
|
|
|
if 'end' in kwargs:
|
|
|
|
self.second = self.type(kwargs.pop('end'))
|
|
|
|
elif 'size' in kwargs:
|
|
|
|
self.second = self.first + self.type(kwargs.pop('size')) - 1
|
|
|
|
else:
|
|
|
|
raise TypeError, "Either end or size must be specified"
|
|
|
|
|
|
|
|
if len(args) == 0:
|
|
|
|
self.first = self.type(kwargs.pop('start'))
|
|
|
|
handle_kwargs(self, kwargs)
|
|
|
|
|
|
|
|
elif len(args) == 1:
|
|
|
|
if kwargs:
|
|
|
|
self.first = self.type(args[0])
|
|
|
|
handle_kwargs(self, kwargs)
|
|
|
|
elif isinstance(args[0], Range):
|
|
|
|
self.first = self.type(args[0].first)
|
|
|
|
self.second = self.type(args[0].second)
|
|
|
|
else:
|
|
|
|
self.first = self.type(0)
|
|
|
|
self.second = self.type(args[0]) - 1
|
|
|
|
|
|
|
|
elif len(args) == 2:
|
|
|
|
self.first = self.type(args[0])
|
|
|
|
self.second = self.type(args[1])
|
|
|
|
else:
|
|
|
|
raise TypeError, "Too many arguments specified"
|
|
|
|
|
|
|
|
if kwargs:
|
|
|
|
raise TypeError, "too many keywords: %s" % kwargs.keys()
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return '%s:%s' % (self.first, self.second)
|
|
|
|
|
|
|
|
class AddrRange(Range):
|
|
|
|
type = Addr
|
|
|
|
|
|
|
|
class TickRange(Range):
|
|
|
|
type = Tick
|
|
|
|
|
|
|
|
# Boolean parameter type. Python doesn't let you subclass bool, since
|
|
|
|
# it doesn't want to let you create multiple instances of True and
|
|
|
|
# False. Thus this is a little more complicated than String.
|
|
|
|
class Bool(ParamValue):
|
|
|
|
cxx_type = 'bool'
|
|
|
|
def __init__(self, value):
|
|
|
|
try:
|
2006-09-05 02:14:07 +02:00
|
|
|
self.value = convert.toBool(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
except TypeError:
|
|
|
|
self.value = bool(value)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.value)
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
if self.value:
|
|
|
|
return 'true'
|
|
|
|
return 'false'
|
|
|
|
|
|
|
|
def IncEthernetAddr(addr, val = 1):
|
|
|
|
bytes = map(lambda x: int(x, 16), addr.split(':'))
|
|
|
|
bytes[5] += val
|
|
|
|
for i in (5, 4, 3, 2, 1):
|
|
|
|
val,rem = divmod(bytes[i], 256)
|
|
|
|
bytes[i] = rem
|
|
|
|
if val == 0:
|
|
|
|
break
|
|
|
|
bytes[i - 1] += val
|
|
|
|
assert(bytes[0] <= 255)
|
|
|
|
return ':'.join(map(lambda x: '%02x' % x, bytes))
|
|
|
|
|
|
|
|
class NextEthernetAddr(object):
|
|
|
|
addr = "00:90:00:00:00:01"
|
|
|
|
|
|
|
|
def __init__(self, inc = 1):
|
|
|
|
self.value = NextEthernetAddr.addr
|
|
|
|
NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc)
|
|
|
|
|
|
|
|
class EthernetAddr(ParamValue):
|
|
|
|
cxx_type = 'Net::EthAddr'
|
|
|
|
cxx_predecls = ['#include "base/inet.hh"']
|
|
|
|
swig_predecls = ['class Net::EthAddr;']
|
|
|
|
def __init__(self, value):
|
|
|
|
if value == NextEthernetAddr:
|
|
|
|
self.value = value
|
|
|
|
return
|
|
|
|
|
|
|
|
if not isinstance(value, str):
|
|
|
|
raise TypeError, "expected an ethernet address and didn't get one"
|
|
|
|
|
|
|
|
bytes = value.split(':')
|
|
|
|
if len(bytes) != 6:
|
|
|
|
raise TypeError, 'invalid ethernet address %s' % value
|
|
|
|
|
|
|
|
for byte in bytes:
|
|
|
|
if not 0 <= int(byte) <= 256:
|
|
|
|
raise TypeError, 'invalid ethernet address %s' % value
|
|
|
|
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def unproxy(self, base):
|
|
|
|
if self.value == NextEthernetAddr:
|
|
|
|
self.addr = self.value().value
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
if self.value == NextEthernetAddr:
|
|
|
|
if hasattr(self, 'addr'):
|
|
|
|
return self.addr
|
|
|
|
else:
|
|
|
|
return "NextEthernetAddr (unresolved)"
|
|
|
|
else:
|
|
|
|
return self.value
|
|
|
|
|
2007-01-03 19:12:55 +01:00
|
|
|
def parse_time(value):
|
|
|
|
strings = [ "%a %b %d %H:%M:%S %Z %Y",
|
|
|
|
"%a %b %d %H:%M:%S %Z %Y",
|
|
|
|
"%Y/%m/%d %H:%M:%S",
|
|
|
|
"%Y/%m/%d %H:%M",
|
|
|
|
"%Y/%m/%d",
|
|
|
|
"%m/%d/%Y %H:%M:%S",
|
|
|
|
"%m/%d/%Y %H:%M",
|
|
|
|
"%m/%d/%Y",
|
|
|
|
"%m/%d/%y %H:%M:%S",
|
|
|
|
"%m/%d/%y %H:%M",
|
|
|
|
"%m/%d/%y"]
|
|
|
|
|
|
|
|
for string in strings:
|
|
|
|
try:
|
|
|
|
return time.strptime(value, string)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
raise ValueError, "Could not parse '%s' as a time" % value
|
|
|
|
|
|
|
|
class Time(ParamValue):
|
|
|
|
cxx_type = 'time_t'
|
|
|
|
def __init__(self, value):
|
|
|
|
if isinstance(value, time.struct_time):
|
|
|
|
self.value = time.mktime(value)
|
|
|
|
elif isinstance(value, int):
|
|
|
|
self.value = value
|
|
|
|
elif isinstance(value, str):
|
|
|
|
if value in ('Now', 'Today'):
|
|
|
|
self.value = time.time()
|
|
|
|
else:
|
|
|
|
self.value = time.mktime(parse_time(value))
|
|
|
|
elif isinstance(value, (datetime.datetime, datetime.date)):
|
|
|
|
self.value = time.mktime(value.timetuple())
|
|
|
|
else:
|
|
|
|
raise ValueError, "Could not parse '%s' as a time" % value
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(int(self.value))
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return str(int(self.value))
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
# Enumerated types are a little more complex. The user specifies the
|
|
|
|
# type as Enum(foo) where foo is either a list or dictionary of
|
|
|
|
# alternatives (typically strings, but not necessarily so). (In the
|
|
|
|
# long run, the integer value of the parameter will be the list index
|
|
|
|
# or the corresponding dictionary value. For now, since we only check
|
|
|
|
# that the alternative is valid and then spit it into a .ini file,
|
|
|
|
# there's not much point in using the dictionary.)
|
|
|
|
|
|
|
|
# What Enum() must do is generate a new type encapsulating the
|
|
|
|
# provided list/dictionary so that specific values of the parameter
|
|
|
|
# can be instances of that type. We define two hidden internal
|
|
|
|
# classes (_ListEnum and _DictEnum) to serve as base classes, then
|
|
|
|
# derive the new type from the appropriate base class on the fly.
|
|
|
|
|
|
|
|
|
|
|
|
# Metaclass for Enum types
|
|
|
|
class MetaEnum(type):
|
|
|
|
def __init__(cls, name, bases, init_dict):
|
|
|
|
if init_dict.has_key('map'):
|
|
|
|
if not isinstance(cls.map, dict):
|
|
|
|
raise TypeError, "Enum-derived class attribute 'map' " \
|
|
|
|
"must be of type dict"
|
|
|
|
# build list of value strings from map
|
|
|
|
cls.vals = cls.map.keys()
|
|
|
|
cls.vals.sort()
|
|
|
|
elif init_dict.has_key('vals'):
|
|
|
|
if not isinstance(cls.vals, list):
|
|
|
|
raise TypeError, "Enum-derived class attribute 'vals' " \
|
|
|
|
"must be of type list"
|
|
|
|
# build string->value map from vals sequence
|
|
|
|
cls.map = {}
|
|
|
|
for idx,val in enumerate(cls.vals):
|
|
|
|
cls.map[val] = idx
|
|
|
|
else:
|
|
|
|
raise TypeError, "Enum-derived class must define "\
|
|
|
|
"attribute 'map' or 'vals'"
|
|
|
|
|
|
|
|
cls.cxx_type = name + '::Enum'
|
|
|
|
|
|
|
|
super(MetaEnum, cls).__init__(name, bases, init_dict)
|
|
|
|
|
|
|
|
# Generate C++ class declaration for this enum type.
|
|
|
|
# Note that we wrap the enum in a class/struct to act as a namespace,
|
|
|
|
# so that the enum strings can be brief w/o worrying about collisions.
|
|
|
|
def cxx_decl(cls):
|
|
|
|
s = 'struct %s {\n enum Enum {\n ' % cls.__name__
|
|
|
|
s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
|
|
|
|
s += '\n };\n};\n'
|
|
|
|
return s
|
|
|
|
|
|
|
|
# Base class for enum types.
|
|
|
|
class Enum(ParamValue):
|
|
|
|
__metaclass__ = MetaEnum
|
|
|
|
vals = []
|
|
|
|
|
|
|
|
def __init__(self, value):
|
|
|
|
if value not in self.map:
|
|
|
|
raise TypeError, "Enum param got bad value '%s' (not in %s)" \
|
|
|
|
% (value, self.vals)
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
ticks_per_sec = None
|
|
|
|
|
|
|
|
# how big does a rounding error need to be before we warn about it?
|
|
|
|
frequency_tolerance = 0.001 # 0.1%
|
|
|
|
|
|
|
|
# convert a floting-point # of ticks to integer, and warn if rounding
|
|
|
|
# discards too much precision
|
|
|
|
def tick_check(float_ticks):
|
|
|
|
if float_ticks == 0:
|
|
|
|
return 0
|
|
|
|
int_ticks = int(round(float_ticks))
|
|
|
|
err = (float_ticks - int_ticks) / float_ticks
|
|
|
|
if err > frequency_tolerance:
|
|
|
|
print >> sys.stderr, "Warning: rounding error > tolerance"
|
|
|
|
print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks)
|
|
|
|
#raise ValueError
|
|
|
|
return int_ticks
|
|
|
|
|
|
|
|
def getLatency(value):
|
|
|
|
if isinstance(value, Latency) or isinstance(value, Clock):
|
|
|
|
return value.value
|
|
|
|
elif isinstance(value, Frequency) or isinstance(value, RootClock):
|
|
|
|
return 1 / value.value
|
|
|
|
elif isinstance(value, str):
|
|
|
|
try:
|
2006-09-05 02:14:07 +02:00
|
|
|
return convert.toLatency(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
except ValueError:
|
|
|
|
try:
|
2006-09-05 02:14:07 +02:00
|
|
|
return 1 / convert.toFrequency(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
except ValueError:
|
|
|
|
pass # fall through
|
|
|
|
raise ValueError, "Invalid Frequency/Latency value '%s'" % value
|
|
|
|
|
|
|
|
|
|
|
|
class Latency(NumericParamValue):
|
|
|
|
cxx_type = 'Tick'
|
|
|
|
cxx_predecls = ['#include "sim/host.hh"']
|
|
|
|
swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
|
|
|
|
'%import "sim/host.hh"']
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = getLatency(value)
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr in ('latency', 'period'):
|
|
|
|
return self
|
|
|
|
if attr == 'frequency':
|
|
|
|
return Frequency(self)
|
|
|
|
raise AttributeError, "Latency object has no attribute '%s'" % attr
|
|
|
|
|
|
|
|
# convert latency to ticks
|
|
|
|
def ini_str(self):
|
|
|
|
return str(tick_check(self.value * ticks_per_sec))
|
|
|
|
|
|
|
|
class Frequency(NumericParamValue):
|
|
|
|
cxx_type = 'Tick'
|
|
|
|
cxx_predecls = ['#include "sim/host.hh"']
|
|
|
|
swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
|
|
|
|
'%import "sim/host.hh"']
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = 1 / getLatency(value)
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr == 'frequency':
|
|
|
|
return self
|
|
|
|
if attr in ('latency', 'period'):
|
|
|
|
return Latency(self)
|
|
|
|
raise AttributeError, "Frequency object has no attribute '%s'" % attr
|
|
|
|
|
|
|
|
# convert frequency to ticks per period
|
|
|
|
def ini_str(self):
|
|
|
|
return self.period.ini_str()
|
|
|
|
|
|
|
|
# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
|
|
|
|
# We can't inherit from Frequency because we don't want it to be directly
|
|
|
|
# assignable to a regular Frequency parameter.
|
|
|
|
class RootClock(ParamValue):
|
|
|
|
cxx_type = 'Tick'
|
|
|
|
cxx_predecls = ['#include "sim/host.hh"']
|
|
|
|
swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
|
|
|
|
'%import "sim/host.hh"']
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = 1 / getLatency(value)
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr == 'frequency':
|
|
|
|
return Frequency(self)
|
|
|
|
if attr in ('latency', 'period'):
|
|
|
|
return Latency(self)
|
|
|
|
raise AttributeError, "Frequency object has no attribute '%s'" % attr
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return str(tick_check(self.value))
|
|
|
|
|
|
|
|
# A generic frequency and/or Latency value. Value is stored as a latency,
|
|
|
|
# but to avoid ambiguity this object does not support numeric ops (* or /).
|
|
|
|
# An explicit conversion to a Latency or Frequency must be made first.
|
|
|
|
class Clock(ParamValue):
|
|
|
|
cxx_type = 'Tick'
|
|
|
|
cxx_predecls = ['#include "sim/host.hh"']
|
|
|
|
swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
|
|
|
|
'%import "sim/host.hh"']
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = getLatency(value)
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr == 'frequency':
|
|
|
|
return Frequency(self)
|
|
|
|
if attr in ('latency', 'period'):
|
|
|
|
return Latency(self)
|
|
|
|
raise AttributeError, "Frequency object has no attribute '%s'" % attr
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return self.period.ini_str()
|
|
|
|
|
|
|
|
class NetworkBandwidth(float,ParamValue):
|
|
|
|
cxx_type = 'float'
|
|
|
|
def __new__(cls, value):
|
2006-09-05 02:14:07 +02:00
|
|
|
val = convert.toNetworkBandwidth(value) / 8.0
|
2006-09-04 19:52:26 +02:00
|
|
|
return super(cls, NetworkBandwidth).__new__(cls, val)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.val)
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return '%f' % (ticks_per_sec / float(self))
|
|
|
|
|
|
|
|
class MemoryBandwidth(float,ParamValue):
|
|
|
|
cxx_type = 'float'
|
|
|
|
def __new__(self, value):
|
2006-09-05 02:14:07 +02:00
|
|
|
val = convert.toMemoryBandwidth(value)
|
2006-09-04 19:52:26 +02:00
|
|
|
return super(cls, MemoryBandwidth).__new__(cls, val)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.val)
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return '%f' % (ticks_per_sec / float(self))
|
|
|
|
|
|
|
|
#
|
|
|
|
# "Constants"... handy aliases for various values.
|
|
|
|
#
|
|
|
|
|
2006-09-05 02:14:07 +02:00
|
|
|
# Special class for NULL pointers. Note the special check in
|
|
|
|
# make_param_value() above that lets these be assigned where a
|
|
|
|
# SimObject is required.
|
|
|
|
# only one copy of a particular node
|
|
|
|
class NullSimObject(object):
|
|
|
|
__metaclass__ = Singleton
|
|
|
|
|
|
|
|
def __call__(cls):
|
|
|
|
return cls
|
|
|
|
|
|
|
|
def _instantiate(self, parent = None, path = ''):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def ini_str(self):
|
|
|
|
return 'Null'
|
|
|
|
|
|
|
|
def unproxy(self, base):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def set_path(self, parent, name):
|
|
|
|
pass
|
|
|
|
def __str__(self):
|
|
|
|
return 'Null'
|
|
|
|
|
|
|
|
# The only instance you'll ever need...
|
|
|
|
NULL = NullSimObject()
|
|
|
|
|
|
|
|
def isNullPointer(value):
|
|
|
|
return isinstance(value, NullSimObject)
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
# Some memory range specifications use this as a default upper bound.
|
|
|
|
MaxAddr = Addr.max
|
|
|
|
MaxTick = Tick.max
|
|
|
|
AllMemory = AddrRange(0, MaxAddr)
|
|
|
|
|
|
|
|
|
|
|
|
#####################################################################
|
|
|
|
#
|
|
|
|
# Port objects
|
|
|
|
#
|
|
|
|
# Ports are used to interconnect objects in the memory system.
|
|
|
|
#
|
|
|
|
#####################################################################
|
|
|
|
|
|
|
|
# Port reference: encapsulates a reference to a particular port on a
|
|
|
|
# particular SimObject.
|
|
|
|
class PortRef(object):
|
2006-09-06 07:04:34 +02:00
|
|
|
def __init__(self, simobj, name):
|
|
|
|
assert(isSimObject(simobj) or isSimObjectClass(simobj))
|
2006-09-04 19:52:26 +02:00
|
|
|
self.simobj = simobj
|
|
|
|
self.name = name
|
|
|
|
self.peer = None # not associated with another port yet
|
|
|
|
self.ccConnected = False # C++ port connection done?
|
2006-09-06 07:04:34 +02:00
|
|
|
self.index = -1 # always -1 for non-vector ports
|
2006-09-04 19:52:26 +02:00
|
|
|
|
2006-09-05 21:22:47 +02:00
|
|
|
def __str__(self):
|
2006-09-06 07:04:34 +02:00
|
|
|
return '%s.%s' % (self.simobj, self.name)
|
|
|
|
|
|
|
|
# for config.ini, print peer's name (not ours)
|
|
|
|
def ini_str(self):
|
|
|
|
return str(self.peer)
|
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
if attr == 'peerObj':
|
|
|
|
# shorthand for proxies
|
|
|
|
return self.peer.simobj
|
|
|
|
raise AttributeError, "'%s' object has no attribute '%s'" % \
|
|
|
|
(self.__class__.__name__, attr)
|
|
|
|
|
|
|
|
# Full connection is symmetric (both ways). Called via
|
|
|
|
# SimObject.__setattr__ as a result of a port assignment, e.g.,
|
2006-09-09 01:10:11 +02:00
|
|
|
# "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
|
2006-09-06 07:04:34 +02:00
|
|
|
# e.g., "obj1.portA[3] = obj2.portB".
|
|
|
|
def connect(self, other):
|
|
|
|
if isinstance(other, VectorPortRef):
|
|
|
|
# reference to plain VectorPort is implicit append
|
|
|
|
other = other._get_next()
|
|
|
|
if self.peer and not proxy.isproxy(self.peer):
|
|
|
|
print "warning: overwriting port", self, \
|
|
|
|
"value", self.peer, "with", other
|
2006-09-04 19:52:26 +02:00
|
|
|
self.peer = other
|
2006-09-09 01:10:11 +02:00
|
|
|
if proxy.isproxy(other):
|
|
|
|
other.set_param_desc(PortParamDesc())
|
|
|
|
elif isinstance(other, PortRef):
|
|
|
|
if other.peer is not self:
|
|
|
|
other.connect(self)
|
|
|
|
else:
|
|
|
|
raise TypeError, \
|
|
|
|
"assigning non-port reference '%s' to port '%s'" \
|
|
|
|
% (other, self)
|
2006-09-04 19:52:26 +02:00
|
|
|
|
2006-09-06 07:04:34 +02:00
|
|
|
def clone(self, simobj, memo):
|
|
|
|
if memo.has_key(self):
|
|
|
|
return memo[self]
|
2006-09-04 19:52:26 +02:00
|
|
|
newRef = copy.copy(self)
|
2006-09-06 07:04:34 +02:00
|
|
|
memo[self] = newRef
|
|
|
|
newRef.simobj = simobj
|
2006-09-04 19:52:26 +02:00
|
|
|
assert(isSimObject(newRef.simobj))
|
2006-09-06 07:04:34 +02:00
|
|
|
if self.peer and not proxy.isproxy(self.peer):
|
2006-10-09 03:26:59 +02:00
|
|
|
peerObj = self.peer.simobj(_memo=memo)
|
2006-09-06 07:04:34 +02:00
|
|
|
newRef.peer = self.peer.clone(peerObj, memo)
|
|
|
|
assert(not isinstance(newRef.peer, VectorPortRef))
|
2006-09-04 19:52:26 +02:00
|
|
|
return newRef
|
|
|
|
|
2006-09-06 07:04:34 +02:00
|
|
|
def unproxy(self, simobj):
|
|
|
|
assert(simobj is self.simobj)
|
|
|
|
if proxy.isproxy(self.peer):
|
|
|
|
try:
|
|
|
|
realPeer = self.peer.unproxy(self.simobj)
|
|
|
|
except:
|
|
|
|
print "Error in unproxying port '%s' of %s" % \
|
|
|
|
(self.name, self.simobj.path())
|
|
|
|
raise
|
|
|
|
self.connect(realPeer)
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
# Call C++ to create corresponding port connection between C++ objects
|
|
|
|
def ccConnect(self):
|
|
|
|
if self.ccConnected: # already done this
|
|
|
|
return
|
|
|
|
peer = self.peer
|
2006-11-13 03:49:16 +01:00
|
|
|
internal.main.connectPorts(self.simobj.getCCObject(), self.name,
|
|
|
|
self.index, peer.simobj.getCCObject(),
|
|
|
|
peer.name, peer.index)
|
2006-09-04 19:52:26 +02:00
|
|
|
self.ccConnected = True
|
|
|
|
peer.ccConnected = True
|
|
|
|
|
2006-09-06 07:04:34 +02:00
|
|
|
# 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, index):
|
|
|
|
PortRef.__init__(self, simobj, name)
|
|
|
|
self.index = index
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return '%s.%s[%d]' % (self.simobj, self.name, self.index)
|
|
|
|
|
|
|
|
# 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):
|
|
|
|
assert(isSimObject(simobj) or isSimObjectClass(simobj))
|
|
|
|
self.simobj = simobj
|
|
|
|
self.name = name
|
|
|
|
self.elements = []
|
|
|
|
|
2006-09-09 01:10:11 +02:00
|
|
|
def __str__(self):
|
|
|
|
return '%s.%s[:]' % (self.simobj, self.name)
|
|
|
|
|
2006-09-06 07:04:34 +02:00
|
|
|
# for config.ini, print peer's name (not ours)
|
|
|
|
def ini_str(self):
|
|
|
|
return ' '.join([el.ini_str() for el in self.elements])
|
|
|
|
|
|
|
|
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, i)
|
|
|
|
for i in range(len(self.elements), key+1)]
|
|
|
|
self.elements.extend(ext)
|
|
|
|
return self.elements[key]
|
|
|
|
|
|
|
|
def _get_next(self):
|
|
|
|
return self[len(self.elements)]
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
if not isinstance(key, int):
|
|
|
|
raise TypeError, "VectorPort index must be integer"
|
|
|
|
self[key].connect(value)
|
|
|
|
|
|
|
|
def connect(self, other):
|
2006-09-09 01:10:11 +02:00
|
|
|
if isinstance(other, (list, tuple)):
|
|
|
|
# Assign list of port refs to vector port.
|
|
|
|
# For now, append them... not sure if that's the right semantics
|
|
|
|
# or if it should replace the current vector.
|
|
|
|
for ref in other:
|
|
|
|
self._get_next().connect(ref)
|
|
|
|
else:
|
|
|
|
# scalar assignment to plain VectorPort is implicit append
|
|
|
|
self._get_next().connect(other)
|
|
|
|
|
|
|
|
def clone(self, simobj, memo):
|
|
|
|
if memo.has_key(self):
|
|
|
|
return memo[self]
|
|
|
|
newRef = copy.copy(self)
|
|
|
|
memo[self] = newRef
|
|
|
|
newRef.simobj = simobj
|
|
|
|
assert(isSimObject(newRef.simobj))
|
|
|
|
newRef.elements = [el.clone(simobj, memo) for el in self.elements]
|
|
|
|
return newRef
|
2006-09-06 07:04:34 +02:00
|
|
|
|
|
|
|
def unproxy(self, simobj):
|
|
|
|
[el.unproxy(simobj) for el in self.elements]
|
|
|
|
|
|
|
|
def ccConnect(self):
|
|
|
|
[el.ccConnect() for el in self.elements]
|
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
# Port description object. Like a ParamDesc object, this represents a
|
|
|
|
# logical port in the SimObject class, not a particular port on a
|
|
|
|
# SimObject instance. The latter are represented by PortRef objects.
|
|
|
|
class Port(object):
|
2006-09-06 07:04:34 +02:00
|
|
|
# Port("description") or Port(default, "description")
|
|
|
|
def __init__(self, *args):
|
|
|
|
if len(args) == 1:
|
|
|
|
self.desc = args[0]
|
|
|
|
elif len(args) == 2:
|
|
|
|
self.default = args[0]
|
|
|
|
self.desc = args[1]
|
|
|
|
else:
|
|
|
|
raise TypeError, 'wrong number of arguments'
|
|
|
|
# self.name is set by SimObject class on assignment
|
|
|
|
# e.g., pio_port = Port("blah") sets self.name to 'pio_port'
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
# Generate a PortRef for this port on the given SimObject with the
|
|
|
|
# given name
|
2006-09-06 07:04:34 +02:00
|
|
|
def makeRef(self, simobj):
|
|
|
|
return PortRef(simobj, self.name)
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
# Connect an instance of this port (on the given SimObject with
|
|
|
|
# the given name) with the port described by the supplied PortRef
|
2006-09-06 07:04:34 +02:00
|
|
|
def connect(self, simobj, ref):
|
|
|
|
self.makeRef(simobj).connect(ref)
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
# VectorPort description object. Like Port, but represents a vector
|
|
|
|
# of connections (e.g., as on a Bus).
|
|
|
|
class VectorPort(Port):
|
2006-09-06 07:04:34 +02:00
|
|
|
def __init__(self, *args):
|
|
|
|
Port.__init__(self, *args)
|
2006-09-04 19:52:26 +02:00
|
|
|
self.isVec = True
|
|
|
|
|
2006-09-06 07:04:34 +02:00
|
|
|
def makeRef(self, simobj):
|
|
|
|
return VectorPortRef(simobj, self.name)
|
|
|
|
|
2006-09-09 01:10:11 +02:00
|
|
|
# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
|
|
|
|
# proxy objects (via set_param_desc()) so that proxy error messages
|
|
|
|
# make sense.
|
|
|
|
class PortParamDesc(object):
|
|
|
|
__metaclass__ = Singleton
|
|
|
|
|
|
|
|
ptype_str = 'Port'
|
|
|
|
ptype = Port
|
2006-09-06 07:04:34 +02:00
|
|
|
|
2006-09-04 19:52:26 +02:00
|
|
|
|
|
|
|
__all__ = ['Param', 'VectorParam',
|
|
|
|
'Enum', 'Bool', 'String', 'Float',
|
|
|
|
'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
|
|
|
|
'Int32', 'UInt32', 'Int64', 'UInt64',
|
|
|
|
'Counter', 'Addr', 'Tick', 'Percent',
|
|
|
|
'TcpPort', 'UdpPort', 'EthernetAddr',
|
|
|
|
'MemorySize', 'MemorySize32',
|
|
|
|
'Latency', 'Frequency', 'RootClock', 'Clock',
|
|
|
|
'NetworkBandwidth', 'MemoryBandwidth',
|
|
|
|
'Range', 'AddrRange', 'TickRange',
|
|
|
|
'MaxAddr', 'MaxTick', 'AllMemory',
|
2007-01-03 19:12:55 +01:00
|
|
|
'Time',
|
2006-09-05 02:14:07 +02:00
|
|
|
'NextEthernetAddr', 'NULL',
|
2006-09-04 19:52:26 +02:00
|
|
|
'Port', 'VectorPort']
|
|
|
|
|
|
|
|
# see comment on imports at end of __init__.py.
|
2006-09-05 02:14:07 +02:00
|
|
|
from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass
|
2006-09-04 19:52:26 +02:00
|
|
|
import proxy
|
2006-09-05 02:14:07 +02:00
|
|
|
import objects
|
2006-11-13 03:49:16 +01:00
|
|
|
import internal
|