params.py revision 9014:e22ded364548
110259SAndrew.Bardsley@arm.com# Copyright (c) 2012 ARM Limited 210259SAndrew.Bardsley@arm.com# All rights reserved. 310259SAndrew.Bardsley@arm.com# 410259SAndrew.Bardsley@arm.com# The license below extends only to copyright in the software and shall 510259SAndrew.Bardsley@arm.com# not be construed as granting a license to any other intellectual 610259SAndrew.Bardsley@arm.com# property including but not limited to intellectual property relating 710259SAndrew.Bardsley@arm.com# to a hardware implementation of the functionality of the software 810259SAndrew.Bardsley@arm.com# licensed hereunder. You may use the software subject to the license 910259SAndrew.Bardsley@arm.com# terms below provided that you ensure that this notice is replicated 1010259SAndrew.Bardsley@arm.com# unmodified and in its entirety in all distributions of the software, 1110259SAndrew.Bardsley@arm.com# modified or unmodified, in source code or in binary form. 1210259SAndrew.Bardsley@arm.com# 1310259SAndrew.Bardsley@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 1410259SAndrew.Bardsley@arm.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 1510259SAndrew.Bardsley@arm.com# All rights reserved. 1610259SAndrew.Bardsley@arm.com# 1710259SAndrew.Bardsley@arm.com# Redistribution and use in source and binary forms, with or without 1810259SAndrew.Bardsley@arm.com# modification, are permitted provided that the following conditions are 1910259SAndrew.Bardsley@arm.com# met: redistributions of source code must retain the above copyright 2010259SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer; 2110259SAndrew.Bardsley@arm.com# redistributions in binary form must reproduce the above copyright 2210259SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer in the 2310259SAndrew.Bardsley@arm.com# documentation and/or other materials provided with the distribution; 2410259SAndrew.Bardsley@arm.com# neither the name of the copyright holders nor the names of its 2510259SAndrew.Bardsley@arm.com# contributors may be used to endorse or promote products derived from 2610259SAndrew.Bardsley@arm.com# this software without specific prior written permission. 2710259SAndrew.Bardsley@arm.com# 2810259SAndrew.Bardsley@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2910259SAndrew.Bardsley@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3010259SAndrew.Bardsley@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3110259SAndrew.Bardsley@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3210259SAndrew.Bardsley@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3310259SAndrew.Bardsley@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3410259SAndrew.Bardsley@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3510259SAndrew.Bardsley@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3610259SAndrew.Bardsley@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3710259SAndrew.Bardsley@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3810259SAndrew.Bardsley@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3910259SAndrew.Bardsley@arm.com# 4010259SAndrew.Bardsley@arm.com# Authors: Steve Reinhardt 4110259SAndrew.Bardsley@arm.com# Nathan Binkert 4210259SAndrew.Bardsley@arm.com# Gabe Black 4310259SAndrew.Bardsley@arm.com# Andreas Hansson 4410259SAndrew.Bardsley@arm.com 4510259SAndrew.Bardsley@arm.com##################################################################### 4610259SAndrew.Bardsley@arm.com# 4710259SAndrew.Bardsley@arm.com# Parameter description classes 4810259SAndrew.Bardsley@arm.com# 4910259SAndrew.Bardsley@arm.com# The _params dictionary in each class maps parameter names to either 5010259SAndrew.Bardsley@arm.com# a Param or a VectorParam object. These objects contain the 5110259SAndrew.Bardsley@arm.com# parameter description string, the parameter type, and the default 5210259SAndrew.Bardsley@arm.com# value (if any). The convert() method on these objects is used to 5310259SAndrew.Bardsley@arm.com# force whatever value is assigned to the parameter to the appropriate 5410259SAndrew.Bardsley@arm.com# type. 5510259SAndrew.Bardsley@arm.com# 5610259SAndrew.Bardsley@arm.com# Note that the default values are loaded into the class's attribute 5710259SAndrew.Bardsley@arm.com# space when the parameter dictionary is initialized (in 5810259SAndrew.Bardsley@arm.com# MetaSimObject._new_param()); after that point they aren't used. 5910259SAndrew.Bardsley@arm.com# 6010259SAndrew.Bardsley@arm.com##################################################################### 6110259SAndrew.Bardsley@arm.com 6210259SAndrew.Bardsley@arm.comimport copy 6310259SAndrew.Bardsley@arm.comimport datetime 6410259SAndrew.Bardsley@arm.comimport re 6510259SAndrew.Bardsley@arm.comimport sys 6610259SAndrew.Bardsley@arm.comimport time 6710259SAndrew.Bardsley@arm.comimport math 6810259SAndrew.Bardsley@arm.com 6910259SAndrew.Bardsley@arm.comimport proxy 7010259SAndrew.Bardsley@arm.comimport ticks 7110259SAndrew.Bardsley@arm.comfrom util import * 7210259SAndrew.Bardsley@arm.com 7310259SAndrew.Bardsley@arm.comdef isSimObject(*args, **kwargs): 7410259SAndrew.Bardsley@arm.com return SimObject.isSimObject(*args, **kwargs) 7510259SAndrew.Bardsley@arm.com 7610259SAndrew.Bardsley@arm.comdef isSimObjectSequence(*args, **kwargs): 7710259SAndrew.Bardsley@arm.com return SimObject.isSimObjectSequence(*args, **kwargs) 7810259SAndrew.Bardsley@arm.com 7910259SAndrew.Bardsley@arm.comdef isSimObjectClass(*args, **kwargs): 8010259SAndrew.Bardsley@arm.com return SimObject.isSimObjectClass(*args, **kwargs) 8110259SAndrew.Bardsley@arm.com 8210259SAndrew.Bardsley@arm.comallParams = {} 8310259SAndrew.Bardsley@arm.com 8410259SAndrew.Bardsley@arm.comclass MetaParamValue(type): 8510259SAndrew.Bardsley@arm.com def __new__(mcls, name, bases, dct): 8610259SAndrew.Bardsley@arm.com cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 8710259SAndrew.Bardsley@arm.com assert name not in allParams 8810259SAndrew.Bardsley@arm.com allParams[name] = cls 8910259SAndrew.Bardsley@arm.com return cls 9010259SAndrew.Bardsley@arm.com 9110259SAndrew.Bardsley@arm.com 9210259SAndrew.Bardsley@arm.com# Dummy base class to identify types that are legitimate for SimObject 9310259SAndrew.Bardsley@arm.com# parameters. 9410259SAndrew.Bardsley@arm.comclass ParamValue(object): 9510259SAndrew.Bardsley@arm.com __metaclass__ = MetaParamValue 9610259SAndrew.Bardsley@arm.com 9710259SAndrew.Bardsley@arm.com 9810259SAndrew.Bardsley@arm.com # Generate the code needed as a prerequisite for declaring a C++ 9910259SAndrew.Bardsley@arm.com # object of this type. Typically generates one or more #include 10010259SAndrew.Bardsley@arm.com # statements. Used when declaring parameters of this type. 10110259SAndrew.Bardsley@arm.com @classmethod 10210259SAndrew.Bardsley@arm.com def cxx_predecls(cls, code): 10310259SAndrew.Bardsley@arm.com pass 10410259SAndrew.Bardsley@arm.com 10510259SAndrew.Bardsley@arm.com # Generate the code needed as a prerequisite for including a 10610259SAndrew.Bardsley@arm.com # reference to a C++ object of this type in a SWIG .i file. 10710259SAndrew.Bardsley@arm.com # Typically generates one or more %import or %include statements. 10810259SAndrew.Bardsley@arm.com @classmethod 10910259SAndrew.Bardsley@arm.com def swig_predecls(cls, code): 11010259SAndrew.Bardsley@arm.com pass 11110259SAndrew.Bardsley@arm.com 11210259SAndrew.Bardsley@arm.com # default for printing to .ini file is regular string conversion. 11310259SAndrew.Bardsley@arm.com # will be overridden in some cases 11410259SAndrew.Bardsley@arm.com def ini_str(self): 11510259SAndrew.Bardsley@arm.com return str(self) 11610259SAndrew.Bardsley@arm.com 11710259SAndrew.Bardsley@arm.com # allows us to blithely call unproxy() on things without checking 11810259SAndrew.Bardsley@arm.com # if they're really proxies or not 11910259SAndrew.Bardsley@arm.com def unproxy(self, base): 12010259SAndrew.Bardsley@arm.com return self 12110259SAndrew.Bardsley@arm.com 12210259SAndrew.Bardsley@arm.com# Regular parameter description. 12310259SAndrew.Bardsley@arm.comclass ParamDesc(object): 12410259SAndrew.Bardsley@arm.com def __init__(self, ptype_str, ptype, *args, **kwargs): 12510259SAndrew.Bardsley@arm.com self.ptype_str = ptype_str 12610259SAndrew.Bardsley@arm.com # remember ptype only if it is provided 12710259SAndrew.Bardsley@arm.com if ptype != None: 12810259SAndrew.Bardsley@arm.com self.ptype = ptype 12910259SAndrew.Bardsley@arm.com 13010259SAndrew.Bardsley@arm.com if args: 13110259SAndrew.Bardsley@arm.com if len(args) == 1: 13210259SAndrew.Bardsley@arm.com self.desc = args[0] 13310259SAndrew.Bardsley@arm.com elif len(args) == 2: 13410259SAndrew.Bardsley@arm.com self.default = args[0] 13510259SAndrew.Bardsley@arm.com self.desc = args[1] 13610259SAndrew.Bardsley@arm.com else: 13710259SAndrew.Bardsley@arm.com raise TypeError, 'too many arguments' 13810259SAndrew.Bardsley@arm.com 13910259SAndrew.Bardsley@arm.com if kwargs.has_key('desc'): 14010259SAndrew.Bardsley@arm.com assert(not hasattr(self, 'desc')) 14110259SAndrew.Bardsley@arm.com self.desc = kwargs['desc'] 14210259SAndrew.Bardsley@arm.com del kwargs['desc'] 14310259SAndrew.Bardsley@arm.com 14410259SAndrew.Bardsley@arm.com if kwargs.has_key('default'): 14510259SAndrew.Bardsley@arm.com assert(not hasattr(self, 'default')) 14610259SAndrew.Bardsley@arm.com self.default = kwargs['default'] 14710259SAndrew.Bardsley@arm.com del kwargs['default'] 14810259SAndrew.Bardsley@arm.com 14910259SAndrew.Bardsley@arm.com if kwargs: 15010259SAndrew.Bardsley@arm.com raise TypeError, 'extra unknown kwargs %s' % kwargs 15110259SAndrew.Bardsley@arm.com 15210259SAndrew.Bardsley@arm.com if not hasattr(self, 'desc'): 15310259SAndrew.Bardsley@arm.com raise TypeError, 'desc attribute missing' 15410259SAndrew.Bardsley@arm.com 15510259SAndrew.Bardsley@arm.com def __getattr__(self, attr): 15610259SAndrew.Bardsley@arm.com if attr == 'ptype': 15710259SAndrew.Bardsley@arm.com ptype = SimObject.allClasses[self.ptype_str] 15810259SAndrew.Bardsley@arm.com assert isSimObjectClass(ptype) 15910259SAndrew.Bardsley@arm.com self.ptype = ptype 16010259SAndrew.Bardsley@arm.com return ptype 16110259SAndrew.Bardsley@arm.com 16210259SAndrew.Bardsley@arm.com raise AttributeError, "'%s' object has no attribute '%s'" % \ 16310259SAndrew.Bardsley@arm.com (type(self).__name__, attr) 16410259SAndrew.Bardsley@arm.com 16510259SAndrew.Bardsley@arm.com def convert(self, value): 16610259SAndrew.Bardsley@arm.com if isinstance(value, proxy.BaseProxy): 16710259SAndrew.Bardsley@arm.com value.set_param_desc(self) 16810259SAndrew.Bardsley@arm.com return value 16910259SAndrew.Bardsley@arm.com if not hasattr(self, 'ptype') and isNullPointer(value): 17010259SAndrew.Bardsley@arm.com # deferred evaluation of SimObject; continue to defer if 17110259SAndrew.Bardsley@arm.com # we're just assigning a null pointer 17210259SAndrew.Bardsley@arm.com return value 17310259SAndrew.Bardsley@arm.com if isinstance(value, self.ptype): 17410259SAndrew.Bardsley@arm.com return value 17510259SAndrew.Bardsley@arm.com if isNullPointer(value) and isSimObjectClass(self.ptype): 17610259SAndrew.Bardsley@arm.com return value 17710259SAndrew.Bardsley@arm.com return self.ptype(value) 17810259SAndrew.Bardsley@arm.com 17910259SAndrew.Bardsley@arm.com def cxx_predecls(self, code): 18010259SAndrew.Bardsley@arm.com code('#include <cstddef>') 18110259SAndrew.Bardsley@arm.com self.ptype.cxx_predecls(code) 18210259SAndrew.Bardsley@arm.com 18310259SAndrew.Bardsley@arm.com def swig_predecls(self, code): 18410259SAndrew.Bardsley@arm.com self.ptype.swig_predecls(code) 18510259SAndrew.Bardsley@arm.com 18610259SAndrew.Bardsley@arm.com def cxx_decl(self, code): 18710259SAndrew.Bardsley@arm.com code('${{self.ptype.cxx_type}} ${{self.name}};') 18810259SAndrew.Bardsley@arm.com 18910259SAndrew.Bardsley@arm.com# Vector-valued parameter description. Just like ParamDesc, except 19010259SAndrew.Bardsley@arm.com# that the value is a vector (list) of the specified type instead of a 19110259SAndrew.Bardsley@arm.com# single value. 19210259SAndrew.Bardsley@arm.com 19310259SAndrew.Bardsley@arm.comclass VectorParamValue(list): 19410259SAndrew.Bardsley@arm.com __metaclass__ = MetaParamValue 19510259SAndrew.Bardsley@arm.com def __setattr__(self, attr, value): 19610259SAndrew.Bardsley@arm.com raise AttributeError, \ 19710259SAndrew.Bardsley@arm.com "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 19810259SAndrew.Bardsley@arm.com 19910259SAndrew.Bardsley@arm.com def ini_str(self): 20010259SAndrew.Bardsley@arm.com return ' '.join([v.ini_str() for v in self]) 20110259SAndrew.Bardsley@arm.com 20210259SAndrew.Bardsley@arm.com def getValue(self): 20310259SAndrew.Bardsley@arm.com return [ v.getValue() for v in self ] 20410259SAndrew.Bardsley@arm.com 20510259SAndrew.Bardsley@arm.com def unproxy(self, base): 20610259SAndrew.Bardsley@arm.com if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 20710259SAndrew.Bardsley@arm.com return self[0].unproxy(base) 20810259SAndrew.Bardsley@arm.com else: 20910259SAndrew.Bardsley@arm.com return [v.unproxy(base) for v in self] 21010259SAndrew.Bardsley@arm.com 21110259SAndrew.Bardsley@arm.comclass SimObjectVector(VectorParamValue): 21210259SAndrew.Bardsley@arm.com # support clone operation 21310259SAndrew.Bardsley@arm.com def __call__(self, **kwargs): 21410259SAndrew.Bardsley@arm.com return SimObjectVector([v(**kwargs) for v in self]) 21510259SAndrew.Bardsley@arm.com 21610259SAndrew.Bardsley@arm.com def clear_parent(self, old_parent): 21710259SAndrew.Bardsley@arm.com for v in self: 21810259SAndrew.Bardsley@arm.com v.clear_parent(old_parent) 21910259SAndrew.Bardsley@arm.com 22010259SAndrew.Bardsley@arm.com def set_parent(self, parent, name): 22110259SAndrew.Bardsley@arm.com if len(self) == 1: 22212104Snathanael.premillieu@arm.com self[0].set_parent(parent, name) 22310259SAndrew.Bardsley@arm.com else: 22410259SAndrew.Bardsley@arm.com width = int(math.ceil(math.log(len(self))/math.log(10))) 22510259SAndrew.Bardsley@arm.com for i,v in enumerate(self): 22610259SAndrew.Bardsley@arm.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 22710259SAndrew.Bardsley@arm.com 22810259SAndrew.Bardsley@arm.com def has_parent(self): 22910259SAndrew.Bardsley@arm.com return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 23010259SAndrew.Bardsley@arm.com 23110259SAndrew.Bardsley@arm.com # return 'cpu0 cpu1' etc. for print_ini() 23212420Sgabeblack@google.com def get_name(self): 23310259SAndrew.Bardsley@arm.com return ' '.join([v._name for v in self]) 23410259SAndrew.Bardsley@arm.com 23510259SAndrew.Bardsley@arm.com # By iterating through the constituent members of the vector here 23610259SAndrew.Bardsley@arm.com # we can nicely handle iterating over all a SimObject's children 23710259SAndrew.Bardsley@arm.com # without having to provide lots of special functions on 23810259SAndrew.Bardsley@arm.com # SimObjectVector directly. 23910259SAndrew.Bardsley@arm.com def descendants(self): 24010259SAndrew.Bardsley@arm.com for v in self: 24110259SAndrew.Bardsley@arm.com for obj in v.descendants(): 24210259SAndrew.Bardsley@arm.com yield obj 24310259SAndrew.Bardsley@arm.com 24410259SAndrew.Bardsley@arm.com def get_config_as_dict(self): 24510259SAndrew.Bardsley@arm.com a = [] 24610259SAndrew.Bardsley@arm.com for v in self: 24710259SAndrew.Bardsley@arm.com a.append(v.get_config_as_dict()) 24810259SAndrew.Bardsley@arm.com return a 24910259SAndrew.Bardsley@arm.com 25010259SAndrew.Bardsley@arm.comclass VectorParamDesc(ParamDesc): 25110259SAndrew.Bardsley@arm.com # Convert assigned value to appropriate type. If the RHS is not a 25210259SAndrew.Bardsley@arm.com # list or tuple, it generates a single-element list. 25310259SAndrew.Bardsley@arm.com def convert(self, value): 25410259SAndrew.Bardsley@arm.com if isinstance(value, (list, tuple)): 25510259SAndrew.Bardsley@arm.com # list: coerce each element into new list 25610259SAndrew.Bardsley@arm.com tmp_list = [ ParamDesc.convert(self, v) for v in value ] 25710259SAndrew.Bardsley@arm.com else: 25810259SAndrew.Bardsley@arm.com # singleton: coerce to a single-element list 25910259SAndrew.Bardsley@arm.com tmp_list = [ ParamDesc.convert(self, value) ] 26010259SAndrew.Bardsley@arm.com 26110259SAndrew.Bardsley@arm.com if isSimObjectSequence(tmp_list): 26210259SAndrew.Bardsley@arm.com return SimObjectVector(tmp_list) 26310259SAndrew.Bardsley@arm.com else: 26410259SAndrew.Bardsley@arm.com return VectorParamValue(tmp_list) 26510259SAndrew.Bardsley@arm.com 26610259SAndrew.Bardsley@arm.com def swig_module_name(self): 26710259SAndrew.Bardsley@arm.com return "%s_vector" % self.ptype_str 26810259SAndrew.Bardsley@arm.com 26910259SAndrew.Bardsley@arm.com def swig_predecls(self, code): 27010259SAndrew.Bardsley@arm.com code('%import "${{self.swig_module_name()}}.i"') 27110259SAndrew.Bardsley@arm.com 27210259SAndrew.Bardsley@arm.com def swig_decl(self, code): 27310259SAndrew.Bardsley@arm.com code('%module(package="m5.internal") ${{self.swig_module_name()}}') 27410259SAndrew.Bardsley@arm.com code('%{') 27510259SAndrew.Bardsley@arm.com self.ptype.cxx_predecls(code) 27610259SAndrew.Bardsley@arm.com code('%}') 27710259SAndrew.Bardsley@arm.com code() 278 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 279 code('%include "std_container.i"') 280 code() 281 self.ptype.swig_predecls(code) 282 code() 283 code('%include "std_vector.i"') 284 code() 285 286 ptype = self.ptype_str 287 cxx_type = self.ptype.cxx_type 288 289 code('''\ 290%typemap(in) std::vector< $cxx_type >::value_type { 291 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 292 if (SWIG_ConvertPtr($$input, (void **)&$$1, 293 $$descriptor($cxx_type), 0) == -1) { 294 return NULL; 295 } 296 } 297} 298 299%typemap(in) std::vector< $cxx_type >::value_type * { 300 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 301 if (SWIG_ConvertPtr($$input, (void **)&$$1, 302 $$descriptor($cxx_type *), 0) == -1) { 303 return NULL; 304 } 305 } 306} 307''') 308 309 code('%template(vector_$ptype) std::vector< $cxx_type >;') 310 311 def cxx_predecls(self, code): 312 code('#include <vector>') 313 self.ptype.cxx_predecls(code) 314 315 def cxx_decl(self, code): 316 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 317 318class ParamFactory(object): 319 def __init__(self, param_desc_class, ptype_str = None): 320 self.param_desc_class = param_desc_class 321 self.ptype_str = ptype_str 322 323 def __getattr__(self, attr): 324 if self.ptype_str: 325 attr = self.ptype_str + '.' + attr 326 return ParamFactory(self.param_desc_class, attr) 327 328 # E.g., Param.Int(5, "number of widgets") 329 def __call__(self, *args, **kwargs): 330 ptype = None 331 try: 332 ptype = allParams[self.ptype_str] 333 except KeyError: 334 # if name isn't defined yet, assume it's a SimObject, and 335 # try to resolve it later 336 pass 337 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 338 339Param = ParamFactory(ParamDesc) 340VectorParam = ParamFactory(VectorParamDesc) 341 342##################################################################### 343# 344# Parameter Types 345# 346# Though native Python types could be used to specify parameter types 347# (the 'ptype' field of the Param and VectorParam classes), it's more 348# flexible to define our own set of types. This gives us more control 349# over how Python expressions are converted to values (via the 350# __init__() constructor) and how these values are printed out (via 351# the __str__() conversion method). 352# 353##################################################################### 354 355# String-valued parameter. Just mixin the ParamValue class with the 356# built-in str class. 357class String(ParamValue,str): 358 cxx_type = 'std::string' 359 360 @classmethod 361 def cxx_predecls(self, code): 362 code('#include <string>') 363 364 @classmethod 365 def swig_predecls(cls, code): 366 code('%include "std_string.i"') 367 368 def getValue(self): 369 return self 370 371# superclass for "numeric" parameter values, to emulate math 372# operations in a type-safe way. e.g., a Latency times an int returns 373# a new Latency object. 374class NumericParamValue(ParamValue): 375 def __str__(self): 376 return str(self.value) 377 378 def __float__(self): 379 return float(self.value) 380 381 def __long__(self): 382 return long(self.value) 383 384 def __int__(self): 385 return int(self.value) 386 387 # hook for bounds checking 388 def _check(self): 389 return 390 391 def __mul__(self, other): 392 newobj = self.__class__(self) 393 newobj.value *= other 394 newobj._check() 395 return newobj 396 397 __rmul__ = __mul__ 398 399 def __div__(self, other): 400 newobj = self.__class__(self) 401 newobj.value /= other 402 newobj._check() 403 return newobj 404 405 def __sub__(self, other): 406 newobj = self.__class__(self) 407 newobj.value -= other 408 newobj._check() 409 return newobj 410 411# Metaclass for bounds-checked integer parameters. See CheckedInt. 412class CheckedIntType(MetaParamValue): 413 def __init__(cls, name, bases, dict): 414 super(CheckedIntType, cls).__init__(name, bases, dict) 415 416 # CheckedInt is an abstract base class, so we actually don't 417 # want to do any processing on it... the rest of this code is 418 # just for classes that derive from CheckedInt. 419 if name == 'CheckedInt': 420 return 421 422 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 423 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 424 panic("CheckedInt subclass %s must define either\n" \ 425 " 'min' and 'max' or 'size' and 'unsigned'\n", 426 name); 427 if cls.unsigned: 428 cls.min = 0 429 cls.max = 2 ** cls.size - 1 430 else: 431 cls.min = -(2 ** (cls.size - 1)) 432 cls.max = (2 ** (cls.size - 1)) - 1 433 434# Abstract superclass for bounds-checked integer parameters. This 435# class is subclassed to generate parameter classes with specific 436# bounds. Initialization of the min and max bounds is done in the 437# metaclass CheckedIntType.__init__. 438class CheckedInt(NumericParamValue): 439 __metaclass__ = CheckedIntType 440 441 def _check(self): 442 if not self.min <= self.value <= self.max: 443 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 444 (self.min, self.value, self.max) 445 446 def __init__(self, value): 447 if isinstance(value, str): 448 self.value = convert.toInteger(value) 449 elif isinstance(value, (int, long, float, NumericParamValue)): 450 self.value = long(value) 451 else: 452 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 453 % type(value).__name__ 454 self._check() 455 456 @classmethod 457 def cxx_predecls(cls, code): 458 # most derived types require this, so we just do it here once 459 code('#include "base/types.hh"') 460 461 @classmethod 462 def swig_predecls(cls, code): 463 # most derived types require this, so we just do it here once 464 code('%import "stdint.i"') 465 code('%import "base/types.hh"') 466 467 def getValue(self): 468 return long(self.value) 469 470class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 471class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 472 473class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 474class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 475class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 476class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 477class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 478class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 479class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 480class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 481 482class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 483class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 484class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 485class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 486 487class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 488 489class Float(ParamValue, float): 490 cxx_type = 'double' 491 492 def __init__(self, value): 493 if isinstance(value, (int, long, float, NumericParamValue, Float)): 494 self.value = float(value) 495 else: 496 raise TypeError, "Can't convert object of type %s to Float" \ 497 % type(value).__name__ 498 499 def getValue(self): 500 return float(self.value) 501 502class MemorySize(CheckedInt): 503 cxx_type = 'uint64_t' 504 size = 64 505 unsigned = True 506 def __init__(self, value): 507 if isinstance(value, MemorySize): 508 self.value = value.value 509 else: 510 self.value = convert.toMemorySize(value) 511 self._check() 512 513class MemorySize32(CheckedInt): 514 cxx_type = 'uint32_t' 515 size = 32 516 unsigned = True 517 def __init__(self, value): 518 if isinstance(value, MemorySize): 519 self.value = value.value 520 else: 521 self.value = convert.toMemorySize(value) 522 self._check() 523 524class Addr(CheckedInt): 525 cxx_type = 'Addr' 526 size = 64 527 unsigned = True 528 def __init__(self, value): 529 if isinstance(value, Addr): 530 self.value = value.value 531 else: 532 try: 533 self.value = convert.toMemorySize(value) 534 except TypeError: 535 self.value = long(value) 536 self._check() 537 def __add__(self, other): 538 if isinstance(other, Addr): 539 return self.value + other.value 540 else: 541 return self.value + other 542 543 544class MetaRange(MetaParamValue): 545 def __init__(cls, name, bases, dict): 546 super(MetaRange, cls).__init__(name, bases, dict) 547 if name == 'Range': 548 return 549 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 550 551class Range(ParamValue): 552 __metaclass__ = MetaRange 553 type = Int # default; can be overridden in subclasses 554 def __init__(self, *args, **kwargs): 555 def handle_kwargs(self, kwargs): 556 if 'end' in kwargs: 557 self.second = self.type(kwargs.pop('end')) 558 elif 'size' in kwargs: 559 self.second = self.first + self.type(kwargs.pop('size')) - 1 560 else: 561 raise TypeError, "Either end or size must be specified" 562 563 if len(args) == 0: 564 self.first = self.type(kwargs.pop('start')) 565 handle_kwargs(self, kwargs) 566 567 elif len(args) == 1: 568 if kwargs: 569 self.first = self.type(args[0]) 570 handle_kwargs(self, kwargs) 571 elif isinstance(args[0], Range): 572 self.first = self.type(args[0].first) 573 self.second = self.type(args[0].second) 574 elif isinstance(args[0], (list, tuple)): 575 self.first = self.type(args[0][0]) 576 self.second = self.type(args[0][1]) 577 else: 578 self.first = self.type(0) 579 self.second = self.type(args[0]) - 1 580 581 elif len(args) == 2: 582 self.first = self.type(args[0]) 583 self.second = self.type(args[1]) 584 else: 585 raise TypeError, "Too many arguments specified" 586 587 if kwargs: 588 raise TypeError, "too many keywords: %s" % kwargs.keys() 589 590 def __str__(self): 591 return '%s:%s' % (self.first, self.second) 592 593 @classmethod 594 def cxx_predecls(cls, code): 595 cls.type.cxx_predecls(code) 596 code('#include "base/range.hh"') 597 598 @classmethod 599 def swig_predecls(cls, code): 600 cls.type.swig_predecls(code) 601 code('%import "python/swig/range.i"') 602 603class AddrRange(Range): 604 type = Addr 605 606 def getValue(self): 607 from m5.internal.range import AddrRange 608 609 value = AddrRange() 610 value.start = long(self.first) 611 value.end = long(self.second) 612 return value 613 614class TickRange(Range): 615 type = Tick 616 617 def getValue(self): 618 from m5.internal.range import TickRange 619 620 value = TickRange() 621 value.start = long(self.first) 622 value.end = long(self.second) 623 return value 624 625# Boolean parameter type. Python doesn't let you subclass bool, since 626# it doesn't want to let you create multiple instances of True and 627# False. Thus this is a little more complicated than String. 628class Bool(ParamValue): 629 cxx_type = 'bool' 630 def __init__(self, value): 631 try: 632 self.value = convert.toBool(value) 633 except TypeError: 634 self.value = bool(value) 635 636 def getValue(self): 637 return bool(self.value) 638 639 def __str__(self): 640 return str(self.value) 641 642 # implement truth value testing for Bool parameters so that these params 643 # evaluate correctly during the python configuration phase 644 def __nonzero__(self): 645 return bool(self.value) 646 647 def ini_str(self): 648 if self.value: 649 return 'true' 650 return 'false' 651 652def IncEthernetAddr(addr, val = 1): 653 bytes = map(lambda x: int(x, 16), addr.split(':')) 654 bytes[5] += val 655 for i in (5, 4, 3, 2, 1): 656 val,rem = divmod(bytes[i], 256) 657 bytes[i] = rem 658 if val == 0: 659 break 660 bytes[i - 1] += val 661 assert(bytes[0] <= 255) 662 return ':'.join(map(lambda x: '%02x' % x, bytes)) 663 664_NextEthernetAddr = "00:90:00:00:00:01" 665def NextEthernetAddr(): 666 global _NextEthernetAddr 667 668 value = _NextEthernetAddr 669 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 670 return value 671 672class EthernetAddr(ParamValue): 673 cxx_type = 'Net::EthAddr' 674 675 @classmethod 676 def cxx_predecls(cls, code): 677 code('#include "base/inet.hh"') 678 679 @classmethod 680 def swig_predecls(cls, code): 681 code('%include "python/swig/inet.i"') 682 683 def __init__(self, value): 684 if value == NextEthernetAddr: 685 self.value = value 686 return 687 688 if not isinstance(value, str): 689 raise TypeError, "expected an ethernet address and didn't get one" 690 691 bytes = value.split(':') 692 if len(bytes) != 6: 693 raise TypeError, 'invalid ethernet address %s' % value 694 695 for byte in bytes: 696 if not 0 <= int(byte) <= 0xff: 697 raise TypeError, 'invalid ethernet address %s' % value 698 699 self.value = value 700 701 def unproxy(self, base): 702 if self.value == NextEthernetAddr: 703 return EthernetAddr(self.value()) 704 return self 705 706 def getValue(self): 707 from m5.internal.params import EthAddr 708 return EthAddr(self.value) 709 710 def ini_str(self): 711 return self.value 712 713# When initializing an IpAddress, pass in an existing IpAddress, a string of 714# the form "a.b.c.d", or an integer representing an IP. 715class IpAddress(ParamValue): 716 cxx_type = 'Net::IpAddress' 717 718 @classmethod 719 def cxx_predecls(cls, code): 720 code('#include "base/inet.hh"') 721 722 @classmethod 723 def swig_predecls(cls, code): 724 code('%include "python/swig/inet.i"') 725 726 def __init__(self, value): 727 if isinstance(value, IpAddress): 728 self.ip = value.ip 729 else: 730 try: 731 self.ip = convert.toIpAddress(value) 732 except TypeError: 733 self.ip = long(value) 734 self.verifyIp() 735 736 def __str__(self): 737 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 738 return '%d.%d.%d.%d' % tuple(tup) 739 740 def __eq__(self, other): 741 if isinstance(other, IpAddress): 742 return self.ip == other.ip 743 elif isinstance(other, str): 744 try: 745 return self.ip == convert.toIpAddress(other) 746 except: 747 return False 748 else: 749 return self.ip == other 750 751 def __ne__(self, other): 752 return not (self == other) 753 754 def verifyIp(self): 755 if self.ip < 0 or self.ip >= (1 << 32): 756 raise TypeError, "invalid ip address %#08x" % self.ip 757 758 def getValue(self): 759 from m5.internal.params import IpAddress 760 return IpAddress(self.ip) 761 762# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 763# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 764# positional or keyword arguments. 765class IpNetmask(IpAddress): 766 cxx_type = 'Net::IpNetmask' 767 768 @classmethod 769 def cxx_predecls(cls, code): 770 code('#include "base/inet.hh"') 771 772 @classmethod 773 def swig_predecls(cls, code): 774 code('%include "python/swig/inet.i"') 775 776 def __init__(self, *args, **kwargs): 777 def handle_kwarg(self, kwargs, key, elseVal = None): 778 if key in kwargs: 779 setattr(self, key, kwargs.pop(key)) 780 elif elseVal: 781 setattr(self, key, elseVal) 782 else: 783 raise TypeError, "No value set for %s" % key 784 785 if len(args) == 0: 786 handle_kwarg(self, kwargs, 'ip') 787 handle_kwarg(self, kwargs, 'netmask') 788 789 elif len(args) == 1: 790 if kwargs: 791 if not 'ip' in kwargs and not 'netmask' in kwargs: 792 raise TypeError, "Invalid arguments" 793 handle_kwarg(self, kwargs, 'ip', args[0]) 794 handle_kwarg(self, kwargs, 'netmask', args[0]) 795 elif isinstance(args[0], IpNetmask): 796 self.ip = args[0].ip 797 self.netmask = args[0].netmask 798 else: 799 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 800 801 elif len(args) == 2: 802 self.ip = args[0] 803 self.netmask = args[1] 804 else: 805 raise TypeError, "Too many arguments specified" 806 807 if kwargs: 808 raise TypeError, "Too many keywords: %s" % kwargs.keys() 809 810 self.verify() 811 812 def __str__(self): 813 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 814 815 def __eq__(self, other): 816 if isinstance(other, IpNetmask): 817 return self.ip == other.ip and self.netmask == other.netmask 818 elif isinstance(other, str): 819 try: 820 return (self.ip, self.netmask) == convert.toIpNetmask(other) 821 except: 822 return False 823 else: 824 return False 825 826 def verify(self): 827 self.verifyIp() 828 if self.netmask < 0 or self.netmask > 32: 829 raise TypeError, "invalid netmask %d" % netmask 830 831 def getValue(self): 832 from m5.internal.params import IpNetmask 833 return IpNetmask(self.ip, self.netmask) 834 835# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 836# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 837class IpWithPort(IpAddress): 838 cxx_type = 'Net::IpWithPort' 839 840 @classmethod 841 def cxx_predecls(cls, code): 842 code('#include "base/inet.hh"') 843 844 @classmethod 845 def swig_predecls(cls, code): 846 code('%include "python/swig/inet.i"') 847 848 def __init__(self, *args, **kwargs): 849 def handle_kwarg(self, kwargs, key, elseVal = None): 850 if key in kwargs: 851 setattr(self, key, kwargs.pop(key)) 852 elif elseVal: 853 setattr(self, key, elseVal) 854 else: 855 raise TypeError, "No value set for %s" % key 856 857 if len(args) == 0: 858 handle_kwarg(self, kwargs, 'ip') 859 handle_kwarg(self, kwargs, 'port') 860 861 elif len(args) == 1: 862 if kwargs: 863 if not 'ip' in kwargs and not 'port' in kwargs: 864 raise TypeError, "Invalid arguments" 865 handle_kwarg(self, kwargs, 'ip', args[0]) 866 handle_kwarg(self, kwargs, 'port', args[0]) 867 elif isinstance(args[0], IpWithPort): 868 self.ip = args[0].ip 869 self.port = args[0].port 870 else: 871 (self.ip, self.port) = convert.toIpWithPort(args[0]) 872 873 elif len(args) == 2: 874 self.ip = args[0] 875 self.port = args[1] 876 else: 877 raise TypeError, "Too many arguments specified" 878 879 if kwargs: 880 raise TypeError, "Too many keywords: %s" % kwargs.keys() 881 882 self.verify() 883 884 def __str__(self): 885 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 886 887 def __eq__(self, other): 888 if isinstance(other, IpWithPort): 889 return self.ip == other.ip and self.port == other.port 890 elif isinstance(other, str): 891 try: 892 return (self.ip, self.port) == convert.toIpWithPort(other) 893 except: 894 return False 895 else: 896 return False 897 898 def verify(self): 899 self.verifyIp() 900 if self.port < 0 or self.port > 0xffff: 901 raise TypeError, "invalid port %d" % self.port 902 903 def getValue(self): 904 from m5.internal.params import IpWithPort 905 return IpWithPort(self.ip, self.port) 906 907time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 908 "%a %b %d %H:%M:%S %Z %Y", 909 "%Y/%m/%d %H:%M:%S", 910 "%Y/%m/%d %H:%M", 911 "%Y/%m/%d", 912 "%m/%d/%Y %H:%M:%S", 913 "%m/%d/%Y %H:%M", 914 "%m/%d/%Y", 915 "%m/%d/%y %H:%M:%S", 916 "%m/%d/%y %H:%M", 917 "%m/%d/%y"] 918 919 920def parse_time(value): 921 from time import gmtime, strptime, struct_time, time 922 from datetime import datetime, date 923 924 if isinstance(value, struct_time): 925 return value 926 927 if isinstance(value, (int, long)): 928 return gmtime(value) 929 930 if isinstance(value, (datetime, date)): 931 return value.timetuple() 932 933 if isinstance(value, str): 934 if value in ('Now', 'Today'): 935 return time.gmtime(time.time()) 936 937 for format in time_formats: 938 try: 939 return strptime(value, format) 940 except ValueError: 941 pass 942 943 raise ValueError, "Could not parse '%s' as a time" % value 944 945class Time(ParamValue): 946 cxx_type = 'tm' 947 948 @classmethod 949 def cxx_predecls(cls, code): 950 code('#include <time.h>') 951 952 @classmethod 953 def swig_predecls(cls, code): 954 code('%include "python/swig/time.i"') 955 956 def __init__(self, value): 957 self.value = parse_time(value) 958 959 def getValue(self): 960 from m5.internal.params import tm 961 962 c_time = tm() 963 py_time = self.value 964 965 # UNIX is years since 1900 966 c_time.tm_year = py_time.tm_year - 1900; 967 968 # Python starts at 1, UNIX starts at 0 969 c_time.tm_mon = py_time.tm_mon - 1; 970 c_time.tm_mday = py_time.tm_mday; 971 c_time.tm_hour = py_time.tm_hour; 972 c_time.tm_min = py_time.tm_min; 973 c_time.tm_sec = py_time.tm_sec; 974 975 # Python has 0 as Monday, UNIX is 0 as sunday 976 c_time.tm_wday = py_time.tm_wday + 1 977 if c_time.tm_wday > 6: 978 c_time.tm_wday -= 7; 979 980 # Python starts at 1, Unix starts at 0 981 c_time.tm_yday = py_time.tm_yday - 1; 982 983 return c_time 984 985 def __str__(self): 986 return time.asctime(self.value) 987 988 def ini_str(self): 989 return str(self) 990 991 def get_config_as_dict(self): 992 return str(self) 993 994# Enumerated types are a little more complex. The user specifies the 995# type as Enum(foo) where foo is either a list or dictionary of 996# alternatives (typically strings, but not necessarily so). (In the 997# long run, the integer value of the parameter will be the list index 998# or the corresponding dictionary value. For now, since we only check 999# that the alternative is valid and then spit it into a .ini file, 1000# there's not much point in using the dictionary.) 1001 1002# What Enum() must do is generate a new type encapsulating the 1003# provided list/dictionary so that specific values of the parameter 1004# can be instances of that type. We define two hidden internal 1005# classes (_ListEnum and _DictEnum) to serve as base classes, then 1006# derive the new type from the appropriate base class on the fly. 1007 1008allEnums = {} 1009# Metaclass for Enum types 1010class MetaEnum(MetaParamValue): 1011 def __new__(mcls, name, bases, dict): 1012 assert name not in allEnums 1013 1014 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1015 allEnums[name] = cls 1016 return cls 1017 1018 def __init__(cls, name, bases, init_dict): 1019 if init_dict.has_key('map'): 1020 if not isinstance(cls.map, dict): 1021 raise TypeError, "Enum-derived class attribute 'map' " \ 1022 "must be of type dict" 1023 # build list of value strings from map 1024 cls.vals = cls.map.keys() 1025 cls.vals.sort() 1026 elif init_dict.has_key('vals'): 1027 if not isinstance(cls.vals, list): 1028 raise TypeError, "Enum-derived class attribute 'vals' " \ 1029 "must be of type list" 1030 # build string->value map from vals sequence 1031 cls.map = {} 1032 for idx,val in enumerate(cls.vals): 1033 cls.map[val] = idx 1034 else: 1035 raise TypeError, "Enum-derived class must define "\ 1036 "attribute 'map' or 'vals'" 1037 1038 cls.cxx_type = 'Enums::%s' % name 1039 1040 super(MetaEnum, cls).__init__(name, bases, init_dict) 1041 1042 # Generate C++ class declaration for this enum type. 1043 # Note that we wrap the enum in a class/struct to act as a namespace, 1044 # so that the enum strings can be brief w/o worrying about collisions. 1045 def cxx_decl(cls, code): 1046 name = cls.__name__ 1047 code('''\ 1048#ifndef __ENUM__${name}__ 1049#define __ENUM__${name}__ 1050 1051namespace Enums { 1052 enum $name { 1053''') 1054 code.indent(2) 1055 for val in cls.vals: 1056 code('$val = ${{cls.map[val]}},') 1057 code('Num_$name = ${{len(cls.vals)}}') 1058 code.dedent(2) 1059 code('''\ 1060 }; 1061extern const char *${name}Strings[Num_${name}]; 1062} 1063 1064#endif // __ENUM__${name}__ 1065''') 1066 1067 def cxx_def(cls, code): 1068 name = cls.__name__ 1069 code('''\ 1070#include "enums/$name.hh" 1071namespace Enums { 1072 const char *${name}Strings[Num_${name}] = 1073 { 1074''') 1075 code.indent(2) 1076 for val in cls.vals: 1077 code('"$val",') 1078 code.dedent(2) 1079 code(''' 1080 }; 1081} // namespace Enums 1082''') 1083 1084 def swig_decl(cls, code): 1085 name = cls.__name__ 1086 code('''\ 1087%module(package="m5.internal") enum_$name 1088 1089%{ 1090#include "enums/$name.hh" 1091%} 1092 1093%include "enums/$name.hh" 1094''') 1095 1096 1097# Base class for enum types. 1098class Enum(ParamValue): 1099 __metaclass__ = MetaEnum 1100 vals = [] 1101 1102 def __init__(self, value): 1103 if value not in self.map: 1104 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1105 % (value, self.vals) 1106 self.value = value 1107 1108 @classmethod 1109 def cxx_predecls(cls, code): 1110 code('#include "enums/$0.hh"', cls.__name__) 1111 1112 @classmethod 1113 def swig_predecls(cls, code): 1114 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1115 1116 def getValue(self): 1117 return int(self.map[self.value]) 1118 1119 def __str__(self): 1120 return self.value 1121 1122# how big does a rounding error need to be before we warn about it? 1123frequency_tolerance = 0.001 # 0.1% 1124 1125class TickParamValue(NumericParamValue): 1126 cxx_type = 'Tick' 1127 1128 @classmethod 1129 def cxx_predecls(cls, code): 1130 code('#include "base/types.hh"') 1131 1132 @classmethod 1133 def swig_predecls(cls, code): 1134 code('%import "stdint.i"') 1135 code('%import "base/types.hh"') 1136 1137 def getValue(self): 1138 return long(self.value) 1139 1140class Latency(TickParamValue): 1141 def __init__(self, value): 1142 if isinstance(value, (Latency, Clock)): 1143 self.ticks = value.ticks 1144 self.value = value.value 1145 elif isinstance(value, Frequency): 1146 self.ticks = value.ticks 1147 self.value = 1.0 / value.value 1148 elif value.endswith('t'): 1149 self.ticks = True 1150 self.value = int(value[:-1]) 1151 else: 1152 self.ticks = False 1153 self.value = convert.toLatency(value) 1154 1155 def __getattr__(self, attr): 1156 if attr in ('latency', 'period'): 1157 return self 1158 if attr == 'frequency': 1159 return Frequency(self) 1160 raise AttributeError, "Latency object has no attribute '%s'" % attr 1161 1162 def getValue(self): 1163 if self.ticks or self.value == 0: 1164 value = self.value 1165 else: 1166 value = ticks.fromSeconds(self.value) 1167 return long(value) 1168 1169 # convert latency to ticks 1170 def ini_str(self): 1171 return '%d' % self.getValue() 1172 1173class Frequency(TickParamValue): 1174 def __init__(self, value): 1175 if isinstance(value, (Latency, Clock)): 1176 if value.value == 0: 1177 self.value = 0 1178 else: 1179 self.value = 1.0 / value.value 1180 self.ticks = value.ticks 1181 elif isinstance(value, Frequency): 1182 self.value = value.value 1183 self.ticks = value.ticks 1184 else: 1185 self.ticks = False 1186 self.value = convert.toFrequency(value) 1187 1188 def __getattr__(self, attr): 1189 if attr == 'frequency': 1190 return self 1191 if attr in ('latency', 'period'): 1192 return Latency(self) 1193 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1194 1195 # convert latency to ticks 1196 def getValue(self): 1197 if self.ticks or self.value == 0: 1198 value = self.value 1199 else: 1200 value = ticks.fromSeconds(1.0 / self.value) 1201 return long(value) 1202 1203 def ini_str(self): 1204 return '%d' % self.getValue() 1205 1206# A generic frequency and/or Latency value. Value is stored as a latency, 1207# but to avoid ambiguity this object does not support numeric ops (* or /). 1208# An explicit conversion to a Latency or Frequency must be made first. 1209class Clock(ParamValue): 1210 cxx_type = 'Tick' 1211 1212 @classmethod 1213 def cxx_predecls(cls, code): 1214 code('#include "base/types.hh"') 1215 1216 @classmethod 1217 def swig_predecls(cls, code): 1218 code('%import "stdint.i"') 1219 code('%import "base/types.hh"') 1220 1221 def __init__(self, value): 1222 if isinstance(value, (Latency, Clock)): 1223 self.ticks = value.ticks 1224 self.value = value.value 1225 elif isinstance(value, Frequency): 1226 self.ticks = value.ticks 1227 self.value = 1.0 / value.value 1228 elif value.endswith('t'): 1229 self.ticks = True 1230 self.value = int(value[:-1]) 1231 else: 1232 self.ticks = False 1233 self.value = convert.anyToLatency(value) 1234 1235 def __getattr__(self, attr): 1236 if attr == 'frequency': 1237 return Frequency(self) 1238 if attr in ('latency', 'period'): 1239 return Latency(self) 1240 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1241 1242 def getValue(self): 1243 return self.period.getValue() 1244 1245 def ini_str(self): 1246 return self.period.ini_str() 1247 1248class NetworkBandwidth(float,ParamValue): 1249 cxx_type = 'float' 1250 def __new__(cls, value): 1251 # convert to bits per second 1252 val = convert.toNetworkBandwidth(value) 1253 return super(cls, NetworkBandwidth).__new__(cls, val) 1254 1255 def __str__(self): 1256 return str(self.val) 1257 1258 def getValue(self): 1259 # convert to seconds per byte 1260 value = 8.0 / float(self) 1261 # convert to ticks per byte 1262 value = ticks.fromSeconds(value) 1263 return float(value) 1264 1265 def ini_str(self): 1266 return '%f' % self.getValue() 1267 1268class MemoryBandwidth(float,ParamValue): 1269 cxx_type = 'float' 1270 def __new__(cls, value): 1271 # convert to bytes per second 1272 val = convert.toMemoryBandwidth(value) 1273 return super(cls, MemoryBandwidth).__new__(cls, val) 1274 1275 def __str__(self): 1276 return str(self.val) 1277 1278 def getValue(self): 1279 # convert to seconds per byte 1280 value = float(self) 1281 if value: 1282 value = 1.0 / float(self) 1283 # convert to ticks per byte 1284 value = ticks.fromSeconds(value) 1285 return float(value) 1286 1287 def ini_str(self): 1288 return '%f' % self.getValue() 1289 1290# 1291# "Constants"... handy aliases for various values. 1292# 1293 1294# Special class for NULL pointers. Note the special check in 1295# make_param_value() above that lets these be assigned where a 1296# SimObject is required. 1297# only one copy of a particular node 1298class NullSimObject(object): 1299 __metaclass__ = Singleton 1300 1301 def __call__(cls): 1302 return cls 1303 1304 def _instantiate(self, parent = None, path = ''): 1305 pass 1306 1307 def ini_str(self): 1308 return 'Null' 1309 1310 def unproxy(self, base): 1311 return self 1312 1313 def set_path(self, parent, name): 1314 pass 1315 1316 def __str__(self): 1317 return 'Null' 1318 1319 def getValue(self): 1320 return None 1321 1322# The only instance you'll ever need... 1323NULL = NullSimObject() 1324 1325def isNullPointer(value): 1326 return isinstance(value, NullSimObject) 1327 1328# Some memory range specifications use this as a default upper bound. 1329MaxAddr = Addr.max 1330MaxTick = Tick.max 1331AllMemory = AddrRange(0, MaxAddr) 1332 1333 1334##################################################################### 1335# 1336# Port objects 1337# 1338# Ports are used to interconnect objects in the memory system. 1339# 1340##################################################################### 1341 1342# Port reference: encapsulates a reference to a particular port on a 1343# particular SimObject. 1344class PortRef(object): 1345 def __init__(self, simobj, name, role): 1346 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1347 self.simobj = simobj 1348 self.name = name 1349 self.role = role 1350 self.peer = None # not associated with another port yet 1351 self.ccConnected = False # C++ port connection done? 1352 self.index = -1 # always -1 for non-vector ports 1353 1354 def __str__(self): 1355 return '%s.%s' % (self.simobj, self.name) 1356 1357 def __len__(self): 1358 # Return the number of connected ports, i.e. 0 is we have no 1359 # peer and 1 if we do. 1360 return int(self.peer != None) 1361 1362 # for config.ini, print peer's name (not ours) 1363 def ini_str(self): 1364 return str(self.peer) 1365 1366 def __getattr__(self, attr): 1367 if attr == 'peerObj': 1368 # shorthand for proxies 1369 return self.peer.simobj 1370 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1371 (self.__class__.__name__, attr) 1372 1373 # Full connection is symmetric (both ways). Called via 1374 # SimObject.__setattr__ as a result of a port assignment, e.g., 1375 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1376 # e.g., "obj1.portA[3] = obj2.portB". 1377 def connect(self, other): 1378 if isinstance(other, VectorPortRef): 1379 # reference to plain VectorPort is implicit append 1380 other = other._get_next() 1381 if self.peer and not proxy.isproxy(self.peer): 1382 fatal("Port %s is already connected to %s, cannot connect %s\n", 1383 self, self.peer, other); 1384 self.peer = other 1385 if proxy.isproxy(other): 1386 other.set_param_desc(PortParamDesc()) 1387 elif isinstance(other, PortRef): 1388 if other.peer is not self: 1389 other.connect(self) 1390 else: 1391 raise TypeError, \ 1392 "assigning non-port reference '%s' to port '%s'" \ 1393 % (other, self) 1394 1395 def clone(self, simobj, memo): 1396 if memo.has_key(self): 1397 return memo[self] 1398 newRef = copy.copy(self) 1399 memo[self] = newRef 1400 newRef.simobj = simobj 1401 assert(isSimObject(newRef.simobj)) 1402 if self.peer and not proxy.isproxy(self.peer): 1403 peerObj = self.peer.simobj(_memo=memo) 1404 newRef.peer = self.peer.clone(peerObj, memo) 1405 assert(not isinstance(newRef.peer, VectorPortRef)) 1406 return newRef 1407 1408 def unproxy(self, simobj): 1409 assert(simobj is self.simobj) 1410 if proxy.isproxy(self.peer): 1411 try: 1412 realPeer = self.peer.unproxy(self.simobj) 1413 except: 1414 print "Error in unproxying port '%s' of %s" % \ 1415 (self.name, self.simobj.path()) 1416 raise 1417 self.connect(realPeer) 1418 1419 # Call C++ to create corresponding port connection between C++ objects 1420 def ccConnect(self): 1421 from m5.internal.pyobject import connectPorts 1422 1423 if self.role == 'SLAVE': 1424 # do nothing and let the master take care of it 1425 return 1426 1427 if self.ccConnected: # already done this 1428 return 1429 peer = self.peer 1430 if not self.peer: # nothing to connect to 1431 return 1432 1433 # check that we connect a master to a slave 1434 if self.role == peer.role: 1435 raise TypeError, \ 1436 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1437 % (peer, self, self.role) 1438 1439 try: 1440 # self is always the master and peer the slave 1441 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1442 peer.simobj.getCCObject(), peer.name, peer.index) 1443 except: 1444 print "Error connecting port %s.%s to %s.%s" % \ 1445 (self.simobj.path(), self.name, 1446 peer.simobj.path(), peer.name) 1447 raise 1448 self.ccConnected = True 1449 peer.ccConnected = True 1450 1451# A reference to an individual element of a VectorPort... much like a 1452# PortRef, but has an index. 1453class VectorPortElementRef(PortRef): 1454 def __init__(self, simobj, name, role, index): 1455 PortRef.__init__(self, simobj, name, role) 1456 self.index = index 1457 1458 def __str__(self): 1459 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1460 1461# A reference to a complete vector-valued port (not just a single element). 1462# Can be indexed to retrieve individual VectorPortElementRef instances. 1463class VectorPortRef(object): 1464 def __init__(self, simobj, name, role): 1465 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1466 self.simobj = simobj 1467 self.name = name 1468 self.role = role 1469 self.elements = [] 1470 1471 def __str__(self): 1472 return '%s.%s[:]' % (self.simobj, self.name) 1473 1474 def __len__(self): 1475 # Return the number of connected peers, corresponding the the 1476 # length of the elements. 1477 return len(self.elements) 1478 1479 # for config.ini, print peer's name (not ours) 1480 def ini_str(self): 1481 return ' '.join([el.ini_str() for el in self.elements]) 1482 1483 def __getitem__(self, key): 1484 if not isinstance(key, int): 1485 raise TypeError, "VectorPort index must be integer" 1486 if key >= len(self.elements): 1487 # need to extend list 1488 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1489 for i in range(len(self.elements), key+1)] 1490 self.elements.extend(ext) 1491 return self.elements[key] 1492 1493 def _get_next(self): 1494 return self[len(self.elements)] 1495 1496 def __setitem__(self, key, value): 1497 if not isinstance(key, int): 1498 raise TypeError, "VectorPort index must be integer" 1499 self[key].connect(value) 1500 1501 def connect(self, other): 1502 if isinstance(other, (list, tuple)): 1503 # Assign list of port refs to vector port. 1504 # For now, append them... not sure if that's the right semantics 1505 # or if it should replace the current vector. 1506 for ref in other: 1507 self._get_next().connect(ref) 1508 else: 1509 # scalar assignment to plain VectorPort is implicit append 1510 self._get_next().connect(other) 1511 1512 def clone(self, simobj, memo): 1513 if memo.has_key(self): 1514 return memo[self] 1515 newRef = copy.copy(self) 1516 memo[self] = newRef 1517 newRef.simobj = simobj 1518 assert(isSimObject(newRef.simobj)) 1519 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1520 return newRef 1521 1522 def unproxy(self, simobj): 1523 [el.unproxy(simobj) for el in self.elements] 1524 1525 def ccConnect(self): 1526 [el.ccConnect() for el in self.elements] 1527 1528# Port description object. Like a ParamDesc object, this represents a 1529# logical port in the SimObject class, not a particular port on a 1530# SimObject instance. The latter are represented by PortRef objects. 1531class Port(object): 1532 # Generate a PortRef for this port on the given SimObject with the 1533 # given name 1534 def makeRef(self, simobj): 1535 return PortRef(simobj, self.name, self.role) 1536 1537 # Connect an instance of this port (on the given SimObject with 1538 # the given name) with the port described by the supplied PortRef 1539 def connect(self, simobj, ref): 1540 self.makeRef(simobj).connect(ref) 1541 1542 # No need for any pre-declarations at the moment as we merely rely 1543 # on an unsigned int. 1544 def cxx_predecls(self, code): 1545 pass 1546 1547 # Declare an unsigned int with the same name as the port, that 1548 # will eventually hold the number of connected ports (and thus the 1549 # number of elements for a VectorPort). 1550 def cxx_decl(self, code): 1551 code('unsigned int port_${{self.name}}_connection_count;') 1552 1553class MasterPort(Port): 1554 # MasterPort("description") 1555 def __init__(self, *args): 1556 if len(args) == 1: 1557 self.desc = args[0] 1558 self.role = 'MASTER' 1559 else: 1560 raise TypeError, 'wrong number of arguments' 1561 1562class SlavePort(Port): 1563 # SlavePort("description") 1564 def __init__(self, *args): 1565 if len(args) == 1: 1566 self.desc = args[0] 1567 self.role = 'SLAVE' 1568 else: 1569 raise TypeError, 'wrong number of arguments' 1570 1571# VectorPort description object. Like Port, but represents a vector 1572# of connections (e.g., as on a Bus). 1573class VectorPort(Port): 1574 def __init__(self, *args): 1575 self.isVec = True 1576 1577 def makeRef(self, simobj): 1578 return VectorPortRef(simobj, self.name, self.role) 1579 1580class VectorMasterPort(VectorPort): 1581 # VectorMasterPort("description") 1582 def __init__(self, *args): 1583 if len(args) == 1: 1584 self.desc = args[0] 1585 self.role = 'MASTER' 1586 VectorPort.__init__(self, *args) 1587 else: 1588 raise TypeError, 'wrong number of arguments' 1589 1590class VectorSlavePort(VectorPort): 1591 # VectorSlavePort("description") 1592 def __init__(self, *args): 1593 if len(args) == 1: 1594 self.desc = args[0] 1595 self.role = 'SLAVE' 1596 VectorPort.__init__(self, *args) 1597 else: 1598 raise TypeError, 'wrong number of arguments' 1599 1600# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1601# proxy objects (via set_param_desc()) so that proxy error messages 1602# make sense. 1603class PortParamDesc(object): 1604 __metaclass__ = Singleton 1605 1606 ptype_str = 'Port' 1607 ptype = Port 1608 1609baseEnums = allEnums.copy() 1610baseParams = allParams.copy() 1611 1612def clear(): 1613 global allEnums, allParams 1614 1615 allEnums = baseEnums.copy() 1616 allParams = baseParams.copy() 1617 1618__all__ = ['Param', 'VectorParam', 1619 'Enum', 'Bool', 'String', 'Float', 1620 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1621 'Int32', 'UInt32', 'Int64', 'UInt64', 1622 'Counter', 'Addr', 'Tick', 'Percent', 1623 'TcpPort', 'UdpPort', 'EthernetAddr', 1624 'IpAddress', 'IpNetmask', 'IpWithPort', 1625 'MemorySize', 'MemorySize32', 1626 'Latency', 'Frequency', 'Clock', 1627 'NetworkBandwidth', 'MemoryBandwidth', 1628 'Range', 'AddrRange', 'TickRange', 1629 'MaxAddr', 'MaxTick', 'AllMemory', 1630 'Time', 1631 'NextEthernetAddr', 'NULL', 1632 'MasterPort', 'SlavePort', 1633 'VectorMasterPort', 'VectorSlavePort'] 1634 1635import SimObject 1636