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