params.py revision 13699
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017, 2018 ARM Limited 23101Sstever@eecs.umich.edu# 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 303101Sstever@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# 473885Sbinkertn@umich.edu# Parameter description classes 483885Sbinkertn@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 513885Sbinkertn@umich.edu# parameter description string, the parameter type, and the default 523885Sbinkertn@umich.edu# value (if any). The convert() method on these objects is used to 533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 544380Sbinkertn@umich.edu# type. 554167Sbinkertn@umich.edu# 563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute 573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in 583101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used. 593101Sstever@eecs.umich.edu# 603101Sstever@eecs.umich.edu##################################################################### 613101Sstever@eecs.umich.edu 623101Sstever@eecs.umich.edufrom __future__ import print_function 633101Sstever@eecs.umich.edu 643101Sstever@eecs.umich.eduimport copy 653101Sstever@eecs.umich.eduimport datetime 663101Sstever@eecs.umich.eduimport re 673101Sstever@eecs.umich.eduimport sys 683101Sstever@eecs.umich.eduimport time 693101Sstever@eecs.umich.eduimport math 703101Sstever@eecs.umich.edu 713101Sstever@eecs.umich.eduimport proxy 723101Sstever@eecs.umich.eduimport ticks 733101Sstever@eecs.umich.edufrom util import * 743101Sstever@eecs.umich.edu 753101Sstever@eecs.umich.edudef isSimObject(*args, **kwargs): 763101Sstever@eecs.umich.edu return SimObject.isSimObject(*args, **kwargs) 773101Sstever@eecs.umich.edu 783101Sstever@eecs.umich.edudef isSimObjectSequence(*args, **kwargs): 793101Sstever@eecs.umich.edu return SimObject.isSimObjectSequence(*args, **kwargs) 803101Sstever@eecs.umich.edu 813101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs): 823101Sstever@eecs.umich.edu return SimObject.isSimObjectClass(*args, **kwargs) 833101Sstever@eecs.umich.edu 843101Sstever@eecs.umich.eduallParams = {} 853101Sstever@eecs.umich.edu 863101Sstever@eecs.umich.educlass MetaParamValue(type): 873101Sstever@eecs.umich.edu def __new__(mcls, name, bases, dct): 883101Sstever@eecs.umich.edu cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 893101Sstever@eecs.umich.edu assert name not in allParams 903101Sstever@eecs.umich.edu allParams[name] = cls 913101Sstever@eecs.umich.edu return cls 923101Sstever@eecs.umich.edu 933101Sstever@eecs.umich.edu 943101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject 953101Sstever@eecs.umich.edu# parameters. 963101Sstever@eecs.umich.educlass ParamValue(object): 973101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 983101Sstever@eecs.umich.edu cmd_line_settable = False 993101Sstever@eecs.umich.edu 1003101Sstever@eecs.umich.edu # Generate the code needed as a prerequisite for declaring a C++ 1013101Sstever@eecs.umich.edu # object of this type. Typically generates one or more #include 1023101Sstever@eecs.umich.edu # statements. Used when declaring parameters of this type. 1033101Sstever@eecs.umich.edu @classmethod 1043101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 1053101Sstever@eecs.umich.edu pass 1063101Sstever@eecs.umich.edu 1073101Sstever@eecs.umich.edu @classmethod 1083101Sstever@eecs.umich.edu def pybind_predecls(cls, code): 1093101Sstever@eecs.umich.edu cls.cxx_predecls(code) 1103101Sstever@eecs.umich.edu 1113102Sstever@eecs.umich.edu # default for printing to .ini file is regular string conversion. 1123101Sstever@eecs.umich.edu # will be overridden in some cases 1133102Sstever@eecs.umich.edu def ini_str(self): 1143101Sstever@eecs.umich.edu return str(self) 1153101Sstever@eecs.umich.edu 1163101Sstever@eecs.umich.edu # default for printing to .json file is regular string conversion. 1173102Sstever@eecs.umich.edu # will be overridden in some cases, mostly to use native Python 1183102Sstever@eecs.umich.edu # types where there are similar JSON types 1193101Sstever@eecs.umich.edu def config_value(self): 1203101Sstever@eecs.umich.edu return str(self) 1213101Sstever@eecs.umich.edu 1223101Sstever@eecs.umich.edu # Prerequisites for .ini parsing with cxx_ini_parse 1233101Sstever@eecs.umich.edu @classmethod 1243101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 1253101Sstever@eecs.umich.edu pass 1263101Sstever@eecs.umich.edu 1273101Sstever@eecs.umich.edu # parse a .ini file entry for this param from string expression 1283101Sstever@eecs.umich.edu # src into lvalue dest (of the param's C++ type) 1293101Sstever@eecs.umich.edu @classmethod 1303101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 1313101Sstever@eecs.umich.edu code('// Unhandled param type: %s' % cls.__name__) 1323102Sstever@eecs.umich.edu code('%s false;' % ret) 1333101Sstever@eecs.umich.edu 1343101Sstever@eecs.umich.edu # allows us to blithely call unproxy() on things without checking 1353101Sstever@eecs.umich.edu # if they're really proxies or not 1363101Sstever@eecs.umich.edu def unproxy(self, base): 1373101Sstever@eecs.umich.edu return self 1383101Sstever@eecs.umich.edu 1393101Sstever@eecs.umich.edu # Produce a human readable version of the stored value 1403101Sstever@eecs.umich.edu def pretty_print(self, value): 1413101Sstever@eecs.umich.edu return str(value) 1423101Sstever@eecs.umich.edu 1433101Sstever@eecs.umich.edu# Regular parameter description. 1443101Sstever@eecs.umich.educlass ParamDesc(object): 1453101Sstever@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 1463101Sstever@eecs.umich.edu self.ptype_str = ptype_str 1473101Sstever@eecs.umich.edu # remember ptype only if it is provided 1483101Sstever@eecs.umich.edu if ptype != None: 1493101Sstever@eecs.umich.edu self.ptype = ptype 1503101Sstever@eecs.umich.edu 1513101Sstever@eecs.umich.edu if args: 1523101Sstever@eecs.umich.edu if len(args) == 1: 1533101Sstever@eecs.umich.edu self.desc = args[0] 1543101Sstever@eecs.umich.edu elif len(args) == 2: 1553101Sstever@eecs.umich.edu self.default = args[0] 1563101Sstever@eecs.umich.edu self.desc = args[1] 1573101Sstever@eecs.umich.edu else: 1583101Sstever@eecs.umich.edu raise TypeError('too many arguments') 1593101Sstever@eecs.umich.edu 1603101Sstever@eecs.umich.edu if 'desc' in kwargs: 1613101Sstever@eecs.umich.edu assert(not hasattr(self, 'desc')) 1623101Sstever@eecs.umich.edu self.desc = kwargs['desc'] 1633101Sstever@eecs.umich.edu del kwargs['desc'] 1643101Sstever@eecs.umich.edu 1653101Sstever@eecs.umich.edu if 'default' in kwargs: 1663101Sstever@eecs.umich.edu assert(not hasattr(self, 'default')) 1673101Sstever@eecs.umich.edu self.default = kwargs['default'] 1683101Sstever@eecs.umich.edu del kwargs['default'] 1693101Sstever@eecs.umich.edu 1703101Sstever@eecs.umich.edu if kwargs: 1713101Sstever@eecs.umich.edu raise TypeError('extra unknown kwargs %s' % kwargs) 1723101Sstever@eecs.umich.edu 1733101Sstever@eecs.umich.edu if not hasattr(self, 'desc'): 1743101Sstever@eecs.umich.edu raise TypeError('desc attribute missing') 1753101Sstever@eecs.umich.edu 1763101Sstever@eecs.umich.edu def __getattr__(self, attr): 1773101Sstever@eecs.umich.edu if attr == 'ptype': 1783101Sstever@eecs.umich.edu ptype = SimObject.allClasses[self.ptype_str] 1793101Sstever@eecs.umich.edu assert isSimObjectClass(ptype) 1803101Sstever@eecs.umich.edu self.ptype = ptype 1813101Sstever@eecs.umich.edu return ptype 1823101Sstever@eecs.umich.edu 1833101Sstever@eecs.umich.edu raise AttributeError("'%s' object has no attribute '%s'" % \ 1843101Sstever@eecs.umich.edu (type(self).__name__, attr)) 1853101Sstever@eecs.umich.edu 1863101Sstever@eecs.umich.edu def example_str(self): 1873101Sstever@eecs.umich.edu if hasattr(self.ptype, "ex_str"): 1883101Sstever@eecs.umich.edu return self.ptype.ex_str 1893101Sstever@eecs.umich.edu else: 1903101Sstever@eecs.umich.edu return self.ptype_str 1913101Sstever@eecs.umich.edu 1923101Sstever@eecs.umich.edu # Is the param available to be exposed on the command line 1933101Sstever@eecs.umich.edu def isCmdLineSettable(self): 1943101Sstever@eecs.umich.edu if hasattr(self.ptype, "cmd_line_settable"): 1953101Sstever@eecs.umich.edu return self.ptype.cmd_line_settable 1963101Sstever@eecs.umich.edu else: 1973101Sstever@eecs.umich.edu return False 1983101Sstever@eecs.umich.edu 1993101Sstever@eecs.umich.edu def convert(self, value): 2003101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 2013101Sstever@eecs.umich.edu value.set_param_desc(self) 2023101Sstever@eecs.umich.edu return value 2033101Sstever@eecs.umich.edu if 'ptype' not in self.__dict__ and isNullPointer(value): 2043101Sstever@eecs.umich.edu # deferred evaluation of SimObject; continue to defer if 2053101Sstever@eecs.umich.edu # we're just assigning a null pointer 2063101Sstever@eecs.umich.edu return value 2073101Sstever@eecs.umich.edu if isinstance(value, self.ptype): 2083101Sstever@eecs.umich.edu return value 2093101Sstever@eecs.umich.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 2103101Sstever@eecs.umich.edu return value 2113101Sstever@eecs.umich.edu return self.ptype(value) 2123101Sstever@eecs.umich.edu 2133101Sstever@eecs.umich.edu def pretty_print(self, value): 2143101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 2153101Sstever@eecs.umich.edu return str(value) 2163101Sstever@eecs.umich.edu if isNullPointer(value): 2173101Sstever@eecs.umich.edu return NULL 2183101Sstever@eecs.umich.edu return self.ptype(value).pretty_print(value) 2193101Sstever@eecs.umich.edu 2203101Sstever@eecs.umich.edu def cxx_predecls(self, code): 2213101Sstever@eecs.umich.edu code('#include <cstddef>') 2223101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2233101Sstever@eecs.umich.edu 2243101Sstever@eecs.umich.edu def pybind_predecls(self, code): 2253101Sstever@eecs.umich.edu self.ptype.pybind_predecls(code) 2263101Sstever@eecs.umich.edu 2273101Sstever@eecs.umich.edu def cxx_decl(self, code): 2283101Sstever@eecs.umich.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 2293101Sstever@eecs.umich.edu 2303101Sstever@eecs.umich.edu# Vector-valued parameter description. Just like ParamDesc, except 2313101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a 2323101Sstever@eecs.umich.edu# single value. 2333101Sstever@eecs.umich.edu 2343101Sstever@eecs.umich.educlass VectorParamValue(list): 2353101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 2363101Sstever@eecs.umich.edu def __setattr__(self, attr, value): 2373101Sstever@eecs.umich.edu raise AttributeError("Not allowed to set %s on '%s'" % \ 2383101Sstever@eecs.umich.edu (attr, type(self).__name__)) 2393101Sstever@eecs.umich.edu 2403101Sstever@eecs.umich.edu def config_value(self): 2413101Sstever@eecs.umich.edu return [v.config_value() for v in self] 2423101Sstever@eecs.umich.edu 2433101Sstever@eecs.umich.edu def ini_str(self): 2443101Sstever@eecs.umich.edu return ' '.join([v.ini_str() for v in self]) 2453101Sstever@eecs.umich.edu 2463101Sstever@eecs.umich.edu def getValue(self): 2473714Sstever@eecs.umich.edu return [ v.getValue() for v in self ] 2483714Sstever@eecs.umich.edu 2493714Sstever@eecs.umich.edu def unproxy(self, base): 2503714Sstever@eecs.umich.edu if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 2513714Sstever@eecs.umich.edu # The value is a proxy (e.g. Parent.any, Parent.all or 2523714Sstever@eecs.umich.edu # Parent.x) therefore try resolve it 2533101Sstever@eecs.umich.edu return self[0].unproxy(base) 2543101Sstever@eecs.umich.edu else: 2553101Sstever@eecs.umich.edu return [v.unproxy(base) for v in self] 2563101Sstever@eecs.umich.edu 2573101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue): 2583101Sstever@eecs.umich.edu # support clone operation 2593101Sstever@eecs.umich.edu def __call__(self, **kwargs): 2603101Sstever@eecs.umich.edu return SimObjectVector([v(**kwargs) for v in self]) 2613101Sstever@eecs.umich.edu 2623101Sstever@eecs.umich.edu def clear_parent(self, old_parent): 2633101Sstever@eecs.umich.edu for v in self: 2643101Sstever@eecs.umich.edu v.clear_parent(old_parent) 2653101Sstever@eecs.umich.edu 2663101Sstever@eecs.umich.edu def set_parent(self, parent, name): 2673101Sstever@eecs.umich.edu if len(self) == 1: 2683101Sstever@eecs.umich.edu self[0].set_parent(parent, name) 2693101Sstever@eecs.umich.edu else: 2703101Sstever@eecs.umich.edu width = int(math.ceil(math.log(len(self))/math.log(10))) 2713101Sstever@eecs.umich.edu for i,v in enumerate(self): 2723101Sstever@eecs.umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2733101Sstever@eecs.umich.edu 2743101Sstever@eecs.umich.edu def has_parent(self): 2753101Sstever@eecs.umich.edu return any([e.has_parent() for e in self if not isNullPointer(e)]) 2763101Sstever@eecs.umich.edu 2773101Sstever@eecs.umich.edu # return 'cpu0 cpu1' etc. for print_ini() 2783101Sstever@eecs.umich.edu def get_name(self): 2793101Sstever@eecs.umich.edu return ' '.join([v._name for v in self]) 2803101Sstever@eecs.umich.edu 2813101Sstever@eecs.umich.edu # By iterating through the constituent members of the vector here 2823101Sstever@eecs.umich.edu # we can nicely handle iterating over all a SimObject's children 2833101Sstever@eecs.umich.edu # without having to provide lots of special functions on 2843101Sstever@eecs.umich.edu # SimObjectVector directly. 2853101Sstever@eecs.umich.edu def descendants(self): 2863101Sstever@eecs.umich.edu for v in self: 2873101Sstever@eecs.umich.edu for obj in v.descendants(): 2883101Sstever@eecs.umich.edu yield obj 2893101Sstever@eecs.umich.edu 2903101Sstever@eecs.umich.edu def get_config_as_dict(self): 2913101Sstever@eecs.umich.edu a = [] 2923101Sstever@eecs.umich.edu for v in self: 2933101Sstever@eecs.umich.edu a.append(v.get_config_as_dict()) 2943101Sstever@eecs.umich.edu return a 2953101Sstever@eecs.umich.edu 2963101Sstever@eecs.umich.edu # If we are replacing an item in the vector, make sure to set the 2973101Sstever@eecs.umich.edu # parent reference of the new SimObject to be the same as the parent 2983101Sstever@eecs.umich.edu # of the SimObject being replaced. Useful to have if we created 2993101Sstever@eecs.umich.edu # a SimObjectVector of temporary objects that will be modified later in 3003101Sstever@eecs.umich.edu # configuration scripts. 3013101Sstever@eecs.umich.edu def __setitem__(self, key, value): 3023101Sstever@eecs.umich.edu val = self[key] 3033101Sstever@eecs.umich.edu if value.has_parent(): 3043101Sstever@eecs.umich.edu warn("SimObject %s already has a parent" % value.get_name() +\ 3053101Sstever@eecs.umich.edu " that is being overwritten by a SimObjectVector") 3063101Sstever@eecs.umich.edu value.set_parent(val.get_parent(), val._name) 3073101Sstever@eecs.umich.edu super(SimObjectVector, self).__setitem__(key, value) 3083101Sstever@eecs.umich.edu 3093101Sstever@eecs.umich.edu # Enumerate the params of each member of the SimObject vector. Creates 3103101Sstever@eecs.umich.edu # strings that will allow indexing into the vector by the python code and 3113101Sstever@eecs.umich.edu # allow it to be specified on the command line. 3123101Sstever@eecs.umich.edu def enumerateParams(self, flags_dict = {}, 3133101Sstever@eecs.umich.edu cmd_line_str = "", 3143101Sstever@eecs.umich.edu access_str = ""): 3153101Sstever@eecs.umich.edu if hasattr(self, "_paramEnumed"): 3163101Sstever@eecs.umich.edu print("Cycle detected enumerating params at %s?!" % (cmd_line_str)) 3173101Sstever@eecs.umich.edu else: 3183101Sstever@eecs.umich.edu x = 0 3193101Sstever@eecs.umich.edu for vals in self: 3203101Sstever@eecs.umich.edu # Each entry in the SimObjectVector should be an 3213101Sstever@eecs.umich.edu # instance of a SimObject 3223101Sstever@eecs.umich.edu flags_dict = vals.enumerateParams(flags_dict, 3233102Sstever@eecs.umich.edu cmd_line_str + "%d." % x, 3243714Sstever@eecs.umich.edu access_str + "[%d]." % x) 3253101Sstever@eecs.umich.edu x = x + 1 3263714Sstever@eecs.umich.edu 3273714Sstever@eecs.umich.edu return flags_dict 3283714Sstever@eecs.umich.edu 3293101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc): 3303101Sstever@eecs.umich.edu # Convert assigned value to appropriate type. If the RHS is not a 3313101Sstever@eecs.umich.edu # list or tuple, it generates a single-element list. 3323101Sstever@eecs.umich.edu def convert(self, value): 3333101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3343101Sstever@eecs.umich.edu # list: coerce each element into new list 3353101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3363101Sstever@eecs.umich.edu elif isinstance(value, str): 3373101Sstever@eecs.umich.edu # If input is a csv string 3383101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3393101Sstever@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3403101Sstever@eecs.umich.edu else: 3413101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3423101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3433101Sstever@eecs.umich.edu 3443101Sstever@eecs.umich.edu if isSimObjectSequence(tmp_list): 3453101Sstever@eecs.umich.edu return SimObjectVector(tmp_list) 3463101Sstever@eecs.umich.edu else: 3473101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3483101Sstever@eecs.umich.edu 3493101Sstever@eecs.umich.edu # Produce a human readable example string that describes 3503101Sstever@eecs.umich.edu # how to set this vector parameter in the absence of a default 3513101Sstever@eecs.umich.edu # value. 3523101Sstever@eecs.umich.edu def example_str(self): 3533101Sstever@eecs.umich.edu s = super(VectorParamDesc, self).example_str() 3543101Sstever@eecs.umich.edu help_str = "[" + s + "," + s + ", ...]" 3553101Sstever@eecs.umich.edu return help_str 3563101Sstever@eecs.umich.edu 3573101Sstever@eecs.umich.edu # Produce a human readable representation of the value of this vector param. 3583101Sstever@eecs.umich.edu def pretty_print(self, value): 3593101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3603101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 3613102Sstever@eecs.umich.edu elif isinstance(value, str): 3623101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 3633101Sstever@eecs.umich.edu else: 3643101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, value) ] 3654168Sbinkertn@umich.edu 3663101Sstever@eecs.umich.edu return tmp_list 3673101Sstever@eecs.umich.edu 3683101Sstever@eecs.umich.edu # This is a helper function for the new config system 3693101Sstever@eecs.umich.edu def __call__(self, value): 3703101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3713101Sstever@eecs.umich.edu # list: coerce each element into new list 3723102Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3733101Sstever@eecs.umich.edu elif isinstance(value, str): 3743101Sstever@eecs.umich.edu # If input is a csv string 3753101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3763101Sstever@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3773101Sstever@eecs.umich.edu else: 3783101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3793101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3803101Sstever@eecs.umich.edu 3813101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3823101Sstever@eecs.umich.edu 3833101Sstever@eecs.umich.edu def cxx_predecls(self, code): 3843101Sstever@eecs.umich.edu code('#include <vector>') 3853102Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 3863101Sstever@eecs.umich.edu 3873101Sstever@eecs.umich.edu def pybind_predecls(self, code): 3883101Sstever@eecs.umich.edu code('#include <vector>') 3893584Ssaidi@eecs.umich.edu self.ptype.pybind_predecls(code) 3903584Ssaidi@eecs.umich.edu 3913584Ssaidi@eecs.umich.edu def cxx_decl(self, code): 3923584Ssaidi@eecs.umich.edu code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 3933584Ssaidi@eecs.umich.edu 3943101Sstever@eecs.umich.educlass ParamFactory(object): 3953101Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 3963101Sstever@eecs.umich.edu self.param_desc_class = param_desc_class 3973101Sstever@eecs.umich.edu self.ptype_str = ptype_str 3983101Sstever@eecs.umich.edu 3993101Sstever@eecs.umich.edu def __getattr__(self, attr): 4003101Sstever@eecs.umich.edu if self.ptype_str: 4013101Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 4023101Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 4033101Sstever@eecs.umich.edu 4043101Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 4053101Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 4063101Sstever@eecs.umich.edu ptype = None 4073101Sstever@eecs.umich.edu try: 4083101Sstever@eecs.umich.edu ptype = allParams[self.ptype_str] 4093101Sstever@eecs.umich.edu except KeyError: 4103101Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 4113101Sstever@eecs.umich.edu # try to resolve it later 4123101Sstever@eecs.umich.edu pass 4133101Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 4143101Sstever@eecs.umich.edu 4153101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc) 4163101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc) 4173101Sstever@eecs.umich.edu 4183101Sstever@eecs.umich.edu##################################################################### 4193101Sstever@eecs.umich.edu# 4203101Sstever@eecs.umich.edu# Parameter Types 4213101Sstever@eecs.umich.edu# 4223101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types 4233101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more 4243101Sstever@eecs.umich.edu# flexible to define our own set of types. This gives us more control 4253101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the 4263101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via 4273101Sstever@eecs.umich.edu# the __str__() conversion method). 4283101Sstever@eecs.umich.edu# 4293101Sstever@eecs.umich.edu##################################################################### 4303101Sstever@eecs.umich.edu 4313101Sstever@eecs.umich.edu# String-valued parameter. Just mixin the ParamValue class with the 4323101Sstever@eecs.umich.edu# built-in str class. 4333101Sstever@eecs.umich.educlass String(ParamValue,str): 4343101Sstever@eecs.umich.edu cxx_type = 'std::string' 4353101Sstever@eecs.umich.edu cmd_line_settable = True 4363101Sstever@eecs.umich.edu 4373101Sstever@eecs.umich.edu @classmethod 4383101Sstever@eecs.umich.edu def cxx_predecls(self, code): 4393101Sstever@eecs.umich.edu code('#include <string>') 4403101Sstever@eecs.umich.edu 4413101Sstever@eecs.umich.edu def __call__(self, value): 4423101Sstever@eecs.umich.edu self = value 4433101Sstever@eecs.umich.edu return value 4443101Sstever@eecs.umich.edu 4453101Sstever@eecs.umich.edu @classmethod 4463101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 4473101Sstever@eecs.umich.edu code('%s = %s;' % (dest, src)) 4483101Sstever@eecs.umich.edu code('%s true;' % ret) 4493101Sstever@eecs.umich.edu 4503101Sstever@eecs.umich.edu def getValue(self): 4513101Sstever@eecs.umich.edu return self 4523101Sstever@eecs.umich.edu 4533101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math 4543101Sstever@eecs.umich.edu# operations in a type-safe way. e.g., a Latency times an int returns 4553101Sstever@eecs.umich.edu# a new Latency object. 4563101Sstever@eecs.umich.educlass NumericParamValue(ParamValue): 4573102Sstever@eecs.umich.edu def __str__(self): 4583101Sstever@eecs.umich.edu return str(self.value) 4593101Sstever@eecs.umich.edu 4603101Sstever@eecs.umich.edu def __float__(self): 4613101Sstever@eecs.umich.edu return float(self.value) 4623101Sstever@eecs.umich.edu 4633101Sstever@eecs.umich.edu def __long__(self): 4643101Sstever@eecs.umich.edu return long(self.value) 4653101Sstever@eecs.umich.edu 4663101Sstever@eecs.umich.edu def __int__(self): 4673101Sstever@eecs.umich.edu return int(self.value) 4683101Sstever@eecs.umich.edu 4693101Sstever@eecs.umich.edu # hook for bounds checking 4703101Sstever@eecs.umich.edu def _check(self): 4713101Sstever@eecs.umich.edu return 4723101Sstever@eecs.umich.edu 4733101Sstever@eecs.umich.edu def __mul__(self, other): 4743101Sstever@eecs.umich.edu newobj = self.__class__(self) 4753101Sstever@eecs.umich.edu newobj.value *= other 4763101Sstever@eecs.umich.edu newobj._check() 4773101Sstever@eecs.umich.edu return newobj 4783101Sstever@eecs.umich.edu 4793101Sstever@eecs.umich.edu __rmul__ = __mul__ 4803101Sstever@eecs.umich.edu 4814380Sbinkertn@umich.edu def __div__(self, other): 4824380Sbinkertn@umich.edu newobj = self.__class__(self) 4834380Sbinkertn@umich.edu newobj.value /= other 4843101Sstever@eecs.umich.edu newobj._check() 4854380Sbinkertn@umich.edu return newobj 4864380Sbinkertn@umich.edu 4874380Sbinkertn@umich.edu def __sub__(self, other): 4883101Sstever@eecs.umich.edu newobj = self.__class__(self) 4893101Sstever@eecs.umich.edu newobj.value -= other 4903101Sstever@eecs.umich.edu newobj._check() 4913101Sstever@eecs.umich.edu return newobj 4923101Sstever@eecs.umich.edu 4933101Sstever@eecs.umich.edu def config_value(self): 4943101Sstever@eecs.umich.edu return self.value 4953101Sstever@eecs.umich.edu 4963101Sstever@eecs.umich.edu @classmethod 4973101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 4983101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 4993101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 5003101Sstever@eecs.umich.edu pass 5013101Sstever@eecs.umich.edu 5023101Sstever@eecs.umich.edu # The default for parsing PODs from an .ini entry is to extract from an 5033101Sstever@eecs.umich.edu # istringstream and let overloading choose the right type according to 5043101Sstever@eecs.umich.edu # the dest type. 5053101Sstever@eecs.umich.edu @classmethod 5063101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 5073101Sstever@eecs.umich.edu code('%s to_number(%s, %s);' % (ret, src, dest)) 5083101Sstever@eecs.umich.edu 5093101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters. See CheckedInt. 5103101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue): 5113101Sstever@eecs.umich.edu def __init__(cls, name, bases, dict): 5123101Sstever@eecs.umich.edu super(CheckedIntType, cls).__init__(name, bases, dict) 5134380Sbinkertn@umich.edu 5143101Sstever@eecs.umich.edu # CheckedInt is an abstract base class, so we actually don't 5153101Sstever@eecs.umich.edu # want to do any processing on it... the rest of this code is 5164380Sbinkertn@umich.edu # just for classes that derive from CheckedInt. 5174380Sbinkertn@umich.edu if name == 'CheckedInt': 5183101Sstever@eecs.umich.edu return 5193932Sbinkertn@umich.edu 5203932Sbinkertn@umich.edu if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 5213932Sbinkertn@umich.edu if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 5223932Sbinkertn@umich.edu panic("CheckedInt subclass %s must define either\n" \ 5233932Sbinkertn@umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n", 5243932Sbinkertn@umich.edu name); 5253932Sbinkertn@umich.edu if cls.unsigned: 5263932Sbinkertn@umich.edu cls.min = 0 5273932Sbinkertn@umich.edu cls.max = 2 ** cls.size - 1 5283932Sbinkertn@umich.edu else: 5293932Sbinkertn@umich.edu cls.min = -(2 ** (cls.size - 1)) 5303932Sbinkertn@umich.edu cls.max = (2 ** (cls.size - 1)) - 1 5313932Sbinkertn@umich.edu 5323885Sbinkertn@umich.edu# Abstract superclass for bounds-checked integer parameters. This 5333932Sbinkertn@umich.edu# class is subclassed to generate parameter classes with specific 5343932Sbinkertn@umich.edu# bounds. Initialization of the min and max bounds is done in the 5353885Sbinkertn@umich.edu# metaclass CheckedIntType.__init__. 5363932Sbinkertn@umich.educlass CheckedInt(NumericParamValue): 5373932Sbinkertn@umich.edu __metaclass__ = CheckedIntType 5383932Sbinkertn@umich.edu cmd_line_settable = True 5393932Sbinkertn@umich.edu 5403932Sbinkertn@umich.edu def _check(self): 5413932Sbinkertn@umich.edu if not self.min <= self.value <= self.max: 5423932Sbinkertn@umich.edu raise TypeError('Integer param out of bounds %d < %d < %d' % \ 5433932Sbinkertn@umich.edu (self.min, self.value, self.max)) 5443932Sbinkertn@umich.edu 5453932Sbinkertn@umich.edu def __init__(self, value): 5463932Sbinkertn@umich.edu if isinstance(value, str): 5473932Sbinkertn@umich.edu self.value = convert.toInteger(value) 5483932Sbinkertn@umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 5493932Sbinkertn@umich.edu self.value = long(value) 5503932Sbinkertn@umich.edu else: 5513932Sbinkertn@umich.edu raise TypeError("Can't convert object of type %s to CheckedInt" \ 5523932Sbinkertn@umich.edu % type(value).__name__) 5533932Sbinkertn@umich.edu self._check() 5543885Sbinkertn@umich.edu 5553885Sbinkertn@umich.edu def __call__(self, value): 5563885Sbinkertn@umich.edu self.__init__(value) 5573885Sbinkertn@umich.edu return value 5583885Sbinkertn@umich.edu 5593885Sbinkertn@umich.edu @classmethod 5603932Sbinkertn@umich.edu def cxx_predecls(cls, code): 5613885Sbinkertn@umich.edu # most derived types require this, so we just do it here once 5623885Sbinkertn@umich.edu code('#include "base/types.hh"') 5633932Sbinkertn@umich.edu 5643932Sbinkertn@umich.edu def getValue(self): 5653885Sbinkertn@umich.edu return long(self.value) 5663885Sbinkertn@umich.edu 5673932Sbinkertn@umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 5683885Sbinkertn@umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 5693101Sstever@eecs.umich.edu 5703101Sstever@eecs.umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 5713101Sstever@eecs.umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 5723101Sstever@eecs.umich.educlass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 5733101Sstever@eecs.umich.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5743101Sstever@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 5753101Sstever@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 5763101Sstever@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 5773101Sstever@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 5783101Sstever@eecs.umich.edu 5793101Sstever@eecs.umich.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 5803101Sstever@eecs.umich.educlass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 5813101Sstever@eecs.umich.educlass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5823101Sstever@eecs.umich.educlass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5833101Sstever@eecs.umich.edu 5843101Sstever@eecs.umich.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 5853101Sstever@eecs.umich.edu 5863101Sstever@eecs.umich.educlass Cycles(CheckedInt): 5873101Sstever@eecs.umich.edu cxx_type = 'Cycles' 5883101Sstever@eecs.umich.edu size = 64 5893101Sstever@eecs.umich.edu unsigned = True 5903101Sstever@eecs.umich.edu 5913101Sstever@eecs.umich.edu def getValue(self): 5923101Sstever@eecs.umich.edu from _m5.core import Cycles 5933101Sstever@eecs.umich.edu return Cycles(self.value) 5943101Sstever@eecs.umich.edu 5953101Sstever@eecs.umich.edu @classmethod 5963101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 5973101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 5983101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 5993101Sstever@eecs.umich.edu pass 6003101Sstever@eecs.umich.edu 6013101Sstever@eecs.umich.edu @classmethod 6023101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 6033101Sstever@eecs.umich.edu code('uint64_t _temp;') 6043101Sstever@eecs.umich.edu code('bool _ret = to_number(%s, _temp);' % src) 6053101Sstever@eecs.umich.edu code('if (_ret)') 6063101Sstever@eecs.umich.edu code(' %s = Cycles(_temp);' % dest) 6073101Sstever@eecs.umich.edu code('%s _ret;' % ret) 6083101Sstever@eecs.umich.edu 6093101Sstever@eecs.umich.educlass Float(ParamValue, float): 6103101Sstever@eecs.umich.edu cxx_type = 'double' 6113101Sstever@eecs.umich.edu cmd_line_settable = True 6123101Sstever@eecs.umich.edu 6133101Sstever@eecs.umich.edu def __init__(self, value): 6143101Sstever@eecs.umich.edu if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 6153101Sstever@eecs.umich.edu self.value = float(value) 6163101Sstever@eecs.umich.edu else: 6173101Sstever@eecs.umich.edu raise TypeError("Can't convert object of type %s to Float" \ 6183101Sstever@eecs.umich.edu % type(value).__name__) 6193101Sstever@eecs.umich.edu 6203101Sstever@eecs.umich.edu def __call__(self, value): 6213101Sstever@eecs.umich.edu self.__init__(value) 6223101Sstever@eecs.umich.edu return value 6233101Sstever@eecs.umich.edu 6243101Sstever@eecs.umich.edu def getValue(self): 6253101Sstever@eecs.umich.edu return float(self.value) 6263101Sstever@eecs.umich.edu 6273101Sstever@eecs.umich.edu def config_value(self): 6283101Sstever@eecs.umich.edu return self 6293101Sstever@eecs.umich.edu 6303101Sstever@eecs.umich.edu @classmethod 6313101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 6323101Sstever@eecs.umich.edu code('#include <sstream>') 6333101Sstever@eecs.umich.edu 6343101Sstever@eecs.umich.edu @classmethod 6353101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 6364167Sbinkertn@umich.edu code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 6373101Sstever@eecs.umich.edu 6383101Sstever@eecs.umich.educlass MemorySize(CheckedInt): 6393101Sstever@eecs.umich.edu cxx_type = 'uint64_t' 6403101Sstever@eecs.umich.edu ex_str = '512MB' 6414167Sbinkertn@umich.edu size = 64 6424167Sbinkertn@umich.edu unsigned = True 6433101Sstever@eecs.umich.edu def __init__(self, value): 6444167Sbinkertn@umich.edu if isinstance(value, MemorySize): 6454167Sbinkertn@umich.edu self.value = value.value 6464167Sbinkertn@umich.edu else: 6474167Sbinkertn@umich.edu self.value = convert.toMemorySize(value) 6484167Sbinkertn@umich.edu self._check() 6494167Sbinkertn@umich.edu 6504167Sbinkertn@umich.educlass MemorySize32(CheckedInt): 6514167Sbinkertn@umich.edu cxx_type = 'uint32_t' 6524167Sbinkertn@umich.edu ex_str = '512MB' 6534167Sbinkertn@umich.edu size = 32 6544167Sbinkertn@umich.edu unsigned = True 6554167Sbinkertn@umich.edu def __init__(self, value): 6563101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 6573101Sstever@eecs.umich.edu self.value = value.value 6583101Sstever@eecs.umich.edu else: 6593101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 6603101Sstever@eecs.umich.edu self._check() 6613101Sstever@eecs.umich.edu 6623101Sstever@eecs.umich.educlass Addr(CheckedInt): 6633101Sstever@eecs.umich.edu cxx_type = 'Addr' 6643101Sstever@eecs.umich.edu size = 64 6653101Sstever@eecs.umich.edu unsigned = True 6664167Sbinkertn@umich.edu def __init__(self, value): 6674167Sbinkertn@umich.edu if isinstance(value, Addr): 6684167Sbinkertn@umich.edu self.value = value.value 6694167Sbinkertn@umich.edu else: 6703101Sstever@eecs.umich.edu try: 6714167Sbinkertn@umich.edu # Often addresses are referred to with sizes. Ex: A device 6723101Sstever@eecs.umich.edu # base address is at "512MB". Use toMemorySize() to convert 6734167Sbinkertn@umich.edu # these into addresses. If the address is not specified with a 6744167Sbinkertn@umich.edu # "size", an exception will occur and numeric translation will 6754167Sbinkertn@umich.edu # proceed below. 6764167Sbinkertn@umich.edu self.value = convert.toMemorySize(value) 6774167Sbinkertn@umich.edu except (TypeError, ValueError): 6784167Sbinkertn@umich.edu # Convert number to string and use long() to do automatic 6794167Sbinkertn@umich.edu # base conversion (requires base=0 for auto-conversion) 6804167Sbinkertn@umich.edu self.value = long(str(value), base=0) 6814167Sbinkertn@umich.edu 6824167Sbinkertn@umich.edu self._check() 6834167Sbinkertn@umich.edu def __add__(self, other): 6844167Sbinkertn@umich.edu if isinstance(other, Addr): 6853101Sstever@eecs.umich.edu return self.value + other.value 6863101Sstever@eecs.umich.edu else: 6873101Sstever@eecs.umich.edu return self.value + other 6883101Sstever@eecs.umich.edu def pretty_print(self, value): 6893101Sstever@eecs.umich.edu try: 6903101Sstever@eecs.umich.edu val = convert.toMemorySize(value) 6913101Sstever@eecs.umich.edu except TypeError: 6923101Sstever@eecs.umich.edu val = long(value) 6934167Sbinkertn@umich.edu return "0x%x" % long(val) 6943101Sstever@eecs.umich.edu 6954167Sbinkertn@umich.educlass AddrRange(ParamValue): 6964167Sbinkertn@umich.edu cxx_type = 'AddrRange' 6974167Sbinkertn@umich.edu 6984167Sbinkertn@umich.edu def __init__(self, *args, **kwargs): 6993101Sstever@eecs.umich.edu # Disable interleaving and hashing by default 7003101Sstever@eecs.umich.edu self.intlvHighBit = 0 7013101Sstever@eecs.umich.edu self.xorHighBit = 0 7023101Sstever@eecs.umich.edu self.intlvBits = 0 7033101Sstever@eecs.umich.edu self.intlvMatch = 0 7043101Sstever@eecs.umich.edu 7053101Sstever@eecs.umich.edu def handle_kwargs(self, kwargs): 7063101Sstever@eecs.umich.edu # An address range needs to have an upper limit, specified 7073101Sstever@eecs.umich.edu # either explicitly with an end, or as an offset using the 7083101Sstever@eecs.umich.edu # size keyword. 7094167Sbinkertn@umich.edu if 'end' in kwargs: 7104167Sbinkertn@umich.edu self.end = Addr(kwargs.pop('end')) 7114167Sbinkertn@umich.edu elif 'size' in kwargs: 7124167Sbinkertn@umich.edu self.end = self.start + Addr(kwargs.pop('size')) - 1 7134167Sbinkertn@umich.edu else: 7144167Sbinkertn@umich.edu raise TypeError("Either end or size must be specified") 7154167Sbinkertn@umich.edu 7164167Sbinkertn@umich.edu # Now on to the optional bit 7174167Sbinkertn@umich.edu if 'intlvHighBit' in kwargs: 7184167Sbinkertn@umich.edu self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 7194167Sbinkertn@umich.edu if 'xorHighBit' in kwargs: 7204167Sbinkertn@umich.edu self.xorHighBit = int(kwargs.pop('xorHighBit')) 7213101Sstever@eecs.umich.edu if 'intlvBits' in kwargs: 7223101Sstever@eecs.umich.edu self.intlvBits = int(kwargs.pop('intlvBits')) 7233101Sstever@eecs.umich.edu if 'intlvMatch' in kwargs: 7243101Sstever@eecs.umich.edu self.intlvMatch = int(kwargs.pop('intlvMatch')) 7253101Sstever@eecs.umich.edu 7263101Sstever@eecs.umich.edu if len(args) == 0: 7273101Sstever@eecs.umich.edu self.start = Addr(kwargs.pop('start')) 7283101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 7293101Sstever@eecs.umich.edu 7303101Sstever@eecs.umich.edu elif len(args) == 1: 7313101Sstever@eecs.umich.edu if kwargs: 7323101Sstever@eecs.umich.edu self.start = Addr(args[0]) 7333101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 7343101Sstever@eecs.umich.edu elif isinstance(args[0], (list, tuple)): 7354167Sbinkertn@umich.edu self.start = Addr(args[0][0]) 7364167Sbinkertn@umich.edu self.end = Addr(args[0][1]) 7373101Sstever@eecs.umich.edu else: 7383101Sstever@eecs.umich.edu self.start = Addr(0) 7393101Sstever@eecs.umich.edu self.end = Addr(args[0]) - 1 7403101Sstever@eecs.umich.edu 7413101Sstever@eecs.umich.edu elif len(args) == 2: 7423101Sstever@eecs.umich.edu self.start = Addr(args[0]) 7434167Sbinkertn@umich.edu self.end = Addr(args[1]) 7444167Sbinkertn@umich.edu else: 7454167Sbinkertn@umich.edu raise TypeError("Too many arguments specified") 7464167Sbinkertn@umich.edu 7473101Sstever@eecs.umich.edu if kwargs: 7483101Sstever@eecs.umich.edu raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 7493101Sstever@eecs.umich.edu 7503101Sstever@eecs.umich.edu def __str__(self): 7514167Sbinkertn@umich.edu return '%s:%s:%s:%s:%s:%s' \ 7523102Sstever@eecs.umich.edu % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 7533101Sstever@eecs.umich.edu self.intlvBits, self.intlvMatch) 7543101Sstever@eecs.umich.edu 7553101Sstever@eecs.umich.edu def size(self): 7563101Sstever@eecs.umich.edu # Divide the size by the size of the interleaving slice 7573101Sstever@eecs.umich.edu return (long(self.end) - long(self.start) + 1) >> self.intlvBits 7583101Sstever@eecs.umich.edu 7594167Sbinkertn@umich.edu @classmethod 7604167Sbinkertn@umich.edu def cxx_predecls(cls, code): 7614167Sbinkertn@umich.edu Addr.cxx_predecls(code) 7624167Sbinkertn@umich.edu code('#include "base/addr_range.hh"') 7633101Sstever@eecs.umich.edu 7643101Sstever@eecs.umich.edu @classmethod 7653101Sstever@eecs.umich.edu def pybind_predecls(cls, code): 7663101Sstever@eecs.umich.edu Addr.pybind_predecls(code) 7673101Sstever@eecs.umich.edu code('#include "base/addr_range.hh"') 7683102Sstever@eecs.umich.edu 7693102Sstever@eecs.umich.edu @classmethod 7703102Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 7713102Sstever@eecs.umich.edu code('#include <sstream>') 7723102Sstever@eecs.umich.edu 7733102Sstever@eecs.umich.edu @classmethod 7743102Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 7753102Sstever@eecs.umich.edu code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 7763102Sstever@eecs.umich.edu code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 7773102Sstever@eecs.umich.edu code('char _sep;') 7783102Sstever@eecs.umich.edu code('std::istringstream _stream(${src});') 7793102Sstever@eecs.umich.edu code('_stream >> _start;') 7803102Sstever@eecs.umich.edu code('_stream.get(_sep);') 7813102Sstever@eecs.umich.edu code('_stream >> _end;') 7823102Sstever@eecs.umich.edu code('if (!_stream.fail() && !_stream.eof()) {') 7833102Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7843102Sstever@eecs.umich.edu code(' _stream >> _intlvHighBit;') 7853102Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7863102Sstever@eecs.umich.edu code(' _stream >> _xorHighBit;') 7873102Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7883102Sstever@eecs.umich.edu code(' _stream >> _intlvBits;') 7893102Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7903102Sstever@eecs.umich.edu code(' _stream >> _intlvMatch;') 7913102Sstever@eecs.umich.edu code('}') 7923102Sstever@eecs.umich.edu code('bool _ret = !_stream.fail() &&' 7933102Sstever@eecs.umich.edu '_stream.eof() && _sep == \':\';') 7943102Sstever@eecs.umich.edu code('if (_ret)') 7953102Sstever@eecs.umich.edu code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 7963102Sstever@eecs.umich.edu _xorHighBit, _intlvBits, _intlvMatch);') 7973102Sstever@eecs.umich.edu code('${ret} _ret;') 7983101Sstever@eecs.umich.edu 7993101Sstever@eecs.umich.edu def getValue(self): 8003101Sstever@eecs.umich.edu # Go from the Python class to the wrapped C++ class 8013101Sstever@eecs.umich.edu from _m5.range import AddrRange 8023101Sstever@eecs.umich.edu 8033101Sstever@eecs.umich.edu return AddrRange(long(self.start), long(self.end), 8043101Sstever@eecs.umich.edu int(self.intlvHighBit), int(self.xorHighBit), 8053101Sstever@eecs.umich.edu int(self.intlvBits), int(self.intlvMatch)) 8063101Sstever@eecs.umich.edu 8073101Sstever@eecs.umich.edu# Boolean parameter type. Python doesn't let you subclass bool, since 8083101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and 8093101Sstever@eecs.umich.edu# False. Thus this is a little more complicated than String. 8103101Sstever@eecs.umich.educlass Bool(ParamValue): 8113101Sstever@eecs.umich.edu cxx_type = 'bool' 8123101Sstever@eecs.umich.edu cmd_line_settable = True 8133101Sstever@eecs.umich.edu 8143101Sstever@eecs.umich.edu def __init__(self, value): 8153105Sstever@eecs.umich.edu try: 8163105Sstever@eecs.umich.edu self.value = convert.toBool(value) 8173101Sstever@eecs.umich.edu except TypeError: 8183101Sstever@eecs.umich.edu self.value = bool(value) 8193101Sstever@eecs.umich.edu 8203101Sstever@eecs.umich.edu def __call__(self, value): 8213105Sstever@eecs.umich.edu self.__init__(value) 8223101Sstever@eecs.umich.edu return value 8233103Sstever@eecs.umich.edu 8243105Sstever@eecs.umich.edu def getValue(self): 8253103Sstever@eecs.umich.edu return bool(self.value) 8263105Sstever@eecs.umich.edu 8273105Sstever@eecs.umich.edu def __str__(self): 8283105Sstever@eecs.umich.edu return str(self.value) 8293105Sstever@eecs.umich.edu 8303105Sstever@eecs.umich.edu # implement truth value testing for Bool parameters so that these params 8313105Sstever@eecs.umich.edu # evaluate correctly during the python configuration phase 8323105Sstever@eecs.umich.edu def __bool__(self): 8333105Sstever@eecs.umich.edu return bool(self.value) 8343105Sstever@eecs.umich.edu 8353105Sstever@eecs.umich.edu # Python 2.7 uses __nonzero__ instead of __bool__ 8363105Sstever@eecs.umich.edu __nonzero__ = __bool__ 8373105Sstever@eecs.umich.edu 8383105Sstever@eecs.umich.edu def ini_str(self): 8393109Sstever@eecs.umich.edu if self.value: 8403105Sstever@eecs.umich.edu return 'true' 8413105Sstever@eecs.umich.edu return 'false' 8423105Sstever@eecs.umich.edu 8433105Sstever@eecs.umich.edu def config_value(self): 8443105Sstever@eecs.umich.edu return self.value 8453105Sstever@eecs.umich.edu 8463105Sstever@eecs.umich.edu @classmethod 8473105Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 8483101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 8493109Sstever@eecs.umich.edu # code('#include "base/str.hh"') 8503109Sstever@eecs.umich.edu pass 8513109Sstever@eecs.umich.edu 8523109Sstever@eecs.umich.edu @classmethod 8533109Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 8543109Sstever@eecs.umich.edu code('%s to_bool(%s, %s);' % (ret, src, dest)) 8553109Sstever@eecs.umich.edu 8563109Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1): 8573109Sstever@eecs.umich.edu bytes = map(lambda x: int(x, 16), addr.split(':')) 8583101Sstever@eecs.umich.edu bytes[5] += val 8593105Sstever@eecs.umich.edu for i in (5, 4, 3, 2, 1): 8603105Sstever@eecs.umich.edu val,rem = divmod(bytes[i], 256) 8613105Sstever@eecs.umich.edu bytes[i] = rem 8623101Sstever@eecs.umich.edu if val == 0: 8633105Sstever@eecs.umich.edu break 8643105Sstever@eecs.umich.edu bytes[i - 1] += val 8653101Sstever@eecs.umich.edu assert(bytes[0] <= 255) 8663105Sstever@eecs.umich.edu return ':'.join(map(lambda x: '%02x' % x, bytes)) 8673179Sstever@eecs.umich.edu 8683105Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01" 8693105Sstever@eecs.umich.edudef NextEthernetAddr(): 8703101Sstever@eecs.umich.edu global _NextEthernetAddr 8713101Sstever@eecs.umich.edu 8723105Sstever@eecs.umich.edu value = _NextEthernetAddr 8733105Sstever@eecs.umich.edu _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 8743105Sstever@eecs.umich.edu return value 8753105Sstever@eecs.umich.edu 8763105Sstever@eecs.umich.educlass EthernetAddr(ParamValue): 8773105Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 8783105Sstever@eecs.umich.edu ex_str = "00:90:00:00:00:01" 8793105Sstever@eecs.umich.edu cmd_line_settable = True 8803105Sstever@eecs.umich.edu 8813105Sstever@eecs.umich.edu @classmethod 8823105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 8833101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 8843101Sstever@eecs.umich.edu 8853101Sstever@eecs.umich.edu def __init__(self, value): 8863101Sstever@eecs.umich.edu if value == NextEthernetAddr: 8873101Sstever@eecs.umich.edu self.value = value 8884123Sbinkertn@umich.edu return 8894123Sbinkertn@umich.edu 8903101Sstever@eecs.umich.edu if not isinstance(value, str): 8913101Sstever@eecs.umich.edu raise TypeError("expected an ethernet address and didn't get one") 8923101Sstever@eecs.umich.edu 8933105Sstever@eecs.umich.edu bytes = value.split(':') 8943105Sstever@eecs.umich.edu if len(bytes) != 6: 8953105Sstever@eecs.umich.edu raise TypeError('invalid ethernet address %s' % value) 8963105Sstever@eecs.umich.edu 8973105Sstever@eecs.umich.edu for byte in bytes: 8983105Sstever@eecs.umich.edu if not 0 <= int(byte, base=16) <= 0xff: 8993105Sstever@eecs.umich.edu raise TypeError('invalid ethernet address %s' % value) 9003105Sstever@eecs.umich.edu 9013105Sstever@eecs.umich.edu self.value = value 9023105Sstever@eecs.umich.edu 9033105Sstever@eecs.umich.edu def __call__(self, value): 9043105Sstever@eecs.umich.edu self.__init__(value) 9053105Sstever@eecs.umich.edu return value 9063105Sstever@eecs.umich.edu 9073105Sstever@eecs.umich.edu def unproxy(self, base): 9083105Sstever@eecs.umich.edu if self.value == NextEthernetAddr: 9093105Sstever@eecs.umich.edu return EthernetAddr(self.value()) 9103105Sstever@eecs.umich.edu return self 9113105Sstever@eecs.umich.edu 9123109Sstever@eecs.umich.edu def getValue(self): 9133109Sstever@eecs.umich.edu from _m5.net import EthAddr 9143109Sstever@eecs.umich.edu return EthAddr(self.value) 9153105Sstever@eecs.umich.edu 9163105Sstever@eecs.umich.edu def __str__(self): 9173105Sstever@eecs.umich.edu return self.value 9183105Sstever@eecs.umich.edu 9193105Sstever@eecs.umich.edu def ini_str(self): 9203105Sstever@eecs.umich.edu return self.value 9213105Sstever@eecs.umich.edu 9223105Sstever@eecs.umich.edu @classmethod 9233105Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 9243105Sstever@eecs.umich.edu code('%s = Net::EthAddr(%s);' % (dest, src)) 9253105Sstever@eecs.umich.edu code('%s true;' % ret) 9263105Sstever@eecs.umich.edu 9273105Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of 9283105Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP. 9293105Sstever@eecs.umich.educlass IpAddress(ParamValue): 9303105Sstever@eecs.umich.edu cxx_type = 'Net::IpAddress' 9313105Sstever@eecs.umich.edu ex_str = "127.0.0.1" 9323105Sstever@eecs.umich.edu cmd_line_settable = True 9333105Sstever@eecs.umich.edu 9343105Sstever@eecs.umich.edu @classmethod 9353105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 9363105Sstever@eecs.umich.edu code('#include "base/inet.hh"') 9373105Sstever@eecs.umich.edu 9383109Sstever@eecs.umich.edu def __init__(self, value): 9393109Sstever@eecs.umich.edu if isinstance(value, IpAddress): 9403109Sstever@eecs.umich.edu self.ip = value.ip 9413109Sstever@eecs.umich.edu else: 9423109Sstever@eecs.umich.edu try: 9433109Sstever@eecs.umich.edu self.ip = convert.toIpAddress(value) 9443109Sstever@eecs.umich.edu except TypeError: 9453109Sstever@eecs.umich.edu self.ip = long(value) 9463109Sstever@eecs.umich.edu self.verifyIp() 9473109Sstever@eecs.umich.edu 9483109Sstever@eecs.umich.edu def __call__(self, value): 9493109Sstever@eecs.umich.edu self.__init__(value) 9503109Sstever@eecs.umich.edu return value 9513109Sstever@eecs.umich.edu 9523109Sstever@eecs.umich.edu def __str__(self): 9533109Sstever@eecs.umich.edu tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 9543109Sstever@eecs.umich.edu return '%d.%d.%d.%d' % tuple(tup) 9553109Sstever@eecs.umich.edu 9563109Sstever@eecs.umich.edu def __eq__(self, other): 9573105Sstever@eecs.umich.edu if isinstance(other, IpAddress): 9583105Sstever@eecs.umich.edu return self.ip == other.ip 9593105Sstever@eecs.umich.edu elif isinstance(other, str): 9603105Sstever@eecs.umich.edu try: 9613105Sstever@eecs.umich.edu return self.ip == convert.toIpAddress(other) 9623105Sstever@eecs.umich.edu except: 9633105Sstever@eecs.umich.edu return False 9643101Sstever@eecs.umich.edu else: 9653101Sstever@eecs.umich.edu return self.ip == other 9663101Sstever@eecs.umich.edu 9673101Sstever@eecs.umich.edu def __ne__(self, other): 9683105Sstever@eecs.umich.edu return not (self == other) 9693105Sstever@eecs.umich.edu 9703105Sstever@eecs.umich.edu def verifyIp(self): 9713105Sstever@eecs.umich.edu if self.ip < 0 or self.ip >= (1 << 32): 9723105Sstever@eecs.umich.edu raise TypeError("invalid ip address %#08x" % self.ip) 9733105Sstever@eecs.umich.edu 9743105Sstever@eecs.umich.edu def getValue(self): 9753105Sstever@eecs.umich.edu from _m5.net import IpAddress 9763105Sstever@eecs.umich.edu return IpAddress(self.ip) 9773105Sstever@eecs.umich.edu 9783105Sstever@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 9793101Sstever@eecs.umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 9803101Sstever@eecs.umich.edu# positional or keyword arguments. 9813101Sstever@eecs.umich.educlass IpNetmask(IpAddress): 9823105Sstever@eecs.umich.edu cxx_type = 'Net::IpNetmask' 9833105Sstever@eecs.umich.edu ex_str = "127.0.0.0/24" 9843101Sstever@eecs.umich.edu cmd_line_settable = True 9853101Sstever@eecs.umich.edu 9863101Sstever@eecs.umich.edu @classmethod 9873105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 9883105Sstever@eecs.umich.edu code('#include "base/inet.hh"') 9893101Sstever@eecs.umich.edu 9903101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 9913101Sstever@eecs.umich.edu def handle_kwarg(self, kwargs, key, elseVal = None): 9923101Sstever@eecs.umich.edu if key in kwargs: 9933105Sstever@eecs.umich.edu setattr(self, key, kwargs.pop(key)) 9943105Sstever@eecs.umich.edu elif elseVal: 9953101Sstever@eecs.umich.edu setattr(self, key, elseVal) 9963101Sstever@eecs.umich.edu else: 9973105Sstever@eecs.umich.edu raise TypeError("No value set for %s" % key) 9983105Sstever@eecs.umich.edu 9993105Sstever@eecs.umich.edu if len(args) == 0: 10003109Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip') 10013109Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'netmask') 10023109Sstever@eecs.umich.edu 10033109Sstever@eecs.umich.edu elif len(args) == 1: 10043109Sstever@eecs.umich.edu if kwargs: 10053109Sstever@eecs.umich.edu if not 'ip' in kwargs and not 'netmask' in kwargs: 10063109Sstever@eecs.umich.edu raise TypeError("Invalid arguments") 10073109Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 10083105Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'netmask', args[0]) 10093101Sstever@eecs.umich.edu elif isinstance(args[0], IpNetmask): 10103101Sstever@eecs.umich.edu self.ip = args[0].ip 10113101Sstever@eecs.umich.edu self.netmask = args[0].netmask 10123101Sstever@eecs.umich.edu else: 10133101Sstever@eecs.umich.edu (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 10143101Sstever@eecs.umich.edu 10153101Sstever@eecs.umich.edu elif len(args) == 2: 10163101Sstever@eecs.umich.edu self.ip = args[0] 10174167Sbinkertn@umich.edu self.netmask = args[1] 10183101Sstever@eecs.umich.edu else: 10193101Sstever@eecs.umich.edu raise TypeError("Too many arguments specified") 10203101Sstever@eecs.umich.edu 10213885Sbinkertn@umich.edu if kwargs: 10223102Sstever@eecs.umich.edu raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 10233101Sstever@eecs.umich.edu 10243101Sstever@eecs.umich.edu self.verify() 10253101Sstever@eecs.umich.edu 10263102Sstever@eecs.umich.edu def __call__(self, value): 10273102Sstever@eecs.umich.edu self.__init__(value) 10283624Sbinkertn@umich.edu return value 1029 1030 def __str__(self): 1031 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1032 1033 def __eq__(self, other): 1034 if isinstance(other, IpNetmask): 1035 return self.ip == other.ip and self.netmask == other.netmask 1036 elif isinstance(other, str): 1037 try: 1038 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1039 except: 1040 return False 1041 else: 1042 return False 1043 1044 def verify(self): 1045 self.verifyIp() 1046 if self.netmask < 0 or self.netmask > 32: 1047 raise TypeError("invalid netmask %d" % netmask) 1048 1049 def getValue(self): 1050 from _m5.net import IpNetmask 1051 return IpNetmask(self.ip, self.netmask) 1052 1053# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1054# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1055class IpWithPort(IpAddress): 1056 cxx_type = 'Net::IpWithPort' 1057 ex_str = "127.0.0.1:80" 1058 cmd_line_settable = True 1059 1060 @classmethod 1061 def cxx_predecls(cls, code): 1062 code('#include "base/inet.hh"') 1063 1064 def __init__(self, *args, **kwargs): 1065 def handle_kwarg(self, kwargs, key, elseVal = None): 1066 if key in kwargs: 1067 setattr(self, key, kwargs.pop(key)) 1068 elif elseVal: 1069 setattr(self, key, elseVal) 1070 else: 1071 raise TypeError("No value set for %s" % key) 1072 1073 if len(args) == 0: 1074 handle_kwarg(self, kwargs, 'ip') 1075 handle_kwarg(self, kwargs, 'port') 1076 1077 elif len(args) == 1: 1078 if kwargs: 1079 if not 'ip' in kwargs and not 'port' in kwargs: 1080 raise TypeError("Invalid arguments") 1081 handle_kwarg(self, kwargs, 'ip', args[0]) 1082 handle_kwarg(self, kwargs, 'port', args[0]) 1083 elif isinstance(args[0], IpWithPort): 1084 self.ip = args[0].ip 1085 self.port = args[0].port 1086 else: 1087 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1088 1089 elif len(args) == 2: 1090 self.ip = args[0] 1091 self.port = args[1] 1092 else: 1093 raise TypeError("Too many arguments specified") 1094 1095 if kwargs: 1096 raise TypeError("Too many keywords: %s" % list(kwargs.keys())) 1097 1098 self.verify() 1099 1100 def __call__(self, value): 1101 self.__init__(value) 1102 return value 1103 1104 def __str__(self): 1105 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1106 1107 def __eq__(self, other): 1108 if isinstance(other, IpWithPort): 1109 return self.ip == other.ip and self.port == other.port 1110 elif isinstance(other, str): 1111 try: 1112 return (self.ip, self.port) == convert.toIpWithPort(other) 1113 except: 1114 return False 1115 else: 1116 return False 1117 1118 def verify(self): 1119 self.verifyIp() 1120 if self.port < 0 or self.port > 0xffff: 1121 raise TypeError("invalid port %d" % self.port) 1122 1123 def getValue(self): 1124 from _m5.net import IpWithPort 1125 return IpWithPort(self.ip, self.port) 1126 1127time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1128 "%a %b %d %H:%M:%S %Y", 1129 "%Y/%m/%d %H:%M:%S", 1130 "%Y/%m/%d %H:%M", 1131 "%Y/%m/%d", 1132 "%m/%d/%Y %H:%M:%S", 1133 "%m/%d/%Y %H:%M", 1134 "%m/%d/%Y", 1135 "%m/%d/%y %H:%M:%S", 1136 "%m/%d/%y %H:%M", 1137 "%m/%d/%y"] 1138 1139 1140def parse_time(value): 1141 from time import gmtime, strptime, struct_time, time 1142 from datetime import datetime, date 1143 1144 if isinstance(value, struct_time): 1145 return value 1146 1147 if isinstance(value, (int, long)): 1148 return gmtime(value) 1149 1150 if isinstance(value, (datetime, date)): 1151 return value.timetuple() 1152 1153 if isinstance(value, str): 1154 if value in ('Now', 'Today'): 1155 return time.gmtime(time.time()) 1156 1157 for format in time_formats: 1158 try: 1159 return strptime(value, format) 1160 except ValueError: 1161 pass 1162 1163 raise ValueError("Could not parse '%s' as a time" % value) 1164 1165class Time(ParamValue): 1166 cxx_type = 'tm' 1167 1168 @classmethod 1169 def cxx_predecls(cls, code): 1170 code('#include <time.h>') 1171 1172 def __init__(self, value): 1173 self.value = parse_time(value) 1174 1175 def __call__(self, value): 1176 self.__init__(value) 1177 return value 1178 1179 def getValue(self): 1180 from _m5.core import tm 1181 import calendar 1182 1183 return tm.gmtime(calendar.timegm(self.value)) 1184 1185 def __str__(self): 1186 return time.asctime(self.value) 1187 1188 def ini_str(self): 1189 return str(self) 1190 1191 def get_config_as_dict(self): 1192 assert false 1193 return str(self) 1194 1195 @classmethod 1196 def cxx_ini_predecls(cls, code): 1197 code('#include <time.h>') 1198 1199 @classmethod 1200 def cxx_ini_parse(cls, code, src, dest, ret): 1201 code('char *_parse_ret = strptime((${src}).c_str(),') 1202 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1203 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1204 1205# Enumerated types are a little more complex. The user specifies the 1206# type as Enum(foo) where foo is either a list or dictionary of 1207# alternatives (typically strings, but not necessarily so). (In the 1208# long run, the integer value of the parameter will be the list index 1209# or the corresponding dictionary value. For now, since we only check 1210# that the alternative is valid and then spit it into a .ini file, 1211# there's not much point in using the dictionary.) 1212 1213# What Enum() must do is generate a new type encapsulating the 1214# provided list/dictionary so that specific values of the parameter 1215# can be instances of that type. We define two hidden internal 1216# classes (_ListEnum and _DictEnum) to serve as base classes, then 1217# derive the new type from the appropriate base class on the fly. 1218 1219allEnums = {} 1220# Metaclass for Enum types 1221class MetaEnum(MetaParamValue): 1222 def __new__(mcls, name, bases, dict): 1223 assert name not in allEnums 1224 1225 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1226 allEnums[name] = cls 1227 return cls 1228 1229 def __init__(cls, name, bases, init_dict): 1230 if 'map' in init_dict: 1231 if not isinstance(cls.map, dict): 1232 raise TypeError("Enum-derived class attribute 'map' " \ 1233 "must be of type dict") 1234 # build list of value strings from map 1235 cls.vals = cls.map.keys() 1236 cls.vals.sort() 1237 elif 'vals' in init_dict: 1238 if not isinstance(cls.vals, list): 1239 raise TypeError("Enum-derived class attribute 'vals' " \ 1240 "must be of type list") 1241 # build string->value map from vals sequence 1242 cls.map = {} 1243 for idx,val in enumerate(cls.vals): 1244 cls.map[val] = idx 1245 else: 1246 raise TypeError("Enum-derived class must define "\ 1247 "attribute 'map' or 'vals'") 1248 1249 if cls.is_class: 1250 cls.cxx_type = '%s' % name 1251 else: 1252 cls.cxx_type = 'Enums::%s' % name 1253 1254 super(MetaEnum, cls).__init__(name, bases, init_dict) 1255 1256 # Generate C++ class declaration for this enum type. 1257 # Note that we wrap the enum in a class/struct to act as a namespace, 1258 # so that the enum strings can be brief w/o worrying about collisions. 1259 def cxx_decl(cls, code): 1260 wrapper_name = cls.wrapper_name 1261 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1262 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1263 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1264 1265 code('''\ 1266#ifndef $idem_macro 1267#define $idem_macro 1268 1269''') 1270 if cls.is_class: 1271 code('''\ 1272enum class $name { 1273''') 1274 else: 1275 code('''\ 1276$wrapper $wrapper_name { 1277 enum $name { 1278''') 1279 code.indent(1) 1280 code.indent(1) 1281 for val in cls.vals: 1282 code('$val = ${{cls.map[val]}},') 1283 code('Num_$name = ${{len(cls.vals)}}') 1284 code.dedent(1) 1285 code('};') 1286 1287 if cls.is_class: 1288 code('''\ 1289extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})]; 1290''') 1291 elif cls.wrapper_is_struct: 1292 code('static const char *${name}Strings[Num_${name}];') 1293 else: 1294 code('extern const char *${name}Strings[Num_${name}];') 1295 1296 if not cls.is_class: 1297 code.dedent(1) 1298 code('};') 1299 1300 code() 1301 code('#endif // $idem_macro') 1302 1303 def cxx_def(cls, code): 1304 wrapper_name = cls.wrapper_name 1305 file_name = cls.__name__ 1306 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1307 1308 code('#include "enums/$file_name.hh"') 1309 if cls.wrapper_is_struct: 1310 code('const char *${wrapper_name}::${name}Strings' 1311 '[Num_${name}] =') 1312 else: 1313 if cls.is_class: 1314 code('''\ 1315const char *${name}Strings[static_cast<int>(${name}::Num_${name})] = 1316''') 1317 else: 1318 code('namespace Enums {') 1319 code.indent(1) 1320 code('const char *${name}Strings[Num_${name}] =') 1321 1322 code('{') 1323 code.indent(1) 1324 for val in cls.vals: 1325 code('"$val",') 1326 code.dedent(1) 1327 code('};') 1328 1329 if not cls.wrapper_is_struct and not cls.is_class: 1330 code.dedent(1) 1331 code('} // namespace $wrapper_name') 1332 1333 1334 def pybind_def(cls, code): 1335 name = cls.__name__ 1336 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1337 wrapper_name = enum_name if cls.is_class else cls.wrapper_name 1338 1339 code('''#include "pybind11/pybind11.h" 1340#include "pybind11/stl.h" 1341 1342#include <sim/init.hh> 1343 1344namespace py = pybind11; 1345 1346static void 1347module_init(py::module &m_internal) 1348{ 1349 py::module m = m_internal.def_submodule("enum_${name}"); 1350 1351''') 1352 if cls.is_class: 1353 code('py::enum_<${enum_name}>(m, "enum_${name}")') 1354 else: 1355 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")') 1356 1357 code.indent() 1358 code.indent() 1359 for val in cls.vals: 1360 code('.value("${val}", ${wrapper_name}::${val})') 1361 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1362 code('.export_values()') 1363 code(';') 1364 code.dedent() 1365 1366 code('}') 1367 code.dedent() 1368 code() 1369 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1370 1371 1372# Base class for enum types. 1373class Enum(ParamValue): 1374 __metaclass__ = MetaEnum 1375 vals = [] 1376 cmd_line_settable = True 1377 1378 # The name of the wrapping namespace or struct 1379 wrapper_name = 'Enums' 1380 1381 # If true, the enum is wrapped in a struct rather than a namespace 1382 wrapper_is_struct = False 1383 1384 is_class = False 1385 1386 # If not None, use this as the enum name rather than this class name 1387 enum_name = None 1388 1389 def __init__(self, value): 1390 if value not in self.map: 1391 raise TypeError("Enum param got bad value '%s' (not in %s)" \ 1392 % (value, self.vals)) 1393 self.value = value 1394 1395 def __call__(self, value): 1396 self.__init__(value) 1397 return value 1398 1399 @classmethod 1400 def cxx_predecls(cls, code): 1401 code('#include "enums/$0.hh"', cls.__name__) 1402 1403 @classmethod 1404 def cxx_ini_parse(cls, code, src, dest, ret): 1405 code('if (false) {') 1406 for elem_name in cls.map.iterkeys(): 1407 code('} else if (%s == "%s") {' % (src, elem_name)) 1408 code.indent() 1409 code('%s = Enums::%s;' % (dest, elem_name)) 1410 code('%s true;' % ret) 1411 code.dedent() 1412 code('} else {') 1413 code(' %s false;' % ret) 1414 code('}') 1415 1416 def getValue(self): 1417 import m5.internal.params 1418 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1419 return e(self.map[self.value]) 1420 1421 def __str__(self): 1422 return self.value 1423 1424# This param will generate a scoped c++ enum and its python bindings. 1425class ScopedEnum(Enum): 1426 __metaclass__ = MetaEnum 1427 vals = [] 1428 cmd_line_settable = True 1429 1430 # The name of the wrapping namespace or struct 1431 wrapper_name = None 1432 1433 # If true, the enum is wrapped in a struct rather than a namespace 1434 wrapper_is_struct = False 1435 1436 # If true, the generated enum is a scoped enum 1437 is_class = True 1438 1439 # If not None, use this as the enum name rather than this class name 1440 enum_name = None 1441 1442# how big does a rounding error need to be before we warn about it? 1443frequency_tolerance = 0.001 # 0.1% 1444 1445class TickParamValue(NumericParamValue): 1446 cxx_type = 'Tick' 1447 ex_str = "1MHz" 1448 cmd_line_settable = True 1449 1450 @classmethod 1451 def cxx_predecls(cls, code): 1452 code('#include "base/types.hh"') 1453 1454 def __call__(self, value): 1455 self.__init__(value) 1456 return value 1457 1458 def getValue(self): 1459 return long(self.value) 1460 1461 @classmethod 1462 def cxx_ini_predecls(cls, code): 1463 code('#include <sstream>') 1464 1465 # Ticks are expressed in seconds in JSON files and in plain 1466 # Ticks in .ini files. Switch based on a config flag 1467 @classmethod 1468 def cxx_ini_parse(self, code, src, dest, ret): 1469 code('${ret} to_number(${src}, ${dest});') 1470 1471class Latency(TickParamValue): 1472 ex_str = "100ns" 1473 1474 def __init__(self, value): 1475 if isinstance(value, (Latency, Clock)): 1476 self.ticks = value.ticks 1477 self.value = value.value 1478 elif isinstance(value, Frequency): 1479 self.ticks = value.ticks 1480 self.value = 1.0 / value.value 1481 elif value.endswith('t'): 1482 self.ticks = True 1483 self.value = int(value[:-1]) 1484 else: 1485 self.ticks = False 1486 self.value = convert.toLatency(value) 1487 1488 def __call__(self, value): 1489 self.__init__(value) 1490 return value 1491 1492 def __getattr__(self, attr): 1493 if attr in ('latency', 'period'): 1494 return self 1495 if attr == 'frequency': 1496 return Frequency(self) 1497 raise AttributeError("Latency object has no attribute '%s'" % attr) 1498 1499 def getValue(self): 1500 if self.ticks or self.value == 0: 1501 value = self.value 1502 else: 1503 value = ticks.fromSeconds(self.value) 1504 return long(value) 1505 1506 def config_value(self): 1507 return self.getValue() 1508 1509 # convert latency to ticks 1510 def ini_str(self): 1511 return '%d' % self.getValue() 1512 1513class Frequency(TickParamValue): 1514 ex_str = "1GHz" 1515 1516 def __init__(self, value): 1517 if isinstance(value, (Latency, Clock)): 1518 if value.value == 0: 1519 self.value = 0 1520 else: 1521 self.value = 1.0 / value.value 1522 self.ticks = value.ticks 1523 elif isinstance(value, Frequency): 1524 self.value = value.value 1525 self.ticks = value.ticks 1526 else: 1527 self.ticks = False 1528 self.value = convert.toFrequency(value) 1529 1530 def __call__(self, value): 1531 self.__init__(value) 1532 return value 1533 1534 def __getattr__(self, attr): 1535 if attr == 'frequency': 1536 return self 1537 if attr in ('latency', 'period'): 1538 return Latency(self) 1539 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1540 1541 # convert latency to ticks 1542 def getValue(self): 1543 if self.ticks or self.value == 0: 1544 value = self.value 1545 else: 1546 value = ticks.fromSeconds(1.0 / self.value) 1547 return long(value) 1548 1549 def config_value(self): 1550 return self.getValue() 1551 1552 def ini_str(self): 1553 return '%d' % self.getValue() 1554 1555# A generic Frequency and/or Latency value. Value is stored as a 1556# latency, just like Latency and Frequency. 1557class Clock(TickParamValue): 1558 def __init__(self, value): 1559 if isinstance(value, (Latency, Clock)): 1560 self.ticks = value.ticks 1561 self.value = value.value 1562 elif isinstance(value, Frequency): 1563 self.ticks = value.ticks 1564 self.value = 1.0 / value.value 1565 elif value.endswith('t'): 1566 self.ticks = True 1567 self.value = int(value[:-1]) 1568 else: 1569 self.ticks = False 1570 self.value = convert.anyToLatency(value) 1571 1572 def __call__(self, value): 1573 self.__init__(value) 1574 return value 1575 1576 def __str__(self): 1577 return "%s" % Latency(self) 1578 1579 def __getattr__(self, attr): 1580 if attr == 'frequency': 1581 return Frequency(self) 1582 if attr in ('latency', 'period'): 1583 return Latency(self) 1584 raise AttributeError("Frequency object has no attribute '%s'" % attr) 1585 1586 def getValue(self): 1587 return self.period.getValue() 1588 1589 def config_value(self): 1590 return self.period.config_value() 1591 1592 def ini_str(self): 1593 return self.period.ini_str() 1594 1595class Voltage(Float): 1596 ex_str = "1V" 1597 1598 def __new__(cls, value): 1599 value = convert.toVoltage(value) 1600 return super(cls, Voltage).__new__(cls, value) 1601 1602 def __init__(self, value): 1603 value = convert.toVoltage(value) 1604 super(Voltage, self).__init__(value) 1605 1606class Current(Float): 1607 ex_str = "1mA" 1608 1609 def __new__(cls, value): 1610 value = convert.toCurrent(value) 1611 return super(cls, Current).__new__(cls, value) 1612 1613 def __init__(self, value): 1614 value = convert.toCurrent(value) 1615 super(Current, self).__init__(value) 1616 1617class Energy(Float): 1618 ex_str = "1pJ" 1619 1620 def __new__(cls, value): 1621 value = convert.toEnergy(value) 1622 return super(cls, Energy).__new__(cls, value) 1623 1624 def __init__(self, value): 1625 value = convert.toEnergy(value) 1626 super(Energy, self).__init__(value) 1627 1628class NetworkBandwidth(float,ParamValue): 1629 cxx_type = 'float' 1630 ex_str = "1Gbps" 1631 cmd_line_settable = True 1632 1633 def __new__(cls, value): 1634 # convert to bits per second 1635 val = convert.toNetworkBandwidth(value) 1636 return super(cls, NetworkBandwidth).__new__(cls, val) 1637 1638 def __str__(self): 1639 return str(self.val) 1640 1641 def __call__(self, value): 1642 val = convert.toNetworkBandwidth(value) 1643 self.__init__(val) 1644 return value 1645 1646 def getValue(self): 1647 # convert to seconds per byte 1648 value = 8.0 / float(self) 1649 # convert to ticks per byte 1650 value = ticks.fromSeconds(value) 1651 return float(value) 1652 1653 def ini_str(self): 1654 return '%f' % self.getValue() 1655 1656 def config_value(self): 1657 return '%f' % self.getValue() 1658 1659 @classmethod 1660 def cxx_ini_predecls(cls, code): 1661 code('#include <sstream>') 1662 1663 @classmethod 1664 def cxx_ini_parse(self, code, src, dest, ret): 1665 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1666 1667class MemoryBandwidth(float,ParamValue): 1668 cxx_type = 'float' 1669 ex_str = "1GB/s" 1670 cmd_line_settable = True 1671 1672 def __new__(cls, value): 1673 # convert to bytes per second 1674 val = convert.toMemoryBandwidth(value) 1675 return super(cls, MemoryBandwidth).__new__(cls, val) 1676 1677 def __call__(self, value): 1678 val = convert.toMemoryBandwidth(value) 1679 self.__init__(val) 1680 return value 1681 1682 def getValue(self): 1683 # convert to seconds per byte 1684 value = float(self) 1685 if value: 1686 value = 1.0 / float(self) 1687 # convert to ticks per byte 1688 value = ticks.fromSeconds(value) 1689 return float(value) 1690 1691 def ini_str(self): 1692 return '%f' % self.getValue() 1693 1694 def config_value(self): 1695 return '%f' % self.getValue() 1696 1697 @classmethod 1698 def cxx_ini_predecls(cls, code): 1699 code('#include <sstream>') 1700 1701 @classmethod 1702 def cxx_ini_parse(self, code, src, dest, ret): 1703 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1704 1705# 1706# "Constants"... handy aliases for various values. 1707# 1708 1709# Special class for NULL pointers. Note the special check in 1710# make_param_value() above that lets these be assigned where a 1711# SimObject is required. 1712# only one copy of a particular node 1713class NullSimObject(object): 1714 __metaclass__ = Singleton 1715 _name = 'Null' 1716 1717 def __call__(cls): 1718 return cls 1719 1720 def _instantiate(self, parent = None, path = ''): 1721 pass 1722 1723 def ini_str(self): 1724 return 'Null' 1725 1726 def unproxy(self, base): 1727 return self 1728 1729 def set_path(self, parent, name): 1730 pass 1731 1732 def set_parent(self, parent, name): 1733 pass 1734 1735 def clear_parent(self, old_parent): 1736 pass 1737 1738 def descendants(self): 1739 return 1740 yield None 1741 1742 def get_config_as_dict(self): 1743 return {} 1744 1745 def __str__(self): 1746 return self._name 1747 1748 def config_value(self): 1749 return None 1750 1751 def getValue(self): 1752 return None 1753 1754# The only instance you'll ever need... 1755NULL = NullSimObject() 1756 1757def isNullPointer(value): 1758 return isinstance(value, NullSimObject) 1759 1760# Some memory range specifications use this as a default upper bound. 1761MaxAddr = Addr.max 1762MaxTick = Tick.max 1763AllMemory = AddrRange(0, MaxAddr) 1764 1765 1766##################################################################### 1767# 1768# Port objects 1769# 1770# Ports are used to interconnect objects in the memory system. 1771# 1772##################################################################### 1773 1774# Port reference: encapsulates a reference to a particular port on a 1775# particular SimObject. 1776class PortRef(object): 1777 def __init__(self, simobj, name, role): 1778 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1779 self.simobj = simobj 1780 self.name = name 1781 self.role = role 1782 self.peer = None # not associated with another port yet 1783 self.ccConnected = False # C++ port connection done? 1784 self.index = -1 # always -1 for non-vector ports 1785 1786 def __str__(self): 1787 return '%s.%s' % (self.simobj, self.name) 1788 1789 def __len__(self): 1790 # Return the number of connected ports, i.e. 0 is we have no 1791 # peer and 1 if we do. 1792 return int(self.peer != None) 1793 1794 # for config.ini, print peer's name (not ours) 1795 def ini_str(self): 1796 return str(self.peer) 1797 1798 # for config.json 1799 def get_config_as_dict(self): 1800 return {'role' : self.role, 'peer' : str(self.peer)} 1801 1802 def __getattr__(self, attr): 1803 if attr == 'peerObj': 1804 # shorthand for proxies 1805 return self.peer.simobj 1806 raise AttributeError("'%s' object has no attribute '%s'" % \ 1807 (self.__class__.__name__, attr)) 1808 1809 # Full connection is symmetric (both ways). Called via 1810 # SimObject.__setattr__ as a result of a port assignment, e.g., 1811 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1812 # e.g., "obj1.portA[3] = obj2.portB". 1813 def connect(self, other): 1814 if isinstance(other, VectorPortRef): 1815 # reference to plain VectorPort is implicit append 1816 other = other._get_next() 1817 if self.peer and not proxy.isproxy(self.peer): 1818 fatal("Port %s is already connected to %s, cannot connect %s\n", 1819 self, self.peer, other); 1820 self.peer = other 1821 if proxy.isproxy(other): 1822 other.set_param_desc(PortParamDesc()) 1823 elif isinstance(other, PortRef): 1824 if other.peer is not self: 1825 other.connect(self) 1826 else: 1827 raise TypeError("assigning non-port reference '%s' to port '%s'" \ 1828 % (other, self)) 1829 1830 # Allow a master/slave port pair to be spliced between 1831 # a port and its connected peer. Useful operation for connecting 1832 # instrumentation structures into a system when it is necessary 1833 # to connect the instrumentation after the full system has been 1834 # constructed. 1835 def splice(self, new_master_peer, new_slave_peer): 1836 if not self.peer or proxy.isproxy(self.peer): 1837 fatal("Port %s not connected, cannot splice in new peers\n", self) 1838 1839 if not isinstance(new_master_peer, PortRef) or \ 1840 not isinstance(new_slave_peer, PortRef): 1841 raise TypeError( 1842 "Splicing non-port references '%s','%s' to port '%s'" % \ 1843 (new_master_peer, new_slave_peer, self)) 1844 1845 old_peer = self.peer 1846 if self.role == 'SLAVE': 1847 self.peer = new_master_peer 1848 old_peer.peer = new_slave_peer 1849 new_master_peer.connect(self) 1850 new_slave_peer.connect(old_peer) 1851 elif self.role == 'MASTER': 1852 self.peer = new_slave_peer 1853 old_peer.peer = new_master_peer 1854 new_slave_peer.connect(self) 1855 new_master_peer.connect(old_peer) 1856 else: 1857 panic("Port %s has unknown role, "+\ 1858 "cannot splice in new peers\n", self) 1859 1860 def clone(self, simobj, memo): 1861 if self in memo: 1862 return memo[self] 1863 newRef = copy.copy(self) 1864 memo[self] = newRef 1865 newRef.simobj = simobj 1866 assert(isSimObject(newRef.simobj)) 1867 if self.peer and not proxy.isproxy(self.peer): 1868 peerObj = self.peer.simobj(_memo=memo) 1869 newRef.peer = self.peer.clone(peerObj, memo) 1870 assert(not isinstance(newRef.peer, VectorPortRef)) 1871 return newRef 1872 1873 def unproxy(self, simobj): 1874 assert(simobj is self.simobj) 1875 if proxy.isproxy(self.peer): 1876 try: 1877 realPeer = self.peer.unproxy(self.simobj) 1878 except: 1879 print("Error in unproxying port '%s' of %s" % 1880 (self.name, self.simobj.path())) 1881 raise 1882 self.connect(realPeer) 1883 1884 # Call C++ to create corresponding port connection between C++ objects 1885 def ccConnect(self): 1886 from _m5.pyobject import connectPorts 1887 1888 if self.ccConnected: # already done this 1889 return 1890 1891 peer = self.peer 1892 if not self.peer: # nothing to connect to 1893 return 1894 1895 # check that we connect a master to a slave 1896 if self.role == peer.role: 1897 raise TypeError( 1898 "cannot connect '%s' and '%s' due to identical role '%s'" % \ 1899 (peer, self, self.role)) 1900 1901 if self.role == 'SLAVE': 1902 # do nothing and let the master take care of it 1903 return 1904 1905 try: 1906 # self is always the master and peer the slave 1907 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1908 peer.simobj.getCCObject(), peer.name, peer.index) 1909 except: 1910 print("Error connecting port %s.%s to %s.%s" % 1911 (self.simobj.path(), self.name, 1912 peer.simobj.path(), peer.name)) 1913 raise 1914 self.ccConnected = True 1915 peer.ccConnected = True 1916 1917# A reference to an individual element of a VectorPort... much like a 1918# PortRef, but has an index. 1919class VectorPortElementRef(PortRef): 1920 def __init__(self, simobj, name, role, index): 1921 PortRef.__init__(self, simobj, name, role) 1922 self.index = index 1923 1924 def __str__(self): 1925 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1926 1927# A reference to a complete vector-valued port (not just a single element). 1928# Can be indexed to retrieve individual VectorPortElementRef instances. 1929class VectorPortRef(object): 1930 def __init__(self, simobj, name, role): 1931 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1932 self.simobj = simobj 1933 self.name = name 1934 self.role = role 1935 self.elements = [] 1936 1937 def __str__(self): 1938 return '%s.%s[:]' % (self.simobj, self.name) 1939 1940 def __len__(self): 1941 # Return the number of connected peers, corresponding the the 1942 # length of the elements. 1943 return len(self.elements) 1944 1945 # for config.ini, print peer's name (not ours) 1946 def ini_str(self): 1947 return ' '.join([el.ini_str() for el in self.elements]) 1948 1949 # for config.json 1950 def get_config_as_dict(self): 1951 return {'role' : self.role, 1952 'peer' : [el.ini_str() for el in self.elements]} 1953 1954 def __getitem__(self, key): 1955 if not isinstance(key, int): 1956 raise TypeError("VectorPort index must be integer") 1957 if key >= len(self.elements): 1958 # need to extend list 1959 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1960 for i in range(len(self.elements), key+1)] 1961 self.elements.extend(ext) 1962 return self.elements[key] 1963 1964 def _get_next(self): 1965 return self[len(self.elements)] 1966 1967 def __setitem__(self, key, value): 1968 if not isinstance(key, int): 1969 raise TypeError("VectorPort index must be integer") 1970 self[key].connect(value) 1971 1972 def connect(self, other): 1973 if isinstance(other, (list, tuple)): 1974 # Assign list of port refs to vector port. 1975 # For now, append them... not sure if that's the right semantics 1976 # or if it should replace the current vector. 1977 for ref in other: 1978 self._get_next().connect(ref) 1979 else: 1980 # scalar assignment to plain VectorPort is implicit append 1981 self._get_next().connect(other) 1982 1983 def clone(self, simobj, memo): 1984 if self in memo: 1985 return memo[self] 1986 newRef = copy.copy(self) 1987 memo[self] = newRef 1988 newRef.simobj = simobj 1989 assert(isSimObject(newRef.simobj)) 1990 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1991 return newRef 1992 1993 def unproxy(self, simobj): 1994 [el.unproxy(simobj) for el in self.elements] 1995 1996 def ccConnect(self): 1997 [el.ccConnect() for el in self.elements] 1998 1999# Port description object. Like a ParamDesc object, this represents a 2000# logical port in the SimObject class, not a particular port on a 2001# SimObject instance. The latter are represented by PortRef objects. 2002class Port(object): 2003 # Generate a PortRef for this port on the given SimObject with the 2004 # given name 2005 def makeRef(self, simobj): 2006 return PortRef(simobj, self.name, self.role) 2007 2008 # Connect an instance of this port (on the given SimObject with 2009 # the given name) with the port described by the supplied PortRef 2010 def connect(self, simobj, ref): 2011 self.makeRef(simobj).connect(ref) 2012 2013 # No need for any pre-declarations at the moment as we merely rely 2014 # on an unsigned int. 2015 def cxx_predecls(self, code): 2016 pass 2017 2018 def pybind_predecls(self, code): 2019 cls.cxx_predecls(self, code) 2020 2021 # Declare an unsigned int with the same name as the port, that 2022 # will eventually hold the number of connected ports (and thus the 2023 # number of elements for a VectorPort). 2024 def cxx_decl(self, code): 2025 code('unsigned int port_${{self.name}}_connection_count;') 2026 2027class MasterPort(Port): 2028 # MasterPort("description") 2029 def __init__(self, *args): 2030 if len(args) == 1: 2031 self.desc = args[0] 2032 self.role = 'MASTER' 2033 else: 2034 raise TypeError('wrong number of arguments') 2035 2036class SlavePort(Port): 2037 # SlavePort("description") 2038 def __init__(self, *args): 2039 if len(args) == 1: 2040 self.desc = args[0] 2041 self.role = 'SLAVE' 2042 else: 2043 raise TypeError('wrong number of arguments') 2044 2045# VectorPort description object. Like Port, but represents a vector 2046# of connections (e.g., as on a XBar). 2047class VectorPort(Port): 2048 def __init__(self, *args): 2049 self.isVec = True 2050 2051 def makeRef(self, simobj): 2052 return VectorPortRef(simobj, self.name, self.role) 2053 2054class VectorMasterPort(VectorPort): 2055 # VectorMasterPort("description") 2056 def __init__(self, *args): 2057 if len(args) == 1: 2058 self.desc = args[0] 2059 self.role = 'MASTER' 2060 VectorPort.__init__(self, *args) 2061 else: 2062 raise TypeError('wrong number of arguments') 2063 2064class VectorSlavePort(VectorPort): 2065 # VectorSlavePort("description") 2066 def __init__(self, *args): 2067 if len(args) == 1: 2068 self.desc = args[0] 2069 self.role = 'SLAVE' 2070 VectorPort.__init__(self, *args) 2071 else: 2072 raise TypeError('wrong number of arguments') 2073 2074# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2075# proxy objects (via set_param_desc()) so that proxy error messages 2076# make sense. 2077class PortParamDesc(object): 2078 __metaclass__ = Singleton 2079 2080 ptype_str = 'Port' 2081 ptype = Port 2082 2083baseEnums = allEnums.copy() 2084baseParams = allParams.copy() 2085 2086def clear(): 2087 global allEnums, allParams 2088 2089 allEnums = baseEnums.copy() 2090 allParams = baseParams.copy() 2091 2092__all__ = ['Param', 'VectorParam', 2093 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float', 2094 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2095 'Int32', 'UInt32', 'Int64', 'UInt64', 2096 'Counter', 'Addr', 'Tick', 'Percent', 2097 'TcpPort', 'UdpPort', 'EthernetAddr', 2098 'IpAddress', 'IpNetmask', 'IpWithPort', 2099 'MemorySize', 'MemorySize32', 2100 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy', 2101 'NetworkBandwidth', 'MemoryBandwidth', 2102 'AddrRange', 2103 'MaxAddr', 'MaxTick', 'AllMemory', 2104 'Time', 2105 'NextEthernetAddr', 'NULL', 2106 'MasterPort', 'SlavePort', 2107 'VectorMasterPort', 'VectorSlavePort'] 2108 2109import SimObject 2110