params.py revision 13543
110461SAndreas.Sandberg@ARM.com# Copyright (c) 2012-2014, 2017 ARM Limited 210461SAndreas.Sandberg@ARM.com# All rights reserved. 310461SAndreas.Sandberg@ARM.com# 410461SAndreas.Sandberg@ARM.com# The license below extends only to copyright in the software and shall 510461SAndreas.Sandberg@ARM.com# not be construed as granting a license to any other intellectual 610461SAndreas.Sandberg@ARM.com# property including but not limited to intellectual property relating 710461SAndreas.Sandberg@ARM.com# to a hardware implementation of the functionality of the software 810461SAndreas.Sandberg@ARM.com# licensed hereunder. You may use the software subject to the license 910461SAndreas.Sandberg@ARM.com# terms below provided that you ensure that this notice is replicated 1010461SAndreas.Sandberg@ARM.com# unmodified and in its entirety in all distributions of the software, 1110461SAndreas.Sandberg@ARM.com# modified or unmodified, in source code or in binary form. 1210461SAndreas.Sandberg@ARM.com# 1310461SAndreas.Sandberg@ARM.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 1410461SAndreas.Sandberg@ARM.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 1510461SAndreas.Sandberg@ARM.com# All rights reserved. 1610461SAndreas.Sandberg@ARM.com# 1710461SAndreas.Sandberg@ARM.com# Redistribution and use in source and binary forms, with or without 1810461SAndreas.Sandberg@ARM.com# modification, are permitted provided that the following conditions are 1910461SAndreas.Sandberg@ARM.com# met: redistributions of source code must retain the above copyright 2010461SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer; 2110461SAndreas.Sandberg@ARM.com# redistributions in binary form must reproduce the above copyright 2210461SAndreas.Sandberg@ARM.com# notice, this list of conditions and the following disclaimer in the 2310461SAndreas.Sandberg@ARM.com# documentation and/or other materials provided with the distribution; 2410461SAndreas.Sandberg@ARM.com# neither the name of the copyright holders nor the names of its 2510461SAndreas.Sandberg@ARM.com# contributors may be used to endorse or promote products derived from 2610461SAndreas.Sandberg@ARM.com# this software without specific prior written permission. 2710461SAndreas.Sandberg@ARM.com# 2810461SAndreas.Sandberg@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2910461SAndreas.Sandberg@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3010461SAndreas.Sandberg@ARM.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3110461SAndreas.Sandberg@ARM.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3210461SAndreas.Sandberg@ARM.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3310461SAndreas.Sandberg@ARM.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3410461SAndreas.Sandberg@ARM.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3510461SAndreas.Sandberg@ARM.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3610461SAndreas.Sandberg@ARM.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3710461SAndreas.Sandberg@ARM.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3810461SAndreas.Sandberg@ARM.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3910461SAndreas.Sandberg@ARM.com# 4010461SAndreas.Sandberg@ARM.com# Authors: Steve Reinhardt 4110461SAndreas.Sandberg@ARM.com# Nathan Binkert 4210461SAndreas.Sandberg@ARM.com# Gabe Black 4310461SAndreas.Sandberg@ARM.com# Andreas Hansson 4410461SAndreas.Sandberg@ARM.com 4510461SAndreas.Sandberg@ARM.com##################################################################### 4610461SAndreas.Sandberg@ARM.com# 4710461SAndreas.Sandberg@ARM.com# Parameter description classes 4810461SAndreas.Sandberg@ARM.com# 4910461SAndreas.Sandberg@ARM.com# The _params dictionary in each class maps parameter names to either 5010461SAndreas.Sandberg@ARM.com# a Param or a VectorParam object. These objects contain the 5110461SAndreas.Sandberg@ARM.com# parameter description string, the parameter type, and the default 5210461SAndreas.Sandberg@ARM.com# value (if any). The convert() method on these objects is used to 5310461SAndreas.Sandberg@ARM.com# force whatever value is assigned to the parameter to the appropriate 5410461SAndreas.Sandberg@ARM.com# type. 5510461SAndreas.Sandberg@ARM.com# 5610461SAndreas.Sandberg@ARM.com# Note that the default values are loaded into the class's attribute 5710461SAndreas.Sandberg@ARM.com# space when the parameter dictionary is initialized (in 5810461SAndreas.Sandberg@ARM.com# MetaSimObject._new_param()); after that point they aren't used. 5910461SAndreas.Sandberg@ARM.com# 6010461SAndreas.Sandberg@ARM.com##################################################################### 6110461SAndreas.Sandberg@ARM.com 6210461SAndreas.Sandberg@ARM.comfrom __future__ import print_function 6310461SAndreas.Sandberg@ARM.com 6410461SAndreas.Sandberg@ARM.comimport copy 6510461SAndreas.Sandberg@ARM.comimport datetime 6610461SAndreas.Sandberg@ARM.comimport re 6710461SAndreas.Sandberg@ARM.comimport sys 6810461SAndreas.Sandberg@ARM.comimport time 6910461SAndreas.Sandberg@ARM.comimport math 7010461SAndreas.Sandberg@ARM.com 7110461SAndreas.Sandberg@ARM.comimport proxy 7210461SAndreas.Sandberg@ARM.comimport ticks 7310461SAndreas.Sandberg@ARM.comfrom util import * 7410461SAndreas.Sandberg@ARM.com 7510461SAndreas.Sandberg@ARM.comdef isSimObject(*args, **kwargs): 7610461SAndreas.Sandberg@ARM.com return SimObject.isSimObject(*args, **kwargs) 7710461SAndreas.Sandberg@ARM.com 7810461SAndreas.Sandberg@ARM.comdef isSimObjectSequence(*args, **kwargs): 7910461SAndreas.Sandberg@ARM.com return SimObject.isSimObjectSequence(*args, **kwargs) 8010461SAndreas.Sandberg@ARM.com 8110461SAndreas.Sandberg@ARM.comdef isSimObjectClass(*args, **kwargs): 8210461SAndreas.Sandberg@ARM.com return SimObject.isSimObjectClass(*args, **kwargs) 8310461SAndreas.Sandberg@ARM.com 8410461SAndreas.Sandberg@ARM.comallParams = {} 8510461SAndreas.Sandberg@ARM.com 8610461SAndreas.Sandberg@ARM.comclass MetaParamValue(type): 8710461SAndreas.Sandberg@ARM.com def __new__(mcls, name, bases, dct): 8810461SAndreas.Sandberg@ARM.com cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 8910461SAndreas.Sandberg@ARM.com assert name not in allParams 9010461SAndreas.Sandberg@ARM.com allParams[name] = cls 9110461SAndreas.Sandberg@ARM.com return cls 9210461SAndreas.Sandberg@ARM.com 9310461SAndreas.Sandberg@ARM.com 9410461SAndreas.Sandberg@ARM.com# Dummy base class to identify types that are legitimate for SimObject 9510461SAndreas.Sandberg@ARM.com# parameters. 9610461SAndreas.Sandberg@ARM.comclass ParamValue(object): 9710461SAndreas.Sandberg@ARM.com __metaclass__ = MetaParamValue 9810461SAndreas.Sandberg@ARM.com cmd_line_settable = False 9910461SAndreas.Sandberg@ARM.com 10010461SAndreas.Sandberg@ARM.com # Generate the code needed as a prerequisite for declaring a C++ 10110461SAndreas.Sandberg@ARM.com # object of this type. Typically generates one or more #include 10210461SAndreas.Sandberg@ARM.com # statements. Used when declaring parameters of this type. 10310461SAndreas.Sandberg@ARM.com @classmethod 10410461SAndreas.Sandberg@ARM.com def cxx_predecls(cls, code): 10510461SAndreas.Sandberg@ARM.com pass 10610461SAndreas.Sandberg@ARM.com 10710461SAndreas.Sandberg@ARM.com @classmethod 10810461SAndreas.Sandberg@ARM.com def pybind_predecls(cls, code): 10910461SAndreas.Sandberg@ARM.com cls.cxx_predecls(code) 11010461SAndreas.Sandberg@ARM.com 11110461SAndreas.Sandberg@ARM.com # default for printing to .ini file is regular string conversion. 11210461SAndreas.Sandberg@ARM.com # will be overridden in some cases 11310461SAndreas.Sandberg@ARM.com def ini_str(self): 11410461SAndreas.Sandberg@ARM.com return str(self) 11510461SAndreas.Sandberg@ARM.com 11610461SAndreas.Sandberg@ARM.com # default for printing to .json file is regular string conversion. 11710461SAndreas.Sandberg@ARM.com # will be overridden in some cases, mostly to use native Python 11810461SAndreas.Sandberg@ARM.com # types where there are similar JSON types 11910461SAndreas.Sandberg@ARM.com def config_value(self): 12010461SAndreas.Sandberg@ARM.com return str(self) 12110461SAndreas.Sandberg@ARM.com 12210461SAndreas.Sandberg@ARM.com # Prerequisites for .ini parsing with cxx_ini_parse 12310461SAndreas.Sandberg@ARM.com @classmethod 12410461SAndreas.Sandberg@ARM.com def cxx_ini_predecls(cls, code): 12510461SAndreas.Sandberg@ARM.com pass 12610461SAndreas.Sandberg@ARM.com 12710461SAndreas.Sandberg@ARM.com # parse a .ini file entry for this param from string expression 12810461SAndreas.Sandberg@ARM.com # src into lvalue dest (of the param's C++ type) 12910461SAndreas.Sandberg@ARM.com @classmethod 13010461SAndreas.Sandberg@ARM.com def cxx_ini_parse(cls, code, src, dest, ret): 13110461SAndreas.Sandberg@ARM.com code('// Unhandled param type: %s' % cls.__name__) 13210461SAndreas.Sandberg@ARM.com code('%s false;' % ret) 13310461SAndreas.Sandberg@ARM.com 13410461SAndreas.Sandberg@ARM.com # allows us to blithely call unproxy() on things without checking 13510461SAndreas.Sandberg@ARM.com # if they're really proxies or not 13610461SAndreas.Sandberg@ARM.com def unproxy(self, base): 13710461SAndreas.Sandberg@ARM.com return self 13810461SAndreas.Sandberg@ARM.com 13910461SAndreas.Sandberg@ARM.com # Produce a human readable version of the stored value 14010461SAndreas.Sandberg@ARM.com def pretty_print(self, value): 14110461SAndreas.Sandberg@ARM.com return str(value) 14210461SAndreas.Sandberg@ARM.com 14310461SAndreas.Sandberg@ARM.com# Regular parameter description. 14410461SAndreas.Sandberg@ARM.comclass ParamDesc(object): 14510461SAndreas.Sandberg@ARM.com def __init__(self, ptype_str, ptype, *args, **kwargs): 14610461SAndreas.Sandberg@ARM.com self.ptype_str = ptype_str 14710461SAndreas.Sandberg@ARM.com # remember ptype only if it is provided 14810461SAndreas.Sandberg@ARM.com if ptype != None: 14910461SAndreas.Sandberg@ARM.com self.ptype = ptype 15010461SAndreas.Sandberg@ARM.com 15110461SAndreas.Sandberg@ARM.com if args: 15210461SAndreas.Sandberg@ARM.com if len(args) == 1: 15310461SAndreas.Sandberg@ARM.com self.desc = args[0] 15410461SAndreas.Sandberg@ARM.com elif len(args) == 2: 15510461SAndreas.Sandberg@ARM.com self.default = args[0] 15610461SAndreas.Sandberg@ARM.com self.desc = args[1] 15710461SAndreas.Sandberg@ARM.com else: 15810461SAndreas.Sandberg@ARM.com raise TypeError, 'too many arguments' 15910461SAndreas.Sandberg@ARM.com 16010461SAndreas.Sandberg@ARM.com if kwargs.has_key('desc'): 16110461SAndreas.Sandberg@ARM.com assert(not hasattr(self, 'desc')) 16210461SAndreas.Sandberg@ARM.com self.desc = kwargs['desc'] 16310461SAndreas.Sandberg@ARM.com del kwargs['desc'] 16410461SAndreas.Sandberg@ARM.com 16510461SAndreas.Sandberg@ARM.com if kwargs.has_key('default'): 16610461SAndreas.Sandberg@ARM.com assert(not hasattr(self, 'default')) 16710461SAndreas.Sandberg@ARM.com self.default = kwargs['default'] 16810461SAndreas.Sandberg@ARM.com del kwargs['default'] 16910461SAndreas.Sandberg@ARM.com 17010461SAndreas.Sandberg@ARM.com if kwargs: 17110461SAndreas.Sandberg@ARM.com raise TypeError, 'extra unknown kwargs %s' % kwargs 17210461SAndreas.Sandberg@ARM.com 17310461SAndreas.Sandberg@ARM.com if not hasattr(self, 'desc'): 17410461SAndreas.Sandberg@ARM.com raise TypeError, 'desc attribute missing' 17510461SAndreas.Sandberg@ARM.com 17610461SAndreas.Sandberg@ARM.com def __getattr__(self, attr): 17710461SAndreas.Sandberg@ARM.com if attr == 'ptype': 17810461SAndreas.Sandberg@ARM.com ptype = SimObject.allClasses[self.ptype_str] 17910461SAndreas.Sandberg@ARM.com assert isSimObjectClass(ptype) 18010461SAndreas.Sandberg@ARM.com self.ptype = ptype 18110461SAndreas.Sandberg@ARM.com return ptype 18210461SAndreas.Sandberg@ARM.com 18310461SAndreas.Sandberg@ARM.com raise AttributeError, "'%s' object has no attribute '%s'" % \ 18410461SAndreas.Sandberg@ARM.com (type(self).__name__, attr) 18510461SAndreas.Sandberg@ARM.com 18610461SAndreas.Sandberg@ARM.com def example_str(self): 18710461SAndreas.Sandberg@ARM.com if hasattr(self.ptype, "ex_str"): 18810461SAndreas.Sandberg@ARM.com return self.ptype.ex_str 18910461SAndreas.Sandberg@ARM.com else: 19010461SAndreas.Sandberg@ARM.com return self.ptype_str 19110461SAndreas.Sandberg@ARM.com 19210461SAndreas.Sandberg@ARM.com # Is the param available to be exposed on the command line 19310461SAndreas.Sandberg@ARM.com def isCmdLineSettable(self): 19410461SAndreas.Sandberg@ARM.com if hasattr(self.ptype, "cmd_line_settable"): 19510461SAndreas.Sandberg@ARM.com return self.ptype.cmd_line_settable 19610461SAndreas.Sandberg@ARM.com else: 19710461SAndreas.Sandberg@ARM.com return False 19810461SAndreas.Sandberg@ARM.com 19910461SAndreas.Sandberg@ARM.com def convert(self, value): 20010461SAndreas.Sandberg@ARM.com if isinstance(value, proxy.BaseProxy): 20110461SAndreas.Sandberg@ARM.com value.set_param_desc(self) 20210461SAndreas.Sandberg@ARM.com return value 20310461SAndreas.Sandberg@ARM.com if not hasattr(self, 'ptype') and isNullPointer(value): 20410461SAndreas.Sandberg@ARM.com # deferred evaluation of SimObject; continue to defer if 20510461SAndreas.Sandberg@ARM.com # we're just assigning a null pointer 20610461SAndreas.Sandberg@ARM.com return value 20710461SAndreas.Sandberg@ARM.com if isinstance(value, self.ptype): 20810461SAndreas.Sandberg@ARM.com return value 20910461SAndreas.Sandberg@ARM.com if isNullPointer(value) and isSimObjectClass(self.ptype): 21010461SAndreas.Sandberg@ARM.com return value 21110461SAndreas.Sandberg@ARM.com return self.ptype(value) 21210461SAndreas.Sandberg@ARM.com 21310461SAndreas.Sandberg@ARM.com def pretty_print(self, value): 21410461SAndreas.Sandberg@ARM.com if isinstance(value, proxy.BaseProxy): 21510461SAndreas.Sandberg@ARM.com return str(value) 21610461SAndreas.Sandberg@ARM.com if isNullPointer(value): 21710461SAndreas.Sandberg@ARM.com return NULL 21810461SAndreas.Sandberg@ARM.com return self.ptype(value).pretty_print(value) 21910461SAndreas.Sandberg@ARM.com 22010461SAndreas.Sandberg@ARM.com def cxx_predecls(self, code): 22110461SAndreas.Sandberg@ARM.com code('#include <cstddef>') 22210461SAndreas.Sandberg@ARM.com self.ptype.cxx_predecls(code) 22310461SAndreas.Sandberg@ARM.com 22410461SAndreas.Sandberg@ARM.com def pybind_predecls(self, code): 22510461SAndreas.Sandberg@ARM.com self.ptype.pybind_predecls(code) 22610461SAndreas.Sandberg@ARM.com 22710461SAndreas.Sandberg@ARM.com def cxx_decl(self, code): 22810461SAndreas.Sandberg@ARM.com code('${{self.ptype.cxx_type}} ${{self.name}};') 22910461SAndreas.Sandberg@ARM.com 23010461SAndreas.Sandberg@ARM.com# Vector-valued parameter description. Just like ParamDesc, except 23110461SAndreas.Sandberg@ARM.com# that the value is a vector (list) of the specified type instead of a 23210461SAndreas.Sandberg@ARM.com# single value. 23310461SAndreas.Sandberg@ARM.com 23410461SAndreas.Sandberg@ARM.comclass VectorParamValue(list): 23510461SAndreas.Sandberg@ARM.com __metaclass__ = MetaParamValue 23610461SAndreas.Sandberg@ARM.com def __setattr__(self, attr, value): 23710461SAndreas.Sandberg@ARM.com raise AttributeError, \ 23810461SAndreas.Sandberg@ARM.com "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 23910461SAndreas.Sandberg@ARM.com 24010461SAndreas.Sandberg@ARM.com def config_value(self): 24110461SAndreas.Sandberg@ARM.com return [v.config_value() for v in self] 24210461SAndreas.Sandberg@ARM.com 24310461SAndreas.Sandberg@ARM.com def ini_str(self): 24410461SAndreas.Sandberg@ARM.com return ' '.join([v.ini_str() for v in self]) 24510461SAndreas.Sandberg@ARM.com 24610461SAndreas.Sandberg@ARM.com def getValue(self): 24710461SAndreas.Sandberg@ARM.com return [ v.getValue() for v in self ] 24810461SAndreas.Sandberg@ARM.com 24910461SAndreas.Sandberg@ARM.com def unproxy(self, base): 25010461SAndreas.Sandberg@ARM.com if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 25110461SAndreas.Sandberg@ARM.com # The value is a proxy (e.g. Parent.any, Parent.all or 25210461SAndreas.Sandberg@ARM.com # Parent.x) therefore try resolve it 25310461SAndreas.Sandberg@ARM.com return self[0].unproxy(base) 25410461SAndreas.Sandberg@ARM.com else: 25510461SAndreas.Sandberg@ARM.com return [v.unproxy(base) for v in self] 25610461SAndreas.Sandberg@ARM.com 25710461SAndreas.Sandberg@ARM.comclass SimObjectVector(VectorParamValue): 25810461SAndreas.Sandberg@ARM.com # support clone operation 25910461SAndreas.Sandberg@ARM.com def __call__(self, **kwargs): 26010461SAndreas.Sandberg@ARM.com return SimObjectVector([v(**kwargs) for v in self]) 26110461SAndreas.Sandberg@ARM.com 26210461SAndreas.Sandberg@ARM.com def clear_parent(self, old_parent): 26310461SAndreas.Sandberg@ARM.com for v in self: 26410461SAndreas.Sandberg@ARM.com v.clear_parent(old_parent) 26510461SAndreas.Sandberg@ARM.com 26610461SAndreas.Sandberg@ARM.com def set_parent(self, parent, name): 26710461SAndreas.Sandberg@ARM.com if len(self) == 1: 26810461SAndreas.Sandberg@ARM.com self[0].set_parent(parent, name) 26910461SAndreas.Sandberg@ARM.com else: 27010461SAndreas.Sandberg@ARM.com width = int(math.ceil(math.log(len(self))/math.log(10))) 27110461SAndreas.Sandberg@ARM.com for i,v in enumerate(self): 27210461SAndreas.Sandberg@ARM.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 27310461SAndreas.Sandberg@ARM.com 27410461SAndreas.Sandberg@ARM.com def has_parent(self): 27510461SAndreas.Sandberg@ARM.com return any([e.has_parent() for e in self if not isNullPointer(e)]) 27610461SAndreas.Sandberg@ARM.com 27710461SAndreas.Sandberg@ARM.com # return 'cpu0 cpu1' etc. for print_ini() 27810461SAndreas.Sandberg@ARM.com def get_name(self): 27910461SAndreas.Sandberg@ARM.com return ' '.join([v._name for v in self]) 28010461SAndreas.Sandberg@ARM.com 28110461SAndreas.Sandberg@ARM.com # By iterating through the constituent members of the vector here 28210461SAndreas.Sandberg@ARM.com # we can nicely handle iterating over all a SimObject's children 28310461SAndreas.Sandberg@ARM.com # without having to provide lots of special functions on 28410461SAndreas.Sandberg@ARM.com # SimObjectVector directly. 28510461SAndreas.Sandberg@ARM.com def descendants(self): 28610461SAndreas.Sandberg@ARM.com for v in self: 28710461SAndreas.Sandberg@ARM.com for obj in v.descendants(): 28810461SAndreas.Sandberg@ARM.com yield obj 28910461SAndreas.Sandberg@ARM.com 29010461SAndreas.Sandberg@ARM.com def get_config_as_dict(self): 29110461SAndreas.Sandberg@ARM.com a = [] 29210461SAndreas.Sandberg@ARM.com for v in self: 29310461SAndreas.Sandberg@ARM.com a.append(v.get_config_as_dict()) 29410461SAndreas.Sandberg@ARM.com return a 29510461SAndreas.Sandberg@ARM.com 29610461SAndreas.Sandberg@ARM.com # If we are replacing an item in the vector, make sure to set the 29710461SAndreas.Sandberg@ARM.com # parent reference of the new SimObject to be the same as the parent 29810461SAndreas.Sandberg@ARM.com # of the SimObject being replaced. Useful to have if we created 29910461SAndreas.Sandberg@ARM.com # a SimObjectVector of temporary objects that will be modified later in 30010461SAndreas.Sandberg@ARM.com # configuration scripts. 30110461SAndreas.Sandberg@ARM.com def __setitem__(self, key, value): 30210461SAndreas.Sandberg@ARM.com val = self[key] 30310461SAndreas.Sandberg@ARM.com if value.has_parent(): 30410461SAndreas.Sandberg@ARM.com warn("SimObject %s already has a parent" % value.get_name() +\ 30510461SAndreas.Sandberg@ARM.com " that is being overwritten by a SimObjectVector") 30610461SAndreas.Sandberg@ARM.com value.set_parent(val.get_parent(), val._name) 30710461SAndreas.Sandberg@ARM.com super(SimObjectVector, self).__setitem__(key, value) 30810461SAndreas.Sandberg@ARM.com 30910461SAndreas.Sandberg@ARM.com # Enumerate the params of each member of the SimObject vector. Creates 31010461SAndreas.Sandberg@ARM.com # strings that will allow indexing into the vector by the python code and 31110461SAndreas.Sandberg@ARM.com # allow it to be specified on the command line. 31210461SAndreas.Sandberg@ARM.com def enumerateParams(self, flags_dict = {}, 31310461SAndreas.Sandberg@ARM.com cmd_line_str = "", 31410461SAndreas.Sandberg@ARM.com access_str = ""): 31510461SAndreas.Sandberg@ARM.com if hasattr(self, "_paramEnumed"): 31610461SAndreas.Sandberg@ARM.com print("Cycle detected enumerating params at %s?!" % (cmd_line_str)) 31710461SAndreas.Sandberg@ARM.com else: 31810461SAndreas.Sandberg@ARM.com x = 0 31910461SAndreas.Sandberg@ARM.com for vals in self: 32010461SAndreas.Sandberg@ARM.com # Each entry in the SimObjectVector should be an 32110461SAndreas.Sandberg@ARM.com # instance of a SimObject 32210461SAndreas.Sandberg@ARM.com flags_dict = vals.enumerateParams(flags_dict, 32310461SAndreas.Sandberg@ARM.com cmd_line_str + "%d." % x, 32410461SAndreas.Sandberg@ARM.com access_str + "[%d]." % x) 32510461SAndreas.Sandberg@ARM.com x = x + 1 32610461SAndreas.Sandberg@ARM.com 32710461SAndreas.Sandberg@ARM.com return flags_dict 32810461SAndreas.Sandberg@ARM.com 32910461SAndreas.Sandberg@ARM.comclass VectorParamDesc(ParamDesc): 33010461SAndreas.Sandberg@ARM.com # Convert assigned value to appropriate type. If the RHS is not a 33110461SAndreas.Sandberg@ARM.com # list or tuple, it generates a single-element list. 33210461SAndreas.Sandberg@ARM.com def convert(self, value): 33310461SAndreas.Sandberg@ARM.com if isinstance(value, (list, tuple)): 33410461SAndreas.Sandberg@ARM.com # list: coerce each element into new list 33510461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, v) for v in value ] 33610461SAndreas.Sandberg@ARM.com elif isinstance(value, str): 33710461SAndreas.Sandberg@ARM.com # If input is a csv string 33810461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, v) \ 33910461SAndreas.Sandberg@ARM.com for v in value.strip('[').strip(']').split(',') ] 34010461SAndreas.Sandberg@ARM.com else: 34110461SAndreas.Sandberg@ARM.com # singleton: coerce to a single-element list 34210461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, value) ] 34310461SAndreas.Sandberg@ARM.com 34410461SAndreas.Sandberg@ARM.com if isSimObjectSequence(tmp_list): 34510461SAndreas.Sandberg@ARM.com return SimObjectVector(tmp_list) 34610461SAndreas.Sandberg@ARM.com else: 34710461SAndreas.Sandberg@ARM.com return VectorParamValue(tmp_list) 34810461SAndreas.Sandberg@ARM.com 34910461SAndreas.Sandberg@ARM.com # Produce a human readable example string that describes 35010461SAndreas.Sandberg@ARM.com # how to set this vector parameter in the absence of a default 35110461SAndreas.Sandberg@ARM.com # value. 35210461SAndreas.Sandberg@ARM.com def example_str(self): 35310461SAndreas.Sandberg@ARM.com s = super(VectorParamDesc, self).example_str() 35410461SAndreas.Sandberg@ARM.com help_str = "[" + s + "," + s + ", ...]" 35510461SAndreas.Sandberg@ARM.com return help_str 35610461SAndreas.Sandberg@ARM.com 35710461SAndreas.Sandberg@ARM.com # Produce a human readable representation of the value of this vector param. 35810461SAndreas.Sandberg@ARM.com def pretty_print(self, value): 35910461SAndreas.Sandberg@ARM.com if isinstance(value, (list, tuple)): 36010461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 36110461SAndreas.Sandberg@ARM.com elif isinstance(value, str): 36210461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 36310461SAndreas.Sandberg@ARM.com else: 36410461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.pretty_print(self, value) ] 36510461SAndreas.Sandberg@ARM.com 36610461SAndreas.Sandberg@ARM.com return tmp_list 36710461SAndreas.Sandberg@ARM.com 36810461SAndreas.Sandberg@ARM.com # This is a helper function for the new config system 36910461SAndreas.Sandberg@ARM.com def __call__(self, value): 37010461SAndreas.Sandberg@ARM.com if isinstance(value, (list, tuple)): 37110461SAndreas.Sandberg@ARM.com # list: coerce each element into new list 37210461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, v) for v in value ] 37310461SAndreas.Sandberg@ARM.com elif isinstance(value, str): 37410461SAndreas.Sandberg@ARM.com # If input is a csv string 37510461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, v) \ 37610461SAndreas.Sandberg@ARM.com for v in value.strip('[').strip(']').split(',') ] 37710461SAndreas.Sandberg@ARM.com else: 37810461SAndreas.Sandberg@ARM.com # singleton: coerce to a single-element list 37910461SAndreas.Sandberg@ARM.com tmp_list = [ ParamDesc.convert(self, value) ] 38010461SAndreas.Sandberg@ARM.com 38110461SAndreas.Sandberg@ARM.com return VectorParamValue(tmp_list) 38210461SAndreas.Sandberg@ARM.com 38310461SAndreas.Sandberg@ARM.com def cxx_predecls(self, code): 38410461SAndreas.Sandberg@ARM.com code('#include <vector>') 38510461SAndreas.Sandberg@ARM.com self.ptype.cxx_predecls(code) 38610461SAndreas.Sandberg@ARM.com 38710461SAndreas.Sandberg@ARM.com def pybind_predecls(self, code): 38810461SAndreas.Sandberg@ARM.com code('#include <vector>') 38910461SAndreas.Sandberg@ARM.com self.ptype.pybind_predecls(code) 39010461SAndreas.Sandberg@ARM.com 39110461SAndreas.Sandberg@ARM.com def cxx_decl(self, code): 39210461SAndreas.Sandberg@ARM.com code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 39310461SAndreas.Sandberg@ARM.com 39410461SAndreas.Sandberg@ARM.comclass ParamFactory(object): 39510461SAndreas.Sandberg@ARM.com def __init__(self, param_desc_class, ptype_str = None): 39610461SAndreas.Sandberg@ARM.com self.param_desc_class = param_desc_class 39710461SAndreas.Sandberg@ARM.com self.ptype_str = ptype_str 39810461SAndreas.Sandberg@ARM.com 39910461SAndreas.Sandberg@ARM.com def __getattr__(self, attr): 40010461SAndreas.Sandberg@ARM.com if self.ptype_str: 40110461SAndreas.Sandberg@ARM.com attr = self.ptype_str + '.' + attr 40210461SAndreas.Sandberg@ARM.com return ParamFactory(self.param_desc_class, attr) 40310461SAndreas.Sandberg@ARM.com 40410461SAndreas.Sandberg@ARM.com # E.g., Param.Int(5, "number of widgets") 40510461SAndreas.Sandberg@ARM.com def __call__(self, *args, **kwargs): 40610461SAndreas.Sandberg@ARM.com ptype = None 40710461SAndreas.Sandberg@ARM.com try: 40810461SAndreas.Sandberg@ARM.com ptype = allParams[self.ptype_str] 40910461SAndreas.Sandberg@ARM.com except KeyError: 41010461SAndreas.Sandberg@ARM.com # if name isn't defined yet, assume it's a SimObject, and 41110461SAndreas.Sandberg@ARM.com # try to resolve it later 41210461SAndreas.Sandberg@ARM.com pass 41310461SAndreas.Sandberg@ARM.com return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 41410461SAndreas.Sandberg@ARM.com 41510461SAndreas.Sandberg@ARM.comParam = ParamFactory(ParamDesc) 41610461SAndreas.Sandberg@ARM.comVectorParam = ParamFactory(VectorParamDesc) 41710461SAndreas.Sandberg@ARM.com 41810461SAndreas.Sandberg@ARM.com##################################################################### 41910461SAndreas.Sandberg@ARM.com# 42010461SAndreas.Sandberg@ARM.com# Parameter Types 42110461SAndreas.Sandberg@ARM.com# 42210461SAndreas.Sandberg@ARM.com# Though native Python types could be used to specify parameter types 42310461SAndreas.Sandberg@ARM.com# (the 'ptype' field of the Param and VectorParam classes), it's more 42410461SAndreas.Sandberg@ARM.com# flexible to define our own set of types. This gives us more control 42510461SAndreas.Sandberg@ARM.com# over how Python expressions are converted to values (via the 42610461SAndreas.Sandberg@ARM.com# __init__() constructor) and how these values are printed out (via 42710461SAndreas.Sandberg@ARM.com# the __str__() conversion method). 42810461SAndreas.Sandberg@ARM.com# 42910461SAndreas.Sandberg@ARM.com##################################################################### 43010461SAndreas.Sandberg@ARM.com 43110461SAndreas.Sandberg@ARM.com# String-valued parameter. Just mixin the ParamValue class with the 43210461SAndreas.Sandberg@ARM.com# built-in str class. 43310461SAndreas.Sandberg@ARM.comclass String(ParamValue,str): 43410461SAndreas.Sandberg@ARM.com cxx_type = 'std::string' 43510461SAndreas.Sandberg@ARM.com cmd_line_settable = True 43610461SAndreas.Sandberg@ARM.com 43710461SAndreas.Sandberg@ARM.com @classmethod 43810461SAndreas.Sandberg@ARM.com def cxx_predecls(self, code): 43910461SAndreas.Sandberg@ARM.com code('#include <string>') 44010461SAndreas.Sandberg@ARM.com 44110461SAndreas.Sandberg@ARM.com def __call__(self, value): 44210461SAndreas.Sandberg@ARM.com self = value 44310461SAndreas.Sandberg@ARM.com return value 44410461SAndreas.Sandberg@ARM.com 44510461SAndreas.Sandberg@ARM.com @classmethod 44610461SAndreas.Sandberg@ARM.com def cxx_ini_parse(self, code, src, dest, ret): 44710461SAndreas.Sandberg@ARM.com code('%s = %s;' % (dest, src)) 44810461SAndreas.Sandberg@ARM.com code('%s true;' % ret) 44910461SAndreas.Sandberg@ARM.com 45010461SAndreas.Sandberg@ARM.com def getValue(self): 45110461SAndreas.Sandberg@ARM.com return self 45210461SAndreas.Sandberg@ARM.com 45310461SAndreas.Sandberg@ARM.com# superclass for "numeric" parameter values, to emulate math 45410461SAndreas.Sandberg@ARM.com# operations in a type-safe way. e.g., a Latency times an int returns 45510461SAndreas.Sandberg@ARM.com# a new Latency object. 45610461SAndreas.Sandberg@ARM.comclass NumericParamValue(ParamValue): 45710461SAndreas.Sandberg@ARM.com def __str__(self): 45810461SAndreas.Sandberg@ARM.com return str(self.value) 45910461SAndreas.Sandberg@ARM.com 46010461SAndreas.Sandberg@ARM.com def __float__(self): 46110461SAndreas.Sandberg@ARM.com return float(self.value) 46210461SAndreas.Sandberg@ARM.com 46310461SAndreas.Sandberg@ARM.com def __long__(self): 46410461SAndreas.Sandberg@ARM.com return long(self.value) 46510461SAndreas.Sandberg@ARM.com 46610461SAndreas.Sandberg@ARM.com def __int__(self): 46710461SAndreas.Sandberg@ARM.com return int(self.value) 46810461SAndreas.Sandberg@ARM.com 46910461SAndreas.Sandberg@ARM.com # hook for bounds checking 47010461SAndreas.Sandberg@ARM.com def _check(self): 47110461SAndreas.Sandberg@ARM.com return 47210461SAndreas.Sandberg@ARM.com 47310461SAndreas.Sandberg@ARM.com def __mul__(self, other): 47410461SAndreas.Sandberg@ARM.com newobj = self.__class__(self) 47510461SAndreas.Sandberg@ARM.com newobj.value *= other 47610461SAndreas.Sandberg@ARM.com newobj._check() 47710461SAndreas.Sandberg@ARM.com return newobj 47810461SAndreas.Sandberg@ARM.com 47910461SAndreas.Sandberg@ARM.com __rmul__ = __mul__ 48010461SAndreas.Sandberg@ARM.com 48110461SAndreas.Sandberg@ARM.com def __div__(self, other): 48210461SAndreas.Sandberg@ARM.com newobj = self.__class__(self) 48310461SAndreas.Sandberg@ARM.com newobj.value /= other 48410461SAndreas.Sandberg@ARM.com newobj._check() 48510461SAndreas.Sandberg@ARM.com return newobj 48610461SAndreas.Sandberg@ARM.com 48710461SAndreas.Sandberg@ARM.com def __sub__(self, other): 48810461SAndreas.Sandberg@ARM.com newobj = self.__class__(self) 48910461SAndreas.Sandberg@ARM.com newobj.value -= other 49010461SAndreas.Sandberg@ARM.com newobj._check() 49110461SAndreas.Sandberg@ARM.com return newobj 49210461SAndreas.Sandberg@ARM.com 49310461SAndreas.Sandberg@ARM.com def config_value(self): 49410461SAndreas.Sandberg@ARM.com return self.value 49510461SAndreas.Sandberg@ARM.com 49610461SAndreas.Sandberg@ARM.com @classmethod 49710461SAndreas.Sandberg@ARM.com def cxx_ini_predecls(cls, code): 49810461SAndreas.Sandberg@ARM.com # Assume that base/str.hh will be included anyway 49910461SAndreas.Sandberg@ARM.com # code('#include "base/str.hh"') 50010461SAndreas.Sandberg@ARM.com pass 50110461SAndreas.Sandberg@ARM.com 50210461SAndreas.Sandberg@ARM.com # The default for parsing PODs from an .ini entry is to extract from an 50310461SAndreas.Sandberg@ARM.com # istringstream and let overloading choose the right type according to 50410461SAndreas.Sandberg@ARM.com # the dest type. 50510461SAndreas.Sandberg@ARM.com @classmethod 50610461SAndreas.Sandberg@ARM.com def cxx_ini_parse(self, code, src, dest, ret): 50710461SAndreas.Sandberg@ARM.com code('%s to_number(%s, %s);' % (ret, src, dest)) 50810461SAndreas.Sandberg@ARM.com 50910461SAndreas.Sandberg@ARM.com# Metaclass for bounds-checked integer parameters. See CheckedInt. 51010461SAndreas.Sandberg@ARM.comclass CheckedIntType(MetaParamValue): 51110461SAndreas.Sandberg@ARM.com def __init__(cls, name, bases, dict): 51210461SAndreas.Sandberg@ARM.com super(CheckedIntType, cls).__init__(name, bases, dict) 51310461SAndreas.Sandberg@ARM.com 51410461SAndreas.Sandberg@ARM.com # CheckedInt is an abstract base class, so we actually don't 51510461SAndreas.Sandberg@ARM.com # want to do any processing on it... the rest of this code is 51610461SAndreas.Sandberg@ARM.com # just for classes that derive from CheckedInt. 51710461SAndreas.Sandberg@ARM.com if name == 'CheckedInt': 51810461SAndreas.Sandberg@ARM.com return 51910461SAndreas.Sandberg@ARM.com 52010461SAndreas.Sandberg@ARM.com if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 52110461SAndreas.Sandberg@ARM.com if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 52210461SAndreas.Sandberg@ARM.com panic("CheckedInt subclass %s must define either\n" \ 52310461SAndreas.Sandberg@ARM.com " 'min' and 'max' or 'size' and 'unsigned'\n", 52410461SAndreas.Sandberg@ARM.com name); 52510461SAndreas.Sandberg@ARM.com if cls.unsigned: 52610461SAndreas.Sandberg@ARM.com cls.min = 0 52710461SAndreas.Sandberg@ARM.com cls.max = 2 ** cls.size - 1 52810461SAndreas.Sandberg@ARM.com else: 52910461SAndreas.Sandberg@ARM.com cls.min = -(2 ** (cls.size - 1)) 53010461SAndreas.Sandberg@ARM.com cls.max = (2 ** (cls.size - 1)) - 1 53110461SAndreas.Sandberg@ARM.com 53210461SAndreas.Sandberg@ARM.com# Abstract superclass for bounds-checked integer parameters. This 53310461SAndreas.Sandberg@ARM.com# class is subclassed to generate parameter classes with specific 53410461SAndreas.Sandberg@ARM.com# bounds. Initialization of the min and max bounds is done in the 53510461SAndreas.Sandberg@ARM.com# metaclass CheckedIntType.__init__. 53610461SAndreas.Sandberg@ARM.comclass CheckedInt(NumericParamValue): 53710461SAndreas.Sandberg@ARM.com __metaclass__ = CheckedIntType 53810461SAndreas.Sandberg@ARM.com cmd_line_settable = True 53910461SAndreas.Sandberg@ARM.com 54010461SAndreas.Sandberg@ARM.com def _check(self): 54110461SAndreas.Sandberg@ARM.com if not self.min <= self.value <= self.max: 54210461SAndreas.Sandberg@ARM.com raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 54310461SAndreas.Sandberg@ARM.com (self.min, self.value, self.max) 54410461SAndreas.Sandberg@ARM.com 54510461SAndreas.Sandberg@ARM.com def __init__(self, value): 54610461SAndreas.Sandberg@ARM.com if isinstance(value, str): 54710461SAndreas.Sandberg@ARM.com self.value = convert.toInteger(value) 54810461SAndreas.Sandberg@ARM.com elif isinstance(value, (int, long, float, NumericParamValue)): 54910461SAndreas.Sandberg@ARM.com self.value = long(value) 55010461SAndreas.Sandberg@ARM.com else: 55110461SAndreas.Sandberg@ARM.com raise TypeError, "Can't convert object of type %s to CheckedInt" \ 55210461SAndreas.Sandberg@ARM.com % type(value).__name__ 55310461SAndreas.Sandberg@ARM.com self._check() 55410461SAndreas.Sandberg@ARM.com 55510461SAndreas.Sandberg@ARM.com def __call__(self, value): 55610461SAndreas.Sandberg@ARM.com self.__init__(value) 55710461SAndreas.Sandberg@ARM.com return value 55810461SAndreas.Sandberg@ARM.com 55910461SAndreas.Sandberg@ARM.com @classmethod 560 def cxx_predecls(cls, code): 561 # most derived types require this, so we just do it here once 562 code('#include "base/types.hh"') 563 564 def getValue(self): 565 return long(self.value) 566 567class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 568class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 569 570class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 571class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 572class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 573class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 574class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 575class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 576class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 577class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 578 579class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 580class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 581class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 582class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 583 584class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 585 586class Cycles(CheckedInt): 587 cxx_type = 'Cycles' 588 size = 64 589 unsigned = True 590 591 def getValue(self): 592 from _m5.core import Cycles 593 return Cycles(self.value) 594 595 @classmethod 596 def cxx_ini_predecls(cls, code): 597 # Assume that base/str.hh will be included anyway 598 # code('#include "base/str.hh"') 599 pass 600 601 @classmethod 602 def cxx_ini_parse(cls, code, src, dest, ret): 603 code('uint64_t _temp;') 604 code('bool _ret = to_number(%s, _temp);' % src) 605 code('if (_ret)') 606 code(' %s = Cycles(_temp);' % dest) 607 code('%s _ret;' % ret) 608 609class Float(ParamValue, float): 610 cxx_type = 'double' 611 cmd_line_settable = True 612 613 def __init__(self, value): 614 if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 615 self.value = float(value) 616 else: 617 raise TypeError, "Can't convert object of type %s to Float" \ 618 % type(value).__name__ 619 620 def __call__(self, value): 621 self.__init__(value) 622 return value 623 624 def getValue(self): 625 return float(self.value) 626 627 def config_value(self): 628 return self 629 630 @classmethod 631 def cxx_ini_predecls(cls, code): 632 code('#include <sstream>') 633 634 @classmethod 635 def cxx_ini_parse(self, code, src, dest, ret): 636 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 637 638class MemorySize(CheckedInt): 639 cxx_type = 'uint64_t' 640 ex_str = '512MB' 641 size = 64 642 unsigned = True 643 def __init__(self, value): 644 if isinstance(value, MemorySize): 645 self.value = value.value 646 else: 647 self.value = convert.toMemorySize(value) 648 self._check() 649 650class MemorySize32(CheckedInt): 651 cxx_type = 'uint32_t' 652 ex_str = '512MB' 653 size = 32 654 unsigned = True 655 def __init__(self, value): 656 if isinstance(value, MemorySize): 657 self.value = value.value 658 else: 659 self.value = convert.toMemorySize(value) 660 self._check() 661 662class Addr(CheckedInt): 663 cxx_type = 'Addr' 664 size = 64 665 unsigned = True 666 def __init__(self, value): 667 if isinstance(value, Addr): 668 self.value = value.value 669 else: 670 try: 671 # Often addresses are referred to with sizes. Ex: A device 672 # base address is at "512MB". Use toMemorySize() to convert 673 # these into addresses. If the address is not specified with a 674 # "size", an exception will occur and numeric translation will 675 # proceed below. 676 self.value = convert.toMemorySize(value) 677 except (TypeError, ValueError): 678 # Convert number to string and use long() to do automatic 679 # base conversion (requires base=0 for auto-conversion) 680 self.value = long(str(value), base=0) 681 682 self._check() 683 def __add__(self, other): 684 if isinstance(other, Addr): 685 return self.value + other.value 686 else: 687 return self.value + other 688 def pretty_print(self, value): 689 try: 690 val = convert.toMemorySize(value) 691 except TypeError: 692 val = long(value) 693 return "0x%x" % long(val) 694 695class AddrRange(ParamValue): 696 cxx_type = 'AddrRange' 697 698 def __init__(self, *args, **kwargs): 699 # Disable interleaving and hashing by default 700 self.intlvHighBit = 0 701 self.xorHighBit = 0 702 self.intlvBits = 0 703 self.intlvMatch = 0 704 705 def handle_kwargs(self, kwargs): 706 # An address range needs to have an upper limit, specified 707 # either explicitly with an end, or as an offset using the 708 # size keyword. 709 if 'end' in kwargs: 710 self.end = Addr(kwargs.pop('end')) 711 elif 'size' in kwargs: 712 self.end = self.start + Addr(kwargs.pop('size')) - 1 713 else: 714 raise TypeError, "Either end or size must be specified" 715 716 # Now on to the optional bit 717 if 'intlvHighBit' in kwargs: 718 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 719 if 'xorHighBit' in kwargs: 720 self.xorHighBit = int(kwargs.pop('xorHighBit')) 721 if 'intlvBits' in kwargs: 722 self.intlvBits = int(kwargs.pop('intlvBits')) 723 if 'intlvMatch' in kwargs: 724 self.intlvMatch = int(kwargs.pop('intlvMatch')) 725 726 if len(args) == 0: 727 self.start = Addr(kwargs.pop('start')) 728 handle_kwargs(self, kwargs) 729 730 elif len(args) == 1: 731 if kwargs: 732 self.start = Addr(args[0]) 733 handle_kwargs(self, kwargs) 734 elif isinstance(args[0], (list, tuple)): 735 self.start = Addr(args[0][0]) 736 self.end = Addr(args[0][1]) 737 else: 738 self.start = Addr(0) 739 self.end = Addr(args[0]) - 1 740 741 elif len(args) == 2: 742 self.start = Addr(args[0]) 743 self.end = Addr(args[1]) 744 else: 745 raise TypeError, "Too many arguments specified" 746 747 if kwargs: 748 raise TypeError, "Too many keywords: %s" % kwargs.keys() 749 750 def __str__(self): 751 return '%s:%s:%s:%s:%s:%s' \ 752 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 753 self.intlvBits, self.intlvMatch) 754 755 def size(self): 756 # Divide the size by the size of the interleaving slice 757 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 758 759 @classmethod 760 def cxx_predecls(cls, code): 761 Addr.cxx_predecls(code) 762 code('#include "base/addr_range.hh"') 763 764 @classmethod 765 def pybind_predecls(cls, code): 766 Addr.pybind_predecls(code) 767 code('#include "base/addr_range.hh"') 768 769 @classmethod 770 def cxx_ini_predecls(cls, code): 771 code('#include <sstream>') 772 773 @classmethod 774 def cxx_ini_parse(cls, code, src, dest, ret): 775 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 776 code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 777 code('char _sep;') 778 code('std::istringstream _stream(${src});') 779 code('_stream >> _start;') 780 code('_stream.get(_sep);') 781 code('_stream >> _end;') 782 code('if (!_stream.fail() && !_stream.eof()) {') 783 code(' _stream.get(_sep);') 784 code(' _stream >> _intlvHighBit;') 785 code(' _stream.get(_sep);') 786 code(' _stream >> _xorHighBit;') 787 code(' _stream.get(_sep);') 788 code(' _stream >> _intlvBits;') 789 code(' _stream.get(_sep);') 790 code(' _stream >> _intlvMatch;') 791 code('}') 792 code('bool _ret = !_stream.fail() &&' 793 '_stream.eof() && _sep == \':\';') 794 code('if (_ret)') 795 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 796 _xorHighBit, _intlvBits, _intlvMatch);') 797 code('${ret} _ret;') 798 799 def getValue(self): 800 # Go from the Python class to the wrapped C++ class 801 from _m5.range import AddrRange 802 803 return AddrRange(long(self.start), long(self.end), 804 int(self.intlvHighBit), int(self.xorHighBit), 805 int(self.intlvBits), int(self.intlvMatch)) 806 807# Boolean parameter type. Python doesn't let you subclass bool, since 808# it doesn't want to let you create multiple instances of True and 809# False. Thus this is a little more complicated than String. 810class Bool(ParamValue): 811 cxx_type = 'bool' 812 cmd_line_settable = True 813 814 def __init__(self, value): 815 try: 816 self.value = convert.toBool(value) 817 except TypeError: 818 self.value = bool(value) 819 820 def __call__(self, value): 821 self.__init__(value) 822 return value 823 824 def getValue(self): 825 return bool(self.value) 826 827 def __str__(self): 828 return str(self.value) 829 830 # implement truth value testing for Bool parameters so that these params 831 # evaluate correctly during the python configuration phase 832 def __nonzero__(self): 833 return bool(self.value) 834 835 def ini_str(self): 836 if self.value: 837 return 'true' 838 return 'false' 839 840 def config_value(self): 841 return self.value 842 843 @classmethod 844 def cxx_ini_predecls(cls, code): 845 # Assume that base/str.hh will be included anyway 846 # code('#include "base/str.hh"') 847 pass 848 849 @classmethod 850 def cxx_ini_parse(cls, code, src, dest, ret): 851 code('%s to_bool(%s, %s);' % (ret, src, dest)) 852 853def IncEthernetAddr(addr, val = 1): 854 bytes = map(lambda x: int(x, 16), addr.split(':')) 855 bytes[5] += val 856 for i in (5, 4, 3, 2, 1): 857 val,rem = divmod(bytes[i], 256) 858 bytes[i] = rem 859 if val == 0: 860 break 861 bytes[i - 1] += val 862 assert(bytes[0] <= 255) 863 return ':'.join(map(lambda x: '%02x' % x, bytes)) 864 865_NextEthernetAddr = "00:90:00:00:00:01" 866def NextEthernetAddr(): 867 global _NextEthernetAddr 868 869 value = _NextEthernetAddr 870 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 871 return value 872 873class EthernetAddr(ParamValue): 874 cxx_type = 'Net::EthAddr' 875 ex_str = "00:90:00:00:00:01" 876 cmd_line_settable = True 877 878 @classmethod 879 def cxx_predecls(cls, code): 880 code('#include "base/inet.hh"') 881 882 def __init__(self, value): 883 if value == NextEthernetAddr: 884 self.value = value 885 return 886 887 if not isinstance(value, str): 888 raise TypeError, "expected an ethernet address and didn't get one" 889 890 bytes = value.split(':') 891 if len(bytes) != 6: 892 raise TypeError, 'invalid ethernet address %s' % value 893 894 for byte in bytes: 895 if not 0 <= int(byte, base=16) <= 0xff: 896 raise TypeError, 'invalid ethernet address %s' % value 897 898 self.value = value 899 900 def __call__(self, value): 901 self.__init__(value) 902 return value 903 904 def unproxy(self, base): 905 if self.value == NextEthernetAddr: 906 return EthernetAddr(self.value()) 907 return self 908 909 def getValue(self): 910 from _m5.net import EthAddr 911 return EthAddr(self.value) 912 913 def __str__(self): 914 return self.value 915 916 def ini_str(self): 917 return self.value 918 919 @classmethod 920 def cxx_ini_parse(self, code, src, dest, ret): 921 code('%s = Net::EthAddr(%s);' % (dest, src)) 922 code('%s true;' % ret) 923 924# When initializing an IpAddress, pass in an existing IpAddress, a string of 925# the form "a.b.c.d", or an integer representing an IP. 926class IpAddress(ParamValue): 927 cxx_type = 'Net::IpAddress' 928 ex_str = "127.0.0.1" 929 cmd_line_settable = True 930 931 @classmethod 932 def cxx_predecls(cls, code): 933 code('#include "base/inet.hh"') 934 935 def __init__(self, value): 936 if isinstance(value, IpAddress): 937 self.ip = value.ip 938 else: 939 try: 940 self.ip = convert.toIpAddress(value) 941 except TypeError: 942 self.ip = long(value) 943 self.verifyIp() 944 945 def __call__(self, value): 946 self.__init__(value) 947 return value 948 949 def __str__(self): 950 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 951 return '%d.%d.%d.%d' % tuple(tup) 952 953 def __eq__(self, other): 954 if isinstance(other, IpAddress): 955 return self.ip == other.ip 956 elif isinstance(other, str): 957 try: 958 return self.ip == convert.toIpAddress(other) 959 except: 960 return False 961 else: 962 return self.ip == other 963 964 def __ne__(self, other): 965 return not (self == other) 966 967 def verifyIp(self): 968 if self.ip < 0 or self.ip >= (1 << 32): 969 raise TypeError, "invalid ip address %#08x" % self.ip 970 971 def getValue(self): 972 from _m5.net import IpAddress 973 return IpAddress(self.ip) 974 975# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 976# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 977# positional or keyword arguments. 978class IpNetmask(IpAddress): 979 cxx_type = 'Net::IpNetmask' 980 ex_str = "127.0.0.0/24" 981 cmd_line_settable = True 982 983 @classmethod 984 def cxx_predecls(cls, code): 985 code('#include "base/inet.hh"') 986 987 def __init__(self, *args, **kwargs): 988 def handle_kwarg(self, kwargs, key, elseVal = None): 989 if key in kwargs: 990 setattr(self, key, kwargs.pop(key)) 991 elif elseVal: 992 setattr(self, key, elseVal) 993 else: 994 raise TypeError, "No value set for %s" % key 995 996 if len(args) == 0: 997 handle_kwarg(self, kwargs, 'ip') 998 handle_kwarg(self, kwargs, 'netmask') 999 1000 elif len(args) == 1: 1001 if kwargs: 1002 if not 'ip' in kwargs and not 'netmask' in kwargs: 1003 raise TypeError, "Invalid arguments" 1004 handle_kwarg(self, kwargs, 'ip', args[0]) 1005 handle_kwarg(self, kwargs, 'netmask', args[0]) 1006 elif isinstance(args[0], IpNetmask): 1007 self.ip = args[0].ip 1008 self.netmask = args[0].netmask 1009 else: 1010 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1011 1012 elif len(args) == 2: 1013 self.ip = args[0] 1014 self.netmask = args[1] 1015 else: 1016 raise TypeError, "Too many arguments specified" 1017 1018 if kwargs: 1019 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1020 1021 self.verify() 1022 1023 def __call__(self, value): 1024 self.__init__(value) 1025 return value 1026 1027 def __str__(self): 1028 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1029 1030 def __eq__(self, other): 1031 if isinstance(other, IpNetmask): 1032 return self.ip == other.ip and self.netmask == other.netmask 1033 elif isinstance(other, str): 1034 try: 1035 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1036 except: 1037 return False 1038 else: 1039 return False 1040 1041 def verify(self): 1042 self.verifyIp() 1043 if self.netmask < 0 or self.netmask > 32: 1044 raise TypeError, "invalid netmask %d" % netmask 1045 1046 def getValue(self): 1047 from _m5.net import IpNetmask 1048 return IpNetmask(self.ip, self.netmask) 1049 1050# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1051# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1052class IpWithPort(IpAddress): 1053 cxx_type = 'Net::IpWithPort' 1054 ex_str = "127.0.0.1:80" 1055 cmd_line_settable = True 1056 1057 @classmethod 1058 def cxx_predecls(cls, code): 1059 code('#include "base/inet.hh"') 1060 1061 def __init__(self, *args, **kwargs): 1062 def handle_kwarg(self, kwargs, key, elseVal = None): 1063 if key in kwargs: 1064 setattr(self, key, kwargs.pop(key)) 1065 elif elseVal: 1066 setattr(self, key, elseVal) 1067 else: 1068 raise TypeError, "No value set for %s" % key 1069 1070 if len(args) == 0: 1071 handle_kwarg(self, kwargs, 'ip') 1072 handle_kwarg(self, kwargs, 'port') 1073 1074 elif len(args) == 1: 1075 if kwargs: 1076 if not 'ip' in kwargs and not 'port' in kwargs: 1077 raise TypeError, "Invalid arguments" 1078 handle_kwarg(self, kwargs, 'ip', args[0]) 1079 handle_kwarg(self, kwargs, 'port', args[0]) 1080 elif isinstance(args[0], IpWithPort): 1081 self.ip = args[0].ip 1082 self.port = args[0].port 1083 else: 1084 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1085 1086 elif len(args) == 2: 1087 self.ip = args[0] 1088 self.port = args[1] 1089 else: 1090 raise TypeError, "Too many arguments specified" 1091 1092 if kwargs: 1093 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1094 1095 self.verify() 1096 1097 def __call__(self, value): 1098 self.__init__(value) 1099 return value 1100 1101 def __str__(self): 1102 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1103 1104 def __eq__(self, other): 1105 if isinstance(other, IpWithPort): 1106 return self.ip == other.ip and self.port == other.port 1107 elif isinstance(other, str): 1108 try: 1109 return (self.ip, self.port) == convert.toIpWithPort(other) 1110 except: 1111 return False 1112 else: 1113 return False 1114 1115 def verify(self): 1116 self.verifyIp() 1117 if self.port < 0 or self.port > 0xffff: 1118 raise TypeError, "invalid port %d" % self.port 1119 1120 def getValue(self): 1121 from _m5.net import IpWithPort 1122 return IpWithPort(self.ip, self.port) 1123 1124time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1125 "%a %b %d %H:%M:%S %Y", 1126 "%Y/%m/%d %H:%M:%S", 1127 "%Y/%m/%d %H:%M", 1128 "%Y/%m/%d", 1129 "%m/%d/%Y %H:%M:%S", 1130 "%m/%d/%Y %H:%M", 1131 "%m/%d/%Y", 1132 "%m/%d/%y %H:%M:%S", 1133 "%m/%d/%y %H:%M", 1134 "%m/%d/%y"] 1135 1136 1137def parse_time(value): 1138 from time import gmtime, strptime, struct_time, time 1139 from datetime import datetime, date 1140 1141 if isinstance(value, struct_time): 1142 return value 1143 1144 if isinstance(value, (int, long)): 1145 return gmtime(value) 1146 1147 if isinstance(value, (datetime, date)): 1148 return value.timetuple() 1149 1150 if isinstance(value, str): 1151 if value in ('Now', 'Today'): 1152 return time.gmtime(time.time()) 1153 1154 for format in time_formats: 1155 try: 1156 return strptime(value, format) 1157 except ValueError: 1158 pass 1159 1160 raise ValueError, "Could not parse '%s' as a time" % value 1161 1162class Time(ParamValue): 1163 cxx_type = 'tm' 1164 1165 @classmethod 1166 def cxx_predecls(cls, code): 1167 code('#include <time.h>') 1168 1169 def __init__(self, value): 1170 self.value = parse_time(value) 1171 1172 def __call__(self, value): 1173 self.__init__(value) 1174 return value 1175 1176 def getValue(self): 1177 from _m5.core import tm 1178 import calendar 1179 1180 return tm.gmtime(calendar.timegm(self.value)) 1181 1182 def __str__(self): 1183 return time.asctime(self.value) 1184 1185 def ini_str(self): 1186 return str(self) 1187 1188 def get_config_as_dict(self): 1189 assert false 1190 return str(self) 1191 1192 @classmethod 1193 def cxx_ini_predecls(cls, code): 1194 code('#include <time.h>') 1195 1196 @classmethod 1197 def cxx_ini_parse(cls, code, src, dest, ret): 1198 code('char *_parse_ret = strptime((${src}).c_str(),') 1199 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1200 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1201 1202# Enumerated types are a little more complex. The user specifies the 1203# type as Enum(foo) where foo is either a list or dictionary of 1204# alternatives (typically strings, but not necessarily so). (In the 1205# long run, the integer value of the parameter will be the list index 1206# or the corresponding dictionary value. For now, since we only check 1207# that the alternative is valid and then spit it into a .ini file, 1208# there's not much point in using the dictionary.) 1209 1210# What Enum() must do is generate a new type encapsulating the 1211# provided list/dictionary so that specific values of the parameter 1212# can be instances of that type. We define two hidden internal 1213# classes (_ListEnum and _DictEnum) to serve as base classes, then 1214# derive the new type from the appropriate base class on the fly. 1215 1216allEnums = {} 1217# Metaclass for Enum types 1218class MetaEnum(MetaParamValue): 1219 def __new__(mcls, name, bases, dict): 1220 assert name not in allEnums 1221 1222 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1223 allEnums[name] = cls 1224 return cls 1225 1226 def __init__(cls, name, bases, init_dict): 1227 if init_dict.has_key('map'): 1228 if not isinstance(cls.map, dict): 1229 raise TypeError, "Enum-derived class attribute 'map' " \ 1230 "must be of type dict" 1231 # build list of value strings from map 1232 cls.vals = cls.map.keys() 1233 cls.vals.sort() 1234 elif init_dict.has_key('vals'): 1235 if not isinstance(cls.vals, list): 1236 raise TypeError, "Enum-derived class attribute 'vals' " \ 1237 "must be of type list" 1238 # build string->value map from vals sequence 1239 cls.map = {} 1240 for idx,val in enumerate(cls.vals): 1241 cls.map[val] = idx 1242 else: 1243 raise TypeError, "Enum-derived class must define "\ 1244 "attribute 'map' or 'vals'" 1245 1246 cls.cxx_type = 'Enums::%s' % name 1247 1248 super(MetaEnum, cls).__init__(name, bases, init_dict) 1249 1250 # Generate C++ class declaration for this enum type. 1251 # Note that we wrap the enum in a class/struct to act as a namespace, 1252 # so that the enum strings can be brief w/o worrying about collisions. 1253 def cxx_decl(cls, code): 1254 wrapper_name = cls.wrapper_name 1255 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1256 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1257 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1258 1259 code('''\ 1260#ifndef $idem_macro 1261#define $idem_macro 1262 1263$wrapper $wrapper_name { 1264 enum $name { 1265''') 1266 code.indent(2) 1267 for val in cls.vals: 1268 code('$val = ${{cls.map[val]}},') 1269 code('Num_$name = ${{len(cls.vals)}}') 1270 code.dedent(2) 1271 code(' };') 1272 1273 if cls.wrapper_is_struct: 1274 code(' static const char *${name}Strings[Num_${name}];') 1275 code('};') 1276 else: 1277 code('extern const char *${name}Strings[Num_${name}];') 1278 code('}') 1279 1280 code() 1281 code('#endif // $idem_macro') 1282 1283 def cxx_def(cls, code): 1284 wrapper_name = cls.wrapper_name 1285 file_name = cls.__name__ 1286 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1287 1288 code('#include "enums/$file_name.hh"') 1289 if cls.wrapper_is_struct: 1290 code('const char *${wrapper_name}::${name}Strings' 1291 '[Num_${name}] =') 1292 else: 1293 code('namespace Enums {') 1294 code.indent(1) 1295 code(' const char *${name}Strings[Num_${name}] =') 1296 1297 code('{') 1298 code.indent(1) 1299 for val in cls.vals: 1300 code('"$val",') 1301 code.dedent(1) 1302 code('};') 1303 1304 if not cls.wrapper_is_struct: 1305 code('} // namespace $wrapper_name') 1306 code.dedent(1) 1307 1308 def pybind_def(cls, code): 1309 name = cls.__name__ 1310 wrapper_name = cls.wrapper_name 1311 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1312 1313 code('''#include "pybind11/pybind11.h" 1314#include "pybind11/stl.h" 1315 1316#include <sim/init.hh> 1317 1318namespace py = pybind11; 1319 1320static void 1321module_init(py::module &m_internal) 1322{ 1323 py::module m = m_internal.def_submodule("enum_${name}"); 1324 1325 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}") 1326''') 1327 1328 code.indent() 1329 code.indent() 1330 for val in cls.vals: 1331 code('.value("${val}", ${wrapper_name}::${val})') 1332 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1333 code('.export_values()') 1334 code(';') 1335 code.dedent() 1336 1337 code('}') 1338 code.dedent() 1339 code() 1340 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1341 1342 1343# Base class for enum types. 1344class Enum(ParamValue): 1345 __metaclass__ = MetaEnum 1346 vals = [] 1347 cmd_line_settable = True 1348 1349 # The name of the wrapping namespace or struct 1350 wrapper_name = 'Enums' 1351 1352 # If true, the enum is wrapped in a struct rather than a namespace 1353 wrapper_is_struct = False 1354 1355 # If not None, use this as the enum name rather than this class name 1356 enum_name = None 1357 1358 def __init__(self, value): 1359 if value not in self.map: 1360 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1361 % (value, self.vals) 1362 self.value = value 1363 1364 def __call__(self, value): 1365 self.__init__(value) 1366 return value 1367 1368 @classmethod 1369 def cxx_predecls(cls, code): 1370 code('#include "enums/$0.hh"', cls.__name__) 1371 1372 @classmethod 1373 def cxx_ini_parse(cls, code, src, dest, ret): 1374 code('if (false) {') 1375 for elem_name in cls.map.iterkeys(): 1376 code('} else if (%s == "%s") {' % (src, elem_name)) 1377 code.indent() 1378 code('%s = Enums::%s;' % (dest, elem_name)) 1379 code('%s true;' % ret) 1380 code.dedent() 1381 code('} else {') 1382 code(' %s false;' % ret) 1383 code('}') 1384 1385 def getValue(self): 1386 import m5.internal.params 1387 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1388 return e(self.map[self.value]) 1389 1390 def __str__(self): 1391 return self.value 1392 1393# how big does a rounding error need to be before we warn about it? 1394frequency_tolerance = 0.001 # 0.1% 1395 1396class TickParamValue(NumericParamValue): 1397 cxx_type = 'Tick' 1398 ex_str = "1MHz" 1399 cmd_line_settable = True 1400 1401 @classmethod 1402 def cxx_predecls(cls, code): 1403 code('#include "base/types.hh"') 1404 1405 def __call__(self, value): 1406 self.__init__(value) 1407 return value 1408 1409 def getValue(self): 1410 return long(self.value) 1411 1412 @classmethod 1413 def cxx_ini_predecls(cls, code): 1414 code('#include <sstream>') 1415 1416 # Ticks are expressed in seconds in JSON files and in plain 1417 # Ticks in .ini files. Switch based on a config flag 1418 @classmethod 1419 def cxx_ini_parse(self, code, src, dest, ret): 1420 code('${ret} to_number(${src}, ${dest});') 1421 1422class Latency(TickParamValue): 1423 ex_str = "100ns" 1424 1425 def __init__(self, value): 1426 if isinstance(value, (Latency, Clock)): 1427 self.ticks = value.ticks 1428 self.value = value.value 1429 elif isinstance(value, Frequency): 1430 self.ticks = value.ticks 1431 self.value = 1.0 / value.value 1432 elif value.endswith('t'): 1433 self.ticks = True 1434 self.value = int(value[:-1]) 1435 else: 1436 self.ticks = False 1437 self.value = convert.toLatency(value) 1438 1439 def __call__(self, value): 1440 self.__init__(value) 1441 return value 1442 1443 def __getattr__(self, attr): 1444 if attr in ('latency', 'period'): 1445 return self 1446 if attr == 'frequency': 1447 return Frequency(self) 1448 raise AttributeError, "Latency object has no attribute '%s'" % attr 1449 1450 def getValue(self): 1451 if self.ticks or self.value == 0: 1452 value = self.value 1453 else: 1454 value = ticks.fromSeconds(self.value) 1455 return long(value) 1456 1457 def config_value(self): 1458 return self.getValue() 1459 1460 # convert latency to ticks 1461 def ini_str(self): 1462 return '%d' % self.getValue() 1463 1464class Frequency(TickParamValue): 1465 ex_str = "1GHz" 1466 1467 def __init__(self, value): 1468 if isinstance(value, (Latency, Clock)): 1469 if value.value == 0: 1470 self.value = 0 1471 else: 1472 self.value = 1.0 / value.value 1473 self.ticks = value.ticks 1474 elif isinstance(value, Frequency): 1475 self.value = value.value 1476 self.ticks = value.ticks 1477 else: 1478 self.ticks = False 1479 self.value = convert.toFrequency(value) 1480 1481 def __call__(self, value): 1482 self.__init__(value) 1483 return value 1484 1485 def __getattr__(self, attr): 1486 if attr == 'frequency': 1487 return self 1488 if attr in ('latency', 'period'): 1489 return Latency(self) 1490 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1491 1492 # convert latency to ticks 1493 def getValue(self): 1494 if self.ticks or self.value == 0: 1495 value = self.value 1496 else: 1497 value = ticks.fromSeconds(1.0 / self.value) 1498 return long(value) 1499 1500 def config_value(self): 1501 return self.getValue() 1502 1503 def ini_str(self): 1504 return '%d' % self.getValue() 1505 1506# A generic Frequency and/or Latency value. Value is stored as a 1507# latency, just like Latency and Frequency. 1508class Clock(TickParamValue): 1509 def __init__(self, value): 1510 if isinstance(value, (Latency, Clock)): 1511 self.ticks = value.ticks 1512 self.value = value.value 1513 elif isinstance(value, Frequency): 1514 self.ticks = value.ticks 1515 self.value = 1.0 / value.value 1516 elif value.endswith('t'): 1517 self.ticks = True 1518 self.value = int(value[:-1]) 1519 else: 1520 self.ticks = False 1521 self.value = convert.anyToLatency(value) 1522 1523 def __call__(self, value): 1524 self.__init__(value) 1525 return value 1526 1527 def __str__(self): 1528 return "%s" % Latency(self) 1529 1530 def __getattr__(self, attr): 1531 if attr == 'frequency': 1532 return Frequency(self) 1533 if attr in ('latency', 'period'): 1534 return Latency(self) 1535 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1536 1537 def getValue(self): 1538 return self.period.getValue() 1539 1540 def config_value(self): 1541 return self.period.config_value() 1542 1543 def ini_str(self): 1544 return self.period.ini_str() 1545 1546class Voltage(Float): 1547 ex_str = "1V" 1548 1549 def __new__(cls, value): 1550 value = convert.toVoltage(value) 1551 return super(cls, Voltage).__new__(cls, value) 1552 1553 def __init__(self, value): 1554 value = convert.toVoltage(value) 1555 super(Voltage, self).__init__(value) 1556 1557class Current(Float): 1558 ex_str = "1mA" 1559 1560 def __new__(cls, value): 1561 value = convert.toCurrent(value) 1562 return super(cls, Current).__new__(cls, value) 1563 1564 def __init__(self, value): 1565 value = convert.toCurrent(value) 1566 super(Current, self).__init__(value) 1567 1568class Energy(Float): 1569 ex_str = "1pJ" 1570 1571 def __new__(cls, value): 1572 value = convert.toEnergy(value) 1573 return super(cls, Energy).__new__(cls, value) 1574 1575 def __init__(self, value): 1576 value = convert.toEnergy(value) 1577 super(Energy, self).__init__(value) 1578 1579class NetworkBandwidth(float,ParamValue): 1580 cxx_type = 'float' 1581 ex_str = "1Gbps" 1582 cmd_line_settable = True 1583 1584 def __new__(cls, value): 1585 # convert to bits per second 1586 val = convert.toNetworkBandwidth(value) 1587 return super(cls, NetworkBandwidth).__new__(cls, val) 1588 1589 def __str__(self): 1590 return str(self.val) 1591 1592 def __call__(self, value): 1593 val = convert.toNetworkBandwidth(value) 1594 self.__init__(val) 1595 return value 1596 1597 def getValue(self): 1598 # convert to seconds per byte 1599 value = 8.0 / float(self) 1600 # convert to ticks per byte 1601 value = ticks.fromSeconds(value) 1602 return float(value) 1603 1604 def ini_str(self): 1605 return '%f' % self.getValue() 1606 1607 def config_value(self): 1608 return '%f' % self.getValue() 1609 1610 @classmethod 1611 def cxx_ini_predecls(cls, code): 1612 code('#include <sstream>') 1613 1614 @classmethod 1615 def cxx_ini_parse(self, code, src, dest, ret): 1616 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1617 1618class MemoryBandwidth(float,ParamValue): 1619 cxx_type = 'float' 1620 ex_str = "1GB/s" 1621 cmd_line_settable = True 1622 1623 def __new__(cls, value): 1624 # convert to bytes per second 1625 val = convert.toMemoryBandwidth(value) 1626 return super(cls, MemoryBandwidth).__new__(cls, val) 1627 1628 def __call__(self, value): 1629 val = convert.toMemoryBandwidth(value) 1630 self.__init__(val) 1631 return value 1632 1633 def getValue(self): 1634 # convert to seconds per byte 1635 value = float(self) 1636 if value: 1637 value = 1.0 / float(self) 1638 # convert to ticks per byte 1639 value = ticks.fromSeconds(value) 1640 return float(value) 1641 1642 def ini_str(self): 1643 return '%f' % self.getValue() 1644 1645 def config_value(self): 1646 return '%f' % self.getValue() 1647 1648 @classmethod 1649 def cxx_ini_predecls(cls, code): 1650 code('#include <sstream>') 1651 1652 @classmethod 1653 def cxx_ini_parse(self, code, src, dest, ret): 1654 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1655 1656# 1657# "Constants"... handy aliases for various values. 1658# 1659 1660# Special class for NULL pointers. Note the special check in 1661# make_param_value() above that lets these be assigned where a 1662# SimObject is required. 1663# only one copy of a particular node 1664class NullSimObject(object): 1665 __metaclass__ = Singleton 1666 _name = 'Null' 1667 1668 def __call__(cls): 1669 return cls 1670 1671 def _instantiate(self, parent = None, path = ''): 1672 pass 1673 1674 def ini_str(self): 1675 return 'Null' 1676 1677 def unproxy(self, base): 1678 return self 1679 1680 def set_path(self, parent, name): 1681 pass 1682 1683 def set_parent(self, parent, name): 1684 pass 1685 1686 def clear_parent(self, old_parent): 1687 pass 1688 1689 def descendants(self): 1690 return 1691 yield None 1692 1693 def get_config_as_dict(self): 1694 return {} 1695 1696 def __str__(self): 1697 return self._name 1698 1699 def config_value(self): 1700 return None 1701 1702 def getValue(self): 1703 return None 1704 1705# The only instance you'll ever need... 1706NULL = NullSimObject() 1707 1708def isNullPointer(value): 1709 return isinstance(value, NullSimObject) 1710 1711# Some memory range specifications use this as a default upper bound. 1712MaxAddr = Addr.max 1713MaxTick = Tick.max 1714AllMemory = AddrRange(0, MaxAddr) 1715 1716 1717##################################################################### 1718# 1719# Port objects 1720# 1721# Ports are used to interconnect objects in the memory system. 1722# 1723##################################################################### 1724 1725# Port reference: encapsulates a reference to a particular port on a 1726# particular SimObject. 1727class PortRef(object): 1728 def __init__(self, simobj, name, role): 1729 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1730 self.simobj = simobj 1731 self.name = name 1732 self.role = role 1733 self.peer = None # not associated with another port yet 1734 self.ccConnected = False # C++ port connection done? 1735 self.index = -1 # always -1 for non-vector ports 1736 1737 def __str__(self): 1738 return '%s.%s' % (self.simobj, self.name) 1739 1740 def __len__(self): 1741 # Return the number of connected ports, i.e. 0 is we have no 1742 # peer and 1 if we do. 1743 return int(self.peer != None) 1744 1745 # for config.ini, print peer's name (not ours) 1746 def ini_str(self): 1747 return str(self.peer) 1748 1749 # for config.json 1750 def get_config_as_dict(self): 1751 return {'role' : self.role, 'peer' : str(self.peer)} 1752 1753 def __getattr__(self, attr): 1754 if attr == 'peerObj': 1755 # shorthand for proxies 1756 return self.peer.simobj 1757 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1758 (self.__class__.__name__, attr) 1759 1760 # Full connection is symmetric (both ways). Called via 1761 # SimObject.__setattr__ as a result of a port assignment, e.g., 1762 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1763 # e.g., "obj1.portA[3] = obj2.portB". 1764 def connect(self, other): 1765 if isinstance(other, VectorPortRef): 1766 # reference to plain VectorPort is implicit append 1767 other = other._get_next() 1768 if self.peer and not proxy.isproxy(self.peer): 1769 fatal("Port %s is already connected to %s, cannot connect %s\n", 1770 self, self.peer, other); 1771 self.peer = other 1772 if proxy.isproxy(other): 1773 other.set_param_desc(PortParamDesc()) 1774 elif isinstance(other, PortRef): 1775 if other.peer is not self: 1776 other.connect(self) 1777 else: 1778 raise TypeError, \ 1779 "assigning non-port reference '%s' to port '%s'" \ 1780 % (other, self) 1781 1782 # Allow a master/slave port pair to be spliced between 1783 # a port and its connected peer. Useful operation for connecting 1784 # instrumentation structures into a system when it is necessary 1785 # to connect the instrumentation after the full system has been 1786 # constructed. 1787 def splice(self, new_master_peer, new_slave_peer): 1788 if not self.peer or proxy.isproxy(self.peer): 1789 fatal("Port %s not connected, cannot splice in new peers\n", self) 1790 1791 if not isinstance(new_master_peer, PortRef) or \ 1792 not isinstance(new_slave_peer, PortRef): 1793 raise TypeError, \ 1794 "Splicing non-port references '%s','%s' to port '%s'" % \ 1795 (new_master_peer, new_slave_peer, self) 1796 1797 old_peer = self.peer 1798 if self.role == 'SLAVE': 1799 self.peer = new_master_peer 1800 old_peer.peer = new_slave_peer 1801 new_master_peer.connect(self) 1802 new_slave_peer.connect(old_peer) 1803 elif self.role == 'MASTER': 1804 self.peer = new_slave_peer 1805 old_peer.peer = new_master_peer 1806 new_slave_peer.connect(self) 1807 new_master_peer.connect(old_peer) 1808 else: 1809 panic("Port %s has unknown role, "+\ 1810 "cannot splice in new peers\n", self) 1811 1812 def clone(self, simobj, memo): 1813 if memo.has_key(self): 1814 return memo[self] 1815 newRef = copy.copy(self) 1816 memo[self] = newRef 1817 newRef.simobj = simobj 1818 assert(isSimObject(newRef.simobj)) 1819 if self.peer and not proxy.isproxy(self.peer): 1820 peerObj = self.peer.simobj(_memo=memo) 1821 newRef.peer = self.peer.clone(peerObj, memo) 1822 assert(not isinstance(newRef.peer, VectorPortRef)) 1823 return newRef 1824 1825 def unproxy(self, simobj): 1826 assert(simobj is self.simobj) 1827 if proxy.isproxy(self.peer): 1828 try: 1829 realPeer = self.peer.unproxy(self.simobj) 1830 except: 1831 print("Error in unproxying port '%s' of %s" % 1832 (self.name, self.simobj.path())) 1833 raise 1834 self.connect(realPeer) 1835 1836 # Call C++ to create corresponding port connection between C++ objects 1837 def ccConnect(self): 1838 from _m5.pyobject import connectPorts 1839 1840 if self.role == 'SLAVE': 1841 # do nothing and let the master take care of it 1842 return 1843 1844 if self.ccConnected: # already done this 1845 return 1846 peer = self.peer 1847 if not self.peer: # nothing to connect to 1848 return 1849 1850 # check that we connect a master to a slave 1851 if self.role == peer.role: 1852 raise TypeError, \ 1853 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1854 % (peer, self, self.role) 1855 1856 try: 1857 # self is always the master and peer the slave 1858 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1859 peer.simobj.getCCObject(), peer.name, peer.index) 1860 except: 1861 print("Error connecting port %s.%s to %s.%s" % 1862 (self.simobj.path(), self.name, 1863 peer.simobj.path(), peer.name)) 1864 raise 1865 self.ccConnected = True 1866 peer.ccConnected = True 1867 1868# A reference to an individual element of a VectorPort... much like a 1869# PortRef, but has an index. 1870class VectorPortElementRef(PortRef): 1871 def __init__(self, simobj, name, role, index): 1872 PortRef.__init__(self, simobj, name, role) 1873 self.index = index 1874 1875 def __str__(self): 1876 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1877 1878# A reference to a complete vector-valued port (not just a single element). 1879# Can be indexed to retrieve individual VectorPortElementRef instances. 1880class VectorPortRef(object): 1881 def __init__(self, simobj, name, role): 1882 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1883 self.simobj = simobj 1884 self.name = name 1885 self.role = role 1886 self.elements = [] 1887 1888 def __str__(self): 1889 return '%s.%s[:]' % (self.simobj, self.name) 1890 1891 def __len__(self): 1892 # Return the number of connected peers, corresponding the the 1893 # length of the elements. 1894 return len(self.elements) 1895 1896 # for config.ini, print peer's name (not ours) 1897 def ini_str(self): 1898 return ' '.join([el.ini_str() for el in self.elements]) 1899 1900 # for config.json 1901 def get_config_as_dict(self): 1902 return {'role' : self.role, 1903 'peer' : [el.ini_str() for el in self.elements]} 1904 1905 def __getitem__(self, key): 1906 if not isinstance(key, int): 1907 raise TypeError, "VectorPort index must be integer" 1908 if key >= len(self.elements): 1909 # need to extend list 1910 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1911 for i in range(len(self.elements), key+1)] 1912 self.elements.extend(ext) 1913 return self.elements[key] 1914 1915 def _get_next(self): 1916 return self[len(self.elements)] 1917 1918 def __setitem__(self, key, value): 1919 if not isinstance(key, int): 1920 raise TypeError, "VectorPort index must be integer" 1921 self[key].connect(value) 1922 1923 def connect(self, other): 1924 if isinstance(other, (list, tuple)): 1925 # Assign list of port refs to vector port. 1926 # For now, append them... not sure if that's the right semantics 1927 # or if it should replace the current vector. 1928 for ref in other: 1929 self._get_next().connect(ref) 1930 else: 1931 # scalar assignment to plain VectorPort is implicit append 1932 self._get_next().connect(other) 1933 1934 def clone(self, simobj, memo): 1935 if memo.has_key(self): 1936 return memo[self] 1937 newRef = copy.copy(self) 1938 memo[self] = newRef 1939 newRef.simobj = simobj 1940 assert(isSimObject(newRef.simobj)) 1941 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1942 return newRef 1943 1944 def unproxy(self, simobj): 1945 [el.unproxy(simobj) for el in self.elements] 1946 1947 def ccConnect(self): 1948 [el.ccConnect() for el in self.elements] 1949 1950# Port description object. Like a ParamDesc object, this represents a 1951# logical port in the SimObject class, not a particular port on a 1952# SimObject instance. The latter are represented by PortRef objects. 1953class Port(object): 1954 # Generate a PortRef for this port on the given SimObject with the 1955 # given name 1956 def makeRef(self, simobj): 1957 return PortRef(simobj, self.name, self.role) 1958 1959 # Connect an instance of this port (on the given SimObject with 1960 # the given name) with the port described by the supplied PortRef 1961 def connect(self, simobj, ref): 1962 self.makeRef(simobj).connect(ref) 1963 1964 # No need for any pre-declarations at the moment as we merely rely 1965 # on an unsigned int. 1966 def cxx_predecls(self, code): 1967 pass 1968 1969 def pybind_predecls(self, code): 1970 cls.cxx_predecls(self, code) 1971 1972 # Declare an unsigned int with the same name as the port, that 1973 # will eventually hold the number of connected ports (and thus the 1974 # number of elements for a VectorPort). 1975 def cxx_decl(self, code): 1976 code('unsigned int port_${{self.name}}_connection_count;') 1977 1978class MasterPort(Port): 1979 # MasterPort("description") 1980 def __init__(self, *args): 1981 if len(args) == 1: 1982 self.desc = args[0] 1983 self.role = 'MASTER' 1984 else: 1985 raise TypeError, 'wrong number of arguments' 1986 1987class SlavePort(Port): 1988 # SlavePort("description") 1989 def __init__(self, *args): 1990 if len(args) == 1: 1991 self.desc = args[0] 1992 self.role = 'SLAVE' 1993 else: 1994 raise TypeError, 'wrong number of arguments' 1995 1996# VectorPort description object. Like Port, but represents a vector 1997# of connections (e.g., as on a XBar). 1998class VectorPort(Port): 1999 def __init__(self, *args): 2000 self.isVec = True 2001 2002 def makeRef(self, simobj): 2003 return VectorPortRef(simobj, self.name, self.role) 2004 2005class VectorMasterPort(VectorPort): 2006 # VectorMasterPort("description") 2007 def __init__(self, *args): 2008 if len(args) == 1: 2009 self.desc = args[0] 2010 self.role = 'MASTER' 2011 VectorPort.__init__(self, *args) 2012 else: 2013 raise TypeError, 'wrong number of arguments' 2014 2015class VectorSlavePort(VectorPort): 2016 # VectorSlavePort("description") 2017 def __init__(self, *args): 2018 if len(args) == 1: 2019 self.desc = args[0] 2020 self.role = 'SLAVE' 2021 VectorPort.__init__(self, *args) 2022 else: 2023 raise TypeError, 'wrong number of arguments' 2024 2025# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2026# proxy objects (via set_param_desc()) so that proxy error messages 2027# make sense. 2028class PortParamDesc(object): 2029 __metaclass__ = Singleton 2030 2031 ptype_str = 'Port' 2032 ptype = Port 2033 2034baseEnums = allEnums.copy() 2035baseParams = allParams.copy() 2036 2037def clear(): 2038 global allEnums, allParams 2039 2040 allEnums = baseEnums.copy() 2041 allParams = baseParams.copy() 2042 2043__all__ = ['Param', 'VectorParam', 2044 'Enum', 'Bool', 'String', 'Float', 2045 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2046 'Int32', 'UInt32', 'Int64', 'UInt64', 2047 'Counter', 'Addr', 'Tick', 'Percent', 2048 'TcpPort', 'UdpPort', 'EthernetAddr', 2049 'IpAddress', 'IpNetmask', 'IpWithPort', 2050 'MemorySize', 'MemorySize32', 2051 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy', 2052 'NetworkBandwidth', 'MemoryBandwidth', 2053 'AddrRange', 2054 'MaxAddr', 'MaxTick', 'AllMemory', 2055 'Time', 2056 'NextEthernetAddr', 'NULL', 2057 'MasterPort', 'SlavePort', 2058 'VectorMasterPort', 'VectorSlavePort'] 2059 2060import SimObject 2061