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