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