275 276 # return 'cpu0 cpu1' etc. for print_ini() 277 def get_name(self): 278 return ' '.join([v._name for v in self]) 279 280 # By iterating through the constituent members of the vector here 281 # we can nicely handle iterating over all a SimObject's children 282 # without having to provide lots of special functions on 283 # SimObjectVector directly. 284 def descendants(self): 285 for v in self: 286 for obj in v.descendants(): 287 yield obj 288 289 def get_config_as_dict(self): 290 a = [] 291 for v in self: 292 a.append(v.get_config_as_dict()) 293 return a 294 295 # If we are replacing an item in the vector, make sure to set the 296 # parent reference of the new SimObject to be the same as the parent 297 # of the SimObject being replaced. Useful to have if we created 298 # a SimObjectVector of temporary objects that will be modified later in 299 # configuration scripts. 300 def __setitem__(self, key, value): 301 val = self[key] 302 if value.has_parent(): 303 warn("SimObject %s already has a parent" % value.get_name() +\ 304 " that is being overwritten by a SimObjectVector") 305 value.set_parent(val.get_parent(), val._name) 306 super(SimObjectVector, self).__setitem__(key, value) 307 308 # Enumerate the params of each member of the SimObject vector. Creates 309 # strings that will allow indexing into the vector by the python code and 310 # allow it to be specified on the command line. 311 def enumerateParams(self, flags_dict = {}, 312 cmd_line_str = "", 313 access_str = ""): 314 if hasattr(self, "_paramEnumed"): 315 print "Cycle detected enumerating params at %s?!" % (cmd_line_str) 316 else: 317 x = 0 318 for vals in self: 319 # Each entry in the SimObjectVector should be an 320 # instance of a SimObject 321 flags_dict = vals.enumerateParams(flags_dict, 322 cmd_line_str + "%d." % x, 323 access_str + "[%d]." % x) 324 x = x + 1 325 326 return flags_dict 327 328class VectorParamDesc(ParamDesc): 329 # Convert assigned value to appropriate type. If the RHS is not a 330 # list or tuple, it generates a single-element list. 331 def convert(self, value): 332 if isinstance(value, (list, tuple)): 333 # list: coerce each element into new list 334 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 335 elif isinstance(value, str): 336 # If input is a csv string 337 tmp_list = [ ParamDesc.convert(self, v) \ 338 for v in value.strip('[').strip(']').split(',') ] 339 else: 340 # singleton: coerce to a single-element list 341 tmp_list = [ ParamDesc.convert(self, value) ] 342 343 if isSimObjectSequence(tmp_list): 344 return SimObjectVector(tmp_list) 345 else: 346 return VectorParamValue(tmp_list) 347 348 # Produce a human readable example string that describes 349 # how to set this vector parameter in the absence of a default 350 # value. 351 def example_str(self): 352 s = super(VectorParamDesc, self).example_str() 353 help_str = "[" + s + "," + s + ", ...]" 354 return help_str 355 356 # Produce a human readable representation of the value of this vector param. 357 def pretty_print(self, value): 358 if isinstance(value, (list, tuple)): 359 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 360 elif isinstance(value, str): 361 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 362 else: 363 tmp_list = [ ParamDesc.pretty_print(self, value) ] 364 365 return tmp_list 366 367 # This is a helper function for the new config system 368 def __call__(self, value): 369 if isinstance(value, (list, tuple)): 370 # list: coerce each element into new list 371 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 372 elif isinstance(value, str): 373 # If input is a csv string 374 tmp_list = [ ParamDesc.convert(self, v) \ 375 for v in value.strip('[').strip(']').split(',') ] 376 else: 377 # singleton: coerce to a single-element list 378 tmp_list = [ ParamDesc.convert(self, value) ] 379 380 return VectorParamValue(tmp_list) 381 382 def cxx_predecls(self, code): 383 code('#include <vector>') 384 self.ptype.cxx_predecls(code) 385 386 def pybind_predecls(self, code): 387 code('#include <vector>') 388 self.ptype.pybind_predecls(code) 389 390 def cxx_decl(self, code): 391 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 392 393class ParamFactory(object): 394 def __init__(self, param_desc_class, ptype_str = None): 395 self.param_desc_class = param_desc_class 396 self.ptype_str = ptype_str 397 398 def __getattr__(self, attr): 399 if self.ptype_str: 400 attr = self.ptype_str + '.' + attr 401 return ParamFactory(self.param_desc_class, attr) 402 403 # E.g., Param.Int(5, "number of widgets") 404 def __call__(self, *args, **kwargs): 405 ptype = None 406 try: 407 ptype = allParams[self.ptype_str] 408 except KeyError: 409 # if name isn't defined yet, assume it's a SimObject, and 410 # try to resolve it later 411 pass 412 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 413 414Param = ParamFactory(ParamDesc) 415VectorParam = ParamFactory(VectorParamDesc) 416 417##################################################################### 418# 419# Parameter Types 420# 421# Though native Python types could be used to specify parameter types 422# (the 'ptype' field of the Param and VectorParam classes), it's more 423# flexible to define our own set of types. This gives us more control 424# over how Python expressions are converted to values (via the 425# __init__() constructor) and how these values are printed out (via 426# the __str__() conversion method). 427# 428##################################################################### 429 430# String-valued parameter. Just mixin the ParamValue class with the 431# built-in str class. 432class String(ParamValue,str): 433 cxx_type = 'std::string' 434 cmd_line_settable = True 435 436 @classmethod 437 def cxx_predecls(self, code): 438 code('#include <string>') 439 440 def __call__(self, value): 441 self = value 442 return value 443 444 @classmethod 445 def cxx_ini_parse(self, code, src, dest, ret): 446 code('%s = %s;' % (dest, src)) 447 code('%s true;' % ret) 448 449 def getValue(self): 450 return self 451 452# superclass for "numeric" parameter values, to emulate math 453# operations in a type-safe way. e.g., a Latency times an int returns 454# a new Latency object. 455class NumericParamValue(ParamValue): 456 def __str__(self): 457 return str(self.value) 458 459 def __float__(self): 460 return float(self.value) 461 462 def __long__(self): 463 return long(self.value) 464 465 def __int__(self): 466 return int(self.value) 467 468 # hook for bounds checking 469 def _check(self): 470 return 471 472 def __mul__(self, other): 473 newobj = self.__class__(self) 474 newobj.value *= other 475 newobj._check() 476 return newobj 477 478 __rmul__ = __mul__ 479 480 def __div__(self, other): 481 newobj = self.__class__(self) 482 newobj.value /= other 483 newobj._check() 484 return newobj 485 486 def __sub__(self, other): 487 newobj = self.__class__(self) 488 newobj.value -= other 489 newobj._check() 490 return newobj 491 492 def config_value(self): 493 return self.value 494 495 @classmethod 496 def cxx_ini_predecls(cls, code): 497 # Assume that base/str.hh will be included anyway 498 # code('#include "base/str.hh"') 499 pass 500 501 # The default for parsing PODs from an .ini entry is to extract from an 502 # istringstream and let overloading choose the right type according to 503 # the dest type. 504 @classmethod 505 def cxx_ini_parse(self, code, src, dest, ret): 506 code('%s to_number(%s, %s);' % (ret, src, dest)) 507 508# Metaclass for bounds-checked integer parameters. See CheckedInt. 509class CheckedIntType(MetaParamValue): 510 def __init__(cls, name, bases, dict): 511 super(CheckedIntType, cls).__init__(name, bases, dict) 512 513 # CheckedInt is an abstract base class, so we actually don't 514 # want to do any processing on it... the rest of this code is 515 # just for classes that derive from CheckedInt. 516 if name == 'CheckedInt': 517 return 518 519 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 520 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 521 panic("CheckedInt subclass %s must define either\n" \ 522 " 'min' and 'max' or 'size' and 'unsigned'\n", 523 name); 524 if cls.unsigned: 525 cls.min = 0 526 cls.max = 2 ** cls.size - 1 527 else: 528 cls.min = -(2 ** (cls.size - 1)) 529 cls.max = (2 ** (cls.size - 1)) - 1 530 531# Abstract superclass for bounds-checked integer parameters. This 532# class is subclassed to generate parameter classes with specific 533# bounds. Initialization of the min and max bounds is done in the 534# metaclass CheckedIntType.__init__. 535class CheckedInt(NumericParamValue): 536 __metaclass__ = CheckedIntType 537 cmd_line_settable = True 538 539 def _check(self): 540 if not self.min <= self.value <= self.max: 541 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 542 (self.min, self.value, self.max) 543 544 def __init__(self, value): 545 if isinstance(value, str): 546 self.value = convert.toInteger(value) 547 elif isinstance(value, (int, long, float, NumericParamValue)): 548 self.value = long(value) 549 else: 550 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 551 % type(value).__name__ 552 self._check() 553 554 def __call__(self, value): 555 self.__init__(value) 556 return value 557 558 @classmethod 559 def cxx_predecls(cls, code): 560 # most derived types require this, so we just do it here once 561 code('#include "base/types.hh"') 562 563 def getValue(self): 564 return long(self.value) 565 566class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 567class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 568 569class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 570class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 571class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 572class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 573class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 574class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 575class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 576class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 577 578class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 579class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 580class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 581class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 582 583class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 584 585class Cycles(CheckedInt): 586 cxx_type = 'Cycles' 587 size = 64 588 unsigned = True 589 590 def getValue(self): 591 from _m5.core import Cycles 592 return Cycles(self.value) 593 594 @classmethod 595 def cxx_ini_predecls(cls, code): 596 # Assume that base/str.hh will be included anyway 597 # code('#include "base/str.hh"') 598 pass 599 600 @classmethod 601 def cxx_ini_parse(cls, code, src, dest, ret): 602 code('uint64_t _temp;') 603 code('bool _ret = to_number(%s, _temp);' % src) 604 code('if (_ret)') 605 code(' %s = Cycles(_temp);' % dest) 606 code('%s _ret;' % ret) 607 608class Float(ParamValue, float): 609 cxx_type = 'double' 610 cmd_line_settable = True 611 612 def __init__(self, value): 613 if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 614 self.value = float(value) 615 else: 616 raise TypeError, "Can't convert object of type %s to Float" \ 617 % type(value).__name__ 618 619 def __call__(self, value): 620 self.__init__(value) 621 return value 622 623 def getValue(self): 624 return float(self.value) 625 626 def config_value(self): 627 return self 628 629 @classmethod 630 def cxx_ini_predecls(cls, code): 631 code('#include <sstream>') 632 633 @classmethod 634 def cxx_ini_parse(self, code, src, dest, ret): 635 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 636 637class MemorySize(CheckedInt): 638 cxx_type = 'uint64_t' 639 ex_str = '512MB' 640 size = 64 641 unsigned = True 642 def __init__(self, value): 643 if isinstance(value, MemorySize): 644 self.value = value.value 645 else: 646 self.value = convert.toMemorySize(value) 647 self._check() 648 649class MemorySize32(CheckedInt): 650 cxx_type = 'uint32_t' 651 ex_str = '512MB' 652 size = 32 653 unsigned = True 654 def __init__(self, value): 655 if isinstance(value, MemorySize): 656 self.value = value.value 657 else: 658 self.value = convert.toMemorySize(value) 659 self._check() 660 661class Addr(CheckedInt): 662 cxx_type = 'Addr' 663 size = 64 664 unsigned = True 665 def __init__(self, value): 666 if isinstance(value, Addr): 667 self.value = value.value 668 else: 669 try: 670 # Often addresses are referred to with sizes. Ex: A device 671 # base address is at "512MB". Use toMemorySize() to convert 672 # these into addresses. If the address is not specified with a 673 # "size", an exception will occur and numeric translation will 674 # proceed below. 675 self.value = convert.toMemorySize(value) 676 except (TypeError, ValueError): 677 # Convert number to string and use long() to do automatic 678 # base conversion (requires base=0 for auto-conversion) 679 self.value = long(str(value), base=0) 680 681 self._check() 682 def __add__(self, other): 683 if isinstance(other, Addr): 684 return self.value + other.value 685 else: 686 return self.value + other 687 def pretty_print(self, value): 688 try: 689 val = convert.toMemorySize(value) 690 except TypeError: 691 val = long(value) 692 return "0x%x" % long(val) 693 694class AddrRange(ParamValue): 695 cxx_type = 'AddrRange' 696 697 def __init__(self, *args, **kwargs): 698 # Disable interleaving and hashing by default 699 self.intlvHighBit = 0 700 self.xorHighBit = 0 701 self.intlvBits = 0 702 self.intlvMatch = 0 703 704 def handle_kwargs(self, kwargs): 705 # An address range needs to have an upper limit, specified 706 # either explicitly with an end, or as an offset using the 707 # size keyword. 708 if 'end' in kwargs: 709 self.end = Addr(kwargs.pop('end')) 710 elif 'size' in kwargs: 711 self.end = self.start + Addr(kwargs.pop('size')) - 1 712 else: 713 raise TypeError, "Either end or size must be specified" 714 715 # Now on to the optional bit 716 if 'intlvHighBit' in kwargs: 717 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 718 if 'xorHighBit' in kwargs: 719 self.xorHighBit = int(kwargs.pop('xorHighBit')) 720 if 'intlvBits' in kwargs: 721 self.intlvBits = int(kwargs.pop('intlvBits')) 722 if 'intlvMatch' in kwargs: 723 self.intlvMatch = int(kwargs.pop('intlvMatch')) 724 725 if len(args) == 0: 726 self.start = Addr(kwargs.pop('start')) 727 handle_kwargs(self, kwargs) 728 729 elif len(args) == 1: 730 if kwargs: 731 self.start = Addr(args[0]) 732 handle_kwargs(self, kwargs) 733 elif isinstance(args[0], (list, tuple)): 734 self.start = Addr(args[0][0]) 735 self.end = Addr(args[0][1]) 736 else: 737 self.start = Addr(0) 738 self.end = Addr(args[0]) - 1 739 740 elif len(args) == 2: 741 self.start = Addr(args[0]) 742 self.end = Addr(args[1]) 743 else: 744 raise TypeError, "Too many arguments specified" 745 746 if kwargs: 747 raise TypeError, "Too many keywords: %s" % kwargs.keys() 748 749 def __str__(self): 750 return '%s:%s:%s:%s:%s:%s' \ 751 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 752 self.intlvBits, self.intlvMatch) 753 754 def size(self): 755 # Divide the size by the size of the interleaving slice 756 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 757 758 @classmethod 759 def cxx_predecls(cls, code): 760 Addr.cxx_predecls(code) 761 code('#include "base/addr_range.hh"') 762 763 @classmethod 764 def pybind_predecls(cls, code): 765 Addr.pybind_predecls(code) 766 code('#include "base/addr_range.hh"') 767 768 @classmethod 769 def cxx_ini_predecls(cls, code): 770 code('#include <sstream>') 771 772 @classmethod 773 def cxx_ini_parse(cls, code, src, dest, ret): 774 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 775 code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 776 code('char _sep;') 777 code('std::istringstream _stream(${src});') 778 code('_stream >> _start;') 779 code('_stream.get(_sep);') 780 code('_stream >> _end;') 781 code('if (!_stream.fail() && !_stream.eof()) {') 782 code(' _stream.get(_sep);') 783 code(' _stream >> _intlvHighBit;') 784 code(' _stream.get(_sep);') 785 code(' _stream >> _xorHighBit;') 786 code(' _stream.get(_sep);') 787 code(' _stream >> _intlvBits;') 788 code(' _stream.get(_sep);') 789 code(' _stream >> _intlvMatch;') 790 code('}') 791 code('bool _ret = !_stream.fail() &&' 792 '_stream.eof() && _sep == \':\';') 793 code('if (_ret)') 794 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 795 _xorHighBit, _intlvBits, _intlvMatch);') 796 code('${ret} _ret;') 797 798 def getValue(self): 799 # Go from the Python class to the wrapped C++ class 800 from _m5.range import AddrRange 801 802 return AddrRange(long(self.start), long(self.end), 803 int(self.intlvHighBit), int(self.xorHighBit), 804 int(self.intlvBits), int(self.intlvMatch)) 805 806# Boolean parameter type. Python doesn't let you subclass bool, since 807# it doesn't want to let you create multiple instances of True and 808# False. Thus this is a little more complicated than String. 809class Bool(ParamValue): 810 cxx_type = 'bool' 811 cmd_line_settable = True 812 813 def __init__(self, value): 814 try: 815 self.value = convert.toBool(value) 816 except TypeError: 817 self.value = bool(value) 818 819 def __call__(self, value): 820 self.__init__(value) 821 return value 822 823 def getValue(self): 824 return bool(self.value) 825 826 def __str__(self): 827 return str(self.value) 828 829 # implement truth value testing for Bool parameters so that these params 830 # evaluate correctly during the python configuration phase 831 def __nonzero__(self): 832 return bool(self.value) 833 834 def ini_str(self): 835 if self.value: 836 return 'true' 837 return 'false' 838 839 def config_value(self): 840 return self.value 841 842 @classmethod 843 def cxx_ini_predecls(cls, code): 844 # Assume that base/str.hh will be included anyway 845 # code('#include "base/str.hh"') 846 pass 847 848 @classmethod 849 def cxx_ini_parse(cls, code, src, dest, ret): 850 code('%s to_bool(%s, %s);' % (ret, src, dest)) 851 852def IncEthernetAddr(addr, val = 1): 853 bytes = map(lambda x: int(x, 16), addr.split(':')) 854 bytes[5] += val 855 for i in (5, 4, 3, 2, 1): 856 val,rem = divmod(bytes[i], 256) 857 bytes[i] = rem 858 if val == 0: 859 break 860 bytes[i - 1] += val 861 assert(bytes[0] <= 255) 862 return ':'.join(map(lambda x: '%02x' % x, bytes)) 863 864_NextEthernetAddr = "00:90:00:00:00:01" 865def NextEthernetAddr(): 866 global _NextEthernetAddr 867 868 value = _NextEthernetAddr 869 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 870 return value 871 872class EthernetAddr(ParamValue): 873 cxx_type = 'Net::EthAddr' 874 ex_str = "00:90:00:00:00:01" 875 cmd_line_settable = True 876 877 @classmethod 878 def cxx_predecls(cls, code): 879 code('#include "base/inet.hh"') 880 881 def __init__(self, value): 882 if value == NextEthernetAddr: 883 self.value = value 884 return 885 886 if not isinstance(value, str): 887 raise TypeError, "expected an ethernet address and didn't get one" 888 889 bytes = value.split(':') 890 if len(bytes) != 6: 891 raise TypeError, 'invalid ethernet address %s' % value 892 893 for byte in bytes: 894 if not 0 <= int(byte, base=16) <= 0xff: 895 raise TypeError, 'invalid ethernet address %s' % value 896 897 self.value = value 898 899 def __call__(self, value): 900 self.__init__(value) 901 return value 902 903 def unproxy(self, base): 904 if self.value == NextEthernetAddr: 905 return EthernetAddr(self.value()) 906 return self 907 908 def getValue(self): 909 from _m5.net import EthAddr 910 return EthAddr(self.value) 911 912 def __str__(self): 913 return self.value 914 915 def ini_str(self): 916 return self.value 917 918 @classmethod 919 def cxx_ini_parse(self, code, src, dest, ret): 920 code('%s = Net::EthAddr(%s);' % (dest, src)) 921 code('%s true;' % ret) 922 923# When initializing an IpAddress, pass in an existing IpAddress, a string of 924# the form "a.b.c.d", or an integer representing an IP. 925class IpAddress(ParamValue): 926 cxx_type = 'Net::IpAddress' 927 ex_str = "127.0.0.1" 928 cmd_line_settable = True 929 930 @classmethod 931 def cxx_predecls(cls, code): 932 code('#include "base/inet.hh"') 933 934 def __init__(self, value): 935 if isinstance(value, IpAddress): 936 self.ip = value.ip 937 else: 938 try: 939 self.ip = convert.toIpAddress(value) 940 except TypeError: 941 self.ip = long(value) 942 self.verifyIp() 943 944 def __call__(self, value): 945 self.__init__(value) 946 return value 947 948 def __str__(self): 949 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 950 return '%d.%d.%d.%d' % tuple(tup) 951 952 def __eq__(self, other): 953 if isinstance(other, IpAddress): 954 return self.ip == other.ip 955 elif isinstance(other, str): 956 try: 957 return self.ip == convert.toIpAddress(other) 958 except: 959 return False 960 else: 961 return self.ip == other 962 963 def __ne__(self, other): 964 return not (self == other) 965 966 def verifyIp(self): 967 if self.ip < 0 or self.ip >= (1 << 32): 968 raise TypeError, "invalid ip address %#08x" % self.ip 969 970 def getValue(self): 971 from _m5.net import IpAddress 972 return IpAddress(self.ip) 973 974# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 975# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 976# positional or keyword arguments. 977class IpNetmask(IpAddress): 978 cxx_type = 'Net::IpNetmask' 979 ex_str = "127.0.0.0/24" 980 cmd_line_settable = True 981 982 @classmethod 983 def cxx_predecls(cls, code): 984 code('#include "base/inet.hh"') 985 986 def __init__(self, *args, **kwargs): 987 def handle_kwarg(self, kwargs, key, elseVal = None): 988 if key in kwargs: 989 setattr(self, key, kwargs.pop(key)) 990 elif elseVal: 991 setattr(self, key, elseVal) 992 else: 993 raise TypeError, "No value set for %s" % key 994 995 if len(args) == 0: 996 handle_kwarg(self, kwargs, 'ip') 997 handle_kwarg(self, kwargs, 'netmask') 998 999 elif len(args) == 1: 1000 if kwargs: 1001 if not 'ip' in kwargs and not 'netmask' in kwargs: 1002 raise TypeError, "Invalid arguments" 1003 handle_kwarg(self, kwargs, 'ip', args[0]) 1004 handle_kwarg(self, kwargs, 'netmask', args[0]) 1005 elif isinstance(args[0], IpNetmask): 1006 self.ip = args[0].ip 1007 self.netmask = args[0].netmask 1008 else: 1009 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1010 1011 elif len(args) == 2: 1012 self.ip = args[0] 1013 self.netmask = args[1] 1014 else: 1015 raise TypeError, "Too many arguments specified" 1016 1017 if kwargs: 1018 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1019 1020 self.verify() 1021 1022 def __call__(self, value): 1023 self.__init__(value) 1024 return value 1025 1026 def __str__(self): 1027 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1028 1029 def __eq__(self, other): 1030 if isinstance(other, IpNetmask): 1031 return self.ip == other.ip and self.netmask == other.netmask 1032 elif isinstance(other, str): 1033 try: 1034 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1035 except: 1036 return False 1037 else: 1038 return False 1039 1040 def verify(self): 1041 self.verifyIp() 1042 if self.netmask < 0 or self.netmask > 32: 1043 raise TypeError, "invalid netmask %d" % netmask 1044 1045 def getValue(self): 1046 from _m5.net import IpNetmask 1047 return IpNetmask(self.ip, self.netmask) 1048 1049# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1050# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1051class IpWithPort(IpAddress): 1052 cxx_type = 'Net::IpWithPort' 1053 ex_str = "127.0.0.1:80" 1054 cmd_line_settable = True 1055 1056 @classmethod 1057 def cxx_predecls(cls, code): 1058 code('#include "base/inet.hh"') 1059 1060 def __init__(self, *args, **kwargs): 1061 def handle_kwarg(self, kwargs, key, elseVal = None): 1062 if key in kwargs: 1063 setattr(self, key, kwargs.pop(key)) 1064 elif elseVal: 1065 setattr(self, key, elseVal) 1066 else: 1067 raise TypeError, "No value set for %s" % key 1068 1069 if len(args) == 0: 1070 handle_kwarg(self, kwargs, 'ip') 1071 handle_kwarg(self, kwargs, 'port') 1072 1073 elif len(args) == 1: 1074 if kwargs: 1075 if not 'ip' in kwargs and not 'port' in kwargs: 1076 raise TypeError, "Invalid arguments" 1077 handle_kwarg(self, kwargs, 'ip', args[0]) 1078 handle_kwarg(self, kwargs, 'port', args[0]) 1079 elif isinstance(args[0], IpWithPort): 1080 self.ip = args[0].ip 1081 self.port = args[0].port 1082 else: 1083 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1084 1085 elif len(args) == 2: 1086 self.ip = args[0] 1087 self.port = args[1] 1088 else: 1089 raise TypeError, "Too many arguments specified" 1090 1091 if kwargs: 1092 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1093 1094 self.verify() 1095 1096 def __call__(self, value): 1097 self.__init__(value) 1098 return value 1099 1100 def __str__(self): 1101 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1102 1103 def __eq__(self, other): 1104 if isinstance(other, IpWithPort): 1105 return self.ip == other.ip and self.port == other.port 1106 elif isinstance(other, str): 1107 try: 1108 return (self.ip, self.port) == convert.toIpWithPort(other) 1109 except: 1110 return False 1111 else: 1112 return False 1113 1114 def verify(self): 1115 self.verifyIp() 1116 if self.port < 0 or self.port > 0xffff: 1117 raise TypeError, "invalid port %d" % self.port 1118 1119 def getValue(self): 1120 from _m5.net import IpWithPort 1121 return IpWithPort(self.ip, self.port) 1122 1123time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1124 "%a %b %d %H:%M:%S %Y", 1125 "%Y/%m/%d %H:%M:%S", 1126 "%Y/%m/%d %H:%M", 1127 "%Y/%m/%d", 1128 "%m/%d/%Y %H:%M:%S", 1129 "%m/%d/%Y %H:%M", 1130 "%m/%d/%Y", 1131 "%m/%d/%y %H:%M:%S", 1132 "%m/%d/%y %H:%M", 1133 "%m/%d/%y"] 1134 1135 1136def parse_time(value): 1137 from time import gmtime, strptime, struct_time, time 1138 from datetime import datetime, date 1139 1140 if isinstance(value, struct_time): 1141 return value 1142 1143 if isinstance(value, (int, long)): 1144 return gmtime(value) 1145 1146 if isinstance(value, (datetime, date)): 1147 return value.timetuple() 1148 1149 if isinstance(value, str): 1150 if value in ('Now', 'Today'): 1151 return time.gmtime(time.time()) 1152 1153 for format in time_formats: 1154 try: 1155 return strptime(value, format) 1156 except ValueError: 1157 pass 1158 1159 raise ValueError, "Could not parse '%s' as a time" % value 1160 1161class Time(ParamValue): 1162 cxx_type = 'tm' 1163 1164 @classmethod 1165 def cxx_predecls(cls, code): 1166 code('#include <time.h>') 1167 1168 def __init__(self, value): 1169 self.value = parse_time(value) 1170 1171 def __call__(self, value): 1172 self.__init__(value) 1173 return value 1174 1175 def getValue(self): 1176 from _m5.core import tm 1177 import calendar 1178 1179 return tm.gmtime(calendar.timegm(self.value)) 1180 1181 def __str__(self): 1182 return time.asctime(self.value) 1183 1184 def ini_str(self): 1185 return str(self) 1186 1187 def get_config_as_dict(self): 1188 assert false 1189 return str(self) 1190 1191 @classmethod 1192 def cxx_ini_predecls(cls, code): 1193 code('#include <time.h>') 1194 1195 @classmethod 1196 def cxx_ini_parse(cls, code, src, dest, ret): 1197 code('char *_parse_ret = strptime((${src}).c_str(),') 1198 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1199 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1200 1201# Enumerated types are a little more complex. The user specifies the 1202# type as Enum(foo) where foo is either a list or dictionary of 1203# alternatives (typically strings, but not necessarily so). (In the 1204# long run, the integer value of the parameter will be the list index 1205# or the corresponding dictionary value. For now, since we only check 1206# that the alternative is valid and then spit it into a .ini file, 1207# there's not much point in using the dictionary.) 1208 1209# What Enum() must do is generate a new type encapsulating the 1210# provided list/dictionary so that specific values of the parameter 1211# can be instances of that type. We define two hidden internal 1212# classes (_ListEnum and _DictEnum) to serve as base classes, then 1213# derive the new type from the appropriate base class on the fly. 1214 1215allEnums = {} 1216# Metaclass for Enum types 1217class MetaEnum(MetaParamValue): 1218 def __new__(mcls, name, bases, dict): 1219 assert name not in allEnums 1220 1221 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1222 allEnums[name] = cls 1223 return cls 1224 1225 def __init__(cls, name, bases, init_dict): 1226 if init_dict.has_key('map'): 1227 if not isinstance(cls.map, dict): 1228 raise TypeError, "Enum-derived class attribute 'map' " \ 1229 "must be of type dict" 1230 # build list of value strings from map 1231 cls.vals = cls.map.keys() 1232 cls.vals.sort() 1233 elif init_dict.has_key('vals'): 1234 if not isinstance(cls.vals, list): 1235 raise TypeError, "Enum-derived class attribute 'vals' " \ 1236 "must be of type list" 1237 # build string->value map from vals sequence 1238 cls.map = {} 1239 for idx,val in enumerate(cls.vals): 1240 cls.map[val] = idx 1241 else: 1242 raise TypeError, "Enum-derived class must define "\ 1243 "attribute 'map' or 'vals'" 1244 1245 cls.cxx_type = 'Enums::%s' % name 1246 1247 super(MetaEnum, cls).__init__(name, bases, init_dict) 1248 1249 # Generate C++ class declaration for this enum type. 1250 # Note that we wrap the enum in a class/struct to act as a namespace, 1251 # so that the enum strings can be brief w/o worrying about collisions. 1252 def cxx_decl(cls, code): 1253 wrapper_name = cls.wrapper_name 1254 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1255 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1256 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1257 1258 code('''\ 1259#ifndef $idem_macro 1260#define $idem_macro 1261 1262$wrapper $wrapper_name { 1263 enum $name { 1264''') 1265 code.indent(2) 1266 for val in cls.vals: 1267 code('$val = ${{cls.map[val]}},') 1268 code('Num_$name = ${{len(cls.vals)}}') 1269 code.dedent(2) 1270 code(' };') 1271 1272 if cls.wrapper_is_struct: 1273 code(' static const char *${name}Strings[Num_${name}];') 1274 code('};') 1275 else: 1276 code('extern const char *${name}Strings[Num_${name}];') 1277 code('}') 1278 1279 code() 1280 code('#endif // $idem_macro') 1281 1282 def cxx_def(cls, code): 1283 wrapper_name = cls.wrapper_name 1284 file_name = cls.__name__ 1285 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1286 1287 code('#include "enums/$file_name.hh"') 1288 if cls.wrapper_is_struct: 1289 code('const char *${wrapper_name}::${name}Strings' 1290 '[Num_${name}] =') 1291 else: 1292 code('namespace Enums {') 1293 code.indent(1) 1294 code(' const char *${name}Strings[Num_${name}] =') 1295 1296 code('{') 1297 code.indent(1) 1298 for val in cls.vals: 1299 code('"$val",') 1300 code.dedent(1) 1301 code('};') 1302 1303 if not cls.wrapper_is_struct: 1304 code('} // namespace $wrapper_name') 1305 code.dedent(1) 1306 1307 def pybind_def(cls, code): 1308 name = cls.__name__ 1309 wrapper_name = cls.wrapper_name 1310 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1311 1312 code('''#include "pybind11/pybind11.h" 1313#include "pybind11/stl.h" 1314 1315#include <sim/init.hh> 1316 1317namespace py = pybind11; 1318 1319static void 1320module_init(py::module &m_internal) 1321{ 1322 py::module m = m_internal.def_submodule("enum_${name}"); 1323 1324 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}") 1325''') 1326 1327 code.indent() 1328 code.indent() 1329 for val in cls.vals: 1330 code('.value("${val}", ${wrapper_name}::${val})') 1331 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1332 code('.export_values()') 1333 code(';') 1334 code.dedent() 1335 1336 code('}') 1337 code.dedent() 1338 code() 1339 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1340 1341 1342# Base class for enum types. 1343class Enum(ParamValue): 1344 __metaclass__ = MetaEnum 1345 vals = [] 1346 cmd_line_settable = True 1347 1348 # The name of the wrapping namespace or struct 1349 wrapper_name = 'Enums' 1350 1351 # If true, the enum is wrapped in a struct rather than a namespace 1352 wrapper_is_struct = False 1353 1354 # If not None, use this as the enum name rather than this class name 1355 enum_name = None 1356 1357 def __init__(self, value): 1358 if value not in self.map: 1359 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1360 % (value, self.vals) 1361 self.value = value 1362 1363 def __call__(self, value): 1364 self.__init__(value) 1365 return value 1366 1367 @classmethod 1368 def cxx_predecls(cls, code): 1369 code('#include "enums/$0.hh"', cls.__name__) 1370 1371 @classmethod 1372 def cxx_ini_parse(cls, code, src, dest, ret): 1373 code('if (false) {') 1374 for elem_name in cls.map.iterkeys(): 1375 code('} else if (%s == "%s") {' % (src, elem_name)) 1376 code.indent() 1377 code('%s = Enums::%s;' % (dest, elem_name)) 1378 code('%s true;' % ret) 1379 code.dedent() 1380 code('} else {') 1381 code(' %s false;' % ret) 1382 code('}') 1383 1384 def getValue(self): 1385 import m5.internal.params 1386 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1387 return e(self.map[self.value]) 1388 1389 def __str__(self): 1390 return self.value 1391 1392# how big does a rounding error need to be before we warn about it? 1393frequency_tolerance = 0.001 # 0.1% 1394 1395class TickParamValue(NumericParamValue): 1396 cxx_type = 'Tick' 1397 ex_str = "1MHz" 1398 cmd_line_settable = True 1399 1400 @classmethod 1401 def cxx_predecls(cls, code): 1402 code('#include "base/types.hh"') 1403 1404 def __call__(self, value): 1405 self.__init__(value) 1406 return value 1407 1408 def getValue(self): 1409 return long(self.value) 1410 1411 @classmethod 1412 def cxx_ini_predecls(cls, code): 1413 code('#include <sstream>') 1414 1415 # Ticks are expressed in seconds in JSON files and in plain 1416 # Ticks in .ini files. Switch based on a config flag 1417 @classmethod 1418 def cxx_ini_parse(self, code, src, dest, ret): 1419 code('${ret} to_number(${src}, ${dest});') 1420 1421class Latency(TickParamValue): 1422 ex_str = "100ns" 1423 1424 def __init__(self, value): 1425 if isinstance(value, (Latency, Clock)): 1426 self.ticks = value.ticks 1427 self.value = value.value 1428 elif isinstance(value, Frequency): 1429 self.ticks = value.ticks 1430 self.value = 1.0 / value.value 1431 elif value.endswith('t'): 1432 self.ticks = True 1433 self.value = int(value[:-1]) 1434 else: 1435 self.ticks = False 1436 self.value = convert.toLatency(value) 1437 1438 def __call__(self, value): 1439 self.__init__(value) 1440 return value 1441 1442 def __getattr__(self, attr): 1443 if attr in ('latency', 'period'): 1444 return self 1445 if attr == 'frequency': 1446 return Frequency(self) 1447 raise AttributeError, "Latency object has no attribute '%s'" % attr 1448 1449 def getValue(self): 1450 if self.ticks or self.value == 0: 1451 value = self.value 1452 else: 1453 value = ticks.fromSeconds(self.value) 1454 return long(value) 1455 1456 def config_value(self): 1457 return self.getValue() 1458 1459 # convert latency to ticks 1460 def ini_str(self): 1461 return '%d' % self.getValue() 1462 1463class Frequency(TickParamValue): 1464 ex_str = "1GHz" 1465 1466 def __init__(self, value): 1467 if isinstance(value, (Latency, Clock)): 1468 if value.value == 0: 1469 self.value = 0 1470 else: 1471 self.value = 1.0 / value.value 1472 self.ticks = value.ticks 1473 elif isinstance(value, Frequency): 1474 self.value = value.value 1475 self.ticks = value.ticks 1476 else: 1477 self.ticks = False 1478 self.value = convert.toFrequency(value) 1479 1480 def __call__(self, value): 1481 self.__init__(value) 1482 return value 1483 1484 def __getattr__(self, attr): 1485 if attr == 'frequency': 1486 return self 1487 if attr in ('latency', 'period'): 1488 return Latency(self) 1489 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1490 1491 # convert latency to ticks 1492 def getValue(self): 1493 if self.ticks or self.value == 0: 1494 value = self.value 1495 else: 1496 value = ticks.fromSeconds(1.0 / self.value) 1497 return long(value) 1498 1499 def config_value(self): 1500 return self.getValue() 1501 1502 def ini_str(self): 1503 return '%d' % self.getValue() 1504 1505# A generic Frequency and/or Latency value. Value is stored as a 1506# latency, just like Latency and Frequency. 1507class Clock(TickParamValue): 1508 def __init__(self, value): 1509 if isinstance(value, (Latency, Clock)): 1510 self.ticks = value.ticks 1511 self.value = value.value 1512 elif isinstance(value, Frequency): 1513 self.ticks = value.ticks 1514 self.value = 1.0 / value.value 1515 elif value.endswith('t'): 1516 self.ticks = True 1517 self.value = int(value[:-1]) 1518 else: 1519 self.ticks = False 1520 self.value = convert.anyToLatency(value) 1521 1522 def __call__(self, value): 1523 self.__init__(value) 1524 return value 1525 1526 def __str__(self): 1527 return "%s" % Latency(self) 1528 1529 def __getattr__(self, attr): 1530 if attr == 'frequency': 1531 return Frequency(self) 1532 if attr in ('latency', 'period'): 1533 return Latency(self) 1534 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1535 1536 def getValue(self): 1537 return self.period.getValue() 1538 1539 def config_value(self): 1540 return self.period.config_value() 1541 1542 def ini_str(self): 1543 return self.period.ini_str() 1544 1545class Voltage(float,ParamValue): 1546 cxx_type = 'double' 1547 ex_str = "1V" 1548 cmd_line_settable = True 1549 1550 def __new__(cls, value): 1551 # convert to voltage 1552 val = convert.toVoltage(value) 1553 return super(cls, Voltage).__new__(cls, val) 1554 1555 def __call__(self, value): 1556 val = convert.toVoltage(value) 1557 self.__init__(val) 1558 return value 1559 1560 def __str__(self): 1561 return str(self.getValue()) 1562 1563 def getValue(self): 1564 value = float(self) 1565 return value 1566 1567 def ini_str(self): 1568 return '%f' % self.getValue() 1569 1570 @classmethod 1571 def cxx_ini_predecls(cls, code): 1572 code('#include <sstream>') 1573 1574 @classmethod 1575 def cxx_ini_parse(self, code, src, dest, ret): 1576 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1577 1578class Current(float, ParamValue): 1579 cxx_type = 'double' 1580 ex_str = "1mA" 1581 cmd_line_settable = False 1582 1583 def __new__(cls, value): 1584 # convert to current 1585 val = convert.toCurrent(value) 1586 return super(cls, Current).__new__(cls, val) 1587 1588 def __call__(self, value): 1589 val = convert.toCurrent(value) 1590 self.__init__(val) 1591 return value 1592 1593 def __str__(self): 1594 return str(self.getValue()) 1595 1596 def getValue(self): 1597 value = float(self) 1598 return value 1599 1600 def ini_str(self): 1601 return '%f' % self.getValue() 1602 1603 @classmethod 1604 def cxx_ini_predecls(cls, code): 1605 code('#include <sstream>') 1606 1607 @classmethod 1608 def cxx_ini_parse(self, code, src, dest, ret): 1609 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1610 1611class NetworkBandwidth(float,ParamValue): 1612 cxx_type = 'float' 1613 ex_str = "1Gbps" 1614 cmd_line_settable = True 1615 1616 def __new__(cls, value): 1617 # convert to bits per second 1618 val = convert.toNetworkBandwidth(value) 1619 return super(cls, NetworkBandwidth).__new__(cls, val) 1620 1621 def __str__(self): 1622 return str(self.val) 1623 1624 def __call__(self, value): 1625 val = convert.toNetworkBandwidth(value) 1626 self.__init__(val) 1627 return value 1628 1629 def getValue(self): 1630 # convert to seconds per byte 1631 value = 8.0 / float(self) 1632 # convert to ticks per byte 1633 value = ticks.fromSeconds(value) 1634 return float(value) 1635 1636 def ini_str(self): 1637 return '%f' % self.getValue() 1638 1639 def config_value(self): 1640 return '%f' % self.getValue() 1641 1642 @classmethod 1643 def cxx_ini_predecls(cls, code): 1644 code('#include <sstream>') 1645 1646 @classmethod 1647 def cxx_ini_parse(self, code, src, dest, ret): 1648 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1649 1650class MemoryBandwidth(float,ParamValue): 1651 cxx_type = 'float' 1652 ex_str = "1GB/s" 1653 cmd_line_settable = True 1654 1655 def __new__(cls, value): 1656 # convert to bytes per second 1657 val = convert.toMemoryBandwidth(value) 1658 return super(cls, MemoryBandwidth).__new__(cls, val) 1659 1660 def __call__(self, value): 1661 val = convert.toMemoryBandwidth(value) 1662 self.__init__(val) 1663 return value 1664 1665 def getValue(self): 1666 # convert to seconds per byte 1667 value = float(self) 1668 if value: 1669 value = 1.0 / float(self) 1670 # convert to ticks per byte 1671 value = ticks.fromSeconds(value) 1672 return float(value) 1673 1674 def ini_str(self): 1675 return '%f' % self.getValue() 1676 1677 def config_value(self): 1678 return '%f' % self.getValue() 1679 1680 @classmethod 1681 def cxx_ini_predecls(cls, code): 1682 code('#include <sstream>') 1683 1684 @classmethod 1685 def cxx_ini_parse(self, code, src, dest, ret): 1686 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1687 1688# 1689# "Constants"... handy aliases for various values. 1690# 1691 1692# Special class for NULL pointers. Note the special check in 1693# make_param_value() above that lets these be assigned where a 1694# SimObject is required. 1695# only one copy of a particular node 1696class NullSimObject(object): 1697 __metaclass__ = Singleton 1698 1699 def __call__(cls): 1700 return cls 1701 1702 def _instantiate(self, parent = None, path = ''): 1703 pass 1704 1705 def ini_str(self): 1706 return 'Null' 1707 1708 def unproxy(self, base): 1709 return self 1710 1711 def set_path(self, parent, name): 1712 pass 1713 1714 def set_parent(self, parent, name): 1715 pass 1716 1717 def __str__(self): 1718 return 'Null' 1719 1720 def config_value(self): 1721 return None 1722 1723 def getValue(self): 1724 return None 1725 1726# The only instance you'll ever need... 1727NULL = NullSimObject() 1728 1729def isNullPointer(value): 1730 return isinstance(value, NullSimObject) 1731 1732# Some memory range specifications use this as a default upper bound. 1733MaxAddr = Addr.max 1734MaxTick = Tick.max 1735AllMemory = AddrRange(0, MaxAddr) 1736 1737 1738##################################################################### 1739# 1740# Port objects 1741# 1742# Ports are used to interconnect objects in the memory system. 1743# 1744##################################################################### 1745 1746# Port reference: encapsulates a reference to a particular port on a 1747# particular SimObject. 1748class PortRef(object): 1749 def __init__(self, simobj, name, role): 1750 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1751 self.simobj = simobj 1752 self.name = name 1753 self.role = role 1754 self.peer = None # not associated with another port yet 1755 self.ccConnected = False # C++ port connection done? 1756 self.index = -1 # always -1 for non-vector ports 1757 1758 def __str__(self): 1759 return '%s.%s' % (self.simobj, self.name) 1760 1761 def __len__(self): 1762 # Return the number of connected ports, i.e. 0 is we have no 1763 # peer and 1 if we do. 1764 return int(self.peer != None) 1765 1766 # for config.ini, print peer's name (not ours) 1767 def ini_str(self): 1768 return str(self.peer) 1769 1770 # for config.json 1771 def get_config_as_dict(self): 1772 return {'role' : self.role, 'peer' : str(self.peer)} 1773 1774 def __getattr__(self, attr): 1775 if attr == 'peerObj': 1776 # shorthand for proxies 1777 return self.peer.simobj 1778 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1779 (self.__class__.__name__, attr) 1780 1781 # Full connection is symmetric (both ways). Called via 1782 # SimObject.__setattr__ as a result of a port assignment, e.g., 1783 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1784 # e.g., "obj1.portA[3] = obj2.portB". 1785 def connect(self, other): 1786 if isinstance(other, VectorPortRef): 1787 # reference to plain VectorPort is implicit append 1788 other = other._get_next() 1789 if self.peer and not proxy.isproxy(self.peer): 1790 fatal("Port %s is already connected to %s, cannot connect %s\n", 1791 self, self.peer, other); 1792 self.peer = other 1793 if proxy.isproxy(other): 1794 other.set_param_desc(PortParamDesc()) 1795 elif isinstance(other, PortRef): 1796 if other.peer is not self: 1797 other.connect(self) 1798 else: 1799 raise TypeError, \ 1800 "assigning non-port reference '%s' to port '%s'" \ 1801 % (other, self) 1802 1803 # Allow a master/slave port pair to be spliced between 1804 # a port and its connected peer. Useful operation for connecting 1805 # instrumentation structures into a system when it is necessary 1806 # to connect the instrumentation after the full system has been 1807 # constructed. 1808 def splice(self, new_master_peer, new_slave_peer): 1809 if self.peer and not proxy.isproxy(self.peer): 1810 if isinstance(new_master_peer, PortRef) and \ 1811 isinstance(new_slave_peer, PortRef): 1812 old_peer = self.peer 1813 if self.role == 'SLAVE': 1814 self.peer = new_master_peer 1815 old_peer.peer = new_slave_peer 1816 new_master_peer.connect(self) 1817 new_slave_peer.connect(old_peer) 1818 elif self.role == 'MASTER': 1819 self.peer = new_slave_peer 1820 old_peer.peer = new_master_peer 1821 new_slave_peer.connect(self) 1822 new_master_peer.connect(old_peer) 1823 else: 1824 panic("Port %s has unknown role, "+\ 1825 "cannot splice in new peers\n", self) 1826 else: 1827 raise TypeError, \ 1828 "Splicing non-port references '%s','%s' to port '%s'"\ 1829 % (new_peer, peers_new_peer, self) 1830 else: 1831 fatal("Port %s not connected, cannot splice in new peers\n", self) 1832 1833 def clone(self, simobj, memo): 1834 if memo.has_key(self): 1835 return memo[self] 1836 newRef = copy.copy(self) 1837 memo[self] = newRef 1838 newRef.simobj = simobj 1839 assert(isSimObject(newRef.simobj)) 1840 if self.peer and not proxy.isproxy(self.peer): 1841 peerObj = self.peer.simobj(_memo=memo) 1842 newRef.peer = self.peer.clone(peerObj, memo) 1843 assert(not isinstance(newRef.peer, VectorPortRef)) 1844 return newRef 1845 1846 def unproxy(self, simobj): 1847 assert(simobj is self.simobj) 1848 if proxy.isproxy(self.peer): 1849 try: 1850 realPeer = self.peer.unproxy(self.simobj) 1851 except: 1852 print "Error in unproxying port '%s' of %s" % \ 1853 (self.name, self.simobj.path()) 1854 raise 1855 self.connect(realPeer) 1856 1857 # Call C++ to create corresponding port connection between C++ objects 1858 def ccConnect(self): 1859 from _m5.pyobject import connectPorts 1860 1861 if self.role == 'SLAVE': 1862 # do nothing and let the master take care of it 1863 return 1864 1865 if self.ccConnected: # already done this 1866 return 1867 peer = self.peer 1868 if not self.peer: # nothing to connect to 1869 return 1870 1871 # check that we connect a master to a slave 1872 if self.role == peer.role: 1873 raise TypeError, \ 1874 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1875 % (peer, self, self.role) 1876 1877 try: 1878 # self is always the master and peer the slave 1879 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1880 peer.simobj.getCCObject(), peer.name, peer.index) 1881 except: 1882 print "Error connecting port %s.%s to %s.%s" % \ 1883 (self.simobj.path(), self.name, 1884 peer.simobj.path(), peer.name) 1885 raise 1886 self.ccConnected = True 1887 peer.ccConnected = True 1888 1889# A reference to an individual element of a VectorPort... much like a 1890# PortRef, but has an index. 1891class VectorPortElementRef(PortRef): 1892 def __init__(self, simobj, name, role, index): 1893 PortRef.__init__(self, simobj, name, role) 1894 self.index = index 1895 1896 def __str__(self): 1897 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1898 1899# A reference to a complete vector-valued port (not just a single element). 1900# Can be indexed to retrieve individual VectorPortElementRef instances. 1901class VectorPortRef(object): 1902 def __init__(self, simobj, name, role): 1903 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1904 self.simobj = simobj 1905 self.name = name 1906 self.role = role 1907 self.elements = [] 1908 1909 def __str__(self): 1910 return '%s.%s[:]' % (self.simobj, self.name) 1911 1912 def __len__(self): 1913 # Return the number of connected peers, corresponding the the 1914 # length of the elements. 1915 return len(self.elements) 1916 1917 # for config.ini, print peer's name (not ours) 1918 def ini_str(self): 1919 return ' '.join([el.ini_str() for el in self.elements]) 1920 1921 # for config.json 1922 def get_config_as_dict(self): 1923 return {'role' : self.role, 1924 'peer' : [el.ini_str() for el in self.elements]} 1925 1926 def __getitem__(self, key): 1927 if not isinstance(key, int): 1928 raise TypeError, "VectorPort index must be integer" 1929 if key >= len(self.elements): 1930 # need to extend list 1931 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1932 for i in range(len(self.elements), key+1)] 1933 self.elements.extend(ext) 1934 return self.elements[key] 1935 1936 def _get_next(self): 1937 return self[len(self.elements)] 1938 1939 def __setitem__(self, key, value): 1940 if not isinstance(key, int): 1941 raise TypeError, "VectorPort index must be integer" 1942 self[key].connect(value) 1943 1944 def connect(self, other): 1945 if isinstance(other, (list, tuple)): 1946 # Assign list of port refs to vector port. 1947 # For now, append them... not sure if that's the right semantics 1948 # or if it should replace the current vector. 1949 for ref in other: 1950 self._get_next().connect(ref) 1951 else: 1952 # scalar assignment to plain VectorPort is implicit append 1953 self._get_next().connect(other) 1954 1955 def clone(self, simobj, memo): 1956 if memo.has_key(self): 1957 return memo[self] 1958 newRef = copy.copy(self) 1959 memo[self] = newRef 1960 newRef.simobj = simobj 1961 assert(isSimObject(newRef.simobj)) 1962 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1963 return newRef 1964 1965 def unproxy(self, simobj): 1966 [el.unproxy(simobj) for el in self.elements] 1967 1968 def ccConnect(self): 1969 [el.ccConnect() for el in self.elements] 1970 1971# Port description object. Like a ParamDesc object, this represents a 1972# logical port in the SimObject class, not a particular port on a 1973# SimObject instance. The latter are represented by PortRef objects. 1974class Port(object): 1975 # Generate a PortRef for this port on the given SimObject with the 1976 # given name 1977 def makeRef(self, simobj): 1978 return PortRef(simobj, self.name, self.role) 1979 1980 # Connect an instance of this port (on the given SimObject with 1981 # the given name) with the port described by the supplied PortRef 1982 def connect(self, simobj, ref): 1983 self.makeRef(simobj).connect(ref) 1984 1985 # No need for any pre-declarations at the moment as we merely rely 1986 # on an unsigned int. 1987 def cxx_predecls(self, code): 1988 pass 1989 1990 def pybind_predecls(self, code): 1991 cls.cxx_predecls(self, code) 1992 1993 # Declare an unsigned int with the same name as the port, that 1994 # will eventually hold the number of connected ports (and thus the 1995 # number of elements for a VectorPort). 1996 def cxx_decl(self, code): 1997 code('unsigned int port_${{self.name}}_connection_count;') 1998 1999class MasterPort(Port): 2000 # MasterPort("description") 2001 def __init__(self, *args): 2002 if len(args) == 1: 2003 self.desc = args[0] 2004 self.role = 'MASTER' 2005 else: 2006 raise TypeError, 'wrong number of arguments' 2007 2008class SlavePort(Port): 2009 # SlavePort("description") 2010 def __init__(self, *args): 2011 if len(args) == 1: 2012 self.desc = args[0] 2013 self.role = 'SLAVE' 2014 else: 2015 raise TypeError, 'wrong number of arguments' 2016 2017# VectorPort description object. Like Port, but represents a vector 2018# of connections (e.g., as on a XBar). 2019class VectorPort(Port): 2020 def __init__(self, *args): 2021 self.isVec = True 2022 2023 def makeRef(self, simobj): 2024 return VectorPortRef(simobj, self.name, self.role) 2025 2026class VectorMasterPort(VectorPort): 2027 # VectorMasterPort("description") 2028 def __init__(self, *args): 2029 if len(args) == 1: 2030 self.desc = args[0] 2031 self.role = 'MASTER' 2032 VectorPort.__init__(self, *args) 2033 else: 2034 raise TypeError, 'wrong number of arguments' 2035 2036class VectorSlavePort(VectorPort): 2037 # VectorSlavePort("description") 2038 def __init__(self, *args): 2039 if len(args) == 1: 2040 self.desc = args[0] 2041 self.role = 'SLAVE' 2042 VectorPort.__init__(self, *args) 2043 else: 2044 raise TypeError, 'wrong number of arguments' 2045 2046# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2047# proxy objects (via set_param_desc()) so that proxy error messages 2048# make sense. 2049class PortParamDesc(object): 2050 __metaclass__ = Singleton 2051 2052 ptype_str = 'Port' 2053 ptype = Port 2054 2055baseEnums = allEnums.copy() 2056baseParams = allParams.copy() 2057 2058def clear(): 2059 global allEnums, allParams 2060 2061 allEnums = baseEnums.copy() 2062 allParams = baseParams.copy() 2063 2064__all__ = ['Param', 'VectorParam', 2065 'Enum', 'Bool', 'String', 'Float', 2066 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2067 'Int32', 'UInt32', 'Int64', 'UInt64', 2068 'Counter', 'Addr', 'Tick', 'Percent', 2069 'TcpPort', 'UdpPort', 'EthernetAddr', 2070 'IpAddress', 'IpNetmask', 'IpWithPort', 2071 'MemorySize', 'MemorySize32', 2072 'Latency', 'Frequency', 'Clock', 'Voltage', 2073 'NetworkBandwidth', 'MemoryBandwidth', 2074 'AddrRange', 2075 'MaxAddr', 'MaxTick', 'AllMemory', 2076 'Time', 2077 'NextEthernetAddr', 'NULL', 2078 'MasterPort', 'SlavePort', 2079 'VectorMasterPort', 'VectorSlavePort'] 2080 2081import SimObject
| 274 275 # return 'cpu0 cpu1' etc. for print_ini() 276 def get_name(self): 277 return ' '.join([v._name for v in self]) 278 279 # By iterating through the constituent members of the vector here 280 # we can nicely handle iterating over all a SimObject's children 281 # without having to provide lots of special functions on 282 # SimObjectVector directly. 283 def descendants(self): 284 for v in self: 285 for obj in v.descendants(): 286 yield obj 287 288 def get_config_as_dict(self): 289 a = [] 290 for v in self: 291 a.append(v.get_config_as_dict()) 292 return a 293 294 # If we are replacing an item in the vector, make sure to set the 295 # parent reference of the new SimObject to be the same as the parent 296 # of the SimObject being replaced. Useful to have if we created 297 # a SimObjectVector of temporary objects that will be modified later in 298 # configuration scripts. 299 def __setitem__(self, key, value): 300 val = self[key] 301 if value.has_parent(): 302 warn("SimObject %s already has a parent" % value.get_name() +\ 303 " that is being overwritten by a SimObjectVector") 304 value.set_parent(val.get_parent(), val._name) 305 super(SimObjectVector, self).__setitem__(key, value) 306 307 # Enumerate the params of each member of the SimObject vector. Creates 308 # strings that will allow indexing into the vector by the python code and 309 # allow it to be specified on the command line. 310 def enumerateParams(self, flags_dict = {}, 311 cmd_line_str = "", 312 access_str = ""): 313 if hasattr(self, "_paramEnumed"): 314 print "Cycle detected enumerating params at %s?!" % (cmd_line_str) 315 else: 316 x = 0 317 for vals in self: 318 # Each entry in the SimObjectVector should be an 319 # instance of a SimObject 320 flags_dict = vals.enumerateParams(flags_dict, 321 cmd_line_str + "%d." % x, 322 access_str + "[%d]." % x) 323 x = x + 1 324 325 return flags_dict 326 327class VectorParamDesc(ParamDesc): 328 # Convert assigned value to appropriate type. If the RHS is not a 329 # list or tuple, it generates a single-element list. 330 def convert(self, value): 331 if isinstance(value, (list, tuple)): 332 # list: coerce each element into new list 333 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 334 elif isinstance(value, str): 335 # If input is a csv string 336 tmp_list = [ ParamDesc.convert(self, v) \ 337 for v in value.strip('[').strip(']').split(',') ] 338 else: 339 # singleton: coerce to a single-element list 340 tmp_list = [ ParamDesc.convert(self, value) ] 341 342 if isSimObjectSequence(tmp_list): 343 return SimObjectVector(tmp_list) 344 else: 345 return VectorParamValue(tmp_list) 346 347 # Produce a human readable example string that describes 348 # how to set this vector parameter in the absence of a default 349 # value. 350 def example_str(self): 351 s = super(VectorParamDesc, self).example_str() 352 help_str = "[" + s + "," + s + ", ...]" 353 return help_str 354 355 # Produce a human readable representation of the value of this vector param. 356 def pretty_print(self, value): 357 if isinstance(value, (list, tuple)): 358 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 359 elif isinstance(value, str): 360 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 361 else: 362 tmp_list = [ ParamDesc.pretty_print(self, value) ] 363 364 return tmp_list 365 366 # This is a helper function for the new config system 367 def __call__(self, value): 368 if isinstance(value, (list, tuple)): 369 # list: coerce each element into new list 370 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 371 elif isinstance(value, str): 372 # If input is a csv string 373 tmp_list = [ ParamDesc.convert(self, v) \ 374 for v in value.strip('[').strip(']').split(',') ] 375 else: 376 # singleton: coerce to a single-element list 377 tmp_list = [ ParamDesc.convert(self, value) ] 378 379 return VectorParamValue(tmp_list) 380 381 def cxx_predecls(self, code): 382 code('#include <vector>') 383 self.ptype.cxx_predecls(code) 384 385 def pybind_predecls(self, code): 386 code('#include <vector>') 387 self.ptype.pybind_predecls(code) 388 389 def cxx_decl(self, code): 390 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 391 392class ParamFactory(object): 393 def __init__(self, param_desc_class, ptype_str = None): 394 self.param_desc_class = param_desc_class 395 self.ptype_str = ptype_str 396 397 def __getattr__(self, attr): 398 if self.ptype_str: 399 attr = self.ptype_str + '.' + attr 400 return ParamFactory(self.param_desc_class, attr) 401 402 # E.g., Param.Int(5, "number of widgets") 403 def __call__(self, *args, **kwargs): 404 ptype = None 405 try: 406 ptype = allParams[self.ptype_str] 407 except KeyError: 408 # if name isn't defined yet, assume it's a SimObject, and 409 # try to resolve it later 410 pass 411 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 412 413Param = ParamFactory(ParamDesc) 414VectorParam = ParamFactory(VectorParamDesc) 415 416##################################################################### 417# 418# Parameter Types 419# 420# Though native Python types could be used to specify parameter types 421# (the 'ptype' field of the Param and VectorParam classes), it's more 422# flexible to define our own set of types. This gives us more control 423# over how Python expressions are converted to values (via the 424# __init__() constructor) and how these values are printed out (via 425# the __str__() conversion method). 426# 427##################################################################### 428 429# String-valued parameter. Just mixin the ParamValue class with the 430# built-in str class. 431class String(ParamValue,str): 432 cxx_type = 'std::string' 433 cmd_line_settable = True 434 435 @classmethod 436 def cxx_predecls(self, code): 437 code('#include <string>') 438 439 def __call__(self, value): 440 self = value 441 return value 442 443 @classmethod 444 def cxx_ini_parse(self, code, src, dest, ret): 445 code('%s = %s;' % (dest, src)) 446 code('%s true;' % ret) 447 448 def getValue(self): 449 return self 450 451# superclass for "numeric" parameter values, to emulate math 452# operations in a type-safe way. e.g., a Latency times an int returns 453# a new Latency object. 454class NumericParamValue(ParamValue): 455 def __str__(self): 456 return str(self.value) 457 458 def __float__(self): 459 return float(self.value) 460 461 def __long__(self): 462 return long(self.value) 463 464 def __int__(self): 465 return int(self.value) 466 467 # hook for bounds checking 468 def _check(self): 469 return 470 471 def __mul__(self, other): 472 newobj = self.__class__(self) 473 newobj.value *= other 474 newobj._check() 475 return newobj 476 477 __rmul__ = __mul__ 478 479 def __div__(self, other): 480 newobj = self.__class__(self) 481 newobj.value /= other 482 newobj._check() 483 return newobj 484 485 def __sub__(self, other): 486 newobj = self.__class__(self) 487 newobj.value -= other 488 newobj._check() 489 return newobj 490 491 def config_value(self): 492 return self.value 493 494 @classmethod 495 def cxx_ini_predecls(cls, code): 496 # Assume that base/str.hh will be included anyway 497 # code('#include "base/str.hh"') 498 pass 499 500 # The default for parsing PODs from an .ini entry is to extract from an 501 # istringstream and let overloading choose the right type according to 502 # the dest type. 503 @classmethod 504 def cxx_ini_parse(self, code, src, dest, ret): 505 code('%s to_number(%s, %s);' % (ret, src, dest)) 506 507# Metaclass for bounds-checked integer parameters. See CheckedInt. 508class CheckedIntType(MetaParamValue): 509 def __init__(cls, name, bases, dict): 510 super(CheckedIntType, cls).__init__(name, bases, dict) 511 512 # CheckedInt is an abstract base class, so we actually don't 513 # want to do any processing on it... the rest of this code is 514 # just for classes that derive from CheckedInt. 515 if name == 'CheckedInt': 516 return 517 518 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 519 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 520 panic("CheckedInt subclass %s must define either\n" \ 521 " 'min' and 'max' or 'size' and 'unsigned'\n", 522 name); 523 if cls.unsigned: 524 cls.min = 0 525 cls.max = 2 ** cls.size - 1 526 else: 527 cls.min = -(2 ** (cls.size - 1)) 528 cls.max = (2 ** (cls.size - 1)) - 1 529 530# Abstract superclass for bounds-checked integer parameters. This 531# class is subclassed to generate parameter classes with specific 532# bounds. Initialization of the min and max bounds is done in the 533# metaclass CheckedIntType.__init__. 534class CheckedInt(NumericParamValue): 535 __metaclass__ = CheckedIntType 536 cmd_line_settable = True 537 538 def _check(self): 539 if not self.min <= self.value <= self.max: 540 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 541 (self.min, self.value, self.max) 542 543 def __init__(self, value): 544 if isinstance(value, str): 545 self.value = convert.toInteger(value) 546 elif isinstance(value, (int, long, float, NumericParamValue)): 547 self.value = long(value) 548 else: 549 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 550 % type(value).__name__ 551 self._check() 552 553 def __call__(self, value): 554 self.__init__(value) 555 return value 556 557 @classmethod 558 def cxx_predecls(cls, code): 559 # most derived types require this, so we just do it here once 560 code('#include "base/types.hh"') 561 562 def getValue(self): 563 return long(self.value) 564 565class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 566class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 567 568class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 569class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 570class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 571class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 572class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 573class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 574class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 575class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 576 577class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 578class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 579class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 580class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 581 582class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 583 584class Cycles(CheckedInt): 585 cxx_type = 'Cycles' 586 size = 64 587 unsigned = True 588 589 def getValue(self): 590 from _m5.core import Cycles 591 return Cycles(self.value) 592 593 @classmethod 594 def cxx_ini_predecls(cls, code): 595 # Assume that base/str.hh will be included anyway 596 # code('#include "base/str.hh"') 597 pass 598 599 @classmethod 600 def cxx_ini_parse(cls, code, src, dest, ret): 601 code('uint64_t _temp;') 602 code('bool _ret = to_number(%s, _temp);' % src) 603 code('if (_ret)') 604 code(' %s = Cycles(_temp);' % dest) 605 code('%s _ret;' % ret) 606 607class Float(ParamValue, float): 608 cxx_type = 'double' 609 cmd_line_settable = True 610 611 def __init__(self, value): 612 if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 613 self.value = float(value) 614 else: 615 raise TypeError, "Can't convert object of type %s to Float" \ 616 % type(value).__name__ 617 618 def __call__(self, value): 619 self.__init__(value) 620 return value 621 622 def getValue(self): 623 return float(self.value) 624 625 def config_value(self): 626 return self 627 628 @classmethod 629 def cxx_ini_predecls(cls, code): 630 code('#include <sstream>') 631 632 @classmethod 633 def cxx_ini_parse(self, code, src, dest, ret): 634 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 635 636class MemorySize(CheckedInt): 637 cxx_type = 'uint64_t' 638 ex_str = '512MB' 639 size = 64 640 unsigned = True 641 def __init__(self, value): 642 if isinstance(value, MemorySize): 643 self.value = value.value 644 else: 645 self.value = convert.toMemorySize(value) 646 self._check() 647 648class MemorySize32(CheckedInt): 649 cxx_type = 'uint32_t' 650 ex_str = '512MB' 651 size = 32 652 unsigned = True 653 def __init__(self, value): 654 if isinstance(value, MemorySize): 655 self.value = value.value 656 else: 657 self.value = convert.toMemorySize(value) 658 self._check() 659 660class Addr(CheckedInt): 661 cxx_type = 'Addr' 662 size = 64 663 unsigned = True 664 def __init__(self, value): 665 if isinstance(value, Addr): 666 self.value = value.value 667 else: 668 try: 669 # Often addresses are referred to with sizes. Ex: A device 670 # base address is at "512MB". Use toMemorySize() to convert 671 # these into addresses. If the address is not specified with a 672 # "size", an exception will occur and numeric translation will 673 # proceed below. 674 self.value = convert.toMemorySize(value) 675 except (TypeError, ValueError): 676 # Convert number to string and use long() to do automatic 677 # base conversion (requires base=0 for auto-conversion) 678 self.value = long(str(value), base=0) 679 680 self._check() 681 def __add__(self, other): 682 if isinstance(other, Addr): 683 return self.value + other.value 684 else: 685 return self.value + other 686 def pretty_print(self, value): 687 try: 688 val = convert.toMemorySize(value) 689 except TypeError: 690 val = long(value) 691 return "0x%x" % long(val) 692 693class AddrRange(ParamValue): 694 cxx_type = 'AddrRange' 695 696 def __init__(self, *args, **kwargs): 697 # Disable interleaving and hashing by default 698 self.intlvHighBit = 0 699 self.xorHighBit = 0 700 self.intlvBits = 0 701 self.intlvMatch = 0 702 703 def handle_kwargs(self, kwargs): 704 # An address range needs to have an upper limit, specified 705 # either explicitly with an end, or as an offset using the 706 # size keyword. 707 if 'end' in kwargs: 708 self.end = Addr(kwargs.pop('end')) 709 elif 'size' in kwargs: 710 self.end = self.start + Addr(kwargs.pop('size')) - 1 711 else: 712 raise TypeError, "Either end or size must be specified" 713 714 # Now on to the optional bit 715 if 'intlvHighBit' in kwargs: 716 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 717 if 'xorHighBit' in kwargs: 718 self.xorHighBit = int(kwargs.pop('xorHighBit')) 719 if 'intlvBits' in kwargs: 720 self.intlvBits = int(kwargs.pop('intlvBits')) 721 if 'intlvMatch' in kwargs: 722 self.intlvMatch = int(kwargs.pop('intlvMatch')) 723 724 if len(args) == 0: 725 self.start = Addr(kwargs.pop('start')) 726 handle_kwargs(self, kwargs) 727 728 elif len(args) == 1: 729 if kwargs: 730 self.start = Addr(args[0]) 731 handle_kwargs(self, kwargs) 732 elif isinstance(args[0], (list, tuple)): 733 self.start = Addr(args[0][0]) 734 self.end = Addr(args[0][1]) 735 else: 736 self.start = Addr(0) 737 self.end = Addr(args[0]) - 1 738 739 elif len(args) == 2: 740 self.start = Addr(args[0]) 741 self.end = Addr(args[1]) 742 else: 743 raise TypeError, "Too many arguments specified" 744 745 if kwargs: 746 raise TypeError, "Too many keywords: %s" % kwargs.keys() 747 748 def __str__(self): 749 return '%s:%s:%s:%s:%s:%s' \ 750 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 751 self.intlvBits, self.intlvMatch) 752 753 def size(self): 754 # Divide the size by the size of the interleaving slice 755 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 756 757 @classmethod 758 def cxx_predecls(cls, code): 759 Addr.cxx_predecls(code) 760 code('#include "base/addr_range.hh"') 761 762 @classmethod 763 def pybind_predecls(cls, code): 764 Addr.pybind_predecls(code) 765 code('#include "base/addr_range.hh"') 766 767 @classmethod 768 def cxx_ini_predecls(cls, code): 769 code('#include <sstream>') 770 771 @classmethod 772 def cxx_ini_parse(cls, code, src, dest, ret): 773 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 774 code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 775 code('char _sep;') 776 code('std::istringstream _stream(${src});') 777 code('_stream >> _start;') 778 code('_stream.get(_sep);') 779 code('_stream >> _end;') 780 code('if (!_stream.fail() && !_stream.eof()) {') 781 code(' _stream.get(_sep);') 782 code(' _stream >> _intlvHighBit;') 783 code(' _stream.get(_sep);') 784 code(' _stream >> _xorHighBit;') 785 code(' _stream.get(_sep);') 786 code(' _stream >> _intlvBits;') 787 code(' _stream.get(_sep);') 788 code(' _stream >> _intlvMatch;') 789 code('}') 790 code('bool _ret = !_stream.fail() &&' 791 '_stream.eof() && _sep == \':\';') 792 code('if (_ret)') 793 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 794 _xorHighBit, _intlvBits, _intlvMatch);') 795 code('${ret} _ret;') 796 797 def getValue(self): 798 # Go from the Python class to the wrapped C++ class 799 from _m5.range import AddrRange 800 801 return AddrRange(long(self.start), long(self.end), 802 int(self.intlvHighBit), int(self.xorHighBit), 803 int(self.intlvBits), int(self.intlvMatch)) 804 805# Boolean parameter type. Python doesn't let you subclass bool, since 806# it doesn't want to let you create multiple instances of True and 807# False. Thus this is a little more complicated than String. 808class Bool(ParamValue): 809 cxx_type = 'bool' 810 cmd_line_settable = True 811 812 def __init__(self, value): 813 try: 814 self.value = convert.toBool(value) 815 except TypeError: 816 self.value = bool(value) 817 818 def __call__(self, value): 819 self.__init__(value) 820 return value 821 822 def getValue(self): 823 return bool(self.value) 824 825 def __str__(self): 826 return str(self.value) 827 828 # implement truth value testing for Bool parameters so that these params 829 # evaluate correctly during the python configuration phase 830 def __nonzero__(self): 831 return bool(self.value) 832 833 def ini_str(self): 834 if self.value: 835 return 'true' 836 return 'false' 837 838 def config_value(self): 839 return self.value 840 841 @classmethod 842 def cxx_ini_predecls(cls, code): 843 # Assume that base/str.hh will be included anyway 844 # code('#include "base/str.hh"') 845 pass 846 847 @classmethod 848 def cxx_ini_parse(cls, code, src, dest, ret): 849 code('%s to_bool(%s, %s);' % (ret, src, dest)) 850 851def IncEthernetAddr(addr, val = 1): 852 bytes = map(lambda x: int(x, 16), addr.split(':')) 853 bytes[5] += val 854 for i in (5, 4, 3, 2, 1): 855 val,rem = divmod(bytes[i], 256) 856 bytes[i] = rem 857 if val == 0: 858 break 859 bytes[i - 1] += val 860 assert(bytes[0] <= 255) 861 return ':'.join(map(lambda x: '%02x' % x, bytes)) 862 863_NextEthernetAddr = "00:90:00:00:00:01" 864def NextEthernetAddr(): 865 global _NextEthernetAddr 866 867 value = _NextEthernetAddr 868 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 869 return value 870 871class EthernetAddr(ParamValue): 872 cxx_type = 'Net::EthAddr' 873 ex_str = "00:90:00:00:00:01" 874 cmd_line_settable = True 875 876 @classmethod 877 def cxx_predecls(cls, code): 878 code('#include "base/inet.hh"') 879 880 def __init__(self, value): 881 if value == NextEthernetAddr: 882 self.value = value 883 return 884 885 if not isinstance(value, str): 886 raise TypeError, "expected an ethernet address and didn't get one" 887 888 bytes = value.split(':') 889 if len(bytes) != 6: 890 raise TypeError, 'invalid ethernet address %s' % value 891 892 for byte in bytes: 893 if not 0 <= int(byte, base=16) <= 0xff: 894 raise TypeError, 'invalid ethernet address %s' % value 895 896 self.value = value 897 898 def __call__(self, value): 899 self.__init__(value) 900 return value 901 902 def unproxy(self, base): 903 if self.value == NextEthernetAddr: 904 return EthernetAddr(self.value()) 905 return self 906 907 def getValue(self): 908 from _m5.net import EthAddr 909 return EthAddr(self.value) 910 911 def __str__(self): 912 return self.value 913 914 def ini_str(self): 915 return self.value 916 917 @classmethod 918 def cxx_ini_parse(self, code, src, dest, ret): 919 code('%s = Net::EthAddr(%s);' % (dest, src)) 920 code('%s true;' % ret) 921 922# When initializing an IpAddress, pass in an existing IpAddress, a string of 923# the form "a.b.c.d", or an integer representing an IP. 924class IpAddress(ParamValue): 925 cxx_type = 'Net::IpAddress' 926 ex_str = "127.0.0.1" 927 cmd_line_settable = True 928 929 @classmethod 930 def cxx_predecls(cls, code): 931 code('#include "base/inet.hh"') 932 933 def __init__(self, value): 934 if isinstance(value, IpAddress): 935 self.ip = value.ip 936 else: 937 try: 938 self.ip = convert.toIpAddress(value) 939 except TypeError: 940 self.ip = long(value) 941 self.verifyIp() 942 943 def __call__(self, value): 944 self.__init__(value) 945 return value 946 947 def __str__(self): 948 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 949 return '%d.%d.%d.%d' % tuple(tup) 950 951 def __eq__(self, other): 952 if isinstance(other, IpAddress): 953 return self.ip == other.ip 954 elif isinstance(other, str): 955 try: 956 return self.ip == convert.toIpAddress(other) 957 except: 958 return False 959 else: 960 return self.ip == other 961 962 def __ne__(self, other): 963 return not (self == other) 964 965 def verifyIp(self): 966 if self.ip < 0 or self.ip >= (1 << 32): 967 raise TypeError, "invalid ip address %#08x" % self.ip 968 969 def getValue(self): 970 from _m5.net import IpAddress 971 return IpAddress(self.ip) 972 973# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 974# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 975# positional or keyword arguments. 976class IpNetmask(IpAddress): 977 cxx_type = 'Net::IpNetmask' 978 ex_str = "127.0.0.0/24" 979 cmd_line_settable = True 980 981 @classmethod 982 def cxx_predecls(cls, code): 983 code('#include "base/inet.hh"') 984 985 def __init__(self, *args, **kwargs): 986 def handle_kwarg(self, kwargs, key, elseVal = None): 987 if key in kwargs: 988 setattr(self, key, kwargs.pop(key)) 989 elif elseVal: 990 setattr(self, key, elseVal) 991 else: 992 raise TypeError, "No value set for %s" % key 993 994 if len(args) == 0: 995 handle_kwarg(self, kwargs, 'ip') 996 handle_kwarg(self, kwargs, 'netmask') 997 998 elif len(args) == 1: 999 if kwargs: 1000 if not 'ip' in kwargs and not 'netmask' in kwargs: 1001 raise TypeError, "Invalid arguments" 1002 handle_kwarg(self, kwargs, 'ip', args[0]) 1003 handle_kwarg(self, kwargs, 'netmask', args[0]) 1004 elif isinstance(args[0], IpNetmask): 1005 self.ip = args[0].ip 1006 self.netmask = args[0].netmask 1007 else: 1008 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1009 1010 elif len(args) == 2: 1011 self.ip = args[0] 1012 self.netmask = args[1] 1013 else: 1014 raise TypeError, "Too many arguments specified" 1015 1016 if kwargs: 1017 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1018 1019 self.verify() 1020 1021 def __call__(self, value): 1022 self.__init__(value) 1023 return value 1024 1025 def __str__(self): 1026 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1027 1028 def __eq__(self, other): 1029 if isinstance(other, IpNetmask): 1030 return self.ip == other.ip and self.netmask == other.netmask 1031 elif isinstance(other, str): 1032 try: 1033 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1034 except: 1035 return False 1036 else: 1037 return False 1038 1039 def verify(self): 1040 self.verifyIp() 1041 if self.netmask < 0 or self.netmask > 32: 1042 raise TypeError, "invalid netmask %d" % netmask 1043 1044 def getValue(self): 1045 from _m5.net import IpNetmask 1046 return IpNetmask(self.ip, self.netmask) 1047 1048# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1049# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1050class IpWithPort(IpAddress): 1051 cxx_type = 'Net::IpWithPort' 1052 ex_str = "127.0.0.1:80" 1053 cmd_line_settable = True 1054 1055 @classmethod 1056 def cxx_predecls(cls, code): 1057 code('#include "base/inet.hh"') 1058 1059 def __init__(self, *args, **kwargs): 1060 def handle_kwarg(self, kwargs, key, elseVal = None): 1061 if key in kwargs: 1062 setattr(self, key, kwargs.pop(key)) 1063 elif elseVal: 1064 setattr(self, key, elseVal) 1065 else: 1066 raise TypeError, "No value set for %s" % key 1067 1068 if len(args) == 0: 1069 handle_kwarg(self, kwargs, 'ip') 1070 handle_kwarg(self, kwargs, 'port') 1071 1072 elif len(args) == 1: 1073 if kwargs: 1074 if not 'ip' in kwargs and not 'port' in kwargs: 1075 raise TypeError, "Invalid arguments" 1076 handle_kwarg(self, kwargs, 'ip', args[0]) 1077 handle_kwarg(self, kwargs, 'port', args[0]) 1078 elif isinstance(args[0], IpWithPort): 1079 self.ip = args[0].ip 1080 self.port = args[0].port 1081 else: 1082 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1083 1084 elif len(args) == 2: 1085 self.ip = args[0] 1086 self.port = args[1] 1087 else: 1088 raise TypeError, "Too many arguments specified" 1089 1090 if kwargs: 1091 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1092 1093 self.verify() 1094 1095 def __call__(self, value): 1096 self.__init__(value) 1097 return value 1098 1099 def __str__(self): 1100 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1101 1102 def __eq__(self, other): 1103 if isinstance(other, IpWithPort): 1104 return self.ip == other.ip and self.port == other.port 1105 elif isinstance(other, str): 1106 try: 1107 return (self.ip, self.port) == convert.toIpWithPort(other) 1108 except: 1109 return False 1110 else: 1111 return False 1112 1113 def verify(self): 1114 self.verifyIp() 1115 if self.port < 0 or self.port > 0xffff: 1116 raise TypeError, "invalid port %d" % self.port 1117 1118 def getValue(self): 1119 from _m5.net import IpWithPort 1120 return IpWithPort(self.ip, self.port) 1121 1122time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1123 "%a %b %d %H:%M:%S %Y", 1124 "%Y/%m/%d %H:%M:%S", 1125 "%Y/%m/%d %H:%M", 1126 "%Y/%m/%d", 1127 "%m/%d/%Y %H:%M:%S", 1128 "%m/%d/%Y %H:%M", 1129 "%m/%d/%Y", 1130 "%m/%d/%y %H:%M:%S", 1131 "%m/%d/%y %H:%M", 1132 "%m/%d/%y"] 1133 1134 1135def parse_time(value): 1136 from time import gmtime, strptime, struct_time, time 1137 from datetime import datetime, date 1138 1139 if isinstance(value, struct_time): 1140 return value 1141 1142 if isinstance(value, (int, long)): 1143 return gmtime(value) 1144 1145 if isinstance(value, (datetime, date)): 1146 return value.timetuple() 1147 1148 if isinstance(value, str): 1149 if value in ('Now', 'Today'): 1150 return time.gmtime(time.time()) 1151 1152 for format in time_formats: 1153 try: 1154 return strptime(value, format) 1155 except ValueError: 1156 pass 1157 1158 raise ValueError, "Could not parse '%s' as a time" % value 1159 1160class Time(ParamValue): 1161 cxx_type = 'tm' 1162 1163 @classmethod 1164 def cxx_predecls(cls, code): 1165 code('#include <time.h>') 1166 1167 def __init__(self, value): 1168 self.value = parse_time(value) 1169 1170 def __call__(self, value): 1171 self.__init__(value) 1172 return value 1173 1174 def getValue(self): 1175 from _m5.core import tm 1176 import calendar 1177 1178 return tm.gmtime(calendar.timegm(self.value)) 1179 1180 def __str__(self): 1181 return time.asctime(self.value) 1182 1183 def ini_str(self): 1184 return str(self) 1185 1186 def get_config_as_dict(self): 1187 assert false 1188 return str(self) 1189 1190 @classmethod 1191 def cxx_ini_predecls(cls, code): 1192 code('#include <time.h>') 1193 1194 @classmethod 1195 def cxx_ini_parse(cls, code, src, dest, ret): 1196 code('char *_parse_ret = strptime((${src}).c_str(),') 1197 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1198 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1199 1200# Enumerated types are a little more complex. The user specifies the 1201# type as Enum(foo) where foo is either a list or dictionary of 1202# alternatives (typically strings, but not necessarily so). (In the 1203# long run, the integer value of the parameter will be the list index 1204# or the corresponding dictionary value. For now, since we only check 1205# that the alternative is valid and then spit it into a .ini file, 1206# there's not much point in using the dictionary.) 1207 1208# What Enum() must do is generate a new type encapsulating the 1209# provided list/dictionary so that specific values of the parameter 1210# can be instances of that type. We define two hidden internal 1211# classes (_ListEnum and _DictEnum) to serve as base classes, then 1212# derive the new type from the appropriate base class on the fly. 1213 1214allEnums = {} 1215# Metaclass for Enum types 1216class MetaEnum(MetaParamValue): 1217 def __new__(mcls, name, bases, dict): 1218 assert name not in allEnums 1219 1220 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1221 allEnums[name] = cls 1222 return cls 1223 1224 def __init__(cls, name, bases, init_dict): 1225 if init_dict.has_key('map'): 1226 if not isinstance(cls.map, dict): 1227 raise TypeError, "Enum-derived class attribute 'map' " \ 1228 "must be of type dict" 1229 # build list of value strings from map 1230 cls.vals = cls.map.keys() 1231 cls.vals.sort() 1232 elif init_dict.has_key('vals'): 1233 if not isinstance(cls.vals, list): 1234 raise TypeError, "Enum-derived class attribute 'vals' " \ 1235 "must be of type list" 1236 # build string->value map from vals sequence 1237 cls.map = {} 1238 for idx,val in enumerate(cls.vals): 1239 cls.map[val] = idx 1240 else: 1241 raise TypeError, "Enum-derived class must define "\ 1242 "attribute 'map' or 'vals'" 1243 1244 cls.cxx_type = 'Enums::%s' % name 1245 1246 super(MetaEnum, cls).__init__(name, bases, init_dict) 1247 1248 # Generate C++ class declaration for this enum type. 1249 # Note that we wrap the enum in a class/struct to act as a namespace, 1250 # so that the enum strings can be brief w/o worrying about collisions. 1251 def cxx_decl(cls, code): 1252 wrapper_name = cls.wrapper_name 1253 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1254 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1255 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1256 1257 code('''\ 1258#ifndef $idem_macro 1259#define $idem_macro 1260 1261$wrapper $wrapper_name { 1262 enum $name { 1263''') 1264 code.indent(2) 1265 for val in cls.vals: 1266 code('$val = ${{cls.map[val]}},') 1267 code('Num_$name = ${{len(cls.vals)}}') 1268 code.dedent(2) 1269 code(' };') 1270 1271 if cls.wrapper_is_struct: 1272 code(' static const char *${name}Strings[Num_${name}];') 1273 code('};') 1274 else: 1275 code('extern const char *${name}Strings[Num_${name}];') 1276 code('}') 1277 1278 code() 1279 code('#endif // $idem_macro') 1280 1281 def cxx_def(cls, code): 1282 wrapper_name = cls.wrapper_name 1283 file_name = cls.__name__ 1284 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1285 1286 code('#include "enums/$file_name.hh"') 1287 if cls.wrapper_is_struct: 1288 code('const char *${wrapper_name}::${name}Strings' 1289 '[Num_${name}] =') 1290 else: 1291 code('namespace Enums {') 1292 code.indent(1) 1293 code(' const char *${name}Strings[Num_${name}] =') 1294 1295 code('{') 1296 code.indent(1) 1297 for val in cls.vals: 1298 code('"$val",') 1299 code.dedent(1) 1300 code('};') 1301 1302 if not cls.wrapper_is_struct: 1303 code('} // namespace $wrapper_name') 1304 code.dedent(1) 1305 1306 def pybind_def(cls, code): 1307 name = cls.__name__ 1308 wrapper_name = cls.wrapper_name 1309 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1310 1311 code('''#include "pybind11/pybind11.h" 1312#include "pybind11/stl.h" 1313 1314#include <sim/init.hh> 1315 1316namespace py = pybind11; 1317 1318static void 1319module_init(py::module &m_internal) 1320{ 1321 py::module m = m_internal.def_submodule("enum_${name}"); 1322 1323 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}") 1324''') 1325 1326 code.indent() 1327 code.indent() 1328 for val in cls.vals: 1329 code('.value("${val}", ${wrapper_name}::${val})') 1330 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1331 code('.export_values()') 1332 code(';') 1333 code.dedent() 1334 1335 code('}') 1336 code.dedent() 1337 code() 1338 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1339 1340 1341# Base class for enum types. 1342class Enum(ParamValue): 1343 __metaclass__ = MetaEnum 1344 vals = [] 1345 cmd_line_settable = True 1346 1347 # The name of the wrapping namespace or struct 1348 wrapper_name = 'Enums' 1349 1350 # If true, the enum is wrapped in a struct rather than a namespace 1351 wrapper_is_struct = False 1352 1353 # If not None, use this as the enum name rather than this class name 1354 enum_name = None 1355 1356 def __init__(self, value): 1357 if value not in self.map: 1358 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1359 % (value, self.vals) 1360 self.value = value 1361 1362 def __call__(self, value): 1363 self.__init__(value) 1364 return value 1365 1366 @classmethod 1367 def cxx_predecls(cls, code): 1368 code('#include "enums/$0.hh"', cls.__name__) 1369 1370 @classmethod 1371 def cxx_ini_parse(cls, code, src, dest, ret): 1372 code('if (false) {') 1373 for elem_name in cls.map.iterkeys(): 1374 code('} else if (%s == "%s") {' % (src, elem_name)) 1375 code.indent() 1376 code('%s = Enums::%s;' % (dest, elem_name)) 1377 code('%s true;' % ret) 1378 code.dedent() 1379 code('} else {') 1380 code(' %s false;' % ret) 1381 code('}') 1382 1383 def getValue(self): 1384 import m5.internal.params 1385 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1386 return e(self.map[self.value]) 1387 1388 def __str__(self): 1389 return self.value 1390 1391# how big does a rounding error need to be before we warn about it? 1392frequency_tolerance = 0.001 # 0.1% 1393 1394class TickParamValue(NumericParamValue): 1395 cxx_type = 'Tick' 1396 ex_str = "1MHz" 1397 cmd_line_settable = True 1398 1399 @classmethod 1400 def cxx_predecls(cls, code): 1401 code('#include "base/types.hh"') 1402 1403 def __call__(self, value): 1404 self.__init__(value) 1405 return value 1406 1407 def getValue(self): 1408 return long(self.value) 1409 1410 @classmethod 1411 def cxx_ini_predecls(cls, code): 1412 code('#include <sstream>') 1413 1414 # Ticks are expressed in seconds in JSON files and in plain 1415 # Ticks in .ini files. Switch based on a config flag 1416 @classmethod 1417 def cxx_ini_parse(self, code, src, dest, ret): 1418 code('${ret} to_number(${src}, ${dest});') 1419 1420class Latency(TickParamValue): 1421 ex_str = "100ns" 1422 1423 def __init__(self, value): 1424 if isinstance(value, (Latency, Clock)): 1425 self.ticks = value.ticks 1426 self.value = value.value 1427 elif isinstance(value, Frequency): 1428 self.ticks = value.ticks 1429 self.value = 1.0 / value.value 1430 elif value.endswith('t'): 1431 self.ticks = True 1432 self.value = int(value[:-1]) 1433 else: 1434 self.ticks = False 1435 self.value = convert.toLatency(value) 1436 1437 def __call__(self, value): 1438 self.__init__(value) 1439 return value 1440 1441 def __getattr__(self, attr): 1442 if attr in ('latency', 'period'): 1443 return self 1444 if attr == 'frequency': 1445 return Frequency(self) 1446 raise AttributeError, "Latency object has no attribute '%s'" % attr 1447 1448 def getValue(self): 1449 if self.ticks or self.value == 0: 1450 value = self.value 1451 else: 1452 value = ticks.fromSeconds(self.value) 1453 return long(value) 1454 1455 def config_value(self): 1456 return self.getValue() 1457 1458 # convert latency to ticks 1459 def ini_str(self): 1460 return '%d' % self.getValue() 1461 1462class Frequency(TickParamValue): 1463 ex_str = "1GHz" 1464 1465 def __init__(self, value): 1466 if isinstance(value, (Latency, Clock)): 1467 if value.value == 0: 1468 self.value = 0 1469 else: 1470 self.value = 1.0 / value.value 1471 self.ticks = value.ticks 1472 elif isinstance(value, Frequency): 1473 self.value = value.value 1474 self.ticks = value.ticks 1475 else: 1476 self.ticks = False 1477 self.value = convert.toFrequency(value) 1478 1479 def __call__(self, value): 1480 self.__init__(value) 1481 return value 1482 1483 def __getattr__(self, attr): 1484 if attr == 'frequency': 1485 return self 1486 if attr in ('latency', 'period'): 1487 return Latency(self) 1488 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1489 1490 # convert latency to ticks 1491 def getValue(self): 1492 if self.ticks or self.value == 0: 1493 value = self.value 1494 else: 1495 value = ticks.fromSeconds(1.0 / self.value) 1496 return long(value) 1497 1498 def config_value(self): 1499 return self.getValue() 1500 1501 def ini_str(self): 1502 return '%d' % self.getValue() 1503 1504# A generic Frequency and/or Latency value. Value is stored as a 1505# latency, just like Latency and Frequency. 1506class Clock(TickParamValue): 1507 def __init__(self, value): 1508 if isinstance(value, (Latency, Clock)): 1509 self.ticks = value.ticks 1510 self.value = value.value 1511 elif isinstance(value, Frequency): 1512 self.ticks = value.ticks 1513 self.value = 1.0 / value.value 1514 elif value.endswith('t'): 1515 self.ticks = True 1516 self.value = int(value[:-1]) 1517 else: 1518 self.ticks = False 1519 self.value = convert.anyToLatency(value) 1520 1521 def __call__(self, value): 1522 self.__init__(value) 1523 return value 1524 1525 def __str__(self): 1526 return "%s" % Latency(self) 1527 1528 def __getattr__(self, attr): 1529 if attr == 'frequency': 1530 return Frequency(self) 1531 if attr in ('latency', 'period'): 1532 return Latency(self) 1533 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1534 1535 def getValue(self): 1536 return self.period.getValue() 1537 1538 def config_value(self): 1539 return self.period.config_value() 1540 1541 def ini_str(self): 1542 return self.period.ini_str() 1543 1544class Voltage(float,ParamValue): 1545 cxx_type = 'double' 1546 ex_str = "1V" 1547 cmd_line_settable = True 1548 1549 def __new__(cls, value): 1550 # convert to voltage 1551 val = convert.toVoltage(value) 1552 return super(cls, Voltage).__new__(cls, val) 1553 1554 def __call__(self, value): 1555 val = convert.toVoltage(value) 1556 self.__init__(val) 1557 return value 1558 1559 def __str__(self): 1560 return str(self.getValue()) 1561 1562 def getValue(self): 1563 value = float(self) 1564 return value 1565 1566 def ini_str(self): 1567 return '%f' % self.getValue() 1568 1569 @classmethod 1570 def cxx_ini_predecls(cls, code): 1571 code('#include <sstream>') 1572 1573 @classmethod 1574 def cxx_ini_parse(self, code, src, dest, ret): 1575 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1576 1577class Current(float, ParamValue): 1578 cxx_type = 'double' 1579 ex_str = "1mA" 1580 cmd_line_settable = False 1581 1582 def __new__(cls, value): 1583 # convert to current 1584 val = convert.toCurrent(value) 1585 return super(cls, Current).__new__(cls, val) 1586 1587 def __call__(self, value): 1588 val = convert.toCurrent(value) 1589 self.__init__(val) 1590 return value 1591 1592 def __str__(self): 1593 return str(self.getValue()) 1594 1595 def getValue(self): 1596 value = float(self) 1597 return value 1598 1599 def ini_str(self): 1600 return '%f' % self.getValue() 1601 1602 @classmethod 1603 def cxx_ini_predecls(cls, code): 1604 code('#include <sstream>') 1605 1606 @classmethod 1607 def cxx_ini_parse(self, code, src, dest, ret): 1608 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1609 1610class NetworkBandwidth(float,ParamValue): 1611 cxx_type = 'float' 1612 ex_str = "1Gbps" 1613 cmd_line_settable = True 1614 1615 def __new__(cls, value): 1616 # convert to bits per second 1617 val = convert.toNetworkBandwidth(value) 1618 return super(cls, NetworkBandwidth).__new__(cls, val) 1619 1620 def __str__(self): 1621 return str(self.val) 1622 1623 def __call__(self, value): 1624 val = convert.toNetworkBandwidth(value) 1625 self.__init__(val) 1626 return value 1627 1628 def getValue(self): 1629 # convert to seconds per byte 1630 value = 8.0 / float(self) 1631 # convert to ticks per byte 1632 value = ticks.fromSeconds(value) 1633 return float(value) 1634 1635 def ini_str(self): 1636 return '%f' % self.getValue() 1637 1638 def config_value(self): 1639 return '%f' % self.getValue() 1640 1641 @classmethod 1642 def cxx_ini_predecls(cls, code): 1643 code('#include <sstream>') 1644 1645 @classmethod 1646 def cxx_ini_parse(self, code, src, dest, ret): 1647 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1648 1649class MemoryBandwidth(float,ParamValue): 1650 cxx_type = 'float' 1651 ex_str = "1GB/s" 1652 cmd_line_settable = True 1653 1654 def __new__(cls, value): 1655 # convert to bytes per second 1656 val = convert.toMemoryBandwidth(value) 1657 return super(cls, MemoryBandwidth).__new__(cls, val) 1658 1659 def __call__(self, value): 1660 val = convert.toMemoryBandwidth(value) 1661 self.__init__(val) 1662 return value 1663 1664 def getValue(self): 1665 # convert to seconds per byte 1666 value = float(self) 1667 if value: 1668 value = 1.0 / float(self) 1669 # convert to ticks per byte 1670 value = ticks.fromSeconds(value) 1671 return float(value) 1672 1673 def ini_str(self): 1674 return '%f' % self.getValue() 1675 1676 def config_value(self): 1677 return '%f' % self.getValue() 1678 1679 @classmethod 1680 def cxx_ini_predecls(cls, code): 1681 code('#include <sstream>') 1682 1683 @classmethod 1684 def cxx_ini_parse(self, code, src, dest, ret): 1685 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1686 1687# 1688# "Constants"... handy aliases for various values. 1689# 1690 1691# Special class for NULL pointers. Note the special check in 1692# make_param_value() above that lets these be assigned where a 1693# SimObject is required. 1694# only one copy of a particular node 1695class NullSimObject(object): 1696 __metaclass__ = Singleton 1697 1698 def __call__(cls): 1699 return cls 1700 1701 def _instantiate(self, parent = None, path = ''): 1702 pass 1703 1704 def ini_str(self): 1705 return 'Null' 1706 1707 def unproxy(self, base): 1708 return self 1709 1710 def set_path(self, parent, name): 1711 pass 1712 1713 def set_parent(self, parent, name): 1714 pass 1715 1716 def __str__(self): 1717 return 'Null' 1718 1719 def config_value(self): 1720 return None 1721 1722 def getValue(self): 1723 return None 1724 1725# The only instance you'll ever need... 1726NULL = NullSimObject() 1727 1728def isNullPointer(value): 1729 return isinstance(value, NullSimObject) 1730 1731# Some memory range specifications use this as a default upper bound. 1732MaxAddr = Addr.max 1733MaxTick = Tick.max 1734AllMemory = AddrRange(0, MaxAddr) 1735 1736 1737##################################################################### 1738# 1739# Port objects 1740# 1741# Ports are used to interconnect objects in the memory system. 1742# 1743##################################################################### 1744 1745# Port reference: encapsulates a reference to a particular port on a 1746# particular SimObject. 1747class PortRef(object): 1748 def __init__(self, simobj, name, role): 1749 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1750 self.simobj = simobj 1751 self.name = name 1752 self.role = role 1753 self.peer = None # not associated with another port yet 1754 self.ccConnected = False # C++ port connection done? 1755 self.index = -1 # always -1 for non-vector ports 1756 1757 def __str__(self): 1758 return '%s.%s' % (self.simobj, self.name) 1759 1760 def __len__(self): 1761 # Return the number of connected ports, i.e. 0 is we have no 1762 # peer and 1 if we do. 1763 return int(self.peer != None) 1764 1765 # for config.ini, print peer's name (not ours) 1766 def ini_str(self): 1767 return str(self.peer) 1768 1769 # for config.json 1770 def get_config_as_dict(self): 1771 return {'role' : self.role, 'peer' : str(self.peer)} 1772 1773 def __getattr__(self, attr): 1774 if attr == 'peerObj': 1775 # shorthand for proxies 1776 return self.peer.simobj 1777 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1778 (self.__class__.__name__, attr) 1779 1780 # Full connection is symmetric (both ways). Called via 1781 # SimObject.__setattr__ as a result of a port assignment, e.g., 1782 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1783 # e.g., "obj1.portA[3] = obj2.portB". 1784 def connect(self, other): 1785 if isinstance(other, VectorPortRef): 1786 # reference to plain VectorPort is implicit append 1787 other = other._get_next() 1788 if self.peer and not proxy.isproxy(self.peer): 1789 fatal("Port %s is already connected to %s, cannot connect %s\n", 1790 self, self.peer, other); 1791 self.peer = other 1792 if proxy.isproxy(other): 1793 other.set_param_desc(PortParamDesc()) 1794 elif isinstance(other, PortRef): 1795 if other.peer is not self: 1796 other.connect(self) 1797 else: 1798 raise TypeError, \ 1799 "assigning non-port reference '%s' to port '%s'" \ 1800 % (other, self) 1801 1802 # Allow a master/slave port pair to be spliced between 1803 # a port and its connected peer. Useful operation for connecting 1804 # instrumentation structures into a system when it is necessary 1805 # to connect the instrumentation after the full system has been 1806 # constructed. 1807 def splice(self, new_master_peer, new_slave_peer): 1808 if self.peer and not proxy.isproxy(self.peer): 1809 if isinstance(new_master_peer, PortRef) and \ 1810 isinstance(new_slave_peer, PortRef): 1811 old_peer = self.peer 1812 if self.role == 'SLAVE': 1813 self.peer = new_master_peer 1814 old_peer.peer = new_slave_peer 1815 new_master_peer.connect(self) 1816 new_slave_peer.connect(old_peer) 1817 elif self.role == 'MASTER': 1818 self.peer = new_slave_peer 1819 old_peer.peer = new_master_peer 1820 new_slave_peer.connect(self) 1821 new_master_peer.connect(old_peer) 1822 else: 1823 panic("Port %s has unknown role, "+\ 1824 "cannot splice in new peers\n", self) 1825 else: 1826 raise TypeError, \ 1827 "Splicing non-port references '%s','%s' to port '%s'"\ 1828 % (new_peer, peers_new_peer, self) 1829 else: 1830 fatal("Port %s not connected, cannot splice in new peers\n", self) 1831 1832 def clone(self, simobj, memo): 1833 if memo.has_key(self): 1834 return memo[self] 1835 newRef = copy.copy(self) 1836 memo[self] = newRef 1837 newRef.simobj = simobj 1838 assert(isSimObject(newRef.simobj)) 1839 if self.peer and not proxy.isproxy(self.peer): 1840 peerObj = self.peer.simobj(_memo=memo) 1841 newRef.peer = self.peer.clone(peerObj, memo) 1842 assert(not isinstance(newRef.peer, VectorPortRef)) 1843 return newRef 1844 1845 def unproxy(self, simobj): 1846 assert(simobj is self.simobj) 1847 if proxy.isproxy(self.peer): 1848 try: 1849 realPeer = self.peer.unproxy(self.simobj) 1850 except: 1851 print "Error in unproxying port '%s' of %s" % \ 1852 (self.name, self.simobj.path()) 1853 raise 1854 self.connect(realPeer) 1855 1856 # Call C++ to create corresponding port connection between C++ objects 1857 def ccConnect(self): 1858 from _m5.pyobject import connectPorts 1859 1860 if self.role == 'SLAVE': 1861 # do nothing and let the master take care of it 1862 return 1863 1864 if self.ccConnected: # already done this 1865 return 1866 peer = self.peer 1867 if not self.peer: # nothing to connect to 1868 return 1869 1870 # check that we connect a master to a slave 1871 if self.role == peer.role: 1872 raise TypeError, \ 1873 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1874 % (peer, self, self.role) 1875 1876 try: 1877 # self is always the master and peer the slave 1878 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1879 peer.simobj.getCCObject(), peer.name, peer.index) 1880 except: 1881 print "Error connecting port %s.%s to %s.%s" % \ 1882 (self.simobj.path(), self.name, 1883 peer.simobj.path(), peer.name) 1884 raise 1885 self.ccConnected = True 1886 peer.ccConnected = True 1887 1888# A reference to an individual element of a VectorPort... much like a 1889# PortRef, but has an index. 1890class VectorPortElementRef(PortRef): 1891 def __init__(self, simobj, name, role, index): 1892 PortRef.__init__(self, simobj, name, role) 1893 self.index = index 1894 1895 def __str__(self): 1896 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1897 1898# A reference to a complete vector-valued port (not just a single element). 1899# Can be indexed to retrieve individual VectorPortElementRef instances. 1900class VectorPortRef(object): 1901 def __init__(self, simobj, name, role): 1902 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1903 self.simobj = simobj 1904 self.name = name 1905 self.role = role 1906 self.elements = [] 1907 1908 def __str__(self): 1909 return '%s.%s[:]' % (self.simobj, self.name) 1910 1911 def __len__(self): 1912 # Return the number of connected peers, corresponding the the 1913 # length of the elements. 1914 return len(self.elements) 1915 1916 # for config.ini, print peer's name (not ours) 1917 def ini_str(self): 1918 return ' '.join([el.ini_str() for el in self.elements]) 1919 1920 # for config.json 1921 def get_config_as_dict(self): 1922 return {'role' : self.role, 1923 'peer' : [el.ini_str() for el in self.elements]} 1924 1925 def __getitem__(self, key): 1926 if not isinstance(key, int): 1927 raise TypeError, "VectorPort index must be integer" 1928 if key >= len(self.elements): 1929 # need to extend list 1930 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1931 for i in range(len(self.elements), key+1)] 1932 self.elements.extend(ext) 1933 return self.elements[key] 1934 1935 def _get_next(self): 1936 return self[len(self.elements)] 1937 1938 def __setitem__(self, key, value): 1939 if not isinstance(key, int): 1940 raise TypeError, "VectorPort index must be integer" 1941 self[key].connect(value) 1942 1943 def connect(self, other): 1944 if isinstance(other, (list, tuple)): 1945 # Assign list of port refs to vector port. 1946 # For now, append them... not sure if that's the right semantics 1947 # or if it should replace the current vector. 1948 for ref in other: 1949 self._get_next().connect(ref) 1950 else: 1951 # scalar assignment to plain VectorPort is implicit append 1952 self._get_next().connect(other) 1953 1954 def clone(self, simobj, memo): 1955 if memo.has_key(self): 1956 return memo[self] 1957 newRef = copy.copy(self) 1958 memo[self] = newRef 1959 newRef.simobj = simobj 1960 assert(isSimObject(newRef.simobj)) 1961 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1962 return newRef 1963 1964 def unproxy(self, simobj): 1965 [el.unproxy(simobj) for el in self.elements] 1966 1967 def ccConnect(self): 1968 [el.ccConnect() for el in self.elements] 1969 1970# Port description object. Like a ParamDesc object, this represents a 1971# logical port in the SimObject class, not a particular port on a 1972# SimObject instance. The latter are represented by PortRef objects. 1973class Port(object): 1974 # Generate a PortRef for this port on the given SimObject with the 1975 # given name 1976 def makeRef(self, simobj): 1977 return PortRef(simobj, self.name, self.role) 1978 1979 # Connect an instance of this port (on the given SimObject with 1980 # the given name) with the port described by the supplied PortRef 1981 def connect(self, simobj, ref): 1982 self.makeRef(simobj).connect(ref) 1983 1984 # No need for any pre-declarations at the moment as we merely rely 1985 # on an unsigned int. 1986 def cxx_predecls(self, code): 1987 pass 1988 1989 def pybind_predecls(self, code): 1990 cls.cxx_predecls(self, code) 1991 1992 # Declare an unsigned int with the same name as the port, that 1993 # will eventually hold the number of connected ports (and thus the 1994 # number of elements for a VectorPort). 1995 def cxx_decl(self, code): 1996 code('unsigned int port_${{self.name}}_connection_count;') 1997 1998class MasterPort(Port): 1999 # MasterPort("description") 2000 def __init__(self, *args): 2001 if len(args) == 1: 2002 self.desc = args[0] 2003 self.role = 'MASTER' 2004 else: 2005 raise TypeError, 'wrong number of arguments' 2006 2007class SlavePort(Port): 2008 # SlavePort("description") 2009 def __init__(self, *args): 2010 if len(args) == 1: 2011 self.desc = args[0] 2012 self.role = 'SLAVE' 2013 else: 2014 raise TypeError, 'wrong number of arguments' 2015 2016# VectorPort description object. Like Port, but represents a vector 2017# of connections (e.g., as on a XBar). 2018class VectorPort(Port): 2019 def __init__(self, *args): 2020 self.isVec = True 2021 2022 def makeRef(self, simobj): 2023 return VectorPortRef(simobj, self.name, self.role) 2024 2025class VectorMasterPort(VectorPort): 2026 # VectorMasterPort("description") 2027 def __init__(self, *args): 2028 if len(args) == 1: 2029 self.desc = args[0] 2030 self.role = 'MASTER' 2031 VectorPort.__init__(self, *args) 2032 else: 2033 raise TypeError, 'wrong number of arguments' 2034 2035class VectorSlavePort(VectorPort): 2036 # VectorSlavePort("description") 2037 def __init__(self, *args): 2038 if len(args) == 1: 2039 self.desc = args[0] 2040 self.role = 'SLAVE' 2041 VectorPort.__init__(self, *args) 2042 else: 2043 raise TypeError, 'wrong number of arguments' 2044 2045# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2046# proxy objects (via set_param_desc()) so that proxy error messages 2047# make sense. 2048class PortParamDesc(object): 2049 __metaclass__ = Singleton 2050 2051 ptype_str = 'Port' 2052 ptype = Port 2053 2054baseEnums = allEnums.copy() 2055baseParams = allParams.copy() 2056 2057def clear(): 2058 global allEnums, allParams 2059 2060 allEnums = baseEnums.copy() 2061 allParams = baseParams.copy() 2062 2063__all__ = ['Param', 'VectorParam', 2064 'Enum', 'Bool', 'String', 'Float', 2065 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2066 'Int32', 'UInt32', 'Int64', 'UInt64', 2067 'Counter', 'Addr', 'Tick', 'Percent', 2068 'TcpPort', 'UdpPort', 'EthernetAddr', 2069 'IpAddress', 'IpNetmask', 'IpWithPort', 2070 'MemorySize', 'MemorySize32', 2071 'Latency', 'Frequency', 'Clock', 'Voltage', 2072 'NetworkBandwidth', 'MemoryBandwidth', 2073 'AddrRange', 2074 'MaxAddr', 'MaxTick', 'AllMemory', 2075 'Time', 2076 'NextEthernetAddr', 'NULL', 2077 'MasterPort', 'SlavePort', 2078 'VectorMasterPort', 'VectorSlavePort'] 2079 2080import SimObject
|