1# Copyright (c) 2004-2006 The Regents of The University of Michigan 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the 10# documentation and/or other materials provided with the distribution; 11# neither the name of the copyright holders nor the names of its 12# contributors may be used to endorse or promote products derived from 13# this software without specific prior written permission. 14# 15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26# 27# Authors: Steve Reinhardt 28# Nathan Binkert 29 30##################################################################### 31# 32# Parameter description classes 33# 34# The _params dictionary in each class maps parameter names to either 35# a Param or a VectorParam object. These objects contain the 36# parameter description string, the parameter type, and the default 37# value (if any). The convert() method on these objects is used to 38# force whatever value is assigned to the parameter to the appropriate 39# type. 40# 41# Note that the default values are loaded into the class's attribute 42# space when the parameter dictionary is initialized (in 43# MetaSimObject._new_param()); after that point they aren't used. 44# 45##################################################################### 46 47import copy 48import datetime 49import inspect 50import sys 51import time 52 53import convert
|
54import ticks |
55from util import * 56 57# Dummy base class to identify types that are legitimate for SimObject 58# parameters. 59class ParamValue(object): 60 61 cxx_predecls = [] 62 swig_predecls = [] 63 64 # default for printing to .ini file is regular string conversion. 65 # will be overridden in some cases 66 def ini_str(self): 67 return str(self) 68 69 # allows us to blithely call unproxy() on things without checking 70 # if they're really proxies or not 71 def unproxy(self, base): 72 return self 73 74# Regular parameter description. 75class ParamDesc(object): 76 def __init__(self, ptype_str, ptype, *args, **kwargs): 77 self.ptype_str = ptype_str 78 # remember ptype only if it is provided 79 if ptype != None: 80 self.ptype = ptype 81 82 if args: 83 if len(args) == 1: 84 self.desc = args[0] 85 elif len(args) == 2: 86 self.default = args[0] 87 self.desc = args[1] 88 else: 89 raise TypeError, 'too many arguments' 90 91 if kwargs.has_key('desc'): 92 assert(not hasattr(self, 'desc')) 93 self.desc = kwargs['desc'] 94 del kwargs['desc'] 95 96 if kwargs.has_key('default'): 97 assert(not hasattr(self, 'default')) 98 self.default = kwargs['default'] 99 del kwargs['default'] 100 101 if kwargs: 102 raise TypeError, 'extra unknown kwargs %s' % kwargs 103 104 if not hasattr(self, 'desc'): 105 raise TypeError, 'desc attribute missing' 106 107 def __getattr__(self, attr): 108 if attr == 'ptype': 109 try: 110 ptype = eval(self.ptype_str, objects.__dict__) 111 if not isinstance(ptype, type): 112 raise NameError 113 self.ptype = ptype 114 return ptype 115 except NameError: 116 raise TypeError, \ 117 "Param qualifier '%s' is not a type" % self.ptype_str 118 raise AttributeError, "'%s' object has no attribute '%s'" % \ 119 (type(self).__name__, attr) 120 121 def convert(self, value): 122 if isinstance(value, proxy.BaseProxy): 123 value.set_param_desc(self) 124 return value 125 if not hasattr(self, 'ptype') and isNullPointer(value): 126 # deferred evaluation of SimObject; continue to defer if 127 # we're just assigning a null pointer 128 return value 129 if isinstance(value, self.ptype): 130 return value 131 if isNullPointer(value) and isSimObjectClass(self.ptype): 132 return value 133 return self.ptype(value) 134 135 def cxx_predecls(self): 136 return self.ptype.cxx_predecls 137 138 def swig_predecls(self): 139 return self.ptype.swig_predecls 140 141 def cxx_decl(self): 142 return '%s %s;' % (self.ptype.cxx_type, self.name) 143 144# Vector-valued parameter description. Just like ParamDesc, except 145# that the value is a vector (list) of the specified type instead of a 146# single value. 147 148class VectorParamValue(list): 149 def ini_str(self): 150 return ' '.join([v.ini_str() for v in self]) 151 152 def unproxy(self, base): 153 return [v.unproxy(base) for v in self] 154 155class SimObjVector(VectorParamValue): 156 def print_ini(self): 157 for v in self: 158 v.print_ini() 159 160class VectorParamDesc(ParamDesc): 161 # Convert assigned value to appropriate type. If the RHS is not a 162 # list or tuple, it generates a single-element list. 163 def convert(self, value): 164 if isinstance(value, (list, tuple)): 165 # list: coerce each element into new list 166 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 167 if isSimObjectSequence(tmp_list): 168 return SimObjVector(tmp_list) 169 else: 170 return VectorParamValue(tmp_list) 171 else: 172 # singleton: leave it be (could coerce to a single-element 173 # list here, but for some historical reason we don't... 174 return ParamDesc.convert(self, value) 175 176 def cxx_predecls(self): 177 return ['#include <vector>'] + self.ptype.cxx_predecls 178 179 def swig_predecls(self): 180 return ['%include "std_vector.i"'] + self.ptype.swig_predecls 181 182 def cxx_decl(self): 183 return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name) 184 185class ParamFactory(object): 186 def __init__(self, param_desc_class, ptype_str = None): 187 self.param_desc_class = param_desc_class 188 self.ptype_str = ptype_str 189 190 def __getattr__(self, attr): 191 if self.ptype_str: 192 attr = self.ptype_str + '.' + attr 193 return ParamFactory(self.param_desc_class, attr) 194 195 # E.g., Param.Int(5, "number of widgets") 196 def __call__(self, *args, **kwargs): 197 caller_frame = inspect.currentframe().f_back 198 ptype = None 199 try: 200 ptype = eval(self.ptype_str, 201 caller_frame.f_globals, caller_frame.f_locals) 202 if not isinstance(ptype, type): 203 raise TypeError, \ 204 "Param qualifier is not a type: %s" % ptype 205 except NameError: 206 # if name isn't defined yet, assume it's a SimObject, and 207 # try to resolve it later 208 pass 209 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 210 211Param = ParamFactory(ParamDesc) 212VectorParam = ParamFactory(VectorParamDesc) 213 214##################################################################### 215# 216# Parameter Types 217# 218# Though native Python types could be used to specify parameter types 219# (the 'ptype' field of the Param and VectorParam classes), it's more 220# flexible to define our own set of types. This gives us more control 221# over how Python expressions are converted to values (via the 222# __init__() constructor) and how these values are printed out (via 223# the __str__() conversion method). 224# 225##################################################################### 226 227# String-valued parameter. Just mixin the ParamValue class with the 228# built-in str class. 229class String(ParamValue,str): 230 cxx_type = 'std::string' 231 cxx_predecls = ['#include <string>'] 232 swig_predecls = ['%include "std_string.i"\n' + 233 '%apply const std::string& {std::string *};'] 234 pass 235 236# superclass for "numeric" parameter values, to emulate math 237# operations in a type-safe way. e.g., a Latency times an int returns 238# a new Latency object. 239class NumericParamValue(ParamValue): 240 def __str__(self): 241 return str(self.value) 242 243 def __float__(self): 244 return float(self.value) 245 246 def __long__(self): 247 return long(self.value) 248 249 def __int__(self): 250 return int(self.value) 251 252 # hook for bounds checking 253 def _check(self): 254 return 255 256 def __mul__(self, other): 257 newobj = self.__class__(self) 258 newobj.value *= other 259 newobj._check() 260 return newobj 261 262 __rmul__ = __mul__ 263 264 def __div__(self, other): 265 newobj = self.__class__(self) 266 newobj.value /= other 267 newobj._check() 268 return newobj 269 270 def __sub__(self, other): 271 newobj = self.__class__(self) 272 newobj.value -= other 273 newobj._check() 274 return newobj 275 276# Metaclass for bounds-checked integer parameters. See CheckedInt. 277class CheckedIntType(type): 278 def __init__(cls, name, bases, dict): 279 super(CheckedIntType, cls).__init__(name, bases, dict) 280 281 # CheckedInt is an abstract base class, so we actually don't 282 # want to do any processing on it... the rest of this code is 283 # just for classes that derive from CheckedInt. 284 if name == 'CheckedInt': 285 return 286 287 if not cls.cxx_predecls: 288 # most derived types require this, so we just do it here once 289 cls.cxx_predecls = ['#include "sim/host.hh"'] 290 291 if not cls.swig_predecls: 292 # most derived types require this, so we just do it here once 293 cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 294 '%import "sim/host.hh"'] 295 296 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 297 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 298 panic("CheckedInt subclass %s must define either\n" \ 299 " 'min' and 'max' or 'size' and 'unsigned'\n" \ 300 % name); 301 if cls.unsigned: 302 cls.min = 0 303 cls.max = 2 ** cls.size - 1 304 else: 305 cls.min = -(2 ** (cls.size - 1)) 306 cls.max = (2 ** (cls.size - 1)) - 1 307 308# Abstract superclass for bounds-checked integer parameters. This 309# class is subclassed to generate parameter classes with specific 310# bounds. Initialization of the min and max bounds is done in the 311# metaclass CheckedIntType.__init__. 312class CheckedInt(NumericParamValue): 313 __metaclass__ = CheckedIntType 314 315 def _check(self): 316 if not self.min <= self.value <= self.max: 317 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 318 (self.min, self.value, self.max) 319 320 def __init__(self, value): 321 if isinstance(value, str): 322 self.value = convert.toInteger(value) 323 elif isinstance(value, (int, long, float, NumericParamValue)): 324 self.value = long(value) 325 else: 326 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 327 % type(value).__name__ 328 self._check() 329 330class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 331class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 332 333class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 334class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 335class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 336class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 337class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 338class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 339class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 340class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 341 342class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 343class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 344class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 345class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 346 347class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 348 349class Float(ParamValue, float): 350 pass 351 352class MemorySize(CheckedInt): 353 cxx_type = 'uint64_t' 354 size = 64 355 unsigned = True 356 def __init__(self, value): 357 if isinstance(value, MemorySize): 358 self.value = value.value 359 else: 360 self.value = convert.toMemorySize(value) 361 self._check() 362 363class MemorySize32(CheckedInt): 364 size = 32 365 unsigned = True 366 def __init__(self, value): 367 if isinstance(value, MemorySize): 368 self.value = value.value 369 else: 370 self.value = convert.toMemorySize(value) 371 self._check() 372 373class Addr(CheckedInt): 374 cxx_type = 'Addr' 375 cxx_predecls = ['#include "targetarch/isa_traits.hh"'] 376 size = 64 377 unsigned = True 378 def __init__(self, value): 379 if isinstance(value, Addr): 380 self.value = value.value 381 else: 382 try: 383 self.value = convert.toMemorySize(value) 384 except TypeError: 385 self.value = long(value) 386 self._check() 387 def __add__(self, other): 388 if isinstance(other, Addr): 389 return self.value + other.value 390 else: 391 return self.value + other 392 393 394class MetaRange(type): 395 def __init__(cls, name, bases, dict): 396 super(MetaRange, cls).__init__(name, bases, dict) 397 if name == 'Range': 398 return 399 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type 400 cls.cxx_predecls = \ 401 ['#include "base/range.hh"'] + cls.type.cxx_predecls 402 403class Range(ParamValue): 404 __metaclass__ = MetaRange 405 type = Int # default; can be overridden in subclasses 406 def __init__(self, *args, **kwargs): 407 def handle_kwargs(self, kwargs): 408 if 'end' in kwargs: 409 self.second = self.type(kwargs.pop('end')) 410 elif 'size' in kwargs: 411 self.second = self.first + self.type(kwargs.pop('size')) - 1 412 else: 413 raise TypeError, "Either end or size must be specified" 414 415 if len(args) == 0: 416 self.first = self.type(kwargs.pop('start')) 417 handle_kwargs(self, kwargs) 418 419 elif len(args) == 1: 420 if kwargs: 421 self.first = self.type(args[0]) 422 handle_kwargs(self, kwargs) 423 elif isinstance(args[0], Range): 424 self.first = self.type(args[0].first) 425 self.second = self.type(args[0].second) 426 else: 427 self.first = self.type(0) 428 self.second = self.type(args[0]) - 1 429 430 elif len(args) == 2: 431 self.first = self.type(args[0]) 432 self.second = self.type(args[1]) 433 else: 434 raise TypeError, "Too many arguments specified" 435 436 if kwargs: 437 raise TypeError, "too many keywords: %s" % kwargs.keys() 438 439 def __str__(self): 440 return '%s:%s' % (self.first, self.second) 441 442class AddrRange(Range): 443 type = Addr 444 445class TickRange(Range): 446 type = Tick 447 448# Boolean parameter type. Python doesn't let you subclass bool, since 449# it doesn't want to let you create multiple instances of True and 450# False. Thus this is a little more complicated than String. 451class Bool(ParamValue): 452 cxx_type = 'bool' 453 def __init__(self, value): 454 try: 455 self.value = convert.toBool(value) 456 except TypeError: 457 self.value = bool(value) 458 459 def __str__(self): 460 return str(self.value) 461 462 def ini_str(self): 463 if self.value: 464 return 'true' 465 return 'false' 466 467def IncEthernetAddr(addr, val = 1): 468 bytes = map(lambda x: int(x, 16), addr.split(':')) 469 bytes[5] += val 470 for i in (5, 4, 3, 2, 1): 471 val,rem = divmod(bytes[i], 256) 472 bytes[i] = rem 473 if val == 0: 474 break 475 bytes[i - 1] += val 476 assert(bytes[0] <= 255) 477 return ':'.join(map(lambda x: '%02x' % x, bytes)) 478 479class NextEthernetAddr(object): 480 addr = "00:90:00:00:00:01" 481 482 def __init__(self, inc = 1): 483 self.value = NextEthernetAddr.addr 484 NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) 485 486class EthernetAddr(ParamValue): 487 cxx_type = 'Net::EthAddr' 488 cxx_predecls = ['#include "base/inet.hh"'] 489 swig_predecls = ['class Net::EthAddr;'] 490 def __init__(self, value): 491 if value == NextEthernetAddr: 492 self.value = value 493 return 494 495 if not isinstance(value, str): 496 raise TypeError, "expected an ethernet address and didn't get one" 497 498 bytes = value.split(':') 499 if len(bytes) != 6: 500 raise TypeError, 'invalid ethernet address %s' % value 501 502 for byte in bytes: 503 if not 0 <= int(byte) <= 256: 504 raise TypeError, 'invalid ethernet address %s' % value 505 506 self.value = value 507 508 def unproxy(self, base): 509 if self.value == NextEthernetAddr: 510 self.addr = self.value().value 511 return self 512 513 def __str__(self): 514 if self.value == NextEthernetAddr: 515 if hasattr(self, 'addr'): 516 return self.addr 517 else: 518 return "NextEthernetAddr (unresolved)" 519 else: 520 return self.value 521 522time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 523 "%a %b %d %H:%M:%S %Z %Y", 524 "%Y/%m/%d %H:%M:%S", 525 "%Y/%m/%d %H:%M", 526 "%Y/%m/%d", 527 "%m/%d/%Y %H:%M:%S", 528 "%m/%d/%Y %H:%M", 529 "%m/%d/%Y", 530 "%m/%d/%y %H:%M:%S", 531 "%m/%d/%y %H:%M", 532 "%m/%d/%y"] 533 534 535def parse_time(value): 536 from time import gmtime, strptime, struct_time, time 537 from datetime import datetime, date 538 539 if isinstance(value, struct_time): 540 return value 541 542 if isinstance(value, (int, long)): 543 return gmtime(value) 544 545 if isinstance(value, (datetime, date)): 546 return value.timetuple() 547 548 if isinstance(value, str): 549 if value in ('Now', 'Today'): 550 return time.gmtime(time.time()) 551 552 for format in time_formats: 553 try: 554 return strptime(value, format) 555 except ValueError: 556 pass 557 558 raise ValueError, "Could not parse '%s' as a time" % value 559 560class Time(ParamValue): 561 cxx_type = 'time_t' 562 def __init__(self, value): 563 self.value = parse_time(value) 564 565 def __str__(self): 566 tm = self.value 567 return ' '.join([ str(tm[i]) for i in xrange(8)]) 568 569 def ini_str(self): 570 return str(self) 571 572# Enumerated types are a little more complex. The user specifies the 573# type as Enum(foo) where foo is either a list or dictionary of 574# alternatives (typically strings, but not necessarily so). (In the 575# long run, the integer value of the parameter will be the list index 576# or the corresponding dictionary value. For now, since we only check 577# that the alternative is valid and then spit it into a .ini file, 578# there's not much point in using the dictionary.) 579 580# What Enum() must do is generate a new type encapsulating the 581# provided list/dictionary so that specific values of the parameter 582# can be instances of that type. We define two hidden internal 583# classes (_ListEnum and _DictEnum) to serve as base classes, then 584# derive the new type from the appropriate base class on the fly. 585 586 587# Metaclass for Enum types 588class MetaEnum(type): 589 def __init__(cls, name, bases, init_dict): 590 if init_dict.has_key('map'): 591 if not isinstance(cls.map, dict): 592 raise TypeError, "Enum-derived class attribute 'map' " \ 593 "must be of type dict" 594 # build list of value strings from map 595 cls.vals = cls.map.keys() 596 cls.vals.sort() 597 elif init_dict.has_key('vals'): 598 if not isinstance(cls.vals, list): 599 raise TypeError, "Enum-derived class attribute 'vals' " \ 600 "must be of type list" 601 # build string->value map from vals sequence 602 cls.map = {} 603 for idx,val in enumerate(cls.vals): 604 cls.map[val] = idx 605 else: 606 raise TypeError, "Enum-derived class must define "\ 607 "attribute 'map' or 'vals'" 608 609 cls.cxx_type = name + '::Enum' 610 611 super(MetaEnum, cls).__init__(name, bases, init_dict) 612 613 # Generate C++ class declaration for this enum type. 614 # Note that we wrap the enum in a class/struct to act as a namespace, 615 # so that the enum strings can be brief w/o worrying about collisions. 616 def cxx_decl(cls): 617 s = 'struct %s {\n enum Enum {\n ' % cls.__name__ 618 s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) 619 s += '\n };\n};\n' 620 return s 621 622# Base class for enum types. 623class Enum(ParamValue): 624 __metaclass__ = MetaEnum 625 vals = [] 626 627 def __init__(self, value): 628 if value not in self.map: 629 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 630 % (value, self.vals) 631 self.value = value 632 633 def __str__(self): 634 return self.value 635
|
635ticks_per_sec = None
636
|
636# how big does a rounding error need to be before we warn about it? 637frequency_tolerance = 0.001 # 0.1% 638
|
640# convert a floting-point # of ticks to integer, and warn if rounding
641# discards too much precision
642def tick_check(float_ticks):
643 if float_ticks == 0:
644 return 0
645 int_ticks = int(round(float_ticks))
646 err = (float_ticks - int_ticks) / float_ticks
647 if err > frequency_tolerance:
648 print >> sys.stderr, "Warning: rounding error > tolerance"
649 print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks)
650 #raise ValueError
651 return int_ticks
652
653def getLatency(value):
654 if isinstance(value, Latency) or isinstance(value, Clock):
655 return value.value
656 elif isinstance(value, Frequency) or isinstance(value, RootClock):
657 return 1 / value.value
658 elif isinstance(value, str):
659 try:
660 return convert.toLatency(value)
661 except ValueError:
662 try:
663 return 1 / convert.toFrequency(value)
664 except ValueError:
665 pass # fall through
666 raise ValueError, "Invalid Frequency/Latency value '%s'" % value
667
668
669class Latency(NumericParamValue):
|
639class TickParamValue(NumericParamValue): |
640 cxx_type = 'Tick' 641 cxx_predecls = ['#include "sim/host.hh"'] 642 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 643 '%import "sim/host.hh"']
|
644 645class Latency(TickParamValue): |
646 def __init__(self, value):
|
675 self.value = getLatency(value)
|
647 if isinstance(value, (Latency, Clock)): 648 self.ticks = value.ticks 649 self.value = value.value 650 elif isinstance(value, Frequency): 651 self.ticks = value.ticks 652 self.value = 1.0 / value.value 653 elif value.endswith('t'): 654 self.ticks = True 655 self.value = int(value[:-1]) 656 else: 657 self.ticks = False 658 self.value = convert.toLatency(value) |
659 660 def __getattr__(self, attr): 661 if attr in ('latency', 'period'): 662 return self 663 if attr == 'frequency': 664 return Frequency(self) 665 raise AttributeError, "Latency object has no attribute '%s'" % attr 666 667 # convert latency to ticks 668 def ini_str(self):
|
686 return str(tick_check(self.value * ticks_per_sec))
|
669 if self.ticks or self.value == 0: 670 return '%d' % self.value 671 else: 672 return '%d' % (ticks.fromSeconds(self.value)) |
673
|
688class Frequency(NumericParamValue):
689 cxx_type = 'Tick'
690 cxx_predecls = ['#include "sim/host.hh"']
691 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
692 '%import "sim/host.hh"']
|
674class Frequency(TickParamValue): |
675 def __init__(self, value):
|
694 self.value = 1 / getLatency(value)
|
676 if isinstance(value, (Latency, Clock)): 677 if value.value == 0: 678 self.value = 0 679 else: 680 self.value = 1.0 / value.value 681 self.ticks = value.ticks 682 elif isinstance(value, Frequency): 683 self.value = value.value 684 self.ticks = value.ticks 685 else: 686 self.ticks = False 687 self.value = convert.toFrequency(value) |
688 689 def __getattr__(self, attr): 690 if attr == 'frequency': 691 return self 692 if attr in ('latency', 'period'): 693 return Latency(self) 694 raise AttributeError, "Frequency object has no attribute '%s'" % attr 695
|
703 # convert frequency to ticks per period
|
696 # convert latency to ticks |
697 def ini_str(self):
|
705 return self.period.ini_str()
|
698 if self.ticks or self.value == 0: 699 return '%d' % self.value 700 else: 701 return '%d' % (ticks.fromSeconds(1.0 / self.value)) |
702
|
707# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
708# We can't inherit from Frequency because we don't want it to be directly
709# assignable to a regular Frequency parameter.
710class RootClock(ParamValue):
711 cxx_type = 'Tick'
712 cxx_predecls = ['#include "sim/host.hh"']
713 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
714 '%import "sim/host.hh"']
715 def __init__(self, value):
716 self.value = 1 / getLatency(value)
717
718 def __getattr__(self, attr):
719 if attr == 'frequency':
720 return Frequency(self)
721 if attr in ('latency', 'period'):
722 return Latency(self)
723 raise AttributeError, "Frequency object has no attribute '%s'" % attr
724
725 def ini_str(self):
726 return str(tick_check(self.value))
727
|
703# A generic frequency and/or Latency value. Value is stored as a latency, 704# but to avoid ambiguity this object does not support numeric ops (* or /). 705# An explicit conversion to a Latency or Frequency must be made first. 706class Clock(ParamValue): 707 cxx_type = 'Tick' 708 cxx_predecls = ['#include "sim/host.hh"'] 709 swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + 710 '%import "sim/host.hh"'] 711 def __init__(self, value):
|
737 self.value = getLatency(value)
|
712 if isinstance(value, (Latency, Clock)): 713 self.ticks = value.ticks 714 self.value = value.value 715 elif isinstance(value, Frequency): 716 self.ticks = value.ticks 717 self.value = 1.0 / value.value 718 elif value.endswith('t'): 719 self.ticks = True 720 self.value = int(value[:-1]) 721 else: 722 self.ticks = False 723 self.value = convert.anyToLatency(value) |
724 725 def __getattr__(self, attr): 726 if attr == 'frequency': 727 return Frequency(self) 728 if attr in ('latency', 'period'): 729 return Latency(self) 730 raise AttributeError, "Frequency object has no attribute '%s'" % attr 731 732 def ini_str(self): 733 return self.period.ini_str() 734 735class NetworkBandwidth(float,ParamValue): 736 cxx_type = 'float' 737 def __new__(cls, value):
|
752 val = convert.toNetworkBandwidth(value) / 8.0
|
738 # convert to bits per second 739 val = convert.toNetworkBandwidth(value) |
740 return super(cls, NetworkBandwidth).__new__(cls, val) 741 742 def __str__(self): 743 return str(self.val) 744 745 def ini_str(self):
|
759 return '%f' % (ticks_per_sec / float(self))
|
746 # convert to seconds per byte 747 value = 8.0 / float(self) 748 # convert to ticks per byte 749 return '%f' % (ticks.fromSeconds(value)) |
750 751class MemoryBandwidth(float,ParamValue): 752 cxx_type = 'float' 753 def __new__(self, value):
|
754 # we want the number of ticks per byte of data |
755 val = convert.toMemoryBandwidth(value) 756 return super(cls, MemoryBandwidth).__new__(cls, val) 757 758 def __str__(self): 759 return str(self.val) 760 761 def ini_str(self):
|
771 return '%f' % (ticks_per_sec / float(self))
|
762 # convert to seconds per byte 763 value = 1.0 / float(self) 764 # convert to ticks per byte 765 return '%f' % (ticks.fromSeconds(value)) |
766 767# 768# "Constants"... handy aliases for various values. 769# 770 771# Special class for NULL pointers. Note the special check in 772# make_param_value() above that lets these be assigned where a 773# SimObject is required. 774# only one copy of a particular node 775class NullSimObject(object): 776 __metaclass__ = Singleton 777 778 def __call__(cls): 779 return cls 780 781 def _instantiate(self, parent = None, path = ''): 782 pass 783 784 def ini_str(self): 785 return 'Null' 786 787 def unproxy(self, base): 788 return self 789 790 def set_path(self, parent, name): 791 pass 792 def __str__(self): 793 return 'Null' 794 795# The only instance you'll ever need... 796NULL = NullSimObject() 797 798def isNullPointer(value): 799 return isinstance(value, NullSimObject) 800 801# Some memory range specifications use this as a default upper bound. 802MaxAddr = Addr.max 803MaxTick = Tick.max 804AllMemory = AddrRange(0, MaxAddr) 805 806 807##################################################################### 808# 809# Port objects 810# 811# Ports are used to interconnect objects in the memory system. 812# 813##################################################################### 814 815# Port reference: encapsulates a reference to a particular port on a 816# particular SimObject. 817class PortRef(object): 818 def __init__(self, simobj, name): 819 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 820 self.simobj = simobj 821 self.name = name 822 self.peer = None # not associated with another port yet 823 self.ccConnected = False # C++ port connection done? 824 self.index = -1 # always -1 for non-vector ports 825 826 def __str__(self): 827 return '%s.%s' % (self.simobj, self.name) 828 829 # for config.ini, print peer's name (not ours) 830 def ini_str(self): 831 return str(self.peer) 832 833 def __getattr__(self, attr): 834 if attr == 'peerObj': 835 # shorthand for proxies 836 return self.peer.simobj 837 raise AttributeError, "'%s' object has no attribute '%s'" % \ 838 (self.__class__.__name__, attr) 839 840 # Full connection is symmetric (both ways). Called via 841 # SimObject.__setattr__ as a result of a port assignment, e.g., 842 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 843 # e.g., "obj1.portA[3] = obj2.portB". 844 def connect(self, other): 845 if isinstance(other, VectorPortRef): 846 # reference to plain VectorPort is implicit append 847 other = other._get_next() 848 if self.peer and not proxy.isproxy(self.peer): 849 print "warning: overwriting port", self, \ 850 "value", self.peer, "with", other 851 self.peer = other 852 if proxy.isproxy(other): 853 other.set_param_desc(PortParamDesc()) 854 elif isinstance(other, PortRef): 855 if other.peer is not self: 856 other.connect(self) 857 else: 858 raise TypeError, \ 859 "assigning non-port reference '%s' to port '%s'" \ 860 % (other, self) 861 862 def clone(self, simobj, memo): 863 if memo.has_key(self): 864 return memo[self] 865 newRef = copy.copy(self) 866 memo[self] = newRef 867 newRef.simobj = simobj 868 assert(isSimObject(newRef.simobj)) 869 if self.peer and not proxy.isproxy(self.peer): 870 peerObj = self.peer.simobj(_memo=memo) 871 newRef.peer = self.peer.clone(peerObj, memo) 872 assert(not isinstance(newRef.peer, VectorPortRef)) 873 return newRef 874 875 def unproxy(self, simobj): 876 assert(simobj is self.simobj) 877 if proxy.isproxy(self.peer): 878 try: 879 realPeer = self.peer.unproxy(self.simobj) 880 except: 881 print "Error in unproxying port '%s' of %s" % \ 882 (self.name, self.simobj.path()) 883 raise 884 self.connect(realPeer) 885 886 # Call C++ to create corresponding port connection between C++ objects 887 def ccConnect(self): 888 if self.ccConnected: # already done this 889 return 890 peer = self.peer 891 internal.sim_object.connectPorts(self.simobj.getCCObject(), self.name, 892 self.index, peer.simobj.getCCObject(), peer.name, peer.index) 893 self.ccConnected = True 894 peer.ccConnected = True 895 896# A reference to an individual element of a VectorPort... much like a 897# PortRef, but has an index. 898class VectorPortElementRef(PortRef): 899 def __init__(self, simobj, name, index): 900 PortRef.__init__(self, simobj, name) 901 self.index = index 902 903 def __str__(self): 904 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 905 906# A reference to a complete vector-valued port (not just a single element). 907# Can be indexed to retrieve individual VectorPortElementRef instances. 908class VectorPortRef(object): 909 def __init__(self, simobj, name): 910 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 911 self.simobj = simobj 912 self.name = name 913 self.elements = [] 914 915 def __str__(self): 916 return '%s.%s[:]' % (self.simobj, self.name) 917 918 # for config.ini, print peer's name (not ours) 919 def ini_str(self): 920 return ' '.join([el.ini_str() for el in self.elements]) 921 922 def __getitem__(self, key): 923 if not isinstance(key, int): 924 raise TypeError, "VectorPort index must be integer" 925 if key >= len(self.elements): 926 # need to extend list 927 ext = [VectorPortElementRef(self.simobj, self.name, i) 928 for i in range(len(self.elements), key+1)] 929 self.elements.extend(ext) 930 return self.elements[key] 931 932 def _get_next(self): 933 return self[len(self.elements)] 934 935 def __setitem__(self, key, value): 936 if not isinstance(key, int): 937 raise TypeError, "VectorPort index must be integer" 938 self[key].connect(value) 939 940 def connect(self, other): 941 if isinstance(other, (list, tuple)): 942 # Assign list of port refs to vector port. 943 # For now, append them... not sure if that's the right semantics 944 # or if it should replace the current vector. 945 for ref in other: 946 self._get_next().connect(ref) 947 else: 948 # scalar assignment to plain VectorPort is implicit append 949 self._get_next().connect(other) 950 951 def clone(self, simobj, memo): 952 if memo.has_key(self): 953 return memo[self] 954 newRef = copy.copy(self) 955 memo[self] = newRef 956 newRef.simobj = simobj 957 assert(isSimObject(newRef.simobj)) 958 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 959 return newRef 960 961 def unproxy(self, simobj): 962 [el.unproxy(simobj) for el in self.elements] 963 964 def ccConnect(self): 965 [el.ccConnect() for el in self.elements] 966 967# Port description object. Like a ParamDesc object, this represents a 968# logical port in the SimObject class, not a particular port on a 969# SimObject instance. The latter are represented by PortRef objects. 970class Port(object): 971 # Port("description") or Port(default, "description") 972 def __init__(self, *args): 973 if len(args) == 1: 974 self.desc = args[0] 975 elif len(args) == 2: 976 self.default = args[0] 977 self.desc = args[1] 978 else: 979 raise TypeError, 'wrong number of arguments' 980 # self.name is set by SimObject class on assignment 981 # e.g., pio_port = Port("blah") sets self.name to 'pio_port' 982 983 # Generate a PortRef for this port on the given SimObject with the 984 # given name 985 def makeRef(self, simobj): 986 return PortRef(simobj, self.name) 987 988 # Connect an instance of this port (on the given SimObject with 989 # the given name) with the port described by the supplied PortRef 990 def connect(self, simobj, ref): 991 self.makeRef(simobj).connect(ref) 992 993# VectorPort description object. Like Port, but represents a vector 994# of connections (e.g., as on a Bus). 995class VectorPort(Port): 996 def __init__(self, *args): 997 Port.__init__(self, *args) 998 self.isVec = True 999 1000 def makeRef(self, simobj): 1001 return VectorPortRef(simobj, self.name) 1002 1003# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1004# proxy objects (via set_param_desc()) so that proxy error messages 1005# make sense. 1006class PortParamDesc(object): 1007 __metaclass__ = Singleton 1008 1009 ptype_str = 'Port' 1010 ptype = Port 1011 1012 1013__all__ = ['Param', 'VectorParam', 1014 'Enum', 'Bool', 'String', 'Float', 1015 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1016 'Int32', 'UInt32', 'Int64', 'UInt64', 1017 'Counter', 'Addr', 'Tick', 'Percent', 1018 'TcpPort', 'UdpPort', 'EthernetAddr', 1019 'MemorySize', 'MemorySize32',
|
1026 'Latency', 'Frequency', 'RootClock', 'Clock',
|
1020 'Latency', 'Frequency', 'Clock', |
1021 'NetworkBandwidth', 'MemoryBandwidth', 1022 'Range', 'AddrRange', 'TickRange', 1023 'MaxAddr', 'MaxTick', 'AllMemory', 1024 'Time', 1025 'NextEthernetAddr', 'NULL', 1026 'Port', 'VectorPort'] 1027 1028# see comment on imports at end of __init__.py. 1029from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass 1030import proxy 1031import objects 1032import internal
|