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