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