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