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