params.py revision 4123
13101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 23101Sstever@eecs.umich.edu# All rights reserved. 33101Sstever@eecs.umich.edu# 43101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 53101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 63101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 73101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 83101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 93101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 103101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 113101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 123101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from 133101Sstever@eecs.umich.edu# this software without specific prior written permission. 143101Sstever@eecs.umich.edu# 153101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 163101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 173101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 183101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 193101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 203101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 213101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 223101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 233101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 243101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 253101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 263101Sstever@eecs.umich.edu# 273101Sstever@eecs.umich.edu# Authors: Steve Reinhardt 283101Sstever@eecs.umich.edu# Nathan Binkert 293101Sstever@eecs.umich.edu 303101Sstever@eecs.umich.edu##################################################################### 313101Sstever@eecs.umich.edu# 323101Sstever@eecs.umich.edu# Parameter description classes 333101Sstever@eecs.umich.edu# 343101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either 353101Sstever@eecs.umich.edu# a Param or a VectorParam object. These objects contain the 363101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default 373101Sstever@eecs.umich.edu# value (if any). The convert() method on these objects is used to 383101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 393101Sstever@eecs.umich.edu# type. 403101Sstever@eecs.umich.edu# 413101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute 423101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in 433101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used. 443101Sstever@eecs.umich.edu# 453101Sstever@eecs.umich.edu##################################################################### 463101Sstever@eecs.umich.edu 473885Sbinkertn@umich.eduimport copy 483885Sbinkertn@umich.eduimport datetime 493885Sbinkertn@umich.eduimport inspect 503885Sbinkertn@umich.eduimport sys 513885Sbinkertn@umich.eduimport time 523885Sbinkertn@umich.edu 533101Sstever@eecs.umich.eduimport convert 543102Sstever@eecs.umich.edufrom util import * 553101Sstever@eecs.umich.edu 563101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject 573101Sstever@eecs.umich.edu# parameters. 583101Sstever@eecs.umich.educlass ParamValue(object): 593101Sstever@eecs.umich.edu 603101Sstever@eecs.umich.edu cxx_predecls = [] 613101Sstever@eecs.umich.edu swig_predecls = [] 623101Sstever@eecs.umich.edu 633101Sstever@eecs.umich.edu # default for printing to .ini file is regular string conversion. 643101Sstever@eecs.umich.edu # will be overridden in some cases 653101Sstever@eecs.umich.edu def ini_str(self): 663101Sstever@eecs.umich.edu return str(self) 673101Sstever@eecs.umich.edu 683101Sstever@eecs.umich.edu # allows us to blithely call unproxy() on things without checking 693101Sstever@eecs.umich.edu # if they're really proxies or not 703101Sstever@eecs.umich.edu def unproxy(self, base): 713101Sstever@eecs.umich.edu return self 723101Sstever@eecs.umich.edu 733101Sstever@eecs.umich.edu# Regular parameter description. 743101Sstever@eecs.umich.educlass ParamDesc(object): 753101Sstever@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 763101Sstever@eecs.umich.edu self.ptype_str = ptype_str 773101Sstever@eecs.umich.edu # remember ptype only if it is provided 783101Sstever@eecs.umich.edu if ptype != None: 793101Sstever@eecs.umich.edu self.ptype = ptype 803101Sstever@eecs.umich.edu 813101Sstever@eecs.umich.edu if args: 823101Sstever@eecs.umich.edu if len(args) == 1: 833101Sstever@eecs.umich.edu self.desc = args[0] 843101Sstever@eecs.umich.edu elif len(args) == 2: 853101Sstever@eecs.umich.edu self.default = args[0] 863101Sstever@eecs.umich.edu self.desc = args[1] 873101Sstever@eecs.umich.edu else: 883101Sstever@eecs.umich.edu raise TypeError, 'too many arguments' 893101Sstever@eecs.umich.edu 903101Sstever@eecs.umich.edu if kwargs.has_key('desc'): 913101Sstever@eecs.umich.edu assert(not hasattr(self, 'desc')) 923101Sstever@eecs.umich.edu self.desc = kwargs['desc'] 933101Sstever@eecs.umich.edu del kwargs['desc'] 943101Sstever@eecs.umich.edu 953101Sstever@eecs.umich.edu if kwargs.has_key('default'): 963101Sstever@eecs.umich.edu assert(not hasattr(self, 'default')) 973101Sstever@eecs.umich.edu self.default = kwargs['default'] 983101Sstever@eecs.umich.edu del kwargs['default'] 993101Sstever@eecs.umich.edu 1003101Sstever@eecs.umich.edu if kwargs: 1013101Sstever@eecs.umich.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 1023101Sstever@eecs.umich.edu 1033101Sstever@eecs.umich.edu if not hasattr(self, 'desc'): 1043101Sstever@eecs.umich.edu raise TypeError, 'desc attribute missing' 1053101Sstever@eecs.umich.edu 1063101Sstever@eecs.umich.edu def __getattr__(self, attr): 1073101Sstever@eecs.umich.edu if attr == 'ptype': 1083101Sstever@eecs.umich.edu try: 1093102Sstever@eecs.umich.edu ptype = eval(self.ptype_str, objects.__dict__) 1103101Sstever@eecs.umich.edu if not isinstance(ptype, type): 1113102Sstever@eecs.umich.edu raise NameError 1123101Sstever@eecs.umich.edu self.ptype = ptype 1133101Sstever@eecs.umich.edu return ptype 1143101Sstever@eecs.umich.edu except NameError: 1153102Sstever@eecs.umich.edu raise TypeError, \ 1163102Sstever@eecs.umich.edu "Param qualifier '%s' is not a type" % self.ptype_str 1173101Sstever@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 1183101Sstever@eecs.umich.edu (type(self).__name__, attr) 1193101Sstever@eecs.umich.edu 1203101Sstever@eecs.umich.edu def convert(self, value): 1213101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 1223101Sstever@eecs.umich.edu value.set_param_desc(self) 1233101Sstever@eecs.umich.edu return value 1243101Sstever@eecs.umich.edu if not hasattr(self, 'ptype') and isNullPointer(value): 1253101Sstever@eecs.umich.edu # deferred evaluation of SimObject; continue to defer if 1263101Sstever@eecs.umich.edu # we're just assigning a null pointer 1273101Sstever@eecs.umich.edu return value 1283101Sstever@eecs.umich.edu if isinstance(value, self.ptype): 1293101Sstever@eecs.umich.edu return value 1303102Sstever@eecs.umich.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 1313101Sstever@eecs.umich.edu return value 1323101Sstever@eecs.umich.edu return self.ptype(value) 1333101Sstever@eecs.umich.edu 1343101Sstever@eecs.umich.edu def cxx_predecls(self): 1353101Sstever@eecs.umich.edu return self.ptype.cxx_predecls 1363101Sstever@eecs.umich.edu 1373101Sstever@eecs.umich.edu def swig_predecls(self): 1383101Sstever@eecs.umich.edu return self.ptype.swig_predecls 1393101Sstever@eecs.umich.edu 1403101Sstever@eecs.umich.edu def cxx_decl(self): 1413101Sstever@eecs.umich.edu return '%s %s;' % (self.ptype.cxx_type, self.name) 1423101Sstever@eecs.umich.edu 1433101Sstever@eecs.umich.edu# Vector-valued parameter description. Just like ParamDesc, except 1443101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a 1453101Sstever@eecs.umich.edu# single value. 1463101Sstever@eecs.umich.edu 1473101Sstever@eecs.umich.educlass VectorParamValue(list): 1483101Sstever@eecs.umich.edu def ini_str(self): 1493101Sstever@eecs.umich.edu return ' '.join([v.ini_str() for v in self]) 1503101Sstever@eecs.umich.edu 1513101Sstever@eecs.umich.edu def unproxy(self, base): 1523101Sstever@eecs.umich.edu return [v.unproxy(base) for v in self] 1533101Sstever@eecs.umich.edu 1543101Sstever@eecs.umich.educlass SimObjVector(VectorParamValue): 1553101Sstever@eecs.umich.edu def print_ini(self): 1563101Sstever@eecs.umich.edu for v in self: 1573101Sstever@eecs.umich.edu v.print_ini() 1583101Sstever@eecs.umich.edu 1593101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc): 1603101Sstever@eecs.umich.edu # Convert assigned value to appropriate type. If the RHS is not a 1613101Sstever@eecs.umich.edu # list or tuple, it generates a single-element list. 1623101Sstever@eecs.umich.edu def convert(self, value): 1633101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 1643101Sstever@eecs.umich.edu # list: coerce each element into new list 1653101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 1663101Sstever@eecs.umich.edu if isSimObjectSequence(tmp_list): 1673101Sstever@eecs.umich.edu return SimObjVector(tmp_list) 1683101Sstever@eecs.umich.edu else: 1693101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 1703101Sstever@eecs.umich.edu else: 1713101Sstever@eecs.umich.edu # singleton: leave it be (could coerce to a single-element 1723101Sstever@eecs.umich.edu # list here, but for some historical reason we don't... 1733101Sstever@eecs.umich.edu return ParamDesc.convert(self, value) 1743101Sstever@eecs.umich.edu 1753101Sstever@eecs.umich.edu def cxx_predecls(self): 1763101Sstever@eecs.umich.edu return ['#include <vector>'] + self.ptype.cxx_predecls 1773101Sstever@eecs.umich.edu 1783101Sstever@eecs.umich.edu def swig_predecls(self): 1793101Sstever@eecs.umich.edu return ['%include "std_vector.i"'] + self.ptype.swig_predecls 1803101Sstever@eecs.umich.edu 1813101Sstever@eecs.umich.edu def cxx_decl(self): 1823101Sstever@eecs.umich.edu return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name) 1833101Sstever@eecs.umich.edu 1843101Sstever@eecs.umich.educlass ParamFactory(object): 1853101Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 1863101Sstever@eecs.umich.edu self.param_desc_class = param_desc_class 1873101Sstever@eecs.umich.edu self.ptype_str = ptype_str 1883101Sstever@eecs.umich.edu 1893101Sstever@eecs.umich.edu def __getattr__(self, attr): 1903101Sstever@eecs.umich.edu if self.ptype_str: 1913101Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 1923101Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 1933101Sstever@eecs.umich.edu 1943101Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 1953101Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 1963101Sstever@eecs.umich.edu caller_frame = inspect.currentframe().f_back 1973101Sstever@eecs.umich.edu ptype = None 1983101Sstever@eecs.umich.edu try: 1993101Sstever@eecs.umich.edu ptype = eval(self.ptype_str, 2003101Sstever@eecs.umich.edu caller_frame.f_globals, caller_frame.f_locals) 2013101Sstever@eecs.umich.edu if not isinstance(ptype, type): 2023101Sstever@eecs.umich.edu raise TypeError, \ 2033101Sstever@eecs.umich.edu "Param qualifier is not a type: %s" % ptype 2043101Sstever@eecs.umich.edu except NameError: 2053101Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 2063101Sstever@eecs.umich.edu # try to resolve it later 2073101Sstever@eecs.umich.edu pass 2083101Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 2093101Sstever@eecs.umich.edu 2103101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc) 2113101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc) 2123101Sstever@eecs.umich.edu 2133101Sstever@eecs.umich.edu##################################################################### 2143101Sstever@eecs.umich.edu# 2153101Sstever@eecs.umich.edu# Parameter Types 2163101Sstever@eecs.umich.edu# 2173101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types 2183101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more 2193101Sstever@eecs.umich.edu# flexible to define our own set of types. This gives us more control 2203101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the 2213101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via 2223101Sstever@eecs.umich.edu# the __str__() conversion method). 2233101Sstever@eecs.umich.edu# 2243101Sstever@eecs.umich.edu##################################################################### 2253101Sstever@eecs.umich.edu 2263101Sstever@eecs.umich.edu# String-valued parameter. Just mixin the ParamValue class with the 2273101Sstever@eecs.umich.edu# built-in str class. 2283101Sstever@eecs.umich.educlass String(ParamValue,str): 2293101Sstever@eecs.umich.edu cxx_type = 'std::string' 2303101Sstever@eecs.umich.edu cxx_predecls = ['#include <string>'] 2313101Sstever@eecs.umich.edu swig_predecls = ['%include "std_string.i"\n' + 2323101Sstever@eecs.umich.edu '%apply const std::string& {std::string *};'] 2333101Sstever@eecs.umich.edu pass 2343101Sstever@eecs.umich.edu 2353101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math 2363101Sstever@eecs.umich.edu# operations in a type-safe way. e.g., a Latency times an int returns 2373101Sstever@eecs.umich.edu# a new Latency object. 2383101Sstever@eecs.umich.educlass NumericParamValue(ParamValue): 2393101Sstever@eecs.umich.edu def __str__(self): 2403101Sstever@eecs.umich.edu return str(self.value) 2413101Sstever@eecs.umich.edu 2423101Sstever@eecs.umich.edu def __float__(self): 2433101Sstever@eecs.umich.edu return float(self.value) 2443101Sstever@eecs.umich.edu 2453714Sstever@eecs.umich.edu def __long__(self): 2463714Sstever@eecs.umich.edu return long(self.value) 2473714Sstever@eecs.umich.edu 2483714Sstever@eecs.umich.edu def __int__(self): 2493714Sstever@eecs.umich.edu return int(self.value) 2503714Sstever@eecs.umich.edu 2513101Sstever@eecs.umich.edu # hook for bounds checking 2523101Sstever@eecs.umich.edu def _check(self): 2533101Sstever@eecs.umich.edu return 2543101Sstever@eecs.umich.edu 2553101Sstever@eecs.umich.edu def __mul__(self, other): 2563101Sstever@eecs.umich.edu newobj = self.__class__(self) 2573101Sstever@eecs.umich.edu newobj.value *= other 2583101Sstever@eecs.umich.edu newobj._check() 2593101Sstever@eecs.umich.edu return newobj 2603101Sstever@eecs.umich.edu 2613101Sstever@eecs.umich.edu __rmul__ = __mul__ 2623101Sstever@eecs.umich.edu 2633101Sstever@eecs.umich.edu def __div__(self, other): 2643101Sstever@eecs.umich.edu newobj = self.__class__(self) 2653101Sstever@eecs.umich.edu newobj.value /= other 2663101Sstever@eecs.umich.edu newobj._check() 2673101Sstever@eecs.umich.edu return newobj 2683101Sstever@eecs.umich.edu 2693101Sstever@eecs.umich.edu def __sub__(self, other): 2703101Sstever@eecs.umich.edu newobj = self.__class__(self) 2713101Sstever@eecs.umich.edu newobj.value -= other 2723101Sstever@eecs.umich.edu newobj._check() 2733101Sstever@eecs.umich.edu return newobj 2743101Sstever@eecs.umich.edu 2753101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters. See CheckedInt. 2763101Sstever@eecs.umich.educlass CheckedIntType(type): 2773101Sstever@eecs.umich.edu def __init__(cls, name, bases, dict): 2783101Sstever@eecs.umich.edu super(CheckedIntType, cls).__init__(name, bases, dict) 2793101Sstever@eecs.umich.edu 2803101Sstever@eecs.umich.edu # CheckedInt is an abstract base class, so we actually don't 2813101Sstever@eecs.umich.edu # want to do any processing on it... the rest of this code is 2823101Sstever@eecs.umich.edu # just for classes that derive from CheckedInt. 2833101Sstever@eecs.umich.edu if name == 'CheckedInt': 2843101Sstever@eecs.umich.edu return 2853101Sstever@eecs.umich.edu 2863101Sstever@eecs.umich.edu if not cls.cxx_predecls: 2873101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 2883101Sstever@eecs.umich.edu cls.cxx_predecls = ['#include "sim/host.hh"'] 2893101Sstever@eecs.umich.edu 2903101Sstever@eecs.umich.edu if not cls.swig_predecls: 2913101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 2923101Sstever@eecs.umich.edu cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 2933101Sstever@eecs.umich.edu '%import "sim/host.hh"'] 2943101Sstever@eecs.umich.edu 2953101Sstever@eecs.umich.edu if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 2963101Sstever@eecs.umich.edu if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 2973101Sstever@eecs.umich.edu panic("CheckedInt subclass %s must define either\n" \ 2983101Sstever@eecs.umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n" \ 2993101Sstever@eecs.umich.edu % name); 3003101Sstever@eecs.umich.edu if cls.unsigned: 3013101Sstever@eecs.umich.edu cls.min = 0 3023101Sstever@eecs.umich.edu cls.max = 2 ** cls.size - 1 3033101Sstever@eecs.umich.edu else: 3043101Sstever@eecs.umich.edu cls.min = -(2 ** (cls.size - 1)) 3053101Sstever@eecs.umich.edu cls.max = (2 ** (cls.size - 1)) - 1 3063101Sstever@eecs.umich.edu 3073101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters. This 3083101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific 3093101Sstever@eecs.umich.edu# bounds. Initialization of the min and max bounds is done in the 3103101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__. 3113101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue): 3123101Sstever@eecs.umich.edu __metaclass__ = CheckedIntType 3133101Sstever@eecs.umich.edu 3143101Sstever@eecs.umich.edu def _check(self): 3153101Sstever@eecs.umich.edu if not self.min <= self.value <= self.max: 3163101Sstever@eecs.umich.edu raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 3173101Sstever@eecs.umich.edu (self.min, self.value, self.max) 3183101Sstever@eecs.umich.edu 3193101Sstever@eecs.umich.edu def __init__(self, value): 3203101Sstever@eecs.umich.edu if isinstance(value, str): 3213102Sstever@eecs.umich.edu self.value = convert.toInteger(value) 3223714Sstever@eecs.umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 3233101Sstever@eecs.umich.edu self.value = long(value) 3243714Sstever@eecs.umich.edu else: 3253714Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to CheckedInt" \ 3263714Sstever@eecs.umich.edu % type(value).__name__ 3273101Sstever@eecs.umich.edu self._check() 3283101Sstever@eecs.umich.edu 3293101Sstever@eecs.umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 3303101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 3313101Sstever@eecs.umich.edu 3323101Sstever@eecs.umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 3333101Sstever@eecs.umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 3343101Sstever@eecs.umich.educlass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 3353101Sstever@eecs.umich.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 3363101Sstever@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 3373101Sstever@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 3383101Sstever@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 3393101Sstever@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 3403101Sstever@eecs.umich.edu 3413101Sstever@eecs.umich.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 3423101Sstever@eecs.umich.educlass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 3433101Sstever@eecs.umich.educlass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 3443101Sstever@eecs.umich.educlass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 3453101Sstever@eecs.umich.edu 3463101Sstever@eecs.umich.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 3473101Sstever@eecs.umich.edu 3483101Sstever@eecs.umich.educlass Float(ParamValue, float): 3493101Sstever@eecs.umich.edu pass 3503101Sstever@eecs.umich.edu 3513101Sstever@eecs.umich.educlass MemorySize(CheckedInt): 3523101Sstever@eecs.umich.edu cxx_type = 'uint64_t' 3533101Sstever@eecs.umich.edu size = 64 3543101Sstever@eecs.umich.edu unsigned = True 3553101Sstever@eecs.umich.edu def __init__(self, value): 3563101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 3573101Sstever@eecs.umich.edu self.value = value.value 3583101Sstever@eecs.umich.edu else: 3593102Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 3603101Sstever@eecs.umich.edu self._check() 3613101Sstever@eecs.umich.edu 3623101Sstever@eecs.umich.educlass MemorySize32(CheckedInt): 3633101Sstever@eecs.umich.edu size = 32 3643101Sstever@eecs.umich.edu unsigned = True 3653101Sstever@eecs.umich.edu def __init__(self, value): 3663101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 3673101Sstever@eecs.umich.edu self.value = value.value 3683101Sstever@eecs.umich.edu else: 3693102Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 3703101Sstever@eecs.umich.edu self._check() 3713101Sstever@eecs.umich.edu 3723101Sstever@eecs.umich.educlass Addr(CheckedInt): 3733101Sstever@eecs.umich.edu cxx_type = 'Addr' 3743101Sstever@eecs.umich.edu cxx_predecls = ['#include "targetarch/isa_traits.hh"'] 3753101Sstever@eecs.umich.edu size = 64 3763101Sstever@eecs.umich.edu unsigned = True 3773101Sstever@eecs.umich.edu def __init__(self, value): 3783101Sstever@eecs.umich.edu if isinstance(value, Addr): 3793101Sstever@eecs.umich.edu self.value = value.value 3803101Sstever@eecs.umich.edu else: 3813101Sstever@eecs.umich.edu try: 3823102Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 3833101Sstever@eecs.umich.edu except TypeError: 3843101Sstever@eecs.umich.edu self.value = long(value) 3853101Sstever@eecs.umich.edu self._check() 3863584Ssaidi@eecs.umich.edu def __add__(self, other): 3873584Ssaidi@eecs.umich.edu if isinstance(other, Addr): 3883584Ssaidi@eecs.umich.edu return self.value + other.value 3893584Ssaidi@eecs.umich.edu else: 3903584Ssaidi@eecs.umich.edu return self.value + other 3913101Sstever@eecs.umich.edu 3923101Sstever@eecs.umich.edu 3933101Sstever@eecs.umich.educlass MetaRange(type): 3943101Sstever@eecs.umich.edu def __init__(cls, name, bases, dict): 3953101Sstever@eecs.umich.edu super(MetaRange, cls).__init__(name, bases, dict) 3963101Sstever@eecs.umich.edu if name == 'Range': 3973101Sstever@eecs.umich.edu return 3983101Sstever@eecs.umich.edu cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 3993101Sstever@eecs.umich.edu cls.cxx_predecls = \ 4003101Sstever@eecs.umich.edu ['#include "base/range.hh"'] + cls.type.cxx_predecls 4013101Sstever@eecs.umich.edu 4023101Sstever@eecs.umich.educlass Range(ParamValue): 4033101Sstever@eecs.umich.edu __metaclass__ = MetaRange 4043101Sstever@eecs.umich.edu type = Int # default; can be overridden in subclasses 4053101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 4063101Sstever@eecs.umich.edu def handle_kwargs(self, kwargs): 4073101Sstever@eecs.umich.edu if 'end' in kwargs: 4083101Sstever@eecs.umich.edu self.second = self.type(kwargs.pop('end')) 4093101Sstever@eecs.umich.edu elif 'size' in kwargs: 4103101Sstever@eecs.umich.edu self.second = self.first + self.type(kwargs.pop('size')) - 1 4113101Sstever@eecs.umich.edu else: 4123101Sstever@eecs.umich.edu raise TypeError, "Either end or size must be specified" 4133101Sstever@eecs.umich.edu 4143101Sstever@eecs.umich.edu if len(args) == 0: 4153101Sstever@eecs.umich.edu self.first = self.type(kwargs.pop('start')) 4163101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 4173101Sstever@eecs.umich.edu 4183101Sstever@eecs.umich.edu elif len(args) == 1: 4193101Sstever@eecs.umich.edu if kwargs: 4203101Sstever@eecs.umich.edu self.first = self.type(args[0]) 4213101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 4223101Sstever@eecs.umich.edu elif isinstance(args[0], Range): 4233101Sstever@eecs.umich.edu self.first = self.type(args[0].first) 4243101Sstever@eecs.umich.edu self.second = self.type(args[0].second) 4253101Sstever@eecs.umich.edu else: 4263101Sstever@eecs.umich.edu self.first = self.type(0) 4273101Sstever@eecs.umich.edu self.second = self.type(args[0]) - 1 4283101Sstever@eecs.umich.edu 4293101Sstever@eecs.umich.edu elif len(args) == 2: 4303101Sstever@eecs.umich.edu self.first = self.type(args[0]) 4313101Sstever@eecs.umich.edu self.second = self.type(args[1]) 4323101Sstever@eecs.umich.edu else: 4333101Sstever@eecs.umich.edu raise TypeError, "Too many arguments specified" 4343101Sstever@eecs.umich.edu 4353101Sstever@eecs.umich.edu if kwargs: 4363101Sstever@eecs.umich.edu raise TypeError, "too many keywords: %s" % kwargs.keys() 4373101Sstever@eecs.umich.edu 4383101Sstever@eecs.umich.edu def __str__(self): 4393101Sstever@eecs.umich.edu return '%s:%s' % (self.first, self.second) 4403101Sstever@eecs.umich.edu 4413101Sstever@eecs.umich.educlass AddrRange(Range): 4423101Sstever@eecs.umich.edu type = Addr 4433101Sstever@eecs.umich.edu 4443101Sstever@eecs.umich.educlass TickRange(Range): 4453101Sstever@eecs.umich.edu type = Tick 4463101Sstever@eecs.umich.edu 4473101Sstever@eecs.umich.edu# Boolean parameter type. Python doesn't let you subclass bool, since 4483101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and 4493101Sstever@eecs.umich.edu# False. Thus this is a little more complicated than String. 4503101Sstever@eecs.umich.educlass Bool(ParamValue): 4513101Sstever@eecs.umich.edu cxx_type = 'bool' 4523101Sstever@eecs.umich.edu def __init__(self, value): 4533101Sstever@eecs.umich.edu try: 4543102Sstever@eecs.umich.edu self.value = convert.toBool(value) 4553101Sstever@eecs.umich.edu except TypeError: 4563101Sstever@eecs.umich.edu self.value = bool(value) 4573101Sstever@eecs.umich.edu 4583101Sstever@eecs.umich.edu def __str__(self): 4593101Sstever@eecs.umich.edu return str(self.value) 4603101Sstever@eecs.umich.edu 4613101Sstever@eecs.umich.edu def ini_str(self): 4623101Sstever@eecs.umich.edu if self.value: 4633101Sstever@eecs.umich.edu return 'true' 4643101Sstever@eecs.umich.edu return 'false' 4653101Sstever@eecs.umich.edu 4663101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1): 4673101Sstever@eecs.umich.edu bytes = map(lambda x: int(x, 16), addr.split(':')) 4683101Sstever@eecs.umich.edu bytes[5] += val 4693101Sstever@eecs.umich.edu for i in (5, 4, 3, 2, 1): 4703101Sstever@eecs.umich.edu val,rem = divmod(bytes[i], 256) 4713101Sstever@eecs.umich.edu bytes[i] = rem 4723101Sstever@eecs.umich.edu if val == 0: 4733101Sstever@eecs.umich.edu break 4743101Sstever@eecs.umich.edu bytes[i - 1] += val 4753101Sstever@eecs.umich.edu assert(bytes[0] <= 255) 4763101Sstever@eecs.umich.edu return ':'.join(map(lambda x: '%02x' % x, bytes)) 4773101Sstever@eecs.umich.edu 4783101Sstever@eecs.umich.educlass NextEthernetAddr(object): 4793101Sstever@eecs.umich.edu addr = "00:90:00:00:00:01" 4803101Sstever@eecs.umich.edu 4813101Sstever@eecs.umich.edu def __init__(self, inc = 1): 4823101Sstever@eecs.umich.edu self.value = NextEthernetAddr.addr 4833101Sstever@eecs.umich.edu NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) 4843101Sstever@eecs.umich.edu 4853101Sstever@eecs.umich.educlass EthernetAddr(ParamValue): 4863101Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 4873101Sstever@eecs.umich.edu cxx_predecls = ['#include "base/inet.hh"'] 4883101Sstever@eecs.umich.edu swig_predecls = ['class Net::EthAddr;'] 4893101Sstever@eecs.umich.edu def __init__(self, value): 4903101Sstever@eecs.umich.edu if value == NextEthernetAddr: 4913101Sstever@eecs.umich.edu self.value = value 4923101Sstever@eecs.umich.edu return 4933101Sstever@eecs.umich.edu 4943101Sstever@eecs.umich.edu if not isinstance(value, str): 4953101Sstever@eecs.umich.edu raise TypeError, "expected an ethernet address and didn't get one" 4963101Sstever@eecs.umich.edu 4973101Sstever@eecs.umich.edu bytes = value.split(':') 4983101Sstever@eecs.umich.edu if len(bytes) != 6: 4993101Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 5003101Sstever@eecs.umich.edu 5013101Sstever@eecs.umich.edu for byte in bytes: 5023101Sstever@eecs.umich.edu if not 0 <= int(byte) <= 256: 5033101Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 5043101Sstever@eecs.umich.edu 5053101Sstever@eecs.umich.edu self.value = value 5063101Sstever@eecs.umich.edu 5073101Sstever@eecs.umich.edu def unproxy(self, base): 5083101Sstever@eecs.umich.edu if self.value == NextEthernetAddr: 5093101Sstever@eecs.umich.edu self.addr = self.value().value 5103101Sstever@eecs.umich.edu return self 5113101Sstever@eecs.umich.edu 5123101Sstever@eecs.umich.edu def __str__(self): 5133101Sstever@eecs.umich.edu if self.value == NextEthernetAddr: 5143101Sstever@eecs.umich.edu if hasattr(self, 'addr'): 5153101Sstever@eecs.umich.edu return self.addr 5163101Sstever@eecs.umich.edu else: 5173101Sstever@eecs.umich.edu return "NextEthernetAddr (unresolved)" 5183101Sstever@eecs.umich.edu else: 5193101Sstever@eecs.umich.edu return self.value 5203101Sstever@eecs.umich.edu 5213932Sbinkertn@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y", 5223932Sbinkertn@umich.edu "%a %b %d %H:%M:%S %Z %Y", 5233932Sbinkertn@umich.edu "%Y/%m/%d %H:%M:%S", 5243932Sbinkertn@umich.edu "%Y/%m/%d %H:%M", 5253932Sbinkertn@umich.edu "%Y/%m/%d", 5263932Sbinkertn@umich.edu "%m/%d/%Y %H:%M:%S", 5273932Sbinkertn@umich.edu "%m/%d/%Y %H:%M", 5283932Sbinkertn@umich.edu "%m/%d/%Y", 5293932Sbinkertn@umich.edu "%m/%d/%y %H:%M:%S", 5303932Sbinkertn@umich.edu "%m/%d/%y %H:%M", 5313932Sbinkertn@umich.edu "%m/%d/%y"] 5323932Sbinkertn@umich.edu 5333932Sbinkertn@umich.edu 5343885Sbinkertn@umich.edudef parse_time(value): 5353932Sbinkertn@umich.edu from time import gmtime, strptime, struct_time, time 5363932Sbinkertn@umich.edu from datetime import datetime, date 5373885Sbinkertn@umich.edu 5383932Sbinkertn@umich.edu if isinstance(value, struct_time): 5393932Sbinkertn@umich.edu return value 5403932Sbinkertn@umich.edu 5413932Sbinkertn@umich.edu if isinstance(value, (int, long)): 5423932Sbinkertn@umich.edu return gmtime(value) 5433932Sbinkertn@umich.edu 5443932Sbinkertn@umich.edu if isinstance(value, (datetime, date)): 5453932Sbinkertn@umich.edu return value.timetuple() 5463932Sbinkertn@umich.edu 5473932Sbinkertn@umich.edu if isinstance(value, str): 5483932Sbinkertn@umich.edu if value in ('Now', 'Today'): 5493932Sbinkertn@umich.edu return time.gmtime(time.time()) 5503932Sbinkertn@umich.edu 5513932Sbinkertn@umich.edu for format in time_formats: 5523932Sbinkertn@umich.edu try: 5533932Sbinkertn@umich.edu return strptime(value, format) 5543932Sbinkertn@umich.edu except ValueError: 5553932Sbinkertn@umich.edu pass 5563885Sbinkertn@umich.edu 5573885Sbinkertn@umich.edu raise ValueError, "Could not parse '%s' as a time" % value 5583885Sbinkertn@umich.edu 5593885Sbinkertn@umich.educlass Time(ParamValue): 5603885Sbinkertn@umich.edu cxx_type = 'time_t' 5613885Sbinkertn@umich.edu def __init__(self, value): 5623932Sbinkertn@umich.edu self.value = parse_time(value) 5633885Sbinkertn@umich.edu 5643885Sbinkertn@umich.edu def __str__(self): 5653932Sbinkertn@umich.edu tm = self.value 5663932Sbinkertn@umich.edu return ' '.join([ str(tm[i]) for i in xrange(8)]) 5673885Sbinkertn@umich.edu 5683885Sbinkertn@umich.edu def ini_str(self): 5693932Sbinkertn@umich.edu return str(self) 5703885Sbinkertn@umich.edu 5713101Sstever@eecs.umich.edu# Enumerated types are a little more complex. The user specifies the 5723101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of 5733101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so). (In the 5743101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index 5753101Sstever@eecs.umich.edu# or the corresponding dictionary value. For now, since we only check 5763101Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file, 5773101Sstever@eecs.umich.edu# there's not much point in using the dictionary.) 5783101Sstever@eecs.umich.edu 5793101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the 5803101Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter 5813101Sstever@eecs.umich.edu# can be instances of that type. We define two hidden internal 5823101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then 5833101Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly. 5843101Sstever@eecs.umich.edu 5853101Sstever@eecs.umich.edu 5863101Sstever@eecs.umich.edu# Metaclass for Enum types 5873101Sstever@eecs.umich.educlass MetaEnum(type): 5883101Sstever@eecs.umich.edu def __init__(cls, name, bases, init_dict): 5893101Sstever@eecs.umich.edu if init_dict.has_key('map'): 5903101Sstever@eecs.umich.edu if not isinstance(cls.map, dict): 5913101Sstever@eecs.umich.edu raise TypeError, "Enum-derived class attribute 'map' " \ 5923101Sstever@eecs.umich.edu "must be of type dict" 5933101Sstever@eecs.umich.edu # build list of value strings from map 5943101Sstever@eecs.umich.edu cls.vals = cls.map.keys() 5953101Sstever@eecs.umich.edu cls.vals.sort() 5963101Sstever@eecs.umich.edu elif init_dict.has_key('vals'): 5973101Sstever@eecs.umich.edu if not isinstance(cls.vals, list): 5983101Sstever@eecs.umich.edu raise TypeError, "Enum-derived class attribute 'vals' " \ 5993101Sstever@eecs.umich.edu "must be of type list" 6003101Sstever@eecs.umich.edu # build string->value map from vals sequence 6013101Sstever@eecs.umich.edu cls.map = {} 6023101Sstever@eecs.umich.edu for idx,val in enumerate(cls.vals): 6033101Sstever@eecs.umich.edu cls.map[val] = idx 6043101Sstever@eecs.umich.edu else: 6053101Sstever@eecs.umich.edu raise TypeError, "Enum-derived class must define "\ 6063101Sstever@eecs.umich.edu "attribute 'map' or 'vals'" 6073101Sstever@eecs.umich.edu 6083101Sstever@eecs.umich.edu cls.cxx_type = name + '::Enum' 6093101Sstever@eecs.umich.edu 6103101Sstever@eecs.umich.edu super(MetaEnum, cls).__init__(name, bases, init_dict) 6113101Sstever@eecs.umich.edu 6123101Sstever@eecs.umich.edu # Generate C++ class declaration for this enum type. 6133101Sstever@eecs.umich.edu # Note that we wrap the enum in a class/struct to act as a namespace, 6143101Sstever@eecs.umich.edu # so that the enum strings can be brief w/o worrying about collisions. 6153101Sstever@eecs.umich.edu def cxx_decl(cls): 6163101Sstever@eecs.umich.edu s = 'struct %s {\n enum Enum {\n ' % cls.__name__ 6173101Sstever@eecs.umich.edu s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) 6183101Sstever@eecs.umich.edu s += '\n };\n};\n' 6193101Sstever@eecs.umich.edu return s 6203101Sstever@eecs.umich.edu 6213101Sstever@eecs.umich.edu# Base class for enum types. 6223101Sstever@eecs.umich.educlass Enum(ParamValue): 6233101Sstever@eecs.umich.edu __metaclass__ = MetaEnum 6243101Sstever@eecs.umich.edu vals = [] 6253101Sstever@eecs.umich.edu 6263101Sstever@eecs.umich.edu def __init__(self, value): 6273101Sstever@eecs.umich.edu if value not in self.map: 6283101Sstever@eecs.umich.edu raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 6293101Sstever@eecs.umich.edu % (value, self.vals) 6303101Sstever@eecs.umich.edu self.value = value 6313101Sstever@eecs.umich.edu 6323101Sstever@eecs.umich.edu def __str__(self): 6333101Sstever@eecs.umich.edu return self.value 6343101Sstever@eecs.umich.edu 6353101Sstever@eecs.umich.eduticks_per_sec = None 6363101Sstever@eecs.umich.edu 6373101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it? 6383101Sstever@eecs.umich.edufrequency_tolerance = 0.001 # 0.1% 6393101Sstever@eecs.umich.edu 6403101Sstever@eecs.umich.edu# convert a floting-point # of ticks to integer, and warn if rounding 6413101Sstever@eecs.umich.edu# discards too much precision 6423101Sstever@eecs.umich.edudef tick_check(float_ticks): 6433101Sstever@eecs.umich.edu if float_ticks == 0: 6443101Sstever@eecs.umich.edu return 0 6453101Sstever@eecs.umich.edu int_ticks = int(round(float_ticks)) 6463101Sstever@eecs.umich.edu err = (float_ticks - int_ticks) / float_ticks 6473101Sstever@eecs.umich.edu if err > frequency_tolerance: 6483101Sstever@eecs.umich.edu print >> sys.stderr, "Warning: rounding error > tolerance" 6493101Sstever@eecs.umich.edu print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks) 6503101Sstever@eecs.umich.edu #raise ValueError 6513101Sstever@eecs.umich.edu return int_ticks 6523101Sstever@eecs.umich.edu 6533101Sstever@eecs.umich.edudef getLatency(value): 6543101Sstever@eecs.umich.edu if isinstance(value, Latency) or isinstance(value, Clock): 6553101Sstever@eecs.umich.edu return value.value 6563101Sstever@eecs.umich.edu elif isinstance(value, Frequency) or isinstance(value, RootClock): 6573101Sstever@eecs.umich.edu return 1 / value.value 6583101Sstever@eecs.umich.edu elif isinstance(value, str): 6593101Sstever@eecs.umich.edu try: 6603102Sstever@eecs.umich.edu return convert.toLatency(value) 6613101Sstever@eecs.umich.edu except ValueError: 6623101Sstever@eecs.umich.edu try: 6633102Sstever@eecs.umich.edu return 1 / convert.toFrequency(value) 6643101Sstever@eecs.umich.edu except ValueError: 6653101Sstever@eecs.umich.edu pass # fall through 6663101Sstever@eecs.umich.edu raise ValueError, "Invalid Frequency/Latency value '%s'" % value 6673101Sstever@eecs.umich.edu 6683101Sstever@eecs.umich.edu 6693101Sstever@eecs.umich.educlass Latency(NumericParamValue): 6703101Sstever@eecs.umich.edu cxx_type = 'Tick' 6713101Sstever@eecs.umich.edu cxx_predecls = ['#include "sim/host.hh"'] 6723101Sstever@eecs.umich.edu swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 6733101Sstever@eecs.umich.edu '%import "sim/host.hh"'] 6743101Sstever@eecs.umich.edu def __init__(self, value): 6753101Sstever@eecs.umich.edu self.value = getLatency(value) 6763101Sstever@eecs.umich.edu 6773101Sstever@eecs.umich.edu def __getattr__(self, attr): 6783101Sstever@eecs.umich.edu if attr in ('latency', 'period'): 6793101Sstever@eecs.umich.edu return self 6803101Sstever@eecs.umich.edu if attr == 'frequency': 6813101Sstever@eecs.umich.edu return Frequency(self) 6823101Sstever@eecs.umich.edu raise AttributeError, "Latency object has no attribute '%s'" % attr 6833101Sstever@eecs.umich.edu 6843101Sstever@eecs.umich.edu # convert latency to ticks 6853101Sstever@eecs.umich.edu def ini_str(self): 6863101Sstever@eecs.umich.edu return str(tick_check(self.value * ticks_per_sec)) 6873101Sstever@eecs.umich.edu 6883101Sstever@eecs.umich.educlass Frequency(NumericParamValue): 6893101Sstever@eecs.umich.edu cxx_type = 'Tick' 6903101Sstever@eecs.umich.edu cxx_predecls = ['#include "sim/host.hh"'] 6913101Sstever@eecs.umich.edu swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 6923101Sstever@eecs.umich.edu '%import "sim/host.hh"'] 6933101Sstever@eecs.umich.edu def __init__(self, value): 6943101Sstever@eecs.umich.edu self.value = 1 / getLatency(value) 6953101Sstever@eecs.umich.edu 6963101Sstever@eecs.umich.edu def __getattr__(self, attr): 6973101Sstever@eecs.umich.edu if attr == 'frequency': 6983101Sstever@eecs.umich.edu return self 6993101Sstever@eecs.umich.edu if attr in ('latency', 'period'): 7003101Sstever@eecs.umich.edu return Latency(self) 7013101Sstever@eecs.umich.edu raise AttributeError, "Frequency object has no attribute '%s'" % attr 7023101Sstever@eecs.umich.edu 7033101Sstever@eecs.umich.edu # convert frequency to ticks per period 7043101Sstever@eecs.umich.edu def ini_str(self): 7053101Sstever@eecs.umich.edu return self.period.ini_str() 7063101Sstever@eecs.umich.edu 7073101Sstever@eecs.umich.edu# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz). 7083101Sstever@eecs.umich.edu# We can't inherit from Frequency because we don't want it to be directly 7093101Sstever@eecs.umich.edu# assignable to a regular Frequency parameter. 7103101Sstever@eecs.umich.educlass RootClock(ParamValue): 7113101Sstever@eecs.umich.edu cxx_type = 'Tick' 7123101Sstever@eecs.umich.edu cxx_predecls = ['#include "sim/host.hh"'] 7133101Sstever@eecs.umich.edu swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 7143101Sstever@eecs.umich.edu '%import "sim/host.hh"'] 7153101Sstever@eecs.umich.edu def __init__(self, value): 7163101Sstever@eecs.umich.edu self.value = 1 / getLatency(value) 7173101Sstever@eecs.umich.edu 7183101Sstever@eecs.umich.edu def __getattr__(self, attr): 7193101Sstever@eecs.umich.edu if attr == 'frequency': 7203101Sstever@eecs.umich.edu return Frequency(self) 7213101Sstever@eecs.umich.edu if attr in ('latency', 'period'): 7223101Sstever@eecs.umich.edu return Latency(self) 7233101Sstever@eecs.umich.edu raise AttributeError, "Frequency object has no attribute '%s'" % attr 7243101Sstever@eecs.umich.edu 7253101Sstever@eecs.umich.edu def ini_str(self): 7263101Sstever@eecs.umich.edu return str(tick_check(self.value)) 7273101Sstever@eecs.umich.edu 7283101Sstever@eecs.umich.edu# A generic frequency and/or Latency value. Value is stored as a latency, 7293101Sstever@eecs.umich.edu# but to avoid ambiguity this object does not support numeric ops (* or /). 7303101Sstever@eecs.umich.edu# An explicit conversion to a Latency or Frequency must be made first. 7313101Sstever@eecs.umich.educlass Clock(ParamValue): 7323101Sstever@eecs.umich.edu cxx_type = 'Tick' 7333101Sstever@eecs.umich.edu cxx_predecls = ['#include "sim/host.hh"'] 7343101Sstever@eecs.umich.edu swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 7353101Sstever@eecs.umich.edu '%import "sim/host.hh"'] 7363101Sstever@eecs.umich.edu def __init__(self, value): 7373101Sstever@eecs.umich.edu self.value = getLatency(value) 7383101Sstever@eecs.umich.edu 7393101Sstever@eecs.umich.edu def __getattr__(self, attr): 7403101Sstever@eecs.umich.edu if attr == 'frequency': 7413101Sstever@eecs.umich.edu return Frequency(self) 7423101Sstever@eecs.umich.edu if attr in ('latency', 'period'): 7433101Sstever@eecs.umich.edu return Latency(self) 7443101Sstever@eecs.umich.edu raise AttributeError, "Frequency object has no attribute '%s'" % attr 7453101Sstever@eecs.umich.edu 7463101Sstever@eecs.umich.edu def ini_str(self): 7473101Sstever@eecs.umich.edu return self.period.ini_str() 7483101Sstever@eecs.umich.edu 7493101Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue): 7503101Sstever@eecs.umich.edu cxx_type = 'float' 7513101Sstever@eecs.umich.edu def __new__(cls, value): 7523102Sstever@eecs.umich.edu val = convert.toNetworkBandwidth(value) / 8.0 7533101Sstever@eecs.umich.edu return super(cls, NetworkBandwidth).__new__(cls, val) 7543101Sstever@eecs.umich.edu 7553101Sstever@eecs.umich.edu def __str__(self): 7563101Sstever@eecs.umich.edu return str(self.val) 7573101Sstever@eecs.umich.edu 7583101Sstever@eecs.umich.edu def ini_str(self): 7593101Sstever@eecs.umich.edu return '%f' % (ticks_per_sec / float(self)) 7603101Sstever@eecs.umich.edu 7613101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue): 7623101Sstever@eecs.umich.edu cxx_type = 'float' 7633101Sstever@eecs.umich.edu def __new__(self, value): 7643102Sstever@eecs.umich.edu val = convert.toMemoryBandwidth(value) 7653101Sstever@eecs.umich.edu return super(cls, MemoryBandwidth).__new__(cls, val) 7663101Sstever@eecs.umich.edu 7673101Sstever@eecs.umich.edu def __str__(self): 7683101Sstever@eecs.umich.edu return str(self.val) 7693101Sstever@eecs.umich.edu 7703101Sstever@eecs.umich.edu def ini_str(self): 7713101Sstever@eecs.umich.edu return '%f' % (ticks_per_sec / float(self)) 7723101Sstever@eecs.umich.edu 7733101Sstever@eecs.umich.edu# 7743101Sstever@eecs.umich.edu# "Constants"... handy aliases for various values. 7753101Sstever@eecs.umich.edu# 7763101Sstever@eecs.umich.edu 7773102Sstever@eecs.umich.edu# Special class for NULL pointers. Note the special check in 7783102Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a 7793102Sstever@eecs.umich.edu# SimObject is required. 7803102Sstever@eecs.umich.edu# only one copy of a particular node 7813102Sstever@eecs.umich.educlass NullSimObject(object): 7823102Sstever@eecs.umich.edu __metaclass__ = Singleton 7833102Sstever@eecs.umich.edu 7843102Sstever@eecs.umich.edu def __call__(cls): 7853102Sstever@eecs.umich.edu return cls 7863102Sstever@eecs.umich.edu 7873102Sstever@eecs.umich.edu def _instantiate(self, parent = None, path = ''): 7883102Sstever@eecs.umich.edu pass 7893102Sstever@eecs.umich.edu 7903102Sstever@eecs.umich.edu def ini_str(self): 7913102Sstever@eecs.umich.edu return 'Null' 7923102Sstever@eecs.umich.edu 7933102Sstever@eecs.umich.edu def unproxy(self, base): 7943102Sstever@eecs.umich.edu return self 7953102Sstever@eecs.umich.edu 7963102Sstever@eecs.umich.edu def set_path(self, parent, name): 7973102Sstever@eecs.umich.edu pass 7983102Sstever@eecs.umich.edu def __str__(self): 7993102Sstever@eecs.umich.edu return 'Null' 8003102Sstever@eecs.umich.edu 8013102Sstever@eecs.umich.edu# The only instance you'll ever need... 8023102Sstever@eecs.umich.eduNULL = NullSimObject() 8033102Sstever@eecs.umich.edu 8043102Sstever@eecs.umich.edudef isNullPointer(value): 8053102Sstever@eecs.umich.edu return isinstance(value, NullSimObject) 8063102Sstever@eecs.umich.edu 8073101Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound. 8083101Sstever@eecs.umich.eduMaxAddr = Addr.max 8093101Sstever@eecs.umich.eduMaxTick = Tick.max 8103101Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr) 8113101Sstever@eecs.umich.edu 8123101Sstever@eecs.umich.edu 8133101Sstever@eecs.umich.edu##################################################################### 8143101Sstever@eecs.umich.edu# 8153101Sstever@eecs.umich.edu# Port objects 8163101Sstever@eecs.umich.edu# 8173101Sstever@eecs.umich.edu# Ports are used to interconnect objects in the memory system. 8183101Sstever@eecs.umich.edu# 8193101Sstever@eecs.umich.edu##################################################################### 8203101Sstever@eecs.umich.edu 8213101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a 8223101Sstever@eecs.umich.edu# particular SimObject. 8233101Sstever@eecs.umich.educlass PortRef(object): 8243105Sstever@eecs.umich.edu def __init__(self, simobj, name): 8253105Sstever@eecs.umich.edu assert(isSimObject(simobj) or isSimObjectClass(simobj)) 8263101Sstever@eecs.umich.edu self.simobj = simobj 8273101Sstever@eecs.umich.edu self.name = name 8283101Sstever@eecs.umich.edu self.peer = None # not associated with another port yet 8293101Sstever@eecs.umich.edu self.ccConnected = False # C++ port connection done? 8303105Sstever@eecs.umich.edu self.index = -1 # always -1 for non-vector ports 8313101Sstever@eecs.umich.edu 8323103Sstever@eecs.umich.edu def __str__(self): 8333105Sstever@eecs.umich.edu return '%s.%s' % (self.simobj, self.name) 8343103Sstever@eecs.umich.edu 8353105Sstever@eecs.umich.edu # for config.ini, print peer's name (not ours) 8363105Sstever@eecs.umich.edu def ini_str(self): 8373105Sstever@eecs.umich.edu return str(self.peer) 8383105Sstever@eecs.umich.edu 8393105Sstever@eecs.umich.edu def __getattr__(self, attr): 8403105Sstever@eecs.umich.edu if attr == 'peerObj': 8413105Sstever@eecs.umich.edu # shorthand for proxies 8423105Sstever@eecs.umich.edu return self.peer.simobj 8433105Sstever@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 8443105Sstever@eecs.umich.edu (self.__class__.__name__, attr) 8453105Sstever@eecs.umich.edu 8463105Sstever@eecs.umich.edu # Full connection is symmetric (both ways). Called via 8473105Sstever@eecs.umich.edu # SimObject.__setattr__ as a result of a port assignment, e.g., 8483109Sstever@eecs.umich.edu # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 8493105Sstever@eecs.umich.edu # e.g., "obj1.portA[3] = obj2.portB". 8503105Sstever@eecs.umich.edu def connect(self, other): 8513105Sstever@eecs.umich.edu if isinstance(other, VectorPortRef): 8523105Sstever@eecs.umich.edu # reference to plain VectorPort is implicit append 8533105Sstever@eecs.umich.edu other = other._get_next() 8543105Sstever@eecs.umich.edu if self.peer and not proxy.isproxy(self.peer): 8553105Sstever@eecs.umich.edu print "warning: overwriting port", self, \ 8563105Sstever@eecs.umich.edu "value", self.peer, "with", other 8573101Sstever@eecs.umich.edu self.peer = other 8583109Sstever@eecs.umich.edu if proxy.isproxy(other): 8593109Sstever@eecs.umich.edu other.set_param_desc(PortParamDesc()) 8603109Sstever@eecs.umich.edu elif isinstance(other, PortRef): 8613109Sstever@eecs.umich.edu if other.peer is not self: 8623109Sstever@eecs.umich.edu other.connect(self) 8633109Sstever@eecs.umich.edu else: 8643109Sstever@eecs.umich.edu raise TypeError, \ 8653109Sstever@eecs.umich.edu "assigning non-port reference '%s' to port '%s'" \ 8663109Sstever@eecs.umich.edu % (other, self) 8673101Sstever@eecs.umich.edu 8683105Sstever@eecs.umich.edu def clone(self, simobj, memo): 8693105Sstever@eecs.umich.edu if memo.has_key(self): 8703105Sstever@eecs.umich.edu return memo[self] 8713101Sstever@eecs.umich.edu newRef = copy.copy(self) 8723105Sstever@eecs.umich.edu memo[self] = newRef 8733105Sstever@eecs.umich.edu newRef.simobj = simobj 8743101Sstever@eecs.umich.edu assert(isSimObject(newRef.simobj)) 8753105Sstever@eecs.umich.edu if self.peer and not proxy.isproxy(self.peer): 8763179Sstever@eecs.umich.edu peerObj = self.peer.simobj(_memo=memo) 8773105Sstever@eecs.umich.edu newRef.peer = self.peer.clone(peerObj, memo) 8783105Sstever@eecs.umich.edu assert(not isinstance(newRef.peer, VectorPortRef)) 8793101Sstever@eecs.umich.edu return newRef 8803101Sstever@eecs.umich.edu 8813105Sstever@eecs.umich.edu def unproxy(self, simobj): 8823105Sstever@eecs.umich.edu assert(simobj is self.simobj) 8833105Sstever@eecs.umich.edu if proxy.isproxy(self.peer): 8843105Sstever@eecs.umich.edu try: 8853105Sstever@eecs.umich.edu realPeer = self.peer.unproxy(self.simobj) 8863105Sstever@eecs.umich.edu except: 8873105Sstever@eecs.umich.edu print "Error in unproxying port '%s' of %s" % \ 8883105Sstever@eecs.umich.edu (self.name, self.simobj.path()) 8893105Sstever@eecs.umich.edu raise 8903105Sstever@eecs.umich.edu self.connect(realPeer) 8913105Sstever@eecs.umich.edu 8923101Sstever@eecs.umich.edu # Call C++ to create corresponding port connection between C++ objects 8933101Sstever@eecs.umich.edu def ccConnect(self): 8943101Sstever@eecs.umich.edu if self.ccConnected: # already done this 8953101Sstever@eecs.umich.edu return 8963101Sstever@eecs.umich.edu peer = self.peer 8974123Sbinkertn@umich.edu internal.sim_object.connectPorts(self.simobj.getCCObject(), self.name, 8984123Sbinkertn@umich.edu self.index, peer.simobj.getCCObject(), peer.name, peer.index) 8993101Sstever@eecs.umich.edu self.ccConnected = True 9003101Sstever@eecs.umich.edu peer.ccConnected = True 9013101Sstever@eecs.umich.edu 9023105Sstever@eecs.umich.edu# A reference to an individual element of a VectorPort... much like a 9033105Sstever@eecs.umich.edu# PortRef, but has an index. 9043105Sstever@eecs.umich.educlass VectorPortElementRef(PortRef): 9053105Sstever@eecs.umich.edu def __init__(self, simobj, name, index): 9063105Sstever@eecs.umich.edu PortRef.__init__(self, simobj, name) 9073105Sstever@eecs.umich.edu self.index = index 9083105Sstever@eecs.umich.edu 9093105Sstever@eecs.umich.edu def __str__(self): 9103105Sstever@eecs.umich.edu return '%s.%s[%d]' % (self.simobj, self.name, self.index) 9113105Sstever@eecs.umich.edu 9123105Sstever@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element). 9133105Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances. 9143105Sstever@eecs.umich.educlass VectorPortRef(object): 9153105Sstever@eecs.umich.edu def __init__(self, simobj, name): 9163105Sstever@eecs.umich.edu assert(isSimObject(simobj) or isSimObjectClass(simobj)) 9173105Sstever@eecs.umich.edu self.simobj = simobj 9183105Sstever@eecs.umich.edu self.name = name 9193105Sstever@eecs.umich.edu self.elements = [] 9203105Sstever@eecs.umich.edu 9213109Sstever@eecs.umich.edu def __str__(self): 9223109Sstever@eecs.umich.edu return '%s.%s[:]' % (self.simobj, self.name) 9233109Sstever@eecs.umich.edu 9243105Sstever@eecs.umich.edu # for config.ini, print peer's name (not ours) 9253105Sstever@eecs.umich.edu def ini_str(self): 9263105Sstever@eecs.umich.edu return ' '.join([el.ini_str() for el in self.elements]) 9273105Sstever@eecs.umich.edu 9283105Sstever@eecs.umich.edu def __getitem__(self, key): 9293105Sstever@eecs.umich.edu if not isinstance(key, int): 9303105Sstever@eecs.umich.edu raise TypeError, "VectorPort index must be integer" 9313105Sstever@eecs.umich.edu if key >= len(self.elements): 9323105Sstever@eecs.umich.edu # need to extend list 9333105Sstever@eecs.umich.edu ext = [VectorPortElementRef(self.simobj, self.name, i) 9343105Sstever@eecs.umich.edu for i in range(len(self.elements), key+1)] 9353105Sstever@eecs.umich.edu self.elements.extend(ext) 9363105Sstever@eecs.umich.edu return self.elements[key] 9373105Sstever@eecs.umich.edu 9383105Sstever@eecs.umich.edu def _get_next(self): 9393105Sstever@eecs.umich.edu return self[len(self.elements)] 9403105Sstever@eecs.umich.edu 9413105Sstever@eecs.umich.edu def __setitem__(self, key, value): 9423105Sstever@eecs.umich.edu if not isinstance(key, int): 9433105Sstever@eecs.umich.edu raise TypeError, "VectorPort index must be integer" 9443105Sstever@eecs.umich.edu self[key].connect(value) 9453105Sstever@eecs.umich.edu 9463105Sstever@eecs.umich.edu def connect(self, other): 9473109Sstever@eecs.umich.edu if isinstance(other, (list, tuple)): 9483109Sstever@eecs.umich.edu # Assign list of port refs to vector port. 9493109Sstever@eecs.umich.edu # For now, append them... not sure if that's the right semantics 9503109Sstever@eecs.umich.edu # or if it should replace the current vector. 9513109Sstever@eecs.umich.edu for ref in other: 9523109Sstever@eecs.umich.edu self._get_next().connect(ref) 9533109Sstever@eecs.umich.edu else: 9543109Sstever@eecs.umich.edu # scalar assignment to plain VectorPort is implicit append 9553109Sstever@eecs.umich.edu self._get_next().connect(other) 9563109Sstever@eecs.umich.edu 9573109Sstever@eecs.umich.edu def clone(self, simobj, memo): 9583109Sstever@eecs.umich.edu if memo.has_key(self): 9593109Sstever@eecs.umich.edu return memo[self] 9603109Sstever@eecs.umich.edu newRef = copy.copy(self) 9613109Sstever@eecs.umich.edu memo[self] = newRef 9623109Sstever@eecs.umich.edu newRef.simobj = simobj 9633109Sstever@eecs.umich.edu assert(isSimObject(newRef.simobj)) 9643109Sstever@eecs.umich.edu newRef.elements = [el.clone(simobj, memo) for el in self.elements] 9653109Sstever@eecs.umich.edu return newRef 9663105Sstever@eecs.umich.edu 9673105Sstever@eecs.umich.edu def unproxy(self, simobj): 9683105Sstever@eecs.umich.edu [el.unproxy(simobj) for el in self.elements] 9693105Sstever@eecs.umich.edu 9703105Sstever@eecs.umich.edu def ccConnect(self): 9713105Sstever@eecs.umich.edu [el.ccConnect() for el in self.elements] 9723105Sstever@eecs.umich.edu 9733101Sstever@eecs.umich.edu# Port description object. Like a ParamDesc object, this represents a 9743101Sstever@eecs.umich.edu# logical port in the SimObject class, not a particular port on a 9753101Sstever@eecs.umich.edu# SimObject instance. The latter are represented by PortRef objects. 9763101Sstever@eecs.umich.educlass Port(object): 9773105Sstever@eecs.umich.edu # Port("description") or Port(default, "description") 9783105Sstever@eecs.umich.edu def __init__(self, *args): 9793105Sstever@eecs.umich.edu if len(args) == 1: 9803105Sstever@eecs.umich.edu self.desc = args[0] 9813105Sstever@eecs.umich.edu elif len(args) == 2: 9823105Sstever@eecs.umich.edu self.default = args[0] 9833105Sstever@eecs.umich.edu self.desc = args[1] 9843105Sstever@eecs.umich.edu else: 9853105Sstever@eecs.umich.edu raise TypeError, 'wrong number of arguments' 9863105Sstever@eecs.umich.edu # self.name is set by SimObject class on assignment 9873105Sstever@eecs.umich.edu # e.g., pio_port = Port("blah") sets self.name to 'pio_port' 9883101Sstever@eecs.umich.edu 9893101Sstever@eecs.umich.edu # Generate a PortRef for this port on the given SimObject with the 9903101Sstever@eecs.umich.edu # given name 9913105Sstever@eecs.umich.edu def makeRef(self, simobj): 9923105Sstever@eecs.umich.edu return PortRef(simobj, self.name) 9933101Sstever@eecs.umich.edu 9943101Sstever@eecs.umich.edu # Connect an instance of this port (on the given SimObject with 9953101Sstever@eecs.umich.edu # the given name) with the port described by the supplied PortRef 9963105Sstever@eecs.umich.edu def connect(self, simobj, ref): 9973105Sstever@eecs.umich.edu self.makeRef(simobj).connect(ref) 9983101Sstever@eecs.umich.edu 9993101Sstever@eecs.umich.edu# VectorPort description object. Like Port, but represents a vector 10003101Sstever@eecs.umich.edu# of connections (e.g., as on a Bus). 10013101Sstever@eecs.umich.educlass VectorPort(Port): 10023105Sstever@eecs.umich.edu def __init__(self, *args): 10033105Sstever@eecs.umich.edu Port.__init__(self, *args) 10043101Sstever@eecs.umich.edu self.isVec = True 10053101Sstever@eecs.umich.edu 10063105Sstever@eecs.umich.edu def makeRef(self, simobj): 10073105Sstever@eecs.umich.edu return VectorPortRef(simobj, self.name) 10083105Sstever@eecs.umich.edu 10093109Sstever@eecs.umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 10103109Sstever@eecs.umich.edu# proxy objects (via set_param_desc()) so that proxy error messages 10113109Sstever@eecs.umich.edu# make sense. 10123109Sstever@eecs.umich.educlass PortParamDesc(object): 10133109Sstever@eecs.umich.edu __metaclass__ = Singleton 10143109Sstever@eecs.umich.edu 10153109Sstever@eecs.umich.edu ptype_str = 'Port' 10163109Sstever@eecs.umich.edu ptype = Port 10173105Sstever@eecs.umich.edu 10183101Sstever@eecs.umich.edu 10193101Sstever@eecs.umich.edu__all__ = ['Param', 'VectorParam', 10203101Sstever@eecs.umich.edu 'Enum', 'Bool', 'String', 'Float', 10213101Sstever@eecs.umich.edu 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 10223101Sstever@eecs.umich.edu 'Int32', 'UInt32', 'Int64', 'UInt64', 10233101Sstever@eecs.umich.edu 'Counter', 'Addr', 'Tick', 'Percent', 10243101Sstever@eecs.umich.edu 'TcpPort', 'UdpPort', 'EthernetAddr', 10253101Sstever@eecs.umich.edu 'MemorySize', 'MemorySize32', 10263101Sstever@eecs.umich.edu 'Latency', 'Frequency', 'RootClock', 'Clock', 10273101Sstever@eecs.umich.edu 'NetworkBandwidth', 'MemoryBandwidth', 10283101Sstever@eecs.umich.edu 'Range', 'AddrRange', 'TickRange', 10293101Sstever@eecs.umich.edu 'MaxAddr', 'MaxTick', 'AllMemory', 10303885Sbinkertn@umich.edu 'Time', 10313102Sstever@eecs.umich.edu 'NextEthernetAddr', 'NULL', 10323101Sstever@eecs.umich.edu 'Port', 'VectorPort'] 10333101Sstever@eecs.umich.edu 10343101Sstever@eecs.umich.edu# see comment on imports at end of __init__.py. 10353102Sstever@eecs.umich.edufrom SimObject import isSimObject, isSimObjectSequence, isSimObjectClass 10363101Sstever@eecs.umich.eduimport proxy 10373102Sstever@eecs.umich.eduimport objects 10383624Sbinkertn@umich.eduimport internal 1039