params.py revision 8656
16791SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan 26791SN/A# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 36791SN/A# All rights reserved. 46791SN/A# 56791SN/A# Redistribution and use in source and binary forms, with or without 66791SN/A# modification, are permitted provided that the following conditions are 76791SN/A# met: redistributions of source code must retain the above copyright 86791SN/A# notice, this list of conditions and the following disclaimer; 96791SN/A# redistributions in binary form must reproduce the above copyright 106791SN/A# notice, this list of conditions and the following disclaimer in the 116791SN/A# documentation and/or other materials provided with the distribution; 126791SN/A# neither the name of the copyright holders nor the names of its 136791SN/A# contributors may be used to endorse or promote products derived from 146791SN/A# this software without specific prior written permission. 156791SN/A# 166791SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176791SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186791SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196791SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206791SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216791SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226791SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236791SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246791SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256791SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266791SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276791SN/A# 286791SN/A# Authors: Steve Reinhardt 2910441Snilay@cs.wisc.edu# Nathan Binkert 3010441Snilay@cs.wisc.edu# Gabe Black 316791SN/A 327055SN/A##################################################################### 337055SN/A# 347455SN/A# Parameter description classes 357039SN/A# 367039SN/A# The _params dictionary in each class maps parameter names to either 3710301Snilay@cs.wisc.edu# a Param or a VectorParam object. These objects contain the 387039SN/A# parameter description string, the parameter type, and the default 396791SN/A# value (if any). The convert() method on these objects is used to 407039SN/A# force whatever value is assigned to the parameter to the appropriate 417039SN/A# type. 427039SN/A# 438607SN/A# Note that the default values are loaded into the class's attribute 447055SN/A# space when the parameter dictionary is initialized (in 456791SN/A# MetaSimObject._new_param()); after that point they aren't used. 467039SN/A# 477039SN/A##################################################################### 487039SN/A 496797SN/Aimport copy 506791SN/Aimport datetime 517039SN/Aimport re 527039SN/Aimport sys 537039SN/Aimport time 547039SN/Aimport math 557039SN/A 566791SN/Aimport proxy 577039SN/Aimport ticks 587039SN/Afrom util import * 597054SN/A 607039SN/Adef isSimObject(*args, **kwargs): 6111025Snilay@cs.wisc.edu return SimObject.isSimObject(*args, **kwargs) 627039SN/A 6311025Snilay@cs.wisc.edudef isSimObjectSequence(*args, **kwargs): 6411025Snilay@cs.wisc.edu return SimObject.isSimObjectSequence(*args, **kwargs) 6511025Snilay@cs.wisc.edu 6611025Snilay@cs.wisc.edudef isSimObjectClass(*args, **kwargs): 6711025Snilay@cs.wisc.edu return SimObject.isSimObjectClass(*args, **kwargs) 6811025Snilay@cs.wisc.edu 6911025Snilay@cs.wisc.eduallParams = {} 7011025Snilay@cs.wisc.edu 716791SN/Aclass MetaParamValue(type): 727055SN/A def __new__(mcls, name, bases, dct): 736791SN/A cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 747039SN/A assert name not in allParams 757039SN/A allParams[name] = cls 767039SN/A return cls 777039SN/A 786791SN/A 797039SN/A# Dummy base class to identify types that are legitimate for SimObject 8011025Snilay@cs.wisc.edu# parameters. 817455SN/Aclass ParamValue(object): 826791SN/A __metaclass__ = MetaParamValue 836791SN/A 847055SN/A 857055SN/A # Generate the code needed as a prerequisite for declaring a C++ 866791SN/A # object of this type. Typically generates one or more #include 877039SN/A # statements. Used when declaring parameters of this type. 887055SN/A @classmethod 897039SN/A def cxx_predecls(cls, code): 906791SN/A pass 916791SN/A 927055SN/A # Generate the code needed as a prerequisite for including a 937055SN/A # reference to a C++ object of this type in a SWIG .i file. 946797SN/A # Typically generates one or more %import or %include statements. 957039SN/A @classmethod 967055SN/A def swig_predecls(cls, code): 977039SN/A pass 986797SN/A 996797SN/A # default for printing to .ini file is regular string conversion. 10010441Snilay@cs.wisc.edu # will be overridden in some cases 101 def ini_str(self): 102 return str(self) 103 104 # allows us to blithely call unproxy() on things without checking 105 # if they're really proxies or not 106 def unproxy(self, base): 107 return self 108 109# Regular parameter description. 110class ParamDesc(object): 111 def __init__(self, ptype_str, ptype, *args, **kwargs): 112 self.ptype_str = ptype_str 113 # remember ptype only if it is provided 114 if ptype != None: 115 self.ptype = ptype 116 117 if args: 118 if len(args) == 1: 119 self.desc = args[0] 120 elif len(args) == 2: 121 self.default = args[0] 122 self.desc = args[1] 123 else: 124 raise TypeError, 'too many arguments' 125 126 if kwargs.has_key('desc'): 127 assert(not hasattr(self, 'desc')) 128 self.desc = kwargs['desc'] 129 del kwargs['desc'] 130 131 if kwargs.has_key('default'): 132 assert(not hasattr(self, 'default')) 133 self.default = kwargs['default'] 134 del kwargs['default'] 135 136 if kwargs: 137 raise TypeError, 'extra unknown kwargs %s' % kwargs 138 139 if not hasattr(self, 'desc'): 140 raise TypeError, 'desc attribute missing' 141 142 def __getattr__(self, attr): 143 if attr == 'ptype': 144 ptype = SimObject.allClasses[self.ptype_str] 145 assert isSimObjectClass(ptype) 146 self.ptype = ptype 147 return ptype 148 149 raise AttributeError, "'%s' object has no attribute '%s'" % \ 150 (type(self).__name__, attr) 151 152 def convert(self, value): 153 if isinstance(value, proxy.BaseProxy): 154 value.set_param_desc(self) 155 return value 156 if not hasattr(self, 'ptype') and isNullPointer(value): 157 # deferred evaluation of SimObject; continue to defer if 158 # we're just assigning a null pointer 159 return value 160 if isinstance(value, self.ptype): 161 return value 162 if isNullPointer(value) and isSimObjectClass(self.ptype): 163 return value 164 return self.ptype(value) 165 166 def cxx_predecls(self, code): 167 code('#include <cstddef>') 168 self.ptype.cxx_predecls(code) 169 170 def swig_predecls(self, code): 171 self.ptype.swig_predecls(code) 172 173 def cxx_decl(self, code): 174 code('${{self.ptype.cxx_type}} ${{self.name}};') 175 176# Vector-valued parameter description. Just like ParamDesc, except 177# that the value is a vector (list) of the specified type instead of a 178# single value. 179 180class VectorParamValue(list): 181 __metaclass__ = MetaParamValue 182 def __setattr__(self, attr, value): 183 raise AttributeError, \ 184 "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 185 186 def ini_str(self): 187 return ' '.join([v.ini_str() for v in self]) 188 189 def getValue(self): 190 return [ v.getValue() for v in self ] 191 192 def unproxy(self, base): 193 if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 194 return self[0].unproxy(base) 195 else: 196 return [v.unproxy(base) for v in self] 197 198class SimObjectVector(VectorParamValue): 199 # support clone operation 200 def __call__(self, **kwargs): 201 return SimObjectVector([v(**kwargs) for v in self]) 202 203 def clear_parent(self, old_parent): 204 for v in self: 205 v.clear_parent(old_parent) 206 207 def set_parent(self, parent, name): 208 if len(self) == 1: 209 self[0].set_parent(parent, name) 210 else: 211 width = int(math.ceil(math.log(len(self))/math.log(10))) 212 for i,v in enumerate(self): 213 v.set_parent(parent, "%s%0*d" % (name, width, i)) 214 215 def has_parent(self): 216 return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 217 218 # return 'cpu0 cpu1' etc. for print_ini() 219 def get_name(self): 220 return ' '.join([v._name for v in self]) 221 222 # By iterating through the constituent members of the vector here 223 # we can nicely handle iterating over all a SimObject's children 224 # without having to provide lots of special functions on 225 # SimObjectVector directly. 226 def descendants(self): 227 for v in self: 228 for obj in v.descendants(): 229 yield obj 230 231class VectorParamDesc(ParamDesc): 232 # Convert assigned value to appropriate type. If the RHS is not a 233 # list or tuple, it generates a single-element list. 234 def convert(self, value): 235 if isinstance(value, (list, tuple)): 236 # list: coerce each element into new list 237 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 238 else: 239 # singleton: coerce to a single-element list 240 tmp_list = [ ParamDesc.convert(self, value) ] 241 242 if isSimObjectSequence(tmp_list): 243 return SimObjectVector(tmp_list) 244 else: 245 return VectorParamValue(tmp_list) 246 247 def swig_module_name(self): 248 return "%s_vector" % self.ptype_str 249 250 def swig_predecls(self, code): 251 code('%import "${{self.swig_module_name()}}.i"') 252 253 def swig_decl(self, code): 254 code('%module(package="m5.internal") ${{self.swig_module_name()}}') 255 code('%{') 256 self.ptype.cxx_predecls(code) 257 code('%}') 258 code() 259 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 260 code('%include "std_container.i"') 261 code() 262 self.ptype.swig_predecls(code) 263 code() 264 code('%include "std_vector.i"') 265 code() 266 267 ptype = self.ptype_str 268 cxx_type = self.ptype.cxx_type 269 270 code('''\ 271%typemap(in) std::vector< $cxx_type >::value_type { 272 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 273 if (SWIG_ConvertPtr($$input, (void **)&$$1, 274 $$descriptor($cxx_type), 0) == -1) { 275 return NULL; 276 } 277 } 278} 279 280%typemap(in) std::vector< $cxx_type >::value_type * { 281 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 282 if (SWIG_ConvertPtr($$input, (void **)&$$1, 283 $$descriptor($cxx_type *), 0) == -1) { 284 return NULL; 285 } 286 } 287} 288''') 289 290 code('%template(vector_$ptype) std::vector< $cxx_type >;') 291 292 def cxx_predecls(self, code): 293 code('#include <vector>') 294 self.ptype.cxx_predecls(code) 295 296 def cxx_decl(self, code): 297 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 298 299class ParamFactory(object): 300 def __init__(self, param_desc_class, ptype_str = None): 301 self.param_desc_class = param_desc_class 302 self.ptype_str = ptype_str 303 304 def __getattr__(self, attr): 305 if self.ptype_str: 306 attr = self.ptype_str + '.' + attr 307 return ParamFactory(self.param_desc_class, attr) 308 309 # E.g., Param.Int(5, "number of widgets") 310 def __call__(self, *args, **kwargs): 311 ptype = None 312 try: 313 ptype = allParams[self.ptype_str] 314 except KeyError: 315 # if name isn't defined yet, assume it's a SimObject, and 316 # try to resolve it later 317 pass 318 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 319 320Param = ParamFactory(ParamDesc) 321VectorParam = ParamFactory(VectorParamDesc) 322 323##################################################################### 324# 325# Parameter Types 326# 327# Though native Python types could be used to specify parameter types 328# (the 'ptype' field of the Param and VectorParam classes), it's more 329# flexible to define our own set of types. This gives us more control 330# over how Python expressions are converted to values (via the 331# __init__() constructor) and how these values are printed out (via 332# the __str__() conversion method). 333# 334##################################################################### 335 336# String-valued parameter. Just mixin the ParamValue class with the 337# built-in str class. 338class String(ParamValue,str): 339 cxx_type = 'std::string' 340 341 @classmethod 342 def cxx_predecls(self, code): 343 code('#include <string>') 344 345 @classmethod 346 def swig_predecls(cls, code): 347 code('%include "std_string.i"') 348 349 def getValue(self): 350 return self 351 352# superclass for "numeric" parameter values, to emulate math 353# operations in a type-safe way. e.g., a Latency times an int returns 354# a new Latency object. 355class NumericParamValue(ParamValue): 356 def __str__(self): 357 return str(self.value) 358 359 def __float__(self): 360 return float(self.value) 361 362 def __long__(self): 363 return long(self.value) 364 365 def __int__(self): 366 return int(self.value) 367 368 # hook for bounds checking 369 def _check(self): 370 return 371 372 def __mul__(self, other): 373 newobj = self.__class__(self) 374 newobj.value *= other 375 newobj._check() 376 return newobj 377 378 __rmul__ = __mul__ 379 380 def __div__(self, other): 381 newobj = self.__class__(self) 382 newobj.value /= other 383 newobj._check() 384 return newobj 385 386 def __sub__(self, other): 387 newobj = self.__class__(self) 388 newobj.value -= other 389 newobj._check() 390 return newobj 391 392# Metaclass for bounds-checked integer parameters. See CheckedInt. 393class CheckedIntType(MetaParamValue): 394 def __init__(cls, name, bases, dict): 395 super(CheckedIntType, cls).__init__(name, bases, dict) 396 397 # CheckedInt is an abstract base class, so we actually don't 398 # want to do any processing on it... the rest of this code is 399 # just for classes that derive from CheckedInt. 400 if name == 'CheckedInt': 401 return 402 403 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 404 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 405 panic("CheckedInt subclass %s must define either\n" \ 406 " 'min' and 'max' or 'size' and 'unsigned'\n", 407 name); 408 if cls.unsigned: 409 cls.min = 0 410 cls.max = 2 ** cls.size - 1 411 else: 412 cls.min = -(2 ** (cls.size - 1)) 413 cls.max = (2 ** (cls.size - 1)) - 1 414 415# Abstract superclass for bounds-checked integer parameters. This 416# class is subclassed to generate parameter classes with specific 417# bounds. Initialization of the min and max bounds is done in the 418# metaclass CheckedIntType.__init__. 419class CheckedInt(NumericParamValue): 420 __metaclass__ = CheckedIntType 421 422 def _check(self): 423 if not self.min <= self.value <= self.max: 424 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 425 (self.min, self.value, self.max) 426 427 def __init__(self, value): 428 if isinstance(value, str): 429 self.value = convert.toInteger(value) 430 elif isinstance(value, (int, long, float, NumericParamValue)): 431 self.value = long(value) 432 else: 433 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 434 % type(value).__name__ 435 self._check() 436 437 @classmethod 438 def cxx_predecls(cls, code): 439 # most derived types require this, so we just do it here once 440 code('#include "base/types.hh"') 441 442 @classmethod 443 def swig_predecls(cls, code): 444 # most derived types require this, so we just do it here once 445 code('%import "stdint.i"') 446 code('%import "base/types.hh"') 447 448 def getValue(self): 449 return long(self.value) 450 451class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 452class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 453 454class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 455class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 456class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 457class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 458class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 459class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 460class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 461class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 462 463class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 464class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 465class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 466class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 467 468class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 469 470class Float(ParamValue, float): 471 cxx_type = 'double' 472 473 def __init__(self, value): 474 if isinstance(value, (int, long, float, NumericParamValue, Float)): 475 self.value = float(value) 476 else: 477 raise TypeError, "Can't convert object of type %s to Float" \ 478 % type(value).__name__ 479 480 def getValue(self): 481 return float(self.value) 482 483class MemorySize(CheckedInt): 484 cxx_type = 'uint64_t' 485 size = 64 486 unsigned = True 487 def __init__(self, value): 488 if isinstance(value, MemorySize): 489 self.value = value.value 490 else: 491 self.value = convert.toMemorySize(value) 492 self._check() 493 494class MemorySize32(CheckedInt): 495 cxx_type = 'uint32_t' 496 size = 32 497 unsigned = True 498 def __init__(self, value): 499 if isinstance(value, MemorySize): 500 self.value = value.value 501 else: 502 self.value = convert.toMemorySize(value) 503 self._check() 504 505class Addr(CheckedInt): 506 cxx_type = 'Addr' 507 size = 64 508 unsigned = True 509 def __init__(self, value): 510 if isinstance(value, Addr): 511 self.value = value.value 512 else: 513 try: 514 self.value = convert.toMemorySize(value) 515 except TypeError: 516 self.value = long(value) 517 self._check() 518 def __add__(self, other): 519 if isinstance(other, Addr): 520 return self.value + other.value 521 else: 522 return self.value + other 523 524 525class MetaRange(MetaParamValue): 526 def __init__(cls, name, bases, dict): 527 super(MetaRange, cls).__init__(name, bases, dict) 528 if name == 'Range': 529 return 530 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 531 532class Range(ParamValue): 533 __metaclass__ = MetaRange 534 type = Int # default; can be overridden in subclasses 535 def __init__(self, *args, **kwargs): 536 def handle_kwargs(self, kwargs): 537 if 'end' in kwargs: 538 self.second = self.type(kwargs.pop('end')) 539 elif 'size' in kwargs: 540 self.second = self.first + self.type(kwargs.pop('size')) - 1 541 else: 542 raise TypeError, "Either end or size must be specified" 543 544 if len(args) == 0: 545 self.first = self.type(kwargs.pop('start')) 546 handle_kwargs(self, kwargs) 547 548 elif len(args) == 1: 549 if kwargs: 550 self.first = self.type(args[0]) 551 handle_kwargs(self, kwargs) 552 elif isinstance(args[0], Range): 553 self.first = self.type(args[0].first) 554 self.second = self.type(args[0].second) 555 elif isinstance(args[0], (list, tuple)): 556 self.first = self.type(args[0][0]) 557 self.second = self.type(args[0][1]) 558 else: 559 self.first = self.type(0) 560 self.second = self.type(args[0]) - 1 561 562 elif len(args) == 2: 563 self.first = self.type(args[0]) 564 self.second = self.type(args[1]) 565 else: 566 raise TypeError, "Too many arguments specified" 567 568 if kwargs: 569 raise TypeError, "too many keywords: %s" % kwargs.keys() 570 571 def __str__(self): 572 return '%s:%s' % (self.first, self.second) 573 574 @classmethod 575 def cxx_predecls(cls, code): 576 cls.type.cxx_predecls(code) 577 code('#include "base/range.hh"') 578 579 @classmethod 580 def swig_predecls(cls, code): 581 cls.type.swig_predecls(code) 582 code('%import "python/swig/range.i"') 583 584class AddrRange(Range): 585 type = Addr 586 587 def getValue(self): 588 from m5.internal.range import AddrRange 589 590 value = AddrRange() 591 value.start = long(self.first) 592 value.end = long(self.second) 593 return value 594 595class TickRange(Range): 596 type = Tick 597 598 def getValue(self): 599 from m5.internal.range import TickRange 600 601 value = TickRange() 602 value.start = long(self.first) 603 value.end = long(self.second) 604 return value 605 606# Boolean parameter type. Python doesn't let you subclass bool, since 607# it doesn't want to let you create multiple instances of True and 608# False. Thus this is a little more complicated than String. 609class Bool(ParamValue): 610 cxx_type = 'bool' 611 def __init__(self, value): 612 try: 613 self.value = convert.toBool(value) 614 except TypeError: 615 self.value = bool(value) 616 617 def getValue(self): 618 return bool(self.value) 619 620 def __str__(self): 621 return str(self.value) 622 623 def ini_str(self): 624 if self.value: 625 return 'true' 626 return 'false' 627 628def IncEthernetAddr(addr, val = 1): 629 bytes = map(lambda x: int(x, 16), addr.split(':')) 630 bytes[5] += val 631 for i in (5, 4, 3, 2, 1): 632 val,rem = divmod(bytes[i], 256) 633 bytes[i] = rem 634 if val == 0: 635 break 636 bytes[i - 1] += val 637 assert(bytes[0] <= 255) 638 return ':'.join(map(lambda x: '%02x' % x, bytes)) 639 640_NextEthernetAddr = "00:90:00:00:00:01" 641def NextEthernetAddr(): 642 global _NextEthernetAddr 643 644 value = _NextEthernetAddr 645 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 646 return value 647 648class EthernetAddr(ParamValue): 649 cxx_type = 'Net::EthAddr' 650 651 @classmethod 652 def cxx_predecls(cls, code): 653 code('#include "base/inet.hh"') 654 655 @classmethod 656 def swig_predecls(cls, code): 657 code('%include "python/swig/inet.i"') 658 659 def __init__(self, value): 660 if value == NextEthernetAddr: 661 self.value = value 662 return 663 664 if not isinstance(value, str): 665 raise TypeError, "expected an ethernet address and didn't get one" 666 667 bytes = value.split(':') 668 if len(bytes) != 6: 669 raise TypeError, 'invalid ethernet address %s' % value 670 671 for byte in bytes: 672 if not 0 <= int(byte) <= 0xff: 673 raise TypeError, 'invalid ethernet address %s' % value 674 675 self.value = value 676 677 def unproxy(self, base): 678 if self.value == NextEthernetAddr: 679 return EthernetAddr(self.value()) 680 return self 681 682 def getValue(self): 683 from m5.internal.params import EthAddr 684 return EthAddr(self.value) 685 686 def ini_str(self): 687 return self.value 688 689# When initializing an IpAddress, pass in an existing IpAddress, a string of 690# the form "a.b.c.d", or an integer representing an IP. 691class IpAddress(ParamValue): 692 cxx_type = 'Net::IpAddress' 693 694 @classmethod 695 def cxx_predecls(cls, code): 696 code('#include "base/inet.hh"') 697 698 @classmethod 699 def swig_predecls(cls, code): 700 code('%include "python/swig/inet.i"') 701 702 def __init__(self, value): 703 if isinstance(value, IpAddress): 704 self.ip = value.ip 705 else: 706 try: 707 self.ip = convert.toIpAddress(value) 708 except TypeError: 709 self.ip = long(value) 710 self.verifyIp() 711 712 def __str__(self): 713 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 714 return '%d.%d.%d.%d' % tuple(tup) 715 716 def __eq__(self, other): 717 if isinstance(other, IpAddress): 718 return self.ip == other.ip 719 elif isinstance(other, str): 720 try: 721 return self.ip == convert.toIpAddress(other) 722 except: 723 return False 724 else: 725 return self.ip == other 726 727 def __ne__(self, other): 728 return not (self == other) 729 730 def verifyIp(self): 731 if self.ip < 0 or self.ip >= (1 << 32): 732 raise TypeError, "invalid ip address %#08x" % self.ip 733 734 def getValue(self): 735 from m5.internal.params import IpAddress 736 return IpAddress(self.ip) 737 738# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 739# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 740# positional or keyword arguments. 741class IpNetmask(IpAddress): 742 cxx_type = 'Net::IpNetmask' 743 744 @classmethod 745 def cxx_predecls(cls, code): 746 code('#include "base/inet.hh"') 747 748 @classmethod 749 def swig_predecls(cls, code): 750 code('%include "python/swig/inet.i"') 751 752 def __init__(self, *args, **kwargs): 753 def handle_kwarg(self, kwargs, key, elseVal = None): 754 if key in kwargs: 755 setattr(self, key, kwargs.pop(key)) 756 elif elseVal: 757 setattr(self, key, elseVal) 758 else: 759 raise TypeError, "No value set for %s" % key 760 761 if len(args) == 0: 762 handle_kwarg(self, kwargs, 'ip') 763 handle_kwarg(self, kwargs, 'netmask') 764 765 elif len(args) == 1: 766 if kwargs: 767 if not 'ip' in kwargs and not 'netmask' in kwargs: 768 raise TypeError, "Invalid arguments" 769 handle_kwarg(self, kwargs, 'ip', args[0]) 770 handle_kwarg(self, kwargs, 'netmask', args[0]) 771 elif isinstance(args[0], IpNetmask): 772 self.ip = args[0].ip 773 self.netmask = args[0].netmask 774 else: 775 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 776 777 elif len(args) == 2: 778 self.ip = args[0] 779 self.netmask = args[1] 780 else: 781 raise TypeError, "Too many arguments specified" 782 783 if kwargs: 784 raise TypeError, "Too many keywords: %s" % kwargs.keys() 785 786 self.verify() 787 788 def __str__(self): 789 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 790 791 def __eq__(self, other): 792 if isinstance(other, IpNetmask): 793 return self.ip == other.ip and self.netmask == other.netmask 794 elif isinstance(other, str): 795 try: 796 return (self.ip, self.netmask) == convert.toIpNetmask(other) 797 except: 798 return False 799 else: 800 return False 801 802 def verify(self): 803 self.verifyIp() 804 if self.netmask < 0 or self.netmask > 32: 805 raise TypeError, "invalid netmask %d" % netmask 806 807 def getValue(self): 808 from m5.internal.params import IpNetmask 809 return IpNetmask(self.ip, self.netmask) 810 811# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 812# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 813class IpWithPort(IpAddress): 814 cxx_type = 'Net::IpWithPort' 815 816 @classmethod 817 def cxx_predecls(cls, code): 818 code('#include "base/inet.hh"') 819 820 @classmethod 821 def swig_predecls(cls, code): 822 code('%include "python/swig/inet.i"') 823 824 def __init__(self, *args, **kwargs): 825 def handle_kwarg(self, kwargs, key, elseVal = None): 826 if key in kwargs: 827 setattr(self, key, kwargs.pop(key)) 828 elif elseVal: 829 setattr(self, key, elseVal) 830 else: 831 raise TypeError, "No value set for %s" % key 832 833 if len(args) == 0: 834 handle_kwarg(self, kwargs, 'ip') 835 handle_kwarg(self, kwargs, 'port') 836 837 elif len(args) == 1: 838 if kwargs: 839 if not 'ip' in kwargs and not 'port' in kwargs: 840 raise TypeError, "Invalid arguments" 841 handle_kwarg(self, kwargs, 'ip', args[0]) 842 handle_kwarg(self, kwargs, 'port', args[0]) 843 elif isinstance(args[0], IpWithPort): 844 self.ip = args[0].ip 845 self.port = args[0].port 846 else: 847 (self.ip, self.port) = convert.toIpWithPort(args[0]) 848 849 elif len(args) == 2: 850 self.ip = args[0] 851 self.port = args[1] 852 else: 853 raise TypeError, "Too many arguments specified" 854 855 if kwargs: 856 raise TypeError, "Too many keywords: %s" % kwargs.keys() 857 858 self.verify() 859 860 def __str__(self): 861 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 862 863 def __eq__(self, other): 864 if isinstance(other, IpWithPort): 865 return self.ip == other.ip and self.port == other.port 866 elif isinstance(other, str): 867 try: 868 return (self.ip, self.port) == convert.toIpWithPort(other) 869 except: 870 return False 871 else: 872 return False 873 874 def verify(self): 875 self.verifyIp() 876 if self.port < 0 or self.port > 0xffff: 877 raise TypeError, "invalid port %d" % self.port 878 879 def getValue(self): 880 from m5.internal.params import IpWithPort 881 return IpWithPort(self.ip, self.port) 882 883time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 884 "%a %b %d %H:%M:%S %Z %Y", 885 "%Y/%m/%d %H:%M:%S", 886 "%Y/%m/%d %H:%M", 887 "%Y/%m/%d", 888 "%m/%d/%Y %H:%M:%S", 889 "%m/%d/%Y %H:%M", 890 "%m/%d/%Y", 891 "%m/%d/%y %H:%M:%S", 892 "%m/%d/%y %H:%M", 893 "%m/%d/%y"] 894 895 896def parse_time(value): 897 from time import gmtime, strptime, struct_time, time 898 from datetime import datetime, date 899 900 if isinstance(value, struct_time): 901 return value 902 903 if isinstance(value, (int, long)): 904 return gmtime(value) 905 906 if isinstance(value, (datetime, date)): 907 return value.timetuple() 908 909 if isinstance(value, str): 910 if value in ('Now', 'Today'): 911 return time.gmtime(time.time()) 912 913 for format in time_formats: 914 try: 915 return strptime(value, format) 916 except ValueError: 917 pass 918 919 raise ValueError, "Could not parse '%s' as a time" % value 920 921class Time(ParamValue): 922 cxx_type = 'tm' 923 924 @classmethod 925 def cxx_predecls(cls, code): 926 code('#include <time.h>') 927 928 @classmethod 929 def swig_predecls(cls, code): 930 code('%include "python/swig/time.i"') 931 932 def __init__(self, value): 933 self.value = parse_time(value) 934 935 def getValue(self): 936 from m5.internal.params import tm 937 938 c_time = tm() 939 py_time = self.value 940 941 # UNIX is years since 1900 942 c_time.tm_year = py_time.tm_year - 1900; 943 944 # Python starts at 1, UNIX starts at 0 945 c_time.tm_mon = py_time.tm_mon - 1; 946 c_time.tm_mday = py_time.tm_mday; 947 c_time.tm_hour = py_time.tm_hour; 948 c_time.tm_min = py_time.tm_min; 949 c_time.tm_sec = py_time.tm_sec; 950 951 # Python has 0 as Monday, UNIX is 0 as sunday 952 c_time.tm_wday = py_time.tm_wday + 1 953 if c_time.tm_wday > 6: 954 c_time.tm_wday -= 7; 955 956 # Python starts at 1, Unix starts at 0 957 c_time.tm_yday = py_time.tm_yday - 1; 958 959 return c_time 960 961 def __str__(self): 962 return time.asctime(self.value) 963 964 def ini_str(self): 965 return str(self) 966 967# Enumerated types are a little more complex. The user specifies the 968# type as Enum(foo) where foo is either a list or dictionary of 969# alternatives (typically strings, but not necessarily so). (In the 970# long run, the integer value of the parameter will be the list index 971# or the corresponding dictionary value. For now, since we only check 972# that the alternative is valid and then spit it into a .ini file, 973# there's not much point in using the dictionary.) 974 975# What Enum() must do is generate a new type encapsulating the 976# provided list/dictionary so that specific values of the parameter 977# can be instances of that type. We define two hidden internal 978# classes (_ListEnum and _DictEnum) to serve as base classes, then 979# derive the new type from the appropriate base class on the fly. 980 981allEnums = {} 982# Metaclass for Enum types 983class MetaEnum(MetaParamValue): 984 def __new__(mcls, name, bases, dict): 985 assert name not in allEnums 986 987 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 988 allEnums[name] = cls 989 return cls 990 991 def __init__(cls, name, bases, init_dict): 992 if init_dict.has_key('map'): 993 if not isinstance(cls.map, dict): 994 raise TypeError, "Enum-derived class attribute 'map' " \ 995 "must be of type dict" 996 # build list of value strings from map 997 cls.vals = cls.map.keys() 998 cls.vals.sort() 999 elif init_dict.has_key('vals'): 1000 if not isinstance(cls.vals, list): 1001 raise TypeError, "Enum-derived class attribute 'vals' " \ 1002 "must be of type list" 1003 # build string->value map from vals sequence 1004 cls.map = {} 1005 for idx,val in enumerate(cls.vals): 1006 cls.map[val] = idx 1007 else: 1008 raise TypeError, "Enum-derived class must define "\ 1009 "attribute 'map' or 'vals'" 1010 1011 cls.cxx_type = 'Enums::%s' % name 1012 1013 super(MetaEnum, cls).__init__(name, bases, init_dict) 1014 1015 # Generate C++ class declaration for this enum type. 1016 # Note that we wrap the enum in a class/struct to act as a namespace, 1017 # so that the enum strings can be brief w/o worrying about collisions. 1018 def cxx_decl(cls, code): 1019 name = cls.__name__ 1020 code('''\ 1021#ifndef __ENUM__${name}__ 1022#define __ENUM__${name}__ 1023 1024namespace Enums { 1025 enum $name { 1026''') 1027 code.indent(2) 1028 for val in cls.vals: 1029 code('$val = ${{cls.map[val]}},') 1030 code('Num_$name = ${{len(cls.vals)}},') 1031 code.dedent(2) 1032 code('''\ 1033 }; 1034extern const char *${name}Strings[Num_${name}]; 1035} 1036 1037#endif // __ENUM__${name}__ 1038''') 1039 1040 def cxx_def(cls, code): 1041 name = cls.__name__ 1042 code('''\ 1043#include "enums/$name.hh" 1044namespace Enums { 1045 const char *${name}Strings[Num_${name}] = 1046 { 1047''') 1048 code.indent(2) 1049 for val in cls.vals: 1050 code('"$val",') 1051 code.dedent(2) 1052 code(''' 1053 }; 1054} // namespace Enums 1055''') 1056 1057 def swig_decl(cls, code): 1058 name = cls.__name__ 1059 code('''\ 1060%module(package="m5.internal") enum_$name 1061 1062%{ 1063#include "enums/$name.hh" 1064%} 1065 1066%include "enums/$name.hh" 1067''') 1068 1069 1070# Base class for enum types. 1071class Enum(ParamValue): 1072 __metaclass__ = MetaEnum 1073 vals = [] 1074 1075 def __init__(self, value): 1076 if value not in self.map: 1077 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1078 % (value, self.vals) 1079 self.value = value 1080 1081 @classmethod 1082 def cxx_predecls(cls, code): 1083 code('#include "enums/$0.hh"', cls.__name__) 1084 1085 @classmethod 1086 def swig_predecls(cls, code): 1087 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1088 1089 def getValue(self): 1090 return int(self.map[self.value]) 1091 1092 def __str__(self): 1093 return self.value 1094 1095# how big does a rounding error need to be before we warn about it? 1096frequency_tolerance = 0.001 # 0.1% 1097 1098class TickParamValue(NumericParamValue): 1099 cxx_type = 'Tick' 1100 1101 @classmethod 1102 def cxx_predecls(cls, code): 1103 code('#include "base/types.hh"') 1104 1105 @classmethod 1106 def swig_predecls(cls, code): 1107 code('%import "stdint.i"') 1108 code('%import "base/types.hh"') 1109 1110 def getValue(self): 1111 return long(self.value) 1112 1113class Latency(TickParamValue): 1114 def __init__(self, value): 1115 if isinstance(value, (Latency, Clock)): 1116 self.ticks = value.ticks 1117 self.value = value.value 1118 elif isinstance(value, Frequency): 1119 self.ticks = value.ticks 1120 self.value = 1.0 / value.value 1121 elif value.endswith('t'): 1122 self.ticks = True 1123 self.value = int(value[:-1]) 1124 else: 1125 self.ticks = False 1126 self.value = convert.toLatency(value) 1127 1128 def __getattr__(self, attr): 1129 if attr in ('latency', 'period'): 1130 return self 1131 if attr == 'frequency': 1132 return Frequency(self) 1133 raise AttributeError, "Latency object has no attribute '%s'" % attr 1134 1135 def getValue(self): 1136 if self.ticks or self.value == 0: 1137 value = self.value 1138 else: 1139 value = ticks.fromSeconds(self.value) 1140 return long(value) 1141 1142 # convert latency to ticks 1143 def ini_str(self): 1144 return '%d' % self.getValue() 1145 1146class Frequency(TickParamValue): 1147 def __init__(self, value): 1148 if isinstance(value, (Latency, Clock)): 1149 if value.value == 0: 1150 self.value = 0 1151 else: 1152 self.value = 1.0 / value.value 1153 self.ticks = value.ticks 1154 elif isinstance(value, Frequency): 1155 self.value = value.value 1156 self.ticks = value.ticks 1157 else: 1158 self.ticks = False 1159 self.value = convert.toFrequency(value) 1160 1161 def __getattr__(self, attr): 1162 if attr == 'frequency': 1163 return self 1164 if attr in ('latency', 'period'): 1165 return Latency(self) 1166 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1167 1168 # convert latency to ticks 1169 def getValue(self): 1170 if self.ticks or self.value == 0: 1171 value = self.value 1172 else: 1173 value = ticks.fromSeconds(1.0 / self.value) 1174 return long(value) 1175 1176 def ini_str(self): 1177 return '%d' % self.getValue() 1178 1179# A generic frequency and/or Latency value. Value is stored as a latency, 1180# but to avoid ambiguity this object does not support numeric ops (* or /). 1181# An explicit conversion to a Latency or Frequency must be made first. 1182class Clock(ParamValue): 1183 cxx_type = 'Tick' 1184 1185 @classmethod 1186 def cxx_predecls(cls, code): 1187 code('#include "base/types.hh"') 1188 1189 @classmethod 1190 def swig_predecls(cls, code): 1191 code('%import "stdint.i"') 1192 code('%import "base/types.hh"') 1193 1194 def __init__(self, value): 1195 if isinstance(value, (Latency, Clock)): 1196 self.ticks = value.ticks 1197 self.value = value.value 1198 elif isinstance(value, Frequency): 1199 self.ticks = value.ticks 1200 self.value = 1.0 / value.value 1201 elif value.endswith('t'): 1202 self.ticks = True 1203 self.value = int(value[:-1]) 1204 else: 1205 self.ticks = False 1206 self.value = convert.anyToLatency(value) 1207 1208 def __getattr__(self, attr): 1209 if attr == 'frequency': 1210 return Frequency(self) 1211 if attr in ('latency', 'period'): 1212 return Latency(self) 1213 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1214 1215 def getValue(self): 1216 return self.period.getValue() 1217 1218 def ini_str(self): 1219 return self.period.ini_str() 1220 1221class NetworkBandwidth(float,ParamValue): 1222 cxx_type = 'float' 1223 def __new__(cls, value): 1224 # convert to bits per second 1225 val = convert.toNetworkBandwidth(value) 1226 return super(cls, NetworkBandwidth).__new__(cls, val) 1227 1228 def __str__(self): 1229 return str(self.val) 1230 1231 def getValue(self): 1232 # convert to seconds per byte 1233 value = 8.0 / float(self) 1234 # convert to ticks per byte 1235 value = ticks.fromSeconds(value) 1236 return float(value) 1237 1238 def ini_str(self): 1239 return '%f' % self.getValue() 1240 1241class MemoryBandwidth(float,ParamValue): 1242 cxx_type = 'float' 1243 def __new__(cls, value): 1244 # convert to bytes per second 1245 val = convert.toMemoryBandwidth(value) 1246 return super(cls, MemoryBandwidth).__new__(cls, val) 1247 1248 def __str__(self): 1249 return str(self.val) 1250 1251 def getValue(self): 1252 # convert to seconds per byte 1253 value = float(self) 1254 if value: 1255 value = 1.0 / float(self) 1256 # convert to ticks per byte 1257 value = ticks.fromSeconds(value) 1258 return float(value) 1259 1260 def ini_str(self): 1261 return '%f' % self.getValue() 1262 1263# 1264# "Constants"... handy aliases for various values. 1265# 1266 1267# Special class for NULL pointers. Note the special check in 1268# make_param_value() above that lets these be assigned where a 1269# SimObject is required. 1270# only one copy of a particular node 1271class NullSimObject(object): 1272 __metaclass__ = Singleton 1273 1274 def __call__(cls): 1275 return cls 1276 1277 def _instantiate(self, parent = None, path = ''): 1278 pass 1279 1280 def ini_str(self): 1281 return 'Null' 1282 1283 def unproxy(self, base): 1284 return self 1285 1286 def set_path(self, parent, name): 1287 pass 1288 1289 def __str__(self): 1290 return 'Null' 1291 1292 def getValue(self): 1293 return None 1294 1295# The only instance you'll ever need... 1296NULL = NullSimObject() 1297 1298def isNullPointer(value): 1299 return isinstance(value, NullSimObject) 1300 1301# Some memory range specifications use this as a default upper bound. 1302MaxAddr = Addr.max 1303MaxTick = Tick.max 1304AllMemory = AddrRange(0, MaxAddr) 1305 1306 1307##################################################################### 1308# 1309# Port objects 1310# 1311# Ports are used to interconnect objects in the memory system. 1312# 1313##################################################################### 1314 1315# Port reference: encapsulates a reference to a particular port on a 1316# particular SimObject. 1317class PortRef(object): 1318 def __init__(self, simobj, name): 1319 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1320 self.simobj = simobj 1321 self.name = name 1322 self.peer = None # not associated with another port yet 1323 self.ccConnected = False # C++ port connection done? 1324 self.index = -1 # always -1 for non-vector ports 1325 1326 def __str__(self): 1327 return '%s.%s' % (self.simobj, self.name) 1328 1329 # for config.ini, print peer's name (not ours) 1330 def ini_str(self): 1331 return str(self.peer) 1332 1333 def __getattr__(self, attr): 1334 if attr == 'peerObj': 1335 # shorthand for proxies 1336 return self.peer.simobj 1337 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1338 (self.__class__.__name__, attr) 1339 1340 # Full connection is symmetric (both ways). Called via 1341 # SimObject.__setattr__ as a result of a port assignment, e.g., 1342 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1343 # e.g., "obj1.portA[3] = obj2.portB". 1344 def connect(self, other): 1345 if isinstance(other, VectorPortRef): 1346 # reference to plain VectorPort is implicit append 1347 other = other._get_next() 1348 if self.peer and not proxy.isproxy(self.peer): 1349 print "warning: overwriting port", self, \ 1350 "value", self.peer, "with", other 1351 self.peer.peer = None 1352 self.peer = other 1353 if proxy.isproxy(other): 1354 other.set_param_desc(PortParamDesc()) 1355 elif isinstance(other, PortRef): 1356 if other.peer is not self: 1357 other.connect(self) 1358 else: 1359 raise TypeError, \ 1360 "assigning non-port reference '%s' to port '%s'" \ 1361 % (other, self) 1362 1363 def clone(self, simobj, memo): 1364 if memo.has_key(self): 1365 return memo[self] 1366 newRef = copy.copy(self) 1367 memo[self] = newRef 1368 newRef.simobj = simobj 1369 assert(isSimObject(newRef.simobj)) 1370 if self.peer and not proxy.isproxy(self.peer): 1371 peerObj = self.peer.simobj(_memo=memo) 1372 newRef.peer = self.peer.clone(peerObj, memo) 1373 assert(not isinstance(newRef.peer, VectorPortRef)) 1374 return newRef 1375 1376 def unproxy(self, simobj): 1377 assert(simobj is self.simobj) 1378 if proxy.isproxy(self.peer): 1379 try: 1380 realPeer = self.peer.unproxy(self.simobj) 1381 except: 1382 print "Error in unproxying port '%s' of %s" % \ 1383 (self.name, self.simobj.path()) 1384 raise 1385 self.connect(realPeer) 1386 1387 # Call C++ to create corresponding port connection between C++ objects 1388 def ccConnect(self): 1389 from m5.internal.pyobject import connectPorts 1390 1391 if self.ccConnected: # already done this 1392 return 1393 peer = self.peer 1394 if not self.peer: # nothing to connect to 1395 return 1396 try: 1397 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1398 peer.simobj.getCCObject(), peer.name, peer.index) 1399 except: 1400 print "Error connecting port %s.%s to %s.%s" % \ 1401 (self.simobj.path(), self.name, 1402 peer.simobj.path(), peer.name) 1403 raise 1404 self.ccConnected = True 1405 peer.ccConnected = True 1406 1407# A reference to an individual element of a VectorPort... much like a 1408# PortRef, but has an index. 1409class VectorPortElementRef(PortRef): 1410 def __init__(self, simobj, name, index): 1411 PortRef.__init__(self, simobj, name) 1412 self.index = index 1413 1414 def __str__(self): 1415 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1416 1417# A reference to a complete vector-valued port (not just a single element). 1418# Can be indexed to retrieve individual VectorPortElementRef instances. 1419class VectorPortRef(object): 1420 def __init__(self, simobj, name): 1421 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1422 self.simobj = simobj 1423 self.name = name 1424 self.elements = [] 1425 1426 def __str__(self): 1427 return '%s.%s[:]' % (self.simobj, self.name) 1428 1429 # for config.ini, print peer's name (not ours) 1430 def ini_str(self): 1431 return ' '.join([el.ini_str() for el in self.elements]) 1432 1433 def __getitem__(self, key): 1434 if not isinstance(key, int): 1435 raise TypeError, "VectorPort index must be integer" 1436 if key >= len(self.elements): 1437 # need to extend list 1438 ext = [VectorPortElementRef(self.simobj, self.name, i) 1439 for i in range(len(self.elements), key+1)] 1440 self.elements.extend(ext) 1441 return self.elements[key] 1442 1443 def _get_next(self): 1444 return self[len(self.elements)] 1445 1446 def __setitem__(self, key, value): 1447 if not isinstance(key, int): 1448 raise TypeError, "VectorPort index must be integer" 1449 self[key].connect(value) 1450 1451 def connect(self, other): 1452 if isinstance(other, (list, tuple)): 1453 # Assign list of port refs to vector port. 1454 # For now, append them... not sure if that's the right semantics 1455 # or if it should replace the current vector. 1456 for ref in other: 1457 self._get_next().connect(ref) 1458 else: 1459 # scalar assignment to plain VectorPort is implicit append 1460 self._get_next().connect(other) 1461 1462 def clone(self, simobj, memo): 1463 if memo.has_key(self): 1464 return memo[self] 1465 newRef = copy.copy(self) 1466 memo[self] = newRef 1467 newRef.simobj = simobj 1468 assert(isSimObject(newRef.simobj)) 1469 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1470 return newRef 1471 1472 def unproxy(self, simobj): 1473 [el.unproxy(simobj) for el in self.elements] 1474 1475 def ccConnect(self): 1476 [el.ccConnect() for el in self.elements] 1477 1478# Port description object. Like a ParamDesc object, this represents a 1479# logical port in the SimObject class, not a particular port on a 1480# SimObject instance. The latter are represented by PortRef objects. 1481class Port(object): 1482 # Port("description") or Port(default, "description") 1483 def __init__(self, *args): 1484 if len(args) == 1: 1485 self.desc = args[0] 1486 elif len(args) == 2: 1487 self.default = args[0] 1488 self.desc = args[1] 1489 else: 1490 raise TypeError, 'wrong number of arguments' 1491 # self.name is set by SimObject class on assignment 1492 # e.g., pio_port = Port("blah") sets self.name to 'pio_port' 1493 1494 # Generate a PortRef for this port on the given SimObject with the 1495 # given name 1496 def makeRef(self, simobj): 1497 return PortRef(simobj, self.name) 1498 1499 # Connect an instance of this port (on the given SimObject with 1500 # the given name) with the port described by the supplied PortRef 1501 def connect(self, simobj, ref): 1502 self.makeRef(simobj).connect(ref) 1503 1504# VectorPort description object. Like Port, but represents a vector 1505# of connections (e.g., as on a Bus). 1506class VectorPort(Port): 1507 def __init__(self, *args): 1508 Port.__init__(self, *args) 1509 self.isVec = True 1510 1511 def makeRef(self, simobj): 1512 return VectorPortRef(simobj, self.name) 1513 1514# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1515# proxy objects (via set_param_desc()) so that proxy error messages 1516# make sense. 1517class PortParamDesc(object): 1518 __metaclass__ = Singleton 1519 1520 ptype_str = 'Port' 1521 ptype = Port 1522 1523baseEnums = allEnums.copy() 1524baseParams = allParams.copy() 1525 1526def clear(): 1527 global allEnums, allParams 1528 1529 allEnums = baseEnums.copy() 1530 allParams = baseParams.copy() 1531 1532__all__ = ['Param', 'VectorParam', 1533 'Enum', 'Bool', 'String', 'Float', 1534 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1535 'Int32', 'UInt32', 'Int64', 'UInt64', 1536 'Counter', 'Addr', 'Tick', 'Percent', 1537 'TcpPort', 'UdpPort', 'EthernetAddr', 1538 'IpAddress', 'IpNetmask', 'IpWithPort', 1539 'MemorySize', 'MemorySize32', 1540 'Latency', 'Frequency', 'Clock', 1541 'NetworkBandwidth', 'MemoryBandwidth', 1542 'Range', 'AddrRange', 'TickRange', 1543 'MaxAddr', 'MaxTick', 'AllMemory', 1544 'Time', 1545 'NextEthernetAddr', 'NULL', 1546 'Port', 'VectorPort'] 1547 1548import SimObject 1549