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