params.py revision 9232
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 = 'Range<Addr>' 554 555 def __init__(self, *args, **kwargs): 556 def handle_kwargs(self, kwargs): 557 if 'end' in kwargs: 558 self.end = Addr(kwargs.pop('end')) 559 elif 'size' in kwargs: 560 self.end = self.start + Addr(kwargs.pop('size')) - 1 561 else: 562 raise TypeError, "Either end or size must be specified" 563 564 if len(args) == 0: 565 self.start = Addr(kwargs.pop('start')) 566 handle_kwargs(self, kwargs) 567 568 elif len(args) == 1: 569 if kwargs: 570 self.start = Addr(args[0]) 571 handle_kwargs(self, kwargs) 572 elif isinstance(args[0], (list, tuple)): 573 self.start = Addr(args[0][0]) 574 self.end = Addr(args[0][1]) 575 else: 576 self.start = Addr(0) 577 self.end = Addr(args[0]) - 1 578 579 elif len(args) == 2: 580 self.start = Addr(args[0]) 581 self.end = Addr(args[1]) 582 else: 583 raise TypeError, "Too many arguments specified" 584 585 if kwargs: 586 raise TypeError, "Too many keywords: %s" % kwargs.keys() 587 588 def __str__(self): 589 return '%s:%s' % (self.start, self.end) 590 591 def size(self): 592 return long(self.end) - long(self.start) + 1 593 594 @classmethod 595 def cxx_predecls(cls, code): 596 Addr.cxx_predecls(code) 597 code('#include "base/range.hh"') 598 599 @classmethod 600 def swig_predecls(cls, code): 601 Addr.swig_predecls(code) 602 code('%import "python/swig/range.i"') 603 604 def getValue(self): 605 from m5.internal.range import AddrRange 606 607 value = AddrRange() 608 value.start = long(self.start) 609 value.end = long(self.end) 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 # implement truth value testing for Bool parameters so that these params 630 # evaluate correctly during the python configuration phase 631 def __nonzero__(self): 632 return bool(self.value) 633 634 def ini_str(self): 635 if self.value: 636 return 'true' 637 return 'false' 638 639def IncEthernetAddr(addr, val = 1): 640 bytes = map(lambda x: int(x, 16), addr.split(':')) 641 bytes[5] += val 642 for i in (5, 4, 3, 2, 1): 643 val,rem = divmod(bytes[i], 256) 644 bytes[i] = rem 645 if val == 0: 646 break 647 bytes[i - 1] += val 648 assert(bytes[0] <= 255) 649 return ':'.join(map(lambda x: '%02x' % x, bytes)) 650 651_NextEthernetAddr = "00:90:00:00:00:01" 652def NextEthernetAddr(): 653 global _NextEthernetAddr 654 655 value = _NextEthernetAddr 656 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 657 return value 658 659class EthernetAddr(ParamValue): 660 cxx_type = 'Net::EthAddr' 661 662 @classmethod 663 def cxx_predecls(cls, code): 664 code('#include "base/inet.hh"') 665 666 @classmethod 667 def swig_predecls(cls, code): 668 code('%include "python/swig/inet.i"') 669 670 def __init__(self, value): 671 if value == NextEthernetAddr: 672 self.value = value 673 return 674 675 if not isinstance(value, str): 676 raise TypeError, "expected an ethernet address and didn't get one" 677 678 bytes = value.split(':') 679 if len(bytes) != 6: 680 raise TypeError, 'invalid ethernet address %s' % value 681 682 for byte in bytes: 683 if not 0 <= int(byte) <= 0xff: 684 raise TypeError, 'invalid ethernet address %s' % value 685 686 self.value = value 687 688 def unproxy(self, base): 689 if self.value == NextEthernetAddr: 690 return EthernetAddr(self.value()) 691 return self 692 693 def getValue(self): 694 from m5.internal.params import EthAddr 695 return EthAddr(self.value) 696 697 def ini_str(self): 698 return self.value 699 700# When initializing an IpAddress, pass in an existing IpAddress, a string of 701# the form "a.b.c.d", or an integer representing an IP. 702class IpAddress(ParamValue): 703 cxx_type = 'Net::IpAddress' 704 705 @classmethod 706 def cxx_predecls(cls, code): 707 code('#include "base/inet.hh"') 708 709 @classmethod 710 def swig_predecls(cls, code): 711 code('%include "python/swig/inet.i"') 712 713 def __init__(self, value): 714 if isinstance(value, IpAddress): 715 self.ip = value.ip 716 else: 717 try: 718 self.ip = convert.toIpAddress(value) 719 except TypeError: 720 self.ip = long(value) 721 self.verifyIp() 722 723 def __str__(self): 724 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 725 return '%d.%d.%d.%d' % tuple(tup) 726 727 def __eq__(self, other): 728 if isinstance(other, IpAddress): 729 return self.ip == other.ip 730 elif isinstance(other, str): 731 try: 732 return self.ip == convert.toIpAddress(other) 733 except: 734 return False 735 else: 736 return self.ip == other 737 738 def __ne__(self, other): 739 return not (self == other) 740 741 def verifyIp(self): 742 if self.ip < 0 or self.ip >= (1 << 32): 743 raise TypeError, "invalid ip address %#08x" % self.ip 744 745 def getValue(self): 746 from m5.internal.params import IpAddress 747 return IpAddress(self.ip) 748 749# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 750# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 751# positional or keyword arguments. 752class IpNetmask(IpAddress): 753 cxx_type = 'Net::IpNetmask' 754 755 @classmethod 756 def cxx_predecls(cls, code): 757 code('#include "base/inet.hh"') 758 759 @classmethod 760 def swig_predecls(cls, code): 761 code('%include "python/swig/inet.i"') 762 763 def __init__(self, *args, **kwargs): 764 def handle_kwarg(self, kwargs, key, elseVal = None): 765 if key in kwargs: 766 setattr(self, key, kwargs.pop(key)) 767 elif elseVal: 768 setattr(self, key, elseVal) 769 else: 770 raise TypeError, "No value set for %s" % key 771 772 if len(args) == 0: 773 handle_kwarg(self, kwargs, 'ip') 774 handle_kwarg(self, kwargs, 'netmask') 775 776 elif len(args) == 1: 777 if kwargs: 778 if not 'ip' in kwargs and not 'netmask' in kwargs: 779 raise TypeError, "Invalid arguments" 780 handle_kwarg(self, kwargs, 'ip', args[0]) 781 handle_kwarg(self, kwargs, 'netmask', args[0]) 782 elif isinstance(args[0], IpNetmask): 783 self.ip = args[0].ip 784 self.netmask = args[0].netmask 785 else: 786 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 787 788 elif len(args) == 2: 789 self.ip = args[0] 790 self.netmask = args[1] 791 else: 792 raise TypeError, "Too many arguments specified" 793 794 if kwargs: 795 raise TypeError, "Too many keywords: %s" % kwargs.keys() 796 797 self.verify() 798 799 def __str__(self): 800 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 801 802 def __eq__(self, other): 803 if isinstance(other, IpNetmask): 804 return self.ip == other.ip and self.netmask == other.netmask 805 elif isinstance(other, str): 806 try: 807 return (self.ip, self.netmask) == convert.toIpNetmask(other) 808 except: 809 return False 810 else: 811 return False 812 813 def verify(self): 814 self.verifyIp() 815 if self.netmask < 0 or self.netmask > 32: 816 raise TypeError, "invalid netmask %d" % netmask 817 818 def getValue(self): 819 from m5.internal.params import IpNetmask 820 return IpNetmask(self.ip, self.netmask) 821 822# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 823# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 824class IpWithPort(IpAddress): 825 cxx_type = 'Net::IpWithPort' 826 827 @classmethod 828 def cxx_predecls(cls, code): 829 code('#include "base/inet.hh"') 830 831 @classmethod 832 def swig_predecls(cls, code): 833 code('%include "python/swig/inet.i"') 834 835 def __init__(self, *args, **kwargs): 836 def handle_kwarg(self, kwargs, key, elseVal = None): 837 if key in kwargs: 838 setattr(self, key, kwargs.pop(key)) 839 elif elseVal: 840 setattr(self, key, elseVal) 841 else: 842 raise TypeError, "No value set for %s" % key 843 844 if len(args) == 0: 845 handle_kwarg(self, kwargs, 'ip') 846 handle_kwarg(self, kwargs, 'port') 847 848 elif len(args) == 1: 849 if kwargs: 850 if not 'ip' in kwargs and not 'port' in kwargs: 851 raise TypeError, "Invalid arguments" 852 handle_kwarg(self, kwargs, 'ip', args[0]) 853 handle_kwarg(self, kwargs, 'port', args[0]) 854 elif isinstance(args[0], IpWithPort): 855 self.ip = args[0].ip 856 self.port = args[0].port 857 else: 858 (self.ip, self.port) = convert.toIpWithPort(args[0]) 859 860 elif len(args) == 2: 861 self.ip = args[0] 862 self.port = args[1] 863 else: 864 raise TypeError, "Too many arguments specified" 865 866 if kwargs: 867 raise TypeError, "Too many keywords: %s" % kwargs.keys() 868 869 self.verify() 870 871 def __str__(self): 872 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 873 874 def __eq__(self, other): 875 if isinstance(other, IpWithPort): 876 return self.ip == other.ip and self.port == other.port 877 elif isinstance(other, str): 878 try: 879 return (self.ip, self.port) == convert.toIpWithPort(other) 880 except: 881 return False 882 else: 883 return False 884 885 def verify(self): 886 self.verifyIp() 887 if self.port < 0 or self.port > 0xffff: 888 raise TypeError, "invalid port %d" % self.port 889 890 def getValue(self): 891 from m5.internal.params import IpWithPort 892 return IpWithPort(self.ip, self.port) 893 894time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 895 "%a %b %d %H:%M:%S %Z %Y", 896 "%Y/%m/%d %H:%M:%S", 897 "%Y/%m/%d %H:%M", 898 "%Y/%m/%d", 899 "%m/%d/%Y %H:%M:%S", 900 "%m/%d/%Y %H:%M", 901 "%m/%d/%Y", 902 "%m/%d/%y %H:%M:%S", 903 "%m/%d/%y %H:%M", 904 "%m/%d/%y"] 905 906 907def parse_time(value): 908 from time import gmtime, strptime, struct_time, time 909 from datetime import datetime, date 910 911 if isinstance(value, struct_time): 912 return value 913 914 if isinstance(value, (int, long)): 915 return gmtime(value) 916 917 if isinstance(value, (datetime, date)): 918 return value.timetuple() 919 920 if isinstance(value, str): 921 if value in ('Now', 'Today'): 922 return time.gmtime(time.time()) 923 924 for format in time_formats: 925 try: 926 return strptime(value, format) 927 except ValueError: 928 pass 929 930 raise ValueError, "Could not parse '%s' as a time" % value 931 932class Time(ParamValue): 933 cxx_type = 'tm' 934 935 @classmethod 936 def cxx_predecls(cls, code): 937 code('#include <time.h>') 938 939 @classmethod 940 def swig_predecls(cls, code): 941 code('%include "python/swig/time.i"') 942 943 def __init__(self, value): 944 self.value = parse_time(value) 945 946 def getValue(self): 947 from m5.internal.params import tm 948 949 c_time = tm() 950 py_time = self.value 951 952 # UNIX is years since 1900 953 c_time.tm_year = py_time.tm_year - 1900; 954 955 # Python starts at 1, UNIX starts at 0 956 c_time.tm_mon = py_time.tm_mon - 1; 957 c_time.tm_mday = py_time.tm_mday; 958 c_time.tm_hour = py_time.tm_hour; 959 c_time.tm_min = py_time.tm_min; 960 c_time.tm_sec = py_time.tm_sec; 961 962 # Python has 0 as Monday, UNIX is 0 as sunday 963 c_time.tm_wday = py_time.tm_wday + 1 964 if c_time.tm_wday > 6: 965 c_time.tm_wday -= 7; 966 967 # Python starts at 1, Unix starts at 0 968 c_time.tm_yday = py_time.tm_yday - 1; 969 970 return c_time 971 972 def __str__(self): 973 return time.asctime(self.value) 974 975 def ini_str(self): 976 return str(self) 977 978 def get_config_as_dict(self): 979 return str(self) 980 981# Enumerated types are a little more complex. The user specifies the 982# type as Enum(foo) where foo is either a list or dictionary of 983# alternatives (typically strings, but not necessarily so). (In the 984# long run, the integer value of the parameter will be the list index 985# or the corresponding dictionary value. For now, since we only check 986# that the alternative is valid and then spit it into a .ini file, 987# there's not much point in using the dictionary.) 988 989# What Enum() must do is generate a new type encapsulating the 990# provided list/dictionary so that specific values of the parameter 991# can be instances of that type. We define two hidden internal 992# classes (_ListEnum and _DictEnum) to serve as base classes, then 993# derive the new type from the appropriate base class on the fly. 994 995allEnums = {} 996# Metaclass for Enum types 997class MetaEnum(MetaParamValue): 998 def __new__(mcls, name, bases, dict): 999 assert name not in allEnums 1000 1001 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1002 allEnums[name] = cls 1003 return cls 1004 1005 def __init__(cls, name, bases, init_dict): 1006 if init_dict.has_key('map'): 1007 if not isinstance(cls.map, dict): 1008 raise TypeError, "Enum-derived class attribute 'map' " \ 1009 "must be of type dict" 1010 # build list of value strings from map 1011 cls.vals = cls.map.keys() 1012 cls.vals.sort() 1013 elif init_dict.has_key('vals'): 1014 if not isinstance(cls.vals, list): 1015 raise TypeError, "Enum-derived class attribute 'vals' " \ 1016 "must be of type list" 1017 # build string->value map from vals sequence 1018 cls.map = {} 1019 for idx,val in enumerate(cls.vals): 1020 cls.map[val] = idx 1021 else: 1022 raise TypeError, "Enum-derived class must define "\ 1023 "attribute 'map' or 'vals'" 1024 1025 cls.cxx_type = 'Enums::%s' % name 1026 1027 super(MetaEnum, cls).__init__(name, bases, init_dict) 1028 1029 # Generate C++ class declaration for this enum type. 1030 # Note that we wrap the enum in a class/struct to act as a namespace, 1031 # so that the enum strings can be brief w/o worrying about collisions. 1032 def cxx_decl(cls, code): 1033 name = cls.__name__ 1034 code('''\ 1035#ifndef __ENUM__${name}__ 1036#define __ENUM__${name}__ 1037 1038namespace Enums { 1039 enum $name { 1040''') 1041 code.indent(2) 1042 for val in cls.vals: 1043 code('$val = ${{cls.map[val]}},') 1044 code('Num_$name = ${{len(cls.vals)}}') 1045 code.dedent(2) 1046 code('''\ 1047 }; 1048extern const char *${name}Strings[Num_${name}]; 1049} 1050 1051#endif // __ENUM__${name}__ 1052''') 1053 1054 def cxx_def(cls, code): 1055 name = cls.__name__ 1056 code('''\ 1057#include "enums/$name.hh" 1058namespace Enums { 1059 const char *${name}Strings[Num_${name}] = 1060 { 1061''') 1062 code.indent(2) 1063 for val in cls.vals: 1064 code('"$val",') 1065 code.dedent(2) 1066 code(''' 1067 }; 1068} // namespace Enums 1069''') 1070 1071 def swig_decl(cls, code): 1072 name = cls.__name__ 1073 code('''\ 1074%module(package="m5.internal") enum_$name 1075 1076%{ 1077#include "enums/$name.hh" 1078%} 1079 1080%include "enums/$name.hh" 1081''') 1082 1083 1084# Base class for enum types. 1085class Enum(ParamValue): 1086 __metaclass__ = MetaEnum 1087 vals = [] 1088 1089 def __init__(self, value): 1090 if value not in self.map: 1091 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1092 % (value, self.vals) 1093 self.value = value 1094 1095 @classmethod 1096 def cxx_predecls(cls, code): 1097 code('#include "enums/$0.hh"', cls.__name__) 1098 1099 @classmethod 1100 def swig_predecls(cls, code): 1101 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1102 1103 def getValue(self): 1104 return int(self.map[self.value]) 1105 1106 def __str__(self): 1107 return self.value 1108 1109# how big does a rounding error need to be before we warn about it? 1110frequency_tolerance = 0.001 # 0.1% 1111 1112class TickParamValue(NumericParamValue): 1113 cxx_type = 'Tick' 1114 1115 @classmethod 1116 def cxx_predecls(cls, code): 1117 code('#include "base/types.hh"') 1118 1119 @classmethod 1120 def swig_predecls(cls, code): 1121 code('%import "stdint.i"') 1122 code('%import "base/types.hh"') 1123 1124 def getValue(self): 1125 return long(self.value) 1126 1127class Latency(TickParamValue): 1128 def __init__(self, value): 1129 if isinstance(value, (Latency, Clock)): 1130 self.ticks = value.ticks 1131 self.value = value.value 1132 elif isinstance(value, Frequency): 1133 self.ticks = value.ticks 1134 self.value = 1.0 / value.value 1135 elif value.endswith('t'): 1136 self.ticks = True 1137 self.value = int(value[:-1]) 1138 else: 1139 self.ticks = False 1140 self.value = convert.toLatency(value) 1141 1142 def __getattr__(self, attr): 1143 if attr in ('latency', 'period'): 1144 return self 1145 if attr == 'frequency': 1146 return Frequency(self) 1147 raise AttributeError, "Latency object has no attribute '%s'" % attr 1148 1149 def getValue(self): 1150 if self.ticks or self.value == 0: 1151 value = self.value 1152 else: 1153 value = ticks.fromSeconds(self.value) 1154 return long(value) 1155 1156 # convert latency to ticks 1157 def ini_str(self): 1158 return '%d' % self.getValue() 1159 1160class Frequency(TickParamValue): 1161 def __init__(self, value): 1162 if isinstance(value, (Latency, Clock)): 1163 if value.value == 0: 1164 self.value = 0 1165 else: 1166 self.value = 1.0 / value.value 1167 self.ticks = value.ticks 1168 elif isinstance(value, Frequency): 1169 self.value = value.value 1170 self.ticks = value.ticks 1171 else: 1172 self.ticks = False 1173 self.value = convert.toFrequency(value) 1174 1175 def __getattr__(self, attr): 1176 if attr == 'frequency': 1177 return self 1178 if attr in ('latency', 'period'): 1179 return Latency(self) 1180 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1181 1182 # convert latency to ticks 1183 def getValue(self): 1184 if self.ticks or self.value == 0: 1185 value = self.value 1186 else: 1187 value = ticks.fromSeconds(1.0 / self.value) 1188 return long(value) 1189 1190 def ini_str(self): 1191 return '%d' % self.getValue() 1192 1193# A generic frequency and/or Latency value. Value is stored as a latency, 1194# but to avoid ambiguity this object does not support numeric ops (* or /). 1195# An explicit conversion to a Latency or Frequency must be made first. 1196class Clock(ParamValue): 1197 cxx_type = 'Tick' 1198 1199 @classmethod 1200 def cxx_predecls(cls, code): 1201 code('#include "base/types.hh"') 1202 1203 @classmethod 1204 def swig_predecls(cls, code): 1205 code('%import "stdint.i"') 1206 code('%import "base/types.hh"') 1207 1208 def __init__(self, value): 1209 if isinstance(value, (Latency, Clock)): 1210 self.ticks = value.ticks 1211 self.value = value.value 1212 elif isinstance(value, Frequency): 1213 self.ticks = value.ticks 1214 self.value = 1.0 / value.value 1215 elif value.endswith('t'): 1216 self.ticks = True 1217 self.value = int(value[:-1]) 1218 else: 1219 self.ticks = False 1220 self.value = convert.anyToLatency(value) 1221 1222 def __getattr__(self, attr): 1223 if attr == 'frequency': 1224 return Frequency(self) 1225 if attr in ('latency', 'period'): 1226 return Latency(self) 1227 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1228 1229 def getValue(self): 1230 return self.period.getValue() 1231 1232 def ini_str(self): 1233 return self.period.ini_str() 1234 1235class NetworkBandwidth(float,ParamValue): 1236 cxx_type = 'float' 1237 def __new__(cls, value): 1238 # convert to bits per second 1239 val = convert.toNetworkBandwidth(value) 1240 return super(cls, NetworkBandwidth).__new__(cls, val) 1241 1242 def __str__(self): 1243 return str(self.val) 1244 1245 def getValue(self): 1246 # convert to seconds per byte 1247 value = 8.0 / float(self) 1248 # convert to ticks per byte 1249 value = ticks.fromSeconds(value) 1250 return float(value) 1251 1252 def ini_str(self): 1253 return '%f' % self.getValue() 1254 1255class MemoryBandwidth(float,ParamValue): 1256 cxx_type = 'float' 1257 def __new__(cls, value): 1258 # convert to bytes per second 1259 val = convert.toMemoryBandwidth(value) 1260 return super(cls, MemoryBandwidth).__new__(cls, val) 1261 1262 def __str__(self): 1263 return str(self.val) 1264 1265 def getValue(self): 1266 # convert to seconds per byte 1267 value = float(self) 1268 if value: 1269 value = 1.0 / float(self) 1270 # convert to ticks per byte 1271 value = ticks.fromSeconds(value) 1272 return float(value) 1273 1274 def ini_str(self): 1275 return '%f' % self.getValue() 1276 1277# 1278# "Constants"... handy aliases for various values. 1279# 1280 1281# Special class for NULL pointers. Note the special check in 1282# make_param_value() above that lets these be assigned where a 1283# SimObject is required. 1284# only one copy of a particular node 1285class NullSimObject(object): 1286 __metaclass__ = Singleton 1287 1288 def __call__(cls): 1289 return cls 1290 1291 def _instantiate(self, parent = None, path = ''): 1292 pass 1293 1294 def ini_str(self): 1295 return 'Null' 1296 1297 def unproxy(self, base): 1298 return self 1299 1300 def set_path(self, parent, name): 1301 pass 1302 1303 def __str__(self): 1304 return 'Null' 1305 1306 def getValue(self): 1307 return None 1308 1309# The only instance you'll ever need... 1310NULL = NullSimObject() 1311 1312def isNullPointer(value): 1313 return isinstance(value, NullSimObject) 1314 1315# Some memory range specifications use this as a default upper bound. 1316MaxAddr = Addr.max 1317MaxTick = Tick.max 1318AllMemory = AddrRange(0, MaxAddr) 1319 1320 1321##################################################################### 1322# 1323# Port objects 1324# 1325# Ports are used to interconnect objects in the memory system. 1326# 1327##################################################################### 1328 1329# Port reference: encapsulates a reference to a particular port on a 1330# particular SimObject. 1331class PortRef(object): 1332 def __init__(self, simobj, name, role): 1333 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1334 self.simobj = simobj 1335 self.name = name 1336 self.role = role 1337 self.peer = None # not associated with another port yet 1338 self.ccConnected = False # C++ port connection done? 1339 self.index = -1 # always -1 for non-vector ports 1340 1341 def __str__(self): 1342 return '%s.%s' % (self.simobj, self.name) 1343 1344 def __len__(self): 1345 # Return the number of connected ports, i.e. 0 is we have no 1346 # peer and 1 if we do. 1347 return int(self.peer != None) 1348 1349 # for config.ini, print peer's name (not ours) 1350 def ini_str(self): 1351 return str(self.peer) 1352 1353 # for config.json 1354 def get_config_as_dict(self): 1355 return {'role' : self.role, 'peer' : str(self.peer)} 1356 1357 def __getattr__(self, attr): 1358 if attr == 'peerObj': 1359 # shorthand for proxies 1360 return self.peer.simobj 1361 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1362 (self.__class__.__name__, attr) 1363 1364 # Full connection is symmetric (both ways). Called via 1365 # SimObject.__setattr__ as a result of a port assignment, e.g., 1366 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1367 # e.g., "obj1.portA[3] = obj2.portB". 1368 def connect(self, other): 1369 if isinstance(other, VectorPortRef): 1370 # reference to plain VectorPort is implicit append 1371 other = other._get_next() 1372 if self.peer and not proxy.isproxy(self.peer): 1373 fatal("Port %s is already connected to %s, cannot connect %s\n", 1374 self, self.peer, other); 1375 self.peer = other 1376 if proxy.isproxy(other): 1377 other.set_param_desc(PortParamDesc()) 1378 elif isinstance(other, PortRef): 1379 if other.peer is not self: 1380 other.connect(self) 1381 else: 1382 raise TypeError, \ 1383 "assigning non-port reference '%s' to port '%s'" \ 1384 % (other, self) 1385 1386 def clone(self, simobj, memo): 1387 if memo.has_key(self): 1388 return memo[self] 1389 newRef = copy.copy(self) 1390 memo[self] = newRef 1391 newRef.simobj = simobj 1392 assert(isSimObject(newRef.simobj)) 1393 if self.peer and not proxy.isproxy(self.peer): 1394 peerObj = self.peer.simobj(_memo=memo) 1395 newRef.peer = self.peer.clone(peerObj, memo) 1396 assert(not isinstance(newRef.peer, VectorPortRef)) 1397 return newRef 1398 1399 def unproxy(self, simobj): 1400 assert(simobj is self.simobj) 1401 if proxy.isproxy(self.peer): 1402 try: 1403 realPeer = self.peer.unproxy(self.simobj) 1404 except: 1405 print "Error in unproxying port '%s' of %s" % \ 1406 (self.name, self.simobj.path()) 1407 raise 1408 self.connect(realPeer) 1409 1410 # Call C++ to create corresponding port connection between C++ objects 1411 def ccConnect(self): 1412 from m5.internal.pyobject import connectPorts 1413 1414 if self.role == 'SLAVE': 1415 # do nothing and let the master take care of it 1416 return 1417 1418 if self.ccConnected: # already done this 1419 return 1420 peer = self.peer 1421 if not self.peer: # nothing to connect to 1422 return 1423 1424 # check that we connect a master to a slave 1425 if self.role == peer.role: 1426 raise TypeError, \ 1427 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1428 % (peer, self, self.role) 1429 1430 try: 1431 # self is always the master and peer the slave 1432 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1433 peer.simobj.getCCObject(), peer.name, peer.index) 1434 except: 1435 print "Error connecting port %s.%s to %s.%s" % \ 1436 (self.simobj.path(), self.name, 1437 peer.simobj.path(), peer.name) 1438 raise 1439 self.ccConnected = True 1440 peer.ccConnected = True 1441 1442# A reference to an individual element of a VectorPort... much like a 1443# PortRef, but has an index. 1444class VectorPortElementRef(PortRef): 1445 def __init__(self, simobj, name, role, index): 1446 PortRef.__init__(self, simobj, name, role) 1447 self.index = index 1448 1449 def __str__(self): 1450 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1451 1452# A reference to a complete vector-valued port (not just a single element). 1453# Can be indexed to retrieve individual VectorPortElementRef instances. 1454class VectorPortRef(object): 1455 def __init__(self, simobj, name, role): 1456 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1457 self.simobj = simobj 1458 self.name = name 1459 self.role = role 1460 self.elements = [] 1461 1462 def __str__(self): 1463 return '%s.%s[:]' % (self.simobj, self.name) 1464 1465 def __len__(self): 1466 # Return the number of connected peers, corresponding the the 1467 # length of the elements. 1468 return len(self.elements) 1469 1470 # for config.ini, print peer's name (not ours) 1471 def ini_str(self): 1472 return ' '.join([el.ini_str() for el in self.elements]) 1473 1474 # for config.json 1475 def get_config_as_dict(self): 1476 return {'role' : self.role, 1477 'peer' : [el.ini_str() for el in self.elements]} 1478 1479 def __getitem__(self, key): 1480 if not isinstance(key, int): 1481 raise TypeError, "VectorPort index must be integer" 1482 if key >= len(self.elements): 1483 # need to extend list 1484 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1485 for i in range(len(self.elements), key+1)] 1486 self.elements.extend(ext) 1487 return self.elements[key] 1488 1489 def _get_next(self): 1490 return self[len(self.elements)] 1491 1492 def __setitem__(self, key, value): 1493 if not isinstance(key, int): 1494 raise TypeError, "VectorPort index must be integer" 1495 self[key].connect(value) 1496 1497 def connect(self, other): 1498 if isinstance(other, (list, tuple)): 1499 # Assign list of port refs to vector port. 1500 # For now, append them... not sure if that's the right semantics 1501 # or if it should replace the current vector. 1502 for ref in other: 1503 self._get_next().connect(ref) 1504 else: 1505 # scalar assignment to plain VectorPort is implicit append 1506 self._get_next().connect(other) 1507 1508 def clone(self, simobj, memo): 1509 if memo.has_key(self): 1510 return memo[self] 1511 newRef = copy.copy(self) 1512 memo[self] = newRef 1513 newRef.simobj = simobj 1514 assert(isSimObject(newRef.simobj)) 1515 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1516 return newRef 1517 1518 def unproxy(self, simobj): 1519 [el.unproxy(simobj) for el in self.elements] 1520 1521 def ccConnect(self): 1522 [el.ccConnect() for el in self.elements] 1523 1524# Port description object. Like a ParamDesc object, this represents a 1525# logical port in the SimObject class, not a particular port on a 1526# SimObject instance. The latter are represented by PortRef objects. 1527class Port(object): 1528 # Generate a PortRef for this port on the given SimObject with the 1529 # given name 1530 def makeRef(self, simobj): 1531 return PortRef(simobj, self.name, self.role) 1532 1533 # Connect an instance of this port (on the given SimObject with 1534 # the given name) with the port described by the supplied PortRef 1535 def connect(self, simobj, ref): 1536 self.makeRef(simobj).connect(ref) 1537 1538 # No need for any pre-declarations at the moment as we merely rely 1539 # on an unsigned int. 1540 def cxx_predecls(self, code): 1541 pass 1542 1543 # Declare an unsigned int with the same name as the port, that 1544 # will eventually hold the number of connected ports (and thus the 1545 # number of elements for a VectorPort). 1546 def cxx_decl(self, code): 1547 code('unsigned int port_${{self.name}}_connection_count;') 1548 1549class MasterPort(Port): 1550 # MasterPort("description") 1551 def __init__(self, *args): 1552 if len(args) == 1: 1553 self.desc = args[0] 1554 self.role = 'MASTER' 1555 else: 1556 raise TypeError, 'wrong number of arguments' 1557 1558class SlavePort(Port): 1559 # SlavePort("description") 1560 def __init__(self, *args): 1561 if len(args) == 1: 1562 self.desc = args[0] 1563 self.role = 'SLAVE' 1564 else: 1565 raise TypeError, 'wrong number of arguments' 1566 1567# VectorPort description object. Like Port, but represents a vector 1568# of connections (e.g., as on a Bus). 1569class VectorPort(Port): 1570 def __init__(self, *args): 1571 self.isVec = True 1572 1573 def makeRef(self, simobj): 1574 return VectorPortRef(simobj, self.name, self.role) 1575 1576class VectorMasterPort(VectorPort): 1577 # VectorMasterPort("description") 1578 def __init__(self, *args): 1579 if len(args) == 1: 1580 self.desc = args[0] 1581 self.role = 'MASTER' 1582 VectorPort.__init__(self, *args) 1583 else: 1584 raise TypeError, 'wrong number of arguments' 1585 1586class VectorSlavePort(VectorPort): 1587 # VectorSlavePort("description") 1588 def __init__(self, *args): 1589 if len(args) == 1: 1590 self.desc = args[0] 1591 self.role = 'SLAVE' 1592 VectorPort.__init__(self, *args) 1593 else: 1594 raise TypeError, 'wrong number of arguments' 1595 1596# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1597# proxy objects (via set_param_desc()) so that proxy error messages 1598# make sense. 1599class PortParamDesc(object): 1600 __metaclass__ = Singleton 1601 1602 ptype_str = 'Port' 1603 ptype = Port 1604 1605baseEnums = allEnums.copy() 1606baseParams = allParams.copy() 1607 1608def clear(): 1609 global allEnums, allParams 1610 1611 allEnums = baseEnums.copy() 1612 allParams = baseParams.copy() 1613 1614__all__ = ['Param', 'VectorParam', 1615 'Enum', 'Bool', 'String', 'Float', 1616 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1617 'Int32', 'UInt32', 'Int64', 'UInt64', 1618 'Counter', 'Addr', 'Tick', 'Percent', 1619 'TcpPort', 'UdpPort', 'EthernetAddr', 1620 'IpAddress', 'IpNetmask', 'IpWithPort', 1621 'MemorySize', 'MemorySize32', 1622 'Latency', 'Frequency', 'Clock', 1623 'NetworkBandwidth', 'MemoryBandwidth', 1624 'AddrRange', 1625 'MaxAddr', 'MaxTick', 'AllMemory', 1626 'Time', 1627 'NextEthernetAddr', 'NULL', 1628 'MasterPort', 'SlavePort', 1629 'VectorMasterPort', 'VectorSlavePort'] 1630 1631import SimObject 1632