params.py revision 8934
12SN/A# Copyright (c) 2012 ARM Limited 210911Sandreas.sandberg@arm.com# All rights reserved. 310911Sandreas.sandberg@arm.com# 410911Sandreas.sandberg@arm.com# The license below extends only to copyright in the software and shall 510911Sandreas.sandberg@arm.com# not be construed as granting a license to any other intellectual 610911Sandreas.sandberg@arm.com# property including but not limited to intellectual property relating 710911Sandreas.sandberg@arm.com# to a hardware implementation of the functionality of the software 810911Sandreas.sandberg@arm.com# licensed hereunder. You may use the software subject to the license 910911Sandreas.sandberg@arm.com# terms below provided that you ensure that this notice is replicated 1010911Sandreas.sandberg@arm.com# unmodified and in its entirety in all distributions of the software, 1110911Sandreas.sandberg@arm.com# modified or unmodified, in source code or in binary form. 1210911Sandreas.sandberg@arm.com# 1310911Sandreas.sandberg@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 141762SN/A# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 157534Ssteve.reinhardt@amd.com# All rights reserved. 162SN/A# 172SN/A# Redistribution and use in source and binary forms, with or without 182SN/A# modification, are permitted provided that the following conditions are 192SN/A# met: redistributions of source code must retain the above copyright 202SN/A# notice, this list of conditions and the following disclaimer; 212SN/A# redistributions in binary form must reproduce the above copyright 222SN/A# notice, this list of conditions and the following disclaimer in the 232SN/A# documentation and/or other materials provided with the distribution; 242SN/A# neither the name of the copyright holders nor the names of its 252SN/A# contributors may be used to endorse or promote products derived from 262SN/A# this software without specific prior written permission. 272SN/A# 282SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392SN/A# 402665Ssaidi@eecs.umich.edu# Authors: Steve Reinhardt 412665Ssaidi@eecs.umich.edu# Nathan Binkert 422665Ssaidi@eecs.umich.edu# Gabe Black 432SN/A# Andreas Hansson 442SN/A 452SN/A##################################################################### 462SN/A# 472SN/A# Parameter description classes 482SN/A# 492SN/A# The _params dictionary in each class maps parameter names to either 502SN/A# a Param or a VectorParam object. These objects contain the 512SN/A# parameter description string, the parameter type, and the default 525491Sgblack@eecs.umich.edu# value (if any). The convert() method on these objects is used to 535491Sgblack@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 542SN/A# type. 555491Sgblack@eecs.umich.edu# 562SN/A# Note that the default values are loaded into the class's attribute 572SN/A# space when the parameter dictionary is initialized (in 588737Skoansin.tan@gmail.com# MetaSimObject._new_param()); after that point they aren't used. 594762Snate@binkert.org# 609342SAndreas.Sandberg@arm.com##################################################################### 619356Snilay@cs.wisc.edu 6256SN/Aimport copy 632SN/Aimport datetime 642797Sktlim@umich.eduimport re 652797Sktlim@umich.eduimport sys 6610023Smatt.horsnell@ARM.comimport time 679196SAndreas.Sandberg@arm.comimport math 682SN/A 692SN/Aimport proxy 702SN/Aimport ticks 719196SAndreas.Sandberg@arm.comfrom util import * 729196SAndreas.Sandberg@arm.com 739196SAndreas.Sandberg@arm.comdef isSimObject(*args, **kwargs): 749196SAndreas.Sandberg@arm.com return SimObject.isSimObject(*args, **kwargs) 759196SAndreas.Sandberg@arm.com 769196SAndreas.Sandberg@arm.comdef isSimObjectSequence(*args, **kwargs): 779196SAndreas.Sandberg@arm.com return SimObject.isSimObjectSequence(*args, **kwargs) 789196SAndreas.Sandberg@arm.com 799196SAndreas.Sandberg@arm.comdef isSimObjectClass(*args, **kwargs): 809196SAndreas.Sandberg@arm.com return SimObject.isSimObjectClass(*args, **kwargs) 819196SAndreas.Sandberg@arm.com 829196SAndreas.Sandberg@arm.comallParams = {} 839196SAndreas.Sandberg@arm.com 849196SAndreas.Sandberg@arm.comclass MetaParamValue(type): 859196SAndreas.Sandberg@arm.com def __new__(mcls, name, bases, dct): 869196SAndreas.Sandberg@arm.com cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 879196SAndreas.Sandberg@arm.com assert name not in allParams 889342SAndreas.Sandberg@arm.com allParams[name] = cls 899196SAndreas.Sandberg@arm.com return cls 909196SAndreas.Sandberg@arm.com 919196SAndreas.Sandberg@arm.com 929196SAndreas.Sandberg@arm.com# Dummy base class to identify types that are legitimate for SimObject 939196SAndreas.Sandberg@arm.com# parameters. 949196SAndreas.Sandberg@arm.comclass ParamValue(object): 959196SAndreas.Sandberg@arm.com __metaclass__ = MetaParamValue 962SN/A 979342SAndreas.Sandberg@arm.com 982SN/A # Generate the code needed as a prerequisite for declaring a C++ 992SN/A # object of this type. Typically generates one or more #include 1002SN/A # statements. Used when declaring parameters of this type. 1012SN/A @classmethod 1029196SAndreas.Sandberg@arm.com def cxx_predecls(cls, code): 1032SN/A pass 1042SN/A 10510023Smatt.horsnell@ARM.com # Generate the code needed as a prerequisite for including a 10610023Smatt.horsnell@ARM.com # reference to a C++ object of this type in a SWIG .i file. 10710023Smatt.horsnell@ARM.com # Typically generates one or more %import or %include statements. 1084762Snate@binkert.org @classmethod 1099196SAndreas.Sandberg@arm.com def swig_predecls(cls, code): 1104762Snate@binkert.org pass 1114762Snate@binkert.org 1122SN/A # default for printing to .ini file is regular string conversion. 1134762Snate@binkert.org # will be overridden in some cases 1144762Snate@binkert.org def ini_str(self): 1154762Snate@binkert.org return str(self) 11610422Sandreas.hansson@arm.com 1172SN/A # allows us to blithely call unproxy() on things without checking 1185034Smilesck@eecs.umich.edu # if they're really proxies or not 1195034Smilesck@eecs.umich.edu def unproxy(self, base): 1201553SN/A return self 121265SN/A 1227532Ssteve.reinhardt@amd.com# Regular parameter description. 1237532Ssteve.reinhardt@amd.comclass ParamDesc(object): 1247532Ssteve.reinhardt@amd.com def __init__(self, ptype_str, ptype, *args, **kwargs): 1257532Ssteve.reinhardt@amd.com self.ptype_str = ptype_str 1267532Ssteve.reinhardt@amd.com # remember ptype only if it is provided 1277532Ssteve.reinhardt@amd.com if ptype != None: 128465SN/A self.ptype = ptype 129465SN/A 1307532Ssteve.reinhardt@amd.com if args: 1317532Ssteve.reinhardt@amd.com if len(args) == 1: 1327532Ssteve.reinhardt@amd.com self.desc = args[0] 1337532Ssteve.reinhardt@amd.com elif len(args) == 2: 1347532Ssteve.reinhardt@amd.com self.default = args[0] 1357532Ssteve.reinhardt@amd.com self.desc = args[1] 1367532Ssteve.reinhardt@amd.com else: 1377532Ssteve.reinhardt@amd.com raise TypeError, 'too many arguments' 1389196SAndreas.Sandberg@arm.com 1399196SAndreas.Sandberg@arm.com if kwargs.has_key('desc'): 1407532Ssteve.reinhardt@amd.com assert(not hasattr(self, 'desc')) 14110905Sandreas.sandberg@arm.com self.desc = kwargs['desc'] 1427532Ssteve.reinhardt@amd.com del kwargs['desc'] 1437532Ssteve.reinhardt@amd.com 1447532Ssteve.reinhardt@amd.com if kwargs.has_key('default'): 1457532Ssteve.reinhardt@amd.com assert(not hasattr(self, 'default')) 1467532Ssteve.reinhardt@amd.com self.default = kwargs['default'] 1477532Ssteve.reinhardt@amd.com del kwargs['default'] 1487532Ssteve.reinhardt@amd.com 1497532Ssteve.reinhardt@amd.com if kwargs: 1509196SAndreas.Sandberg@arm.com raise TypeError, 'extra unknown kwargs %s' % kwargs 1519196SAndreas.Sandberg@arm.com 1529196SAndreas.Sandberg@arm.com if not hasattr(self, 'desc'): 1532SN/A raise TypeError, 'desc attribute missing' 1549196SAndreas.Sandberg@arm.com 1559196SAndreas.Sandberg@arm.com def __getattr__(self, attr): 1569196SAndreas.Sandberg@arm.com if attr == 'ptype': 1579196SAndreas.Sandberg@arm.com ptype = SimObject.allClasses[self.ptype_str] 158330SN/A assert isSimObjectClass(ptype) 1592SN/A self.ptype = ptype 1607532Ssteve.reinhardt@amd.com return ptype 16110023Smatt.horsnell@ARM.com 16210023Smatt.horsnell@ARM.com raise AttributeError, "'%s' object has no attribute '%s'" % \ 16310023Smatt.horsnell@ARM.com (type(self).__name__, attr) 16410023Smatt.horsnell@ARM.com 16510023Smatt.horsnell@ARM.com def convert(self, value): 16610023Smatt.horsnell@ARM.com if isinstance(value, proxy.BaseProxy): 16710023Smatt.horsnell@ARM.com value.set_param_desc(self) 16810023Smatt.horsnell@ARM.com return value 16910023Smatt.horsnell@ARM.com if not hasattr(self, 'ptype') and isNullPointer(value): 17010023Smatt.horsnell@ARM.com # deferred evaluation of SimObject; continue to defer if 17110023Smatt.horsnell@ARM.com # we're just assigning a null pointer 17210023Smatt.horsnell@ARM.com return value 17310023Smatt.horsnell@ARM.com if isinstance(value, self.ptype): 17410023Smatt.horsnell@ARM.com return value 17510023Smatt.horsnell@ARM.com if isNullPointer(value) and isSimObjectClass(self.ptype): 1767532Ssteve.reinhardt@amd.com return value 1777532Ssteve.reinhardt@amd.com return self.ptype(value) 1787823Ssteve.reinhardt@amd.com 1797532Ssteve.reinhardt@amd.com def cxx_predecls(self, code): 1807532Ssteve.reinhardt@amd.com code('#include <cstddef>') 1817492Ssteve.reinhardt@amd.com self.ptype.cxx_predecls(code) 182330SN/A 1839196SAndreas.Sandberg@arm.com def swig_predecls(self, code): 18410913Sandreas.sandberg@arm.com self.ptype.swig_predecls(code) 18510913Sandreas.sandberg@arm.com 1869342SAndreas.Sandberg@arm.com def cxx_decl(self, code): 18710913Sandreas.sandberg@arm.com code('${{self.ptype.cxx_type}} ${{self.name}};') 1889342SAndreas.Sandberg@arm.com 18910911Sandreas.sandberg@arm.com# Vector-valued parameter description. Just like ParamDesc, except 19010911Sandreas.sandberg@arm.com# that the value is a vector (list) of the specified type instead of a 19110911Sandreas.sandberg@arm.com# single value. 19210911Sandreas.sandberg@arm.com 19310911Sandreas.sandberg@arm.comclass VectorParamValue(list): 19410911Sandreas.sandberg@arm.com __metaclass__ = MetaParamValue 19510911Sandreas.sandberg@arm.com def __setattr__(self, attr, value): 19610911Sandreas.sandberg@arm.com raise AttributeError, \ 19710911Sandreas.sandberg@arm.com "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 19810911Sandreas.sandberg@arm.com 19910911Sandreas.sandberg@arm.com def ini_str(self): 20010911Sandreas.sandberg@arm.com return ' '.join([v.ini_str() for v in self]) 20110911Sandreas.sandberg@arm.com 20210911Sandreas.sandberg@arm.com def getValue(self): 20310911Sandreas.sandberg@arm.com return [ v.getValue() for v in self ] 20410911Sandreas.sandberg@arm.com 20510911Sandreas.sandberg@arm.com def unproxy(self, base): 20610911Sandreas.sandberg@arm.com if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 20710911Sandreas.sandberg@arm.com return self[0].unproxy(base) 20810911Sandreas.sandberg@arm.com else: 20910911Sandreas.sandberg@arm.com return [v.unproxy(base) for v in self] 21010911Sandreas.sandberg@arm.com 21110905Sandreas.sandberg@arm.comclass SimObjectVector(VectorParamValue): 21210905Sandreas.sandberg@arm.com # support clone operation 21310905Sandreas.sandberg@arm.com def __call__(self, **kwargs): 21410905Sandreas.sandberg@arm.com return SimObjectVector([v(**kwargs) for v in self]) 2159342SAndreas.Sandberg@arm.com 2169196SAndreas.Sandberg@arm.com def clear_parent(self, old_parent): 2179196SAndreas.Sandberg@arm.com for v in self: 21810905Sandreas.sandberg@arm.com v.clear_parent(old_parent) 219938SN/A 2201031SN/A def set_parent(self, parent, name): 2211031SN/A if len(self) == 1: 2221031SN/A self[0].set_parent(parent, name) 2231031SN/A else: 2241031SN/A width = int(math.ceil(math.log(len(self))/math.log(10))) 2251031SN/A for i,v in enumerate(self): 2265314Sstever@gmail.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 2275314Sstever@gmail.com 2285315Sstever@gmail.com def has_parent(self): 2295314Sstever@gmail.com return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 2305314Sstever@gmail.com 2315314Sstever@gmail.com # return 'cpu0 cpu1' etc. for print_ini() 2322SN/A def get_name(self): 2332SN/A return ' '.join([v._name for v in self]) 2349554Sandreas.hansson@arm.com 2359554Sandreas.hansson@arm.com # By iterating through the constituent members of the vector here 2369554Sandreas.hansson@arm.com # we can nicely handle iterating over all a SimObject's children 2379554Sandreas.hansson@arm.com # without having to provide lots of special functions on 2382SN/A # SimObjectVector directly. 239 def descendants(self): 240 for v in self: 241 for obj in v.descendants(): 242 yield obj 243 244 def get_config_as_dict(self): 245 a = [] 246 for v in self: 247 a.append(v.get_config_as_dict()) 248 return a 249 250class VectorParamDesc(ParamDesc): 251 # Convert assigned value to appropriate type. If the RHS is not a 252 # list or tuple, it generates a single-element list. 253 def convert(self, value): 254 if isinstance(value, (list, tuple)): 255 # list: coerce each element into new list 256 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 257 else: 258 # singleton: coerce to a single-element list 259 tmp_list = [ ParamDesc.convert(self, value) ] 260 261 if isSimObjectSequence(tmp_list): 262 return SimObjectVector(tmp_list) 263 else: 264 return VectorParamValue(tmp_list) 265 266 def swig_module_name(self): 267 return "%s_vector" % self.ptype_str 268 269 def swig_predecls(self, code): 270 code('%import "${{self.swig_module_name()}}.i"') 271 272 def swig_decl(self, code): 273 code('%module(package="m5.internal") ${{self.swig_module_name()}}') 274 code('%{') 275 self.ptype.cxx_predecls(code) 276 code('%}') 277 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 print "warning: overwriting port", self, \ 1383 "value", self.peer, "with", other 1384 self.peer.peer = None 1385 self.peer = other 1386 if proxy.isproxy(other): 1387 other.set_param_desc(PortParamDesc()) 1388 elif isinstance(other, PortRef): 1389 if other.peer is not self: 1390 other.connect(self) 1391 else: 1392 raise TypeError, \ 1393 "assigning non-port reference '%s' to port '%s'" \ 1394 % (other, self) 1395 1396 def clone(self, simobj, memo): 1397 if memo.has_key(self): 1398 return memo[self] 1399 newRef = copy.copy(self) 1400 memo[self] = newRef 1401 newRef.simobj = simobj 1402 assert(isSimObject(newRef.simobj)) 1403 if self.peer and not proxy.isproxy(self.peer): 1404 peerObj = self.peer.simobj(_memo=memo) 1405 newRef.peer = self.peer.clone(peerObj, memo) 1406 assert(not isinstance(newRef.peer, VectorPortRef)) 1407 return newRef 1408 1409 def unproxy(self, simobj): 1410 assert(simobj is self.simobj) 1411 if proxy.isproxy(self.peer): 1412 try: 1413 realPeer = self.peer.unproxy(self.simobj) 1414 except: 1415 print "Error in unproxying port '%s' of %s" % \ 1416 (self.name, self.simobj.path()) 1417 raise 1418 self.connect(realPeer) 1419 1420 # Call C++ to create corresponding port connection between C++ objects 1421 def ccConnect(self): 1422 from m5.internal.pyobject import connectPorts 1423 1424 if self.role == 'SLAVE': 1425 # do nothing and let the master take care of it 1426 return 1427 1428 if self.ccConnected: # already done this 1429 return 1430 peer = self.peer 1431 if not self.peer: # nothing to connect to 1432 return 1433 1434 # check that we connect a master to a slave 1435 if self.role == peer.role: 1436 raise TypeError, \ 1437 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1438 % (peer, self, self.role) 1439 1440 try: 1441 # self is always the master and peer the slave 1442 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1443 peer.simobj.getCCObject(), peer.name, peer.index) 1444 except: 1445 print "Error connecting port %s.%s to %s.%s" % \ 1446 (self.simobj.path(), self.name, 1447 peer.simobj.path(), peer.name) 1448 raise 1449 self.ccConnected = True 1450 peer.ccConnected = True 1451 1452# A reference to an individual element of a VectorPort... much like a 1453# PortRef, but has an index. 1454class VectorPortElementRef(PortRef): 1455 def __init__(self, simobj, name, role, index): 1456 PortRef.__init__(self, simobj, name, role) 1457 self.index = index 1458 1459 def __str__(self): 1460 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1461 1462# A reference to a complete vector-valued port (not just a single element). 1463# Can be indexed to retrieve individual VectorPortElementRef instances. 1464class VectorPortRef(object): 1465 def __init__(self, simobj, name, role): 1466 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1467 self.simobj = simobj 1468 self.name = name 1469 self.role = role 1470 self.elements = [] 1471 1472 def __str__(self): 1473 return '%s.%s[:]' % (self.simobj, self.name) 1474 1475 def __len__(self): 1476 # Return the number of connected peers, corresponding the the 1477 # length of the elements. 1478 return len(self.elements) 1479 1480 # for config.ini, print peer's name (not ours) 1481 def ini_str(self): 1482 return ' '.join([el.ini_str() for el in self.elements]) 1483 1484 def __getitem__(self, key): 1485 if not isinstance(key, int): 1486 raise TypeError, "VectorPort index must be integer" 1487 if key >= len(self.elements): 1488 # need to extend list 1489 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1490 for i in range(len(self.elements), key+1)] 1491 self.elements.extend(ext) 1492 return self.elements[key] 1493 1494 def _get_next(self): 1495 return self[len(self.elements)] 1496 1497 def __setitem__(self, key, value): 1498 if not isinstance(key, int): 1499 raise TypeError, "VectorPort index must be integer" 1500 self[key].connect(value) 1501 1502 def connect(self, other): 1503 if isinstance(other, (list, tuple)): 1504 # Assign list of port refs to vector port. 1505 # For now, append them... not sure if that's the right semantics 1506 # or if it should replace the current vector. 1507 for ref in other: 1508 self._get_next().connect(ref) 1509 else: 1510 # scalar assignment to plain VectorPort is implicit append 1511 self._get_next().connect(other) 1512 1513 def clone(self, simobj, memo): 1514 if memo.has_key(self): 1515 return memo[self] 1516 newRef = copy.copy(self) 1517 memo[self] = newRef 1518 newRef.simobj = simobj 1519 assert(isSimObject(newRef.simobj)) 1520 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1521 return newRef 1522 1523 def unproxy(self, simobj): 1524 [el.unproxy(simobj) for el in self.elements] 1525 1526 def ccConnect(self): 1527 [el.ccConnect() for el in self.elements] 1528 1529# Port description object. Like a ParamDesc object, this represents a 1530# logical port in the SimObject class, not a particular port on a 1531# SimObject instance. The latter are represented by PortRef objects. 1532class Port(object): 1533 # Generate a PortRef for this port on the given SimObject with the 1534 # given name 1535 def makeRef(self, simobj): 1536 return PortRef(simobj, self.name, self.role) 1537 1538 # Connect an instance of this port (on the given SimObject with 1539 # the given name) with the port described by the supplied PortRef 1540 def connect(self, simobj, ref): 1541 self.makeRef(simobj).connect(ref) 1542 1543 # No need for any pre-declarations at the moment as we merely rely 1544 # on an unsigned int. 1545 def cxx_predecls(self, code): 1546 pass 1547 1548 # Declare an unsigned int with the same name as the port, that 1549 # will eventually hold the number of connected ports (and thus the 1550 # number of elements for a VectorPort). 1551 def cxx_decl(self, code): 1552 code('unsigned int port_${{self.name}}_connection_count;') 1553 1554class MasterPort(Port): 1555 # MasterPort("description") 1556 def __init__(self, *args): 1557 if len(args) == 1: 1558 self.desc = args[0] 1559 self.role = 'MASTER' 1560 else: 1561 raise TypeError, 'wrong number of arguments' 1562 1563class SlavePort(Port): 1564 # SlavePort("description") 1565 def __init__(self, *args): 1566 if len(args) == 1: 1567 self.desc = args[0] 1568 self.role = 'SLAVE' 1569 else: 1570 raise TypeError, 'wrong number of arguments' 1571 1572# VectorPort description object. Like Port, but represents a vector 1573# of connections (e.g., as on a Bus). 1574class VectorPort(Port): 1575 def __init__(self, *args): 1576 self.isVec = True 1577 1578 def makeRef(self, simobj): 1579 return VectorPortRef(simobj, self.name, self.role) 1580 1581class VectorMasterPort(VectorPort): 1582 # VectorMasterPort("description") 1583 def __init__(self, *args): 1584 if len(args) == 1: 1585 self.desc = args[0] 1586 self.role = 'MASTER' 1587 VectorPort.__init__(self, *args) 1588 else: 1589 raise TypeError, 'wrong number of arguments' 1590 1591class VectorSlavePort(VectorPort): 1592 # VectorSlavePort("description") 1593 def __init__(self, *args): 1594 if len(args) == 1: 1595 self.desc = args[0] 1596 self.role = 'SLAVE' 1597 VectorPort.__init__(self, *args) 1598 else: 1599 raise TypeError, 'wrong number of arguments' 1600 1601# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1602# proxy objects (via set_param_desc()) so that proxy error messages 1603# make sense. 1604class PortParamDesc(object): 1605 __metaclass__ = Singleton 1606 1607 ptype_str = 'Port' 1608 ptype = Port 1609 1610baseEnums = allEnums.copy() 1611baseParams = allParams.copy() 1612 1613def clear(): 1614 global allEnums, allParams 1615 1616 allEnums = baseEnums.copy() 1617 allParams = baseParams.copy() 1618 1619__all__ = ['Param', 'VectorParam', 1620 'Enum', 'Bool', 'String', 'Float', 1621 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1622 'Int32', 'UInt32', 'Int64', 'UInt64', 1623 'Counter', 'Addr', 'Tick', 'Percent', 1624 'TcpPort', 'UdpPort', 'EthernetAddr', 1625 'IpAddress', 'IpNetmask', 'IpWithPort', 1626 'MemorySize', 'MemorySize32', 1627 'Latency', 'Frequency', 'Clock', 1628 'NetworkBandwidth', 'MemoryBandwidth', 1629 'Range', 'AddrRange', 'TickRange', 1630 'MaxAddr', 'MaxTick', 'AllMemory', 1631 'Time', 1632 'NextEthernetAddr', 'NULL', 1633 'MasterPort', 'SlavePort', 1634 'VectorMasterPort', 'VectorSlavePort'] 1635 1636import SimObject 1637