params.py revision 14059
12567SN/A# Copyright (c) 2012-2014, 2017-2019 ARM Limited 214128Sgiacomo.travaglini@arm.com# All rights reserved. 37585SAli.Saidi@arm.com# 47585SAli.Saidi@arm.com# The license below extends only to copyright in the software and shall 57585SAli.Saidi@arm.com# not be construed as granting a license to any other intellectual 67585SAli.Saidi@arm.com# property including but not limited to intellectual property relating 77585SAli.Saidi@arm.com# to a hardware implementation of the functionality of the software 87585SAli.Saidi@arm.com# licensed hereunder. You may use the software subject to the license 97585SAli.Saidi@arm.com# terms below provided that you ensure that this notice is replicated 107585SAli.Saidi@arm.com# unmodified and in its entirety in all distributions of the software, 117585SAli.Saidi@arm.com# modified or unmodified, in source code or in binary form. 127585SAli.Saidi@arm.com# 137585SAli.Saidi@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 142567SN/A# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 152567SN/A# All rights reserved. 162567SN/A# 172567SN/A# Redistribution and use in source and binary forms, with or without 182567SN/A# modification, are permitted provided that the following conditions are 192567SN/A# met: redistributions of source code must retain the above copyright 202567SN/A# notice, this list of conditions and the following disclaimer; 212567SN/A# redistributions in binary form must reproduce the above copyright 222567SN/A# notice, this list of conditions and the following disclaimer in the 232567SN/A# documentation and/or other materials provided with the distribution; 242567SN/A# neither the name of the copyright holders nor the names of its 252567SN/A# contributors may be used to endorse or promote products derived from 262567SN/A# this software without specific prior written permission. 272567SN/A# 282567SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292567SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302567SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312567SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322567SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332567SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342567SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352567SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362567SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372567SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382567SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A# 402665SN/A# Authors: Steve Reinhardt 412567SN/A# Nathan Binkert 422567SN/A# Gabe Black 4311793Sbrandon.potter@amd.com# Andreas Hansson 4411793Sbrandon.potter@amd.com 458229Snate@binkert.org##################################################################### 468229Snate@binkert.org# 4712531Sandreas.sandberg@arm.com# Parameter description classes 488286SAli.Saidi@ARM.com# 498286SAli.Saidi@ARM.com# The _params dictionary in each class maps parameter names to either 508286SAli.Saidi@ARM.com# a Param or a VectorParam object. These objects contain the 5113531Sjairo.balart@metempsy.com# parameter description string, the parameter type, and the default 5211793Sbrandon.potter@amd.com# value (if any). The convert() method on these objects is used to 538286SAli.Saidi@ARM.com# force whatever value is assigned to the parameter to the appropriate 5410037SARM gem5 Developers# type. 552567SN/A# 567650SAli.Saidi@ARM.com# Note that the default values are loaded into the class's attribute 577650SAli.Saidi@ARM.com# space when the parameter dictionary is initialized (in 582567SN/A# MetaSimObject._new_param()); after that point they aren't used. 596757SAli.Saidi@ARM.com# 6011234Sandreas.sandberg@arm.com##################################################################### 6111234Sandreas.sandberg@arm.com 6211234Sandreas.sandberg@arm.comfrom __future__ import print_function 6310037SARM gem5 Developersimport six 6410037SARM gem5 Developersif six.PY3: 6513173Sgiacomo.travaglini@arm.com long = int 6610537Sandreas.hansson@arm.com 6713531Sjairo.balart@metempsy.comimport copy 6813396Sgiacomo.travaglini@arm.comimport datetime 6913396Sgiacomo.travaglini@arm.comimport re 7013396Sgiacomo.travaglini@arm.comimport sys 7110037SARM gem5 Developersimport time 7210037SARM gem5 Developersimport math 7310037SARM gem5 Developers 7413759Sgiacomo.gabrielli@arm.comfrom . import proxy 7513759Sgiacomo.gabrielli@arm.comfrom . import ticks 7614133Sjordi.vaquero@metempsy.comfrom .util import * 7714128Sgiacomo.travaglini@arm.com 7812005Sandreas.sandberg@arm.comdef isSimObject(*args, **kwargs): 7912005Sandreas.sandberg@arm.com from . import SimObject 8012005Sandreas.sandberg@arm.com return SimObject.isSimObject(*args, **kwargs) 8112531Sandreas.sandberg@arm.com 8210037SARM gem5 Developersdef isSimObjectSequence(*args, **kwargs): 832567SN/A from . import SimObject 8410037SARM gem5 Developers return SimObject.isSimObjectSequence(*args, **kwargs) 8510037SARM gem5 Developers 8610037SARM gem5 Developersdef isSimObjectClass(*args, **kwargs): 8710037SARM gem5 Developers from . import SimObject 8810037SARM gem5 Developers return SimObject.isSimObjectClass(*args, **kwargs) 8910037SARM gem5 Developers 9010037SARM gem5 DevelopersallParams = {} 9110037SARM gem5 Developers 9211234Sandreas.sandberg@arm.comclass MetaParamValue(type): 9311234Sandreas.sandberg@arm.com def __new__(mcls, name, bases, dct): 9411234Sandreas.sandberg@arm.com cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 9511234Sandreas.sandberg@arm.com assert name not in allParams 968885SAli.Saidi@ARM.com allParams[name] = cls 9711234Sandreas.sandberg@arm.com return cls 9811234Sandreas.sandberg@arm.com 9911234Sandreas.sandberg@arm.com 1008885SAli.Saidi@ARM.com# Dummy base class to identify types that are legitimate for SimObject 10111234Sandreas.sandberg@arm.com# parameters. 10211234Sandreas.sandberg@arm.comclass ParamValue(object): 10311234Sandreas.sandberg@arm.com __metaclass__ = MetaParamValue 10411234Sandreas.sandberg@arm.com cmd_line_settable = False 10511234Sandreas.sandberg@arm.com 10611234Sandreas.sandberg@arm.com # Generate the code needed as a prerequisite for declaring a C++ 10711234Sandreas.sandberg@arm.com # object of this type. Typically generates one or more #include 10811234Sandreas.sandberg@arm.com # statements. Used when declaring parameters of this type. 10911234Sandreas.sandberg@arm.com @classmethod 11011234Sandreas.sandberg@arm.com def cxx_predecls(cls, code): 11111234Sandreas.sandberg@arm.com pass 11211234Sandreas.sandberg@arm.com 11313397Sgiacomo.travaglini@arm.com @classmethod 11413397Sgiacomo.travaglini@arm.com def pybind_predecls(cls, code): 11513397Sgiacomo.travaglini@arm.com cls.cxx_predecls(code) 11613397Sgiacomo.travaglini@arm.com 11713397Sgiacomo.travaglini@arm.com # default for printing to .ini file is regular string conversion. 11813397Sgiacomo.travaglini@arm.com # will be overridden in some cases 11910037SARM gem5 Developers def ini_str(self): 12010037SARM gem5 Developers return str(self) 12110037SARM gem5 Developers 12210037SARM gem5 Developers # default for printing to .json file is regular string conversion. 12310037SARM gem5 Developers # will be overridden in some cases, mostly to use native Python 12410037SARM gem5 Developers # types where there are similar JSON types 12510037SARM gem5 Developers def config_value(self): 12610037SARM gem5 Developers return str(self) 12710037SARM gem5 Developers 12811234Sandreas.sandberg@arm.com # Prerequisites for .ini parsing with cxx_ini_parse 12910037SARM gem5 Developers @classmethod 1308885SAli.Saidi@ARM.com def cxx_ini_predecls(cls, code): 1318706Sandreas.hansson@arm.com pass 1328706Sandreas.hansson@arm.com 1338706Sandreas.hansson@arm.com # parse a .ini file entry for this param from string expression 1348706Sandreas.hansson@arm.com # src into lvalue dest (of the param's C++ type) 1358706Sandreas.hansson@arm.com @classmethod 1368706Sandreas.hansson@arm.com def cxx_ini_parse(cls, code, src, dest, ret): 1378706Sandreas.hansson@arm.com code('// Unhandled param type: %s' % cls.__name__) 1388706Sandreas.hansson@arm.com code('%s false;' % ret) 1398706Sandreas.hansson@arm.com 1408706Sandreas.hansson@arm.com # allows us to blithely call unproxy() on things without checking 1418706Sandreas.hansson@arm.com # if they're really proxies or not 1428706Sandreas.hansson@arm.com def unproxy(self, base): 1432567SN/A return self 1448885SAli.Saidi@ARM.com 14513531Sjairo.balart@metempsy.com # Produce a human readable version of the stored value 1468706Sandreas.hansson@arm.com def pretty_print(self, value): 1478286SAli.Saidi@ARM.com return str(value) 1488286SAli.Saidi@ARM.com 1498286SAli.Saidi@ARM.com# Regular parameter description. 1508286SAli.Saidi@ARM.comclass ParamDesc(object): 1518286SAli.Saidi@ARM.com def __init__(self, ptype_str, ptype, *args, **kwargs): 1528286SAli.Saidi@ARM.com self.ptype_str = ptype_str 15313531Sjairo.balart@metempsy.com # remember ptype only if it is provided 15413531Sjairo.balart@metempsy.com if ptype != None: 15513531Sjairo.balart@metempsy.com self.ptype = ptype 15613531Sjairo.balart@metempsy.com 15713531Sjairo.balart@metempsy.com if args: 1588885SAli.Saidi@ARM.com if len(args) == 1: 1598286SAli.Saidi@ARM.com self.desc = args[0] 16010037SARM gem5 Developers elif len(args) == 2: 16110037SARM gem5 Developers self.default = args[0] 16210037SARM gem5 Developers self.desc = args[1] 16313531Sjairo.balart@metempsy.com else: 16413531Sjairo.balart@metempsy.com raise TypeError('too many arguments') 1658286SAli.Saidi@ARM.com 1668286SAli.Saidi@ARM.com if 'desc' in kwargs: 16710037SARM gem5 Developers assert(not hasattr(self, 'desc')) 16810037SARM gem5 Developers self.desc = kwargs['desc'] 1698286SAli.Saidi@ARM.com del kwargs['desc'] 1708286SAli.Saidi@ARM.com 17110037SARM gem5 Developers if 'default' in kwargs: 17210037SARM gem5 Developers assert(not hasattr(self, 'default')) 17310037SARM gem5 Developers self.default = kwargs['default'] 1748286SAli.Saidi@ARM.com del kwargs['default'] 1752567SN/A 1762567SN/A if kwargs: 17712317Sgiacomo.travaglini@arm.com raise TypeError('extra unknown kwargs %s' % kwargs) 17812317Sgiacomo.travaglini@arm.com 17912317Sgiacomo.travaglini@arm.com if not hasattr(self, 'desc'): 18012317Sgiacomo.travaglini@arm.com raise TypeError('desc attribute missing') 18112317Sgiacomo.travaglini@arm.com 18212317Sgiacomo.travaglini@arm.com def __getattr__(self, attr): 18312317Sgiacomo.travaglini@arm.com if attr == 'ptype': 18412317Sgiacomo.travaglini@arm.com from . import SimObject 18510037SARM gem5 Developers ptype = SimObject.allClasses[self.ptype_str] 18610037SARM gem5 Developers assert isSimObjectClass(ptype) 18710037SARM gem5 Developers self.ptype = ptype 18812317Sgiacomo.travaglini@arm.com return ptype 18910037SARM gem5 Developers 19010037SARM gem5 Developers raise AttributeError("'%s' object has no attribute '%s'" % \ 19110037SARM gem5 Developers (type(self).__name__, attr)) 1926757SAli.Saidi@ARM.com 1932567SN/A def example_str(self): 1948286SAli.Saidi@ARM.com if hasattr(self.ptype, "ex_str"): 1958286SAli.Saidi@ARM.com return self.ptype.ex_str 1962567SN/A else: 1972567SN/A return self.ptype_str 19811234Sandreas.sandberg@arm.com 19911234Sandreas.sandberg@arm.com # Is the param available to be exposed on the command line 20011234Sandreas.sandberg@arm.com def isCmdLineSettable(self): 20111234Sandreas.sandberg@arm.com if hasattr(self.ptype, "cmd_line_settable"): 20211234Sandreas.sandberg@arm.com return self.ptype.cmd_line_settable 20311234Sandreas.sandberg@arm.com else: 20411234Sandreas.sandberg@arm.com return False 20511234Sandreas.sandberg@arm.com 20611234Sandreas.sandberg@arm.com def convert(self, value): 20711234Sandreas.sandberg@arm.com if isinstance(value, proxy.BaseProxy): 20811234Sandreas.sandberg@arm.com value.set_param_desc(self) 20910037SARM gem5 Developers return value 21010037SARM gem5 Developers if 'ptype' not in self.__dict__ and isNullPointer(value): 21110037SARM gem5 Developers # deferred evaluation of SimObject; continue to defer if 21212317Sgiacomo.travaglini@arm.com # we're just assigning a null pointer 21310037SARM gem5 Developers return value 21410037SARM gem5 Developers if isinstance(value, self.ptype): 21510037SARM gem5 Developers return value 21610037SARM gem5 Developers if isNullPointer(value) and isSimObjectClass(self.ptype): 21710037SARM gem5 Developers return value 21812317Sgiacomo.travaglini@arm.com return self.ptype(value) 21910037SARM gem5 Developers 22010037SARM gem5 Developers def pretty_print(self, value): 22110037SARM gem5 Developers if isinstance(value, proxy.BaseProxy): 22210037SARM gem5 Developers return str(value) 22310037SARM gem5 Developers if isNullPointer(value): 22412317Sgiacomo.travaglini@arm.com return NULL 22510037SARM gem5 Developers return self.ptype(value).pretty_print(value) 22610037SARM gem5 Developers 22710037SARM gem5 Developers def cxx_predecls(self, code): 22810037SARM gem5 Developers code('#include <cstddef>') 22910037SARM gem5 Developers self.ptype.cxx_predecls(code) 23012317Sgiacomo.travaglini@arm.com 23110037SARM gem5 Developers def pybind_predecls(self, code): 23210037SARM gem5 Developers self.ptype.pybind_predecls(code) 23312318Sgiacomo.travaglini@arm.com 23412318Sgiacomo.travaglini@arm.com def cxx_decl(self, code): 23512318Sgiacomo.travaglini@arm.com code('${{self.ptype.cxx_type}} ${{self.name}};') 23612318Sgiacomo.travaglini@arm.com 23712318Sgiacomo.travaglini@arm.com# Vector-valued parameter description. Just like ParamDesc, except 23812318Sgiacomo.travaglini@arm.com# that the value is a vector (list) of the specified type instead of a 23912318Sgiacomo.travaglini@arm.com# single value. 24012318Sgiacomo.travaglini@arm.com 24112318Sgiacomo.travaglini@arm.comclass VectorParamValue(list): 24212318Sgiacomo.travaglini@arm.com __metaclass__ = MetaParamValue 24312318Sgiacomo.travaglini@arm.com def __setattr__(self, attr, value): 24412318Sgiacomo.travaglini@arm.com raise AttributeError("Not allowed to set %s on '%s'" % \ 24512318Sgiacomo.travaglini@arm.com (attr, type(self).__name__)) 24612318Sgiacomo.travaglini@arm.com 24712318Sgiacomo.travaglini@arm.com def config_value(self): 24812318Sgiacomo.travaglini@arm.com return [v.config_value() for v in self] 24912318Sgiacomo.travaglini@arm.com 25010037SARM gem5 Developers def ini_str(self): 25113396Sgiacomo.travaglini@arm.com return ' '.join([v.ini_str() for v in self]) 25210037SARM gem5 Developers 25313396Sgiacomo.travaglini@arm.com def getValue(self): 25410037SARM gem5 Developers return [ v.getValue() for v in self ] 25510037SARM gem5 Developers 25610037SARM gem5 Developers def unproxy(self, base): 25710037SARM gem5 Developers if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 25810037SARM gem5 Developers # The value is a proxy (e.g. Parent.any, Parent.all or 25912317Sgiacomo.travaglini@arm.com # Parent.x) therefore try resolve it 26010037SARM gem5 Developers return self[0].unproxy(base) 26110037SARM gem5 Developers else: 26210037SARM gem5 Developers return [v.unproxy(base) for v in self] 26310037SARM gem5 Developers 26410037SARM gem5 Developersclass SimObjectVector(VectorParamValue): 26512317Sgiacomo.travaglini@arm.com # support clone operation 26610037SARM gem5 Developers def __call__(self, **kwargs): 26710037SARM gem5 Developers return SimObjectVector([v(**kwargs) for v in self]) 26810037SARM gem5 Developers 26910037SARM gem5 Developers def clear_parent(self, old_parent): 27010037SARM gem5 Developers for v in self: 27112317Sgiacomo.travaglini@arm.com v.clear_parent(old_parent) 27210037SARM gem5 Developers 27310810Sbr@bsdpad.com def set_parent(self, parent, name): 27412531Sandreas.sandberg@arm.com if len(self) == 1: 27512531Sandreas.sandberg@arm.com self[0].set_parent(parent, name) 27612531Sandreas.sandberg@arm.com else: 27712534Sgiacomo.travaglini@arm.com width = int(math.ceil(math.log(len(self))/math.log(10))) 27812531Sandreas.sandberg@arm.com for i,v in enumerate(self): 27912531Sandreas.sandberg@arm.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 28012531Sandreas.sandberg@arm.com 28112531Sandreas.sandberg@arm.com def has_parent(self): 28212531Sandreas.sandberg@arm.com return any([e.has_parent() for e in self if not isNullPointer(e)]) 28312531Sandreas.sandberg@arm.com 28412531Sandreas.sandberg@arm.com # return 'cpu0 cpu1' etc. for print_ini() 28512531Sandreas.sandberg@arm.com def get_name(self): 28612531Sandreas.sandberg@arm.com return ' '.join([v._name for v in self]) 28712531Sandreas.sandberg@arm.com 28812531Sandreas.sandberg@arm.com # By iterating through the constituent members of the vector here 28912531Sandreas.sandberg@arm.com # we can nicely handle iterating over all a SimObject's children 29012531Sandreas.sandberg@arm.com # without having to provide lots of special functions on 29112531Sandreas.sandberg@arm.com # SimObjectVector directly. 29212531Sandreas.sandberg@arm.com def descendants(self): 29312531Sandreas.sandberg@arm.com for v in self: 29412531Sandreas.sandberg@arm.com for obj in v.descendants(): 29512531Sandreas.sandberg@arm.com yield obj 2966757SAli.Saidi@ARM.com 2976757SAli.Saidi@ARM.com def get_config_as_dict(self): 2982567SN/A a = [] 2996757SAli.Saidi@ARM.com for v in self: 3002567SN/A a.append(v.get_config_as_dict()) 30110810Sbr@bsdpad.com return a 30210810Sbr@bsdpad.com 30310810Sbr@bsdpad.com # If we are replacing an item in the vector, make sure to set the 30410810Sbr@bsdpad.com # parent reference of the new SimObject to be the same as the parent 30510810Sbr@bsdpad.com # of the SimObject being replaced. Useful to have if we created 30610810Sbr@bsdpad.com # a SimObjectVector of temporary objects that will be modified later in 30710810Sbr@bsdpad.com # configuration scripts. 30810810Sbr@bsdpad.com def __setitem__(self, key, value): 30910810Sbr@bsdpad.com val = self[key] 31010810Sbr@bsdpad.com if value.has_parent(): 31110810Sbr@bsdpad.com warn("SimObject %s already has a parent" % value.get_name() +\ 31210810Sbr@bsdpad.com " that is being overwritten by a SimObjectVector") 31310810Sbr@bsdpad.com value.set_parent(val.get_parent(), val._name) 31410810Sbr@bsdpad.com super(SimObjectVector, self).__setitem__(key, value) 31510810Sbr@bsdpad.com 31610810Sbr@bsdpad.com # Enumerate the params of each member of the SimObject vector. Creates 31710810Sbr@bsdpad.com # strings that will allow indexing into the vector by the python code and 318 # allow it to be specified on the command line. 319 def enumerateParams(self, flags_dict = {}, 320 cmd_line_str = "", 321 access_str = ""): 322 if hasattr(self, "_paramEnumed"): 323 print("Cycle detected enumerating params at %s?!" % (cmd_line_str)) 324 else: 325 x = 0 326 for vals in self: 327 # Each entry in the SimObjectVector should be an 328 # instance of a SimObject 329 flags_dict = vals.enumerateParams(flags_dict, 330 cmd_line_str + "%d." % x, 331 access_str + "[%d]." % x) 332 x = x + 1 333 334 return flags_dict 335 336class VectorParamDesc(ParamDesc): 337 # Convert assigned value to appropriate type. If the RHS is not a 338 # list or tuple, it generates a single-element list. 339 def convert(self, value): 340 if isinstance(value, (list, tuple)): 341 # list: coerce each element into new list 342 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 343 elif isinstance(value, str): 344 # If input is a csv string 345 tmp_list = [ ParamDesc.convert(self, v) \ 346 for v in value.strip('[').strip(']').split(',') ] 347 else: 348 # singleton: coerce to a single-element list 349 tmp_list = [ ParamDesc.convert(self, value) ] 350 351 if isSimObjectSequence(tmp_list): 352 return SimObjectVector(tmp_list) 353 else: 354 return VectorParamValue(tmp_list) 355 356 # Produce a human readable example string that describes 357 # how to set this vector parameter in the absence of a default 358 # value. 359 def example_str(self): 360 s = super(VectorParamDesc, self).example_str() 361 help_str = "[" + s + "," + s + ", ...]" 362 return help_str 363 364 # Produce a human readable representation of the value of this vector param. 365 def pretty_print(self, value): 366 if isinstance(value, (list, tuple)): 367 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 368 elif isinstance(value, str): 369 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 370 else: 371 tmp_list = [ ParamDesc.pretty_print(self, value) ] 372 373 return tmp_list 374 375 # This is a helper function for the new config system 376 def __call__(self, value): 377 if isinstance(value, (list, tuple)): 378 # list: coerce each element into new list 379 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 380 elif isinstance(value, str): 381 # If input is a csv string 382 tmp_list = [ ParamDesc.convert(self, v) \ 383 for v in value.strip('[').strip(']').split(',') ] 384 else: 385 # singleton: coerce to a single-element list 386 tmp_list = [ ParamDesc.convert(self, value) ] 387 388 return VectorParamValue(tmp_list) 389 390 def cxx_predecls(self, code): 391 code('#include <vector>') 392 self.ptype.cxx_predecls(code) 393 394 def pybind_predecls(self, code): 395 code('#include <vector>') 396 self.ptype.pybind_predecls(code) 397 398 def cxx_decl(self, code): 399 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 400 401class ParamFactory(object): 402 def __init__(self, param_desc_class, ptype_str = None): 403 self.param_desc_class = param_desc_class 404 self.ptype_str = ptype_str 405 406 def __getattr__(self, attr): 407 if self.ptype_str: 408 attr = self.ptype_str + '.' + attr 409 return ParamFactory(self.param_desc_class, attr) 410 411 # E.g., Param.Int(5, "number of widgets") 412 def __call__(self, *args, **kwargs): 413 ptype = None 414 try: 415 ptype = allParams[self.ptype_str] 416 except KeyError: 417 # if name isn't defined yet, assume it's a SimObject, and 418 # try to resolve it later 419 pass 420 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 421 422Param = ParamFactory(ParamDesc) 423VectorParam = ParamFactory(VectorParamDesc) 424 425##################################################################### 426# 427# Parameter Types 428# 429# Though native Python types could be used to specify parameter types 430# (the 'ptype' field of the Param and VectorParam classes), it's more 431# flexible to define our own set of types. This gives us more control 432# over how Python expressions are converted to values (via the 433# __init__() constructor) and how these values are printed out (via 434# the __str__() conversion method). 435# 436##################################################################### 437 438# String-valued parameter. Just mixin the ParamValue class with the 439# built-in str class. 440class String(ParamValue,str): 441 cxx_type = 'std::string' 442 cmd_line_settable = True 443 444 @classmethod 445 def cxx_predecls(self, code): 446 code('#include <string>') 447 448 def __call__(self, value): 449 self = value 450 return value 451 452 @classmethod 453 def cxx_ini_parse(self, code, src, dest, ret): 454 code('%s = %s;' % (dest, src)) 455 code('%s true;' % ret) 456 457 def getValue(self): 458 return self 459 460# superclass for "numeric" parameter values, to emulate math 461# operations in a type-safe way. e.g., a Latency times an int returns 462# a new Latency object. 463class NumericParamValue(ParamValue): 464 @staticmethod 465 def unwrap(v): 466 return v.value if isinstance(v, NumericParamValue) else v 467 468 def __str__(self): 469 return str(self.value) 470 471 def __float__(self): 472 return float(self.value) 473 474 def __long__(self): 475 return long(self.value) 476 477 def __int__(self): 478 return int(self.value) 479 480 # hook for bounds checking 481 def _check(self): 482 return 483 484 def __mul__(self, other): 485 newobj = self.__class__(self) 486 newobj.value *= NumericParamValue.unwrap(other) 487 newobj._check() 488 return newobj 489 490 __rmul__ = __mul__ 491 492 def __truediv__(self, other): 493 newobj = self.__class__(self) 494 newobj.value /= NumericParamValue.unwrap(other) 495 newobj._check() 496 return newobj 497 498 def __floordiv__(self, other): 499 newobj = self.__class__(self) 500 newobj.value //= NumericParamValue.unwrap(other) 501 newobj._check() 502 return newobj 503 504 505 def __add__(self, other): 506 newobj = self.__class__(self) 507 newobj.value += NumericParamValue.unwrap(other) 508 newobj._check() 509 return newobj 510 511 def __sub__(self, other): 512 newobj = self.__class__(self) 513 newobj.value -= NumericParamValue.unwrap(other) 514 newobj._check() 515 return newobj 516 517 def __iadd__(self, other): 518 self.value += NumericParamValue.unwrap(other) 519 self._check() 520 return self 521 522 def __isub__(self, other): 523 self.value -= NumericParamValue.unwrap(other) 524 self._check() 525 return self 526 527 def __imul__(self, other): 528 self.value *= NumericParamValue.unwrap(other) 529 self._check() 530 return self 531 532 def __itruediv__(self, other): 533 self.value /= NumericParamValue.unwrap(other) 534 self._check() 535 return self 536 537 def __ifloordiv__(self, other): 538 self.value //= NumericParamValue.unwrap(other) 539 self._check() 540 return self 541 542 def __lt__(self, other): 543 return self.value < NumericParamValue.unwrap(other) 544 545 # Python 2.7 pre __future__.division operators 546 # TODO: Remove these when after "import division from __future__" 547 __div__ = __truediv__ 548 __idiv__ = __itruediv__ 549 550 def config_value(self): 551 return self.value 552 553 @classmethod 554 def cxx_ini_predecls(cls, code): 555 # Assume that base/str.hh will be included anyway 556 # code('#include "base/str.hh"') 557 pass 558 559 # The default for parsing PODs from an .ini entry is to extract from an 560 # istringstream and let overloading choose the right type according to 561 # the dest type. 562 @classmethod 563 def cxx_ini_parse(self, code, src, dest, ret): 564 code('%s to_number(%s, %s);' % (ret, src, dest)) 565 566# Metaclass for bounds-checked integer parameters. See CheckedInt. 567class CheckedIntType(MetaParamValue): 568 def __init__(cls, name, bases, dict): 569 super(CheckedIntType, cls).__init__(name, bases, dict) 570 571 # CheckedInt is an abstract base class, so we actually don't 572 # want to do any processing on it... the rest of this code is 573 # just for classes that derive from CheckedInt. 574 if name == 'CheckedInt': 575 return 576 577 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 578 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 579 panic("CheckedInt subclass %s must define either\n" \ 580 " 'min' and 'max' or 'size' and 'unsigned'\n", 581 name); 582 if cls.unsigned: 583 cls.min = 0 584 cls.max = 2 ** cls.size - 1 585 else: 586 cls.min = -(2 ** (cls.size - 1)) 587 cls.max = (2 ** (cls.size - 1)) - 1 588 589# Abstract superclass for bounds-checked integer parameters. This 590# class is subclassed to generate parameter classes with specific 591# bounds. Initialization of the min and max bounds is done in the 592# metaclass CheckedIntType.__init__. 593class CheckedInt(NumericParamValue): 594 __metaclass__ = CheckedIntType 595 cmd_line_settable = True 596 597 def _check(self): 598 if not self.min <= self.value <= self.max: 599 raise TypeError('Integer param out of bounds %d < %d < %d' % \ 600 (self.min, self.value, self.max)) 601 602 def __init__(self, value): 603 if isinstance(value, str): 604 self.value = convert.toInteger(value) 605 elif isinstance(value, (int, long, float, NumericParamValue)): 606 self.value = long(value) 607 else: 608 raise TypeError("Can't convert object of type %s to CheckedInt" \ 609 % type(value).__name__) 610 self._check() 611 612 def __call__(self, value): 613 self.__init__(value) 614 return value 615 616 def __index__(self): 617 return int(self.value) 618 619 @classmethod 620 def cxx_predecls(cls, code): 621 # most derived types require this, so we just do it here once 622 code('#include "base/types.hh"') 623 624 def getValue(self): 625 return long(self.value) 626 627class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 628class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 629 630class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 631class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 632class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 633class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 634class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 635class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 636class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 637class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 638 639class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 640class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 641class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 642class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 643 644class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 645 646class Cycles(CheckedInt): 647 cxx_type = 'Cycles' 648 size = 64 649 unsigned = True 650 651 def getValue(self): 652 from _m5.core import Cycles 653 return Cycles(self.value) 654 655 @classmethod 656 def cxx_ini_predecls(cls, code): 657 # Assume that base/str.hh will be included anyway 658 # code('#include "base/str.hh"') 659 pass 660 661 @classmethod 662 def cxx_ini_parse(cls, code, src, dest, ret): 663 code('uint64_t _temp;') 664 code('bool _ret = to_number(%s, _temp);' % src) 665 code('if (_ret)') 666 code(' %s = Cycles(_temp);' % dest) 667 code('%s _ret;' % ret) 668 669class Float(ParamValue, float): 670 cxx_type = 'double' 671 cmd_line_settable = True 672 673 def __init__(self, value): 674 if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 675 self.value = float(value) 676 else: 677 raise TypeError("Can't convert object of type %s to Float" \ 678 % type(value).__name__) 679 680 def __call__(self, value): 681 self.__init__(value) 682 return value 683 684 def getValue(self): 685 return float(self.value) 686 687 def config_value(self): 688 return self 689 690 @classmethod 691 def cxx_ini_predecls(cls, code): 692 code('#include <sstream>') 693 694 @classmethod 695 def cxx_ini_parse(self, code, src, dest, ret): 696 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 697 698class MemorySize(CheckedInt): 699 cxx_type = 'uint64_t' 700 ex_str = '512MB' 701 size = 64 702 unsigned = True 703 def __init__(self, value): 704 if isinstance(value, MemorySize): 705 self.value = value.value 706 else: 707 self.value = convert.toMemorySize(value) 708 self._check() 709 710class MemorySize32(CheckedInt): 711 cxx_type = 'uint32_t' 712 ex_str = '512MB' 713 size = 32 714 unsigned = True 715 def __init__(self, value): 716 if isinstance(value, MemorySize): 717 self.value = value.value 718 else: 719 self.value = convert.toMemorySize(value) 720 self._check() 721 722class Addr(CheckedInt): 723 cxx_type = 'Addr' 724 size = 64 725 unsigned = True 726 def __init__(self, value): 727 if isinstance(value, Addr): 728 self.value = value.value 729 else: 730 try: 731 # Often addresses are referred to with sizes. Ex: A device 732 # base address is at "512MB". Use toMemorySize() to convert 733 # these into addresses. If the address is not specified with a 734 # "size", an exception will occur and numeric translation will 735 # proceed below. 736 self.value = convert.toMemorySize(value) 737 except (TypeError, ValueError): 738 # Convert number to string and use long() to do automatic 739 # base conversion (requires base=0 for auto-conversion) 740 self.value = long(str(value), base=0) 741 742 self._check() 743 def __add__(self, other): 744 if isinstance(other, Addr): 745 return self.value + other.value 746 else: 747 return self.value + other 748 def pretty_print(self, value): 749 try: 750 val = convert.toMemorySize(value) 751 except TypeError: 752 val = long(value) 753 return "0x%x" % long(val) 754 755class AddrRange(ParamValue): 756 cxx_type = 'AddrRange' 757 758 def __init__(self, *args, **kwargs): 759 # Disable interleaving and hashing by default 760 self.intlvBits = 0 761 self.intlvMatch = 0 762 self.masks = [] 763 764 def handle_kwargs(self, kwargs): 765 # An address range needs to have an upper limit, specified 766 # either explicitly with an end, or as an offset using the 767 # size keyword. 768 if 'end' in kwargs: 769 self.end = Addr(kwargs.pop('end')) 770 elif 'size' in kwargs: 771 self.end = self.start + Addr(kwargs.pop('size')) - 1 772 else: 773 raise TypeError("Either end or size must be specified") 774 775 # Now on to the optional bit 776 if 'intlvMatch' in kwargs: 777 self.intlvMatch = int(kwargs.pop('intlvMatch')) 778 779 if 'masks' in kwargs: 780 self.masks = [ long(x) for x in list(kwargs.pop('masks')) ] 781 self.intlvBits = len(self.masks) 782 else: 783 if 'intlvBits' in kwargs: 784 self.intlvBits = int(kwargs.pop('intlvBits')) 785 self.masks = [0] * self.intlvBits 786 if 'intlvHighBit' not in kwargs: 787 raise TypeError("No interleave bits specified") 788 intlv_high_bit = int(kwargs.pop('intlvHighBit')) 789 xor_high_bit = 0 790 if 'xorHighBit' in kwargs: 791 xor_high_bit = int(kwargs.pop('xorHighBit')) 792 for i in range(0, self.intlvBits): 793 bit1 = intlv_high_bit - i 794 mask = 1 << bit1 795 if xor_high_bit != 0: 796 bit2 = xor_high_bit - i 797 mask |= 1 << bit2 798 self.masks[self.intlvBits - i - 1] = mask 799 800 if len(args) == 0: 801 self.start = Addr(kwargs.pop('start')) 802 handle_kwargs(self, kwargs) 803 804 elif len(args) == 1: 805 if kwargs: 806 self.start = Addr(args[0]) 807 handle_kwargs(self, kwargs) 808 elif isinstance(args[0], (list, tuple)): 809 self.start = Addr(args[0][0]) 810 self.end = Addr(args[0][1]) 811 else: 812 self.start = Addr(0) 813 self.end = Addr(args[0]) - 1 814 815 elif len(args) == 2: 816 self.start = Addr(args[0]) 817 self.end = Addr(args[1]) 818 else: 819 raise TypeError("Too many arguments specified") 820 821 if kwargs: 822 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 823 824 def __str__(self): 825 if len(self.masks) == 0: 826 return '%s:%s' % (self.start, self.end) 827 else: 828 return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch, 829 ':'.join(str(m) for m in self.masks)) 830 831 def size(self): 832 # Divide the size by the size of the interleaving slice 833 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 834 835 @classmethod 836 def cxx_predecls(cls, code): 837 Addr.cxx_predecls(code) 838 code('#include "base/addr_range.hh"') 839 840 @classmethod 841 def pybind_predecls(cls, code): 842 Addr.pybind_predecls(code) 843 code('#include "base/addr_range.hh"') 844 845 @classmethod 846 def cxx_ini_predecls(cls, code): 847 code('#include <sstream>') 848 code('#include <vector>') 849 code('#include "base/types.hh"') 850 851 @classmethod 852 def cxx_ini_parse(cls, code, src, dest, ret): 853 code('bool _ret = true;') 854 code('uint64_t _start, _end, _intlvMatch = 0;') 855 code('std::vector<Addr> _masks;') 856 code('char _sep;') 857 code('std::istringstream _stream(${src});') 858 code('_stream >> _start;') 859 code('_stream.get(_sep);') 860 code('_ret = _sep == \':\';') 861 code('_stream >> _end;') 862 code('if (!_stream.fail() && !_stream.eof()) {') 863 code(' _stream.get(_sep);') 864 code(' _ret = ret && _sep == \':\';') 865 code(' _stream >> _intlvMatch;') 866 code(' while (!_stream.fail() && !_stream.eof()) {') 867 code(' _stream.get(_sep);') 868 code(' _ret = ret && _sep == \':\';') 869 code(' Addr mask;') 870 code(' _stream >> mask;') 871 code(' _masks.push_back(mask);') 872 code(' }') 873 code('}') 874 code('_ret = _ret && !_stream.fail() && _stream.eof();') 875 code('if (_ret)') 876 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);') 877 code('${ret} _ret;') 878 879 def getValue(self): 880 # Go from the Python class to the wrapped C++ class 881 from _m5.range import AddrRange 882 883 return AddrRange(long(self.start), long(self.end), 884 self.masks, int(self.intlvMatch)) 885 886# Boolean parameter type. Python doesn't let you subclass bool, since 887# it doesn't want to let you create multiple instances of True and 888# False. Thus this is a little more complicated than String. 889class Bool(ParamValue): 890 cxx_type = 'bool' 891 cmd_line_settable = True 892 893 def __init__(self, value): 894 try: 895 self.value = convert.toBool(value) 896 except TypeError: 897 self.value = bool(value) 898 899 def __call__(self, value): 900 self.__init__(value) 901 return value 902 903 def getValue(self): 904 return bool(self.value) 905 906 def __str__(self): 907 return str(self.value) 908 909 # implement truth value testing for Bool parameters so that these params 910 # evaluate correctly during the python configuration phase 911 def __bool__(self): 912 return bool(self.value) 913 914 # Python 2.7 uses __nonzero__ instead of __bool__ 915 __nonzero__ = __bool__ 916 917 def ini_str(self): 918 if self.value: 919 return 'true' 920 return 'false' 921 922 def config_value(self): 923 return self.value 924 925 @classmethod 926 def cxx_ini_predecls(cls, code): 927 # Assume that base/str.hh will be included anyway 928 # code('#include "base/str.hh"') 929 pass 930 931 @classmethod 932 def cxx_ini_parse(cls, code, src, dest, ret): 933 code('%s to_bool(%s, %s);' % (ret, src, dest)) 934 935def IncEthernetAddr(addr, val = 1): 936 bytes = [ int(x, 16) for x in addr.split(':') ] 937 bytes[5] += val 938 for i in (5, 4, 3, 2, 1): 939 val,rem = divmod(bytes[i], 256) 940 bytes[i] = rem 941 if val == 0: 942 break 943 bytes[i - 1] += val 944 assert(bytes[0] <= 255) 945 return ':'.join(map(lambda x: '%02x' % x, bytes)) 946 947_NextEthernetAddr = "00:90:00:00:00:01" 948def NextEthernetAddr(): 949 global _NextEthernetAddr 950 951 value = _NextEthernetAddr 952 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 953 return value 954 955class EthernetAddr(ParamValue): 956 cxx_type = 'Net::EthAddr' 957 ex_str = "00:90:00:00:00:01" 958 cmd_line_settable = True 959 960 @classmethod 961 def cxx_predecls(cls, code): 962 code('#include "base/inet.hh"') 963 964 def __init__(self, value): 965 if value == NextEthernetAddr: 966 self.value = value 967 return 968 969 if not isinstance(value, str): 970 raise TypeError("expected an ethernet address and didn't get one") 971 972 bytes = value.split(':') 973 if len(bytes) != 6: 974 raise TypeError('invalid ethernet address %s' % value) 975 976 for byte in bytes: 977 if not 0 <= int(byte, base=16) <= 0xff: 978 raise TypeError('invalid ethernet address %s' % value) 979 980 self.value = value 981 982 def __call__(self, value): 983 self.__init__(value) 984 return value 985 986 def unproxy(self, base): 987 if self.value == NextEthernetAddr: 988 return EthernetAddr(self.value()) 989 return self 990 991 def getValue(self): 992 from _m5.net import EthAddr 993 return EthAddr(self.value) 994 995 def __str__(self): 996 return self.value 997 998 def ini_str(self): 999 return self.value 1000 1001 @classmethod 1002 def cxx_ini_parse(self, code, src, dest, ret): 1003 code('%s = Net::EthAddr(%s);' % (dest, src)) 1004 code('%s true;' % ret) 1005 1006# When initializing an IpAddress, pass in an existing IpAddress, a string of 1007# the form "a.b.c.d", or an integer representing an IP. 1008class IpAddress(ParamValue): 1009 cxx_type = 'Net::IpAddress' 1010 ex_str = "127.0.0.1" 1011 cmd_line_settable = True 1012 1013 @classmethod 1014 def cxx_predecls(cls, code): 1015 code('#include "base/inet.hh"') 1016 1017 def __init__(self, value): 1018 if isinstance(value, IpAddress): 1019 self.ip = value.ip 1020 else: 1021 try: 1022 self.ip = convert.toIpAddress(value) 1023 except TypeError: 1024 self.ip = long(value) 1025 self.verifyIp() 1026 1027 def __call__(self, value): 1028 self.__init__(value) 1029 return value 1030 1031 def __str__(self): 1032 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 1033 return '%d.%d.%d.%d' % tuple(tup) 1034 1035 def __eq__(self, other): 1036 if isinstance(other, IpAddress): 1037 return self.ip == other.ip 1038 elif isinstance(other, str): 1039 try: 1040 return self.ip == convert.toIpAddress(other) 1041 except: 1042 return False 1043 else: 1044 return self.ip == other 1045 1046 def __ne__(self, other): 1047 return not (self == other) 1048 1049 def verifyIp(self): 1050 if self.ip < 0 or self.ip >= (1 << 32): 1051 raise TypeError("invalid ip address %#08x" % self.ip) 1052 1053 def getValue(self): 1054 from _m5.net import IpAddress 1055 return IpAddress(self.ip) 1056 1057# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 1058# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 1059# positional or keyword arguments. 1060class IpNetmask(IpAddress): 1061 cxx_type = 'Net::IpNetmask' 1062 ex_str = "127.0.0.0/24" 1063 cmd_line_settable = True 1064 1065 @classmethod 1066 def cxx_predecls(cls, code): 1067 code('#include "base/inet.hh"') 1068 1069 def __init__(self, *args, **kwargs): 1070 def handle_kwarg(self, kwargs, key, elseVal = None): 1071 if key in kwargs: 1072 setattr(self, key, kwargs.pop(key)) 1073 elif elseVal: 1074 setattr(self, key, elseVal) 1075 else: 1076 raise TypeError("No value set for %s" % key) 1077 1078 if len(args) == 0: 1079 handle_kwarg(self, kwargs, 'ip') 1080 handle_kwarg(self, kwargs, 'netmask') 1081 1082 elif len(args) == 1: 1083 if kwargs: 1084 if not 'ip' in kwargs and not 'netmask' in kwargs: 1085 raise TypeError("Invalid arguments") 1086 handle_kwarg(self, kwargs, 'ip', args[0]) 1087 handle_kwarg(self, kwargs, 'netmask', args[0]) 1088 elif isinstance(args[0], IpNetmask): 1089 self.ip = args[0].ip 1090 self.netmask = args[0].netmask 1091 else: 1092 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1093 1094 elif len(args) == 2: 1095 self.ip = args[0] 1096 self.netmask = args[1] 1097 else: 1098 raise TypeError("Too many arguments specified") 1099 1100 if kwargs: 1101 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 1102 1103 self.verify() 1104 1105 def __call__(self, value): 1106 self.__init__(value) 1107 return value 1108 1109 def __str__(self): 1110 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1111 1112 def __eq__(self, other): 1113 if isinstance(other, IpNetmask): 1114 return self.ip == other.ip and self.netmask == other.netmask 1115 elif isinstance(other, str): 1116 try: 1117 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1118 except: 1119 return False 1120 else: 1121 return False 1122 1123 def verify(self): 1124 self.verifyIp() 1125 if self.netmask < 0 or self.netmask > 32: 1126 raise TypeError("invalid netmask %d" % netmask) 1127 1128 def getValue(self): 1129 from _m5.net import IpNetmask 1130 return IpNetmask(self.ip, self.netmask) 1131 1132# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1133# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1134class IpWithPort(IpAddress): 1135 cxx_type = 'Net::IpWithPort' 1136 ex_str = "127.0.0.1:80" 1137 cmd_line_settable = True 1138 1139 @classmethod 1140 def cxx_predecls(cls, code): 1141 code('#include "base/inet.hh"') 1142 1143 def __init__(self, *args, **kwargs): 1144 def handle_kwarg(self, kwargs, key, elseVal = None): 1145 if key in kwargs: 1146 setattr(self, key, kwargs.pop(key)) 1147 elif elseVal: 1148 setattr(self, key, elseVal) 1149 else: 1150 raise TypeError("No value set for %s" % key) 1151 1152 if len(args) == 0: 1153 handle_kwarg(self, kwargs, 'ip') 1154 handle_kwarg(self, kwargs, 'port') 1155 1156 elif len(args) == 1: 1157 if kwargs: 1158 if not 'ip' in kwargs and not 'port' in kwargs: 1159 raise TypeError("Invalid arguments") 1160 handle_kwarg(self, kwargs, 'ip', args[0]) 1161 handle_kwarg(self, kwargs, 'port', args[0]) 1162 elif isinstance(args[0], IpWithPort): 1163 self.ip = args[0].ip 1164 self.port = args[0].port 1165 else: 1166 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1167 1168 elif len(args) == 2: 1169 self.ip = args[0] 1170 self.port = args[1] 1171 else: 1172 raise TypeError("Too many arguments specified") 1173 1174 if kwargs: 1175 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 1176 1177 self.verify() 1178 1179 def __call__(self, value): 1180 self.__init__(value) 1181 return value 1182 1183 def __str__(self): 1184 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1185 1186 def __eq__(self, other): 1187 if isinstance(other, IpWithPort): 1188 return self.ip == other.ip and self.port == other.port 1189 elif isinstance(other, str): 1190 try: 1191 return (self.ip, self.port) == convert.toIpWithPort(other) 1192 except: 1193 return False 1194 else: 1195 return False 1196 1197 def verify(self): 1198 self.verifyIp() 1199 if self.port < 0 or self.port > 0xffff: 1200 raise TypeError("invalid port %d" % self.port) 1201 1202 def getValue(self): 1203 from _m5.net import IpWithPort 1204 return IpWithPort(self.ip, self.port) 1205 1206time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1207 "%a %b %d %H:%M:%S %Y", 1208 "%Y/%m/%d %H:%M:%S", 1209 "%Y/%m/%d %H:%M", 1210 "%Y/%m/%d", 1211 "%m/%d/%Y %H:%M:%S", 1212 "%m/%d/%Y %H:%M", 1213 "%m/%d/%Y", 1214 "%m/%d/%y %H:%M:%S", 1215 "%m/%d/%y %H:%M", 1216 "%m/%d/%y"] 1217 1218 1219def parse_time(value): 1220 from time import gmtime, strptime, struct_time, time 1221 from datetime import datetime, date 1222 1223 if isinstance(value, struct_time): 1224 return value 1225 1226 if isinstance(value, (int, long)): 1227 return gmtime(value) 1228 1229 if isinstance(value, (datetime, date)): 1230 return value.timetuple() 1231 1232 if isinstance(value, str): 1233 if value in ('Now', 'Today'): 1234 return time.gmtime(time.time()) 1235 1236 for format in time_formats: 1237 try: 1238 return strptime(value, format) 1239 except ValueError: 1240 pass 1241 1242 raise ValueError("Could not parse '%s' as a time" % value) 1243 1244class Time(ParamValue): 1245 cxx_type = 'tm' 1246 1247 @classmethod 1248 def cxx_predecls(cls, code): 1249 code('#include <time.h>') 1250 1251 def __init__(self, value): 1252 self.value = parse_time(value) 1253 1254 def __call__(self, value): 1255 self.__init__(value) 1256 return value 1257 1258 def getValue(self): 1259 from _m5.core import tm 1260 import calendar 1261 1262 return tm.gmtime(calendar.timegm(self.value)) 1263 1264 def __str__(self): 1265 return time.asctime(self.value) 1266 1267 def ini_str(self): 1268 return str(self) 1269 1270 def get_config_as_dict(self): 1271 assert false 1272 return str(self) 1273 1274 @classmethod 1275 def cxx_ini_predecls(cls, code): 1276 code('#include <time.h>') 1277 1278 @classmethod 1279 def cxx_ini_parse(cls, code, src, dest, ret): 1280 code('char *_parse_ret = strptime((${src}).c_str(),') 1281 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1282 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1283 1284# Enumerated types are a little more complex. The user specifies the 1285# type as Enum(foo) where foo is either a list or dictionary of 1286# alternatives (typically strings, but not necessarily so). (In the 1287# long run, the integer value of the parameter will be the list index 1288# or the corresponding dictionary value. For now, since we only check 1289# that the alternative is valid and then spit it into a .ini file, 1290# there's not much point in using the dictionary.) 1291 1292# What Enum() must do is generate a new type encapsulating the 1293# provided list/dictionary so that specific values of the parameter 1294# can be instances of that type. We define two hidden internal 1295# classes (_ListEnum and _DictEnum) to serve as base classes, then 1296# derive the new type from the appropriate base class on the fly. 1297 1298allEnums = {} 1299# Metaclass for Enum types 1300class MetaEnum(MetaParamValue): 1301 def __new__(mcls, name, bases, dict): 1302 assert name not in allEnums 1303 1304 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1305 allEnums[name] = cls 1306 return cls 1307 1308 def __init__(cls, name, bases, init_dict): 1309 if 'map' in init_dict: 1310 if not isinstance(cls.map, dict): 1311 raise TypeError("Enum-derived class attribute 'map' " \ 1312 "must be of type dict") 1313 # build list of value strings from map 1314 cls.vals = list(cls.map.keys()) 1315 cls.vals.sort() 1316 elif 'vals' in init_dict: 1317 if not isinstance(cls.vals, list): 1318 raise TypeError("Enum-derived class attribute 'vals' " \ 1319 "must be of type list") 1320 # build string->value map from vals sequence 1321 cls.map = {} 1322 for idx,val in enumerate(cls.vals): 1323 cls.map[val] = idx 1324 else: 1325 raise TypeError("Enum-derived class must define "\ 1326 "attribute 'map' or 'vals'") 1327 1328 if cls.is_class: 1329 cls.cxx_type = '%s' % name 1330 else: 1331 cls.cxx_type = 'Enums::%s' % name 1332 1333 super(MetaEnum, cls).__init__(name, bases, init_dict) 1334 1335 # Generate C++ class declaration for this enum type. 1336 # Note that we wrap the enum in a class/struct to act as a namespace, 1337 # so that the enum strings can be brief w/o worrying about collisions. 1338 def cxx_decl(cls, code): 1339 wrapper_name = cls.wrapper_name 1340 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1341 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1342 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1343 1344 code('''\ 1345#ifndef $idem_macro 1346#define $idem_macro 1347 1348''') 1349 if cls.is_class: 1350 code('''\ 1351enum class $name { 1352''') 1353 else: 1354 code('''\ 1355$wrapper $wrapper_name { 1356 enum $name { 1357''') 1358 code.indent(1) 1359 code.indent(1) 1360 for val in cls.vals: 1361 code('$val = ${{cls.map[val]}},') 1362 code('Num_$name = ${{len(cls.vals)}}') 1363 code.dedent(1) 1364 code('};') 1365 1366 if cls.is_class: 1367 code('''\ 1368extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})]; 1369''') 1370 elif cls.wrapper_is_struct: 1371 code('static const char *${name}Strings[Num_${name}];') 1372 else: 1373 code('extern const char *${name}Strings[Num_${name}];') 1374 1375 if not cls.is_class: 1376 code.dedent(1) 1377 code('};') 1378 1379 code() 1380 code('#endif // $idem_macro') 1381 1382 def cxx_def(cls, code): 1383 wrapper_name = cls.wrapper_name 1384 file_name = cls.__name__ 1385 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1386 1387 code('#include "enums/$file_name.hh"') 1388 if cls.wrapper_is_struct: 1389 code('const char *${wrapper_name}::${name}Strings' 1390 '[Num_${name}] =') 1391 else: 1392 if cls.is_class: 1393 code('''\ 1394const char *${name}Strings[static_cast<int>(${name}::Num_${name})] = 1395''') 1396 else: 1397 code('namespace Enums {') 1398 code.indent(1) 1399 code('const char *${name}Strings[Num_${name}] =') 1400 1401 code('{') 1402 code.indent(1) 1403 for val in cls.vals: 1404 code('"$val",') 1405 code.dedent(1) 1406 code('};') 1407 1408 if not cls.wrapper_is_struct and not cls.is_class: 1409 code.dedent(1) 1410 code('} // namespace $wrapper_name') 1411 1412 1413 def pybind_def(cls, code): 1414 name = cls.__name__ 1415 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1416 wrapper_name = enum_name if cls.is_class else cls.wrapper_name 1417 1418 code('''#include "pybind11/pybind11.h" 1419#include "pybind11/stl.h" 1420 1421#include <sim/init.hh> 1422 1423namespace py = pybind11; 1424 1425static void 1426module_init(py::module &m_internal) 1427{ 1428 py::module m = m_internal.def_submodule("enum_${name}"); 1429 1430''') 1431 if cls.is_class: 1432 code('py::enum_<${enum_name}>(m, "enum_${name}")') 1433 else: 1434 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")') 1435 1436 code.indent() 1437 code.indent() 1438 for val in cls.vals: 1439 code('.value("${val}", ${wrapper_name}::${val})') 1440 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1441 code('.export_values()') 1442 code(';') 1443 code.dedent() 1444 1445 code('}') 1446 code.dedent() 1447 code() 1448 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1449 1450 1451# Base class for enum types. 1452class Enum(ParamValue): 1453 __metaclass__ = MetaEnum 1454 vals = [] 1455 cmd_line_settable = True 1456 1457 # The name of the wrapping namespace or struct 1458 wrapper_name = 'Enums' 1459 1460 # If true, the enum is wrapped in a struct rather than a namespace 1461 wrapper_is_struct = False 1462 1463 is_class = False 1464 1465 # If not None, use this as the enum name rather than this class name 1466 enum_name = None 1467 1468 def __init__(self, value): 1469 if value not in self.map: 1470 raise TypeError("Enum param got bad value '%s' (not in %s)" \ 1471 % (value, self.vals)) 1472 self.value = value 1473 1474 def __call__(self, value): 1475 self.__init__(value) 1476 return value 1477 1478 @classmethod 1479 def cxx_predecls(cls, code): 1480 code('#include "enums/$0.hh"', cls.__name__) 1481 1482 @classmethod 1483 def cxx_ini_parse(cls, code, src, dest, ret): 1484 code('if (false) {') 1485 for elem_name in cls.map.keys(): 1486 code('} else if (%s == "%s") {' % (src, elem_name)) 1487 code.indent() 1488 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1489 code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums', 1490 elem_name)) 1491 code('%s true;' % ret) 1492 code.dedent() 1493 code('} else {') 1494 code(' %s false;' % ret) 1495 code('}') 1496 1497 def getValue(self): 1498 import m5.internal.params 1499 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1500 return e(self.map[self.value]) 1501 1502 def __str__(self): 1503 return self.value 1504 1505# This param will generate a scoped c++ enum and its python bindings. 1506class ScopedEnum(Enum): 1507 __metaclass__ = MetaEnum 1508 vals = [] 1509 cmd_line_settable = True 1510 1511 # The name of the wrapping namespace or struct 1512 wrapper_name = None 1513 1514 # If true, the enum is wrapped in a struct rather than a namespace 1515 wrapper_is_struct = False 1516 1517 # If true, the generated enum is a scoped enum 1518 is_class = True 1519 1520 # If not None, use this as the enum name rather than this class name 1521 enum_name = None 1522 1523# how big does a rounding error need to be before we warn about it? 1524frequency_tolerance = 0.001 # 0.1% 1525 1526class TickParamValue(NumericParamValue): 1527 cxx_type = 'Tick' 1528 ex_str = "1MHz" 1529 cmd_line_settable = True 1530 1531 @classmethod 1532 def cxx_predecls(cls, code): 1533 code('#include "base/types.hh"') 1534 1535 def __call__(self, value): 1536 self.__init__(value) 1537 return value 1538 1539 def getValue(self): 1540 return long(self.value) 1541 1542 @classmethod 1543 def cxx_ini_predecls(cls, code): 1544 code('#include <sstream>') 1545 1546 # Ticks are expressed in seconds in JSON files and in plain 1547 # Ticks in .ini files. Switch based on a config flag 1548 @classmethod 1549 def cxx_ini_parse(self, code, src, dest, ret): 1550 code('${ret} to_number(${src}, ${dest});') 1551 1552class Latency(TickParamValue): 1553 ex_str = "100ns" 1554 1555 def __init__(self, value): 1556 if isinstance(value, (Latency, Clock)): 1557 self.ticks = value.ticks 1558 self.value = value.value 1559 elif isinstance(value, Frequency): 1560 self.ticks = value.ticks 1561 self.value = 1.0 / value.value 1562 elif value.endswith('t'): 1563 self.ticks = True 1564 self.value = int(value[:-1]) 1565 else: 1566 self.ticks = False 1567 self.value = convert.toLatency(value) 1568 1569 def __call__(self, value): 1570 self.__init__(value) 1571 return value 1572 1573 def __getattr__(self, attr): 1574 if attr in ('latency', 'period'): 1575 return self 1576 if attr == 'frequency': 1577 return Frequency(self) 1578 raise AttributeError("Latency object has no attribute '%s'" % attr) 1579 1580 def getValue(self): 1581 if self.ticks or self.value == 0: 1582 value = self.value 1583 else: 1584 value = ticks.fromSeconds(self.value) 1585 return long(value) 1586 1587 def config_value(self): 1588 return self.getValue() 1589 1590 # convert latency to ticks 1591 def ini_str(self): 1592 return '%d' % self.getValue() 1593 1594class Frequency(TickParamValue): 1595 ex_str = "1GHz" 1596 1597 def __init__(self, value): 1598 if isinstance(value, (Latency, Clock)): 1599 if value.value == 0: 1600 self.value = 0 1601 else: 1602 self.value = 1.0 / value.value 1603 self.ticks = value.ticks 1604 elif isinstance(value, Frequency): 1605 self.value = value.value 1606 self.ticks = value.ticks 1607 else: 1608 self.ticks = False 1609 self.value = convert.toFrequency(value) 1610 1611 def __call__(self, value): 1612 self.__init__(value) 1613 return value 1614 1615 def __getattr__(self, attr): 1616 if attr == 'frequency': 1617 return self 1618 if attr in ('latency', 'period'): 1619 return Latency(self) 1620 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1621 1622 # convert latency to ticks 1623 def getValue(self): 1624 if self.ticks or self.value == 0: 1625 value = self.value 1626 else: 1627 value = ticks.fromSeconds(1.0 / self.value) 1628 return long(value) 1629 1630 def config_value(self): 1631 return self.getValue() 1632 1633 def ini_str(self): 1634 return '%d' % self.getValue() 1635 1636# A generic Frequency and/or Latency value. Value is stored as a 1637# latency, just like Latency and Frequency. 1638class Clock(TickParamValue): 1639 def __init__(self, value): 1640 if isinstance(value, (Latency, Clock)): 1641 self.ticks = value.ticks 1642 self.value = value.value 1643 elif isinstance(value, Frequency): 1644 self.ticks = value.ticks 1645 self.value = 1.0 / value.value 1646 elif value.endswith('t'): 1647 self.ticks = True 1648 self.value = int(value[:-1]) 1649 else: 1650 self.ticks = False 1651 self.value = convert.anyToLatency(value) 1652 1653 def __call__(self, value): 1654 self.__init__(value) 1655 return value 1656 1657 def __str__(self): 1658 return "%s" % Latency(self) 1659 1660 def __getattr__(self, attr): 1661 if attr == 'frequency': 1662 return Frequency(self) 1663 if attr in ('latency', 'period'): 1664 return Latency(self) 1665 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1666 1667 def getValue(self): 1668 return self.period.getValue() 1669 1670 def config_value(self): 1671 return self.period.config_value() 1672 1673 def ini_str(self): 1674 return self.period.ini_str() 1675 1676class Voltage(Float): 1677 ex_str = "1V" 1678 1679 def __new__(cls, value): 1680 value = convert.toVoltage(value) 1681 return super(cls, Voltage).__new__(cls, value) 1682 1683 def __init__(self, value): 1684 value = convert.toVoltage(value) 1685 super(Voltage, self).__init__(value) 1686 1687class Current(Float): 1688 ex_str = "1mA" 1689 1690 def __new__(cls, value): 1691 value = convert.toCurrent(value) 1692 return super(cls, Current).__new__(cls, value) 1693 1694 def __init__(self, value): 1695 value = convert.toCurrent(value) 1696 super(Current, self).__init__(value) 1697 1698class Energy(Float): 1699 ex_str = "1pJ" 1700 1701 def __new__(cls, value): 1702 value = convert.toEnergy(value) 1703 return super(cls, Energy).__new__(cls, value) 1704 1705 def __init__(self, value): 1706 value = convert.toEnergy(value) 1707 super(Energy, self).__init__(value) 1708 1709class NetworkBandwidth(float,ParamValue): 1710 cxx_type = 'float' 1711 ex_str = "1Gbps" 1712 cmd_line_settable = True 1713 1714 def __new__(cls, value): 1715 # convert to bits per second 1716 val = convert.toNetworkBandwidth(value) 1717 return super(cls, NetworkBandwidth).__new__(cls, val) 1718 1719 def __str__(self): 1720 return str(self.val) 1721 1722 def __call__(self, value): 1723 val = convert.toNetworkBandwidth(value) 1724 self.__init__(val) 1725 return value 1726 1727 def getValue(self): 1728 # convert to seconds per byte 1729 value = 8.0 / float(self) 1730 # convert to ticks per byte 1731 value = ticks.fromSeconds(value) 1732 return float(value) 1733 1734 def ini_str(self): 1735 return '%f' % self.getValue() 1736 1737 def config_value(self): 1738 return '%f' % self.getValue() 1739 1740 @classmethod 1741 def cxx_ini_predecls(cls, code): 1742 code('#include <sstream>') 1743 1744 @classmethod 1745 def cxx_ini_parse(self, code, src, dest, ret): 1746 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1747 1748class MemoryBandwidth(float,ParamValue): 1749 cxx_type = 'float' 1750 ex_str = "1GB/s" 1751 cmd_line_settable = True 1752 1753 def __new__(cls, value): 1754 # convert to bytes per second 1755 val = convert.toMemoryBandwidth(value) 1756 return super(cls, MemoryBandwidth).__new__(cls, val) 1757 1758 def __call__(self, value): 1759 val = convert.toMemoryBandwidth(value) 1760 self.__init__(val) 1761 return value 1762 1763 def getValue(self): 1764 # convert to seconds per byte 1765 value = float(self) 1766 if value: 1767 value = 1.0 / float(self) 1768 # convert to ticks per byte 1769 value = ticks.fromSeconds(value) 1770 return float(value) 1771 1772 def ini_str(self): 1773 return '%f' % self.getValue() 1774 1775 def config_value(self): 1776 return '%f' % self.getValue() 1777 1778 @classmethod 1779 def cxx_ini_predecls(cls, code): 1780 code('#include <sstream>') 1781 1782 @classmethod 1783 def cxx_ini_parse(self, code, src, dest, ret): 1784 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1785 1786# 1787# "Constants"... handy aliases for various values. 1788# 1789 1790# Special class for NULL pointers. Note the special check in 1791# make_param_value() above that lets these be assigned where a 1792# SimObject is required. 1793# only one copy of a particular node 1794class NullSimObject(object): 1795 __metaclass__ = Singleton 1796 _name = 'Null' 1797 1798 def __call__(cls): 1799 return cls 1800 1801 def _instantiate(self, parent = None, path = ''): 1802 pass 1803 1804 def ini_str(self): 1805 return 'Null' 1806 1807 def unproxy(self, base): 1808 return self 1809 1810 def set_path(self, parent, name): 1811 pass 1812 1813 def set_parent(self, parent, name): 1814 pass 1815 1816 def clear_parent(self, old_parent): 1817 pass 1818 1819 def descendants(self): 1820 return 1821 yield None 1822 1823 def get_config_as_dict(self): 1824 return {} 1825 1826 def __str__(self): 1827 return self._name 1828 1829 def config_value(self): 1830 return None 1831 1832 def getValue(self): 1833 return None 1834 1835# The only instance you'll ever need... 1836NULL = NullSimObject() 1837 1838def isNullPointer(value): 1839 return isinstance(value, NullSimObject) 1840 1841# Some memory range specifications use this as a default upper bound. 1842MaxAddr = Addr.max 1843MaxTick = Tick.max 1844AllMemory = AddrRange(0, MaxAddr) 1845 1846 1847##################################################################### 1848# 1849# Port objects 1850# 1851# Ports are used to interconnect objects in the memory system. 1852# 1853##################################################################### 1854 1855# Port reference: encapsulates a reference to a particular port on a 1856# particular SimObject. 1857class PortRef(object): 1858 def __init__(self, simobj, name, role, is_source): 1859 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1860 self.simobj = simobj 1861 self.name = name 1862 self.role = role 1863 self.is_source = is_source 1864 self.peer = None # not associated with another port yet 1865 self.ccConnected = False # C++ port connection done? 1866 self.index = -1 # always -1 for non-vector ports 1867 1868 def __str__(self): 1869 return '%s.%s' % (self.simobj, self.name) 1870 1871 def __len__(self): 1872 # Return the number of connected ports, i.e. 0 is we have no 1873 # peer and 1 if we do. 1874 return int(self.peer != None) 1875 1876 # for config.ini, print peer's name (not ours) 1877 def ini_str(self): 1878 return str(self.peer) 1879 1880 # for config.json 1881 def get_config_as_dict(self): 1882 return {'role' : self.role, 'peer' : str(self.peer), 1883 'is_source' : str(self.is_source)} 1884 1885 def __getattr__(self, attr): 1886 if attr == 'peerObj': 1887 # shorthand for proxies 1888 return self.peer.simobj 1889 raise AttributeError("'%s' object has no attribute '%s'" % \ 1890 (self.__class__.__name__, attr)) 1891 1892 # Full connection is symmetric (both ways). Called via 1893 # SimObject.__setattr__ as a result of a port assignment, e.g., 1894 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1895 # e.g., "obj1.portA[3] = obj2.portB". 1896 def connect(self, other): 1897 if isinstance(other, VectorPortRef): 1898 # reference to plain VectorPort is implicit append 1899 other = other._get_next() 1900 if self.peer and not proxy.isproxy(self.peer): 1901 fatal("Port %s is already connected to %s, cannot connect %s\n", 1902 self, self.peer, other); 1903 self.peer = other 1904 1905 if proxy.isproxy(other): 1906 other.set_param_desc(PortParamDesc()) 1907 return 1908 elif not isinstance(other, PortRef): 1909 raise TypeError("assigning non-port reference '%s' to port '%s'" \ 1910 % (other, self)) 1911 1912 if not Port.is_compat(self, other): 1913 fatal("Ports %s and %s with roles '%s' and '%s' " 1914 "are not compatible", self, other, self.role, other.role) 1915 1916 if other.peer is not self: 1917 other.connect(self) 1918 1919 # Allow a compatible port pair to be spliced between a port and its 1920 # connected peer. Useful operation for connecting instrumentation 1921 # structures into a system when it is necessary to connect the 1922 # instrumentation after the full system has been constructed. 1923 def splice(self, new_1, new_2): 1924 if not self.peer or proxy.isproxy(self.peer): 1925 fatal("Port %s not connected, cannot splice in new peers\n", self) 1926 1927 if not isinstance(new_1, PortRef) or not isinstance(new_2, PortRef): 1928 raise TypeError( 1929 "Splicing non-port references '%s','%s' to port '%s'" % \ 1930 (new_1, new_2, self)) 1931 1932 old_peer = self.peer 1933 1934 if Port.is_compat(old_peer, new_1) and Port.is_compat(self, new_2): 1935 old_peer.peer = new_1 1936 new_1.peer = old_peer 1937 self.peer = new_2 1938 new_2.peer = self 1939 elif Port.is_compat(old_peer, new_2) and Port.is_compat(self, new_1): 1940 old_peer.peer = new_2 1941 new_2.peer = old_peer 1942 self.peer = new_1 1943 new_1.peer = self 1944 else: 1945 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with " 1946 "%s(%s) and %s(%s)", self, self.role, 1947 old_peer, old_peer.role, new_1, new_1.role, 1948 new_2, new_2.role) 1949 1950 def clone(self, simobj, memo): 1951 if self in memo: 1952 return memo[self] 1953 newRef = copy.copy(self) 1954 memo[self] = newRef 1955 newRef.simobj = simobj 1956 assert(isSimObject(newRef.simobj)) 1957 if self.peer and not proxy.isproxy(self.peer): 1958 peerObj = self.peer.simobj(_memo=memo) 1959 newRef.peer = self.peer.clone(peerObj, memo) 1960 assert(not isinstance(newRef.peer, VectorPortRef)) 1961 return newRef 1962 1963 def unproxy(self, simobj): 1964 assert(simobj is self.simobj) 1965 if proxy.isproxy(self.peer): 1966 try: 1967 realPeer = self.peer.unproxy(self.simobj) 1968 except: 1969 print("Error in unproxying port '%s' of %s" % 1970 (self.name, self.simobj.path())) 1971 raise 1972 self.connect(realPeer) 1973 1974 # Call C++ to create corresponding port connection between C++ objects 1975 def ccConnect(self): 1976 if self.ccConnected: # already done this 1977 return 1978 1979 peer = self.peer 1980 if not self.peer: # nothing to connect to 1981 return 1982 1983 port = self.simobj.getPort(self.name, self.index) 1984 peer_port = peer.simobj.getPort(peer.name, peer.index) 1985 port.bind(peer_port) 1986 1987 self.ccConnected = True 1988 1989# A reference to an individual element of a VectorPort... much like a 1990# PortRef, but has an index. 1991class VectorPortElementRef(PortRef): 1992 def __init__(self, simobj, name, role, is_source, index): 1993 PortRef.__init__(self, simobj, name, role, is_source) 1994 self.index = index 1995 1996 def __str__(self): 1997 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1998 1999# A reference to a complete vector-valued port (not just a single element). 2000# Can be indexed to retrieve individual VectorPortElementRef instances. 2001class VectorPortRef(object): 2002 def __init__(self, simobj, name, role, is_source): 2003 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 2004 self.simobj = simobj 2005 self.name = name 2006 self.role = role 2007 self.is_source = is_source 2008 self.elements = [] 2009 2010 def __str__(self): 2011 return '%s.%s[:]' % (self.simobj, self.name) 2012 2013 def __len__(self): 2014 # Return the number of connected peers, corresponding the the 2015 # length of the elements. 2016 return len(self.elements) 2017 2018 # for config.ini, print peer's name (not ours) 2019 def ini_str(self): 2020 return ' '.join([el.ini_str() for el in self.elements]) 2021 2022 # for config.json 2023 def get_config_as_dict(self): 2024 return {'role' : self.role, 2025 'peer' : [el.ini_str() for el in self.elements], 2026 'is_source' : str(self.is_source)} 2027 2028 def __getitem__(self, key): 2029 if not isinstance(key, int): 2030 raise TypeError("VectorPort index must be integer") 2031 if key >= len(self.elements): 2032 # need to extend list 2033 ext = [VectorPortElementRef( 2034 self.simobj, self.name, self.role, self.is_source, i) 2035 for i in range(len(self.elements), key+1)] 2036 self.elements.extend(ext) 2037 return self.elements[key] 2038 2039 def _get_next(self): 2040 return self[len(self.elements)] 2041 2042 def __setitem__(self, key, value): 2043 if not isinstance(key, int): 2044 raise TypeError("VectorPort index must be integer") 2045 self[key].connect(value) 2046 2047 def connect(self, other): 2048 if isinstance(other, (list, tuple)): 2049 # Assign list of port refs to vector port. 2050 # For now, append them... not sure if that's the right semantics 2051 # or if it should replace the current vector. 2052 for ref in other: 2053 self._get_next().connect(ref) 2054 else: 2055 # scalar assignment to plain VectorPort is implicit append 2056 self._get_next().connect(other) 2057 2058 def clone(self, simobj, memo): 2059 if self in memo: 2060 return memo[self] 2061 newRef = copy.copy(self) 2062 memo[self] = newRef 2063 newRef.simobj = simobj 2064 assert(isSimObject(newRef.simobj)) 2065 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 2066 return newRef 2067 2068 def unproxy(self, simobj): 2069 [el.unproxy(simobj) for el in self.elements] 2070 2071 def ccConnect(self): 2072 [el.ccConnect() for el in self.elements] 2073 2074# Port description object. Like a ParamDesc object, this represents a 2075# logical port in the SimObject class, not a particular port on a 2076# SimObject instance. The latter are represented by PortRef objects. 2077class Port(object): 2078 # Port("role", "description") 2079 2080 _compat_dict = { } 2081 2082 @classmethod 2083 def compat(cls, role, peer): 2084 cls._compat_dict.setdefault(role, set()).add(peer) 2085 cls._compat_dict.setdefault(peer, set()).add(role) 2086 2087 @classmethod 2088 def is_compat(cls, one, two): 2089 for port in one, two: 2090 if not port.role in Port._compat_dict: 2091 fatal("Unrecognized role '%s' for port %s\n", port.role, port) 2092 return one.role in Port._compat_dict[two.role] 2093 2094 def __init__(self, role, desc, is_source=False): 2095 self.desc = desc 2096 self.role = role 2097 self.is_source = is_source 2098 2099 # Generate a PortRef for this port on the given SimObject with the 2100 # given name 2101 def makeRef(self, simobj): 2102 return PortRef(simobj, self.name, self.role, self.is_source) 2103 2104 # Connect an instance of this port (on the given SimObject with 2105 # the given name) with the port described by the supplied PortRef 2106 def connect(self, simobj, ref): 2107 self.makeRef(simobj).connect(ref) 2108 2109 # No need for any pre-declarations at the moment as we merely rely 2110 # on an unsigned int. 2111 def cxx_predecls(self, code): 2112 pass 2113 2114 def pybind_predecls(self, code): 2115 cls.cxx_predecls(self, code) 2116 2117 # Declare an unsigned int with the same name as the port, that 2118 # will eventually hold the number of connected ports (and thus the 2119 # number of elements for a VectorPort). 2120 def cxx_decl(self, code): 2121 code('unsigned int port_${{self.name}}_connection_count;') 2122 2123Port.compat('GEM5 REQUESTER', 'GEM5 RESPONDER') 2124 2125class RequestPort(Port): 2126 # RequestPort("description") 2127 def __init__(self, desc): 2128 super(RequestPort, self).__init__( 2129 'GEM5 REQUESTER', desc, is_source=True) 2130 2131class ResponsePort(Port): 2132 # ResponsePort("description") 2133 def __init__(self, desc): 2134 super(ResponsePort, self).__init__('GEM5 RESPONDER', desc) 2135 2136# VectorPort description object. Like Port, but represents a vector 2137# of connections (e.g., as on a XBar). 2138class VectorPort(Port): 2139 def makeRef(self, simobj): 2140 return VectorPortRef(simobj, self.name, self.role, self.is_source) 2141 2142class VectorRequestPort(VectorPort): 2143 # VectorRequestPort("description") 2144 def __init__(self, desc): 2145 super(VectorRequestPort, self).__init__( 2146 'GEM5 REQUESTER', desc, is_source=True) 2147 2148class VectorResponsePort(VectorPort): 2149 # VectorResponsePort("description") 2150 def __init__(self, desc): 2151 super(VectorResponsePort, self).__init__('GEM5 RESPONDER', desc) 2152 2153# Old names, maintained for compatibility. 2154MasterPort = RequestPort 2155SlavePort = ResponsePort 2156VectorMasterPort = VectorRequestPort 2157VectorSlavePort = VectorResponsePort 2158 2159# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2160# proxy objects (via set_param_desc()) so that proxy error messages 2161# make sense. 2162class PortParamDesc(object): 2163 __metaclass__ = Singleton 2164 2165 ptype_str = 'Port' 2166 ptype = Port 2167 2168baseEnums = allEnums.copy() 2169baseParams = allParams.copy() 2170 2171def clear(): 2172 global allEnums, allParams 2173 2174 allEnums = baseEnums.copy() 2175 allParams = baseParams.copy() 2176 2177__all__ = ['Param', 'VectorParam', 2178 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float', 2179 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2180 'Int32', 'UInt32', 'Int64', 'UInt64', 2181 'Counter', 'Addr', 'Tick', 'Percent', 2182 'TcpPort', 'UdpPort', 'EthernetAddr', 2183 'IpAddress', 'IpNetmask', 'IpWithPort', 2184 'MemorySize', 'MemorySize32', 2185 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy', 2186 'NetworkBandwidth', 'MemoryBandwidth', 2187 'AddrRange', 2188 'MaxAddr', 'MaxTick', 'AllMemory', 2189 'Time', 2190 'NextEthernetAddr', 'NULL', 2191 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort', 2192 'VectorPort', 'VectorRequestPort', 'VectorResponsePort', 2193 'VectorMasterPort', 'VectorSlavePort'] 2194