params.py revision 7673:b28bd1fa9a35
12623SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan 22623SN/A# Copyright (c) 2010 Advanced Micro Devices, Inc. 32623SN/A# All rights reserved. 42623SN/A# 52623SN/A# Redistribution and use in source and binary forms, with or without 62623SN/A# modification, are permitted provided that the following conditions are 72623SN/A# met: redistributions of source code must retain the above copyright 82623SN/A# notice, this list of conditions and the following disclaimer; 92623SN/A# redistributions in binary form must reproduce the above copyright 102623SN/A# notice, this list of conditions and the following disclaimer in the 112623SN/A# documentation and/or other materials provided with the distribution; 122623SN/A# neither the name of the copyright holders nor the names of its 132623SN/A# contributors may be used to endorse or promote products derived from 142623SN/A# this software without specific prior written permission. 152623SN/A# 162623SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172623SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182623SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192623SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202623SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212623SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222623SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232623SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242623SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252623SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262623SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu# 282665Ssaidi@eecs.umich.edu# Authors: Steve Reinhardt 292623SN/A# Nathan Binkert 302623SN/A 312623SN/A##################################################################### 322623SN/A# 332623SN/A# Parameter description classes 342623SN/A# 352623SN/A# The _params dictionary in each class maps parameter names to either 362623SN/A# a Param or a VectorParam object. These objects contain the 372623SN/A# parameter description string, the parameter type, and the default 382623SN/A# value (if any). The convert() method on these objects is used to 392623SN/A# force whatever value is assigned to the parameter to the appropriate 402623SN/A# type. 412623SN/A# 422623SN/A# Note that the default values are loaded into the class's attribute 432623SN/A# space when the parameter dictionary is initialized (in 442623SN/A# MetaSimObject._new_param()); after that point they aren't used. 452623SN/A# 462623SN/A##################################################################### 472623SN/A 482623SN/Aimport copy 492623SN/Aimport datetime 502623SN/Aimport re 512623SN/Aimport sys 522623SN/Aimport time 532623SN/Aimport math 542623SN/A 552623SN/Aimport proxy 562623SN/Aimport ticks 572623SN/Afrom util import * 582856Srdreslin@umich.edu 592856Srdreslin@umich.edudef isSimObject(*args, **kwargs): 602856Srdreslin@umich.edu return SimObject.isSimObject(*args, **kwargs) 612856Srdreslin@umich.edu 622856Srdreslin@umich.edudef isSimObjectSequence(*args, **kwargs): 632856Srdreslin@umich.edu return SimObject.isSimObjectSequence(*args, **kwargs) 642856Srdreslin@umich.edu 652856Srdreslin@umich.edudef isSimObjectClass(*args, **kwargs): 662856Srdreslin@umich.edu return SimObject.isSimObjectClass(*args, **kwargs) 672856Srdreslin@umich.edu 682623SN/AallParams = {} 692623SN/A 702623SN/Aclass MetaParamValue(type): 712623SN/A def __new__(mcls, name, bases, dct): 722623SN/A cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 732856Srdreslin@umich.edu assert name not in allParams 742856Srdreslin@umich.edu allParams[name] = cls 752856Srdreslin@umich.edu return cls 762623SN/A 772856Srdreslin@umich.edu 782856Srdreslin@umich.edu# Dummy base class to identify types that are legitimate for SimObject 792856Srdreslin@umich.edu# parameters. 802623SN/Aclass ParamValue(object): 812623SN/A __metaclass__ = MetaParamValue 822623SN/A 832680Sktlim@umich.edu @classmethod 842680Sktlim@umich.edu def cxx_predecls(cls, code): 852623SN/A pass 862623SN/A 872680Sktlim@umich.edu @classmethod 882623SN/A def swig_predecls(cls, code): 892623SN/A pass 902623SN/A 912623SN/A # default for printing to .ini file is regular string conversion. 922623SN/A # will be overridden in some cases 932630SN/A def ini_str(self): 942623SN/A return str(self) 952623SN/A 962623SN/A # allows us to blithely call unproxy() on things without checking 972623SN/A # if they're really proxies or not 982623SN/A def unproxy(self, base): 992623SN/A return self 1002630SN/A 1012623SN/A# Regular parameter description. 1022623SN/Aclass ParamDesc(object): 1032623SN/A file_ext = 'ptype' 1042623SN/A 1052623SN/A def __init__(self, ptype_str, ptype, *args, **kwargs): 1062623SN/A self.ptype_str = ptype_str 1072630SN/A # remember ptype only if it is provided 1082623SN/A if ptype != None: 1092623SN/A self.ptype = ptype 1102623SN/A 1112623SN/A if args: 1122623SN/A if len(args) == 1: 1132623SN/A self.desc = args[0] 1142623SN/A elif len(args) == 2: 1152626SN/A self.default = args[0] 1162626SN/A self.desc = args[1] 1172626SN/A else: 1182623SN/A raise TypeError, 'too many arguments' 1192623SN/A 1202623SN/A if kwargs.has_key('desc'): 1212657Ssaidi@eecs.umich.edu assert(not hasattr(self, 'desc')) 1222623SN/A self.desc = kwargs['desc'] 1232623SN/A del kwargs['desc'] 1242623SN/A 1252623SN/A if kwargs.has_key('default'): 1262623SN/A assert(not hasattr(self, 'default')) 1272623SN/A self.default = kwargs['default'] 1282623SN/A del kwargs['default'] 1292623SN/A 1302623SN/A if kwargs: 1312640Sstever@eecs.umich.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 1322623SN/A 1332623SN/A if not hasattr(self, 'desc'): 1342623SN/A raise TypeError, 'desc attribute missing' 1352663Sstever@eecs.umich.edu 1362663Sstever@eecs.umich.edu def __getattr__(self, attr): 1372827Srdreslin@umich.edu if attr == 'ptype': 1382641Sstever@eecs.umich.edu ptype = SimObject.allClasses[self.ptype_str] 1392623SN/A assert isSimObjectClass(ptype) 1402623SN/A self.ptype = ptype 1412663Sstever@eecs.umich.edu return ptype 1422827Srdreslin@umich.edu 1432641Sstever@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 1442641Sstever@eecs.umich.edu (type(self).__name__, attr) 1452623SN/A 1462623SN/A def convert(self, value): 1472663Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 1482827Srdreslin@umich.edu value.set_param_desc(self) 1492641Sstever@eecs.umich.edu return value 1502641Sstever@eecs.umich.edu if not hasattr(self, 'ptype') and isNullPointer(value): 1512623SN/A # deferred evaluation of SimObject; continue to defer if 1522623SN/A # we're just assigning a null pointer 1532623SN/A return value 1542623SN/A if isinstance(value, self.ptype): 1552623SN/A return value 1562623SN/A if isNullPointer(value) and isSimObjectClass(self.ptype): 1572623SN/A return value 1582623SN/A return self.ptype(value) 1592623SN/A 1602623SN/A def cxx_predecls(self, code): 1612915Sktlim@umich.edu self.ptype.cxx_predecls(code) 1622915Sktlim@umich.edu 1632623SN/A def swig_predecls(self, code): 1642623SN/A self.ptype.swig_predecls(code) 1652915Sktlim@umich.edu 1662623SN/A def cxx_decl(self, code): 1672623SN/A code('${{self.ptype.cxx_type}} ${{self.name}};') 1682623SN/A 1692623SN/A# Vector-valued parameter description. Just like ParamDesc, except 1702623SN/A# that the value is a vector (list) of the specified type instead of a 1712915Sktlim@umich.edu# single value. 1722915Sktlim@umich.edu 1732915Sktlim@umich.educlass VectorParamValue(list): 1742623SN/A __metaclass__ = MetaParamValue 1752915Sktlim@umich.edu def __setattr__(self, attr, value): 1762915Sktlim@umich.edu raise AttributeError, \ 1772915Sktlim@umich.edu "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 1782915Sktlim@umich.edu 1792915Sktlim@umich.edu def ini_str(self): 1802915Sktlim@umich.edu return ' '.join([v.ini_str() for v in self]) 1812915Sktlim@umich.edu 1822915Sktlim@umich.edu def getValue(self): 1832915Sktlim@umich.edu return [ v.getValue() for v in self ] 1842623SN/A 1852623SN/A def unproxy(self, base): 1862623SN/A return [v.unproxy(base) for v in self] 1872798Sktlim@umich.edu 1882623SN/Aclass SimObjectVector(VectorParamValue): 1892798Sktlim@umich.edu # support clone operation 1902798Sktlim@umich.edu def __call__(self, **kwargs): 1912623SN/A return SimObjectVector([v(**kwargs) for v in self]) 1922798Sktlim@umich.edu 1932623SN/A def clear_parent(self, old_parent): 1942623SN/A for v in self: 1952623SN/A v.clear_parent(old_parent) 1962623SN/A 1972623SN/A def set_parent(self, parent, name): 1982623SN/A if len(self) == 1: 1992623SN/A self[0].set_parent(parent, name) 2002623SN/A else: 2012623SN/A width = int(math.ceil(math.log(len(self))/math.log(10))) 2022623SN/A for i,v in enumerate(self): 2032680Sktlim@umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2042623SN/A 2052680Sktlim@umich.edu def get_parent(self): 2062680Sktlim@umich.edu parent_set = set(v._parent for v in self) 2072680Sktlim@umich.edu if len(parent_set) != 1: 2082623SN/A raise RuntimeError, \ 2092623SN/A "SimObjectVector elements have inconsistent parent value." 2102623SN/A return parent_set.pop() 2112623SN/A 2122623SN/A # return 'cpu0 cpu1' etc. for print_ini() 2132623SN/A def get_name(self): 2142623SN/A return ' '.join([v._name for v in self]) 2152623SN/A 2162623SN/A # By iterating through the constituent members of the vector here 2172623SN/A # we can nicely handle iterating over all a SimObject's children 2182623SN/A # without having to provide lots of special functions on 2192623SN/A # SimObjectVector directly. 2202683Sktlim@umich.edu def descendants(self): 2212623SN/A for v in self: 2222623SN/A for obj in v.descendants(): 2232623SN/A yield obj 2242623SN/A 2252623SN/Aclass VectorParamDesc(ParamDesc): 2262623SN/A file_ext = 'vptype' 2272623SN/A 2282623SN/A # Convert assigned value to appropriate type. If the RHS is not a 2292623SN/A # list or tuple, it generates a single-element list. 2302623SN/A def convert(self, value): 2312623SN/A if isinstance(value, (list, tuple)): 2322623SN/A # list: coerce each element into new list 2332623SN/A tmp_list = [ ParamDesc.convert(self, v) for v in value ] 2342623SN/A else: 2352683Sktlim@umich.edu # singleton: coerce to a single-element list 2362623SN/A tmp_list = [ ParamDesc.convert(self, value) ] 2372623SN/A 2382626SN/A if isSimObjectSequence(tmp_list): 2392626SN/A return SimObjectVector(tmp_list) 2402626SN/A else: 2412626SN/A return VectorParamValue(tmp_list) 2422626SN/A 2432623SN/A def swig_predecls(self, code): 2442623SN/A code('%include "${{self.ptype_str}}_vptype.i"') 2452623SN/A 2462623SN/A def swig_decl(self, code): 2472623SN/A cxx_type = re.sub('std::', '', self.ptype.cxx_type) 2482623SN/A code('%include "std_vector.i"') 2492623SN/A self.ptype.swig_predecls(code) 2502623SN/A code('''\ 2512623SN/Anamespace std { 2522623SN/A%template(vector_${{self.ptype_str}}) vector< $cxx_type >; 2532683Sktlim@umich.edu} 2542623SN/A''') 2552623SN/A 2562623SN/A def cxx_predecls(self, code): 2572623SN/A code('#include <vector>') 2582623SN/A self.ptype.cxx_predecls(code) 2592623SN/A 2602683Sktlim@umich.edu def cxx_decl(self, code): 2612623SN/A code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 2622623SN/A 2632623SN/Aclass ParamFactory(object): 2642641Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 2652623SN/A self.param_desc_class = param_desc_class 2662662Sstever@eecs.umich.edu self.ptype_str = ptype_str 2672623SN/A 2682623SN/A def __getattr__(self, attr): 2692641Sstever@eecs.umich.edu if self.ptype_str: 2702623SN/A attr = self.ptype_str + '.' + attr 2712623SN/A return ParamFactory(self.param_desc_class, attr) 2722623SN/A 2732623SN/A # E.g., Param.Int(5, "number of widgets") 2742623SN/A def __call__(self, *args, **kwargs): 2752623SN/A ptype = None 2762623SN/A try: 2772623SN/A ptype = allParams[self.ptype_str] 2782623SN/A except KeyError: 2792623SN/A # if name isn't defined yet, assume it's a SimObject, and 2802623SN/A # try to resolve it later 2812623SN/A pass 2822623SN/A return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 2832623SN/A 2842623SN/AParam = ParamFactory(ParamDesc) 2852623SN/AVectorParam = ParamFactory(VectorParamDesc) 2862623SN/A 2872623SN/A##################################################################### 2882623SN/A# 2892623SN/A# Parameter Types 2902623SN/A# 2912623SN/A# Though native Python types could be used to specify parameter types 2922623SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more 2932623SN/A# flexible to define our own set of types. This gives us more control 2942623SN/A# over how Python expressions are converted to values (via the 2952623SN/A# __init__() constructor) and how these values are printed out (via 2962623SN/A# the __str__() conversion method). 2972623SN/A# 2982623SN/A##################################################################### 2992623SN/A 3002623SN/A# String-valued parameter. Just mixin the ParamValue class with the 3012623SN/A# built-in str class. 3022623SN/Aclass String(ParamValue,str): 3032623SN/A cxx_type = 'std::string' 3042623SN/A 3052623SN/A @classmethod 3062623SN/A def cxx_predecls(self, code): 3072623SN/A code('#include <string>') 3082623SN/A 3092623SN/A @classmethod 3102623SN/A def swig_predecls(cls, code): 3112623SN/A code('%include "std_string.i"') 3122623SN/A 3132623SN/A def getValue(self): 3142623SN/A return self 3152623SN/A 3162623SN/A# superclass for "numeric" parameter values, to emulate math 3172623SN/A# operations in a type-safe way. e.g., a Latency times an int returns 3182623SN/A# a new Latency object. 3192623SN/Aclass NumericParamValue(ParamValue): 3202623SN/A def __str__(self): 3212623SN/A return str(self.value) 3222623SN/A 3232623SN/A def __float__(self): 3242623SN/A return float(self.value) 3252623SN/A 3262623SN/A def __long__(self): 3272623SN/A return long(self.value) 3282683Sktlim@umich.edu 3292623SN/A def __int__(self): 3302623SN/A return int(self.value) 3312623SN/A 3322623SN/A # hook for bounds checking 3332623SN/A def _check(self): 3342623SN/A return 3352683Sktlim@umich.edu 3362623SN/A def __mul__(self, other): 3372623SN/A newobj = self.__class__(self) 3382623SN/A newobj.value *= other 3392623SN/A newobj._check() 3402662Sstever@eecs.umich.edu return newobj 3412623SN/A 3422623SN/A __rmul__ = __mul__ 3432662Sstever@eecs.umich.edu 3442623SN/A def __div__(self, other): 3452623SN/A newobj = self.__class__(self) 3462641Sstever@eecs.umich.edu newobj.value /= other 3472631SN/A newobj._check() 3482631SN/A return newobj 3492631SN/A 3502631SN/A def __sub__(self, other): 3512623SN/A newobj = self.__class__(self) 3522623SN/A newobj.value -= other 3532623SN/A newobj._check() 3542623SN/A return newobj 3552623SN/A 3562623SN/A# Metaclass for bounds-checked integer parameters. See CheckedInt. 3572623SN/Aclass CheckedIntType(MetaParamValue): 3582623SN/A def __init__(cls, name, bases, dict): 3592623SN/A super(CheckedIntType, cls).__init__(name, bases, dict) 3602623SN/A 3612623SN/A # CheckedInt is an abstract base class, so we actually don't 3622623SN/A # want to do any processing on it... the rest of this code is 3632623SN/A # just for classes that derive from CheckedInt. 3642623SN/A if name == 'CheckedInt': 3652623SN/A return 3662623SN/A 3672623SN/A if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 3682623SN/A if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 3692623SN/A panic("CheckedInt subclass %s must define either\n" \ 3702623SN/A " 'min' and 'max' or 'size' and 'unsigned'\n", 3712623SN/A name); 3722623SN/A if cls.unsigned: 3732623SN/A cls.min = 0 3742623SN/A cls.max = 2 ** cls.size - 1 3752623SN/A else: 3762623SN/A cls.min = -(2 ** (cls.size - 1)) 3772623SN/A cls.max = (2 ** (cls.size - 1)) - 1 3782623SN/A 3792623SN/A# Abstract superclass for bounds-checked integer parameters. This 3802623SN/A# class is subclassed to generate parameter classes with specific 3812623SN/A# bounds. Initialization of the min and max bounds is done in the 3822623SN/A# metaclass CheckedIntType.__init__. 3832623SN/Aclass CheckedInt(NumericParamValue): 3842623SN/A __metaclass__ = CheckedIntType 3852623SN/A 3862623SN/A def _check(self): 3872623SN/A if not self.min <= self.value <= self.max: 3882623SN/A raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 3892623SN/A (self.min, self.value, self.max) 3902623SN/A 3912623SN/A def __init__(self, value): 3922623SN/A if isinstance(value, str): 3932623SN/A self.value = convert.toInteger(value) 3942623SN/A elif isinstance(value, (int, long, float, NumericParamValue)): 3952623SN/A self.value = long(value) 3962623SN/A else: 3972623SN/A raise TypeError, "Can't convert object of type %s to CheckedInt" \ 3982623SN/A % type(value).__name__ 3992623SN/A self._check() 4002623SN/A 4012623SN/A @classmethod 4022623SN/A def cxx_predecls(cls, code): 4032623SN/A # most derived types require this, so we just do it here once 4042623SN/A code('#include "base/types.hh"') 4052623SN/A 4062623SN/A @classmethod 4072623SN/A def swig_predecls(cls, code): 4082623SN/A # most derived types require this, so we just do it here once 4092623SN/A code('%import "stdint.i"') 4102623SN/A code('%import "base/types.hh"') 4112623SN/A 4122623SN/A def getValue(self): 4132623SN/A return long(self.value) 4142623SN/A 4152623SN/Aclass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 4162623SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 4172626SN/A 4182626SN/Aclass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 4192662Sstever@eecs.umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 4202623SN/Aclass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 4212623SN/Aclass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4222662Sstever@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 4232662Sstever@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 4242662Sstever@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 4252623SN/Aclass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 4262623SN/A 4272623SN/Aclass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 4282623SN/Aclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 4292623SN/Aclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4302623SN/Aclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4312623SN/A 4322623SN/Aclass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 4332623SN/A 4342662Sstever@eecs.umich.educlass Float(ParamValue, float): 4352623SN/A cxx_type = 'double' 4362662Sstever@eecs.umich.edu 4372803Ssaidi@eecs.umich.edu def __init__(self, value): 4382803Ssaidi@eecs.umich.edu if isinstance(value, (int, long, float, NumericParamValue, Float)): 4392803Ssaidi@eecs.umich.edu self.value = float(value) 4402803Ssaidi@eecs.umich.edu else: 4412803Ssaidi@eecs.umich.edu raise TypeError, "Can't convert object of type %s to Float" \ 4422623SN/A % type(value).__name__ 4432623SN/A 4442623SN/A def getValue(self): 4452623SN/A return float(self.value) 4462623SN/A 4472623SN/Aclass MemorySize(CheckedInt): 4482623SN/A cxx_type = 'uint64_t' 4492626SN/A size = 64 4502626SN/A unsigned = True 4512623SN/A def __init__(self, value): 4522623SN/A if isinstance(value, MemorySize): 4532623SN/A self.value = value.value 4542623SN/A else: 4552623SN/A self.value = convert.toMemorySize(value) 4562623SN/A self._check() 4572623SN/A 4582623SN/Aclass MemorySize32(CheckedInt): 4592623SN/A cxx_type = 'uint32_t' 4602623SN/A size = 32 4612623SN/A unsigned = True 4622623SN/A def __init__(self, value): 4632623SN/A if isinstance(value, MemorySize): 4642623SN/A self.value = value.value 4652623SN/A else: 4662623SN/A self.value = convert.toMemorySize(value) 4672623SN/A self._check() 4682623SN/A 4692623SN/Aclass Addr(CheckedInt): 4702623SN/A cxx_type = 'Addr' 4712623SN/A size = 64 4722623SN/A unsigned = True 4732623SN/A def __init__(self, value): 4742623SN/A if isinstance(value, Addr): 4752623SN/A self.value = value.value 4762623SN/A else: 4772623SN/A try: 4782623SN/A self.value = convert.toMemorySize(value) 4792623SN/A except TypeError: 4802623SN/A self.value = long(value) 4812623SN/A self._check() 4822623SN/A def __add__(self, other): 4832623SN/A if isinstance(other, Addr): 4842623SN/A return self.value + other.value 4852623SN/A else: 4862623SN/A return self.value + other 4872623SN/A 4882623SN/A 4892623SN/Aclass MetaRange(MetaParamValue): 4902623SN/A def __init__(cls, name, bases, dict): 4912623SN/A super(MetaRange, cls).__init__(name, bases, dict) 4922623SN/A if name == 'Range': 4932623SN/A return 4942623SN/A cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 4952623SN/A 4962623SN/Aclass Range(ParamValue): 4972623SN/A __metaclass__ = MetaRange 4982623SN/A type = Int # default; can be overridden in subclasses 4992623SN/A def __init__(self, *args, **kwargs): 5002623SN/A def handle_kwargs(self, kwargs): 5012623SN/A if 'end' in kwargs: 5022623SN/A self.second = self.type(kwargs.pop('end')) 5032623SN/A elif 'size' in kwargs: 5042623SN/A self.second = self.first + self.type(kwargs.pop('size')) - 1 5052623SN/A else: 5062623SN/A raise TypeError, "Either end or size must be specified" 5072623SN/A 5082623SN/A if len(args) == 0: 5092623SN/A self.first = self.type(kwargs.pop('start')) 5102623SN/A handle_kwargs(self, kwargs) 5112623SN/A 5122623SN/A elif len(args) == 1: 5132623SN/A if kwargs: 5142623SN/A self.first = self.type(args[0]) 5152623SN/A handle_kwargs(self, kwargs) 5162623SN/A elif isinstance(args[0], Range): 5172623SN/A self.first = self.type(args[0].first) 5182623SN/A self.second = self.type(args[0].second) 5192623SN/A elif isinstance(args[0], (list, tuple)): 5202623SN/A self.first = self.type(args[0][0]) 5212623SN/A self.second = self.type(args[0][1]) 5222623SN/A else: 5232623SN/A self.first = self.type(0) 5242623SN/A self.second = self.type(args[0]) - 1 5252623SN/A 5262623SN/A elif len(args) == 2: 5272623SN/A self.first = self.type(args[0]) 5282623SN/A self.second = self.type(args[1]) 5292623SN/A else: 5302623SN/A raise TypeError, "Too many arguments specified" 5312623SN/A 5322623SN/A if kwargs: 5332623SN/A raise TypeError, "too many keywords: %s" % kwargs.keys() 5342623SN/A 5352623SN/A def __str__(self): 5362623SN/A return '%s:%s' % (self.first, self.second) 5372623SN/A 5382623SN/A @classmethod 5392623SN/A def cxx_predecls(cls, code): 5402623SN/A code('#include "base/range.hh"') 5412623SN/A cls.type.cxx_predecls(code) 5422623SN/A 5432623SN/Aclass AddrRange(Range): 5442623SN/A type = Addr 5452623SN/A 5462623SN/A @classmethod 5472623SN/A def swig_predecls(cls, code): 5482623SN/A code('%include "python/swig/range.i"') 5492623SN/A 5502623SN/A def getValue(self): 551 from m5.objects.params import AddrRange 552 553 value = AddrRange() 554 value.start = long(self.first) 555 value.end = long(self.second) 556 return value 557 558class TickRange(Range): 559 type = Tick 560 561 @classmethod 562 def swig_predecls(cls, code): 563 code('%include "python/swig/range.i"') 564 565 def getValue(self): 566 from m5.objects.params import TickRange 567 568 value = TickRange() 569 value.start = long(self.first) 570 value.end = long(self.second) 571 return value 572 573# Boolean parameter type. Python doesn't let you subclass bool, since 574# it doesn't want to let you create multiple instances of True and 575# False. Thus this is a little more complicated than String. 576class Bool(ParamValue): 577 cxx_type = 'bool' 578 def __init__(self, value): 579 try: 580 self.value = convert.toBool(value) 581 except TypeError: 582 self.value = bool(value) 583 584 def getValue(self): 585 return bool(self.value) 586 587 def __str__(self): 588 return str(self.value) 589 590 def ini_str(self): 591 if self.value: 592 return 'true' 593 return 'false' 594 595def IncEthernetAddr(addr, val = 1): 596 bytes = map(lambda x: int(x, 16), addr.split(':')) 597 bytes[5] += val 598 for i in (5, 4, 3, 2, 1): 599 val,rem = divmod(bytes[i], 256) 600 bytes[i] = rem 601 if val == 0: 602 break 603 bytes[i - 1] += val 604 assert(bytes[0] <= 255) 605 return ':'.join(map(lambda x: '%02x' % x, bytes)) 606 607_NextEthernetAddr = "00:90:00:00:00:01" 608def NextEthernetAddr(): 609 global _NextEthernetAddr 610 611 value = _NextEthernetAddr 612 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 613 return value 614 615class EthernetAddr(ParamValue): 616 cxx_type = 'Net::EthAddr' 617 618 @classmethod 619 def cxx_predecls(cls, code): 620 code('#include "base/inet.hh"') 621 622 @classmethod 623 def swig_predecls(cls, code): 624 code('%include "python/swig/inet.i"') 625 626 def __init__(self, value): 627 if value == NextEthernetAddr: 628 self.value = value 629 return 630 631 if not isinstance(value, str): 632 raise TypeError, "expected an ethernet address and didn't get one" 633 634 bytes = value.split(':') 635 if len(bytes) != 6: 636 raise TypeError, 'invalid ethernet address %s' % value 637 638 for byte in bytes: 639 if not 0 <= int(byte) <= 256: 640 raise TypeError, 'invalid ethernet address %s' % value 641 642 self.value = value 643 644 def unproxy(self, base): 645 if self.value == NextEthernetAddr: 646 return EthernetAddr(self.value()) 647 return self 648 649 def getValue(self): 650 from m5.objects.params import EthAddr 651 return EthAddr(self.value) 652 653 def ini_str(self): 654 return self.value 655 656time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 657 "%a %b %d %H:%M:%S %Z %Y", 658 "%Y/%m/%d %H:%M:%S", 659 "%Y/%m/%d %H:%M", 660 "%Y/%m/%d", 661 "%m/%d/%Y %H:%M:%S", 662 "%m/%d/%Y %H:%M", 663 "%m/%d/%Y", 664 "%m/%d/%y %H:%M:%S", 665 "%m/%d/%y %H:%M", 666 "%m/%d/%y"] 667 668 669def parse_time(value): 670 from time import gmtime, strptime, struct_time, time 671 from datetime import datetime, date 672 673 if isinstance(value, struct_time): 674 return value 675 676 if isinstance(value, (int, long)): 677 return gmtime(value) 678 679 if isinstance(value, (datetime, date)): 680 return value.timetuple() 681 682 if isinstance(value, str): 683 if value in ('Now', 'Today'): 684 return time.gmtime(time.time()) 685 686 for format in time_formats: 687 try: 688 return strptime(value, format) 689 except ValueError: 690 pass 691 692 raise ValueError, "Could not parse '%s' as a time" % value 693 694class Time(ParamValue): 695 cxx_type = 'tm' 696 697 @classmethod 698 def cxx_predecls(cls, code): 699 code('#include <time.h>') 700 701 @classmethod 702 def swig_predecls(cls, code): 703 code('%include "python/swig/time.i"') 704 705 def __init__(self, value): 706 self.value = parse_time(value) 707 708 def getValue(self): 709 from m5.objects.params import tm 710 711 c_time = tm() 712 py_time = self.value 713 714 # UNIX is years since 1900 715 c_time.tm_year = py_time.tm_year - 1900; 716 717 # Python starts at 1, UNIX starts at 0 718 c_time.tm_mon = py_time.tm_mon - 1; 719 c_time.tm_mday = py_time.tm_mday; 720 c_time.tm_hour = py_time.tm_hour; 721 c_time.tm_min = py_time.tm_min; 722 c_time.tm_sec = py_time.tm_sec; 723 724 # Python has 0 as Monday, UNIX is 0 as sunday 725 c_time.tm_wday = py_time.tm_wday + 1 726 if c_time.tm_wday > 6: 727 c_time.tm_wday -= 7; 728 729 # Python starts at 1, Unix starts at 0 730 c_time.tm_yday = py_time.tm_yday - 1; 731 732 return c_time 733 734 def __str__(self): 735 return time.asctime(self.value) 736 737 def ini_str(self): 738 return str(self) 739 740# Enumerated types are a little more complex. The user specifies the 741# type as Enum(foo) where foo is either a list or dictionary of 742# alternatives (typically strings, but not necessarily so). (In the 743# long run, the integer value of the parameter will be the list index 744# or the corresponding dictionary value. For now, since we only check 745# that the alternative is valid and then spit it into a .ini file, 746# there's not much point in using the dictionary.) 747 748# What Enum() must do is generate a new type encapsulating the 749# provided list/dictionary so that specific values of the parameter 750# can be instances of that type. We define two hidden internal 751# classes (_ListEnum and _DictEnum) to serve as base classes, then 752# derive the new type from the appropriate base class on the fly. 753 754allEnums = {} 755# Metaclass for Enum types 756class MetaEnum(MetaParamValue): 757 def __new__(mcls, name, bases, dict): 758 assert name not in allEnums 759 760 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 761 allEnums[name] = cls 762 return cls 763 764 def __init__(cls, name, bases, init_dict): 765 if init_dict.has_key('map'): 766 if not isinstance(cls.map, dict): 767 raise TypeError, "Enum-derived class attribute 'map' " \ 768 "must be of type dict" 769 # build list of value strings from map 770 cls.vals = cls.map.keys() 771 cls.vals.sort() 772 elif init_dict.has_key('vals'): 773 if not isinstance(cls.vals, list): 774 raise TypeError, "Enum-derived class attribute 'vals' " \ 775 "must be of type list" 776 # build string->value map from vals sequence 777 cls.map = {} 778 for idx,val in enumerate(cls.vals): 779 cls.map[val] = idx 780 else: 781 raise TypeError, "Enum-derived class must define "\ 782 "attribute 'map' or 'vals'" 783 784 cls.cxx_type = 'Enums::%s' % name 785 786 super(MetaEnum, cls).__init__(name, bases, init_dict) 787 788 # Generate C++ class declaration for this enum type. 789 # Note that we wrap the enum in a class/struct to act as a namespace, 790 # so that the enum strings can be brief w/o worrying about collisions. 791 def cxx_decl(cls, code): 792 name = cls.__name__ 793 code('''\ 794#ifndef __ENUM__${name}__ 795#define __ENUM__${name}__ 796 797namespace Enums { 798 enum $name { 799''') 800 code.indent(2) 801 for val in cls.vals: 802 code('$val = ${{cls.map[val]}},') 803 code('Num_$name = ${{len(cls.vals)}},') 804 code.dedent(2) 805 code('''\ 806 }; 807extern const char *${name}Strings[Num_${name}]; 808} 809 810#endif // __ENUM__${name}__ 811''') 812 813 def cxx_def(cls, code): 814 name = cls.__name__ 815 code('''\ 816#include "enums/${name}.hh" 817namespace Enums { 818 const char *${name}Strings[Num_${name}] = 819 { 820''') 821 code.indent(2) 822 for val in cls.vals: 823 code('"$val",') 824 code.dedent(2) 825 code(''' 826 }; 827/* namespace Enums */ } 828''') 829 830# Base class for enum types. 831class Enum(ParamValue): 832 __metaclass__ = MetaEnum 833 vals = [] 834 835 def __init__(self, value): 836 if value not in self.map: 837 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 838 % (value, self.vals) 839 self.value = value 840 841 def getValue(self): 842 return int(self.map[self.value]) 843 844 def __str__(self): 845 return self.value 846 847# how big does a rounding error need to be before we warn about it? 848frequency_tolerance = 0.001 # 0.1% 849 850class TickParamValue(NumericParamValue): 851 cxx_type = 'Tick' 852 853 @classmethod 854 def cxx_predecls(cls, code): 855 code('#include "base/types.hh"') 856 857 @classmethod 858 def swig_predecls(cls, code): 859 code('%import "stdint.i"') 860 code('%import "base/types.hh"') 861 862 def getValue(self): 863 return long(self.value) 864 865class Latency(TickParamValue): 866 def __init__(self, value): 867 if isinstance(value, (Latency, Clock)): 868 self.ticks = value.ticks 869 self.value = value.value 870 elif isinstance(value, Frequency): 871 self.ticks = value.ticks 872 self.value = 1.0 / value.value 873 elif value.endswith('t'): 874 self.ticks = True 875 self.value = int(value[:-1]) 876 else: 877 self.ticks = False 878 self.value = convert.toLatency(value) 879 880 def __getattr__(self, attr): 881 if attr in ('latency', 'period'): 882 return self 883 if attr == 'frequency': 884 return Frequency(self) 885 raise AttributeError, "Latency object has no attribute '%s'" % attr 886 887 def getValue(self): 888 if self.ticks or self.value == 0: 889 value = self.value 890 else: 891 value = ticks.fromSeconds(self.value) 892 return long(value) 893 894 # convert latency to ticks 895 def ini_str(self): 896 return '%d' % self.getValue() 897 898class Frequency(TickParamValue): 899 def __init__(self, value): 900 if isinstance(value, (Latency, Clock)): 901 if value.value == 0: 902 self.value = 0 903 else: 904 self.value = 1.0 / value.value 905 self.ticks = value.ticks 906 elif isinstance(value, Frequency): 907 self.value = value.value 908 self.ticks = value.ticks 909 else: 910 self.ticks = False 911 self.value = convert.toFrequency(value) 912 913 def __getattr__(self, attr): 914 if attr == 'frequency': 915 return self 916 if attr in ('latency', 'period'): 917 return Latency(self) 918 raise AttributeError, "Frequency object has no attribute '%s'" % attr 919 920 # convert latency to ticks 921 def getValue(self): 922 if self.ticks or self.value == 0: 923 value = self.value 924 else: 925 value = ticks.fromSeconds(1.0 / self.value) 926 return long(value) 927 928 def ini_str(self): 929 return '%d' % self.getValue() 930 931# A generic frequency and/or Latency value. Value is stored as a latency, 932# but to avoid ambiguity this object does not support numeric ops (* or /). 933# An explicit conversion to a Latency or Frequency must be made first. 934class Clock(ParamValue): 935 cxx_type = 'Tick' 936 937 @classmethod 938 def cxx_predecls(cls, code): 939 code('#include "base/types.hh"') 940 941 @classmethod 942 def swig_predecls(cls, code): 943 code('%import "stdint.i"') 944 code('%import "base/types.hh"') 945 946 def __init__(self, value): 947 if isinstance(value, (Latency, Clock)): 948 self.ticks = value.ticks 949 self.value = value.value 950 elif isinstance(value, Frequency): 951 self.ticks = value.ticks 952 self.value = 1.0 / value.value 953 elif value.endswith('t'): 954 self.ticks = True 955 self.value = int(value[:-1]) 956 else: 957 self.ticks = False 958 self.value = convert.anyToLatency(value) 959 960 def __getattr__(self, attr): 961 if attr == 'frequency': 962 return Frequency(self) 963 if attr in ('latency', 'period'): 964 return Latency(self) 965 raise AttributeError, "Frequency object has no attribute '%s'" % attr 966 967 def getValue(self): 968 return self.period.getValue() 969 970 def ini_str(self): 971 return self.period.ini_str() 972 973class NetworkBandwidth(float,ParamValue): 974 cxx_type = 'float' 975 def __new__(cls, value): 976 # convert to bits per second 977 val = convert.toNetworkBandwidth(value) 978 return super(cls, NetworkBandwidth).__new__(cls, val) 979 980 def __str__(self): 981 return str(self.val) 982 983 def getValue(self): 984 # convert to seconds per byte 985 value = 8.0 / float(self) 986 # convert to ticks per byte 987 value = ticks.fromSeconds(value) 988 return float(value) 989 990 def ini_str(self): 991 return '%f' % self.getValue() 992 993class MemoryBandwidth(float,ParamValue): 994 cxx_type = 'float' 995 def __new__(cls, value): 996 # we want the number of ticks per byte of data 997 val = convert.toMemoryBandwidth(value) 998 return super(cls, MemoryBandwidth).__new__(cls, val) 999 1000 def __str__(self): 1001 return str(self.val) 1002 1003 def getValue(self): 1004 # convert to seconds per byte 1005 value = float(self) 1006 if value: 1007 value = 1.0 / float(self) 1008 # convert to ticks per byte 1009 value = ticks.fromSeconds(value) 1010 return float(value) 1011 1012 def ini_str(self): 1013 return '%f' % self.getValue() 1014 1015# 1016# "Constants"... handy aliases for various values. 1017# 1018 1019# Special class for NULL pointers. Note the special check in 1020# make_param_value() above that lets these be assigned where a 1021# SimObject is required. 1022# only one copy of a particular node 1023class NullSimObject(object): 1024 __metaclass__ = Singleton 1025 1026 def __call__(cls): 1027 return cls 1028 1029 def _instantiate(self, parent = None, path = ''): 1030 pass 1031 1032 def ini_str(self): 1033 return 'Null' 1034 1035 def unproxy(self, base): 1036 return self 1037 1038 def set_path(self, parent, name): 1039 pass 1040 1041 def __str__(self): 1042 return 'Null' 1043 1044 def getValue(self): 1045 return None 1046 1047# The only instance you'll ever need... 1048NULL = NullSimObject() 1049 1050def isNullPointer(value): 1051 return isinstance(value, NullSimObject) 1052 1053# Some memory range specifications use this as a default upper bound. 1054MaxAddr = Addr.max 1055MaxTick = Tick.max 1056AllMemory = AddrRange(0, MaxAddr) 1057 1058 1059##################################################################### 1060# 1061# Port objects 1062# 1063# Ports are used to interconnect objects in the memory system. 1064# 1065##################################################################### 1066 1067# Port reference: encapsulates a reference to a particular port on a 1068# particular SimObject. 1069class PortRef(object): 1070 def __init__(self, simobj, name): 1071 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1072 self.simobj = simobj 1073 self.name = name 1074 self.peer = None # not associated with another port yet 1075 self.ccConnected = False # C++ port connection done? 1076 self.index = -1 # always -1 for non-vector ports 1077 1078 def __str__(self): 1079 return '%s.%s' % (self.simobj, self.name) 1080 1081 # for config.ini, print peer's name (not ours) 1082 def ini_str(self): 1083 return str(self.peer) 1084 1085 def __getattr__(self, attr): 1086 if attr == 'peerObj': 1087 # shorthand for proxies 1088 return self.peer.simobj 1089 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1090 (self.__class__.__name__, attr) 1091 1092 # Full connection is symmetric (both ways). Called via 1093 # SimObject.__setattr__ as a result of a port assignment, e.g., 1094 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1095 # e.g., "obj1.portA[3] = obj2.portB". 1096 def connect(self, other): 1097 if isinstance(other, VectorPortRef): 1098 # reference to plain VectorPort is implicit append 1099 other = other._get_next() 1100 if self.peer and not proxy.isproxy(self.peer): 1101 print "warning: overwriting port", self, \ 1102 "value", self.peer, "with", other 1103 self.peer.peer = None 1104 self.peer = other 1105 if proxy.isproxy(other): 1106 other.set_param_desc(PortParamDesc()) 1107 elif isinstance(other, PortRef): 1108 if other.peer is not self: 1109 other.connect(self) 1110 else: 1111 raise TypeError, \ 1112 "assigning non-port reference '%s' to port '%s'" \ 1113 % (other, self) 1114 1115 def clone(self, simobj, memo): 1116 if memo.has_key(self): 1117 return memo[self] 1118 newRef = copy.copy(self) 1119 memo[self] = newRef 1120 newRef.simobj = simobj 1121 assert(isSimObject(newRef.simobj)) 1122 if self.peer and not proxy.isproxy(self.peer): 1123 peerObj = self.peer.simobj(_memo=memo) 1124 newRef.peer = self.peer.clone(peerObj, memo) 1125 assert(not isinstance(newRef.peer, VectorPortRef)) 1126 return newRef 1127 1128 def unproxy(self, simobj): 1129 assert(simobj is self.simobj) 1130 if proxy.isproxy(self.peer): 1131 try: 1132 realPeer = self.peer.unproxy(self.simobj) 1133 except: 1134 print "Error in unproxying port '%s' of %s" % \ 1135 (self.name, self.simobj.path()) 1136 raise 1137 self.connect(realPeer) 1138 1139 # Call C++ to create corresponding port connection between C++ objects 1140 def ccConnect(self): 1141 from m5.objects.params import connectPorts 1142 1143 if self.ccConnected: # already done this 1144 return 1145 peer = self.peer 1146 if not self.peer: # nothing to connect to 1147 return 1148 try: 1149 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1150 peer.simobj.getCCObject(), peer.name, peer.index) 1151 except: 1152 print "Error connecting port %s.%s to %s.%s" % \ 1153 (self.simobj.path(), self.name, 1154 peer.simobj.path(), peer.name) 1155 raise 1156 self.ccConnected = True 1157 peer.ccConnected = True 1158 1159# A reference to an individual element of a VectorPort... much like a 1160# PortRef, but has an index. 1161class VectorPortElementRef(PortRef): 1162 def __init__(self, simobj, name, index): 1163 PortRef.__init__(self, simobj, name) 1164 self.index = index 1165 1166 def __str__(self): 1167 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1168 1169# A reference to a complete vector-valued port (not just a single element). 1170# Can be indexed to retrieve individual VectorPortElementRef instances. 1171class VectorPortRef(object): 1172 def __init__(self, simobj, name): 1173 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1174 self.simobj = simobj 1175 self.name = name 1176 self.elements = [] 1177 1178 def __str__(self): 1179 return '%s.%s[:]' % (self.simobj, self.name) 1180 1181 # for config.ini, print peer's name (not ours) 1182 def ini_str(self): 1183 return ' '.join([el.ini_str() for el in self.elements]) 1184 1185 def __getitem__(self, key): 1186 if not isinstance(key, int): 1187 raise TypeError, "VectorPort index must be integer" 1188 if key >= len(self.elements): 1189 # need to extend list 1190 ext = [VectorPortElementRef(self.simobj, self.name, i) 1191 for i in range(len(self.elements), key+1)] 1192 self.elements.extend(ext) 1193 return self.elements[key] 1194 1195 def _get_next(self): 1196 return self[len(self.elements)] 1197 1198 def __setitem__(self, key, value): 1199 if not isinstance(key, int): 1200 raise TypeError, "VectorPort index must be integer" 1201 self[key].connect(value) 1202 1203 def connect(self, other): 1204 if isinstance(other, (list, tuple)): 1205 # Assign list of port refs to vector port. 1206 # For now, append them... not sure if that's the right semantics 1207 # or if it should replace the current vector. 1208 for ref in other: 1209 self._get_next().connect(ref) 1210 else: 1211 # scalar assignment to plain VectorPort is implicit append 1212 self._get_next().connect(other) 1213 1214 def clone(self, simobj, memo): 1215 if memo.has_key(self): 1216 return memo[self] 1217 newRef = copy.copy(self) 1218 memo[self] = newRef 1219 newRef.simobj = simobj 1220 assert(isSimObject(newRef.simobj)) 1221 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1222 return newRef 1223 1224 def unproxy(self, simobj): 1225 [el.unproxy(simobj) for el in self.elements] 1226 1227 def ccConnect(self): 1228 [el.ccConnect() for el in self.elements] 1229 1230# Port description object. Like a ParamDesc object, this represents a 1231# logical port in the SimObject class, not a particular port on a 1232# SimObject instance. The latter are represented by PortRef objects. 1233class Port(object): 1234 # Port("description") or Port(default, "description") 1235 def __init__(self, *args): 1236 if len(args) == 1: 1237 self.desc = args[0] 1238 elif len(args) == 2: 1239 self.default = args[0] 1240 self.desc = args[1] 1241 else: 1242 raise TypeError, 'wrong number of arguments' 1243 # self.name is set by SimObject class on assignment 1244 # e.g., pio_port = Port("blah") sets self.name to 'pio_port' 1245 1246 # Generate a PortRef for this port on the given SimObject with the 1247 # given name 1248 def makeRef(self, simobj): 1249 return PortRef(simobj, self.name) 1250 1251 # Connect an instance of this port (on the given SimObject with 1252 # the given name) with the port described by the supplied PortRef 1253 def connect(self, simobj, ref): 1254 self.makeRef(simobj).connect(ref) 1255 1256# VectorPort description object. Like Port, but represents a vector 1257# of connections (e.g., as on a Bus). 1258class VectorPort(Port): 1259 def __init__(self, *args): 1260 Port.__init__(self, *args) 1261 self.isVec = True 1262 1263 def makeRef(self, simobj): 1264 return VectorPortRef(simobj, self.name) 1265 1266# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1267# proxy objects (via set_param_desc()) so that proxy error messages 1268# make sense. 1269class PortParamDesc(object): 1270 __metaclass__ = Singleton 1271 1272 ptype_str = 'Port' 1273 ptype = Port 1274 1275baseEnums = allEnums.copy() 1276baseParams = allParams.copy() 1277 1278def clear(): 1279 global allEnums, allParams 1280 1281 allEnums = baseEnums.copy() 1282 allParams = baseParams.copy() 1283 1284__all__ = ['Param', 'VectorParam', 1285 'Enum', 'Bool', 'String', 'Float', 1286 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1287 'Int32', 'UInt32', 'Int64', 'UInt64', 1288 'Counter', 'Addr', 'Tick', 'Percent', 1289 'TcpPort', 'UdpPort', 'EthernetAddr', 1290 'MemorySize', 'MemorySize32', 1291 'Latency', 'Frequency', 'Clock', 1292 'NetworkBandwidth', 'MemoryBandwidth', 1293 'Range', 'AddrRange', 'TickRange', 1294 'MaxAddr', 'MaxTick', 'AllMemory', 1295 'Time', 1296 'NextEthernetAddr', 'NULL', 1297 'Port', 'VectorPort'] 1298 1299import SimObject 1300