params.py revision 13716:950f9a2ffb78
12623SN/A# Copyright (c) 2012-2014, 2017, 2018 ARM Limited 210596Sgabeblack@google.com# All rights reserved. 312276Sanouk.vanlaer@arm.com# 48926Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall 58926Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual 68926Sandreas.hansson@arm.com# property including but not limited to intellectual property relating 78926Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software 88926Sandreas.hansson@arm.com# licensed hereunder. You may use the software subject to the license 98926Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated 108926Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software, 118926Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form. 128926Sandreas.hansson@arm.com# 138926Sandreas.hansson@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 148926Sandreas.hansson@arm.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 152623SN/A# All rights reserved. 162623SN/A# 172623SN/A# Redistribution and use in source and binary forms, with or without 182623SN/A# modification, are permitted provided that the following conditions are 192623SN/A# met: redistributions of source code must retain the above copyright 202623SN/A# notice, this list of conditions and the following disclaimer; 212623SN/A# redistributions in binary form must reproduce the above copyright 222623SN/A# notice, this list of conditions and the following disclaimer in the 232623SN/A# documentation and/or other materials provided with the distribution; 242623SN/A# neither the name of the copyright holders nor the names of its 252623SN/A# contributors may be used to endorse or promote products derived from 262623SN/A# this software without specific prior written permission. 272623SN/A# 282623SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292623SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302623SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312623SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322623SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332623SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342623SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352623SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362623SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372623SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382623SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392623SN/A# 402665Ssaidi@eecs.umich.edu# Authors: Steve Reinhardt 412665Ssaidi@eecs.umich.edu# Nathan Binkert 422623SN/A# Gabe Black 432623SN/A# Andreas Hansson 4411793Sbrandon.potter@amd.com 4511793Sbrandon.potter@amd.com##################################################################### 463170Sstever@eecs.umich.edu# 478105Sgblack@eecs.umich.edu# Parameter description classes 482623SN/A# 494040Ssaidi@eecs.umich.edu# The _params dictionary in each class maps parameter names to either 509647Sdam.sunwoo@arm.com# a Param or a VectorParam object. These objects contain the 516658Snate@binkert.org# parameter description string, the parameter type, and the default 522623SN/A# value (if any). The convert() method on these objects is used to 539443SAndreas.Sandberg@ARM.com# force whatever value is assigned to the parameter to the appropriate 548232Snate@binkert.org# type. 558232Snate@binkert.org# 563348Sbinkertn@umich.edu# Note that the default values are loaded into the class's attribute 573348Sbinkertn@umich.edu# space when the parameter dictionary is initialized (in 588926Sandreas.hansson@arm.com# MetaSimObject._new_param()); after that point they aren't used. 594762Snate@binkert.org# 607678Sgblack@eecs.umich.edu##################################################################### 6111793Sbrandon.potter@amd.com 622901Ssaidi@eecs.umich.edufrom __future__ import print_function 632623SN/A 642623SN/Aimport copy 652623SN/Aimport datetime 662623SN/Aimport re 672623SN/Aimport sys 682623SN/Aimport time 692623SN/Aimport math 7011147Smitch.hayenga@arm.com 718921Sandreas.hansson@arm.comfrom . import proxy 7211148Smitch.hayenga@arm.comfrom . import ticks 7311435Smitch.hayenga@arm.comfrom .util import * 7411435Smitch.hayenga@arm.com 7511435Smitch.hayenga@arm.comdef isSimObject(*args, **kwargs): 762623SN/A from . import SimObject 772623SN/A return SimObject.isSimObject(*args, **kwargs) 785529Snate@binkert.org 7912127Sspwilson2@wisc.edudef isSimObjectSequence(*args, **kwargs): 8012127Sspwilson2@wisc.edu from . import SimObject 8112127Sspwilson2@wisc.edu return SimObject.isSimObjectSequence(*args, **kwargs) 8212127Sspwilson2@wisc.edu 835487Snate@binkert.orgdef isSimObjectClass(*args, **kwargs): 845487Snate@binkert.org from . import SimObject 859095Sandreas.hansson@arm.com return SimObject.isSimObjectClass(*args, **kwargs) 869095Sandreas.hansson@arm.com 8710537Sandreas.hansson@arm.comallParams = {} 8810537Sandreas.hansson@arm.com 892623SN/Aclass MetaParamValue(type): 902623SN/A def __new__(mcls, name, bases, dct): 912623SN/A cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 922623SN/A assert name not in allParams 932623SN/A allParams[name] = cls 942623SN/A return cls 952623SN/A 966775SBrad.Beckmann@amd.com 976775SBrad.Beckmann@amd.com# Dummy base class to identify types that are legitimate for SimObject 986775SBrad.Beckmann@amd.com# parameters. 992623SN/Aclass ParamValue(object): 1002623SN/A __metaclass__ = MetaParamValue 10110913Sandreas.sandberg@arm.com cmd_line_settable = False 10210913Sandreas.sandberg@arm.com 1032623SN/A # Generate the code needed as a prerequisite for declaring a C++ 10412276Sanouk.vanlaer@arm.com # object of this type. Typically generates one or more #include 10512276Sanouk.vanlaer@arm.com # statements. Used when declaring parameters of this type. 10612276Sanouk.vanlaer@arm.com @classmethod 1079448SAndreas.Sandberg@ARM.com def cxx_predecls(cls, code): 10810913Sandreas.sandberg@arm.com pass 1092623SN/A 1109443SAndreas.Sandberg@ARM.com @classmethod 11111147Smitch.hayenga@arm.com def pybind_predecls(cls, code): 11210913Sandreas.sandberg@arm.com cls.cxx_predecls(code) 1139443SAndreas.Sandberg@ARM.com 1149443SAndreas.Sandberg@ARM.com # default for printing to .ini file is regular string conversion. 1159443SAndreas.Sandberg@ARM.com # will be overridden in some cases 1162915Sktlim@umich.edu def ini_str(self): 11711147Smitch.hayenga@arm.com return str(self) 1189443SAndreas.Sandberg@ARM.com 11910913Sandreas.sandberg@arm.com # default for printing to .json file is regular string conversion. 1209443SAndreas.Sandberg@ARM.com # will be overridden in some cases, mostly to use native Python 1219342SAndreas.Sandberg@arm.com # types where there are similar JSON types 1229342SAndreas.Sandberg@arm.com def config_value(self): 1232915Sktlim@umich.edu return str(self) 12411148Smitch.hayenga@arm.com 12511148Smitch.hayenga@arm.com # Prerequisites for .ini parsing with cxx_ini_parse 12611148Smitch.hayenga@arm.com @classmethod 12711148Smitch.hayenga@arm.com def cxx_ini_predecls(cls, code): 12811148Smitch.hayenga@arm.com pass 12911148Smitch.hayenga@arm.com 13011148Smitch.hayenga@arm.com # parse a .ini file entry for this param from string expression 13111321Ssteve.reinhardt@amd.com # src into lvalue dest (of the param's C++ type) 13211151Smitch.hayenga@arm.com @classmethod 13311148Smitch.hayenga@arm.com def cxx_ini_parse(cls, code, src, dest, ret): 13411148Smitch.hayenga@arm.com code('// Unhandled param type: %s' % cls.__name__) 13511148Smitch.hayenga@arm.com code('%s false;' % ret) 13611148Smitch.hayenga@arm.com 13711148Smitch.hayenga@arm.com # allows us to blithely call unproxy() on things without checking 13811148Smitch.hayenga@arm.com # if they're really proxies or not 13911148Smitch.hayenga@arm.com def unproxy(self, base): 14011148Smitch.hayenga@arm.com return self 14111148Smitch.hayenga@arm.com 1429342SAndreas.Sandberg@arm.com # Produce a human readable version of the stored value 1432915Sktlim@umich.edu def pretty_print(self, value): 1449448SAndreas.Sandberg@ARM.com return str(value) 1459448SAndreas.Sandberg@ARM.com 1465220Ssaidi@eecs.umich.edu# Regular parameter description. 1475220Ssaidi@eecs.umich.educlass ParamDesc(object): 1484940Snate@binkert.org def __init__(self, ptype_str, ptype, *args, **kwargs): 1499523SAndreas.Sandberg@ARM.com self.ptype_str = ptype_str 1503324Shsul@eecs.umich.edu # remember ptype only if it is provided 1519448SAndreas.Sandberg@ARM.com if ptype != None: 1529448SAndreas.Sandberg@ARM.com self.ptype = ptype 15311147Smitch.hayenga@arm.com 15411147Smitch.hayenga@arm.com if args: 15511147Smitch.hayenga@arm.com if len(args) == 1: 15611147Smitch.hayenga@arm.com self.desc = args[0] 15711147Smitch.hayenga@arm.com elif len(args) == 2: 15811147Smitch.hayenga@arm.com self.default = args[0] 15911147Smitch.hayenga@arm.com self.desc = args[1] 16011147Smitch.hayenga@arm.com else: 16111147Smitch.hayenga@arm.com raise TypeError('too many arguments') 16211147Smitch.hayenga@arm.com 16311147Smitch.hayenga@arm.com if 'desc' in kwargs: 16411147Smitch.hayenga@arm.com assert(not hasattr(self, 'desc')) 16511147Smitch.hayenga@arm.com self.desc = kwargs['desc'] 16611147Smitch.hayenga@arm.com del kwargs['desc'] 16711147Smitch.hayenga@arm.com 1689448SAndreas.Sandberg@ARM.com if 'default' in kwargs: 16912276Sanouk.vanlaer@arm.com assert(not hasattr(self, 'default')) 17012276Sanouk.vanlaer@arm.com self.default = kwargs['default'] 17112276Sanouk.vanlaer@arm.com del kwargs['default'] 1722623SN/A 1732623SN/A if kwargs: 1749443SAndreas.Sandberg@ARM.com raise TypeError('extra unknown kwargs %s' % kwargs) 1759443SAndreas.Sandberg@ARM.com 1769443SAndreas.Sandberg@ARM.com if not hasattr(self, 'desc'): 17710913Sandreas.sandberg@arm.com raise TypeError('desc attribute missing') 1789443SAndreas.Sandberg@ARM.com 1799443SAndreas.Sandberg@ARM.com def __getattr__(self, attr): 18011147Smitch.hayenga@arm.com if attr == 'ptype': 1819443SAndreas.Sandberg@ARM.com from . import SimObject 1829443SAndreas.Sandberg@ARM.com ptype = SimObject.allClasses[self.ptype_str] 1839443SAndreas.Sandberg@ARM.com assert isSimObjectClass(ptype) 1849443SAndreas.Sandberg@ARM.com self.ptype = ptype 18510913Sandreas.sandberg@arm.com return ptype 1869443SAndreas.Sandberg@ARM.com 1879443SAndreas.Sandberg@ARM.com raise AttributeError("'%s' object has no attribute '%s'" % \ 1889443SAndreas.Sandberg@ARM.com (type(self).__name__, attr)) 1899443SAndreas.Sandberg@ARM.com 1909443SAndreas.Sandberg@ARM.com def example_str(self): 1912623SN/A if hasattr(self.ptype, "ex_str"): 1922798Sktlim@umich.edu return self.ptype.ex_str 1932623SN/A else: 1949429SAndreas.Sandberg@ARM.com return self.ptype_str 1959429SAndreas.Sandberg@ARM.com 1969443SAndreas.Sandberg@ARM.com # Is the param available to be exposed on the command line 1979342SAndreas.Sandberg@arm.com def isCmdLineSettable(self): 1989443SAndreas.Sandberg@ARM.com if hasattr(self.ptype, "cmd_line_settable"): 1992623SN/A return self.ptype.cmd_line_settable 2002623SN/A else: 2012623SN/A return False 2022623SN/A 2032623SN/A def convert(self, value): 2042623SN/A if isinstance(value, proxy.BaseProxy): 2059429SAndreas.Sandberg@ARM.com value.set_param_desc(self) 2062623SN/A return value 2079443SAndreas.Sandberg@ARM.com if 'ptype' not in self.__dict__ and isNullPointer(value): 2082623SN/A # deferred evaluation of SimObject; continue to defer if 2092623SN/A # we're just assigning a null pointer 2102623SN/A return value 2119523SAndreas.Sandberg@ARM.com if isinstance(value, self.ptype): 2129523SAndreas.Sandberg@ARM.com return value 2139523SAndreas.Sandberg@ARM.com if isNullPointer(value) and isSimObjectClass(self.ptype): 2149524SAndreas.Sandberg@ARM.com return value 2159523SAndreas.Sandberg@ARM.com return self.ptype(value) 2169523SAndreas.Sandberg@ARM.com 2179523SAndreas.Sandberg@ARM.com def pretty_print(self, value): 2189523SAndreas.Sandberg@ARM.com if isinstance(value, proxy.BaseProxy): 2192623SN/A return str(value) 2202623SN/A if isNullPointer(value): 22110407Smitch.hayenga@arm.com return NULL 2222623SN/A return self.ptype(value).pretty_print(value) 22310407Smitch.hayenga@arm.com 2244940Snate@binkert.org def cxx_predecls(self, code): 22511147Smitch.hayenga@arm.com code('#include <cstddef>') 2262623SN/A self.ptype.cxx_predecls(code) 22711147Smitch.hayenga@arm.com 22811147Smitch.hayenga@arm.com def pybind_predecls(self, code): 22911147Smitch.hayenga@arm.com self.ptype.pybind_predecls(code) 23010464SAndreas.Sandberg@ARM.com 2313686Sktlim@umich.edu def cxx_decl(self, code): 23211147Smitch.hayenga@arm.com code('${{self.ptype.cxx_type}} ${{self.name}};') 23311147Smitch.hayenga@arm.com 23411147Smitch.hayenga@arm.com# Vector-valued parameter description. Just like ParamDesc, except 23511147Smitch.hayenga@arm.com# that the value is a vector (list) of the specified type instead of a 2369342SAndreas.Sandberg@arm.com# single value. 23711147Smitch.hayenga@arm.com 23811147Smitch.hayenga@arm.comclass VectorParamValue(list): 23911147Smitch.hayenga@arm.com __metaclass__ = MetaParamValue 24011147Smitch.hayenga@arm.com def __setattr__(self, attr, value): 24111526Sdavid.guillen@arm.com raise AttributeError("Not allowed to set %s on '%s'" % \ 24211526Sdavid.guillen@arm.com (attr, type(self).__name__)) 2432623SN/A 2442623SN/A def config_value(self): 2452623SN/A return [v.config_value() for v in self] 2462623SN/A 2478737Skoansin.tan@gmail.com def ini_str(self): 2482623SN/A return ' '.join([v.ini_str() for v in self]) 2494940Snate@binkert.org 2504940Snate@binkert.org def getValue(self): 25111147Smitch.hayenga@arm.com return [ v.getValue() for v in self ] 25211147Smitch.hayenga@arm.com 2532623SN/A def unproxy(self, base): 2546043Sgblack@eecs.umich.edu if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 2556043Sgblack@eecs.umich.edu # The value is a proxy (e.g. Parent.any, Parent.all or 2566043Sgblack@eecs.umich.edu # Parent.x) therefore try resolve it 2579342SAndreas.Sandberg@arm.com return self[0].unproxy(base) 2582626SN/A else: 25911147Smitch.hayenga@arm.com return [v.unproxy(base) for v in self] 2602623SN/A 26111147Smitch.hayenga@arm.comclass SimObjectVector(VectorParamValue): 26211147Smitch.hayenga@arm.com # support clone operation 26311147Smitch.hayenga@arm.com def __call__(self, **kwargs): 26411147Smitch.hayenga@arm.com return SimObjectVector([v(**kwargs) for v in self]) 26511147Smitch.hayenga@arm.com 26611147Smitch.hayenga@arm.com def clear_parent(self, old_parent): 26711147Smitch.hayenga@arm.com for v in self: 26811147Smitch.hayenga@arm.com v.clear_parent(old_parent) 26911526Sdavid.guillen@arm.com 2702623SN/A def set_parent(self, parent, name): 2712623SN/A if len(self) == 1: 2722623SN/A self[0].set_parent(parent, name) 27310030SAli.Saidi@ARM.com else: 27410030SAli.Saidi@ARM.com width = int(math.ceil(math.log(len(self))/math.log(10))) 27510030SAli.Saidi@ARM.com for i,v in enumerate(self): 27610030SAli.Saidi@ARM.com v.set_parent(parent, "%s%0*d" % (name, width, i)) 27710030SAli.Saidi@ARM.com 27810030SAli.Saidi@ARM.com def has_parent(self): 27910529Smorr@cs.wisc.edu return any([e.has_parent() for e in self if not isNullPointer(e)]) 28010529Smorr@cs.wisc.edu 28111148Smitch.hayenga@arm.com # return 'cpu0 cpu1' etc. for print_ini() 28211148Smitch.hayenga@arm.com def get_name(self): 28311148Smitch.hayenga@arm.com return ' '.join([v._name for v in self]) 28411151Smitch.hayenga@arm.com 28511148Smitch.hayenga@arm.com # By iterating through the constituent members of the vector here 28610529Smorr@cs.wisc.edu # we can nicely handle iterating over all a SimObject's children 28710529Smorr@cs.wisc.edu # without having to provide lots of special functions on 28810030SAli.Saidi@ARM.com # SimObjectVector directly. 28911356Skrinat01@arm.com def descendants(self): 29011356Skrinat01@arm.com for v in self: 29111356Skrinat01@arm.com for obj in v.descendants(): 29211356Skrinat01@arm.com yield obj 29310030SAli.Saidi@ARM.com 29410030SAli.Saidi@ARM.com def get_config_as_dict(self): 29511147Smitch.hayenga@arm.com a = [] 29611147Smitch.hayenga@arm.com for v in self: 29711147Smitch.hayenga@arm.com a.append(v.get_config_as_dict()) 29810030SAli.Saidi@ARM.com return a 29910030SAli.Saidi@ARM.com 30010030SAli.Saidi@ARM.com # If we are replacing an item in the vector, make sure to set the 30110030SAli.Saidi@ARM.com # parent reference of the new SimObject to be the same as the parent 30210030SAli.Saidi@ARM.com # of the SimObject being replaced. Useful to have if we created 30310030SAli.Saidi@ARM.com # a SimObjectVector of temporary objects that will be modified later in 30410030SAli.Saidi@ARM.com # configuration scripts. 30510030SAli.Saidi@ARM.com def __setitem__(self, key, value): 30610030SAli.Saidi@ARM.com val = self[key] 30710030SAli.Saidi@ARM.com if value.has_parent(): 30810030SAli.Saidi@ARM.com warn("SimObject %s already has a parent" % value.get_name() +\ 30910529Smorr@cs.wisc.edu " that is being overwritten by a SimObjectVector") 31010529Smorr@cs.wisc.edu value.set_parent(val.get_parent(), val._name) 31111148Smitch.hayenga@arm.com super(SimObjectVector, self).__setitem__(key, value) 31211321Ssteve.reinhardt@amd.com 31311151Smitch.hayenga@arm.com # Enumerate the params of each member of the SimObject vector. Creates 31411148Smitch.hayenga@arm.com # strings that will allow indexing into the vector by the python code and 31510529Smorr@cs.wisc.edu # allow it to be specified on the command line. 31610529Smorr@cs.wisc.edu def enumerateParams(self, flags_dict = {}, 31710030SAli.Saidi@ARM.com cmd_line_str = "", 31810030SAli.Saidi@ARM.com access_str = ""): 31910030SAli.Saidi@ARM.com if hasattr(self, "_paramEnumed"): 32010030SAli.Saidi@ARM.com print("Cycle detected enumerating params at %s?!" % (cmd_line_str)) 32111147Smitch.hayenga@arm.com else: 32211147Smitch.hayenga@arm.com x = 0 32311147Smitch.hayenga@arm.com for vals in self: 32410030SAli.Saidi@ARM.com # Each entry in the SimObjectVector should be an 32510030SAli.Saidi@ARM.com # instance of a SimObject 32610030SAli.Saidi@ARM.com flags_dict = vals.enumerateParams(flags_dict, 3272623SN/A cmd_line_str + "%d." % x, 32811608Snikos.nikoleris@arm.com access_str + "[%d]." % x) 32911608Snikos.nikoleris@arm.com x = x + 1 3302623SN/A 33111147Smitch.hayenga@arm.com return flags_dict 33211147Smitch.hayenga@arm.com 33311147Smitch.hayenga@arm.comclass VectorParamDesc(ParamDesc): 3343169Sstever@eecs.umich.edu # Convert assigned value to appropriate type. If the RHS is not a 3354870Sstever@eecs.umich.edu # list or tuple, it generates a single-element list. 3362623SN/A def convert(self, value): 33710665SAli.Saidi@ARM.com if isinstance(value, (list, tuple)): 33810665SAli.Saidi@ARM.com # list: coerce each element into new list 3392623SN/A tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3404999Sgblack@eecs.umich.edu elif isinstance(value, str): 3417520Sgblack@eecs.umich.edu # If input is a csv string 3422623SN/A tmp_list = [ ParamDesc.convert(self, v) \ 3434999Sgblack@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3444999Sgblack@eecs.umich.edu else: 3459814Sandreas.hansson@arm.com # singleton: coerce to a single-element list 3464999Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3477520Sgblack@eecs.umich.edu 3487520Sgblack@eecs.umich.edu if isSimObjectSequence(tmp_list): 3494999Sgblack@eecs.umich.edu return SimObjectVector(tmp_list) 3504999Sgblack@eecs.umich.edu else: 3514999Sgblack@eecs.umich.edu return VectorParamValue(tmp_list) 35210024Sdam.sunwoo@arm.com 3537520Sgblack@eecs.umich.edu # Produce a human readable example string that describes 3548832SAli.Saidi@ARM.com # how to set this vector parameter in the absence of a default 3554999Sgblack@eecs.umich.edu # value. 3564999Sgblack@eecs.umich.edu def example_str(self): 35711147Smitch.hayenga@arm.com s = super(VectorParamDesc, self).example_str() 35811147Smitch.hayenga@arm.com help_str = "[" + s + "," + s + ", ...]" 3594999Sgblack@eecs.umich.edu return help_str 3604999Sgblack@eecs.umich.edu 3616623Sgblack@eecs.umich.edu # Produce a human readable representation of the value of this vector param. 36210739Ssteve.reinhardt@amd.com def pretty_print(self, value): 3637520Sgblack@eecs.umich.edu if isinstance(value, (list, tuple)): 3644999Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 3658105Sgblack@eecs.umich.edu elif isinstance(value, str): 3664999Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 3674999Sgblack@eecs.umich.edu else: 3688931Sandreas.hansson@arm.com tmp_list = [ ParamDesc.pretty_print(self, value) ] 3698931Sandreas.hansson@arm.com 3704999Sgblack@eecs.umich.edu return tmp_list 3714999Sgblack@eecs.umich.edu 3724999Sgblack@eecs.umich.edu # This is a helper function for the new config system 3734999Sgblack@eecs.umich.edu def __call__(self, value): 3745012Sgblack@eecs.umich.edu if isinstance(value, (list, tuple)): 3754999Sgblack@eecs.umich.edu # list: coerce each element into new list 3764999Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3776102Sgblack@eecs.umich.edu elif isinstance(value, str): 3784999Sgblack@eecs.umich.edu # If input is a csv string 3794999Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3804968Sacolyte@umich.edu for v in value.strip('[').strip(']').split(',') ] 3814986Ssaidi@eecs.umich.edu else: 3824999Sgblack@eecs.umich.edu # singleton: coerce to a single-element list 3836739Sgblack@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3846739Sgblack@eecs.umich.edu 3856739Sgblack@eecs.umich.edu return VectorParamValue(tmp_list) 3866739Sgblack@eecs.umich.edu 3876739Sgblack@eecs.umich.edu def cxx_predecls(self, code): 3886739Sgblack@eecs.umich.edu code('#include <vector>') 3896739Sgblack@eecs.umich.edu self.ptype.cxx_predecls(code) 3906739Sgblack@eecs.umich.edu 3914999Sgblack@eecs.umich.edu def pybind_predecls(self, code): 3924999Sgblack@eecs.umich.edu code('#include <vector>') 3934999Sgblack@eecs.umich.edu self.ptype.pybind_predecls(code) 39410760Ssteve.reinhardt@amd.com 3956078Sgblack@eecs.umich.edu def cxx_decl(self, code): 3966078Sgblack@eecs.umich.edu code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 3976078Sgblack@eecs.umich.edu 39811147Smitch.hayenga@arm.comclass ParamFactory(object): 3994999Sgblack@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 4004968Sacolyte@umich.edu self.param_desc_class = param_desc_class 4013170Sstever@eecs.umich.edu self.ptype_str = ptype_str 4024999Sgblack@eecs.umich.edu 4034999Sgblack@eecs.umich.edu def __getattr__(self, attr): 4044999Sgblack@eecs.umich.edu if self.ptype_str: 4054999Sgblack@eecs.umich.edu attr = self.ptype_str + '.' + attr 4064999Sgblack@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 4077520Sgblack@eecs.umich.edu 4084999Sgblack@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 4097520Sgblack@eecs.umich.edu def __call__(self, *args, **kwargs): 4104999Sgblack@eecs.umich.edu ptype = None 4114999Sgblack@eecs.umich.edu try: 4122623SN/A ptype = allParams[self.ptype_str] 4132623SN/A except KeyError: 4142623SN/A # if name isn't defined yet, assume it's a SimObject, and 41511303Ssteve.reinhardt@amd.com # try to resolve it later 41611608Snikos.nikoleris@arm.com pass 41711608Snikos.nikoleris@arm.com return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 41811303Ssteve.reinhardt@amd.com 41911303Ssteve.reinhardt@amd.comParam = ParamFactory(ParamDesc) 42011303Ssteve.reinhardt@amd.comVectorParam = ParamFactory(VectorParamDesc) 42111303Ssteve.reinhardt@amd.com 4227520Sgblack@eecs.umich.edu##################################################################### 4232623SN/A# 42411608Snikos.nikoleris@arm.com# Parameter Types 42511608Snikos.nikoleris@arm.com# 4262623SN/A# Though native Python types could be used to specify parameter types 42711147Smitch.hayenga@arm.com# (the 'ptype' field of the Param and VectorParam classes), it's more 42811147Smitch.hayenga@arm.com# flexible to define our own set of types. This gives us more control 42910031SAli.Saidi@ARM.com# over how Python expressions are converted to values (via the 43010031SAli.Saidi@ARM.com# __init__() constructor) and how these values are printed out (via 43110031SAli.Saidi@ARM.com# the __str__() conversion method). 43210031SAli.Saidi@ARM.com# 43310031SAli.Saidi@ARM.com##################################################################### 43410031SAli.Saidi@ARM.com 43510031SAli.Saidi@ARM.com# String-valued parameter. Just mixin the ParamValue class with the 43610031SAli.Saidi@ARM.com# built-in str class. 43710031SAli.Saidi@ARM.comclass String(ParamValue,str): 4383169Sstever@eecs.umich.edu cxx_type = 'std::string' 4394870Sstever@eecs.umich.edu cmd_line_settable = True 4402623SN/A 44110665SAli.Saidi@ARM.com @classmethod 44210665SAli.Saidi@ARM.com def cxx_predecls(self, code): 4432623SN/A code('#include <string>') 4444999Sgblack@eecs.umich.edu 4457520Sgblack@eecs.umich.edu def __call__(self, value): 4462623SN/A self = value 4474999Sgblack@eecs.umich.edu return value 4484999Sgblack@eecs.umich.edu 4499814Sandreas.hansson@arm.com @classmethod 4504999Sgblack@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 45111321Ssteve.reinhardt@amd.com code('%s = %s;' % (dest, src)) 4527520Sgblack@eecs.umich.edu code('%s true;' % ret) 4534999Sgblack@eecs.umich.edu 4544999Sgblack@eecs.umich.edu def getValue(self): 4554999Sgblack@eecs.umich.edu return self 45610024Sdam.sunwoo@arm.com 45711321Ssteve.reinhardt@amd.com# superclass for "numeric" parameter values, to emulate math 4588832SAli.Saidi@ARM.com# operations in a type-safe way. e.g., a Latency times an int returns 4594999Sgblack@eecs.umich.edu# a new Latency object. 4604999Sgblack@eecs.umich.educlass NumericParamValue(ParamValue): 46111147Smitch.hayenga@arm.com @staticmethod 4624999Sgblack@eecs.umich.edu def unwrap(v): 4634999Sgblack@eecs.umich.edu return v.value if isinstance(v, NumericParamValue) else v 4644999Sgblack@eecs.umich.edu 4654999Sgblack@eecs.umich.edu def __str__(self): 4664999Sgblack@eecs.umich.edu return str(self.value) 4674999Sgblack@eecs.umich.edu 4686102Sgblack@eecs.umich.edu def __float__(self): 4694999Sgblack@eecs.umich.edu return float(self.value) 47010030SAli.Saidi@ARM.com 4714999Sgblack@eecs.umich.edu def __long__(self): 4724999Sgblack@eecs.umich.edu return long(self.value) 4734999Sgblack@eecs.umich.edu 4744999Sgblack@eecs.umich.edu def __int__(self): 4754999Sgblack@eecs.umich.edu return int(self.value) 4764999Sgblack@eecs.umich.edu 4774999Sgblack@eecs.umich.edu # hook for bounds checking 4784999Sgblack@eecs.umich.edu def _check(self): 4796623Sgblack@eecs.umich.edu return 4808949Sandreas.hansson@arm.com 4817520Sgblack@eecs.umich.edu def __mul__(self, other): 4824999Sgblack@eecs.umich.edu newobj = self.__class__(self) 4838105Sgblack@eecs.umich.edu newobj.value *= NumericParamValue.unwrap(other) 4844999Sgblack@eecs.umich.edu newobj._check() 4854999Sgblack@eecs.umich.edu return newobj 4864999Sgblack@eecs.umich.edu 4878931Sandreas.hansson@arm.com __rmul__ = __mul__ 4888931Sandreas.hansson@arm.com 4894999Sgblack@eecs.umich.edu def __truediv__(self, other): 4904999Sgblack@eecs.umich.edu newobj = self.__class__(self) 49111148Smitch.hayenga@arm.com newobj.value /= NumericParamValue.unwrap(other) 49211148Smitch.hayenga@arm.com newobj._check() 49311148Smitch.hayenga@arm.com return newobj 4944999Sgblack@eecs.umich.edu 4954999Sgblack@eecs.umich.edu def __floordiv__(self, other): 4964999Sgblack@eecs.umich.edu newobj = self.__class__(self) 4974999Sgblack@eecs.umich.edu newobj.value //= NumericParamValue.unwrap(other) 4984999Sgblack@eecs.umich.edu newobj._check() 4994999Sgblack@eecs.umich.edu return newobj 50010563Sandreas.hansson@arm.com 5014999Sgblack@eecs.umich.edu 5024999Sgblack@eecs.umich.edu def __add__(self, other): 5034999Sgblack@eecs.umich.edu newobj = self.__class__(self) 5044999Sgblack@eecs.umich.edu newobj.value += NumericParamValue.unwrap(other) 5054999Sgblack@eecs.umich.edu newobj._check() 5064878Sstever@eecs.umich.edu return newobj 5074040Ssaidi@eecs.umich.edu 5084040Ssaidi@eecs.umich.edu def __sub__(self, other): 5094999Sgblack@eecs.umich.edu newobj = self.__class__(self) 5104999Sgblack@eecs.umich.edu newobj.value -= NumericParamValue.unwrap(other) 5114999Sgblack@eecs.umich.edu newobj._check() 5124999Sgblack@eecs.umich.edu return newobj 51310760Ssteve.reinhardt@amd.com 5146078Sgblack@eecs.umich.edu def __iadd__(self, other): 5156078Sgblack@eecs.umich.edu self.value += NumericParamValue.unwrap(other) 5166078Sgblack@eecs.umich.edu self._check() 51711147Smitch.hayenga@arm.com return self 51811147Smitch.hayenga@arm.com 5196739Sgblack@eecs.umich.edu def __isub__(self, other): 5206739Sgblack@eecs.umich.edu self.value -= NumericParamValue.unwrap(other) 5216739Sgblack@eecs.umich.edu self._check() 5226739Sgblack@eecs.umich.edu return self 5236739Sgblack@eecs.umich.edu 5243170Sstever@eecs.umich.edu def __imul__(self, other): 5253170Sstever@eecs.umich.edu self.value *= NumericParamValue.unwrap(other) 5264999Sgblack@eecs.umich.edu self._check() 5274999Sgblack@eecs.umich.edu return self 5284999Sgblack@eecs.umich.edu 5294999Sgblack@eecs.umich.edu def __itruediv__(self, other): 5304999Sgblack@eecs.umich.edu self.value /= NumericParamValue.unwrap(other) 5317520Sgblack@eecs.umich.edu self._check() 5324999Sgblack@eecs.umich.edu return self 5337520Sgblack@eecs.umich.edu 5344999Sgblack@eecs.umich.edu def __ifloordiv__(self, other): 5354999Sgblack@eecs.umich.edu self.value //= NumericParamValue.unwrap(other) 5362623SN/A self._check() 5372623SN/A return self 5382623SN/A 5392623SN/A def __lt__(self, other): 5402623SN/A return self.value < NumericParamValue.unwrap(other) 5412623SN/A 5422623SN/A # Python 2.7 pre __future__.division operators 5434940Snate@binkert.org # TODO: Remove these when after "import division from __future__" 5444940Snate@binkert.org __div__ = __truediv__ 54511147Smitch.hayenga@arm.com __idiv__ = __itruediv__ 54611147Smitch.hayenga@arm.com 54711147Smitch.hayenga@arm.com def config_value(self): 54811147Smitch.hayenga@arm.com return self.value 54911147Smitch.hayenga@arm.com 55011148Smitch.hayenga@arm.com @classmethod 55111148Smitch.hayenga@arm.com def cxx_ini_predecls(cls, code): 55211435Smitch.hayenga@arm.com # Assume that base/str.hh will be included anyway 55311435Smitch.hayenga@arm.com # code('#include "base/str.hh"') 55411435Smitch.hayenga@arm.com pass 55511147Smitch.hayenga@arm.com 55611147Smitch.hayenga@arm.com # The default for parsing PODs from an .ini entry is to extract from an 55711147Smitch.hayenga@arm.com # istringstream and let overloading choose the right type according to 55811147Smitch.hayenga@arm.com # the dest type. 55911147Smitch.hayenga@arm.com @classmethod 5605487Snate@binkert.org def cxx_ini_parse(self, code, src, dest, ret): 5612623SN/A code('%s to_number(%s, %s);' % (ret, src, dest)) 5626078Sgblack@eecs.umich.edu 5632623SN/A# Metaclass for bounds-checked integer parameters. See CheckedInt. 56412284Sjose.marinho@arm.comclass CheckedIntType(MetaParamValue): 5652623SN/A def __init__(cls, name, bases, dict): 56610596Sgabeblack@google.com super(CheckedIntType, cls).__init__(name, bases, dict) 5673387Sgblack@eecs.umich.edu 56810596Sgabeblack@google.com # CheckedInt is an abstract base class, so we actually don't 56910596Sgabeblack@google.com # want to do any processing on it... the rest of this code is 5702626SN/A # just for classes that derive from CheckedInt. 5718143SAli.Saidi@ARM.com if name == 'CheckedInt': 5729443SAndreas.Sandberg@ARM.com return 5739443SAndreas.Sandberg@ARM.com 5748143SAli.Saidi@ARM.com if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 5759443SAndreas.Sandberg@ARM.com if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 5765348Ssaidi@eecs.umich.edu panic("CheckedInt subclass %s must define either\n" \ 5775669Sgblack@eecs.umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n", 5785669Sgblack@eecs.umich.edu name); 5797720Sgblack@eecs.umich.edu if cls.unsigned: 5807720Sgblack@eecs.umich.edu cls.min = 0 5817720Sgblack@eecs.umich.edu cls.max = 2 ** cls.size - 1 5827720Sgblack@eecs.umich.edu else: 5837720Sgblack@eecs.umich.edu cls.min = -(2 ** (cls.size - 1)) 58410024Sdam.sunwoo@arm.com cls.max = (2 ** (cls.size - 1)) - 1 5855894Sgblack@eecs.umich.edu 58611147Smitch.hayenga@arm.com# Abstract superclass for bounds-checked integer parameters. This 5876023Snate@binkert.org# class is subclassed to generate parameter classes with specific 5885894Sgblack@eecs.umich.edu# bounds. Initialization of the min and max bounds is done in the 5892623SN/A# metaclass CheckedIntType.__init__. 5902623SN/Aclass CheckedInt(NumericParamValue): 5914182Sgblack@eecs.umich.edu __metaclass__ = CheckedIntType 5924182Sgblack@eecs.umich.edu cmd_line_settable = True 5934182Sgblack@eecs.umich.edu 5942662Sstever@eecs.umich.edu def _check(self): 5957720Sgblack@eecs.umich.edu if not self.min <= self.value <= self.max: 5969023Sgblack@eecs.umich.edu raise TypeError('Integer param out of bounds %d < %d < %d' % \ 5975694Sgblack@eecs.umich.edu (self.min, self.value, self.max)) 5985694Sgblack@eecs.umich.edu 5995694Sgblack@eecs.umich.edu def __init__(self, value): 6005669Sgblack@eecs.umich.edu if isinstance(value, str): 60111321Ssteve.reinhardt@amd.com self.value = convert.toInteger(value) 6025669Sgblack@eecs.umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 6035669Sgblack@eecs.umich.edu self.value = long(value) 6048949Sandreas.hansson@arm.com else: 6055669Sgblack@eecs.umich.edu raise TypeError("Can't convert object of type %s to CheckedInt" \ 6062623SN/A % type(value).__name__) 6078931Sandreas.hansson@arm.com self._check() 6088931Sandreas.hansson@arm.com 6095669Sgblack@eecs.umich.edu def __call__(self, value): 6105669Sgblack@eecs.umich.edu self.__init__(value) 6114968Sacolyte@umich.edu return value 6125669Sgblack@eecs.umich.edu 6134968Sacolyte@umich.edu def __index__(self): 6145669Sgblack@eecs.umich.edu return int(self.value) 6155669Sgblack@eecs.umich.edu 6165669Sgblack@eecs.umich.edu @classmethod 6175669Sgblack@eecs.umich.edu def cxx_predecls(cls, code): 6184182Sgblack@eecs.umich.edu # most derived types require this, so we just do it here once 6192623SN/A code('#include "base/types.hh"') 6203814Ssaidi@eecs.umich.edu 62111877Sbrandon.potter@amd.com def getValue(self): 6225001Sgblack@eecs.umich.edu return long(self.value) 62311147Smitch.hayenga@arm.com 6244998Sgblack@eecs.umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 6254998Sgblack@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 62610381Sdam.sunwoo@arm.com 6274998Sgblack@eecs.umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 62810651Snikos.nikoleris@gmail.comclass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 62910381Sdam.sunwoo@arm.comclass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 6307655Sali.saidi@arm.comclass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 6315001Sgblack@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 6325001Sgblack@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 6335001Sgblack@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 6344998Sgblack@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 63511877Sbrandon.potter@amd.com 63611877Sbrandon.potter@amd.comclass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 63711877Sbrandon.potter@amd.comclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 63811877Sbrandon.potter@amd.comclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 63911877Sbrandon.potter@amd.comclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 64011877Sbrandon.potter@amd.com 64111877Sbrandon.potter@amd.comclass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 6424182Sgblack@eecs.umich.edu 6434182Sgblack@eecs.umich.educlass Cycles(CheckedInt): 6442623SN/A cxx_type = 'Cycles' 6453814Ssaidi@eecs.umich.edu size = 64 6464539Sgblack@eecs.umich.edu unsigned = True 6474539Sgblack@eecs.umich.edu 6483814Ssaidi@eecs.umich.edu def getValue(self): 6493814Ssaidi@eecs.umich.edu from _m5.core import Cycles 6505487Snate@binkert.org return Cycles(self.value) 6515487Snate@binkert.org 6525487Snate@binkert.org @classmethod 6535487Snate@binkert.org def cxx_ini_predecls(cls, code): 6545487Snate@binkert.org # Assume that base/str.hh will be included anyway 6555487Snate@binkert.org # code('#include "base/str.hh"') 6565487Snate@binkert.org pass 6579180Sandreas.hansson@arm.com 6589180Sandreas.hansson@arm.com @classmethod 6599180Sandreas.hansson@arm.com def cxx_ini_parse(cls, code, src, dest, ret): 6609180Sandreas.hansson@arm.com code('uint64_t _temp;') 6619180Sandreas.hansson@arm.com code('bool _ret = to_number(%s, _temp);' % src) 6622623SN/A code('if (_ret)') 6632623SN/A code(' %s = Cycles(_temp);' % dest) 6642623SN/A code('%s _ret;' % ret) 66511321Ssteve.reinhardt@amd.com 6664182Sgblack@eecs.umich.educlass Float(ParamValue, float): 6672623SN/A cxx_type = 'double' 6682623SN/A cmd_line_settable = True 6699443SAndreas.Sandberg@ARM.com 6709443SAndreas.Sandberg@ARM.com def __init__(self, value): 6719443SAndreas.Sandberg@ARM.com if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 6725487Snate@binkert.org self.value = float(value) 6739179Sandreas.hansson@arm.com else: 6749179Sandreas.hansson@arm.com raise TypeError("Can't convert object of type %s to Float" \ 6755487Snate@binkert.org % type(value).__name__) 6762626SN/A 67711147Smitch.hayenga@arm.com def __call__(self, value): 6782623SN/A self.__init__(value) 6792623SN/A return value 68010381Sdam.sunwoo@arm.com 68110381Sdam.sunwoo@arm.com def getValue(self): 68210381Sdam.sunwoo@arm.com return float(self.value) 68310464SAndreas.Sandberg@ARM.com 68410464SAndreas.Sandberg@ARM.com def config_value(self): 68510381Sdam.sunwoo@arm.com return self 68610381Sdam.sunwoo@arm.com 68710381Sdam.sunwoo@arm.com @classmethod 6882623SN/A def cxx_ini_predecls(cls, code): 6895315Sstever@gmail.com code('#include <sstream>') 6905315Sstever@gmail.com 6915315Sstever@gmail.com @classmethod 6925315Sstever@gmail.com def cxx_ini_parse(self, code, src, dest, ret): 6935315Sstever@gmail.com code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 6945315Sstever@gmail.com 6952623SN/Aclass MemorySize(CheckedInt): 6962623SN/A cxx_type = 'uint64_t' 6972623SN/A ex_str = '512MB' 6982623SN/A size = 64 6994762Snate@binkert.org unsigned = True 7004762Snate@binkert.org def __init__(self, value): 7012623SN/A if isinstance(value, MemorySize): 7025529Snate@binkert.org self.value = value.value 7032623SN/A else: 704 self.value = convert.toMemorySize(value) 705 self._check() 706 707class MemorySize32(CheckedInt): 708 cxx_type = 'uint32_t' 709 ex_str = '512MB' 710 size = 32 711 unsigned = True 712 def __init__(self, value): 713 if isinstance(value, MemorySize): 714 self.value = value.value 715 else: 716 self.value = convert.toMemorySize(value) 717 self._check() 718 719class Addr(CheckedInt): 720 cxx_type = 'Addr' 721 size = 64 722 unsigned = True 723 def __init__(self, value): 724 if isinstance(value, Addr): 725 self.value = value.value 726 else: 727 try: 728 # Often addresses are referred to with sizes. Ex: A device 729 # base address is at "512MB". Use toMemorySize() to convert 730 # these into addresses. If the address is not specified with a 731 # "size", an exception will occur and numeric translation will 732 # proceed below. 733 self.value = convert.toMemorySize(value) 734 except (TypeError, ValueError): 735 # Convert number to string and use long() to do automatic 736 # base conversion (requires base=0 for auto-conversion) 737 self.value = long(str(value), base=0) 738 739 self._check() 740 def __add__(self, other): 741 if isinstance(other, Addr): 742 return self.value + other.value 743 else: 744 return self.value + other 745 def pretty_print(self, value): 746 try: 747 val = convert.toMemorySize(value) 748 except TypeError: 749 val = long(value) 750 return "0x%x" % long(val) 751 752class AddrRange(ParamValue): 753 cxx_type = 'AddrRange' 754 755 def __init__(self, *args, **kwargs): 756 # Disable interleaving and hashing by default 757 self.intlvHighBit = 0 758 self.xorHighBit = 0 759 self.intlvBits = 0 760 self.intlvMatch = 0 761 762 def handle_kwargs(self, kwargs): 763 # An address range needs to have an upper limit, specified 764 # either explicitly with an end, or as an offset using the 765 # size keyword. 766 if 'end' in kwargs: 767 self.end = Addr(kwargs.pop('end')) 768 elif 'size' in kwargs: 769 self.end = self.start + Addr(kwargs.pop('size')) - 1 770 else: 771 raise TypeError("Either end or size must be specified") 772 773 # Now on to the optional bit 774 if 'intlvHighBit' in kwargs: 775 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 776 if 'xorHighBit' in kwargs: 777 self.xorHighBit = int(kwargs.pop('xorHighBit')) 778 if 'intlvBits' in kwargs: 779 self.intlvBits = int(kwargs.pop('intlvBits')) 780 if 'intlvMatch' in kwargs: 781 self.intlvMatch = int(kwargs.pop('intlvMatch')) 782 783 if len(args) == 0: 784 self.start = Addr(kwargs.pop('start')) 785 handle_kwargs(self, kwargs) 786 787 elif len(args) == 1: 788 if kwargs: 789 self.start = Addr(args[0]) 790 handle_kwargs(self, kwargs) 791 elif isinstance(args[0], (list, tuple)): 792 self.start = Addr(args[0][0]) 793 self.end = Addr(args[0][1]) 794 else: 795 self.start = Addr(0) 796 self.end = Addr(args[0]) - 1 797 798 elif len(args) == 2: 799 self.start = Addr(args[0]) 800 self.end = Addr(args[1]) 801 else: 802 raise TypeError("Too many arguments specified") 803 804 if kwargs: 805 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 806 807 def __str__(self): 808 return '%s:%s:%s:%s:%s:%s' \ 809 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 810 self.intlvBits, self.intlvMatch) 811 812 def size(self): 813 # Divide the size by the size of the interleaving slice 814 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 815 816 @classmethod 817 def cxx_predecls(cls, code): 818 Addr.cxx_predecls(code) 819 code('#include "base/addr_range.hh"') 820 821 @classmethod 822 def pybind_predecls(cls, code): 823 Addr.pybind_predecls(code) 824 code('#include "base/addr_range.hh"') 825 826 @classmethod 827 def cxx_ini_predecls(cls, code): 828 code('#include <sstream>') 829 830 @classmethod 831 def cxx_ini_parse(cls, code, src, dest, ret): 832 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 833 code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 834 code('char _sep;') 835 code('std::istringstream _stream(${src});') 836 code('_stream >> _start;') 837 code('_stream.get(_sep);') 838 code('_stream >> _end;') 839 code('if (!_stream.fail() && !_stream.eof()) {') 840 code(' _stream.get(_sep);') 841 code(' _stream >> _intlvHighBit;') 842 code(' _stream.get(_sep);') 843 code(' _stream >> _xorHighBit;') 844 code(' _stream.get(_sep);') 845 code(' _stream >> _intlvBits;') 846 code(' _stream.get(_sep);') 847 code(' _stream >> _intlvMatch;') 848 code('}') 849 code('bool _ret = !_stream.fail() &&' 850 '_stream.eof() && _sep == \':\';') 851 code('if (_ret)') 852 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 853 _xorHighBit, _intlvBits, _intlvMatch);') 854 code('${ret} _ret;') 855 856 def getValue(self): 857 # Go from the Python class to the wrapped C++ class 858 from _m5.range import AddrRange 859 860 return AddrRange(long(self.start), long(self.end), 861 int(self.intlvHighBit), int(self.xorHighBit), 862 int(self.intlvBits), int(self.intlvMatch)) 863 864# Boolean parameter type. Python doesn't let you subclass bool, since 865# it doesn't want to let you create multiple instances of True and 866# False. Thus this is a little more complicated than String. 867class Bool(ParamValue): 868 cxx_type = 'bool' 869 cmd_line_settable = True 870 871 def __init__(self, value): 872 try: 873 self.value = convert.toBool(value) 874 except TypeError: 875 self.value = bool(value) 876 877 def __call__(self, value): 878 self.__init__(value) 879 return value 880 881 def getValue(self): 882 return bool(self.value) 883 884 def __str__(self): 885 return str(self.value) 886 887 # implement truth value testing for Bool parameters so that these params 888 # evaluate correctly during the python configuration phase 889 def __bool__(self): 890 return bool(self.value) 891 892 # Python 2.7 uses __nonzero__ instead of __bool__ 893 __nonzero__ = __bool__ 894 895 def ini_str(self): 896 if self.value: 897 return 'true' 898 return 'false' 899 900 def config_value(self): 901 return self.value 902 903 @classmethod 904 def cxx_ini_predecls(cls, code): 905 # Assume that base/str.hh will be included anyway 906 # code('#include "base/str.hh"') 907 pass 908 909 @classmethod 910 def cxx_ini_parse(cls, code, src, dest, ret): 911 code('%s to_bool(%s, %s);' % (ret, src, dest)) 912 913def IncEthernetAddr(addr, val = 1): 914 bytes = [ int(x, 16) for x in addr.split(':') ] 915 bytes[5] += val 916 for i in (5, 4, 3, 2, 1): 917 val,rem = divmod(bytes[i], 256) 918 bytes[i] = rem 919 if val == 0: 920 break 921 bytes[i - 1] += val 922 assert(bytes[0] <= 255) 923 return ':'.join(map(lambda x: '%02x' % x, bytes)) 924 925_NextEthernetAddr = "00:90:00:00:00:01" 926def NextEthernetAddr(): 927 global _NextEthernetAddr 928 929 value = _NextEthernetAddr 930 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 931 return value 932 933class EthernetAddr(ParamValue): 934 cxx_type = 'Net::EthAddr' 935 ex_str = "00:90:00:00:00:01" 936 cmd_line_settable = True 937 938 @classmethod 939 def cxx_predecls(cls, code): 940 code('#include "base/inet.hh"') 941 942 def __init__(self, value): 943 if value == NextEthernetAddr: 944 self.value = value 945 return 946 947 if not isinstance(value, str): 948 raise TypeError("expected an ethernet address and didn't get one") 949 950 bytes = value.split(':') 951 if len(bytes) != 6: 952 raise TypeError('invalid ethernet address %s' % value) 953 954 for byte in bytes: 955 if not 0 <= int(byte, base=16) <= 0xff: 956 raise TypeError('invalid ethernet address %s' % value) 957 958 self.value = value 959 960 def __call__(self, value): 961 self.__init__(value) 962 return value 963 964 def unproxy(self, base): 965 if self.value == NextEthernetAddr: 966 return EthernetAddr(self.value()) 967 return self 968 969 def getValue(self): 970 from _m5.net import EthAddr 971 return EthAddr(self.value) 972 973 def __str__(self): 974 return self.value 975 976 def ini_str(self): 977 return self.value 978 979 @classmethod 980 def cxx_ini_parse(self, code, src, dest, ret): 981 code('%s = Net::EthAddr(%s);' % (dest, src)) 982 code('%s true;' % ret) 983 984# When initializing an IpAddress, pass in an existing IpAddress, a string of 985# the form "a.b.c.d", or an integer representing an IP. 986class IpAddress(ParamValue): 987 cxx_type = 'Net::IpAddress' 988 ex_str = "127.0.0.1" 989 cmd_line_settable = True 990 991 @classmethod 992 def cxx_predecls(cls, code): 993 code('#include "base/inet.hh"') 994 995 def __init__(self, value): 996 if isinstance(value, IpAddress): 997 self.ip = value.ip 998 else: 999 try: 1000 self.ip = convert.toIpAddress(value) 1001 except TypeError: 1002 self.ip = long(value) 1003 self.verifyIp() 1004 1005 def __call__(self, value): 1006 self.__init__(value) 1007 return value 1008 1009 def __str__(self): 1010 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 1011 return '%d.%d.%d.%d' % tuple(tup) 1012 1013 def __eq__(self, other): 1014 if isinstance(other, IpAddress): 1015 return self.ip == other.ip 1016 elif isinstance(other, str): 1017 try: 1018 return self.ip == convert.toIpAddress(other) 1019 except: 1020 return False 1021 else: 1022 return self.ip == other 1023 1024 def __ne__(self, other): 1025 return not (self == other) 1026 1027 def verifyIp(self): 1028 if self.ip < 0 or self.ip >= (1 << 32): 1029 raise TypeError("invalid ip address %#08x" % self.ip) 1030 1031 def getValue(self): 1032 from _m5.net import IpAddress 1033 return IpAddress(self.ip) 1034 1035# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 1036# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 1037# positional or keyword arguments. 1038class IpNetmask(IpAddress): 1039 cxx_type = 'Net::IpNetmask' 1040 ex_str = "127.0.0.0/24" 1041 cmd_line_settable = True 1042 1043 @classmethod 1044 def cxx_predecls(cls, code): 1045 code('#include "base/inet.hh"') 1046 1047 def __init__(self, *args, **kwargs): 1048 def handle_kwarg(self, kwargs, key, elseVal = None): 1049 if key in kwargs: 1050 setattr(self, key, kwargs.pop(key)) 1051 elif elseVal: 1052 setattr(self, key, elseVal) 1053 else: 1054 raise TypeError("No value set for %s" % key) 1055 1056 if len(args) == 0: 1057 handle_kwarg(self, kwargs, 'ip') 1058 handle_kwarg(self, kwargs, 'netmask') 1059 1060 elif len(args) == 1: 1061 if kwargs: 1062 if not 'ip' in kwargs and not 'netmask' in kwargs: 1063 raise TypeError("Invalid arguments") 1064 handle_kwarg(self, kwargs, 'ip', args[0]) 1065 handle_kwarg(self, kwargs, 'netmask', args[0]) 1066 elif isinstance(args[0], IpNetmask): 1067 self.ip = args[0].ip 1068 self.netmask = args[0].netmask 1069 else: 1070 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1071 1072 elif len(args) == 2: 1073 self.ip = args[0] 1074 self.netmask = args[1] 1075 else: 1076 raise TypeError("Too many arguments specified") 1077 1078 if kwargs: 1079 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 1080 1081 self.verify() 1082 1083 def __call__(self, value): 1084 self.__init__(value) 1085 return value 1086 1087 def __str__(self): 1088 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1089 1090 def __eq__(self, other): 1091 if isinstance(other, IpNetmask): 1092 return self.ip == other.ip and self.netmask == other.netmask 1093 elif isinstance(other, str): 1094 try: 1095 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1096 except: 1097 return False 1098 else: 1099 return False 1100 1101 def verify(self): 1102 self.verifyIp() 1103 if self.netmask < 0 or self.netmask > 32: 1104 raise TypeError("invalid netmask %d" % netmask) 1105 1106 def getValue(self): 1107 from _m5.net import IpNetmask 1108 return IpNetmask(self.ip, self.netmask) 1109 1110# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1111# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1112class IpWithPort(IpAddress): 1113 cxx_type = 'Net::IpWithPort' 1114 ex_str = "127.0.0.1:80" 1115 cmd_line_settable = True 1116 1117 @classmethod 1118 def cxx_predecls(cls, code): 1119 code('#include "base/inet.hh"') 1120 1121 def __init__(self, *args, **kwargs): 1122 def handle_kwarg(self, kwargs, key, elseVal = None): 1123 if key in kwargs: 1124 setattr(self, key, kwargs.pop(key)) 1125 elif elseVal: 1126 setattr(self, key, elseVal) 1127 else: 1128 raise TypeError("No value set for %s" % key) 1129 1130 if len(args) == 0: 1131 handle_kwarg(self, kwargs, 'ip') 1132 handle_kwarg(self, kwargs, 'port') 1133 1134 elif len(args) == 1: 1135 if kwargs: 1136 if not 'ip' in kwargs and not 'port' in kwargs: 1137 raise TypeError("Invalid arguments") 1138 handle_kwarg(self, kwargs, 'ip', args[0]) 1139 handle_kwarg(self, kwargs, 'port', args[0]) 1140 elif isinstance(args[0], IpWithPort): 1141 self.ip = args[0].ip 1142 self.port = args[0].port 1143 else: 1144 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1145 1146 elif len(args) == 2: 1147 self.ip = args[0] 1148 self.port = args[1] 1149 else: 1150 raise TypeError("Too many arguments specified") 1151 1152 if kwargs: 1153 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 1154 1155 self.verify() 1156 1157 def __call__(self, value): 1158 self.__init__(value) 1159 return value 1160 1161 def __str__(self): 1162 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1163 1164 def __eq__(self, other): 1165 if isinstance(other, IpWithPort): 1166 return self.ip == other.ip and self.port == other.port 1167 elif isinstance(other, str): 1168 try: 1169 return (self.ip, self.port) == convert.toIpWithPort(other) 1170 except: 1171 return False 1172 else: 1173 return False 1174 1175 def verify(self): 1176 self.verifyIp() 1177 if self.port < 0 or self.port > 0xffff: 1178 raise TypeError("invalid port %d" % self.port) 1179 1180 def getValue(self): 1181 from _m5.net import IpWithPort 1182 return IpWithPort(self.ip, self.port) 1183 1184time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1185 "%a %b %d %H:%M:%S %Y", 1186 "%Y/%m/%d %H:%M:%S", 1187 "%Y/%m/%d %H:%M", 1188 "%Y/%m/%d", 1189 "%m/%d/%Y %H:%M:%S", 1190 "%m/%d/%Y %H:%M", 1191 "%m/%d/%Y", 1192 "%m/%d/%y %H:%M:%S", 1193 "%m/%d/%y %H:%M", 1194 "%m/%d/%y"] 1195 1196 1197def parse_time(value): 1198 from time import gmtime, strptime, struct_time, time 1199 from datetime import datetime, date 1200 1201 if isinstance(value, struct_time): 1202 return value 1203 1204 if isinstance(value, (int, long)): 1205 return gmtime(value) 1206 1207 if isinstance(value, (datetime, date)): 1208 return value.timetuple() 1209 1210 if isinstance(value, str): 1211 if value in ('Now', 'Today'): 1212 return time.gmtime(time.time()) 1213 1214 for format in time_formats: 1215 try: 1216 return strptime(value, format) 1217 except ValueError: 1218 pass 1219 1220 raise ValueError("Could not parse '%s' as a time" % value) 1221 1222class Time(ParamValue): 1223 cxx_type = 'tm' 1224 1225 @classmethod 1226 def cxx_predecls(cls, code): 1227 code('#include <time.h>') 1228 1229 def __init__(self, value): 1230 self.value = parse_time(value) 1231 1232 def __call__(self, value): 1233 self.__init__(value) 1234 return value 1235 1236 def getValue(self): 1237 from _m5.core import tm 1238 import calendar 1239 1240 return tm.gmtime(calendar.timegm(self.value)) 1241 1242 def __str__(self): 1243 return time.asctime(self.value) 1244 1245 def ini_str(self): 1246 return str(self) 1247 1248 def get_config_as_dict(self): 1249 assert false 1250 return str(self) 1251 1252 @classmethod 1253 def cxx_ini_predecls(cls, code): 1254 code('#include <time.h>') 1255 1256 @classmethod 1257 def cxx_ini_parse(cls, code, src, dest, ret): 1258 code('char *_parse_ret = strptime((${src}).c_str(),') 1259 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1260 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1261 1262# Enumerated types are a little more complex. The user specifies the 1263# type as Enum(foo) where foo is either a list or dictionary of 1264# alternatives (typically strings, but not necessarily so). (In the 1265# long run, the integer value of the parameter will be the list index 1266# or the corresponding dictionary value. For now, since we only check 1267# that the alternative is valid and then spit it into a .ini file, 1268# there's not much point in using the dictionary.) 1269 1270# What Enum() must do is generate a new type encapsulating the 1271# provided list/dictionary so that specific values of the parameter 1272# can be instances of that type. We define two hidden internal 1273# classes (_ListEnum and _DictEnum) to serve as base classes, then 1274# derive the new type from the appropriate base class on the fly. 1275 1276allEnums = {} 1277# Metaclass for Enum types 1278class MetaEnum(MetaParamValue): 1279 def __new__(mcls, name, bases, dict): 1280 assert name not in allEnums 1281 1282 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1283 allEnums[name] = cls 1284 return cls 1285 1286 def __init__(cls, name, bases, init_dict): 1287 if 'map' in init_dict: 1288 if not isinstance(cls.map, dict): 1289 raise TypeError("Enum-derived class attribute 'map' " \ 1290 "must be of type dict") 1291 # build list of value strings from map 1292 cls.vals = list(cls.map.keys()) 1293 cls.vals.sort() 1294 elif 'vals' in init_dict: 1295 if not isinstance(cls.vals, list): 1296 raise TypeError("Enum-derived class attribute 'vals' " \ 1297 "must be of type list") 1298 # build string->value map from vals sequence 1299 cls.map = {} 1300 for idx,val in enumerate(cls.vals): 1301 cls.map[val] = idx 1302 else: 1303 raise TypeError("Enum-derived class must define "\ 1304 "attribute 'map' or 'vals'") 1305 1306 if cls.is_class: 1307 cls.cxx_type = '%s' % name 1308 else: 1309 cls.cxx_type = 'Enums::%s' % name 1310 1311 super(MetaEnum, cls).__init__(name, bases, init_dict) 1312 1313 # Generate C++ class declaration for this enum type. 1314 # Note that we wrap the enum in a class/struct to act as a namespace, 1315 # so that the enum strings can be brief w/o worrying about collisions. 1316 def cxx_decl(cls, code): 1317 wrapper_name = cls.wrapper_name 1318 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1319 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1320 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1321 1322 code('''\ 1323#ifndef $idem_macro 1324#define $idem_macro 1325 1326''') 1327 if cls.is_class: 1328 code('''\ 1329enum class $name { 1330''') 1331 else: 1332 code('''\ 1333$wrapper $wrapper_name { 1334 enum $name { 1335''') 1336 code.indent(1) 1337 code.indent(1) 1338 for val in cls.vals: 1339 code('$val = ${{cls.map[val]}},') 1340 code('Num_$name = ${{len(cls.vals)}}') 1341 code.dedent(1) 1342 code('};') 1343 1344 if cls.is_class: 1345 code('''\ 1346extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})]; 1347''') 1348 elif cls.wrapper_is_struct: 1349 code('static const char *${name}Strings[Num_${name}];') 1350 else: 1351 code('extern const char *${name}Strings[Num_${name}];') 1352 1353 if not cls.is_class: 1354 code.dedent(1) 1355 code('};') 1356 1357 code() 1358 code('#endif // $idem_macro') 1359 1360 def cxx_def(cls, code): 1361 wrapper_name = cls.wrapper_name 1362 file_name = cls.__name__ 1363 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1364 1365 code('#include "enums/$file_name.hh"') 1366 if cls.wrapper_is_struct: 1367 code('const char *${wrapper_name}::${name}Strings' 1368 '[Num_${name}] =') 1369 else: 1370 if cls.is_class: 1371 code('''\ 1372const char *${name}Strings[static_cast<int>(${name}::Num_${name})] = 1373''') 1374 else: 1375 code('namespace Enums {') 1376 code.indent(1) 1377 code('const char *${name}Strings[Num_${name}] =') 1378 1379 code('{') 1380 code.indent(1) 1381 for val in cls.vals: 1382 code('"$val",') 1383 code.dedent(1) 1384 code('};') 1385 1386 if not cls.wrapper_is_struct and not cls.is_class: 1387 code.dedent(1) 1388 code('} // namespace $wrapper_name') 1389 1390 1391 def pybind_def(cls, code): 1392 name = cls.__name__ 1393 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1394 wrapper_name = enum_name if cls.is_class else cls.wrapper_name 1395 1396 code('''#include "pybind11/pybind11.h" 1397#include "pybind11/stl.h" 1398 1399#include <sim/init.hh> 1400 1401namespace py = pybind11; 1402 1403static void 1404module_init(py::module &m_internal) 1405{ 1406 py::module m = m_internal.def_submodule("enum_${name}"); 1407 1408''') 1409 if cls.is_class: 1410 code('py::enum_<${enum_name}>(m, "enum_${name}")') 1411 else: 1412 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")') 1413 1414 code.indent() 1415 code.indent() 1416 for val in cls.vals: 1417 code('.value("${val}", ${wrapper_name}::${val})') 1418 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1419 code('.export_values()') 1420 code(';') 1421 code.dedent() 1422 1423 code('}') 1424 code.dedent() 1425 code() 1426 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1427 1428 1429# Base class for enum types. 1430class Enum(ParamValue): 1431 __metaclass__ = MetaEnum 1432 vals = [] 1433 cmd_line_settable = True 1434 1435 # The name of the wrapping namespace or struct 1436 wrapper_name = 'Enums' 1437 1438 # If true, the enum is wrapped in a struct rather than a namespace 1439 wrapper_is_struct = False 1440 1441 is_class = False 1442 1443 # If not None, use this as the enum name rather than this class name 1444 enum_name = None 1445 1446 def __init__(self, value): 1447 if value not in self.map: 1448 raise TypeError("Enum param got bad value '%s' (not in %s)" \ 1449 % (value, self.vals)) 1450 self.value = value 1451 1452 def __call__(self, value): 1453 self.__init__(value) 1454 return value 1455 1456 @classmethod 1457 def cxx_predecls(cls, code): 1458 code('#include "enums/$0.hh"', cls.__name__) 1459 1460 @classmethod 1461 def cxx_ini_parse(cls, code, src, dest, ret): 1462 code('if (false) {') 1463 for elem_name in cls.map.keys(): 1464 code('} else if (%s == "%s") {' % (src, elem_name)) 1465 code.indent() 1466 code('%s = Enums::%s;' % (dest, elem_name)) 1467 code('%s true;' % ret) 1468 code.dedent() 1469 code('} else {') 1470 code(' %s false;' % ret) 1471 code('}') 1472 1473 def getValue(self): 1474 import m5.internal.params 1475 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1476 return e(self.map[self.value]) 1477 1478 def __str__(self): 1479 return self.value 1480 1481# This param will generate a scoped c++ enum and its python bindings. 1482class ScopedEnum(Enum): 1483 __metaclass__ = MetaEnum 1484 vals = [] 1485 cmd_line_settable = True 1486 1487 # The name of the wrapping namespace or struct 1488 wrapper_name = None 1489 1490 # If true, the enum is wrapped in a struct rather than a namespace 1491 wrapper_is_struct = False 1492 1493 # If true, the generated enum is a scoped enum 1494 is_class = True 1495 1496 # If not None, use this as the enum name rather than this class name 1497 enum_name = None 1498 1499# how big does a rounding error need to be before we warn about it? 1500frequency_tolerance = 0.001 # 0.1% 1501 1502class TickParamValue(NumericParamValue): 1503 cxx_type = 'Tick' 1504 ex_str = "1MHz" 1505 cmd_line_settable = True 1506 1507 @classmethod 1508 def cxx_predecls(cls, code): 1509 code('#include "base/types.hh"') 1510 1511 def __call__(self, value): 1512 self.__init__(value) 1513 return value 1514 1515 def getValue(self): 1516 return long(self.value) 1517 1518 @classmethod 1519 def cxx_ini_predecls(cls, code): 1520 code('#include <sstream>') 1521 1522 # Ticks are expressed in seconds in JSON files and in plain 1523 # Ticks in .ini files. Switch based on a config flag 1524 @classmethod 1525 def cxx_ini_parse(self, code, src, dest, ret): 1526 code('${ret} to_number(${src}, ${dest});') 1527 1528class Latency(TickParamValue): 1529 ex_str = "100ns" 1530 1531 def __init__(self, value): 1532 if isinstance(value, (Latency, Clock)): 1533 self.ticks = value.ticks 1534 self.value = value.value 1535 elif isinstance(value, Frequency): 1536 self.ticks = value.ticks 1537 self.value = 1.0 / value.value 1538 elif value.endswith('t'): 1539 self.ticks = True 1540 self.value = int(value[:-1]) 1541 else: 1542 self.ticks = False 1543 self.value = convert.toLatency(value) 1544 1545 def __call__(self, value): 1546 self.__init__(value) 1547 return value 1548 1549 def __getattr__(self, attr): 1550 if attr in ('latency', 'period'): 1551 return self 1552 if attr == 'frequency': 1553 return Frequency(self) 1554 raise AttributeError("Latency object has no attribute '%s'" % attr) 1555 1556 def getValue(self): 1557 if self.ticks or self.value == 0: 1558 value = self.value 1559 else: 1560 value = ticks.fromSeconds(self.value) 1561 return long(value) 1562 1563 def config_value(self): 1564 return self.getValue() 1565 1566 # convert latency to ticks 1567 def ini_str(self): 1568 return '%d' % self.getValue() 1569 1570class Frequency(TickParamValue): 1571 ex_str = "1GHz" 1572 1573 def __init__(self, value): 1574 if isinstance(value, (Latency, Clock)): 1575 if value.value == 0: 1576 self.value = 0 1577 else: 1578 self.value = 1.0 / value.value 1579 self.ticks = value.ticks 1580 elif isinstance(value, Frequency): 1581 self.value = value.value 1582 self.ticks = value.ticks 1583 else: 1584 self.ticks = False 1585 self.value = convert.toFrequency(value) 1586 1587 def __call__(self, value): 1588 self.__init__(value) 1589 return value 1590 1591 def __getattr__(self, attr): 1592 if attr == 'frequency': 1593 return self 1594 if attr in ('latency', 'period'): 1595 return Latency(self) 1596 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1597 1598 # convert latency to ticks 1599 def getValue(self): 1600 if self.ticks or self.value == 0: 1601 value = self.value 1602 else: 1603 value = ticks.fromSeconds(1.0 / self.value) 1604 return long(value) 1605 1606 def config_value(self): 1607 return self.getValue() 1608 1609 def ini_str(self): 1610 return '%d' % self.getValue() 1611 1612# A generic Frequency and/or Latency value. Value is stored as a 1613# latency, just like Latency and Frequency. 1614class Clock(TickParamValue): 1615 def __init__(self, value): 1616 if isinstance(value, (Latency, Clock)): 1617 self.ticks = value.ticks 1618 self.value = value.value 1619 elif isinstance(value, Frequency): 1620 self.ticks = value.ticks 1621 self.value = 1.0 / value.value 1622 elif value.endswith('t'): 1623 self.ticks = True 1624 self.value = int(value[:-1]) 1625 else: 1626 self.ticks = False 1627 self.value = convert.anyToLatency(value) 1628 1629 def __call__(self, value): 1630 self.__init__(value) 1631 return value 1632 1633 def __str__(self): 1634 return "%s" % Latency(self) 1635 1636 def __getattr__(self, attr): 1637 if attr == 'frequency': 1638 return Frequency(self) 1639 if attr in ('latency', 'period'): 1640 return Latency(self) 1641 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1642 1643 def getValue(self): 1644 return self.period.getValue() 1645 1646 def config_value(self): 1647 return self.period.config_value() 1648 1649 def ini_str(self): 1650 return self.period.ini_str() 1651 1652class Voltage(Float): 1653 ex_str = "1V" 1654 1655 def __new__(cls, value): 1656 value = convert.toVoltage(value) 1657 return super(cls, Voltage).__new__(cls, value) 1658 1659 def __init__(self, value): 1660 value = convert.toVoltage(value) 1661 super(Voltage, self).__init__(value) 1662 1663class Current(Float): 1664 ex_str = "1mA" 1665 1666 def __new__(cls, value): 1667 value = convert.toCurrent(value) 1668 return super(cls, Current).__new__(cls, value) 1669 1670 def __init__(self, value): 1671 value = convert.toCurrent(value) 1672 super(Current, self).__init__(value) 1673 1674class Energy(Float): 1675 ex_str = "1pJ" 1676 1677 def __new__(cls, value): 1678 value = convert.toEnergy(value) 1679 return super(cls, Energy).__new__(cls, value) 1680 1681 def __init__(self, value): 1682 value = convert.toEnergy(value) 1683 super(Energy, self).__init__(value) 1684 1685class NetworkBandwidth(float,ParamValue): 1686 cxx_type = 'float' 1687 ex_str = "1Gbps" 1688 cmd_line_settable = True 1689 1690 def __new__(cls, value): 1691 # convert to bits per second 1692 val = convert.toNetworkBandwidth(value) 1693 return super(cls, NetworkBandwidth).__new__(cls, val) 1694 1695 def __str__(self): 1696 return str(self.val) 1697 1698 def __call__(self, value): 1699 val = convert.toNetworkBandwidth(value) 1700 self.__init__(val) 1701 return value 1702 1703 def getValue(self): 1704 # convert to seconds per byte 1705 value = 8.0 / float(self) 1706 # convert to ticks per byte 1707 value = ticks.fromSeconds(value) 1708 return float(value) 1709 1710 def ini_str(self): 1711 return '%f' % self.getValue() 1712 1713 def config_value(self): 1714 return '%f' % self.getValue() 1715 1716 @classmethod 1717 def cxx_ini_predecls(cls, code): 1718 code('#include <sstream>') 1719 1720 @classmethod 1721 def cxx_ini_parse(self, code, src, dest, ret): 1722 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1723 1724class MemoryBandwidth(float,ParamValue): 1725 cxx_type = 'float' 1726 ex_str = "1GB/s" 1727 cmd_line_settable = True 1728 1729 def __new__(cls, value): 1730 # convert to bytes per second 1731 val = convert.toMemoryBandwidth(value) 1732 return super(cls, MemoryBandwidth).__new__(cls, val) 1733 1734 def __call__(self, value): 1735 val = convert.toMemoryBandwidth(value) 1736 self.__init__(val) 1737 return value 1738 1739 def getValue(self): 1740 # convert to seconds per byte 1741 value = float(self) 1742 if value: 1743 value = 1.0 / float(self) 1744 # convert to ticks per byte 1745 value = ticks.fromSeconds(value) 1746 return float(value) 1747 1748 def ini_str(self): 1749 return '%f' % self.getValue() 1750 1751 def config_value(self): 1752 return '%f' % self.getValue() 1753 1754 @classmethod 1755 def cxx_ini_predecls(cls, code): 1756 code('#include <sstream>') 1757 1758 @classmethod 1759 def cxx_ini_parse(self, code, src, dest, ret): 1760 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1761 1762# 1763# "Constants"... handy aliases for various values. 1764# 1765 1766# Special class for NULL pointers. Note the special check in 1767# make_param_value() above that lets these be assigned where a 1768# SimObject is required. 1769# only one copy of a particular node 1770class NullSimObject(object): 1771 __metaclass__ = Singleton 1772 _name = 'Null' 1773 1774 def __call__(cls): 1775 return cls 1776 1777 def _instantiate(self, parent = None, path = ''): 1778 pass 1779 1780 def ini_str(self): 1781 return 'Null' 1782 1783 def unproxy(self, base): 1784 return self 1785 1786 def set_path(self, parent, name): 1787 pass 1788 1789 def set_parent(self, parent, name): 1790 pass 1791 1792 def clear_parent(self, old_parent): 1793 pass 1794 1795 def descendants(self): 1796 return 1797 yield None 1798 1799 def get_config_as_dict(self): 1800 return {} 1801 1802 def __str__(self): 1803 return self._name 1804 1805 def config_value(self): 1806 return None 1807 1808 def getValue(self): 1809 return None 1810 1811# The only instance you'll ever need... 1812NULL = NullSimObject() 1813 1814def isNullPointer(value): 1815 return isinstance(value, NullSimObject) 1816 1817# Some memory range specifications use this as a default upper bound. 1818MaxAddr = Addr.max 1819MaxTick = Tick.max 1820AllMemory = AddrRange(0, MaxAddr) 1821 1822 1823##################################################################### 1824# 1825# Port objects 1826# 1827# Ports are used to interconnect objects in the memory system. 1828# 1829##################################################################### 1830 1831# Port reference: encapsulates a reference to a particular port on a 1832# particular SimObject. 1833class PortRef(object): 1834 def __init__(self, simobj, name, role): 1835 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1836 self.simobj = simobj 1837 self.name = name 1838 self.role = role 1839 self.peer = None # not associated with another port yet 1840 self.ccConnected = False # C++ port connection done? 1841 self.index = -1 # always -1 for non-vector ports 1842 1843 def __str__(self): 1844 return '%s.%s' % (self.simobj, self.name) 1845 1846 def __len__(self): 1847 # Return the number of connected ports, i.e. 0 is we have no 1848 # peer and 1 if we do. 1849 return int(self.peer != None) 1850 1851 # for config.ini, print peer's name (not ours) 1852 def ini_str(self): 1853 return str(self.peer) 1854 1855 # for config.json 1856 def get_config_as_dict(self): 1857 return {'role' : self.role, 'peer' : str(self.peer)} 1858 1859 def __getattr__(self, attr): 1860 if attr == 'peerObj': 1861 # shorthand for proxies 1862 return self.peer.simobj 1863 raise AttributeError("'%s' object has no attribute '%s'" % \ 1864 (self.__class__.__name__, attr)) 1865 1866 # Full connection is symmetric (both ways). Called via 1867 # SimObject.__setattr__ as a result of a port assignment, e.g., 1868 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1869 # e.g., "obj1.portA[3] = obj2.portB". 1870 def connect(self, other): 1871 if isinstance(other, VectorPortRef): 1872 # reference to plain VectorPort is implicit append 1873 other = other._get_next() 1874 if self.peer and not proxy.isproxy(self.peer): 1875 fatal("Port %s is already connected to %s, cannot connect %s\n", 1876 self, self.peer, other); 1877 self.peer = other 1878 if proxy.isproxy(other): 1879 other.set_param_desc(PortParamDesc()) 1880 elif isinstance(other, PortRef): 1881 if other.peer is not self: 1882 other.connect(self) 1883 else: 1884 raise TypeError("assigning non-port reference '%s' to port '%s'" \ 1885 % (other, self)) 1886 1887 # Allow a master/slave port pair to be spliced between 1888 # a port and its connected peer. Useful operation for connecting 1889 # instrumentation structures into a system when it is necessary 1890 # to connect the instrumentation after the full system has been 1891 # constructed. 1892 def splice(self, new_master_peer, new_slave_peer): 1893 if not self.peer or proxy.isproxy(self.peer): 1894 fatal("Port %s not connected, cannot splice in new peers\n", self) 1895 1896 if not isinstance(new_master_peer, PortRef) or \ 1897 not isinstance(new_slave_peer, PortRef): 1898 raise TypeError( 1899 "Splicing non-port references '%s','%s' to port '%s'" % \ 1900 (new_master_peer, new_slave_peer, self)) 1901 1902 old_peer = self.peer 1903 if self.role == 'SLAVE': 1904 self.peer = new_master_peer 1905 old_peer.peer = new_slave_peer 1906 new_master_peer.connect(self) 1907 new_slave_peer.connect(old_peer) 1908 elif self.role == 'MASTER': 1909 self.peer = new_slave_peer 1910 old_peer.peer = new_master_peer 1911 new_slave_peer.connect(self) 1912 new_master_peer.connect(old_peer) 1913 else: 1914 panic("Port %s has unknown role, "+\ 1915 "cannot splice in new peers\n", self) 1916 1917 def clone(self, simobj, memo): 1918 if self in memo: 1919 return memo[self] 1920 newRef = copy.copy(self) 1921 memo[self] = newRef 1922 newRef.simobj = simobj 1923 assert(isSimObject(newRef.simobj)) 1924 if self.peer and not proxy.isproxy(self.peer): 1925 peerObj = self.peer.simobj(_memo=memo) 1926 newRef.peer = self.peer.clone(peerObj, memo) 1927 assert(not isinstance(newRef.peer, VectorPortRef)) 1928 return newRef 1929 1930 def unproxy(self, simobj): 1931 assert(simobj is self.simobj) 1932 if proxy.isproxy(self.peer): 1933 try: 1934 realPeer = self.peer.unproxy(self.simobj) 1935 except: 1936 print("Error in unproxying port '%s' of %s" % 1937 (self.name, self.simobj.path())) 1938 raise 1939 self.connect(realPeer) 1940 1941 # Call C++ to create corresponding port connection between C++ objects 1942 def ccConnect(self): 1943 from _m5.pyobject import connectPorts 1944 1945 if self.ccConnected: # already done this 1946 return 1947 1948 peer = self.peer 1949 if not self.peer: # nothing to connect to 1950 return 1951 1952 # check that we connect a master to a slave 1953 if self.role == peer.role: 1954 raise TypeError( 1955 "cannot connect '%s' and '%s' due to identical role '%s'" % \ 1956 (peer, self, self.role)) 1957 1958 if self.role == 'SLAVE': 1959 # do nothing and let the master take care of it 1960 return 1961 1962 try: 1963 # self is always the master and peer the slave 1964 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1965 peer.simobj.getCCObject(), peer.name, peer.index) 1966 except: 1967 print("Error connecting port %s.%s to %s.%s" % 1968 (self.simobj.path(), self.name, 1969 peer.simobj.path(), peer.name)) 1970 raise 1971 self.ccConnected = True 1972 peer.ccConnected = True 1973 1974# A reference to an individual element of a VectorPort... much like a 1975# PortRef, but has an index. 1976class VectorPortElementRef(PortRef): 1977 def __init__(self, simobj, name, role, index): 1978 PortRef.__init__(self, simobj, name, role) 1979 self.index = index 1980 1981 def __str__(self): 1982 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1983 1984# A reference to a complete vector-valued port (not just a single element). 1985# Can be indexed to retrieve individual VectorPortElementRef instances. 1986class VectorPortRef(object): 1987 def __init__(self, simobj, name, role): 1988 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1989 self.simobj = simobj 1990 self.name = name 1991 self.role = role 1992 self.elements = [] 1993 1994 def __str__(self): 1995 return '%s.%s[:]' % (self.simobj, self.name) 1996 1997 def __len__(self): 1998 # Return the number of connected peers, corresponding the the 1999 # length of the elements. 2000 return len(self.elements) 2001 2002 # for config.ini, print peer's name (not ours) 2003 def ini_str(self): 2004 return ' '.join([el.ini_str() for el in self.elements]) 2005 2006 # for config.json 2007 def get_config_as_dict(self): 2008 return {'role' : self.role, 2009 'peer' : [el.ini_str() for el in self.elements]} 2010 2011 def __getitem__(self, key): 2012 if not isinstance(key, int): 2013 raise TypeError("VectorPort index must be integer") 2014 if key >= len(self.elements): 2015 # need to extend list 2016 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 2017 for i in range(len(self.elements), key+1)] 2018 self.elements.extend(ext) 2019 return self.elements[key] 2020 2021 def _get_next(self): 2022 return self[len(self.elements)] 2023 2024 def __setitem__(self, key, value): 2025 if not isinstance(key, int): 2026 raise TypeError("VectorPort index must be integer") 2027 self[key].connect(value) 2028 2029 def connect(self, other): 2030 if isinstance(other, (list, tuple)): 2031 # Assign list of port refs to vector port. 2032 # For now, append them... not sure if that's the right semantics 2033 # or if it should replace the current vector. 2034 for ref in other: 2035 self._get_next().connect(ref) 2036 else: 2037 # scalar assignment to plain VectorPort is implicit append 2038 self._get_next().connect(other) 2039 2040 def clone(self, simobj, memo): 2041 if self in memo: 2042 return memo[self] 2043 newRef = copy.copy(self) 2044 memo[self] = newRef 2045 newRef.simobj = simobj 2046 assert(isSimObject(newRef.simobj)) 2047 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 2048 return newRef 2049 2050 def unproxy(self, simobj): 2051 [el.unproxy(simobj) for el in self.elements] 2052 2053 def ccConnect(self): 2054 [el.ccConnect() for el in self.elements] 2055 2056# Port description object. Like a ParamDesc object, this represents a 2057# logical port in the SimObject class, not a particular port on a 2058# SimObject instance. The latter are represented by PortRef objects. 2059class Port(object): 2060 # Generate a PortRef for this port on the given SimObject with the 2061 # given name 2062 def makeRef(self, simobj): 2063 return PortRef(simobj, self.name, self.role) 2064 2065 # Connect an instance of this port (on the given SimObject with 2066 # the given name) with the port described by the supplied PortRef 2067 def connect(self, simobj, ref): 2068 self.makeRef(simobj).connect(ref) 2069 2070 # No need for any pre-declarations at the moment as we merely rely 2071 # on an unsigned int. 2072 def cxx_predecls(self, code): 2073 pass 2074 2075 def pybind_predecls(self, code): 2076 cls.cxx_predecls(self, code) 2077 2078 # Declare an unsigned int with the same name as the port, that 2079 # will eventually hold the number of connected ports (and thus the 2080 # number of elements for a VectorPort). 2081 def cxx_decl(self, code): 2082 code('unsigned int port_${{self.name}}_connection_count;') 2083 2084class MasterPort(Port): 2085 # MasterPort("description") 2086 def __init__(self, *args): 2087 if len(args) == 1: 2088 self.desc = args[0] 2089 self.role = 'MASTER' 2090 else: 2091 raise TypeError('wrong number of arguments') 2092 2093class SlavePort(Port): 2094 # SlavePort("description") 2095 def __init__(self, *args): 2096 if len(args) == 1: 2097 self.desc = args[0] 2098 self.role = 'SLAVE' 2099 else: 2100 raise TypeError('wrong number of arguments') 2101 2102# VectorPort description object. Like Port, but represents a vector 2103# of connections (e.g., as on a XBar). 2104class VectorPort(Port): 2105 def __init__(self, *args): 2106 self.isVec = True 2107 2108 def makeRef(self, simobj): 2109 return VectorPortRef(simobj, self.name, self.role) 2110 2111class VectorMasterPort(VectorPort): 2112 # VectorMasterPort("description") 2113 def __init__(self, *args): 2114 if len(args) == 1: 2115 self.desc = args[0] 2116 self.role = 'MASTER' 2117 VectorPort.__init__(self, *args) 2118 else: 2119 raise TypeError('wrong number of arguments') 2120 2121class VectorSlavePort(VectorPort): 2122 # VectorSlavePort("description") 2123 def __init__(self, *args): 2124 if len(args) == 1: 2125 self.desc = args[0] 2126 self.role = 'SLAVE' 2127 VectorPort.__init__(self, *args) 2128 else: 2129 raise TypeError('wrong number of arguments') 2130 2131# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2132# proxy objects (via set_param_desc()) so that proxy error messages 2133# make sense. 2134class PortParamDesc(object): 2135 __metaclass__ = Singleton 2136 2137 ptype_str = 'Port' 2138 ptype = Port 2139 2140baseEnums = allEnums.copy() 2141baseParams = allParams.copy() 2142 2143def clear(): 2144 global allEnums, allParams 2145 2146 allEnums = baseEnums.copy() 2147 allParams = baseParams.copy() 2148 2149__all__ = ['Param', 'VectorParam', 2150 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float', 2151 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2152 'Int32', 'UInt32', 'Int64', 'UInt64', 2153 'Counter', 'Addr', 'Tick', 'Percent', 2154 'TcpPort', 'UdpPort', 'EthernetAddr', 2155 'IpAddress', 'IpNetmask', 'IpWithPort', 2156 'MemorySize', 'MemorySize32', 2157 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy', 2158 'NetworkBandwidth', 'MemoryBandwidth', 2159 'AddrRange', 2160 'MaxAddr', 'MaxTick', 'AllMemory', 2161 'Time', 2162 'NextEthernetAddr', 'NULL', 2163 'MasterPort', 'SlavePort', 2164 'VectorMasterPort', 'VectorSlavePort'] 2165