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