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