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