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