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