params.py revision 10267
110037SARM gem5 Developers# Copyright (c) 2012-2013 ARM Limited 210037SARM gem5 Developers# All rights reserved. 312359Snikos.nikoleris@arm.com# 410037SARM gem5 Developers# The license below extends only to copyright in the software and shall 510037SARM gem5 Developers# not be construed as granting a license to any other intellectual 610037SARM gem5 Developers# property including but not limited to intellectual property relating 710037SARM gem5 Developers# to a hardware implementation of the functionality of the software 810037SARM gem5 Developers# licensed hereunder. You may use the software subject to the license 910037SARM gem5 Developers# terms below provided that you ensure that this notice is replicated 1010037SARM gem5 Developers# unmodified and in its entirety in all distributions of the software, 1110037SARM gem5 Developers# modified or unmodified, in source code or in binary form. 1210037SARM gem5 Developers# 1310037SARM gem5 Developers# Copyright (c) 2004-2006 The Regents of The University of Michigan 1410037SARM gem5 Developers# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 1510037SARM gem5 Developers# All rights reserved. 1610037SARM gem5 Developers# 1710037SARM gem5 Developers# Redistribution and use in source and binary forms, with or without 1810037SARM gem5 Developers# modification, are permitted provided that the following conditions are 1910037SARM gem5 Developers# met: redistributions of source code must retain the above copyright 2010037SARM gem5 Developers# notice, this list of conditions and the following disclaimer; 2110037SARM gem5 Developers# redistributions in binary form must reproduce the above copyright 2210037SARM gem5 Developers# notice, this list of conditions and the following disclaimer in the 2310037SARM gem5 Developers# documentation and/or other materials provided with the distribution; 2410037SARM gem5 Developers# neither the name of the copyright holders nor the names of its 2510037SARM gem5 Developers# contributors may be used to endorse or promote products derived from 2610037SARM gem5 Developers# this software without specific prior written permission. 2710037SARM gem5 Developers# 2810037SARM gem5 Developers# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2910037SARM gem5 Developers# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3010037SARM gem5 Developers# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3110037SARM gem5 Developers# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3210037SARM gem5 Developers# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3310037SARM gem5 Developers# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3410037SARM gem5 Developers# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3510037SARM gem5 Developers# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3610037SARM gem5 Developers# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3710037SARM gem5 Developers# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3810037SARM gem5 Developers# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3910037SARM gem5 Developers# 4010037SARM gem5 Developers# Authors: Steve Reinhardt 4110037SARM gem5 Developers# Nathan Binkert 4210037SARM gem5 Developers# Gabe Black 4310037SARM gem5 Developers# Andreas Hansson 4410037SARM gem5 Developers 4510037SARM gem5 Developers##################################################################### 4610037SARM gem5 Developers# 4710037SARM gem5 Developers# Parameter description classes 4810037SARM gem5 Developers# 4910037SARM gem5 Developers# The _params dictionary in each class maps parameter names to either 5010037SARM gem5 Developers# a Param or a VectorParam object. These objects contain the 5110037SARM gem5 Developers# parameter description string, the parameter type, and the default 5210037SARM gem5 Developers# value (if any). The convert() method on these objects is used to 5311862Snikos.nikoleris@arm.com# force whatever value is assigned to the parameter to the appropriate 5410037SARM gem5 Developers# type. 5510037SARM gem5 Developers# 5610037SARM gem5 Developers# Note that the default values are loaded into the class's attribute 5710037SARM gem5 Developers# space when the parameter dictionary is initialized (in 5810037SARM gem5 Developers# MetaSimObject._new_param()); after that point they aren't used. 5910037SARM gem5 Developers# 6010037SARM gem5 Developers##################################################################### 6110037SARM gem5 Developers 6210037SARM gem5 Developersimport copy 6310037SARM gem5 Developersimport datetime 6410037SARM gem5 Developersimport re 6510037SARM gem5 Developersimport sys 6610037SARM gem5 Developersimport time 6710037SARM gem5 Developersimport math 6810037SARM gem5 Developers 6910037SARM gem5 Developersimport proxy 7010037SARM gem5 Developersimport ticks 7110037SARM gem5 Developersfrom util import * 7210037SARM gem5 Developers 7310037SARM gem5 Developersdef isSimObject(*args, **kwargs): 7410037SARM gem5 Developers return SimObject.isSimObject(*args, **kwargs) 7510037SARM gem5 Developers 7610037SARM gem5 Developersdef isSimObjectSequence(*args, **kwargs): 7710037SARM gem5 Developers return SimObject.isSimObjectSequence(*args, **kwargs) 7810037SARM gem5 Developers 7910037SARM gem5 Developersdef isSimObjectClass(*args, **kwargs): 8010037SARM gem5 Developers return SimObject.isSimObjectClass(*args, **kwargs) 8110037SARM gem5 Developers 8210037SARM gem5 DevelopersallParams = {} 8310037SARM gem5 Developers 8410037SARM gem5 Developersclass MetaParamValue(type): 8510037SARM gem5 Developers def __new__(mcls, name, bases, dct): 8610037SARM gem5 Developers cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 8710037SARM gem5 Developers assert name not in allParams 8810037SARM gem5 Developers allParams[name] = cls 8910037SARM gem5 Developers return cls 9010037SARM gem5 Developers 9110037SARM gem5 Developers 9210037SARM gem5 Developers# Dummy base class to identify types that are legitimate for SimObject 9310037SARM gem5 Developers# parameters. 9410037SARM gem5 Developersclass ParamValue(object): 9510037SARM gem5 Developers __metaclass__ = MetaParamValue 9610037SARM gem5 Developers cmd_line_settable = False 9710037SARM gem5 Developers 9810037SARM gem5 Developers # Generate the code needed as a prerequisite for declaring a C++ 9910037SARM gem5 Developers # object of this type. Typically generates one or more #include 10010037SARM gem5 Developers # statements. Used when declaring parameters of this type. 10110037SARM gem5 Developers @classmethod 10210037SARM gem5 Developers def cxx_predecls(cls, code): 10310037SARM gem5 Developers pass 10410037SARM gem5 Developers 10510037SARM gem5 Developers # Generate the code needed as a prerequisite for including a 10610037SARM gem5 Developers # reference to a C++ object of this type in a SWIG .i file. 10710037SARM gem5 Developers # Typically generates one or more %import or %include statements. 10810037SARM gem5 Developers @classmethod 10910037SARM gem5 Developers def swig_predecls(cls, code): 11010037SARM gem5 Developers pass 11110037SARM gem5 Developers 11210037SARM gem5 Developers # default for printing to .ini file is regular string conversion. 11310037SARM gem5 Developers # will be overridden in some cases 11410037SARM gem5 Developers def ini_str(self): 11510037SARM gem5 Developers return str(self) 11610037SARM gem5 Developers 11710037SARM gem5 Developers # allows us to blithely call unproxy() on things without checking 11810037SARM gem5 Developers # if they're really proxies or not 11910037SARM gem5 Developers def unproxy(self, base): 12010037SARM gem5 Developers return self 12110037SARM gem5 Developers 12210037SARM gem5 Developers # Produce a human readable version of the stored value 12310037SARM gem5 Developers def pretty_print(self, value): 12410037SARM gem5 Developers return str(value) 12510037SARM gem5 Developers 12610037SARM gem5 Developers# Regular parameter description. 12710037SARM gem5 Developersclass ParamDesc(object): 12810037SARM gem5 Developers def __init__(self, ptype_str, ptype, *args, **kwargs): 12910037SARM gem5 Developers self.ptype_str = ptype_str 13010037SARM gem5 Developers # remember ptype only if it is provided 13110037SARM gem5 Developers if ptype != None: 13210037SARM gem5 Developers self.ptype = ptype 13310037SARM gem5 Developers 13410037SARM gem5 Developers if args: 13510037SARM gem5 Developers if len(args) == 1: 13610037SARM gem5 Developers self.desc = args[0] 13710037SARM gem5 Developers elif len(args) == 2: 13810037SARM gem5 Developers self.default = args[0] 13910037SARM gem5 Developers self.desc = args[1] 14010037SARM gem5 Developers else: 14110037SARM gem5 Developers raise TypeError, 'too many arguments' 14210037SARM gem5 Developers 14310037SARM gem5 Developers if kwargs.has_key('desc'): 14410037SARM gem5 Developers assert(not hasattr(self, 'desc')) 14510037SARM gem5 Developers self.desc = kwargs['desc'] 14610037SARM gem5 Developers del kwargs['desc'] 14710037SARM gem5 Developers 14810037SARM gem5 Developers if kwargs.has_key('default'): 14910037SARM gem5 Developers assert(not hasattr(self, 'default')) 15010037SARM gem5 Developers self.default = kwargs['default'] 15110037SARM gem5 Developers del kwargs['default'] 15210037SARM gem5 Developers 15310037SARM gem5 Developers if kwargs: 15410037SARM gem5 Developers raise TypeError, 'extra unknown kwargs %s' % kwargs 15510037SARM gem5 Developers 15610037SARM gem5 Developers if not hasattr(self, 'desc'): 15710037SARM gem5 Developers raise TypeError, 'desc attribute missing' 15810037SARM gem5 Developers 15910037SARM gem5 Developers def __getattr__(self, attr): 16010037SARM gem5 Developers if attr == 'ptype': 16110037SARM gem5 Developers ptype = SimObject.allClasses[self.ptype_str] 16210037SARM gem5 Developers assert isSimObjectClass(ptype) 16310037SARM gem5 Developers self.ptype = ptype 16410037SARM gem5 Developers return ptype 16510037SARM gem5 Developers 16610037SARM gem5 Developers raise AttributeError, "'%s' object has no attribute '%s'" % \ 16710037SARM gem5 Developers (type(self).__name__, attr) 16810037SARM gem5 Developers 16910037SARM gem5 Developers def example_str(self): 17010037SARM gem5 Developers if hasattr(self.ptype, "ex_str"): 17110037SARM gem5 Developers return self.ptype.ex_str 17210037SARM gem5 Developers else: 17310037SARM gem5 Developers return self.ptype_str 17410037SARM gem5 Developers 17510037SARM gem5 Developers # Is the param available to be exposed on the command line 17610037SARM gem5 Developers def isCmdLineSettable(self): 17710037SARM gem5 Developers if hasattr(self.ptype, "cmd_line_settable"): 17810037SARM gem5 Developers return self.ptype.cmd_line_settable 17910037SARM gem5 Developers else: 18010037SARM gem5 Developers return False 18110037SARM gem5 Developers 18210037SARM gem5 Developers def convert(self, value): 18310037SARM gem5 Developers if isinstance(value, proxy.BaseProxy): 18410037SARM gem5 Developers value.set_param_desc(self) 18510037SARM gem5 Developers return value 18610037SARM gem5 Developers if not hasattr(self, 'ptype') and isNullPointer(value): 18710037SARM gem5 Developers # deferred evaluation of SimObject; continue to defer if 18810037SARM gem5 Developers # we're just assigning a null pointer 18910037SARM gem5 Developers return value 19010037SARM gem5 Developers if isinstance(value, self.ptype): 19110037SARM gem5 Developers return value 19210037SARM gem5 Developers if isNullPointer(value) and isSimObjectClass(self.ptype): 19310037SARM gem5 Developers return value 19410037SARM gem5 Developers return self.ptype(value) 19510037SARM gem5 Developers 19610037SARM gem5 Developers def pretty_print(self, value): 19710037SARM gem5 Developers if isinstance(value, proxy.BaseProxy): 19810037SARM gem5 Developers return str(value) 19910037SARM gem5 Developers if isNullPointer(value): 20010037SARM gem5 Developers return NULL 20110037SARM gem5 Developers return self.ptype(value).pretty_print(value) 20210037SARM gem5 Developers 20310037SARM gem5 Developers def cxx_predecls(self, code): 20410037SARM gem5 Developers code('#include <cstddef>') 20510037SARM gem5 Developers self.ptype.cxx_predecls(code) 20610037SARM gem5 Developers 20710037SARM gem5 Developers def swig_predecls(self, code): 20810037SARM gem5 Developers self.ptype.swig_predecls(code) 20910037SARM gem5 Developers 21010037SARM gem5 Developers def cxx_decl(self, code): 21110037SARM gem5 Developers code('${{self.ptype.cxx_type}} ${{self.name}};') 21210037SARM gem5 Developers 21310037SARM gem5 Developers# Vector-valued parameter description. Just like ParamDesc, except 21410037SARM gem5 Developers# that the value is a vector (list) of the specified type instead of a 21510037SARM gem5 Developers# single value. 21610037SARM gem5 Developers 21710037SARM gem5 Developersclass VectorParamValue(list): 21810037SARM gem5 Developers __metaclass__ = MetaParamValue 21910037SARM gem5 Developers def __setattr__(self, attr, value): 22010037SARM gem5 Developers raise AttributeError, \ 22110037SARM gem5 Developers "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 22210037SARM gem5 Developers 22310037SARM gem5 Developers def ini_str(self): 22410037SARM gem5 Developers return ' '.join([v.ini_str() for v in self]) 22510037SARM gem5 Developers 22610037SARM gem5 Developers def getValue(self): 22710037SARM gem5 Developers return [ v.getValue() for v in self ] 22810037SARM gem5 Developers 22912258Sgiacomo.travaglini@arm.com def unproxy(self, base): 23012258Sgiacomo.travaglini@arm.com if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 23112258Sgiacomo.travaglini@arm.com return self[0].unproxy(base) 23212258Sgiacomo.travaglini@arm.com else: 23312258Sgiacomo.travaglini@arm.com return [v.unproxy(base) for v in self] 23412258Sgiacomo.travaglini@arm.com 23512258Sgiacomo.travaglini@arm.comclass SimObjectVector(VectorParamValue): 23612258Sgiacomo.travaglini@arm.com # support clone operation 23712258Sgiacomo.travaglini@arm.com def __call__(self, **kwargs): 23812258Sgiacomo.travaglini@arm.com return SimObjectVector([v(**kwargs) for v in self]) 23912258Sgiacomo.travaglini@arm.com 24012258Sgiacomo.travaglini@arm.com def clear_parent(self, old_parent): 24112258Sgiacomo.travaglini@arm.com for v in self: 24212258Sgiacomo.travaglini@arm.com v.clear_parent(old_parent) 24312258Sgiacomo.travaglini@arm.com 24412258Sgiacomo.travaglini@arm.com def set_parent(self, parent, name): 24512258Sgiacomo.travaglini@arm.com if len(self) == 1: 24612258Sgiacomo.travaglini@arm.com self[0].set_parent(parent, name) 24712258Sgiacomo.travaglini@arm.com else: 24812258Sgiacomo.travaglini@arm.com width = int(math.ceil(math.log(len(self))/math.log(10))) 24912258Sgiacomo.travaglini@arm.com for i,v in enumerate(self): 25012258Sgiacomo.travaglini@arm.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 25112258Sgiacomo.travaglini@arm.com 25212258Sgiacomo.travaglini@arm.com def has_parent(self): 25312258Sgiacomo.travaglini@arm.com return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 25412258Sgiacomo.travaglini@arm.com 25512258Sgiacomo.travaglini@arm.com # return 'cpu0 cpu1' etc. for print_ini() 25612258Sgiacomo.travaglini@arm.com def get_name(self): 25712258Sgiacomo.travaglini@arm.com return ' '.join([v._name for v in self]) 25812258Sgiacomo.travaglini@arm.com 25912258Sgiacomo.travaglini@arm.com # By iterating through the constituent members of the vector here 26012258Sgiacomo.travaglini@arm.com # we can nicely handle iterating over all a SimObject's children 26112258Sgiacomo.travaglini@arm.com # without having to provide lots of special functions on 26212258Sgiacomo.travaglini@arm.com # SimObjectVector directly. 26312258Sgiacomo.travaglini@arm.com def descendants(self): 26412258Sgiacomo.travaglini@arm.com for v in self: 26510037SARM gem5 Developers for obj in v.descendants(): 26610037SARM gem5 Developers yield obj 26710037SARM gem5 Developers 26810037SARM gem5 Developers def get_config_as_dict(self): 26910037SARM gem5 Developers a = [] 27010037SARM gem5 Developers for v in self: 27110037SARM gem5 Developers a.append(v.get_config_as_dict()) 27210037SARM gem5 Developers return a 27310037SARM gem5 Developers 27410037SARM gem5 Developers # If we are replacing an item in the vector, make sure to set the 27510037SARM gem5 Developers # parent reference of the new SimObject to be the same as the parent 27610037SARM gem5 Developers # of the SimObject being replaced. Useful to have if we created 27710037SARM gem5 Developers # a SimObjectVector of temporary objects that will be modified later in 27810037SARM gem5 Developers # configuration scripts. 27910037SARM gem5 Developers def __setitem__(self, key, value): 28010037SARM gem5 Developers val = self[key] 28110037SARM gem5 Developers if value.has_parent(): 28210037SARM gem5 Developers warn("SimObject %s already has a parent" % value.get_name() +\ 28310037SARM gem5 Developers " that is being overwritten by a SimObjectVector") 28410037SARM gem5 Developers value.set_parent(val.get_parent(), val._name) 28510037SARM gem5 Developers super(SimObjectVector, self).__setitem__(key, value) 28610037SARM gem5 Developers 28712227Sgiacomo.travaglini@arm.com # Enumerate the params of each member of the SimObject vector. Creates 28810037SARM gem5 Developers # strings that will allow indexing into the vector by the python code and 28910037SARM gem5 Developers # allow it to be specified on the command line. 29010037SARM gem5 Developers def enumerateParams(self, flags_dict = {}, 29110037SARM gem5 Developers cmd_line_str = "", 29210037SARM gem5 Developers access_str = ""): 29310037SARM gem5 Developers if hasattr(self, "_paramEnumed"): 29410037SARM gem5 Developers print "Cycle detected enumerating params at %s?!" % (cmd_line_str) 29510037SARM gem5 Developers else: 29610037SARM gem5 Developers x = 0 29710037SARM gem5 Developers for vals in self: 29810037SARM gem5 Developers # Each entry in the SimObjectVector should be an 29910037SARM gem5 Developers # instance of a SimObject 30010037SARM gem5 Developers flags_dict = vals.enumerateParams(flags_dict, 30110037SARM gem5 Developers cmd_line_str + "%d." % x, 30210037SARM gem5 Developers access_str + "[%d]." % x) 30310037SARM gem5 Developers x = x + 1 30410037SARM gem5 Developers 30510037SARM gem5 Developers return flags_dict 30610037SARM gem5 Developers 30710037SARM gem5 Developersclass VectorParamDesc(ParamDesc): 30810037SARM gem5 Developers # Convert assigned value to appropriate type. If the RHS is not a 30910037SARM gem5 Developers # list or tuple, it generates a single-element list. 31010037SARM gem5 Developers def convert(self, value): 31110037SARM gem5 Developers if isinstance(value, (list, tuple)): 31210037SARM gem5 Developers # list: coerce each element into new list 31310037SARM gem5 Developers tmp_list = [ ParamDesc.convert(self, v) for v in value ] 31410037SARM gem5 Developers else: 31510037SARM gem5 Developers # singleton: coerce to a single-element list 31610037SARM gem5 Developers tmp_list = [ ParamDesc.convert(self, value) ] 31710037SARM gem5 Developers 31810037SARM gem5 Developers if isSimObjectSequence(tmp_list): 31910037SARM gem5 Developers return SimObjectVector(tmp_list) 32012359Snikos.nikoleris@arm.com else: 32112359Snikos.nikoleris@arm.com return VectorParamValue(tmp_list) 32210037SARM gem5 Developers 32310474Sandreas.hansson@arm.com # Produce a human readable example string that describes 32410474Sandreas.hansson@arm.com # how to set this vector parameter in the absence of a default 32510205SAli.Saidi@ARM.com # value. 32610474Sandreas.hansson@arm.com def example_str(self): 32710474Sandreas.hansson@arm.com s = super(VectorParamDesc, self).example_str() 32810037SARM gem5 Developers help_str = "[" + s + "," + s + ", ...]" 32910037SARM gem5 Developers return help_str 33010037SARM gem5 Developers 33110037SARM gem5 Developers # Produce a human readable representation of the value of this vector param. 33210474Sandreas.hansson@arm.com def pretty_print(self, value): 33310474Sandreas.hansson@arm.com if isinstance(value, (list, tuple)): 33410037SARM gem5 Developers tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 33510037SARM gem5 Developers elif isinstance(value, str): 33610037SARM gem5 Developers tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 33710037SARM gem5 Developers else: 33810037SARM gem5 Developers tmp_list = [ ParamDesc.pretty_print(self, value) ] 33911582SDylan.Johnson@ARM.com 34010474Sandreas.hansson@arm.com return tmp_list 34110474Sandreas.hansson@arm.com 34210037SARM gem5 Developers # This is a helper function for the new config system 34310037SARM gem5 Developers def __call__(self, value): 34410037SARM gem5 Developers if isinstance(value, (list, tuple)): 34510037SARM gem5 Developers # list: coerce each element into new list 34610037SARM gem5 Developers tmp_list = [ ParamDesc.convert(self, v) for v in value ] 34710037SARM gem5 Developers elif isinstance(value, str): 34810474Sandreas.hansson@arm.com # If input is a csv string 34910474Sandreas.hansson@arm.com tmp_list = [ ParamDesc.convert(self, v) for v in value.split(',') ] 35010037SARM gem5 Developers else: 35110037SARM gem5 Developers # singleton: coerce to a single-element list 35210037SARM gem5 Developers tmp_list = [ ParamDesc.convert(self, value) ] 35310037SARM gem5 Developers 35410037SARM gem5 Developers return VectorParamValue(tmp_list) 35512280Sgiacomo.travaglini@arm.com 35610037SARM gem5 Developers def swig_module_name(self): 35712106SRekai.GonzalezAlberquilla@arm.com return "%s_vector" % self.ptype_str 35810037SARM gem5 Developers 35910037SARM gem5 Developers def swig_predecls(self, code): 36010037SARM gem5 Developers code('%import "${{self.swig_module_name()}}.i"') 36110037SARM gem5 Developers 36212280Sgiacomo.travaglini@arm.com def swig_decl(self, code): 36312280Sgiacomo.travaglini@arm.com code('%module(package="m5.internal") ${{self.swig_module_name()}}') 36412280Sgiacomo.travaglini@arm.com code('%{') 36512280Sgiacomo.travaglini@arm.com self.ptype.cxx_predecls(code) 36612280Sgiacomo.travaglini@arm.com code('%}') 36712280Sgiacomo.travaglini@arm.com code() 36812280Sgiacomo.travaglini@arm.com # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 36912280Sgiacomo.travaglini@arm.com code('%include "std_container.i"') 37010037SARM gem5 Developers code() 37110037SARM gem5 Developers self.ptype.swig_predecls(code) 37210037SARM gem5 Developers code() 37310037SARM gem5 Developers code('%include "std_vector.i"') 37410037SARM gem5 Developers code() 37510037SARM gem5 Developers 37610037SARM gem5 Developers ptype = self.ptype_str 37710037SARM gem5 Developers cxx_type = self.ptype.cxx_type 37810037SARM gem5 Developers 37912280Sgiacomo.travaglini@arm.com code('%template(vector_$ptype) std::vector< $cxx_type >;') 38010037SARM gem5 Developers 38112106SRekai.GonzalezAlberquilla@arm.com def cxx_predecls(self, code): 38210037SARM gem5 Developers code('#include <vector>') 38310037SARM gem5 Developers self.ptype.cxx_predecls(code) 38410037SARM gem5 Developers 38510037SARM gem5 Developers def cxx_decl(self, code): 38612280Sgiacomo.travaglini@arm.com code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 38712280Sgiacomo.travaglini@arm.com 38812280Sgiacomo.travaglini@arm.comclass ParamFactory(object): 38912280Sgiacomo.travaglini@arm.com def __init__(self, param_desc_class, ptype_str = None): 39012280Sgiacomo.travaglini@arm.com self.param_desc_class = param_desc_class 39112280Sgiacomo.travaglini@arm.com self.ptype_str = ptype_str 39212280Sgiacomo.travaglini@arm.com 39312280Sgiacomo.travaglini@arm.com def __getattr__(self, attr): 39412280Sgiacomo.travaglini@arm.com if self.ptype_str: 39510037SARM gem5 Developers attr = self.ptype_str + '.' + attr 39610037SARM gem5 Developers return ParamFactory(self.param_desc_class, attr) 39710037SARM gem5 Developers 39810037SARM gem5 Developers # E.g., Param.Int(5, "number of widgets") 39910037SARM gem5 Developers def __call__(self, *args, **kwargs): 40010037SARM gem5 Developers ptype = None 40110037SARM gem5 Developers try: 40210037SARM gem5 Developers ptype = allParams[self.ptype_str] 40310037SARM gem5 Developers except KeyError: 40412106SRekai.GonzalezAlberquilla@arm.com # if name isn't defined yet, assume it's a SimObject, and 40512106SRekai.GonzalezAlberquilla@arm.com # try to resolve it later 40610037SARM gem5 Developers pass 40710037SARM gem5 Developers return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 40810037SARM gem5 Developers 40910037SARM gem5 DevelopersParam = ParamFactory(ParamDesc) 41010037SARM gem5 DevelopersVectorParam = ParamFactory(VectorParamDesc) 41110037SARM gem5 Developers 41210037SARM gem5 Developers##################################################################### 41310037SARM gem5 Developers# 41410037SARM gem5 Developers# Parameter Types 41510037SARM gem5 Developers# 41610037SARM gem5 Developers# Though native Python types could be used to specify parameter types 41710037SARM gem5 Developers# (the 'ptype' field of the Param and VectorParam classes), it's more 41810037SARM gem5 Developers# flexible to define our own set of types. This gives us more control 41910037SARM gem5 Developers# over how Python expressions are converted to values (via the 42012504Snikos.nikoleris@arm.com# __init__() constructor) and how these values are printed out (via 42110037SARM gem5 Developers# the __str__() conversion method). 42210037SARM gem5 Developers# 42310037SARM gem5 Developers##################################################################### 42410037SARM gem5 Developers 42510037SARM gem5 Developers# String-valued parameter. Just mixin the ParamValue class with the 42610037SARM gem5 Developers# built-in str class. 42710037SARM gem5 Developersclass String(ParamValue,str): 42810037SARM gem5 Developers cxx_type = 'std::string' 42910037SARM gem5 Developers cmd_line_settable = True 43010037SARM gem5 Developers 43112359Snikos.nikoleris@arm.com @classmethod 43212359Snikos.nikoleris@arm.com def cxx_predecls(self, code): 43312359Snikos.nikoleris@arm.com code('#include <string>') 43412359Snikos.nikoleris@arm.com 43512359Snikos.nikoleris@arm.com @classmethod 43612359Snikos.nikoleris@arm.com def swig_predecls(cls, code): 43712359Snikos.nikoleris@arm.com code('%include "std_string.i"') 43812359Snikos.nikoleris@arm.com 43912359Snikos.nikoleris@arm.com def __call__(self, value): 44012359Snikos.nikoleris@arm.com self = value 44112359Snikos.nikoleris@arm.com return value 44212359Snikos.nikoleris@arm.com 44312359Snikos.nikoleris@arm.com def getValue(self): 44412359Snikos.nikoleris@arm.com return self 44512359Snikos.nikoleris@arm.com 44612359Snikos.nikoleris@arm.com# superclass for "numeric" parameter values, to emulate math 44712359Snikos.nikoleris@arm.com# operations in a type-safe way. e.g., a Latency times an int returns 44812359Snikos.nikoleris@arm.com# a new Latency object. 44912359Snikos.nikoleris@arm.comclass NumericParamValue(ParamValue): 45012359Snikos.nikoleris@arm.com def __str__(self): 45112359Snikos.nikoleris@arm.com return str(self.value) 45212359Snikos.nikoleris@arm.com 45312359Snikos.nikoleris@arm.com def __float__(self): 45412359Snikos.nikoleris@arm.com return float(self.value) 45512359Snikos.nikoleris@arm.com 45612359Snikos.nikoleris@arm.com def __long__(self): 45712359Snikos.nikoleris@arm.com return long(self.value) 45812359Snikos.nikoleris@arm.com 45912359Snikos.nikoleris@arm.com def __int__(self): 46012359Snikos.nikoleris@arm.com return int(self.value) 46112359Snikos.nikoleris@arm.com 46212359Snikos.nikoleris@arm.com # hook for bounds checking 46312359Snikos.nikoleris@arm.com def _check(self): 46412359Snikos.nikoleris@arm.com return 46512359Snikos.nikoleris@arm.com 46612359Snikos.nikoleris@arm.com def __mul__(self, other): 46712359Snikos.nikoleris@arm.com newobj = self.__class__(self) 46812359Snikos.nikoleris@arm.com newobj.value *= other 46912359Snikos.nikoleris@arm.com newobj._check() 47012359Snikos.nikoleris@arm.com return newobj 47112359Snikos.nikoleris@arm.com 47212359Snikos.nikoleris@arm.com __rmul__ = __mul__ 47312359Snikos.nikoleris@arm.com 47412359Snikos.nikoleris@arm.com def __div__(self, other): 47512359Snikos.nikoleris@arm.com newobj = self.__class__(self) 47612359Snikos.nikoleris@arm.com newobj.value /= other 47712359Snikos.nikoleris@arm.com newobj._check() 47812359Snikos.nikoleris@arm.com return newobj 47912359Snikos.nikoleris@arm.com 48012359Snikos.nikoleris@arm.com def __sub__(self, other): 48112359Snikos.nikoleris@arm.com newobj = self.__class__(self) 48212359Snikos.nikoleris@arm.com newobj.value -= other 48312359Snikos.nikoleris@arm.com newobj._check() 48412359Snikos.nikoleris@arm.com return newobj 48512359Snikos.nikoleris@arm.com 48612359Snikos.nikoleris@arm.com# Metaclass for bounds-checked integer parameters. See CheckedInt. 48712359Snikos.nikoleris@arm.comclass CheckedIntType(MetaParamValue): 48812359Snikos.nikoleris@arm.com def __init__(cls, name, bases, dict): 48912359Snikos.nikoleris@arm.com super(CheckedIntType, cls).__init__(name, bases, dict) 49012359Snikos.nikoleris@arm.com 49112359Snikos.nikoleris@arm.com # CheckedInt is an abstract base class, so we actually don't 49212359Snikos.nikoleris@arm.com # want to do any processing on it... the rest of this code is 49312359Snikos.nikoleris@arm.com # just for classes that derive from CheckedInt. 49412359Snikos.nikoleris@arm.com if name == 'CheckedInt': 49512359Snikos.nikoleris@arm.com return 49612359Snikos.nikoleris@arm.com 49712359Snikos.nikoleris@arm.com if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 49812359Snikos.nikoleris@arm.com if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 49912359Snikos.nikoleris@arm.com panic("CheckedInt subclass %s must define either\n" \ 50012359Snikos.nikoleris@arm.com " 'min' and 'max' or 'size' and 'unsigned'\n", 50112359Snikos.nikoleris@arm.com name); 50212359Snikos.nikoleris@arm.com if cls.unsigned: 50312359Snikos.nikoleris@arm.com cls.min = 0 50412359Snikos.nikoleris@arm.com cls.max = 2 ** cls.size - 1 50512359Snikos.nikoleris@arm.com else: 50612359Snikos.nikoleris@arm.com cls.min = -(2 ** (cls.size - 1)) 50712359Snikos.nikoleris@arm.com cls.max = (2 ** (cls.size - 1)) - 1 50812359Snikos.nikoleris@arm.com 50912359Snikos.nikoleris@arm.com# Abstract superclass for bounds-checked integer parameters. This 51012359Snikos.nikoleris@arm.com# class is subclassed to generate parameter classes with specific 51112359Snikos.nikoleris@arm.com# bounds. Initialization of the min and max bounds is done in the 51212359Snikos.nikoleris@arm.com# metaclass CheckedIntType.__init__. 51312359Snikos.nikoleris@arm.comclass CheckedInt(NumericParamValue): 51412359Snikos.nikoleris@arm.com __metaclass__ = CheckedIntType 51512359Snikos.nikoleris@arm.com cmd_line_settable = True 51612359Snikos.nikoleris@arm.com 51712359Snikos.nikoleris@arm.com def _check(self): 51812359Snikos.nikoleris@arm.com if not self.min <= self.value <= self.max: 51912359Snikos.nikoleris@arm.com raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 52012359Snikos.nikoleris@arm.com (self.min, self.value, self.max) 52112359Snikos.nikoleris@arm.com 52212359Snikos.nikoleris@arm.com def __init__(self, value): 52312359Snikos.nikoleris@arm.com if isinstance(value, str): 52412359Snikos.nikoleris@arm.com self.value = convert.toInteger(value) 52512359Snikos.nikoleris@arm.com elif isinstance(value, (int, long, float, NumericParamValue)): 52612359Snikos.nikoleris@arm.com self.value = long(value) 52712359Snikos.nikoleris@arm.com else: 52812359Snikos.nikoleris@arm.com raise TypeError, "Can't convert object of type %s to CheckedInt" \ 52912359Snikos.nikoleris@arm.com % type(value).__name__ 53012359Snikos.nikoleris@arm.com self._check() 53112359Snikos.nikoleris@arm.com 53212359Snikos.nikoleris@arm.com def __call__(self, value): 53312359Snikos.nikoleris@arm.com self.__init__(value) 53412359Snikos.nikoleris@arm.com return value 53512359Snikos.nikoleris@arm.com 53612359Snikos.nikoleris@arm.com @classmethod 53712359Snikos.nikoleris@arm.com def cxx_predecls(cls, code): 53812359Snikos.nikoleris@arm.com # most derived types require this, so we just do it here once 53912359Snikos.nikoleris@arm.com code('#include "base/types.hh"') 54012359Snikos.nikoleris@arm.com 54112359Snikos.nikoleris@arm.com @classmethod 54210037SARM gem5 Developers def swig_predecls(cls, code): 54310037SARM gem5 Developers # most derived types require this, so we just do it here once 54410037SARM gem5 Developers code('%import "stdint.i"') 54512106SRekai.GonzalezAlberquilla@arm.com code('%import "base/types.hh"') 54612106SRekai.GonzalezAlberquilla@arm.com 54710037SARM gem5 Developers def getValue(self): 54810474Sandreas.hansson@arm.com return long(self.value) 54910474Sandreas.hansson@arm.com 55010037SARM gem5 Developersclass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 55110037SARM gem5 Developersclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 55210037SARM gem5 Developers 55310037SARM gem5 Developersclass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 55410037SARM gem5 Developersclass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 55510037SARM gem5 Developersclass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 55612106SRekai.GonzalezAlberquilla@arm.comclass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 55712106SRekai.GonzalezAlberquilla@arm.comclass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 55810037SARM gem5 Developersclass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 55910474Sandreas.hansson@arm.comclass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 56010474Sandreas.hansson@arm.comclass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 56110205SAli.Saidi@ARM.com 56210037SARM gem5 Developersclass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 56310037SARM gem5 Developersclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 56410037SARM gem5 Developersclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 56510037SARM gem5 Developersclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 56610037SARM gem5 Developers 56710037SARM gem5 Developersclass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 56810037SARM gem5 Developers 56910037SARM gem5 Developersclass Cycles(CheckedInt): 57012106SRekai.GonzalezAlberquilla@arm.com cxx_type = 'Cycles' 57112106SRekai.GonzalezAlberquilla@arm.com size = 64 57210037SARM gem5 Developers unsigned = True 57310474Sandreas.hansson@arm.com 57410474Sandreas.hansson@arm.com def getValue(self): 57510205SAli.Saidi@ARM.com from m5.internal.core import Cycles 57610037SARM gem5 Developers return Cycles(self.value) 57710037SARM gem5 Developers 57810037SARM gem5 Developersclass Float(ParamValue, float): 57910037SARM gem5 Developers cxx_type = 'double' 58010037SARM gem5 Developers cmdLineSettable = True 58110037SARM gem5 Developers 58210037SARM gem5 Developers def __init__(self, value): 58310037SARM gem5 Developers if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 58410037SARM gem5 Developers self.value = float(value) 58510037SARM gem5 Developers else: 58610037SARM gem5 Developers raise TypeError, "Can't convert object of type %s to Float" \ 58710037SARM gem5 Developers % type(value).__name__ 58810037SARM gem5 Developers 58910037SARM gem5 Developers def __call__(self, value): 59010037SARM gem5 Developers self.__init__(value) 59110037SARM gem5 Developers return value 59210037SARM gem5 Developers 59310037SARM gem5 Developers def getValue(self): 59410037SARM gem5 Developers return float(self.value) 59510037SARM gem5 Developers 59610037SARM gem5 Developersclass MemorySize(CheckedInt): 59710037SARM gem5 Developers cxx_type = 'uint64_t' 59810037SARM gem5 Developers ex_str = '512MB' 59910037SARM gem5 Developers size = 64 60010037SARM gem5 Developers unsigned = True 60110037SARM gem5 Developers def __init__(self, value): 60210037SARM gem5 Developers if isinstance(value, MemorySize): 60310037SARM gem5 Developers self.value = value.value 60410037SARM gem5 Developers else: 60510037SARM gem5 Developers self.value = convert.toMemorySize(value) 60610037SARM gem5 Developers self._check() 60710037SARM gem5 Developers 60810037SARM gem5 Developersclass MemorySize32(CheckedInt): 60910037SARM gem5 Developers cxx_type = 'uint32_t' 61010037SARM gem5 Developers ex_str = '512MB' 61110037SARM gem5 Developers size = 32 61210037SARM gem5 Developers unsigned = True 61310037SARM gem5 Developers def __init__(self, value): 61410037SARM gem5 Developers if isinstance(value, MemorySize): 61510037SARM gem5 Developers self.value = value.value 61610037SARM gem5 Developers else: 61710037SARM gem5 Developers self.value = convert.toMemorySize(value) 61810037SARM gem5 Developers self._check() 61910037SARM gem5 Developers 62010037SARM gem5 Developersclass Addr(CheckedInt): 62110037SARM gem5 Developers cxx_type = 'Addr' 62210037SARM gem5 Developers size = 64 62310037SARM gem5 Developers unsigned = True 62410037SARM gem5 Developers def __init__(self, value): 62510037SARM gem5 Developers if isinstance(value, Addr): 62610037SARM gem5 Developers self.value = value.value 62710037SARM gem5 Developers else: 62810037SARM gem5 Developers try: 62910037SARM gem5 Developers self.value = convert.toMemorySize(value) 63010037SARM gem5 Developers except TypeError: 631 self.value = long(value) 632 self._check() 633 def __add__(self, other): 634 if isinstance(other, Addr): 635 return self.value + other.value 636 else: 637 return self.value + other 638 def pretty_print(self, value): 639 try: 640 val = convert.toMemorySize(value) 641 except TypeError: 642 val = long(value) 643 return "0x%x" % long(val) 644 645class AddrRange(ParamValue): 646 cxx_type = 'AddrRange' 647 648 def __init__(self, *args, **kwargs): 649 # Disable interleaving by default 650 self.intlvHighBit = 0 651 self.intlvBits = 0 652 self.intlvMatch = 0 653 654 def handle_kwargs(self, kwargs): 655 # An address range needs to have an upper limit, specified 656 # either explicitly with an end, or as an offset using the 657 # size keyword. 658 if 'end' in kwargs: 659 self.end = Addr(kwargs.pop('end')) 660 elif 'size' in kwargs: 661 self.end = self.start + Addr(kwargs.pop('size')) - 1 662 else: 663 raise TypeError, "Either end or size must be specified" 664 665 # Now on to the optional bit 666 if 'intlvHighBit' in kwargs: 667 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 668 if 'intlvBits' in kwargs: 669 self.intlvBits = int(kwargs.pop('intlvBits')) 670 if 'intlvMatch' in kwargs: 671 self.intlvMatch = int(kwargs.pop('intlvMatch')) 672 673 if len(args) == 0: 674 self.start = Addr(kwargs.pop('start')) 675 handle_kwargs(self, kwargs) 676 677 elif len(args) == 1: 678 if kwargs: 679 self.start = Addr(args[0]) 680 handle_kwargs(self, kwargs) 681 elif isinstance(args[0], (list, tuple)): 682 self.start = Addr(args[0][0]) 683 self.end = Addr(args[0][1]) 684 else: 685 self.start = Addr(0) 686 self.end = Addr(args[0]) - 1 687 688 elif len(args) == 2: 689 self.start = Addr(args[0]) 690 self.end = Addr(args[1]) 691 else: 692 raise TypeError, "Too many arguments specified" 693 694 if kwargs: 695 raise TypeError, "Too many keywords: %s" % kwargs.keys() 696 697 def __str__(self): 698 return '%s:%s' % (self.start, self.end) 699 700 def size(self): 701 # Divide the size by the size of the interleaving slice 702 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 703 704 @classmethod 705 def cxx_predecls(cls, code): 706 Addr.cxx_predecls(code) 707 code('#include "base/addr_range.hh"') 708 709 @classmethod 710 def swig_predecls(cls, code): 711 Addr.swig_predecls(code) 712 713 def getValue(self): 714 # Go from the Python class to the wrapped C++ class generated 715 # by swig 716 from m5.internal.range import AddrRange 717 718 return AddrRange(long(self.start), long(self.end), 719 int(self.intlvHighBit), int(self.intlvBits), 720 int(self.intlvMatch)) 721 722# Boolean parameter type. Python doesn't let you subclass bool, since 723# it doesn't want to let you create multiple instances of True and 724# False. Thus this is a little more complicated than String. 725class Bool(ParamValue): 726 cxx_type = 'bool' 727 cmd_line_settable = True 728 729 def __init__(self, value): 730 try: 731 self.value = convert.toBool(value) 732 except TypeError: 733 self.value = bool(value) 734 735 def __call__(self, value): 736 self.__init__(value) 737 return value 738 739 def getValue(self): 740 return bool(self.value) 741 742 def __str__(self): 743 return str(self.value) 744 745 # implement truth value testing for Bool parameters so that these params 746 # evaluate correctly during the python configuration phase 747 def __nonzero__(self): 748 return bool(self.value) 749 750 def ini_str(self): 751 if self.value: 752 return 'true' 753 return 'false' 754 755def IncEthernetAddr(addr, val = 1): 756 bytes = map(lambda x: int(x, 16), addr.split(':')) 757 bytes[5] += val 758 for i in (5, 4, 3, 2, 1): 759 val,rem = divmod(bytes[i], 256) 760 bytes[i] = rem 761 if val == 0: 762 break 763 bytes[i - 1] += val 764 assert(bytes[0] <= 255) 765 return ':'.join(map(lambda x: '%02x' % x, bytes)) 766 767_NextEthernetAddr = "00:90:00:00:00:01" 768def NextEthernetAddr(): 769 global _NextEthernetAddr 770 771 value = _NextEthernetAddr 772 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 773 return value 774 775class EthernetAddr(ParamValue): 776 cxx_type = 'Net::EthAddr' 777 ex_str = "00:90:00:00:00:01" 778 cmd_line_settable = True 779 780 @classmethod 781 def cxx_predecls(cls, code): 782 code('#include "base/inet.hh"') 783 784 @classmethod 785 def swig_predecls(cls, code): 786 code('%include "python/swig/inet.i"') 787 788 def __init__(self, value): 789 if value == NextEthernetAddr: 790 self.value = value 791 return 792 793 if not isinstance(value, str): 794 raise TypeError, "expected an ethernet address and didn't get one" 795 796 bytes = value.split(':') 797 if len(bytes) != 6: 798 raise TypeError, 'invalid ethernet address %s' % value 799 800 for byte in bytes: 801 if not 0 <= int(byte, base=16) <= 0xff: 802 raise TypeError, 'invalid ethernet address %s' % value 803 804 self.value = value 805 806 def __call__(self, value): 807 self.__init__(value) 808 return value 809 810 def unproxy(self, base): 811 if self.value == NextEthernetAddr: 812 return EthernetAddr(self.value()) 813 return self 814 815 def getValue(self): 816 from m5.internal.params import EthAddr 817 return EthAddr(self.value) 818 819 def ini_str(self): 820 return self.value 821 822# When initializing an IpAddress, pass in an existing IpAddress, a string of 823# the form "a.b.c.d", or an integer representing an IP. 824class IpAddress(ParamValue): 825 cxx_type = 'Net::IpAddress' 826 ex_str = "127.0.0.1" 827 cmd_line_settable = True 828 829 @classmethod 830 def cxx_predecls(cls, code): 831 code('#include "base/inet.hh"') 832 833 @classmethod 834 def swig_predecls(cls, code): 835 code('%include "python/swig/inet.i"') 836 837 def __init__(self, value): 838 if isinstance(value, IpAddress): 839 self.ip = value.ip 840 else: 841 try: 842 self.ip = convert.toIpAddress(value) 843 except TypeError: 844 self.ip = long(value) 845 self.verifyIp() 846 847 def __call__(self, value): 848 self.__init__(value) 849 return value 850 851 def __str__(self): 852 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 853 return '%d.%d.%d.%d' % tuple(tup) 854 855 def __eq__(self, other): 856 if isinstance(other, IpAddress): 857 return self.ip == other.ip 858 elif isinstance(other, str): 859 try: 860 return self.ip == convert.toIpAddress(other) 861 except: 862 return False 863 else: 864 return self.ip == other 865 866 def __ne__(self, other): 867 return not (self == other) 868 869 def verifyIp(self): 870 if self.ip < 0 or self.ip >= (1 << 32): 871 raise TypeError, "invalid ip address %#08x" % self.ip 872 873 def getValue(self): 874 from m5.internal.params import IpAddress 875 return IpAddress(self.ip) 876 877# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 878# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 879# positional or keyword arguments. 880class IpNetmask(IpAddress): 881 cxx_type = 'Net::IpNetmask' 882 ex_str = "127.0.0.0/24" 883 cmd_line_settable = True 884 885 @classmethod 886 def cxx_predecls(cls, code): 887 code('#include "base/inet.hh"') 888 889 @classmethod 890 def swig_predecls(cls, code): 891 code('%include "python/swig/inet.i"') 892 893 def __init__(self, *args, **kwargs): 894 def handle_kwarg(self, kwargs, key, elseVal = None): 895 if key in kwargs: 896 setattr(self, key, kwargs.pop(key)) 897 elif elseVal: 898 setattr(self, key, elseVal) 899 else: 900 raise TypeError, "No value set for %s" % key 901 902 if len(args) == 0: 903 handle_kwarg(self, kwargs, 'ip') 904 handle_kwarg(self, kwargs, 'netmask') 905 906 elif len(args) == 1: 907 if kwargs: 908 if not 'ip' in kwargs and not 'netmask' in kwargs: 909 raise TypeError, "Invalid arguments" 910 handle_kwarg(self, kwargs, 'ip', args[0]) 911 handle_kwarg(self, kwargs, 'netmask', args[0]) 912 elif isinstance(args[0], IpNetmask): 913 self.ip = args[0].ip 914 self.netmask = args[0].netmask 915 else: 916 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 917 918 elif len(args) == 2: 919 self.ip = args[0] 920 self.netmask = args[1] 921 else: 922 raise TypeError, "Too many arguments specified" 923 924 if kwargs: 925 raise TypeError, "Too many keywords: %s" % kwargs.keys() 926 927 self.verify() 928 929 def __call__(self, value): 930 self.__init__(value) 931 return value 932 933 def __str__(self): 934 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 935 936 def __eq__(self, other): 937 if isinstance(other, IpNetmask): 938 return self.ip == other.ip and self.netmask == other.netmask 939 elif isinstance(other, str): 940 try: 941 return (self.ip, self.netmask) == convert.toIpNetmask(other) 942 except: 943 return False 944 else: 945 return False 946 947 def verify(self): 948 self.verifyIp() 949 if self.netmask < 0 or self.netmask > 32: 950 raise TypeError, "invalid netmask %d" % netmask 951 952 def getValue(self): 953 from m5.internal.params import IpNetmask 954 return IpNetmask(self.ip, self.netmask) 955 956# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 957# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 958class IpWithPort(IpAddress): 959 cxx_type = 'Net::IpWithPort' 960 ex_str = "127.0.0.1:80" 961 cmd_line_settable = True 962 963 @classmethod 964 def cxx_predecls(cls, code): 965 code('#include "base/inet.hh"') 966 967 @classmethod 968 def swig_predecls(cls, code): 969 code('%include "python/swig/inet.i"') 970 971 def __init__(self, *args, **kwargs): 972 def handle_kwarg(self, kwargs, key, elseVal = None): 973 if key in kwargs: 974 setattr(self, key, kwargs.pop(key)) 975 elif elseVal: 976 setattr(self, key, elseVal) 977 else: 978 raise TypeError, "No value set for %s" % key 979 980 if len(args) == 0: 981 handle_kwarg(self, kwargs, 'ip') 982 handle_kwarg(self, kwargs, 'port') 983 984 elif len(args) == 1: 985 if kwargs: 986 if not 'ip' in kwargs and not 'port' in kwargs: 987 raise TypeError, "Invalid arguments" 988 handle_kwarg(self, kwargs, 'ip', args[0]) 989 handle_kwarg(self, kwargs, 'port', args[0]) 990 elif isinstance(args[0], IpWithPort): 991 self.ip = args[0].ip 992 self.port = args[0].port 993 else: 994 (self.ip, self.port) = convert.toIpWithPort(args[0]) 995 996 elif len(args) == 2: 997 self.ip = args[0] 998 self.port = args[1] 999 else: 1000 raise TypeError, "Too many arguments specified" 1001 1002 if kwargs: 1003 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1004 1005 self.verify() 1006 1007 def __call__(self, value): 1008 self.__init__(value) 1009 return value 1010 1011 def __str__(self): 1012 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1013 1014 def __eq__(self, other): 1015 if isinstance(other, IpWithPort): 1016 return self.ip == other.ip and self.port == other.port 1017 elif isinstance(other, str): 1018 try: 1019 return (self.ip, self.port) == convert.toIpWithPort(other) 1020 except: 1021 return False 1022 else: 1023 return False 1024 1025 def verify(self): 1026 self.verifyIp() 1027 if self.port < 0 or self.port > 0xffff: 1028 raise TypeError, "invalid port %d" % self.port 1029 1030 def getValue(self): 1031 from m5.internal.params import IpWithPort 1032 return IpWithPort(self.ip, self.port) 1033 1034time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1035 "%a %b %d %H:%M:%S %Z %Y", 1036 "%Y/%m/%d %H:%M:%S", 1037 "%Y/%m/%d %H:%M", 1038 "%Y/%m/%d", 1039 "%m/%d/%Y %H:%M:%S", 1040 "%m/%d/%Y %H:%M", 1041 "%m/%d/%Y", 1042 "%m/%d/%y %H:%M:%S", 1043 "%m/%d/%y %H:%M", 1044 "%m/%d/%y"] 1045 1046 1047def parse_time(value): 1048 from time import gmtime, strptime, struct_time, time 1049 from datetime import datetime, date 1050 1051 if isinstance(value, struct_time): 1052 return value 1053 1054 if isinstance(value, (int, long)): 1055 return gmtime(value) 1056 1057 if isinstance(value, (datetime, date)): 1058 return value.timetuple() 1059 1060 if isinstance(value, str): 1061 if value in ('Now', 'Today'): 1062 return time.gmtime(time.time()) 1063 1064 for format in time_formats: 1065 try: 1066 return strptime(value, format) 1067 except ValueError: 1068 pass 1069 1070 raise ValueError, "Could not parse '%s' as a time" % value 1071 1072class Time(ParamValue): 1073 cxx_type = 'tm' 1074 1075 @classmethod 1076 def cxx_predecls(cls, code): 1077 code('#include <time.h>') 1078 1079 @classmethod 1080 def swig_predecls(cls, code): 1081 code('%include "python/swig/time.i"') 1082 1083 def __init__(self, value): 1084 self.value = parse_time(value) 1085 1086 def __call__(self, value): 1087 self.__init__(value) 1088 return value 1089 1090 def getValue(self): 1091 from m5.internal.params import tm 1092 1093 c_time = tm() 1094 py_time = self.value 1095 1096 # UNIX is years since 1900 1097 c_time.tm_year = py_time.tm_year - 1900; 1098 1099 # Python starts at 1, UNIX starts at 0 1100 c_time.tm_mon = py_time.tm_mon - 1; 1101 c_time.tm_mday = py_time.tm_mday; 1102 c_time.tm_hour = py_time.tm_hour; 1103 c_time.tm_min = py_time.tm_min; 1104 c_time.tm_sec = py_time.tm_sec; 1105 1106 # Python has 0 as Monday, UNIX is 0 as sunday 1107 c_time.tm_wday = py_time.tm_wday + 1 1108 if c_time.tm_wday > 6: 1109 c_time.tm_wday -= 7; 1110 1111 # Python starts at 1, Unix starts at 0 1112 c_time.tm_yday = py_time.tm_yday - 1; 1113 1114 return c_time 1115 1116 def __str__(self): 1117 return time.asctime(self.value) 1118 1119 def ini_str(self): 1120 return str(self) 1121 1122 def get_config_as_dict(self): 1123 return str(self) 1124 1125# Enumerated types are a little more complex. The user specifies the 1126# type as Enum(foo) where foo is either a list or dictionary of 1127# alternatives (typically strings, but not necessarily so). (In the 1128# long run, the integer value of the parameter will be the list index 1129# or the corresponding dictionary value. For now, since we only check 1130# that the alternative is valid and then spit it into a .ini file, 1131# there's not much point in using the dictionary.) 1132 1133# What Enum() must do is generate a new type encapsulating the 1134# provided list/dictionary so that specific values of the parameter 1135# can be instances of that type. We define two hidden internal 1136# classes (_ListEnum and _DictEnum) to serve as base classes, then 1137# derive the new type from the appropriate base class on the fly. 1138 1139allEnums = {} 1140# Metaclass for Enum types 1141class MetaEnum(MetaParamValue): 1142 def __new__(mcls, name, bases, dict): 1143 assert name not in allEnums 1144 1145 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1146 allEnums[name] = cls 1147 return cls 1148 1149 def __init__(cls, name, bases, init_dict): 1150 if init_dict.has_key('map'): 1151 if not isinstance(cls.map, dict): 1152 raise TypeError, "Enum-derived class attribute 'map' " \ 1153 "must be of type dict" 1154 # build list of value strings from map 1155 cls.vals = cls.map.keys() 1156 cls.vals.sort() 1157 elif init_dict.has_key('vals'): 1158 if not isinstance(cls.vals, list): 1159 raise TypeError, "Enum-derived class attribute 'vals' " \ 1160 "must be of type list" 1161 # build string->value map from vals sequence 1162 cls.map = {} 1163 for idx,val in enumerate(cls.vals): 1164 cls.map[val] = idx 1165 else: 1166 raise TypeError, "Enum-derived class must define "\ 1167 "attribute 'map' or 'vals'" 1168 1169 cls.cxx_type = 'Enums::%s' % name 1170 1171 super(MetaEnum, cls).__init__(name, bases, init_dict) 1172 1173 # Generate C++ class declaration for this enum type. 1174 # Note that we wrap the enum in a class/struct to act as a namespace, 1175 # so that the enum strings can be brief w/o worrying about collisions. 1176 def cxx_decl(cls, code): 1177 wrapper_name = cls.wrapper_name 1178 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1179 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1180 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1181 1182 code('''\ 1183#ifndef $idem_macro 1184#define $idem_macro 1185 1186$wrapper $wrapper_name { 1187 enum $name { 1188''') 1189 code.indent(2) 1190 for val in cls.vals: 1191 code('$val = ${{cls.map[val]}},') 1192 code('Num_$name = ${{len(cls.vals)}}') 1193 code.dedent(2) 1194 code(' };') 1195 1196 if cls.wrapper_is_struct: 1197 code(' static const char *${name}Strings[Num_${name}];') 1198 code('};') 1199 else: 1200 code('extern const char *${name}Strings[Num_${name}];') 1201 code('}') 1202 1203 code() 1204 code('#endif // $idem_macro') 1205 1206 def cxx_def(cls, code): 1207 wrapper_name = cls.wrapper_name 1208 file_name = cls.__name__ 1209 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1210 1211 code('#include "enums/$file_name.hh"') 1212 if cls.wrapper_is_struct: 1213 code('const char *${wrapper_name}::${name}Strings' 1214 '[Num_${name}] =') 1215 else: 1216 code('namespace Enums {') 1217 code.indent(1) 1218 code(' const char *${name}Strings[Num_${name}] =') 1219 1220 code('{') 1221 code.indent(1) 1222 for val in cls.vals: 1223 code('"$val",') 1224 code.dedent(1) 1225 code('};') 1226 1227 if not cls.wrapper_is_struct: 1228 code('} // namespace $wrapper_name') 1229 code.dedent(1) 1230 1231 def swig_decl(cls, code): 1232 name = cls.__name__ 1233 code('''\ 1234%module(package="m5.internal") enum_$name 1235 1236%{ 1237#include "enums/$name.hh" 1238%} 1239 1240%include "enums/$name.hh" 1241''') 1242 1243 1244# Base class for enum types. 1245class Enum(ParamValue): 1246 __metaclass__ = MetaEnum 1247 vals = [] 1248 cmd_line_settable = True 1249 1250 # The name of the wrapping namespace or struct 1251 wrapper_name = 'Enums' 1252 1253 # If true, the enum is wrapped in a struct rather than a namespace 1254 wrapper_is_struct = False 1255 1256 # If not None, use this as the enum name rather than this class name 1257 enum_name = None 1258 1259 def __init__(self, value): 1260 if value not in self.map: 1261 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1262 % (value, self.vals) 1263 self.value = value 1264 1265 def __call__(self, value): 1266 self.__init__(value) 1267 return value 1268 1269 @classmethod 1270 def cxx_predecls(cls, code): 1271 code('#include "enums/$0.hh"', cls.__name__) 1272 1273 @classmethod 1274 def swig_predecls(cls, code): 1275 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1276 1277 def getValue(self): 1278 return int(self.map[self.value]) 1279 1280 def __str__(self): 1281 return self.value 1282 1283# how big does a rounding error need to be before we warn about it? 1284frequency_tolerance = 0.001 # 0.1% 1285 1286class TickParamValue(NumericParamValue): 1287 cxx_type = 'Tick' 1288 ex_str = "1MHz" 1289 cmd_line_settable = True 1290 1291 @classmethod 1292 def cxx_predecls(cls, code): 1293 code('#include "base/types.hh"') 1294 1295 @classmethod 1296 def swig_predecls(cls, code): 1297 code('%import "stdint.i"') 1298 code('%import "base/types.hh"') 1299 1300 def __call__(self, value): 1301 self.__init__(value) 1302 return value 1303 1304 def getValue(self): 1305 return long(self.value) 1306 1307class Latency(TickParamValue): 1308 ex_str = "100ns" 1309 1310 def __init__(self, value): 1311 if isinstance(value, (Latency, Clock)): 1312 self.ticks = value.ticks 1313 self.value = value.value 1314 elif isinstance(value, Frequency): 1315 self.ticks = value.ticks 1316 self.value = 1.0 / value.value 1317 elif value.endswith('t'): 1318 self.ticks = True 1319 self.value = int(value[:-1]) 1320 else: 1321 self.ticks = False 1322 self.value = convert.toLatency(value) 1323 1324 def __call__(self, value): 1325 self.__init__(value) 1326 return value 1327 1328 def __getattr__(self, attr): 1329 if attr in ('latency', 'period'): 1330 return self 1331 if attr == 'frequency': 1332 return Frequency(self) 1333 raise AttributeError, "Latency object has no attribute '%s'" % attr 1334 1335 def getValue(self): 1336 if self.ticks or self.value == 0: 1337 value = self.value 1338 else: 1339 value = ticks.fromSeconds(self.value) 1340 return long(value) 1341 1342 # convert latency to ticks 1343 def ini_str(self): 1344 return '%d' % self.getValue() 1345 1346class Frequency(TickParamValue): 1347 ex_str = "1GHz" 1348 1349 def __init__(self, value): 1350 if isinstance(value, (Latency, Clock)): 1351 if value.value == 0: 1352 self.value = 0 1353 else: 1354 self.value = 1.0 / value.value 1355 self.ticks = value.ticks 1356 elif isinstance(value, Frequency): 1357 self.value = value.value 1358 self.ticks = value.ticks 1359 else: 1360 self.ticks = False 1361 self.value = convert.toFrequency(value) 1362 1363 def __call__(self, value): 1364 self.__init__(value) 1365 return value 1366 1367 def __getattr__(self, attr): 1368 if attr == 'frequency': 1369 return self 1370 if attr in ('latency', 'period'): 1371 return Latency(self) 1372 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1373 1374 # convert latency to ticks 1375 def getValue(self): 1376 if self.ticks or self.value == 0: 1377 value = self.value 1378 else: 1379 value = ticks.fromSeconds(1.0 / self.value) 1380 return long(value) 1381 1382 def ini_str(self): 1383 return '%d' % self.getValue() 1384 1385# A generic Frequency and/or Latency value. Value is stored as a 1386# latency, just like Latency and Frequency. 1387class Clock(TickParamValue): 1388 def __init__(self, value): 1389 if isinstance(value, (Latency, Clock)): 1390 self.ticks = value.ticks 1391 self.value = value.value 1392 elif isinstance(value, Frequency): 1393 self.ticks = value.ticks 1394 self.value = 1.0 / value.value 1395 elif value.endswith('t'): 1396 self.ticks = True 1397 self.value = int(value[:-1]) 1398 else: 1399 self.ticks = False 1400 self.value = convert.anyToLatency(value) 1401 1402 def __call__(self, value): 1403 self.__init__(value) 1404 return value 1405 1406 def __str__(self): 1407 return "%s" % Latency(self) 1408 1409 def __getattr__(self, attr): 1410 if attr == 'frequency': 1411 return Frequency(self) 1412 if attr in ('latency', 'period'): 1413 return Latency(self) 1414 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1415 1416 def getValue(self): 1417 return self.period.getValue() 1418 1419 def ini_str(self): 1420 return self.period.ini_str() 1421 1422class Voltage(float,ParamValue): 1423 cxx_type = 'double' 1424 ex_str = "1V" 1425 cmd_line_settable = False 1426 1427 def __new__(cls, value): 1428 # convert to voltage 1429 val = convert.toVoltage(value) 1430 return super(cls, Voltage).__new__(cls, val) 1431 1432 def __call__(self, value): 1433 val = convert.toVoltage(value) 1434 self.__init__(val) 1435 return value 1436 1437 def __str__(self): 1438 return str(self.getValue()) 1439 1440 def getValue(self): 1441 value = float(self) 1442 return value 1443 1444 def ini_str(self): 1445 return '%f' % self.getValue() 1446 1447class NetworkBandwidth(float,ParamValue): 1448 cxx_type = 'float' 1449 ex_str = "1Gbps" 1450 cmd_line_settable = True 1451 1452 def __new__(cls, value): 1453 # convert to bits per second 1454 val = convert.toNetworkBandwidth(value) 1455 return super(cls, NetworkBandwidth).__new__(cls, val) 1456 1457 def __str__(self): 1458 return str(self.val) 1459 1460 def __call__(self, value): 1461 val = convert.toNetworkBandwidth(value) 1462 self.__init__(val) 1463 return value 1464 1465 def getValue(self): 1466 # convert to seconds per byte 1467 value = 8.0 / float(self) 1468 # convert to ticks per byte 1469 value = ticks.fromSeconds(value) 1470 return float(value) 1471 1472 def ini_str(self): 1473 return '%f' % self.getValue() 1474 1475class MemoryBandwidth(float,ParamValue): 1476 cxx_type = 'float' 1477 ex_str = "1GB/s" 1478 cmd_line_settable = True 1479 1480 def __new__(cls, value): 1481 # convert to bytes per second 1482 val = convert.toMemoryBandwidth(value) 1483 return super(cls, MemoryBandwidth).__new__(cls, val) 1484 1485 def __call__(self, value): 1486 val = convert.toMemoryBandwidth(value) 1487 self.__init__(val) 1488 return value 1489 1490 def getValue(self): 1491 # convert to seconds per byte 1492 value = float(self) 1493 if value: 1494 value = 1.0 / float(self) 1495 # convert to ticks per byte 1496 value = ticks.fromSeconds(value) 1497 return float(value) 1498 1499 def ini_str(self): 1500 return '%f' % self.getValue() 1501 1502# 1503# "Constants"... handy aliases for various values. 1504# 1505 1506# Special class for NULL pointers. Note the special check in 1507# make_param_value() above that lets these be assigned where a 1508# SimObject is required. 1509# only one copy of a particular node 1510class NullSimObject(object): 1511 __metaclass__ = Singleton 1512 1513 def __call__(cls): 1514 return cls 1515 1516 def _instantiate(self, parent = None, path = ''): 1517 pass 1518 1519 def ini_str(self): 1520 return 'Null' 1521 1522 def unproxy(self, base): 1523 return self 1524 1525 def set_path(self, parent, name): 1526 pass 1527 1528 def __str__(self): 1529 return 'Null' 1530 1531 def getValue(self): 1532 return None 1533 1534# The only instance you'll ever need... 1535NULL = NullSimObject() 1536 1537def isNullPointer(value): 1538 return isinstance(value, NullSimObject) 1539 1540# Some memory range specifications use this as a default upper bound. 1541MaxAddr = Addr.max 1542MaxTick = Tick.max 1543AllMemory = AddrRange(0, MaxAddr) 1544 1545 1546##################################################################### 1547# 1548# Port objects 1549# 1550# Ports are used to interconnect objects in the memory system. 1551# 1552##################################################################### 1553 1554# Port reference: encapsulates a reference to a particular port on a 1555# particular SimObject. 1556class PortRef(object): 1557 def __init__(self, simobj, name, role): 1558 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1559 self.simobj = simobj 1560 self.name = name 1561 self.role = role 1562 self.peer = None # not associated with another port yet 1563 self.ccConnected = False # C++ port connection done? 1564 self.index = -1 # always -1 for non-vector ports 1565 1566 def __str__(self): 1567 return '%s.%s' % (self.simobj, self.name) 1568 1569 def __len__(self): 1570 # Return the number of connected ports, i.e. 0 is we have no 1571 # peer and 1 if we do. 1572 return int(self.peer != None) 1573 1574 # for config.ini, print peer's name (not ours) 1575 def ini_str(self): 1576 return str(self.peer) 1577 1578 # for config.json 1579 def get_config_as_dict(self): 1580 return {'role' : self.role, 'peer' : str(self.peer)} 1581 1582 def __getattr__(self, attr): 1583 if attr == 'peerObj': 1584 # shorthand for proxies 1585 return self.peer.simobj 1586 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1587 (self.__class__.__name__, attr) 1588 1589 # Full connection is symmetric (both ways). Called via 1590 # SimObject.__setattr__ as a result of a port assignment, e.g., 1591 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1592 # e.g., "obj1.portA[3] = obj2.portB". 1593 def connect(self, other): 1594 if isinstance(other, VectorPortRef): 1595 # reference to plain VectorPort is implicit append 1596 other = other._get_next() 1597 if self.peer and not proxy.isproxy(self.peer): 1598 fatal("Port %s is already connected to %s, cannot connect %s\n", 1599 self, self.peer, other); 1600 self.peer = other 1601 if proxy.isproxy(other): 1602 other.set_param_desc(PortParamDesc()) 1603 elif isinstance(other, PortRef): 1604 if other.peer is not self: 1605 other.connect(self) 1606 else: 1607 raise TypeError, \ 1608 "assigning non-port reference '%s' to port '%s'" \ 1609 % (other, self) 1610 1611 def clone(self, simobj, memo): 1612 if memo.has_key(self): 1613 return memo[self] 1614 newRef = copy.copy(self) 1615 memo[self] = newRef 1616 newRef.simobj = simobj 1617 assert(isSimObject(newRef.simobj)) 1618 if self.peer and not proxy.isproxy(self.peer): 1619 peerObj = self.peer.simobj(_memo=memo) 1620 newRef.peer = self.peer.clone(peerObj, memo) 1621 assert(not isinstance(newRef.peer, VectorPortRef)) 1622 return newRef 1623 1624 def unproxy(self, simobj): 1625 assert(simobj is self.simobj) 1626 if proxy.isproxy(self.peer): 1627 try: 1628 realPeer = self.peer.unproxy(self.simobj) 1629 except: 1630 print "Error in unproxying port '%s' of %s" % \ 1631 (self.name, self.simobj.path()) 1632 raise 1633 self.connect(realPeer) 1634 1635 # Call C++ to create corresponding port connection between C++ objects 1636 def ccConnect(self): 1637 from m5.internal.pyobject import connectPorts 1638 1639 if self.role == 'SLAVE': 1640 # do nothing and let the master take care of it 1641 return 1642 1643 if self.ccConnected: # already done this 1644 return 1645 peer = self.peer 1646 if not self.peer: # nothing to connect to 1647 return 1648 1649 # check that we connect a master to a slave 1650 if self.role == peer.role: 1651 raise TypeError, \ 1652 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1653 % (peer, self, self.role) 1654 1655 try: 1656 # self is always the master and peer the slave 1657 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1658 peer.simobj.getCCObject(), peer.name, peer.index) 1659 except: 1660 print "Error connecting port %s.%s to %s.%s" % \ 1661 (self.simobj.path(), self.name, 1662 peer.simobj.path(), peer.name) 1663 raise 1664 self.ccConnected = True 1665 peer.ccConnected = True 1666 1667# A reference to an individual element of a VectorPort... much like a 1668# PortRef, but has an index. 1669class VectorPortElementRef(PortRef): 1670 def __init__(self, simobj, name, role, index): 1671 PortRef.__init__(self, simobj, name, role) 1672 self.index = index 1673 1674 def __str__(self): 1675 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1676 1677# A reference to a complete vector-valued port (not just a single element). 1678# Can be indexed to retrieve individual VectorPortElementRef instances. 1679class VectorPortRef(object): 1680 def __init__(self, simobj, name, role): 1681 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1682 self.simobj = simobj 1683 self.name = name 1684 self.role = role 1685 self.elements = [] 1686 1687 def __str__(self): 1688 return '%s.%s[:]' % (self.simobj, self.name) 1689 1690 def __len__(self): 1691 # Return the number of connected peers, corresponding the the 1692 # length of the elements. 1693 return len(self.elements) 1694 1695 # for config.ini, print peer's name (not ours) 1696 def ini_str(self): 1697 return ' '.join([el.ini_str() for el in self.elements]) 1698 1699 # for config.json 1700 def get_config_as_dict(self): 1701 return {'role' : self.role, 1702 'peer' : [el.ini_str() for el in self.elements]} 1703 1704 def __getitem__(self, key): 1705 if not isinstance(key, int): 1706 raise TypeError, "VectorPort index must be integer" 1707 if key >= len(self.elements): 1708 # need to extend list 1709 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1710 for i in range(len(self.elements), key+1)] 1711 self.elements.extend(ext) 1712 return self.elements[key] 1713 1714 def _get_next(self): 1715 return self[len(self.elements)] 1716 1717 def __setitem__(self, key, value): 1718 if not isinstance(key, int): 1719 raise TypeError, "VectorPort index must be integer" 1720 self[key].connect(value) 1721 1722 def connect(self, other): 1723 if isinstance(other, (list, tuple)): 1724 # Assign list of port refs to vector port. 1725 # For now, append them... not sure if that's the right semantics 1726 # or if it should replace the current vector. 1727 for ref in other: 1728 self._get_next().connect(ref) 1729 else: 1730 # scalar assignment to plain VectorPort is implicit append 1731 self._get_next().connect(other) 1732 1733 def clone(self, simobj, memo): 1734 if memo.has_key(self): 1735 return memo[self] 1736 newRef = copy.copy(self) 1737 memo[self] = newRef 1738 newRef.simobj = simobj 1739 assert(isSimObject(newRef.simobj)) 1740 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1741 return newRef 1742 1743 def unproxy(self, simobj): 1744 [el.unproxy(simobj) for el in self.elements] 1745 1746 def ccConnect(self): 1747 [el.ccConnect() for el in self.elements] 1748 1749# Port description object. Like a ParamDesc object, this represents a 1750# logical port in the SimObject class, not a particular port on a 1751# SimObject instance. The latter are represented by PortRef objects. 1752class Port(object): 1753 # Generate a PortRef for this port on the given SimObject with the 1754 # given name 1755 def makeRef(self, simobj): 1756 return PortRef(simobj, self.name, self.role) 1757 1758 # Connect an instance of this port (on the given SimObject with 1759 # the given name) with the port described by the supplied PortRef 1760 def connect(self, simobj, ref): 1761 self.makeRef(simobj).connect(ref) 1762 1763 # No need for any pre-declarations at the moment as we merely rely 1764 # on an unsigned int. 1765 def cxx_predecls(self, code): 1766 pass 1767 1768 # Declare an unsigned int with the same name as the port, that 1769 # will eventually hold the number of connected ports (and thus the 1770 # number of elements for a VectorPort). 1771 def cxx_decl(self, code): 1772 code('unsigned int port_${{self.name}}_connection_count;') 1773 1774class MasterPort(Port): 1775 # MasterPort("description") 1776 def __init__(self, *args): 1777 if len(args) == 1: 1778 self.desc = args[0] 1779 self.role = 'MASTER' 1780 else: 1781 raise TypeError, 'wrong number of arguments' 1782 1783class SlavePort(Port): 1784 # SlavePort("description") 1785 def __init__(self, *args): 1786 if len(args) == 1: 1787 self.desc = args[0] 1788 self.role = 'SLAVE' 1789 else: 1790 raise TypeError, 'wrong number of arguments' 1791 1792# VectorPort description object. Like Port, but represents a vector 1793# of connections (e.g., as on a Bus). 1794class VectorPort(Port): 1795 def __init__(self, *args): 1796 self.isVec = True 1797 1798 def makeRef(self, simobj): 1799 return VectorPortRef(simobj, self.name, self.role) 1800 1801class VectorMasterPort(VectorPort): 1802 # VectorMasterPort("description") 1803 def __init__(self, *args): 1804 if len(args) == 1: 1805 self.desc = args[0] 1806 self.role = 'MASTER' 1807 VectorPort.__init__(self, *args) 1808 else: 1809 raise TypeError, 'wrong number of arguments' 1810 1811class VectorSlavePort(VectorPort): 1812 # VectorSlavePort("description") 1813 def __init__(self, *args): 1814 if len(args) == 1: 1815 self.desc = args[0] 1816 self.role = 'SLAVE' 1817 VectorPort.__init__(self, *args) 1818 else: 1819 raise TypeError, 'wrong number of arguments' 1820 1821# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1822# proxy objects (via set_param_desc()) so that proxy error messages 1823# make sense. 1824class PortParamDesc(object): 1825 __metaclass__ = Singleton 1826 1827 ptype_str = 'Port' 1828 ptype = Port 1829 1830baseEnums = allEnums.copy() 1831baseParams = allParams.copy() 1832 1833def clear(): 1834 global allEnums, allParams 1835 1836 allEnums = baseEnums.copy() 1837 allParams = baseParams.copy() 1838 1839__all__ = ['Param', 'VectorParam', 1840 'Enum', 'Bool', 'String', 'Float', 1841 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1842 'Int32', 'UInt32', 'Int64', 'UInt64', 1843 'Counter', 'Addr', 'Tick', 'Percent', 1844 'TcpPort', 'UdpPort', 'EthernetAddr', 1845 'IpAddress', 'IpNetmask', 'IpWithPort', 1846 'MemorySize', 'MemorySize32', 1847 'Latency', 'Frequency', 'Clock', 'Voltage', 1848 'NetworkBandwidth', 'MemoryBandwidth', 1849 'AddrRange', 1850 'MaxAddr', 'MaxTick', 'AllMemory', 1851 'Time', 1852 'NextEthernetAddr', 'NULL', 1853 'MasterPort', 'SlavePort', 1854 'VectorMasterPort', 'VectorSlavePort'] 1855 1856import SimObject 1857