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