params.py revision 14052:8e23338327aa
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017-2019 ARM Limited 27534Ssteve.reinhardt@amd.com# All rights reserved. 33101Sstever@eecs.umich.edu# 43101Sstever@eecs.umich.edu# The license below extends only to copyright in the software and shall 53101Sstever@eecs.umich.edu# not be construed as granting a license to any other intellectual 63101Sstever@eecs.umich.edu# property including but not limited to intellectual property relating 73101Sstever@eecs.umich.edu# to a hardware implementation of the functionality of the software 83101Sstever@eecs.umich.edu# licensed hereunder. You may use the software subject to the license 93101Sstever@eecs.umich.edu# terms below provided that you ensure that this notice is replicated 103101Sstever@eecs.umich.edu# unmodified and in its entirety in all distributions of the software, 113101Sstever@eecs.umich.edu# modified or unmodified, in source code or in binary form. 123101Sstever@eecs.umich.edu# 133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 143101Sstever@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 153101Sstever@eecs.umich.edu# All rights reserved. 163101Sstever@eecs.umich.edu# 173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from 263101Sstever@eecs.umich.edu# this software without specific prior written permission. 273101Sstever@eecs.umich.edu# 283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307778Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 393101Sstever@eecs.umich.edu# 403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt 413101Sstever@eecs.umich.edu# Nathan Binkert 423101Sstever@eecs.umich.edu# Gabe Black 433101Sstever@eecs.umich.edu# Andreas Hansson 443101Sstever@eecs.umich.edu 453101Sstever@eecs.umich.edu##################################################################### 463101Sstever@eecs.umich.edu# 473101Sstever@eecs.umich.edu# Parameter description classes 483101Sstever@eecs.umich.edu# 493885Sbinkertn@umich.edu# The _params dictionary in each class maps parameter names to either 503885Sbinkertn@umich.edu# a Param or a VectorParam object. These objects contain the 514762Snate@binkert.org# parameter description string, the parameter type, and the default 523885Sbinkertn@umich.edu# value (if any). The convert() method on these objects is used to 533885Sbinkertn@umich.edu# force whatever value is assigned to the parameter to the appropriate 547528Ssteve.reinhardt@amd.com# type. 553885Sbinkertn@umich.edu# 564380Sbinkertn@umich.edu# Note that the default values are loaded into the class's attribute 574167Sbinkertn@umich.edu# space when the parameter dictionary is initialized (in 583102Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used. 593101Sstever@eecs.umich.edu# 604762Snate@binkert.org##################################################################### 614762Snate@binkert.org 624762Snate@binkert.orgfrom __future__ import print_function 634762Snate@binkert.orgimport six 644762Snate@binkert.orgif six.PY3: 654762Snate@binkert.org long = int 664762Snate@binkert.org 674762Snate@binkert.orgimport copy 684762Snate@binkert.orgimport datetime 695033Smilesck@eecs.umich.eduimport re 705033Smilesck@eecs.umich.eduimport sys 715033Smilesck@eecs.umich.eduimport time 725033Smilesck@eecs.umich.eduimport math 735033Smilesck@eecs.umich.edu 745033Smilesck@eecs.umich.edufrom . import proxy 755033Smilesck@eecs.umich.edufrom . import ticks 765033Smilesck@eecs.umich.edufrom .util import * 775033Smilesck@eecs.umich.edu 785033Smilesck@eecs.umich.edudef isSimObject(*args, **kwargs): 793101Sstever@eecs.umich.edu from . import SimObject 803101Sstever@eecs.umich.edu return SimObject.isSimObject(*args, **kwargs) 813101Sstever@eecs.umich.edu 825033Smilesck@eecs.umich.edudef isSimObjectSequence(*args, **kwargs): 833101Sstever@eecs.umich.edu from . import SimObject 847673Snate@binkert.org return SimObject.isSimObjectSequence(*args, **kwargs) 857673Snate@binkert.org 867673Snate@binkert.orgdef isSimObjectClass(*args, **kwargs): 877673Snate@binkert.org from . import SimObject 887673Snate@binkert.org return SimObject.isSimObjectClass(*args, **kwargs) 897673Snate@binkert.org 907673Snate@binkert.orgallParams = {} 913101Sstever@eecs.umich.edu 923101Sstever@eecs.umich.educlass MetaParamValue(type): 933101Sstever@eecs.umich.edu def __new__(mcls, name, bases, dct): 943101Sstever@eecs.umich.edu cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 953101Sstever@eecs.umich.edu assert name not in allParams 963101Sstever@eecs.umich.edu allParams[name] = cls 973101Sstever@eecs.umich.edu return cls 983101Sstever@eecs.umich.edu 993101Sstever@eecs.umich.edu 1003101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject 1013101Sstever@eecs.umich.edu# parameters. 1023101Sstever@eecs.umich.educlass ParamValue(object): 1033101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 1046656Snate@binkert.org cmd_line_settable = False 1056656Snate@binkert.org 1063101Sstever@eecs.umich.edu # Generate the code needed as a prerequisite for declaring a C++ 1073101Sstever@eecs.umich.edu # object of this type. Typically generates one or more #include 1083101Sstever@eecs.umich.edu # statements. Used when declaring parameters of this type. 1093101Sstever@eecs.umich.edu @classmethod 1103101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 1113101Sstever@eecs.umich.edu pass 1123101Sstever@eecs.umich.edu 1133101Sstever@eecs.umich.edu @classmethod 1143101Sstever@eecs.umich.edu def pybind_predecls(cls, code): 1153101Sstever@eecs.umich.edu cls.cxx_predecls(code) 1163101Sstever@eecs.umich.edu 1173101Sstever@eecs.umich.edu # default for printing to .ini file is regular string conversion. 1183101Sstever@eecs.umich.edu # will be overridden in some cases 1193101Sstever@eecs.umich.edu def ini_str(self): 1203101Sstever@eecs.umich.edu return str(self) 1213101Sstever@eecs.umich.edu 1223101Sstever@eecs.umich.edu # default for printing to .json file is regular string conversion. 1233101Sstever@eecs.umich.edu # will be overridden in some cases, mostly to use native Python 1243101Sstever@eecs.umich.edu # types where there are similar JSON types 1253101Sstever@eecs.umich.edu def config_value(self): 1263101Sstever@eecs.umich.edu return str(self) 1273101Sstever@eecs.umich.edu 1283101Sstever@eecs.umich.edu # Prerequisites for .ini parsing with cxx_ini_parse 1293101Sstever@eecs.umich.edu @classmethod 1303101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 1313101Sstever@eecs.umich.edu pass 1323101Sstever@eecs.umich.edu 1333101Sstever@eecs.umich.edu # parse a .ini file entry for this param from string expression 1343101Sstever@eecs.umich.edu # src into lvalue dest (of the param's C++ type) 1353101Sstever@eecs.umich.edu @classmethod 1363101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 1373101Sstever@eecs.umich.edu code('// Unhandled param type: %s' % cls.__name__) 1383101Sstever@eecs.umich.edu code('%s false;' % ret) 1395033Smilesck@eecs.umich.edu 1406656Snate@binkert.org # allows us to blithely call unproxy() on things without checking 1415033Smilesck@eecs.umich.edu # if they're really proxies or not 1425033Smilesck@eecs.umich.edu def unproxy(self, base): 1435033Smilesck@eecs.umich.edu return self 1443101Sstever@eecs.umich.edu 1453101Sstever@eecs.umich.edu # Produce a human readable version of the stored value 1463101Sstever@eecs.umich.edu def pretty_print(self, value): 1473101Sstever@eecs.umich.edu return str(value) 1483101Sstever@eecs.umich.edu 1493101Sstever@eecs.umich.edu# Regular parameter description. 1503101Sstever@eecs.umich.educlass ParamDesc(object): 1513101Sstever@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 1523101Sstever@eecs.umich.edu self.ptype_str = ptype_str 1533101Sstever@eecs.umich.edu # remember ptype only if it is provided 1543101Sstever@eecs.umich.edu if ptype != None: 1553101Sstever@eecs.umich.edu self.ptype = ptype 1563101Sstever@eecs.umich.edu 1573102Sstever@eecs.umich.edu if args: 1583101Sstever@eecs.umich.edu if len(args) == 1: 1593101Sstever@eecs.umich.edu self.desc = args[0] 1603101Sstever@eecs.umich.edu elif len(args) == 2: 1617673Snate@binkert.org self.default = args[0] 1627673Snate@binkert.org self.desc = args[1] 1633101Sstever@eecs.umich.edu else: 1647673Snate@binkert.org raise TypeError('too many arguments') 1657673Snate@binkert.org 1663101Sstever@eecs.umich.edu if 'desc' in kwargs: 1677673Snate@binkert.org assert(not hasattr(self, 'desc')) 1687673Snate@binkert.org self.desc = kwargs['desc'] 1693101Sstever@eecs.umich.edu del kwargs['desc'] 1703101Sstever@eecs.umich.edu 1713101Sstever@eecs.umich.edu if 'default' in kwargs: 1723101Sstever@eecs.umich.edu assert(not hasattr(self, 'default')) 1733101Sstever@eecs.umich.edu self.default = kwargs['default'] 1743101Sstever@eecs.umich.edu del kwargs['default'] 1755033Smilesck@eecs.umich.edu 1765475Snate@binkert.org if kwargs: 1775475Snate@binkert.org raise TypeError('extra unknown kwargs %s' % kwargs) 1785475Snate@binkert.org 1795475Snate@binkert.org if not hasattr(self, 'desc'): 1803101Sstever@eecs.umich.edu raise TypeError('desc attribute missing') 1813101Sstever@eecs.umich.edu 1823101Sstever@eecs.umich.edu def __getattr__(self, attr): 1834762Snate@binkert.org if attr == 'ptype': 1844762Snate@binkert.org from . import SimObject 1854762Snate@binkert.org ptype = SimObject.allClasses[self.ptype_str] 1863101Sstever@eecs.umich.edu assert isSimObjectClass(ptype) 1873101Sstever@eecs.umich.edu self.ptype = ptype 1883101Sstever@eecs.umich.edu return ptype 1897528Ssteve.reinhardt@amd.com 1907528Ssteve.reinhardt@amd.com raise AttributeError("'%s' object has no attribute '%s'" % \ 1917528Ssteve.reinhardt@amd.com (type(self).__name__, attr)) 1927528Ssteve.reinhardt@amd.com 1937528Ssteve.reinhardt@amd.com def example_str(self): 1947528Ssteve.reinhardt@amd.com if hasattr(self.ptype, "ex_str"): 1953101Sstever@eecs.umich.edu return self.ptype.ex_str 1967528Ssteve.reinhardt@amd.com else: 1977528Ssteve.reinhardt@amd.com return self.ptype_str 1987528Ssteve.reinhardt@amd.com 1997528Ssteve.reinhardt@amd.com # Is the param available to be exposed on the command line 2007528Ssteve.reinhardt@amd.com def isCmdLineSettable(self): 2017528Ssteve.reinhardt@amd.com if hasattr(self.ptype, "cmd_line_settable"): 2027528Ssteve.reinhardt@amd.com return self.ptype.cmd_line_settable 2037528Ssteve.reinhardt@amd.com else: 2047528Ssteve.reinhardt@amd.com return False 2057528Ssteve.reinhardt@amd.com 2067528Ssteve.reinhardt@amd.com def convert(self, value): 2077528Ssteve.reinhardt@amd.com if isinstance(value, proxy.BaseProxy): 2087528Ssteve.reinhardt@amd.com value.set_param_desc(self) 2097528Ssteve.reinhardt@amd.com return value 2107528Ssteve.reinhardt@amd.com if 'ptype' not in self.__dict__ and isNullPointer(value): 2117528Ssteve.reinhardt@amd.com # deferred evaluation of SimObject; continue to defer if 2127528Ssteve.reinhardt@amd.com # we're just assigning a null pointer 2137528Ssteve.reinhardt@amd.com return value 2147528Ssteve.reinhardt@amd.com if isinstance(value, self.ptype): 2157528Ssteve.reinhardt@amd.com return value 2167528Ssteve.reinhardt@amd.com if isNullPointer(value) and isSimObjectClass(self.ptype): 2177528Ssteve.reinhardt@amd.com return value 2187528Ssteve.reinhardt@amd.com return self.ptype(value) 2197528Ssteve.reinhardt@amd.com 2207528Ssteve.reinhardt@amd.com def pretty_print(self, value): 2217528Ssteve.reinhardt@amd.com if isinstance(value, proxy.BaseProxy): 2227528Ssteve.reinhardt@amd.com return str(value) 2237528Ssteve.reinhardt@amd.com if isNullPointer(value): 2247528Ssteve.reinhardt@amd.com return NULL 2253101Sstever@eecs.umich.edu return self.ptype(value).pretty_print(value) 2263101Sstever@eecs.umich.edu 2276656Snate@binkert.org def cxx_predecls(self, code): 2286656Snate@binkert.org code('#include <cstddef>') 2293101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2303101Sstever@eecs.umich.edu 2313101Sstever@eecs.umich.edu def pybind_predecls(self, code): 2323101Sstever@eecs.umich.edu self.ptype.pybind_predecls(code) 2333101Sstever@eecs.umich.edu 2343101Sstever@eecs.umich.edu def cxx_decl(self, code): 2353101Sstever@eecs.umich.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 2364762Snate@binkert.org 2374762Snate@binkert.org# Vector-valued parameter description. Just like ParamDesc, except 2384762Snate@binkert.org# that the value is a vector (list) of the specified type instead of a 2394762Snate@binkert.org# single value. 2407528Ssteve.reinhardt@amd.com 2414762Snate@binkert.orgclass VectorParamValue(list): 2424762Snate@binkert.org __metaclass__ = MetaParamValue 2434762Snate@binkert.org def __setattr__(self, attr, value): 2447673Snate@binkert.org raise AttributeError("Not allowed to set %s on '%s'" % \ 2457677Snate@binkert.org (attr, type(self).__name__)) 2464762Snate@binkert.org 2477673Snate@binkert.org def config_value(self): 2487675Snate@binkert.org return [v.config_value() for v in self] 2497675Snate@binkert.org 2507675Snate@binkert.org def ini_str(self): 2517675Snate@binkert.org return ' '.join([v.ini_str() for v in self]) 2527675Snate@binkert.org 2537675Snate@binkert.org def getValue(self): 2547673Snate@binkert.org return [ v.getValue() for v in self ] 2557675Snate@binkert.org 2567675Snate@binkert.org def unproxy(self, base): 2577675Snate@binkert.org if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 2587675Snate@binkert.org # The value is a proxy (e.g. Parent.any, Parent.all or 2597675Snate@binkert.org # Parent.x) therefore try resolve it 2607673Snate@binkert.org return self[0].unproxy(base) 2617675Snate@binkert.org else: 2627675Snate@binkert.org return [v.unproxy(base) for v in self] 2637675Snate@binkert.org 2647675Snate@binkert.orgclass SimObjectVector(VectorParamValue): 2657675Snate@binkert.org # support clone operation 2667675Snate@binkert.org def __call__(self, **kwargs): 2677675Snate@binkert.org return SimObjectVector([v(**kwargs) for v in self]) 2687675Snate@binkert.org 2697675Snate@binkert.org def clear_parent(self, old_parent): 2707675Snate@binkert.org for v in self: 2717675Snate@binkert.org v.clear_parent(old_parent) 2727675Snate@binkert.org 2737675Snate@binkert.org def set_parent(self, parent, name): 2747675Snate@binkert.org if len(self) == 1: 2757675Snate@binkert.org self[0].set_parent(parent, name) 2767675Snate@binkert.org else: 2777673Snate@binkert.org width = int(math.ceil(math.log(len(self))/math.log(10))) 2787673Snate@binkert.org for i,v in enumerate(self): 2793101Sstever@eecs.umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2807675Snate@binkert.org 2817675Snate@binkert.org def has_parent(self): 2827673Snate@binkert.org return any([e.has_parent() for e in self if not isNullPointer(e)]) 2837673Snate@binkert.org 2847673Snate@binkert.org # return 'cpu0 cpu1' etc. for print_ini() 2853101Sstever@eecs.umich.edu def get_name(self): 2867673Snate@binkert.org return ' '.join([v._name for v in self]) 2877673Snate@binkert.org 2883101Sstever@eecs.umich.edu # By iterating through the constituent members of the vector here 2893101Sstever@eecs.umich.edu # we can nicely handle iterating over all a SimObject's children 2903101Sstever@eecs.umich.edu # without having to provide lots of special functions on 2913101Sstever@eecs.umich.edu # SimObjectVector directly. 2923101Sstever@eecs.umich.edu def descendants(self): 2933101Sstever@eecs.umich.edu for v in self: 2943101Sstever@eecs.umich.edu for obj in v.descendants(): 2953101Sstever@eecs.umich.edu yield obj 2963101Sstever@eecs.umich.edu 2973101Sstever@eecs.umich.edu def get_config_as_dict(self): 2983101Sstever@eecs.umich.edu a = [] 2993101Sstever@eecs.umich.edu for v in self: 3003101Sstever@eecs.umich.edu a.append(v.get_config_as_dict()) 3013101Sstever@eecs.umich.edu return a 3023101Sstever@eecs.umich.edu 3035033Smilesck@eecs.umich.edu # If we are replacing an item in the vector, make sure to set the 3045033Smilesck@eecs.umich.edu # parent reference of the new SimObject to be the same as the parent 3053101Sstever@eecs.umich.edu # of the SimObject being replaced. Useful to have if we created 3063101Sstever@eecs.umich.edu # a SimObjectVector of temporary objects that will be modified later in 3073101Sstever@eecs.umich.edu # configuration scripts. 3083101Sstever@eecs.umich.edu def __setitem__(self, key, value): 3093101Sstever@eecs.umich.edu val = self[key] 3103101Sstever@eecs.umich.edu if value.has_parent(): 3113101Sstever@eecs.umich.edu warn("SimObject %s already has a parent" % value.get_name() +\ 3123101Sstever@eecs.umich.edu " that is being overwritten by a SimObjectVector") 3133101Sstever@eecs.umich.edu value.set_parent(val.get_parent(), val._name) 3143101Sstever@eecs.umich.edu super(SimObjectVector, self).__setitem__(key, value) 3153101Sstever@eecs.umich.edu 3163101Sstever@eecs.umich.edu # Enumerate the params of each member of the SimObject vector. Creates 3173101Sstever@eecs.umich.edu # strings that will allow indexing into the vector by the python code and 3183101Sstever@eecs.umich.edu # allow it to be specified on the command line. 3193101Sstever@eecs.umich.edu def enumerateParams(self, flags_dict = {}, 3203101Sstever@eecs.umich.edu cmd_line_str = "", 3213101Sstever@eecs.umich.edu access_str = ""): 3223101Sstever@eecs.umich.edu if hasattr(self, "_paramEnumed"): 3233101Sstever@eecs.umich.edu print("Cycle detected enumerating params at %s?!" % (cmd_line_str)) 3243101Sstever@eecs.umich.edu else: 3253101Sstever@eecs.umich.edu x = 0 3263101Sstever@eecs.umich.edu for vals in self: 3273101Sstever@eecs.umich.edu # Each entry in the SimObjectVector should be an 3283101Sstever@eecs.umich.edu # instance of a SimObject 3293101Sstever@eecs.umich.edu flags_dict = vals.enumerateParams(flags_dict, 3307673Snate@binkert.org cmd_line_str + "%d." % x, 3317673Snate@binkert.org access_str + "[%d]." % x) 3327673Snate@binkert.org x = x + 1 3337673Snate@binkert.org 3347673Snate@binkert.org return flags_dict 3357673Snate@binkert.org 3367673Snate@binkert.orgclass VectorParamDesc(ParamDesc): 3377673Snate@binkert.org # Convert assigned value to appropriate type. If the RHS is not a 3384762Snate@binkert.org # list or tuple, it generates a single-element list. 3394762Snate@binkert.org def convert(self, value): 3404762Snate@binkert.org if isinstance(value, (list, tuple)): 3413101Sstever@eecs.umich.edu # list: coerce each element into new list 3423101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3433101Sstever@eecs.umich.edu elif isinstance(value, str): 3443101Sstever@eecs.umich.edu # If input is a csv string 3453101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3463101Sstever@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3473101Sstever@eecs.umich.edu else: 3483101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3493101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3503101Sstever@eecs.umich.edu 3513101Sstever@eecs.umich.edu if isSimObjectSequence(tmp_list): 3523714Sstever@eecs.umich.edu return SimObjectVector(tmp_list) 3533714Sstever@eecs.umich.edu else: 3543714Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3553714Sstever@eecs.umich.edu 3563714Sstever@eecs.umich.edu # Produce a human readable example string that describes 3573714Sstever@eecs.umich.edu # how to set this vector parameter in the absence of a default 3583101Sstever@eecs.umich.edu # value. 3593101Sstever@eecs.umich.edu def example_str(self): 3603101Sstever@eecs.umich.edu s = super(VectorParamDesc, self).example_str() 3613101Sstever@eecs.umich.edu help_str = "[" + s + "," + s + ", ...]" 3623101Sstever@eecs.umich.edu return help_str 3633101Sstever@eecs.umich.edu 3643101Sstever@eecs.umich.edu # Produce a human readable representation of the value of this vector param. 3653101Sstever@eecs.umich.edu def pretty_print(self, value): 3663101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3673101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 3683101Sstever@eecs.umich.edu elif isinstance(value, str): 3693101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 3703101Sstever@eecs.umich.edu else: 3713101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, value) ] 3723101Sstever@eecs.umich.edu 3733101Sstever@eecs.umich.edu return tmp_list 3743101Sstever@eecs.umich.edu 3753101Sstever@eecs.umich.edu # This is a helper function for the new config system 3763101Sstever@eecs.umich.edu def __call__(self, value): 3773101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3783101Sstever@eecs.umich.edu # list: coerce each element into new list 3793101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3803101Sstever@eecs.umich.edu elif isinstance(value, str): 3813101Sstever@eecs.umich.edu # If input is a csv string 3823101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3835033Smilesck@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3843101Sstever@eecs.umich.edu else: 3853101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3863101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3873101Sstever@eecs.umich.edu 3883101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3893101Sstever@eecs.umich.edu 3903101Sstever@eecs.umich.edu def cxx_predecls(self, code): 3913101Sstever@eecs.umich.edu code('#include <vector>') 3923101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 3933101Sstever@eecs.umich.edu 3943101Sstever@eecs.umich.edu def pybind_predecls(self, code): 3953101Sstever@eecs.umich.edu code('#include <vector>') 3965822Ssaidi@eecs.umich.edu self.ptype.pybind_predecls(code) 3975822Ssaidi@eecs.umich.edu 3983101Sstever@eecs.umich.edu def cxx_decl(self, code): 3993101Sstever@eecs.umich.edu code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 4003101Sstever@eecs.umich.edu 4013101Sstever@eecs.umich.educlass ParamFactory(object): 4023101Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 4033101Sstever@eecs.umich.edu self.param_desc_class = param_desc_class 4043101Sstever@eecs.umich.edu self.ptype_str = ptype_str 4053101Sstever@eecs.umich.edu 4063101Sstever@eecs.umich.edu def __getattr__(self, attr): 4073101Sstever@eecs.umich.edu if self.ptype_str: 4083101Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 4093101Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 4103101Sstever@eecs.umich.edu 4113101Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 4123101Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 4133101Sstever@eecs.umich.edu ptype = None 4143101Sstever@eecs.umich.edu try: 4153101Sstever@eecs.umich.edu ptype = allParams[self.ptype_str] 4163101Sstever@eecs.umich.edu except KeyError: 4173101Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 4183101Sstever@eecs.umich.edu # try to resolve it later 4193102Sstever@eecs.umich.edu pass 4203714Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 4213101Sstever@eecs.umich.edu 4223714Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc) 4233714Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc) 4243714Sstever@eecs.umich.edu 4253101Sstever@eecs.umich.edu##################################################################### 4263101Sstever@eecs.umich.edu# 4277673Snate@binkert.org# Parameter Types 4287673Snate@binkert.org# 4297673Snate@binkert.org# Though native Python types could be used to specify parameter types 4307673Snate@binkert.org# (the 'ptype' field of the Param and VectorParam classes), it's more 4317673Snate@binkert.org# flexible to define our own set of types. This gives us more control 4327673Snate@binkert.org# over how Python expressions are converted to values (via the 4337673Snate@binkert.org# __init__() constructor) and how these values are printed out (via 4347673Snate@binkert.org# the __str__() conversion method). 4357673Snate@binkert.org# 4367673Snate@binkert.org##################################################################### 4377673Snate@binkert.org 4384762Snate@binkert.org# String-valued parameter. Just mixin the ParamValue class with the 4394762Snate@binkert.org# built-in str class. 4404762Snate@binkert.orgclass String(ParamValue,str): 4413101Sstever@eecs.umich.edu cxx_type = 'std::string' 4423101Sstever@eecs.umich.edu cmd_line_settable = True 4433101Sstever@eecs.umich.edu 4443101Sstever@eecs.umich.edu @classmethod 4453101Sstever@eecs.umich.edu def cxx_predecls(self, code): 4463101Sstever@eecs.umich.edu code('#include <string>') 4473101Sstever@eecs.umich.edu 4483101Sstever@eecs.umich.edu def __call__(self, value): 4493101Sstever@eecs.umich.edu self = value 4503101Sstever@eecs.umich.edu return value 4513101Sstever@eecs.umich.edu 4523101Sstever@eecs.umich.edu @classmethod 4533101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 4543101Sstever@eecs.umich.edu code('%s = %s;' % (dest, src)) 4553101Sstever@eecs.umich.edu code('%s true;' % ret) 4563101Sstever@eecs.umich.edu 4573101Sstever@eecs.umich.edu def getValue(self): 4583101Sstever@eecs.umich.edu return self 4593101Sstever@eecs.umich.edu 4603101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math 4614446Sbinkertn@umich.edu# operations in a type-safe way. e.g., a Latency times an int returns 4623101Sstever@eecs.umich.edu# a new Latency object. 4635468Snate@binkert.orgclass NumericParamValue(ParamValue): 4645468Snate@binkert.org @staticmethod 4655468Snate@binkert.org def unwrap(v): 4665468Snate@binkert.org return v.value if isinstance(v, NumericParamValue) else v 4675468Snate@binkert.org 4685468Snate@binkert.org def __str__(self): 4695468Snate@binkert.org return str(self.value) 4704762Snate@binkert.org 4714762Snate@binkert.org def __float__(self): 4724762Snate@binkert.org return float(self.value) 4733101Sstever@eecs.umich.edu 4743101Sstever@eecs.umich.edu def __long__(self): 4753101Sstever@eecs.umich.edu return long(self.value) 4763101Sstever@eecs.umich.edu 4773101Sstever@eecs.umich.edu def __int__(self): 4783101Sstever@eecs.umich.edu return int(self.value) 4793101Sstever@eecs.umich.edu 4803101Sstever@eecs.umich.edu # hook for bounds checking 4813102Sstever@eecs.umich.edu def _check(self): 4823101Sstever@eecs.umich.edu return 4833101Sstever@eecs.umich.edu 4843101Sstever@eecs.umich.edu def __mul__(self, other): 4854168Sbinkertn@umich.edu newobj = self.__class__(self) 4863101Sstever@eecs.umich.edu newobj.value *= NumericParamValue.unwrap(other) 4873101Sstever@eecs.umich.edu newobj._check() 4883101Sstever@eecs.umich.edu return newobj 4893101Sstever@eecs.umich.edu 4903101Sstever@eecs.umich.edu __rmul__ = __mul__ 4913101Sstever@eecs.umich.edu 4923102Sstever@eecs.umich.edu def __truediv__(self, other): 4933101Sstever@eecs.umich.edu newobj = self.__class__(self) 4943101Sstever@eecs.umich.edu newobj.value /= NumericParamValue.unwrap(other) 4953101Sstever@eecs.umich.edu newobj._check() 4963101Sstever@eecs.umich.edu return newobj 4973101Sstever@eecs.umich.edu 4983101Sstever@eecs.umich.edu def __floordiv__(self, other): 4993101Sstever@eecs.umich.edu newobj = self.__class__(self) 5003101Sstever@eecs.umich.edu newobj.value //= NumericParamValue.unwrap(other) 5013101Sstever@eecs.umich.edu newobj._check() 5023101Sstever@eecs.umich.edu return newobj 5033101Sstever@eecs.umich.edu 5043102Sstever@eecs.umich.edu 5053101Sstever@eecs.umich.edu def __add__(self, other): 5063101Sstever@eecs.umich.edu newobj = self.__class__(self) 5073101Sstever@eecs.umich.edu newobj.value += NumericParamValue.unwrap(other) 5083584Ssaidi@eecs.umich.edu newobj._check() 5093584Ssaidi@eecs.umich.edu return newobj 5103584Ssaidi@eecs.umich.edu 5113584Ssaidi@eecs.umich.edu def __sub__(self, other): 5123584Ssaidi@eecs.umich.edu newobj = self.__class__(self) 5133101Sstever@eecs.umich.edu newobj.value -= NumericParamValue.unwrap(other) 5143101Sstever@eecs.umich.edu newobj._check() 5155033Smilesck@eecs.umich.edu return newobj 5163101Sstever@eecs.umich.edu 5173101Sstever@eecs.umich.edu def __iadd__(self, other): 5183101Sstever@eecs.umich.edu self.value += NumericParamValue.unwrap(other) 5193101Sstever@eecs.umich.edu self._check() 5203101Sstever@eecs.umich.edu return self 5213101Sstever@eecs.umich.edu 5223101Sstever@eecs.umich.edu def __isub__(self, other): 5233101Sstever@eecs.umich.edu self.value -= NumericParamValue.unwrap(other) 5243101Sstever@eecs.umich.edu self._check() 5253101Sstever@eecs.umich.edu return self 5263101Sstever@eecs.umich.edu 5273101Sstever@eecs.umich.edu def __imul__(self, other): 5283101Sstever@eecs.umich.edu self.value *= NumericParamValue.unwrap(other) 5293101Sstever@eecs.umich.edu self._check() 5303101Sstever@eecs.umich.edu return self 5313101Sstever@eecs.umich.edu 5323101Sstever@eecs.umich.edu def __itruediv__(self, other): 5333101Sstever@eecs.umich.edu self.value /= NumericParamValue.unwrap(other) 5343101Sstever@eecs.umich.edu self._check() 5353101Sstever@eecs.umich.edu return self 5363101Sstever@eecs.umich.edu 5373101Sstever@eecs.umich.edu def __ifloordiv__(self, other): 5383101Sstever@eecs.umich.edu self.value //= NumericParamValue.unwrap(other) 5393101Sstever@eecs.umich.edu self._check() 5403101Sstever@eecs.umich.edu return self 5413101Sstever@eecs.umich.edu 5423101Sstever@eecs.umich.edu def __lt__(self, other): 5433101Sstever@eecs.umich.edu return self.value < NumericParamValue.unwrap(other) 5443101Sstever@eecs.umich.edu 5455219Ssaidi@eecs.umich.edu # Python 2.7 pre __future__.division operators 5465219Ssaidi@eecs.umich.edu # TODO: Remove these when after "import division from __future__" 5475219Ssaidi@eecs.umich.edu __div__ = __truediv__ 5483101Sstever@eecs.umich.edu __idiv__ = __itruediv__ 5493101Sstever@eecs.umich.edu 5503101Sstever@eecs.umich.edu def config_value(self): 5513101Sstever@eecs.umich.edu return self.value 5523101Sstever@eecs.umich.edu 5533101Sstever@eecs.umich.edu @classmethod 5543101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 5553101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 5563101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 5573101Sstever@eecs.umich.edu pass 5583101Sstever@eecs.umich.edu 5593101Sstever@eecs.umich.edu # The default for parsing PODs from an .ini entry is to extract from an 5603101Sstever@eecs.umich.edu # istringstream and let overloading choose the right type according to 5613101Sstever@eecs.umich.edu # the dest type. 5623101Sstever@eecs.umich.edu @classmethod 5633101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 5647673Snate@binkert.org code('%s to_number(%s, %s);' % (ret, src, dest)) 5657673Snate@binkert.org 5667675Snate@binkert.org# Metaclass for bounds-checked integer parameters. See CheckedInt. 5677673Snate@binkert.orgclass CheckedIntType(MetaParamValue): 5687675Snate@binkert.org def __init__(cls, name, bases, dict): 5697675Snate@binkert.org super(CheckedIntType, cls).__init__(name, bases, dict) 5707675Snate@binkert.org 5717675Snate@binkert.org # CheckedInt is an abstract base class, so we actually don't 5727675Snate@binkert.org # want to do any processing on it... the rest of this code is 5737673Snate@binkert.org # just for classes that derive from CheckedInt. 5743101Sstever@eecs.umich.edu if name == 'CheckedInt': 5753101Sstever@eecs.umich.edu return 5767673Snate@binkert.org 5774762Snate@binkert.org if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 5787675Snate@binkert.org if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 5794762Snate@binkert.org panic("CheckedInt subclass %s must define either\n" \ 5804762Snate@binkert.org " 'min' and 'max' or 'size' and 'unsigned'\n", 5814762Snate@binkert.org name); 5824762Snate@binkert.org if cls.unsigned: 5834762Snate@binkert.org cls.min = 0 5843101Sstever@eecs.umich.edu cls.max = 2 ** cls.size - 1 5853101Sstever@eecs.umich.edu else: 5863101Sstever@eecs.umich.edu cls.min = -(2 ** (cls.size - 1)) 5877673Snate@binkert.org cls.max = (2 ** (cls.size - 1)) - 1 5884762Snate@binkert.org 5897675Snate@binkert.org# Abstract superclass for bounds-checked integer parameters. This 5904762Snate@binkert.org# class is subclassed to generate parameter classes with specific 5914762Snate@binkert.org# bounds. Initialization of the min and max bounds is done in the 5924762Snate@binkert.org# metaclass CheckedIntType.__init__. 5934762Snate@binkert.orgclass CheckedInt(NumericParamValue): 5944762Snate@binkert.org __metaclass__ = CheckedIntType 5953101Sstever@eecs.umich.edu cmd_line_settable = True 5963101Sstever@eecs.umich.edu 5973101Sstever@eecs.umich.edu def _check(self): 5983101Sstever@eecs.umich.edu if not self.min <= self.value <= self.max: 5993101Sstever@eecs.umich.edu raise TypeError('Integer param out of bounds %d < %d < %d' % \ 6003101Sstever@eecs.umich.edu (self.min, self.value, self.max)) 6013101Sstever@eecs.umich.edu 6023101Sstever@eecs.umich.edu def __init__(self, value): 6033102Sstever@eecs.umich.edu if isinstance(value, str): 6043101Sstever@eecs.umich.edu self.value = convert.toInteger(value) 6053101Sstever@eecs.umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 6063101Sstever@eecs.umich.edu self.value = long(value) 6074762Snate@binkert.org else: 6084762Snate@binkert.org raise TypeError("Can't convert object of type %s to CheckedInt" \ 6094762Snate@binkert.org % type(value).__name__) 6103101Sstever@eecs.umich.edu self._check() 6113101Sstever@eecs.umich.edu 6123101Sstever@eecs.umich.edu def __call__(self, value): 6133101Sstever@eecs.umich.edu self.__init__(value) 6143101Sstever@eecs.umich.edu return value 6153101Sstever@eecs.umich.edu 6163101Sstever@eecs.umich.edu def __index__(self): 6173101Sstever@eecs.umich.edu return int(self.value) 6183101Sstever@eecs.umich.edu 6193101Sstever@eecs.umich.edu @classmethod 6203101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 6213101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 6223101Sstever@eecs.umich.edu code('#include "base/types.hh"') 6233101Sstever@eecs.umich.edu 6243101Sstever@eecs.umich.edu def getValue(self): 6253101Sstever@eecs.umich.edu return long(self.value) 6263101Sstever@eecs.umich.edu 6273101Sstever@eecs.umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 6283101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 6293101Sstever@eecs.umich.edu 6304380Sbinkertn@umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 6314380Sbinkertn@umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 6324380Sbinkertn@umich.educlass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 6333101Sstever@eecs.umich.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 6344380Sbinkertn@umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 6354380Sbinkertn@umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 6364380Sbinkertn@umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 6373101Sstever@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 6383101Sstever@eecs.umich.edu 6393101Sstever@eecs.umich.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 6407673Snate@binkert.orgclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 6417673Snate@binkert.orgclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 6427673Snate@binkert.orgclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 6437673Snate@binkert.org 6447673Snate@binkert.orgclass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 6457673Snate@binkert.org 6467673Snate@binkert.orgclass Cycles(CheckedInt): 6477673Snate@binkert.org cxx_type = 'Cycles' 6487673Snate@binkert.org size = 64 6493101Sstever@eecs.umich.edu unsigned = True 6503101Sstever@eecs.umich.edu 6513101Sstever@eecs.umich.edu def getValue(self): 6523101Sstever@eecs.umich.edu from _m5.core import Cycles 6533101Sstever@eecs.umich.edu return Cycles(self.value) 6543101Sstever@eecs.umich.edu 6553101Sstever@eecs.umich.edu @classmethod 6563101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 6573101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 6583101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 6593101Sstever@eecs.umich.edu pass 6603101Sstever@eecs.umich.edu 6613101Sstever@eecs.umich.edu @classmethod 6627743Sgblack@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 6633101Sstever@eecs.umich.edu code('uint64_t _temp;') 6643101Sstever@eecs.umich.edu code('bool _ret = to_number(%s, _temp);' % src) 6653101Sstever@eecs.umich.edu code('if (_ret)') 6663101Sstever@eecs.umich.edu code(' %s = Cycles(_temp);' % dest) 6673101Sstever@eecs.umich.edu code('%s _ret;' % ret) 6683101Sstever@eecs.umich.edu 6694380Sbinkertn@umich.educlass Float(ParamValue, float): 6703101Sstever@eecs.umich.edu cxx_type = 'double' 6713101Sstever@eecs.umich.edu cmd_line_settable = True 6724762Snate@binkert.org 6737677Snate@binkert.org def __init__(self, value): 6744762Snate@binkert.org if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 6754762Snate@binkert.org self.value = float(value) 6764380Sbinkertn@umich.edu else: 6774380Sbinkertn@umich.edu raise TypeError("Can't convert object of type %s to Float" \ 6783101Sstever@eecs.umich.edu % type(value).__name__) 6797777Sgblack@eecs.umich.edu 6807777Sgblack@eecs.umich.edu def __call__(self, value): 6817777Sgblack@eecs.umich.edu self.__init__(value) 6827777Sgblack@eecs.umich.edu return value 6837777Sgblack@eecs.umich.edu 6847777Sgblack@eecs.umich.edu def getValue(self): 6857777Sgblack@eecs.umich.edu return float(self.value) 6867777Sgblack@eecs.umich.edu 6877777Sgblack@eecs.umich.edu def config_value(self): 6887777Sgblack@eecs.umich.edu return self 6897777Sgblack@eecs.umich.edu 6907777Sgblack@eecs.umich.edu @classmethod 6917777Sgblack@eecs.umich.edu def cxx_ini_predecls(cls, code): 6927777Sgblack@eecs.umich.edu code('#include <sstream>') 6937777Sgblack@eecs.umich.edu 6947777Sgblack@eecs.umich.edu @classmethod 6957777Sgblack@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 6967777Sgblack@eecs.umich.edu code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 6977777Sgblack@eecs.umich.edu 6987777Sgblack@eecs.umich.educlass MemorySize(CheckedInt): 6997777Sgblack@eecs.umich.edu cxx_type = 'uint64_t' 7007777Sgblack@eecs.umich.edu ex_str = '512MB' 7017777Sgblack@eecs.umich.edu size = 64 7027777Sgblack@eecs.umich.edu unsigned = True 7037777Sgblack@eecs.umich.edu def __init__(self, value): 7047777Sgblack@eecs.umich.edu if isinstance(value, MemorySize): 7057777Sgblack@eecs.umich.edu self.value = value.value 7067777Sgblack@eecs.umich.edu else: 7077777Sgblack@eecs.umich.edu self.value = convert.toMemorySize(value) 7087777Sgblack@eecs.umich.edu self._check() 7097777Sgblack@eecs.umich.edu 7107777Sgblack@eecs.umich.educlass MemorySize32(CheckedInt): 7117777Sgblack@eecs.umich.edu cxx_type = 'uint32_t' 7127777Sgblack@eecs.umich.edu ex_str = '512MB' 7137777Sgblack@eecs.umich.edu size = 32 7147777Sgblack@eecs.umich.edu unsigned = True 7157777Sgblack@eecs.umich.edu def __init__(self, value): 7167777Sgblack@eecs.umich.edu if isinstance(value, MemorySize): 7177777Sgblack@eecs.umich.edu self.value = value.value 7187777Sgblack@eecs.umich.edu else: 7197777Sgblack@eecs.umich.edu self.value = convert.toMemorySize(value) 7207777Sgblack@eecs.umich.edu self._check() 7217777Sgblack@eecs.umich.edu 7227777Sgblack@eecs.umich.educlass Addr(CheckedInt): 7237777Sgblack@eecs.umich.edu cxx_type = 'Addr' 7247777Sgblack@eecs.umich.edu size = 64 7257777Sgblack@eecs.umich.edu unsigned = True 7267777Sgblack@eecs.umich.edu def __init__(self, value): 7277777Sgblack@eecs.umich.edu if isinstance(value, Addr): 7287777Sgblack@eecs.umich.edu self.value = value.value 7297777Sgblack@eecs.umich.edu else: 7307777Sgblack@eecs.umich.edu try: 7317777Sgblack@eecs.umich.edu # Often addresses are referred to with sizes. Ex: A device 7327777Sgblack@eecs.umich.edu # base address is at "512MB". Use toMemorySize() to convert 7337777Sgblack@eecs.umich.edu # these into addresses. If the address is not specified with a 7347777Sgblack@eecs.umich.edu # "size", an exception will occur and numeric translation will 7357777Sgblack@eecs.umich.edu # proceed below. 7367777Sgblack@eecs.umich.edu self.value = convert.toMemorySize(value) 7377777Sgblack@eecs.umich.edu except (TypeError, ValueError): 7387777Sgblack@eecs.umich.edu # Convert number to string and use long() to do automatic 7397777Sgblack@eecs.umich.edu # base conversion (requires base=0 for auto-conversion) 7407777Sgblack@eecs.umich.edu self.value = long(str(value), base=0) 7417777Sgblack@eecs.umich.edu 7427777Sgblack@eecs.umich.edu self._check() 7437777Sgblack@eecs.umich.edu def __add__(self, other): 7447777Sgblack@eecs.umich.edu if isinstance(other, Addr): 7457777Sgblack@eecs.umich.edu return self.value + other.value 7467777Sgblack@eecs.umich.edu else: 7477777Sgblack@eecs.umich.edu return self.value + other 7487777Sgblack@eecs.umich.edu def pretty_print(self, value): 7497777Sgblack@eecs.umich.edu try: 7507777Sgblack@eecs.umich.edu val = convert.toMemorySize(value) 7517777Sgblack@eecs.umich.edu except TypeError: 7527777Sgblack@eecs.umich.edu val = long(value) 7537777Sgblack@eecs.umich.edu return "0x%x" % long(val) 7547777Sgblack@eecs.umich.edu 7557777Sgblack@eecs.umich.educlass AddrRange(ParamValue): 7567777Sgblack@eecs.umich.edu cxx_type = 'AddrRange' 7577777Sgblack@eecs.umich.edu 7587777Sgblack@eecs.umich.edu def __init__(self, *args, **kwargs): 7597777Sgblack@eecs.umich.edu # Disable interleaving and hashing by default 7607777Sgblack@eecs.umich.edu self.intlvHighBit = 0 7617777Sgblack@eecs.umich.edu self.xorHighBit = 0 7627777Sgblack@eecs.umich.edu self.intlvBits = 0 7637777Sgblack@eecs.umich.edu self.intlvMatch = 0 7647777Sgblack@eecs.umich.edu self.masks = [] 7657777Sgblack@eecs.umich.edu 7667777Sgblack@eecs.umich.edu def handle_kwargs(self, kwargs): 7677777Sgblack@eecs.umich.edu # An address range needs to have an upper limit, specified 7687777Sgblack@eecs.umich.edu # either explicitly with an end, or as an offset using the 7697777Sgblack@eecs.umich.edu # size keyword. 7707777Sgblack@eecs.umich.edu if 'end' in kwargs: 7717777Sgblack@eecs.umich.edu self.end = Addr(kwargs.pop('end')) 7727777Sgblack@eecs.umich.edu elif 'size' in kwargs: 7737777Sgblack@eecs.umich.edu self.end = self.start + Addr(kwargs.pop('size')) - 1 7747777Sgblack@eecs.umich.edu else: 7757777Sgblack@eecs.umich.edu raise TypeError("Either end or size must be specified") 7767777Sgblack@eecs.umich.edu 7777777Sgblack@eecs.umich.edu # Now on to the optional bit 7787777Sgblack@eecs.umich.edu if 'intlvMatch' in kwargs: 7797777Sgblack@eecs.umich.edu self.intlvMatch = int(kwargs.pop('intlvMatch')) 7807777Sgblack@eecs.umich.edu 7817777Sgblack@eecs.umich.edu if 'masks' in kwargs: 7827777Sgblack@eecs.umich.edu self.masks = [ long(x) for x in list(kwargs.pop('masks')) ] 7837777Sgblack@eecs.umich.edu self.intlvBits = len(self.masks) 7847777Sgblack@eecs.umich.edu else: 7857777Sgblack@eecs.umich.edu if 'intlvHighBit' in kwargs: 7867777Sgblack@eecs.umich.edu intlv_high_bit = int(kwargs.pop('intlvHighBit')) 7877777Sgblack@eecs.umich.edu if 'xorHighBit' in kwargs: 7887777Sgblack@eecs.umich.edu xor_high_bit = int(kwargs.pop('xorHighBit')) 7897777Sgblack@eecs.umich.edu if 'intlvBits' in kwargs: 7907777Sgblack@eecs.umich.edu self.intlvBits = int(kwargs.pop('intlvBits')) 7917777Sgblack@eecs.umich.edu self.masks = [0] * self.intlvBits 7927777Sgblack@eecs.umich.edu for i in range(0, self.intlvBits): 7937777Sgblack@eecs.umich.edu bit1 = intlv_high_bit - i 7947777Sgblack@eecs.umich.edu mask = 1 << bit1 7957777Sgblack@eecs.umich.edu if xor_high_bit != 0: 7967777Sgblack@eecs.umich.edu bit2 = xor_high_bit - i 7977777Sgblack@eecs.umich.edu mask |= 1 << bit2 7987777Sgblack@eecs.umich.edu self.masks[self.intlvBits - i - 1] = mask 7997777Sgblack@eecs.umich.edu 8007777Sgblack@eecs.umich.edu if len(args) == 0: 8017777Sgblack@eecs.umich.edu self.start = Addr(kwargs.pop('start')) 8027777Sgblack@eecs.umich.edu handle_kwargs(self, kwargs) 8037777Sgblack@eecs.umich.edu 8047777Sgblack@eecs.umich.edu elif len(args) == 1: 8057777Sgblack@eecs.umich.edu if kwargs: 8067777Sgblack@eecs.umich.edu self.start = Addr(args[0]) 8077777Sgblack@eecs.umich.edu handle_kwargs(self, kwargs) 8087777Sgblack@eecs.umich.edu elif isinstance(args[0], (list, tuple)): 8097777Sgblack@eecs.umich.edu self.start = Addr(args[0][0]) 8107777Sgblack@eecs.umich.edu self.end = Addr(args[0][1]) 8117777Sgblack@eecs.umich.edu else: 8127777Sgblack@eecs.umich.edu self.start = Addr(0) 8137777Sgblack@eecs.umich.edu self.end = Addr(args[0]) - 1 8147777Sgblack@eecs.umich.edu 8157777Sgblack@eecs.umich.edu elif len(args) == 2: 8167777Sgblack@eecs.umich.edu self.start = Addr(args[0]) 8177777Sgblack@eecs.umich.edu self.end = Addr(args[1]) 8187777Sgblack@eecs.umich.edu else: 8197777Sgblack@eecs.umich.edu raise TypeError("Too many arguments specified") 8207777Sgblack@eecs.umich.edu 8217777Sgblack@eecs.umich.edu if kwargs: 8227777Sgblack@eecs.umich.edu raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 8237777Sgblack@eecs.umich.edu 8247777Sgblack@eecs.umich.edu def __str__(self): 8257777Sgblack@eecs.umich.edu if len(self.masks) == 0: 8267777Sgblack@eecs.umich.edu return '%s:%s' % (self.start, self.end) 8277777Sgblack@eecs.umich.edu else: 8287777Sgblack@eecs.umich.edu return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch, 8297777Sgblack@eecs.umich.edu ':'.join(str(m) for m in self.masks)) 8307777Sgblack@eecs.umich.edu 8317777Sgblack@eecs.umich.edu def size(self): 8327777Sgblack@eecs.umich.edu # Divide the size by the size of the interleaving slice 8337777Sgblack@eecs.umich.edu return (long(self.end) - long(self.start) + 1) >> self.intlvBits 8347777Sgblack@eecs.umich.edu 8357777Sgblack@eecs.umich.edu @classmethod 8363932Sbinkertn@umich.edu def cxx_predecls(cls, code): 8373932Sbinkertn@umich.edu Addr.cxx_predecls(code) 8383932Sbinkertn@umich.edu code('#include "base/addr_range.hh"') 8393932Sbinkertn@umich.edu 8403932Sbinkertn@umich.edu @classmethod 8413932Sbinkertn@umich.edu def pybind_predecls(cls, code): 8423932Sbinkertn@umich.edu Addr.pybind_predecls(code) 8433932Sbinkertn@umich.edu code('#include "base/addr_range.hh"') 8443932Sbinkertn@umich.edu 8453932Sbinkertn@umich.edu @classmethod 8463932Sbinkertn@umich.edu def cxx_ini_predecls(cls, code): 8473932Sbinkertn@umich.edu code('#include <sstream>') 8483932Sbinkertn@umich.edu code('#include <vector>') 8493885Sbinkertn@umich.edu code('#include "base/types.hh"') 8503932Sbinkertn@umich.edu 8513932Sbinkertn@umich.edu @classmethod 8523885Sbinkertn@umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 8533932Sbinkertn@umich.edu code('bool _ret = true;') 8543932Sbinkertn@umich.edu code('uint64_t _start, _end, _intlvMatch = 0;') 8553932Sbinkertn@umich.edu code('std::vector<Addr> _masks;') 8563932Sbinkertn@umich.edu code('char _sep;') 8573932Sbinkertn@umich.edu code('std::istringstream _stream(${src});') 8583932Sbinkertn@umich.edu code('_stream >> _start;') 8593932Sbinkertn@umich.edu code('_stream.get(_sep);') 8603932Sbinkertn@umich.edu code('_ret = _sep == \':\';') 8613932Sbinkertn@umich.edu code('_stream >> _end;') 8623932Sbinkertn@umich.edu code('if (!_stream.fail() && !_stream.eof()) {') 8633932Sbinkertn@umich.edu code(' _stream.get(_sep);') 8643932Sbinkertn@umich.edu code(' _ret = ret && _sep == \':\';') 8653932Sbinkertn@umich.edu code(' _stream >> _intlvMatch;') 8663932Sbinkertn@umich.edu code(' while (!_stream.fail() && !_stream.eof()) {') 8673932Sbinkertn@umich.edu code(' _stream.get(_sep);') 8683932Sbinkertn@umich.edu code(' _ret = ret && _sep == \':\';') 8693932Sbinkertn@umich.edu code(' Addr mask;') 8703932Sbinkertn@umich.edu code(' _stream >> mask;') 8713885Sbinkertn@umich.edu code(' _masks.push_back(mask);') 8723885Sbinkertn@umich.edu code(' }') 8733885Sbinkertn@umich.edu code('}') 8743885Sbinkertn@umich.edu code('_ret = _ret && !_stream.fail() && _stream.eof();') 8754762Snate@binkert.org code('if (_ret)') 8767673Snate@binkert.org code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);') 8777673Snate@binkert.org code('${ret} _ret;') 8787673Snate@binkert.org 8797673Snate@binkert.org def getValue(self): 8807673Snate@binkert.org # Go from the Python class to the wrapped C++ class 8817673Snate@binkert.org from _m5.range import AddrRange 8827673Snate@binkert.org 8837673Snate@binkert.org return AddrRange(long(self.start), long(self.end), 8847673Snate@binkert.org self.masks, int(self.intlvMatch)) 8853885Sbinkertn@umich.edu 8863932Sbinkertn@umich.edu# Boolean parameter type. Python doesn't let you subclass bool, since 8873885Sbinkertn@umich.edu# it doesn't want to let you create multiple instances of True and 8884762Snate@binkert.org# False. Thus this is a little more complicated than String. 8897677Snate@binkert.orgclass Bool(ParamValue): 8904762Snate@binkert.org cxx_type = 'bool' 8914762Snate@binkert.org cmd_line_settable = True 8924762Snate@binkert.org 8934762Snate@binkert.org def __init__(self, value): 8944762Snate@binkert.org try: 8954762Snate@binkert.org self.value = convert.toBool(value) 8964762Snate@binkert.org except TypeError: 8974762Snate@binkert.org self.value = bool(value) 8984762Snate@binkert.org 8994762Snate@binkert.org def __call__(self, value): 9004762Snate@binkert.org self.__init__(value) 9014762Snate@binkert.org return value 9024762Snate@binkert.org 9034762Snate@binkert.org def getValue(self): 9044762Snate@binkert.org return bool(self.value) 9054762Snate@binkert.org 9064762Snate@binkert.org def __str__(self): 9074762Snate@binkert.org return str(self.value) 9084762Snate@binkert.org 9094762Snate@binkert.org # implement truth value testing for Bool parameters so that these params 9104762Snate@binkert.org # evaluate correctly during the python configuration phase 9114762Snate@binkert.org def __bool__(self): 9124762Snate@binkert.org return bool(self.value) 9134762Snate@binkert.org 9143885Sbinkertn@umich.edu # Python 2.7 uses __nonzero__ instead of __bool__ 9154762Snate@binkert.org __nonzero__ = __bool__ 9163885Sbinkertn@umich.edu 9173885Sbinkertn@umich.edu def ini_str(self): 9183932Sbinkertn@umich.edu if self.value: 9193885Sbinkertn@umich.edu return 'true' 9203101Sstever@eecs.umich.edu return 'false' 9213101Sstever@eecs.umich.edu 9223101Sstever@eecs.umich.edu def config_value(self): 9233101Sstever@eecs.umich.edu return self.value 9243101Sstever@eecs.umich.edu 9253101Sstever@eecs.umich.edu @classmethod 9263101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 9273101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 9283101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 9293101Sstever@eecs.umich.edu pass 9303101Sstever@eecs.umich.edu 9313101Sstever@eecs.umich.edu @classmethod 9323101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 9333101Sstever@eecs.umich.edu code('%s to_bool(%s, %s);' % (ret, src, dest)) 9344762Snate@binkert.org 9353101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1): 9365033Smilesck@eecs.umich.edu bytes = [ int(x, 16) for x in addr.split(':') ] 9374762Snate@binkert.org bytes[5] += val 9384762Snate@binkert.org for i in (5, 4, 3, 2, 1): 9394762Snate@binkert.org val,rem = divmod(bytes[i], 256) 9404762Snate@binkert.org bytes[i] = rem 9414762Snate@binkert.org if val == 0: 9424762Snate@binkert.org break 9434762Snate@binkert.org bytes[i - 1] += val 9443101Sstever@eecs.umich.edu assert(bytes[0] <= 255) 9453101Sstever@eecs.umich.edu return ':'.join(map(lambda x: '%02x' % x, bytes)) 9463101Sstever@eecs.umich.edu 9473101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01" 9483101Sstever@eecs.umich.edudef NextEthernetAddr(): 9493101Sstever@eecs.umich.edu global _NextEthernetAddr 9503101Sstever@eecs.umich.edu 9513101Sstever@eecs.umich.edu value = _NextEthernetAddr 9523101Sstever@eecs.umich.edu _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 9533101Sstever@eecs.umich.edu return value 9543101Sstever@eecs.umich.edu 9553101Sstever@eecs.umich.educlass EthernetAddr(ParamValue): 9563101Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 9573101Sstever@eecs.umich.edu ex_str = "00:90:00:00:00:01" 9583101Sstever@eecs.umich.edu cmd_line_settable = True 9593101Sstever@eecs.umich.edu 9603101Sstever@eecs.umich.edu @classmethod 9613101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 9623101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 9633101Sstever@eecs.umich.edu 9644762Snate@binkert.org def __init__(self, value): 9653101Sstever@eecs.umich.edu if value == NextEthernetAddr: 9663101Sstever@eecs.umich.edu self.value = value 9673101Sstever@eecs.umich.edu return 9683101Sstever@eecs.umich.edu 9693101Sstever@eecs.umich.edu if not isinstance(value, str): 9703101Sstever@eecs.umich.edu raise TypeError("expected an ethernet address and didn't get one") 9717673Snate@binkert.org 9726654Snate@binkert.org bytes = value.split(':') 9737673Snate@binkert.org if len(bytes) != 6: 9747673Snate@binkert.org raise TypeError('invalid ethernet address %s' % value) 9757673Snate@binkert.org 9767673Snate@binkert.org for byte in bytes: 9777673Snate@binkert.org if not 0 <= int(byte, base=16) <= 0xff: 9787673Snate@binkert.org raise TypeError('invalid ethernet address %s' % value) 9797673Snate@binkert.org 9807673Snate@binkert.org self.value = value 9814762Snate@binkert.org 9827673Snate@binkert.org def __call__(self, value): 9837673Snate@binkert.org self.__init__(value) 9847673Snate@binkert.org return value 9857673Snate@binkert.org 9867673Snate@binkert.org def unproxy(self, base): 9877673Snate@binkert.org if self.value == NextEthernetAddr: 9887673Snate@binkert.org return EthernetAddr(self.value()) 9894762Snate@binkert.org return self 9907673Snate@binkert.org 9917673Snate@binkert.org def getValue(self): 9927673Snate@binkert.org from _m5.net import EthAddr 9937673Snate@binkert.org return EthAddr(self.value) 9946654Snate@binkert.org 9957673Snate@binkert.org def __str__(self): 9967677Snate@binkert.org return self.value 9977673Snate@binkert.org 9987673Snate@binkert.org def ini_str(self): 9997673Snate@binkert.org return self.value 10007673Snate@binkert.org 10017673Snate@binkert.org @classmethod 10024762Snate@binkert.org def cxx_ini_parse(self, code, src, dest, ret): 10037673Snate@binkert.org code('%s = Net::EthAddr(%s);' % (dest, src)) 10047673Snate@binkert.org code('%s true;' % ret) 10057673Snate@binkert.org 10067673Snate@binkert.org# When initializing an IpAddress, pass in an existing IpAddress, a string of 10077673Snate@binkert.org# the form "a.b.c.d", or an integer representing an IP. 10087673Snate@binkert.orgclass IpAddress(ParamValue): 10093101Sstever@eecs.umich.edu cxx_type = 'Net::IpAddress' 10103101Sstever@eecs.umich.edu ex_str = "127.0.0.1" 10113101Sstever@eecs.umich.edu cmd_line_settable = True 10123101Sstever@eecs.umich.edu 10133101Sstever@eecs.umich.edu @classmethod 10143101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 10153101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 10163101Sstever@eecs.umich.edu 10173101Sstever@eecs.umich.edu def __init__(self, value): 10183101Sstever@eecs.umich.edu if isinstance(value, IpAddress): 10193101Sstever@eecs.umich.edu self.ip = value.ip 10203101Sstever@eecs.umich.edu else: 10217675Snate@binkert.org try: 10227675Snate@binkert.org self.ip = convert.toIpAddress(value) 10237675Snate@binkert.org except TypeError: 10247675Snate@binkert.org self.ip = long(value) 10257675Snate@binkert.org self.verifyIp() 10267675Snate@binkert.org 10277677Snate@binkert.org def __call__(self, value): 10287675Snate@binkert.org self.__init__(value) 10294762Snate@binkert.org return value 10304762Snate@binkert.org 10314762Snate@binkert.org def __str__(self): 10323101Sstever@eecs.umich.edu tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 10333101Sstever@eecs.umich.edu return '%d.%d.%d.%d' % tuple(tup) 10343101Sstever@eecs.umich.edu 10353101Sstever@eecs.umich.edu def __eq__(self, other): 10363101Sstever@eecs.umich.edu if isinstance(other, IpAddress): 10373101Sstever@eecs.umich.edu return self.ip == other.ip 10384167Sbinkertn@umich.edu elif isinstance(other, str): 10393101Sstever@eecs.umich.edu try: 10407673Snate@binkert.org return self.ip == convert.toIpAddress(other) 10417673Snate@binkert.org except: 10427673Snate@binkert.org return False 10437673Snate@binkert.org else: 10447673Snate@binkert.org return self.ip == other 10457673Snate@binkert.org 10467673Snate@binkert.org def __ne__(self, other): 10477673Snate@binkert.org return not (self == other) 10487673Snate@binkert.org 10494167Sbinkertn@umich.edu def verifyIp(self): 10504762Snate@binkert.org if self.ip < 0 or self.ip >= (1 << 32): 10514762Snate@binkert.org raise TypeError("invalid ip address %#08x" % self.ip) 10524762Snate@binkert.org 10534167Sbinkertn@umich.edu def getValue(self): 10543101Sstever@eecs.umich.edu from _m5.net import IpAddress 10554167Sbinkertn@umich.edu return IpAddress(self.ip) 10564167Sbinkertn@umich.edu 10574167Sbinkertn@umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 10584167Sbinkertn@umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 10594167Sbinkertn@umich.edu# positional or keyword arguments. 10604167Sbinkertn@umich.educlass IpNetmask(IpAddress): 10614167Sbinkertn@umich.edu cxx_type = 'Net::IpNetmask' 10624167Sbinkertn@umich.edu ex_str = "127.0.0.0/24" 10634167Sbinkertn@umich.edu cmd_line_settable = True 10644167Sbinkertn@umich.edu 10654167Sbinkertn@umich.edu @classmethod 10664167Sbinkertn@umich.edu def cxx_predecls(cls, code): 10673101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 10683101Sstever@eecs.umich.edu 10693101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 10703101Sstever@eecs.umich.edu def handle_kwarg(self, kwargs, key, elseVal = None): 10713101Sstever@eecs.umich.edu if key in kwargs: 10723101Sstever@eecs.umich.edu setattr(self, key, kwargs.pop(key)) 10733101Sstever@eecs.umich.edu elif elseVal: 10743101Sstever@eecs.umich.edu setattr(self, key, elseVal) 10754762Snate@binkert.org else: 10764762Snate@binkert.org raise TypeError("No value set for %s" % key) 10774762Snate@binkert.org 10784762Snate@binkert.org if len(args) == 0: 10794762Snate@binkert.org handle_kwarg(self, kwargs, 'ip') 10804762Snate@binkert.org handle_kwarg(self, kwargs, 'netmask') 10814762Snate@binkert.org 10823101Sstever@eecs.umich.edu elif len(args) == 1: 10833101Sstever@eecs.umich.edu if kwargs: 10844762Snate@binkert.org if not 'ip' in kwargs and not 'netmask' in kwargs: 10853101Sstever@eecs.umich.edu raise TypeError("Invalid arguments") 10864167Sbinkertn@umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 10873101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'netmask', args[0]) 10884167Sbinkertn@umich.edu elif isinstance(args[0], IpNetmask): 10894167Sbinkertn@umich.edu self.ip = args[0].ip 10904167Sbinkertn@umich.edu self.netmask = args[0].netmask 10914167Sbinkertn@umich.edu else: 10924167Sbinkertn@umich.edu (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 10934167Sbinkertn@umich.edu 10944167Sbinkertn@umich.edu elif len(args) == 2: 10954167Sbinkertn@umich.edu self.ip = args[0] 10964167Sbinkertn@umich.edu self.netmask = args[1] 10974167Sbinkertn@umich.edu else: 10984167Sbinkertn@umich.edu raise TypeError("Too many arguments specified") 10994167Sbinkertn@umich.edu 11003101Sstever@eecs.umich.edu if kwargs: 11013101Sstever@eecs.umich.edu raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 11023101Sstever@eecs.umich.edu 11033101Sstever@eecs.umich.edu self.verify() 11043101Sstever@eecs.umich.edu 11053101Sstever@eecs.umich.edu def __call__(self, value): 11063101Sstever@eecs.umich.edu self.__init__(value) 11073101Sstever@eecs.umich.edu return value 11084167Sbinkertn@umich.edu 11094762Snate@binkert.org def __str__(self): 11104762Snate@binkert.org return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 11114762Snate@binkert.org 11124762Snate@binkert.org def __eq__(self, other): 11134762Snate@binkert.org if isinstance(other, IpNetmask): 11144762Snate@binkert.org return self.ip == other.ip and self.netmask == other.netmask 11154762Snate@binkert.org elif isinstance(other, str): 11163101Sstever@eecs.umich.edu try: 11174762Snate@binkert.org return (self.ip, self.netmask) == convert.toIpNetmask(other) 11183101Sstever@eecs.umich.edu except: 11193101Sstever@eecs.umich.edu return False 11203101Sstever@eecs.umich.edu else: 11213101Sstever@eecs.umich.edu return False 11223101Sstever@eecs.umich.edu 11233101Sstever@eecs.umich.edu def verify(self): 11247673Snate@binkert.org self.verifyIp() 11257673Snate@binkert.org if self.netmask < 0 or self.netmask > 32: 11267673Snate@binkert.org raise TypeError("invalid netmask %d" % netmask) 11277673Snate@binkert.org 11287673Snate@binkert.org def getValue(self): 11297673Snate@binkert.org from _m5.net import IpNetmask 11307673Snate@binkert.org return IpNetmask(self.ip, self.netmask) 11317673Snate@binkert.org 11327673Snate@binkert.org# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 11337673Snate@binkert.org# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 11343101Sstever@eecs.umich.educlass IpWithPort(IpAddress): 11354167Sbinkertn@umich.edu cxx_type = 'Net::IpWithPort' 11364167Sbinkertn@umich.edu ex_str = "127.0.0.1:80" 11374167Sbinkertn@umich.edu cmd_line_settable = True 11384167Sbinkertn@umich.edu 11394167Sbinkertn@umich.edu @classmethod 11404167Sbinkertn@umich.edu def cxx_predecls(cls, code): 11414167Sbinkertn@umich.edu code('#include "base/inet.hh"') 11424167Sbinkertn@umich.edu 11434167Sbinkertn@umich.edu def __init__(self, *args, **kwargs): 11444167Sbinkertn@umich.edu def handle_kwarg(self, kwargs, key, elseVal = None): 11454167Sbinkertn@umich.edu if key in kwargs: 11464167Sbinkertn@umich.edu setattr(self, key, kwargs.pop(key)) 11473101Sstever@eecs.umich.edu elif elseVal: 11483101Sstever@eecs.umich.edu setattr(self, key, elseVal) 11493101Sstever@eecs.umich.edu else: 11503101Sstever@eecs.umich.edu raise TypeError("No value set for %s" % key) 11513101Sstever@eecs.umich.edu 11523101Sstever@eecs.umich.edu if len(args) == 0: 11533101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip') 11543101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'port') 11554762Snate@binkert.org 11564762Snate@binkert.org elif len(args) == 1: 11574762Snate@binkert.org if kwargs: 11583101Sstever@eecs.umich.edu if not 'ip' in kwargs and not 'port' in kwargs: 11593101Sstever@eecs.umich.edu raise TypeError("Invalid arguments") 11603101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 11613101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'port', args[0]) 11623101Sstever@eecs.umich.edu elif isinstance(args[0], IpWithPort): 11633101Sstever@eecs.umich.edu self.ip = args[0].ip 11644167Sbinkertn@umich.edu self.port = args[0].port 11654167Sbinkertn@umich.edu else: 11663101Sstever@eecs.umich.edu (self.ip, self.port) = convert.toIpWithPort(args[0]) 11673101Sstever@eecs.umich.edu 11683101Sstever@eecs.umich.edu elif len(args) == 2: 11693101Sstever@eecs.umich.edu self.ip = args[0] 11703101Sstever@eecs.umich.edu self.port = args[1] 11714762Snate@binkert.org else: 11724167Sbinkertn@umich.edu raise TypeError("Too many arguments specified") 11734167Sbinkertn@umich.edu 11744167Sbinkertn@umich.edu if kwargs: 11754762Snate@binkert.org raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 11764762Snate@binkert.org 11774762Snate@binkert.org self.verify() 11784762Snate@binkert.org 11794762Snate@binkert.org def __call__(self, value): 11803101Sstever@eecs.umich.edu self.__init__(value) 11813101Sstever@eecs.umich.edu return value 11823101Sstever@eecs.umich.edu 11835469Snate@binkert.org def __str__(self): 11847743Sgblack@eecs.umich.edu return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 11853102Sstever@eecs.umich.edu 11863101Sstever@eecs.umich.edu def __eq__(self, other): 11873101Sstever@eecs.umich.edu if isinstance(other, IpWithPort): 11883101Sstever@eecs.umich.edu return self.ip == other.ip and self.port == other.port 11893101Sstever@eecs.umich.edu elif isinstance(other, str): 11903101Sstever@eecs.umich.edu try: 11914762Snate@binkert.org return (self.ip, self.port) == convert.toIpWithPort(other) 11924167Sbinkertn@umich.edu except: 11935468Snate@binkert.org return False 11945468Snate@binkert.org else: 11955468Snate@binkert.org return False 11964167Sbinkertn@umich.edu 11974762Snate@binkert.org def verify(self): 11984762Snate@binkert.org self.verifyIp() 11994762Snate@binkert.org if self.port < 0 or self.port > 0xffff: 12004762Snate@binkert.org raise TypeError("invalid port %d" % self.port) 12014762Snate@binkert.org 12023101Sstever@eecs.umich.edu def getValue(self): 12033101Sstever@eecs.umich.edu from _m5.net import IpWithPort 12043101Sstever@eecs.umich.edu return IpWithPort(self.ip, self.port) 12053101Sstever@eecs.umich.edu 12063101Sstever@eecs.umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y", 12073102Sstever@eecs.umich.edu "%a %b %d %H:%M:%S %Y", 12083102Sstever@eecs.umich.edu "%Y/%m/%d %H:%M:%S", 12093102Sstever@eecs.umich.edu "%Y/%m/%d %H:%M", 12103102Sstever@eecs.umich.edu "%Y/%m/%d", 12113102Sstever@eecs.umich.edu "%m/%d/%Y %H:%M:%S", 12123102Sstever@eecs.umich.edu "%m/%d/%Y %H:%M", 12133102Sstever@eecs.umich.edu "%m/%d/%Y", 12143102Sstever@eecs.umich.edu "%m/%d/%y %H:%M:%S", 12153102Sstever@eecs.umich.edu "%m/%d/%y %H:%M", 12163102Sstever@eecs.umich.edu "%m/%d/%y"] 12173102Sstever@eecs.umich.edu 12183102Sstever@eecs.umich.edu 12193102Sstever@eecs.umich.edudef parse_time(value): 12203102Sstever@eecs.umich.edu from time import gmtime, strptime, struct_time, time 12213102Sstever@eecs.umich.edu from datetime import datetime, date 12223102Sstever@eecs.umich.edu 12233102Sstever@eecs.umich.edu if isinstance(value, struct_time): 12243102Sstever@eecs.umich.edu return value 12253102Sstever@eecs.umich.edu 12263102Sstever@eecs.umich.edu if isinstance(value, (int, long)): 12273102Sstever@eecs.umich.edu return gmtime(value) 12284762Snate@binkert.org 12293102Sstever@eecs.umich.edu if isinstance(value, (datetime, date)): 12303102Sstever@eecs.umich.edu return value.timetuple() 12313102Sstever@eecs.umich.edu 12324762Snate@binkert.org if isinstance(value, str): 12334762Snate@binkert.org if value in ('Now', 'Today'): 12344762Snate@binkert.org return time.gmtime(time.time()) 12353102Sstever@eecs.umich.edu 12363102Sstever@eecs.umich.edu for format in time_formats: 12373102Sstever@eecs.umich.edu try: 12383102Sstever@eecs.umich.edu return strptime(value, format) 12393102Sstever@eecs.umich.edu except ValueError: 12403102Sstever@eecs.umich.edu pass 12413101Sstever@eecs.umich.edu 12423101Sstever@eecs.umich.edu raise ValueError("Could not parse '%s' as a time" % value) 12433101Sstever@eecs.umich.edu 12443101Sstever@eecs.umich.educlass Time(ParamValue): 12453101Sstever@eecs.umich.edu cxx_type = 'tm' 12463101Sstever@eecs.umich.edu 12473101Sstever@eecs.umich.edu @classmethod 12483101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 12493101Sstever@eecs.umich.edu code('#include <time.h>') 12503101Sstever@eecs.umich.edu 12513101Sstever@eecs.umich.edu def __init__(self, value): 12523101Sstever@eecs.umich.edu self.value = parse_time(value) 12533101Sstever@eecs.umich.edu 12543101Sstever@eecs.umich.edu def __call__(self, value): 12553101Sstever@eecs.umich.edu self.__init__(value) 12563101Sstever@eecs.umich.edu return value 12573101Sstever@eecs.umich.edu 12583105Sstever@eecs.umich.edu def getValue(self): 12593105Sstever@eecs.umich.edu from _m5.core import tm 12603101Sstever@eecs.umich.edu import calendar 12613101Sstever@eecs.umich.edu 12623101Sstever@eecs.umich.edu return tm.gmtime(calendar.timegm(self.value)) 12633101Sstever@eecs.umich.edu 12643105Sstever@eecs.umich.edu def __str__(self): 12653101Sstever@eecs.umich.edu return time.asctime(self.value) 12663103Sstever@eecs.umich.edu 12673105Sstever@eecs.umich.edu def ini_str(self): 12683103Sstever@eecs.umich.edu return str(self) 12693105Sstever@eecs.umich.edu 12703105Sstever@eecs.umich.edu def get_config_as_dict(self): 12713105Sstever@eecs.umich.edu assert false 12723105Sstever@eecs.umich.edu return str(self) 12733105Sstever@eecs.umich.edu 12743105Sstever@eecs.umich.edu @classmethod 12753105Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 12763105Sstever@eecs.umich.edu code('#include <time.h>') 12773105Sstever@eecs.umich.edu 12783105Sstever@eecs.umich.edu @classmethod 12793105Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 12803105Sstever@eecs.umich.edu code('char *_parse_ret = strptime((${src}).c_str(),') 12813105Sstever@eecs.umich.edu code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 12823109Sstever@eecs.umich.edu code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 12833105Sstever@eecs.umich.edu 12843105Sstever@eecs.umich.edu# Enumerated types are a little more complex. The user specifies the 12853105Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of 12863105Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so). (In the 12873105Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index 12883105Sstever@eecs.umich.edu# or the corresponding dictionary value. For now, since we only check 12893105Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file, 12903105Sstever@eecs.umich.edu# there's not much point in using the dictionary.) 12915578SSteve.Reinhardt@amd.com 12923101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the 12933109Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter 12943109Sstever@eecs.umich.edu# can be instances of that type. We define two hidden internal 12953109Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then 12963109Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly. 12973109Sstever@eecs.umich.edu 12983109Sstever@eecs.umich.eduallEnums = {} 12993109Sstever@eecs.umich.edu# Metaclass for Enum types 13003109Sstever@eecs.umich.educlass MetaEnum(MetaParamValue): 13013109Sstever@eecs.umich.edu def __new__(mcls, name, bases, dict): 13023101Sstever@eecs.umich.edu assert name not in allEnums 13033105Sstever@eecs.umich.edu 13043105Sstever@eecs.umich.edu cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 13053105Sstever@eecs.umich.edu allEnums[name] = cls 13063101Sstever@eecs.umich.edu return cls 13073105Sstever@eecs.umich.edu 13083105Sstever@eecs.umich.edu def __init__(cls, name, bases, init_dict): 13093101Sstever@eecs.umich.edu if 'map' in init_dict: 13103105Sstever@eecs.umich.edu if not isinstance(cls.map, dict): 13113179Sstever@eecs.umich.edu raise TypeError("Enum-derived class attribute 'map' " \ 13123105Sstever@eecs.umich.edu "must be of type dict") 13133105Sstever@eecs.umich.edu # build list of value strings from map 13143101Sstever@eecs.umich.edu cls.vals = list(cls.map.keys()) 13153101Sstever@eecs.umich.edu cls.vals.sort() 13163105Sstever@eecs.umich.edu elif 'vals' in init_dict: 13173105Sstever@eecs.umich.edu if not isinstance(cls.vals, list): 13183105Sstever@eecs.umich.edu raise TypeError("Enum-derived class attribute 'vals' " \ 13193105Sstever@eecs.umich.edu "must be of type list") 13203105Sstever@eecs.umich.edu # build string->value map from vals sequence 13213105Sstever@eecs.umich.edu cls.map = {} 13223105Sstever@eecs.umich.edu for idx,val in enumerate(cls.vals): 13233105Sstever@eecs.umich.edu cls.map[val] = idx 13243105Sstever@eecs.umich.edu else: 13253105Sstever@eecs.umich.edu raise TypeError("Enum-derived class must define "\ 13263105Sstever@eecs.umich.edu "attribute 'map' or 'vals'") 13273101Sstever@eecs.umich.edu 13283101Sstever@eecs.umich.edu if cls.is_class: 13297677Snate@binkert.org cls.cxx_type = '%s' % name 13304762Snate@binkert.org else: 13313101Sstever@eecs.umich.edu cls.cxx_type = 'Enums::%s' % name 13323101Sstever@eecs.umich.edu 13333101Sstever@eecs.umich.edu super(MetaEnum, cls).__init__(name, bases, init_dict) 13345578SSteve.Reinhardt@amd.com 13355578SSteve.Reinhardt@amd.com # Generate C++ class declaration for this enum type. 13367526Ssteve.reinhardt@amd.com # Note that we wrap the enum in a class/struct to act as a namespace, 13377526Ssteve.reinhardt@amd.com # so that the enum strings can be brief w/o worrying about collisions. 13387526Ssteve.reinhardt@amd.com def cxx_decl(cls, code): 13397526Ssteve.reinhardt@amd.com wrapper_name = cls.wrapper_name 13407526Ssteve.reinhardt@amd.com wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 13417526Ssteve.reinhardt@amd.com name = cls.__name__ if cls.enum_name is None else cls.enum_name 13427526Ssteve.reinhardt@amd.com idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 13437526Ssteve.reinhardt@amd.com 13443101Sstever@eecs.umich.edu code('''\ 13453101Sstever@eecs.umich.edu#ifndef $idem_macro 13463101Sstever@eecs.umich.edu#define $idem_macro 13473105Sstever@eecs.umich.edu 13483105Sstever@eecs.umich.edu''') 13493105Sstever@eecs.umich.edu if cls.is_class: 13503105Sstever@eecs.umich.edu code('''\ 13513105Sstever@eecs.umich.eduenum class $name { 13523105Sstever@eecs.umich.edu''') 13533105Sstever@eecs.umich.edu else: 13543105Sstever@eecs.umich.edu code('''\ 13553105Sstever@eecs.umich.edu$wrapper $wrapper_name { 13563105Sstever@eecs.umich.edu enum $name { 13573105Sstever@eecs.umich.edu''') 13583105Sstever@eecs.umich.edu code.indent(1) 13593105Sstever@eecs.umich.edu code.indent(1) 13603105Sstever@eecs.umich.edu for val in cls.vals: 13613105Sstever@eecs.umich.edu code('$val = ${{cls.map[val]}},') 13623105Sstever@eecs.umich.edu code('Num_$name = ${{len(cls.vals)}}') 13633105Sstever@eecs.umich.edu code.dedent(1) 13643105Sstever@eecs.umich.edu code('};') 13653105Sstever@eecs.umich.edu 13663109Sstever@eecs.umich.edu if cls.is_class: 13673109Sstever@eecs.umich.edu code('''\ 13683109Sstever@eecs.umich.eduextern const char *${name}Strings[static_cast<int>(${name}::Num_${name})]; 13693105Sstever@eecs.umich.edu''') 13703105Sstever@eecs.umich.edu elif cls.wrapper_is_struct: 13713105Sstever@eecs.umich.edu code('static const char *${name}Strings[Num_${name}];') 13723105Sstever@eecs.umich.edu else: 13733105Sstever@eecs.umich.edu code('extern const char *${name}Strings[Num_${name}];') 13743105Sstever@eecs.umich.edu 13753105Sstever@eecs.umich.edu if not cls.is_class: 13763105Sstever@eecs.umich.edu code.dedent(1) 13773105Sstever@eecs.umich.edu code('};') 13783105Sstever@eecs.umich.edu 13793105Sstever@eecs.umich.edu code() 13803105Sstever@eecs.umich.edu code('#endif // $idem_macro') 13813105Sstever@eecs.umich.edu 13823105Sstever@eecs.umich.edu def cxx_def(cls, code): 13833105Sstever@eecs.umich.edu wrapper_name = cls.wrapper_name 13843105Sstever@eecs.umich.edu file_name = cls.__name__ 13853105Sstever@eecs.umich.edu name = cls.__name__ if cls.enum_name is None else cls.enum_name 13863105Sstever@eecs.umich.edu 13873105Sstever@eecs.umich.edu code('#include "enums/$file_name.hh"') 13883105Sstever@eecs.umich.edu if cls.wrapper_is_struct: 13893105Sstever@eecs.umich.edu code('const char *${wrapper_name}::${name}Strings' 13903105Sstever@eecs.umich.edu '[Num_${name}] =') 13913105Sstever@eecs.umich.edu else: 13923109Sstever@eecs.umich.edu if cls.is_class: 13933109Sstever@eecs.umich.edu code('''\ 13943109Sstever@eecs.umich.educonst char *${name}Strings[static_cast<int>(${name}::Num_${name})] = 13953109Sstever@eecs.umich.edu''') 13963109Sstever@eecs.umich.edu else: 13973109Sstever@eecs.umich.edu code('namespace Enums {') 13983109Sstever@eecs.umich.edu code.indent(1) 13993109Sstever@eecs.umich.edu code('const char *${name}Strings[Num_${name}] =') 14003109Sstever@eecs.umich.edu 14013109Sstever@eecs.umich.edu code('{') 14023109Sstever@eecs.umich.edu code.indent(1) 14033109Sstever@eecs.umich.edu for val in cls.vals: 14043109Sstever@eecs.umich.edu code('"$val",') 14053109Sstever@eecs.umich.edu code.dedent(1) 14063109Sstever@eecs.umich.edu code('};') 14073109Sstever@eecs.umich.edu 14083109Sstever@eecs.umich.edu if not cls.wrapper_is_struct and not cls.is_class: 14093109Sstever@eecs.umich.edu code.dedent(1) 14103109Sstever@eecs.umich.edu code('} // namespace $wrapper_name') 14113105Sstever@eecs.umich.edu 14123105Sstever@eecs.umich.edu 14133105Sstever@eecs.umich.edu def pybind_def(cls, code): 14143105Sstever@eecs.umich.edu name = cls.__name__ 14153105Sstever@eecs.umich.edu enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 14163105Sstever@eecs.umich.edu wrapper_name = enum_name if cls.is_class else cls.wrapper_name 14173105Sstever@eecs.umich.edu 14183101Sstever@eecs.umich.edu code('''#include "pybind11/pybind11.h" 14193101Sstever@eecs.umich.edu#include "pybind11/stl.h" 14203101Sstever@eecs.umich.edu 14213101Sstever@eecs.umich.edu#include <sim/init.hh> 14223105Sstever@eecs.umich.edu 14233105Sstever@eecs.umich.edunamespace py = pybind11; 14243105Sstever@eecs.umich.edu 14253105Sstever@eecs.umich.edustatic void 14263105Sstever@eecs.umich.edumodule_init(py::module &m_internal) 14273105Sstever@eecs.umich.edu{ 14283105Sstever@eecs.umich.edu py::module m = m_internal.def_submodule("enum_${name}"); 14293105Sstever@eecs.umich.edu 14303105Sstever@eecs.umich.edu''') 14313105Sstever@eecs.umich.edu if cls.is_class: 14323105Sstever@eecs.umich.edu code('py::enum_<${enum_name}>(m, "enum_${name}")') 14333101Sstever@eecs.umich.edu else: 14343101Sstever@eecs.umich.edu code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")') 14353101Sstever@eecs.umich.edu 14363105Sstever@eecs.umich.edu code.indent() 14373105Sstever@eecs.umich.edu code.indent() 14383101Sstever@eecs.umich.edu for val in cls.vals: 14393101Sstever@eecs.umich.edu code('.value("${val}", ${wrapper_name}::${val})') 14403101Sstever@eecs.umich.edu code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 14413105Sstever@eecs.umich.edu code('.export_values()') 14423105Sstever@eecs.umich.edu code(';') 14433101Sstever@eecs.umich.edu code.dedent() 14443101Sstever@eecs.umich.edu 14453101Sstever@eecs.umich.edu code('}') 14463101Sstever@eecs.umich.edu code.dedent() 14473105Sstever@eecs.umich.edu code() 14483105Sstever@eecs.umich.edu code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 14493101Sstever@eecs.umich.edu 14503101Sstever@eecs.umich.edu 14513105Sstever@eecs.umich.edu# Base class for enum types. 14523105Sstever@eecs.umich.educlass Enum(ParamValue): 14533105Sstever@eecs.umich.edu __metaclass__ = MetaEnum 14543109Sstever@eecs.umich.edu vals = [] 14553109Sstever@eecs.umich.edu cmd_line_settable = True 14563109Sstever@eecs.umich.edu 14573109Sstever@eecs.umich.edu # The name of the wrapping namespace or struct 14583109Sstever@eecs.umich.edu wrapper_name = 'Enums' 14593109Sstever@eecs.umich.edu 14603109Sstever@eecs.umich.edu # If true, the enum is wrapped in a struct rather than a namespace 14613109Sstever@eecs.umich.edu wrapper_is_struct = False 14623105Sstever@eecs.umich.edu 14636654Snate@binkert.org is_class = False 14646654Snate@binkert.org 14656654Snate@binkert.org # If not None, use this as the enum name rather than this class name 14666654Snate@binkert.org enum_name = None 14676654Snate@binkert.org 14686654Snate@binkert.org def __init__(self, value): 14696654Snate@binkert.org if value not in self.map: 14706654Snate@binkert.org raise TypeError("Enum param got bad value '%s' (not in %s)" \ 14716654Snate@binkert.org % (value, self.vals)) 14723101Sstever@eecs.umich.edu self.value = value 14733101Sstever@eecs.umich.edu 14743101Sstever@eecs.umich.edu def __call__(self, value): 14753101Sstever@eecs.umich.edu self.__init__(value) 14763101Sstever@eecs.umich.edu return value 14773101Sstever@eecs.umich.edu 14787777Sgblack@eecs.umich.edu @classmethod 14793101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 14804167Sbinkertn@umich.edu code('#include "enums/$0.hh"', cls.__name__) 14813101Sstever@eecs.umich.edu 14823101Sstever@eecs.umich.edu @classmethod 14833101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 14843885Sbinkertn@umich.edu code('if (false) {') 14853102Sstever@eecs.umich.edu for elem_name in cls.map.keys(): 14863101Sstever@eecs.umich.edu code('} else if (%s == "%s") {' % (src, elem_name)) 14876654Snate@binkert.org code.indent() 14886654Snate@binkert.org name = cls.__name__ if cls.enum_name is None else cls.enum_name 1489 code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums', 1490 elem_name)) 1491 code('%s true;' % ret) 1492 code.dedent() 1493 code('} else {') 1494 code(' %s false;' % ret) 1495 code('}') 1496 1497 def getValue(self): 1498 import m5.internal.params 1499 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1500 return e(self.map[self.value]) 1501 1502 def __str__(self): 1503 return self.value 1504 1505# This param will generate a scoped c++ enum and its python bindings. 1506class ScopedEnum(Enum): 1507 __metaclass__ = MetaEnum 1508 vals = [] 1509 cmd_line_settable = True 1510 1511 # The name of the wrapping namespace or struct 1512 wrapper_name = None 1513 1514 # If true, the enum is wrapped in a struct rather than a namespace 1515 wrapper_is_struct = False 1516 1517 # If true, the generated enum is a scoped enum 1518 is_class = True 1519 1520 # If not None, use this as the enum name rather than this class name 1521 enum_name = None 1522 1523# how big does a rounding error need to be before we warn about it? 1524frequency_tolerance = 0.001 # 0.1% 1525 1526class TickParamValue(NumericParamValue): 1527 cxx_type = 'Tick' 1528 ex_str = "1MHz" 1529 cmd_line_settable = True 1530 1531 @classmethod 1532 def cxx_predecls(cls, code): 1533 code('#include "base/types.hh"') 1534 1535 def __call__(self, value): 1536 self.__init__(value) 1537 return value 1538 1539 def getValue(self): 1540 return long(self.value) 1541 1542 @classmethod 1543 def cxx_ini_predecls(cls, code): 1544 code('#include <sstream>') 1545 1546 # Ticks are expressed in seconds in JSON files and in plain 1547 # Ticks in .ini files. Switch based on a config flag 1548 @classmethod 1549 def cxx_ini_parse(self, code, src, dest, ret): 1550 code('${ret} to_number(${src}, ${dest});') 1551 1552class Latency(TickParamValue): 1553 ex_str = "100ns" 1554 1555 def __init__(self, value): 1556 if isinstance(value, (Latency, Clock)): 1557 self.ticks = value.ticks 1558 self.value = value.value 1559 elif isinstance(value, Frequency): 1560 self.ticks = value.ticks 1561 self.value = 1.0 / value.value 1562 elif value.endswith('t'): 1563 self.ticks = True 1564 self.value = int(value[:-1]) 1565 else: 1566 self.ticks = False 1567 self.value = convert.toLatency(value) 1568 1569 def __call__(self, value): 1570 self.__init__(value) 1571 return value 1572 1573 def __getattr__(self, attr): 1574 if attr in ('latency', 'period'): 1575 return self 1576 if attr == 'frequency': 1577 return Frequency(self) 1578 raise AttributeError("Latency object has no attribute '%s'" % attr) 1579 1580 def getValue(self): 1581 if self.ticks or self.value == 0: 1582 value = self.value 1583 else: 1584 value = ticks.fromSeconds(self.value) 1585 return long(value) 1586 1587 def config_value(self): 1588 return self.getValue() 1589 1590 # convert latency to ticks 1591 def ini_str(self): 1592 return '%d' % self.getValue() 1593 1594class Frequency(TickParamValue): 1595 ex_str = "1GHz" 1596 1597 def __init__(self, value): 1598 if isinstance(value, (Latency, Clock)): 1599 if value.value == 0: 1600 self.value = 0 1601 else: 1602 self.value = 1.0 / value.value 1603 self.ticks = value.ticks 1604 elif isinstance(value, Frequency): 1605 self.value = value.value 1606 self.ticks = value.ticks 1607 else: 1608 self.ticks = False 1609 self.value = convert.toFrequency(value) 1610 1611 def __call__(self, value): 1612 self.__init__(value) 1613 return value 1614 1615 def __getattr__(self, attr): 1616 if attr == 'frequency': 1617 return self 1618 if attr in ('latency', 'period'): 1619 return Latency(self) 1620 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1621 1622 # convert latency to ticks 1623 def getValue(self): 1624 if self.ticks or self.value == 0: 1625 value = self.value 1626 else: 1627 value = ticks.fromSeconds(1.0 / self.value) 1628 return long(value) 1629 1630 def config_value(self): 1631 return self.getValue() 1632 1633 def ini_str(self): 1634 return '%d' % self.getValue() 1635 1636# A generic Frequency and/or Latency value. Value is stored as a 1637# latency, just like Latency and Frequency. 1638class Clock(TickParamValue): 1639 def __init__(self, value): 1640 if isinstance(value, (Latency, Clock)): 1641 self.ticks = value.ticks 1642 self.value = value.value 1643 elif isinstance(value, Frequency): 1644 self.ticks = value.ticks 1645 self.value = 1.0 / value.value 1646 elif value.endswith('t'): 1647 self.ticks = True 1648 self.value = int(value[:-1]) 1649 else: 1650 self.ticks = False 1651 self.value = convert.anyToLatency(value) 1652 1653 def __call__(self, value): 1654 self.__init__(value) 1655 return value 1656 1657 def __str__(self): 1658 return "%s" % Latency(self) 1659 1660 def __getattr__(self, attr): 1661 if attr == 'frequency': 1662 return Frequency(self) 1663 if attr in ('latency', 'period'): 1664 return Latency(self) 1665 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1666 1667 def getValue(self): 1668 return self.period.getValue() 1669 1670 def config_value(self): 1671 return self.period.config_value() 1672 1673 def ini_str(self): 1674 return self.period.ini_str() 1675 1676class Voltage(Float): 1677 ex_str = "1V" 1678 1679 def __new__(cls, value): 1680 value = convert.toVoltage(value) 1681 return super(cls, Voltage).__new__(cls, value) 1682 1683 def __init__(self, value): 1684 value = convert.toVoltage(value) 1685 super(Voltage, self).__init__(value) 1686 1687class Current(Float): 1688 ex_str = "1mA" 1689 1690 def __new__(cls, value): 1691 value = convert.toCurrent(value) 1692 return super(cls, Current).__new__(cls, value) 1693 1694 def __init__(self, value): 1695 value = convert.toCurrent(value) 1696 super(Current, self).__init__(value) 1697 1698class Energy(Float): 1699 ex_str = "1pJ" 1700 1701 def __new__(cls, value): 1702 value = convert.toEnergy(value) 1703 return super(cls, Energy).__new__(cls, value) 1704 1705 def __init__(self, value): 1706 value = convert.toEnergy(value) 1707 super(Energy, self).__init__(value) 1708 1709class NetworkBandwidth(float,ParamValue): 1710 cxx_type = 'float' 1711 ex_str = "1Gbps" 1712 cmd_line_settable = True 1713 1714 def __new__(cls, value): 1715 # convert to bits per second 1716 val = convert.toNetworkBandwidth(value) 1717 return super(cls, NetworkBandwidth).__new__(cls, val) 1718 1719 def __str__(self): 1720 return str(self.val) 1721 1722 def __call__(self, value): 1723 val = convert.toNetworkBandwidth(value) 1724 self.__init__(val) 1725 return value 1726 1727 def getValue(self): 1728 # convert to seconds per byte 1729 value = 8.0 / float(self) 1730 # convert to ticks per byte 1731 value = ticks.fromSeconds(value) 1732 return float(value) 1733 1734 def ini_str(self): 1735 return '%f' % self.getValue() 1736 1737 def config_value(self): 1738 return '%f' % self.getValue() 1739 1740 @classmethod 1741 def cxx_ini_predecls(cls, code): 1742 code('#include <sstream>') 1743 1744 @classmethod 1745 def cxx_ini_parse(self, code, src, dest, ret): 1746 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1747 1748class MemoryBandwidth(float,ParamValue): 1749 cxx_type = 'float' 1750 ex_str = "1GB/s" 1751 cmd_line_settable = True 1752 1753 def __new__(cls, value): 1754 # convert to bytes per second 1755 val = convert.toMemoryBandwidth(value) 1756 return super(cls, MemoryBandwidth).__new__(cls, val) 1757 1758 def __call__(self, value): 1759 val = convert.toMemoryBandwidth(value) 1760 self.__init__(val) 1761 return value 1762 1763 def getValue(self): 1764 # convert to seconds per byte 1765 value = float(self) 1766 if value: 1767 value = 1.0 / float(self) 1768 # convert to ticks per byte 1769 value = ticks.fromSeconds(value) 1770 return float(value) 1771 1772 def ini_str(self): 1773 return '%f' % self.getValue() 1774 1775 def config_value(self): 1776 return '%f' % self.getValue() 1777 1778 @classmethod 1779 def cxx_ini_predecls(cls, code): 1780 code('#include <sstream>') 1781 1782 @classmethod 1783 def cxx_ini_parse(self, code, src, dest, ret): 1784 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1785 1786# 1787# "Constants"... handy aliases for various values. 1788# 1789 1790# Special class for NULL pointers. Note the special check in 1791# make_param_value() above that lets these be assigned where a 1792# SimObject is required. 1793# only one copy of a particular node 1794class NullSimObject(object): 1795 __metaclass__ = Singleton 1796 _name = 'Null' 1797 1798 def __call__(cls): 1799 return cls 1800 1801 def _instantiate(self, parent = None, path = ''): 1802 pass 1803 1804 def ini_str(self): 1805 return 'Null' 1806 1807 def unproxy(self, base): 1808 return self 1809 1810 def set_path(self, parent, name): 1811 pass 1812 1813 def set_parent(self, parent, name): 1814 pass 1815 1816 def clear_parent(self, old_parent): 1817 pass 1818 1819 def descendants(self): 1820 return 1821 yield None 1822 1823 def get_config_as_dict(self): 1824 return {} 1825 1826 def __str__(self): 1827 return self._name 1828 1829 def config_value(self): 1830 return None 1831 1832 def getValue(self): 1833 return None 1834 1835# The only instance you'll ever need... 1836NULL = NullSimObject() 1837 1838def isNullPointer(value): 1839 return isinstance(value, NullSimObject) 1840 1841# Some memory range specifications use this as a default upper bound. 1842MaxAddr = Addr.max 1843MaxTick = Tick.max 1844AllMemory = AddrRange(0, MaxAddr) 1845 1846 1847##################################################################### 1848# 1849# Port objects 1850# 1851# Ports are used to interconnect objects in the memory system. 1852# 1853##################################################################### 1854 1855# Port reference: encapsulates a reference to a particular port on a 1856# particular SimObject. 1857class PortRef(object): 1858 def __init__(self, simobj, name, role, is_source): 1859 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1860 self.simobj = simobj 1861 self.name = name 1862 self.role = role 1863 self.is_source = is_source 1864 self.peer = None # not associated with another port yet 1865 self.ccConnected = False # C++ port connection done? 1866 self.index = -1 # always -1 for non-vector ports 1867 1868 def __str__(self): 1869 return '%s.%s' % (self.simobj, self.name) 1870 1871 def __len__(self): 1872 # Return the number of connected ports, i.e. 0 is we have no 1873 # peer and 1 if we do. 1874 return int(self.peer != None) 1875 1876 # for config.ini, print peer's name (not ours) 1877 def ini_str(self): 1878 return str(self.peer) 1879 1880 # for config.json 1881 def get_config_as_dict(self): 1882 return {'role' : self.role, 'peer' : str(self.peer), 1883 'is_source' : str(self.is_source)} 1884 1885 def __getattr__(self, attr): 1886 if attr == 'peerObj': 1887 # shorthand for proxies 1888 return self.peer.simobj 1889 raise AttributeError("'%s' object has no attribute '%s'" % \ 1890 (self.__class__.__name__, attr)) 1891 1892 # Full connection is symmetric (both ways). Called via 1893 # SimObject.__setattr__ as a result of a port assignment, e.g., 1894 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1895 # e.g., "obj1.portA[3] = obj2.portB". 1896 def connect(self, other): 1897 if isinstance(other, VectorPortRef): 1898 # reference to plain VectorPort is implicit append 1899 other = other._get_next() 1900 if self.peer and not proxy.isproxy(self.peer): 1901 fatal("Port %s is already connected to %s, cannot connect %s\n", 1902 self, self.peer, other); 1903 self.peer = other 1904 1905 if proxy.isproxy(other): 1906 other.set_param_desc(PortParamDesc()) 1907 return 1908 elif not isinstance(other, PortRef): 1909 raise TypeError("assigning non-port reference '%s' to port '%s'" \ 1910 % (other, self)) 1911 1912 if not Port.is_compat(self, other): 1913 fatal("Ports %s and %s with roles '%s' and '%s' " 1914 "are not compatible", self, other, self.role, other.role) 1915 1916 if other.peer is not self: 1917 other.connect(self) 1918 1919 # Allow a compatible port pair to be spliced between a port and its 1920 # connected peer. Useful operation for connecting instrumentation 1921 # structures into a system when it is necessary to connect the 1922 # instrumentation after the full system has been constructed. 1923 def splice(self, new_1, new_2): 1924 if not self.peer or proxy.isproxy(self.peer): 1925 fatal("Port %s not connected, cannot splice in new peers\n", self) 1926 1927 if not isinstance(new_1, PortRef) or not isinstance(new_2, PortRef): 1928 raise TypeError( 1929 "Splicing non-port references '%s','%s' to port '%s'" % \ 1930 (new_1, new_2, self)) 1931 1932 old_peer = self.peer 1933 1934 if Port.is_compat(old_peer, new_1) and Port.is_compat(self, new_2): 1935 old_peer.peer = new_1 1936 new_1.peer = old_peer 1937 self.peer = new_2 1938 new_2.peer = self 1939 elif Port.is_compat(old_peer, new_2) and Port.is_compat(self, new_1): 1940 old_peer.peer = new_2 1941 new_2.peer = old_peer 1942 self.peer = new_1 1943 new_1.peer = self 1944 else: 1945 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with " 1946 "%s(%s) and %s(%s)", self, self.role, 1947 old_peer, old_peer.role, new_1, new_1.role, 1948 new_2, new_2.role) 1949 1950 def clone(self, simobj, memo): 1951 if self in memo: 1952 return memo[self] 1953 newRef = copy.copy(self) 1954 memo[self] = newRef 1955 newRef.simobj = simobj 1956 assert(isSimObject(newRef.simobj)) 1957 if self.peer and not proxy.isproxy(self.peer): 1958 peerObj = self.peer.simobj(_memo=memo) 1959 newRef.peer = self.peer.clone(peerObj, memo) 1960 assert(not isinstance(newRef.peer, VectorPortRef)) 1961 return newRef 1962 1963 def unproxy(self, simobj): 1964 assert(simobj is self.simobj) 1965 if proxy.isproxy(self.peer): 1966 try: 1967 realPeer = self.peer.unproxy(self.simobj) 1968 except: 1969 print("Error in unproxying port '%s' of %s" % 1970 (self.name, self.simobj.path())) 1971 raise 1972 self.connect(realPeer) 1973 1974 # Call C++ to create corresponding port connection between C++ objects 1975 def ccConnect(self): 1976 if self.ccConnected: # already done this 1977 return 1978 1979 peer = self.peer 1980 if not self.peer: # nothing to connect to 1981 return 1982 1983 port = self.simobj.getPort(self.name, self.index) 1984 peer_port = peer.simobj.getPort(peer.name, peer.index) 1985 port.bind(peer_port) 1986 1987 self.ccConnected = True 1988 1989# A reference to an individual element of a VectorPort... much like a 1990# PortRef, but has an index. 1991class VectorPortElementRef(PortRef): 1992 def __init__(self, simobj, name, role, is_source, index): 1993 PortRef.__init__(self, simobj, name, role, is_source) 1994 self.index = index 1995 1996 def __str__(self): 1997 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1998 1999# A reference to a complete vector-valued port (not just a single element). 2000# Can be indexed to retrieve individual VectorPortElementRef instances. 2001class VectorPortRef(object): 2002 def __init__(self, simobj, name, role, is_source): 2003 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 2004 self.simobj = simobj 2005 self.name = name 2006 self.role = role 2007 self.is_source = is_source 2008 self.elements = [] 2009 2010 def __str__(self): 2011 return '%s.%s[:]' % (self.simobj, self.name) 2012 2013 def __len__(self): 2014 # Return the number of connected peers, corresponding the the 2015 # length of the elements. 2016 return len(self.elements) 2017 2018 # for config.ini, print peer's name (not ours) 2019 def ini_str(self): 2020 return ' '.join([el.ini_str() for el in self.elements]) 2021 2022 # for config.json 2023 def get_config_as_dict(self): 2024 return {'role' : self.role, 2025 'peer' : [el.ini_str() for el in self.elements], 2026 'is_source' : str(self.is_source)} 2027 2028 def __getitem__(self, key): 2029 if not isinstance(key, int): 2030 raise TypeError("VectorPort index must be integer") 2031 if key >= len(self.elements): 2032 # need to extend list 2033 ext = [VectorPortElementRef( 2034 self.simobj, self.name, self.role, self.is_source, i) 2035 for i in range(len(self.elements), key+1)] 2036 self.elements.extend(ext) 2037 return self.elements[key] 2038 2039 def _get_next(self): 2040 return self[len(self.elements)] 2041 2042 def __setitem__(self, key, value): 2043 if not isinstance(key, int): 2044 raise TypeError("VectorPort index must be integer") 2045 self[key].connect(value) 2046 2047 def connect(self, other): 2048 if isinstance(other, (list, tuple)): 2049 # Assign list of port refs to vector port. 2050 # For now, append them... not sure if that's the right semantics 2051 # or if it should replace the current vector. 2052 for ref in other: 2053 self._get_next().connect(ref) 2054 else: 2055 # scalar assignment to plain VectorPort is implicit append 2056 self._get_next().connect(other) 2057 2058 def clone(self, simobj, memo): 2059 if self in memo: 2060 return memo[self] 2061 newRef = copy.copy(self) 2062 memo[self] = newRef 2063 newRef.simobj = simobj 2064 assert(isSimObject(newRef.simobj)) 2065 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 2066 return newRef 2067 2068 def unproxy(self, simobj): 2069 [el.unproxy(simobj) for el in self.elements] 2070 2071 def ccConnect(self): 2072 [el.ccConnect() for el in self.elements] 2073 2074# Port description object. Like a ParamDesc object, this represents a 2075# logical port in the SimObject class, not a particular port on a 2076# SimObject instance. The latter are represented by PortRef objects. 2077class Port(object): 2078 # Port("role", "description") 2079 2080 _compat_dict = { } 2081 2082 @classmethod 2083 def compat(cls, role, peer): 2084 cls._compat_dict.setdefault(role, set()).add(peer) 2085 cls._compat_dict.setdefault(peer, set()).add(role) 2086 2087 @classmethod 2088 def is_compat(cls, one, two): 2089 for port in one, two: 2090 if not port.role in Port._compat_dict: 2091 fatal("Unrecognized role '%s' for port %s\n", port.role, port) 2092 return one.role in Port._compat_dict[two.role] 2093 2094 def __init__(self, role, desc, is_source=False): 2095 self.desc = desc 2096 self.role = role 2097 self.is_source = is_source 2098 2099 # Generate a PortRef for this port on the given SimObject with the 2100 # given name 2101 def makeRef(self, simobj): 2102 return PortRef(simobj, self.name, self.role, self.is_source) 2103 2104 # Connect an instance of this port (on the given SimObject with 2105 # the given name) with the port described by the supplied PortRef 2106 def connect(self, simobj, ref): 2107 self.makeRef(simobj).connect(ref) 2108 2109 # No need for any pre-declarations at the moment as we merely rely 2110 # on an unsigned int. 2111 def cxx_predecls(self, code): 2112 pass 2113 2114 def pybind_predecls(self, code): 2115 cls.cxx_predecls(self, code) 2116 2117 # Declare an unsigned int with the same name as the port, that 2118 # will eventually hold the number of connected ports (and thus the 2119 # number of elements for a VectorPort). 2120 def cxx_decl(self, code): 2121 code('unsigned int port_${{self.name}}_connection_count;') 2122 2123Port.compat('GEM5 REQUESTER', 'GEM5 RESPONDER') 2124 2125class RequestPort(Port): 2126 # RequestPort("description") 2127 def __init__(self, desc): 2128 super(RequestPort, self).__init__( 2129 'GEM5 REQUESTER', desc, is_source=True) 2130 2131class ResponsePort(Port): 2132 # ResponsePort("description") 2133 def __init__(self, desc): 2134 super(ResponsePort, self).__init__('GEM5 RESPONDER', desc) 2135 2136# VectorPort description object. Like Port, but represents a vector 2137# of connections (e.g., as on a XBar). 2138class VectorPort(Port): 2139 def makeRef(self, simobj): 2140 return VectorPortRef(simobj, self.name, self.role, self.is_source) 2141 2142class VectorRequestPort(VectorPort): 2143 # VectorRequestPort("description") 2144 def __init__(self, desc): 2145 super(VectorRequestPort, self).__init__( 2146 'GEM5 REQUESTER', desc, is_source=True) 2147 2148class VectorResponsePort(VectorPort): 2149 # VectorResponsePort("description") 2150 def __init__(self, desc): 2151 super(VectorResponsePort, self).__init__('GEM5 RESPONDER', desc) 2152 2153# Old names, maintained for compatibility. 2154MasterPort = RequestPort 2155SlavePort = ResponsePort 2156VectorMasterPort = VectorRequestPort 2157VectorSlavePort = VectorResponsePort 2158 2159# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2160# proxy objects (via set_param_desc()) so that proxy error messages 2161# make sense. 2162class PortParamDesc(object): 2163 __metaclass__ = Singleton 2164 2165 ptype_str = 'Port' 2166 ptype = Port 2167 2168baseEnums = allEnums.copy() 2169baseParams = allParams.copy() 2170 2171def clear(): 2172 global allEnums, allParams 2173 2174 allEnums = baseEnums.copy() 2175 allParams = baseParams.copy() 2176 2177__all__ = ['Param', 'VectorParam', 2178 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float', 2179 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2180 'Int32', 'UInt32', 'Int64', 'UInt64', 2181 'Counter', 'Addr', 'Tick', 'Percent', 2182 'TcpPort', 'UdpPort', 'EthernetAddr', 2183 'IpAddress', 'IpNetmask', 'IpWithPort', 2184 'MemorySize', 'MemorySize32', 2185 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy', 2186 'NetworkBandwidth', 'MemoryBandwidth', 2187 'AddrRange', 2188 'MaxAddr', 'MaxTick', 'AllMemory', 2189 'Time', 2190 'NextEthernetAddr', 'NULL', 2191 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort', 2192 'VectorPort', 'VectorRequestPort', 'VectorResponsePort', 2193 'VectorMasterPort', 'VectorSlavePort'] 2194