params.py revision 12200
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017 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# 473101Sstever@eecs.umich.edu# Parameter description classes 483101Sstever@eecs.umich.edu# 493102Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either 503101Sstever@eecs.umich.edu# a Param or a VectorParam object. These objects contain the 513101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default 523101Sstever@eecs.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 543101Sstever@eecs.umich.edu# type. 553101Sstever@eecs.umich.edu# 563101Sstever@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.eduimport copy 633101Sstever@eecs.umich.eduimport datetime 643101Sstever@eecs.umich.eduimport re 653101Sstever@eecs.umich.eduimport sys 663101Sstever@eecs.umich.eduimport time 673101Sstever@eecs.umich.eduimport math 683101Sstever@eecs.umich.edu 693101Sstever@eecs.umich.eduimport proxy 703101Sstever@eecs.umich.eduimport ticks 713101Sstever@eecs.umich.edufrom util import * 723101Sstever@eecs.umich.edu 733101Sstever@eecs.umich.edudef isSimObject(*args, **kwargs): 743101Sstever@eecs.umich.edu return SimObject.isSimObject(*args, **kwargs) 753101Sstever@eecs.umich.edu 763101Sstever@eecs.umich.edudef isSimObjectSequence(*args, **kwargs): 773101Sstever@eecs.umich.edu return SimObject.isSimObjectSequence(*args, **kwargs) 783101Sstever@eecs.umich.edu 793101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs): 803101Sstever@eecs.umich.edu return SimObject.isSimObjectClass(*args, **kwargs) 813101Sstever@eecs.umich.edu 823101Sstever@eecs.umich.eduallParams = {} 833101Sstever@eecs.umich.edu 843101Sstever@eecs.umich.educlass MetaParamValue(type): 853101Sstever@eecs.umich.edu def __new__(mcls, name, bases, dct): 863101Sstever@eecs.umich.edu cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 873101Sstever@eecs.umich.edu assert name not in allParams 883101Sstever@eecs.umich.edu allParams[name] = cls 893101Sstever@eecs.umich.edu return cls 903101Sstever@eecs.umich.edu 913101Sstever@eecs.umich.edu 923101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject 933101Sstever@eecs.umich.edu# parameters. 943101Sstever@eecs.umich.educlass ParamValue(object): 953101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 963101Sstever@eecs.umich.edu cmd_line_settable = False 973101Sstever@eecs.umich.edu 983101Sstever@eecs.umich.edu # Generate the code needed as a prerequisite for declaring a C++ 993101Sstever@eecs.umich.edu # object of this type. Typically generates one or more #include 1003101Sstever@eecs.umich.edu # statements. Used when declaring parameters of this type. 1013101Sstever@eecs.umich.edu @classmethod 1023101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 1033101Sstever@eecs.umich.edu pass 1043102Sstever@eecs.umich.edu 1053101Sstever@eecs.umich.edu @classmethod 1063102Sstever@eecs.umich.edu def pybind_predecls(cls, code): 1073101Sstever@eecs.umich.edu cls.cxx_predecls(code) 1083101Sstever@eecs.umich.edu 1093101Sstever@eecs.umich.edu # default for printing to .ini file is regular string conversion. 1103102Sstever@eecs.umich.edu # will be overridden in some cases 1113102Sstever@eecs.umich.edu def ini_str(self): 1123101Sstever@eecs.umich.edu return str(self) 1133101Sstever@eecs.umich.edu 1143101Sstever@eecs.umich.edu # default for printing to .json file is regular string conversion. 1153101Sstever@eecs.umich.edu # will be overridden in some cases, mostly to use native Python 1163101Sstever@eecs.umich.edu # types where there are similar JSON types 1173101Sstever@eecs.umich.edu def config_value(self): 1183101Sstever@eecs.umich.edu return str(self) 1193101Sstever@eecs.umich.edu 1203101Sstever@eecs.umich.edu # Prerequisites for .ini parsing with cxx_ini_parse 1213101Sstever@eecs.umich.edu @classmethod 1223101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 1233101Sstever@eecs.umich.edu pass 1243101Sstever@eecs.umich.edu 1253102Sstever@eecs.umich.edu # parse a .ini file entry for this param from string expression 1263101Sstever@eecs.umich.edu # src into lvalue dest (of the param's C++ type) 1273101Sstever@eecs.umich.edu @classmethod 1283101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 1293101Sstever@eecs.umich.edu code('// Unhandled param type: %s' % cls.__name__) 1303101Sstever@eecs.umich.edu code('%s false;' % ret) 1313101Sstever@eecs.umich.edu 1323101Sstever@eecs.umich.edu # allows us to blithely call unproxy() on things without checking 1333101Sstever@eecs.umich.edu # if they're really proxies or not 1343101Sstever@eecs.umich.edu def unproxy(self, base): 1353101Sstever@eecs.umich.edu return self 1363101Sstever@eecs.umich.edu 1373101Sstever@eecs.umich.edu # Produce a human readable version of the stored value 1383101Sstever@eecs.umich.edu def pretty_print(self, value): 1393101Sstever@eecs.umich.edu return str(value) 1403101Sstever@eecs.umich.edu 1413101Sstever@eecs.umich.edu# Regular parameter description. 1423101Sstever@eecs.umich.educlass ParamDesc(object): 1433101Sstever@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 1443101Sstever@eecs.umich.edu self.ptype_str = ptype_str 1453101Sstever@eecs.umich.edu # remember ptype only if it is provided 1463101Sstever@eecs.umich.edu if ptype != None: 1473101Sstever@eecs.umich.edu self.ptype = ptype 1483101Sstever@eecs.umich.edu 1493101Sstever@eecs.umich.edu if args: 1503101Sstever@eecs.umich.edu if len(args) == 1: 1513101Sstever@eecs.umich.edu self.desc = args[0] 1523101Sstever@eecs.umich.edu elif len(args) == 2: 1533101Sstever@eecs.umich.edu self.default = args[0] 1543101Sstever@eecs.umich.edu self.desc = args[1] 1553101Sstever@eecs.umich.edu else: 1563101Sstever@eecs.umich.edu raise TypeError, 'too many arguments' 1573101Sstever@eecs.umich.edu 1583101Sstever@eecs.umich.edu if kwargs.has_key('desc'): 1593101Sstever@eecs.umich.edu assert(not hasattr(self, 'desc')) 1603101Sstever@eecs.umich.edu self.desc = kwargs['desc'] 1613101Sstever@eecs.umich.edu del kwargs['desc'] 1623101Sstever@eecs.umich.edu 1633101Sstever@eecs.umich.edu if kwargs.has_key('default'): 1643101Sstever@eecs.umich.edu assert(not hasattr(self, 'default')) 1653101Sstever@eecs.umich.edu self.default = kwargs['default'] 1663101Sstever@eecs.umich.edu del kwargs['default'] 1673101Sstever@eecs.umich.edu 1683101Sstever@eecs.umich.edu if kwargs: 1693101Sstever@eecs.umich.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 1703101Sstever@eecs.umich.edu 1713101Sstever@eecs.umich.edu if not hasattr(self, 'desc'): 1723101Sstever@eecs.umich.edu raise TypeError, 'desc attribute missing' 1733101Sstever@eecs.umich.edu 1743101Sstever@eecs.umich.edu def __getattr__(self, attr): 1753101Sstever@eecs.umich.edu if attr == 'ptype': 1763101Sstever@eecs.umich.edu ptype = SimObject.allClasses[self.ptype_str] 1773101Sstever@eecs.umich.edu assert isSimObjectClass(ptype) 1783101Sstever@eecs.umich.edu self.ptype = ptype 1793101Sstever@eecs.umich.edu return ptype 1803101Sstever@eecs.umich.edu 1813101Sstever@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 1823101Sstever@eecs.umich.edu (type(self).__name__, attr) 1833101Sstever@eecs.umich.edu 1843101Sstever@eecs.umich.edu def example_str(self): 1853101Sstever@eecs.umich.edu if hasattr(self.ptype, "ex_str"): 1863101Sstever@eecs.umich.edu return self.ptype.ex_str 1873101Sstever@eecs.umich.edu else: 1883101Sstever@eecs.umich.edu return self.ptype_str 1893101Sstever@eecs.umich.edu 1903101Sstever@eecs.umich.edu # Is the param available to be exposed on the command line 1913101Sstever@eecs.umich.edu def isCmdLineSettable(self): 1923101Sstever@eecs.umich.edu if hasattr(self.ptype, "cmd_line_settable"): 1933101Sstever@eecs.umich.edu return self.ptype.cmd_line_settable 1943101Sstever@eecs.umich.edu else: 1953101Sstever@eecs.umich.edu return False 1963101Sstever@eecs.umich.edu 1973101Sstever@eecs.umich.edu def convert(self, value): 1983101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 1993101Sstever@eecs.umich.edu value.set_param_desc(self) 2003101Sstever@eecs.umich.edu return value 2013101Sstever@eecs.umich.edu if not hasattr(self, 'ptype') and isNullPointer(value): 2023101Sstever@eecs.umich.edu # deferred evaluation of SimObject; continue to defer if 2033101Sstever@eecs.umich.edu # we're just assigning a null pointer 2043101Sstever@eecs.umich.edu return value 2053101Sstever@eecs.umich.edu if isinstance(value, self.ptype): 2063101Sstever@eecs.umich.edu return value 2073101Sstever@eecs.umich.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 2083101Sstever@eecs.umich.edu return value 2093101Sstever@eecs.umich.edu return self.ptype(value) 2103101Sstever@eecs.umich.edu 2113101Sstever@eecs.umich.edu def pretty_print(self, value): 2123101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 2133101Sstever@eecs.umich.edu return str(value) 2143101Sstever@eecs.umich.edu if isNullPointer(value): 2153101Sstever@eecs.umich.edu return NULL 2163101Sstever@eecs.umich.edu return self.ptype(value).pretty_print(value) 2173101Sstever@eecs.umich.edu 2183101Sstever@eecs.umich.edu def cxx_predecls(self, code): 2193101Sstever@eecs.umich.edu code('#include <cstddef>') 2203101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2213101Sstever@eecs.umich.edu 2223101Sstever@eecs.umich.edu def pybind_predecls(self, code): 2233101Sstever@eecs.umich.edu self.ptype.pybind_predecls(code) 2243101Sstever@eecs.umich.edu 2253101Sstever@eecs.umich.edu def cxx_decl(self, code): 2263101Sstever@eecs.umich.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 2273101Sstever@eecs.umich.edu 2283101Sstever@eecs.umich.edu# Vector-valued parameter description. Just like ParamDesc, except 2293101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a 2303101Sstever@eecs.umich.edu# single value. 2313101Sstever@eecs.umich.edu 2323101Sstever@eecs.umich.educlass VectorParamValue(list): 2333101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 2343101Sstever@eecs.umich.edu def __setattr__(self, attr, value): 2353101Sstever@eecs.umich.edu raise AttributeError, \ 2363101Sstever@eecs.umich.edu "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 2373101Sstever@eecs.umich.edu 2383101Sstever@eecs.umich.edu def config_value(self): 2393101Sstever@eecs.umich.edu return [v.config_value() for v in self] 2403101Sstever@eecs.umich.edu 2413101Sstever@eecs.umich.edu def ini_str(self): 2423101Sstever@eecs.umich.edu return ' '.join([v.ini_str() for v in self]) 2433101Sstever@eecs.umich.edu 2443101Sstever@eecs.umich.edu def getValue(self): 2453101Sstever@eecs.umich.edu return [ v.getValue() for v in self ] 2463101Sstever@eecs.umich.edu 2473101Sstever@eecs.umich.edu def unproxy(self, base): 2483101Sstever@eecs.umich.edu if len(self) == 1 and isinstance(self[0], proxy.BaseProxy): 2493101Sstever@eecs.umich.edu # The value is a proxy (e.g. Parent.any, Parent.all or 2503101Sstever@eecs.umich.edu # Parent.x) therefore try resolve it 2513101Sstever@eecs.umich.edu return self[0].unproxy(base) 2523101Sstever@eecs.umich.edu else: 2533101Sstever@eecs.umich.edu return [v.unproxy(base) for v in self] 2543101Sstever@eecs.umich.edu 2553101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue): 2563101Sstever@eecs.umich.edu # support clone operation 2573101Sstever@eecs.umich.edu def __call__(self, **kwargs): 2583101Sstever@eecs.umich.edu return SimObjectVector([v(**kwargs) for v in self]) 2593101Sstever@eecs.umich.edu 2603101Sstever@eecs.umich.edu def clear_parent(self, old_parent): 2613101Sstever@eecs.umich.edu for v in self: 2623101Sstever@eecs.umich.edu v.clear_parent(old_parent) 2633101Sstever@eecs.umich.edu 2643101Sstever@eecs.umich.edu def set_parent(self, parent, name): 2653101Sstever@eecs.umich.edu if len(self) == 1: 2663101Sstever@eecs.umich.edu self[0].set_parent(parent, name) 2673101Sstever@eecs.umich.edu else: 2683101Sstever@eecs.umich.edu width = int(math.ceil(math.log(len(self))/math.log(10))) 2693101Sstever@eecs.umich.edu for i,v in enumerate(self): 2703101Sstever@eecs.umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2713101Sstever@eecs.umich.edu 2723101Sstever@eecs.umich.edu def has_parent(self): 2733101Sstever@eecs.umich.edu return any([e.has_parent() for e in self if not isNullPointer(e)]) 2743101Sstever@eecs.umich.edu 2753101Sstever@eecs.umich.edu # return 'cpu0 cpu1' etc. for print_ini() 2763101Sstever@eecs.umich.edu def get_name(self): 2773101Sstever@eecs.umich.edu return ' '.join([v._name for v in self]) 2783101Sstever@eecs.umich.edu 2793101Sstever@eecs.umich.edu # By iterating through the constituent members of the vector here 2803101Sstever@eecs.umich.edu # we can nicely handle iterating over all a SimObject's children 2813101Sstever@eecs.umich.edu # without having to provide lots of special functions on 2823101Sstever@eecs.umich.edu # SimObjectVector directly. 2833101Sstever@eecs.umich.edu def descendants(self): 2843101Sstever@eecs.umich.edu for v in self: 2853101Sstever@eecs.umich.edu for obj in v.descendants(): 2863101Sstever@eecs.umich.edu yield obj 2873101Sstever@eecs.umich.edu 2883101Sstever@eecs.umich.edu def get_config_as_dict(self): 2893101Sstever@eecs.umich.edu a = [] 2903101Sstever@eecs.umich.edu for v in self: 2913101Sstever@eecs.umich.edu a.append(v.get_config_as_dict()) 2923101Sstever@eecs.umich.edu return a 2933101Sstever@eecs.umich.edu 2943101Sstever@eecs.umich.edu # If we are replacing an item in the vector, make sure to set the 2953101Sstever@eecs.umich.edu # parent reference of the new SimObject to be the same as the parent 2963101Sstever@eecs.umich.edu # of the SimObject being replaced. Useful to have if we created 2973101Sstever@eecs.umich.edu # a SimObjectVector of temporary objects that will be modified later in 2983101Sstever@eecs.umich.edu # configuration scripts. 2993101Sstever@eecs.umich.edu def __setitem__(self, key, value): 3003101Sstever@eecs.umich.edu val = self[key] 3013101Sstever@eecs.umich.edu if value.has_parent(): 3023101Sstever@eecs.umich.edu warn("SimObject %s already has a parent" % value.get_name() +\ 3033101Sstever@eecs.umich.edu " that is being overwritten by a SimObjectVector") 3043101Sstever@eecs.umich.edu value.set_parent(val.get_parent(), val._name) 3053101Sstever@eecs.umich.edu super(SimObjectVector, self).__setitem__(key, value) 3063101Sstever@eecs.umich.edu 3073101Sstever@eecs.umich.edu # Enumerate the params of each member of the SimObject vector. Creates 3083101Sstever@eecs.umich.edu # strings that will allow indexing into the vector by the python code and 3093101Sstever@eecs.umich.edu # allow it to be specified on the command line. 3103102Sstever@eecs.umich.edu def enumerateParams(self, flags_dict = {}, 3113101Sstever@eecs.umich.edu cmd_line_str = "", 3123101Sstever@eecs.umich.edu access_str = ""): 3133101Sstever@eecs.umich.edu if hasattr(self, "_paramEnumed"): 3143101Sstever@eecs.umich.edu print "Cycle detected enumerating params at %s?!" % (cmd_line_str) 3153101Sstever@eecs.umich.edu else: 3163101Sstever@eecs.umich.edu x = 0 3173101Sstever@eecs.umich.edu for vals in self: 3183101Sstever@eecs.umich.edu # Each entry in the SimObjectVector should be an 3193101Sstever@eecs.umich.edu # instance of a SimObject 3203101Sstever@eecs.umich.edu flags_dict = vals.enumerateParams(flags_dict, 3213101Sstever@eecs.umich.edu cmd_line_str + "%d." % x, 3223101Sstever@eecs.umich.edu access_str + "[%d]." % x) 3233101Sstever@eecs.umich.edu x = x + 1 3243101Sstever@eecs.umich.edu 3253101Sstever@eecs.umich.edu return flags_dict 3263101Sstever@eecs.umich.edu 3273101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc): 3283101Sstever@eecs.umich.edu # Convert assigned value to appropriate type. If the RHS is not a 3293101Sstever@eecs.umich.edu # list or tuple, it generates a single-element list. 3303101Sstever@eecs.umich.edu def convert(self, value): 3313101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3323101Sstever@eecs.umich.edu # list: coerce each element into new list 3333101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3343101Sstever@eecs.umich.edu elif isinstance(value, str): 3353101Sstever@eecs.umich.edu # If input is a csv string 3363101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3373101Sstever@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3383101Sstever@eecs.umich.edu else: 3393101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3403101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3413101Sstever@eecs.umich.edu 3423101Sstever@eecs.umich.edu if isSimObjectSequence(tmp_list): 3433101Sstever@eecs.umich.edu return SimObjectVector(tmp_list) 3443101Sstever@eecs.umich.edu else: 3453102Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3463101Sstever@eecs.umich.edu 3473101Sstever@eecs.umich.edu # Produce a human readable example string that describes 3483101Sstever@eecs.umich.edu # how to set this vector parameter in the absence of a default 3493101Sstever@eecs.umich.edu # value. 3503101Sstever@eecs.umich.edu def example_str(self): 3513101Sstever@eecs.umich.edu s = super(VectorParamDesc, self).example_str() 3523101Sstever@eecs.umich.edu help_str = "[" + s + "," + s + ", ...]" 3533101Sstever@eecs.umich.edu return help_str 3543101Sstever@eecs.umich.edu 3553102Sstever@eecs.umich.edu # Produce a human readable representation of the value of this vector param. 3563101Sstever@eecs.umich.edu def pretty_print(self, value): 3573101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3583101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 3593101Sstever@eecs.umich.edu elif isinstance(value, str): 3603101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 3613101Sstever@eecs.umich.edu else: 3623101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.pretty_print(self, value) ] 3633101Sstever@eecs.umich.edu 3643101Sstever@eecs.umich.edu return tmp_list 3653101Sstever@eecs.umich.edu 3663101Sstever@eecs.umich.edu # This is a helper function for the new config system 3673101Sstever@eecs.umich.edu def __call__(self, value): 3683102Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 3693101Sstever@eecs.umich.edu # list: coerce each element into new list 3703101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 3713101Sstever@eecs.umich.edu elif isinstance(value, str): 3723101Sstever@eecs.umich.edu # If input is a csv string 3733101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) \ 3743101Sstever@eecs.umich.edu for v in value.strip('[').strip(']').split(',') ] 3753101Sstever@eecs.umich.edu else: 3763101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 3773101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 3783101Sstever@eecs.umich.edu 3793101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 3803101Sstever@eecs.umich.edu 3813101Sstever@eecs.umich.edu def cxx_predecls(self, code): 3823101Sstever@eecs.umich.edu code('#include <vector>') 3833101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 3843101Sstever@eecs.umich.edu 3853101Sstever@eecs.umich.edu def pybind_predecls(self, code): 3863101Sstever@eecs.umich.edu code('#include <vector>') 3873101Sstever@eecs.umich.edu self.ptype.pybind_predecls(code) 3883101Sstever@eecs.umich.edu 3893101Sstever@eecs.umich.edu def cxx_decl(self, code): 3903101Sstever@eecs.umich.edu code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 3913101Sstever@eecs.umich.edu 3923101Sstever@eecs.umich.educlass ParamFactory(object): 3933101Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 3943101Sstever@eecs.umich.edu self.param_desc_class = param_desc_class 3953101Sstever@eecs.umich.edu self.ptype_str = ptype_str 3963101Sstever@eecs.umich.edu 3973101Sstever@eecs.umich.edu def __getattr__(self, attr): 3983101Sstever@eecs.umich.edu if self.ptype_str: 3993101Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 4003101Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 4013101Sstever@eecs.umich.edu 4023101Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 4033101Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 4043101Sstever@eecs.umich.edu ptype = None 4053101Sstever@eecs.umich.edu try: 4063101Sstever@eecs.umich.edu ptype = allParams[self.ptype_str] 4073101Sstever@eecs.umich.edu except KeyError: 4083101Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 4093101Sstever@eecs.umich.edu # try to resolve it later 4103101Sstever@eecs.umich.edu pass 4113101Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 4123101Sstever@eecs.umich.edu 4133101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc) 4143101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc) 4153101Sstever@eecs.umich.edu 4163101Sstever@eecs.umich.edu##################################################################### 4173101Sstever@eecs.umich.edu# 4183101Sstever@eecs.umich.edu# Parameter Types 4193101Sstever@eecs.umich.edu# 4203101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types 4213101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more 4223101Sstever@eecs.umich.edu# flexible to define our own set of types. This gives us more control 4233101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the 4243101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via 4253101Sstever@eecs.umich.edu# the __str__() conversion method). 4263101Sstever@eecs.umich.edu# 4273101Sstever@eecs.umich.edu##################################################################### 4283101Sstever@eecs.umich.edu 4293101Sstever@eecs.umich.edu# String-valued parameter. Just mixin the ParamValue class with the 4303101Sstever@eecs.umich.edu# built-in str class. 4313101Sstever@eecs.umich.educlass String(ParamValue,str): 4323101Sstever@eecs.umich.edu cxx_type = 'std::string' 4333101Sstever@eecs.umich.edu cmd_line_settable = True 4343101Sstever@eecs.umich.edu 4353102Sstever@eecs.umich.edu @classmethod 4363101Sstever@eecs.umich.edu def cxx_predecls(self, code): 4373101Sstever@eecs.umich.edu code('#include <string>') 4383101Sstever@eecs.umich.edu 4393101Sstever@eecs.umich.edu def __call__(self, value): 4403101Sstever@eecs.umich.edu self = value 4413101Sstever@eecs.umich.edu return value 4423101Sstever@eecs.umich.edu 4433101Sstever@eecs.umich.edu @classmethod 4443101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 4453101Sstever@eecs.umich.edu code('%s = %s;' % (dest, src)) 4463101Sstever@eecs.umich.edu code('%s true;' % ret) 4473101Sstever@eecs.umich.edu 4483101Sstever@eecs.umich.edu def getValue(self): 4493101Sstever@eecs.umich.edu return self 4503101Sstever@eecs.umich.edu 4513101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math 4523101Sstever@eecs.umich.edu# operations in a type-safe way. e.g., a Latency times an int returns 4533101Sstever@eecs.umich.edu# a new Latency object. 4543101Sstever@eecs.umich.educlass NumericParamValue(ParamValue): 4553101Sstever@eecs.umich.edu def __str__(self): 4563101Sstever@eecs.umich.edu return str(self.value) 4573101Sstever@eecs.umich.edu 4583101Sstever@eecs.umich.edu def __float__(self): 4593101Sstever@eecs.umich.edu return float(self.value) 4603101Sstever@eecs.umich.edu 4613101Sstever@eecs.umich.edu def __long__(self): 4623101Sstever@eecs.umich.edu return long(self.value) 4633101Sstever@eecs.umich.edu 4643101Sstever@eecs.umich.edu def __int__(self): 4653101Sstever@eecs.umich.edu return int(self.value) 4663101Sstever@eecs.umich.edu 4673101Sstever@eecs.umich.edu # hook for bounds checking 4683101Sstever@eecs.umich.edu def _check(self): 4693101Sstever@eecs.umich.edu return 4703101Sstever@eecs.umich.edu 4713101Sstever@eecs.umich.edu def __mul__(self, other): 4723101Sstever@eecs.umich.edu newobj = self.__class__(self) 4733101Sstever@eecs.umich.edu newobj.value *= other 4743101Sstever@eecs.umich.edu newobj._check() 4753101Sstever@eecs.umich.edu return newobj 4763101Sstever@eecs.umich.edu 4773101Sstever@eecs.umich.edu __rmul__ = __mul__ 4783101Sstever@eecs.umich.edu 4793101Sstever@eecs.umich.edu def __div__(self, other): 4803101Sstever@eecs.umich.edu newobj = self.__class__(self) 4813101Sstever@eecs.umich.edu newobj.value /= other 4823101Sstever@eecs.umich.edu newobj._check() 4833101Sstever@eecs.umich.edu return newobj 4843101Sstever@eecs.umich.edu 4853101Sstever@eecs.umich.edu def __sub__(self, other): 4863101Sstever@eecs.umich.edu newobj = self.__class__(self) 4873101Sstever@eecs.umich.edu newobj.value -= other 4883101Sstever@eecs.umich.edu newobj._check() 4893101Sstever@eecs.umich.edu return newobj 4903101Sstever@eecs.umich.edu 4913101Sstever@eecs.umich.edu def config_value(self): 4923101Sstever@eecs.umich.edu return self.value 4933101Sstever@eecs.umich.edu 4943101Sstever@eecs.umich.edu @classmethod 4953101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 4963101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 4973101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 4983101Sstever@eecs.umich.edu pass 4993101Sstever@eecs.umich.edu 5003101Sstever@eecs.umich.edu # The default for parsing PODs from an .ini entry is to extract from an 5013101Sstever@eecs.umich.edu # istringstream and let overloading choose the right type according to 5023101Sstever@eecs.umich.edu # the dest type. 5033101Sstever@eecs.umich.edu @classmethod 5043101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 5053101Sstever@eecs.umich.edu code('%s to_number(%s, %s);' % (ret, src, dest)) 5063101Sstever@eecs.umich.edu 5073101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters. See CheckedInt. 5083101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue): 5093101Sstever@eecs.umich.edu def __init__(cls, name, bases, dict): 5103101Sstever@eecs.umich.edu super(CheckedIntType, cls).__init__(name, bases, dict) 5113101Sstever@eecs.umich.edu 5123101Sstever@eecs.umich.edu # CheckedInt is an abstract base class, so we actually don't 5133101Sstever@eecs.umich.edu # want to do any processing on it... the rest of this code is 5143101Sstever@eecs.umich.edu # just for classes that derive from CheckedInt. 5153101Sstever@eecs.umich.edu if name == 'CheckedInt': 5163101Sstever@eecs.umich.edu return 5173101Sstever@eecs.umich.edu 5183101Sstever@eecs.umich.edu if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 5193101Sstever@eecs.umich.edu if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 5203101Sstever@eecs.umich.edu panic("CheckedInt subclass %s must define either\n" \ 5213101Sstever@eecs.umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n", 5223101Sstever@eecs.umich.edu name); 5233101Sstever@eecs.umich.edu if cls.unsigned: 5243101Sstever@eecs.umich.edu cls.min = 0 5253101Sstever@eecs.umich.edu cls.max = 2 ** cls.size - 1 5263101Sstever@eecs.umich.edu else: 5273101Sstever@eecs.umich.edu cls.min = -(2 ** (cls.size - 1)) 5283101Sstever@eecs.umich.edu cls.max = (2 ** (cls.size - 1)) - 1 5293101Sstever@eecs.umich.edu 5303101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters. This 5313101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific 5323101Sstever@eecs.umich.edu# bounds. Initialization of the min and max bounds is done in the 5333101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__. 5343101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue): 5353101Sstever@eecs.umich.edu __metaclass__ = CheckedIntType 5363101Sstever@eecs.umich.edu cmd_line_settable = True 5373101Sstever@eecs.umich.edu 5383101Sstever@eecs.umich.edu def _check(self): 5393101Sstever@eecs.umich.edu if not self.min <= self.value <= self.max: 5403101Sstever@eecs.umich.edu raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 5413101Sstever@eecs.umich.edu (self.min, self.value, self.max) 5423101Sstever@eecs.umich.edu 5433101Sstever@eecs.umich.edu def __init__(self, value): 5443101Sstever@eecs.umich.edu if isinstance(value, str): 5453101Sstever@eecs.umich.edu self.value = convert.toInteger(value) 5463101Sstever@eecs.umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 5473101Sstever@eecs.umich.edu self.value = long(value) 5483101Sstever@eecs.umich.edu else: 5493101Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to CheckedInt" \ 5503101Sstever@eecs.umich.edu % type(value).__name__ 5513101Sstever@eecs.umich.edu self._check() 5523101Sstever@eecs.umich.edu 5533101Sstever@eecs.umich.edu def __call__(self, value): 5543101Sstever@eecs.umich.edu self.__init__(value) 5553101Sstever@eecs.umich.edu return value 5563101Sstever@eecs.umich.edu 5573101Sstever@eecs.umich.edu @classmethod 5583101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 5593101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 5603101Sstever@eecs.umich.edu code('#include "base/types.hh"') 5613101Sstever@eecs.umich.edu 5623101Sstever@eecs.umich.edu def getValue(self): 5633101Sstever@eecs.umich.edu return long(self.value) 5643101Sstever@eecs.umich.edu 5653101Sstever@eecs.umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 5663101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 5673101Sstever@eecs.umich.edu 5683101Sstever@eecs.umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 5693101Sstever@eecs.umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 5703101Sstever@eecs.umich.educlass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 5713101Sstever@eecs.umich.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5723101Sstever@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 5733101Sstever@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 5743101Sstever@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 5753101Sstever@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 5763101Sstever@eecs.umich.edu 5773101Sstever@eecs.umich.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 5783101Sstever@eecs.umich.educlass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 5793101Sstever@eecs.umich.educlass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5803101Sstever@eecs.umich.educlass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 5813101Sstever@eecs.umich.edu 5823101Sstever@eecs.umich.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 5833101Sstever@eecs.umich.edu 5843101Sstever@eecs.umich.educlass Cycles(CheckedInt): 5853101Sstever@eecs.umich.edu cxx_type = 'Cycles' 5863101Sstever@eecs.umich.edu size = 64 5873101Sstever@eecs.umich.edu unsigned = True 5883101Sstever@eecs.umich.edu 5893101Sstever@eecs.umich.edu def getValue(self): 5903101Sstever@eecs.umich.edu from _m5.core import Cycles 5913102Sstever@eecs.umich.edu return Cycles(self.value) 5923101Sstever@eecs.umich.edu 5933101Sstever@eecs.umich.edu @classmethod 5943102Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 5953101Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 5963101Sstever@eecs.umich.edu # code('#include "base/str.hh"') 5973101Sstever@eecs.umich.edu pass 5983101Sstever@eecs.umich.edu 5993101Sstever@eecs.umich.edu @classmethod 6003101Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 6013101Sstever@eecs.umich.edu code('uint64_t _temp;') 6023101Sstever@eecs.umich.edu code('bool _ret = to_number(%s, _temp);' % src) 6033101Sstever@eecs.umich.edu code('if (_ret)') 6043101Sstever@eecs.umich.edu code(' %s = Cycles(_temp);' % dest) 6053101Sstever@eecs.umich.edu code('%s _ret;' % ret) 6063101Sstever@eecs.umich.edu 6073101Sstever@eecs.umich.educlass Float(ParamValue, float): 6083101Sstever@eecs.umich.edu cxx_type = 'double' 6093101Sstever@eecs.umich.edu cmd_line_settable = True 6103101Sstever@eecs.umich.edu 6113101Sstever@eecs.umich.edu def __init__(self, value): 6123101Sstever@eecs.umich.edu if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 6133101Sstever@eecs.umich.edu self.value = float(value) 6143101Sstever@eecs.umich.edu else: 6153101Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to Float" \ 6163101Sstever@eecs.umich.edu % type(value).__name__ 6173101Sstever@eecs.umich.edu 6183101Sstever@eecs.umich.edu def __call__(self, value): 6193101Sstever@eecs.umich.edu self.__init__(value) 6203101Sstever@eecs.umich.edu return value 6213101Sstever@eecs.umich.edu 6223101Sstever@eecs.umich.edu def getValue(self): 6233101Sstever@eecs.umich.edu return float(self.value) 6243101Sstever@eecs.umich.edu 6253101Sstever@eecs.umich.edu def config_value(self): 6263101Sstever@eecs.umich.edu return self 6273101Sstever@eecs.umich.edu 6283101Sstever@eecs.umich.edu @classmethod 6293101Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 6303101Sstever@eecs.umich.edu code('#include <sstream>') 6313101Sstever@eecs.umich.edu 6323101Sstever@eecs.umich.edu @classmethod 6333101Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 6343101Sstever@eecs.umich.edu code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 6353101Sstever@eecs.umich.edu 6363101Sstever@eecs.umich.educlass MemorySize(CheckedInt): 6373101Sstever@eecs.umich.edu cxx_type = 'uint64_t' 6383101Sstever@eecs.umich.edu ex_str = '512MB' 6393101Sstever@eecs.umich.edu size = 64 6403101Sstever@eecs.umich.edu unsigned = True 6413101Sstever@eecs.umich.edu def __init__(self, value): 6423101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 6433101Sstever@eecs.umich.edu self.value = value.value 6443101Sstever@eecs.umich.edu else: 6453101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 6463101Sstever@eecs.umich.edu self._check() 6473101Sstever@eecs.umich.edu 6483101Sstever@eecs.umich.educlass MemorySize32(CheckedInt): 6493101Sstever@eecs.umich.edu cxx_type = 'uint32_t' 6503101Sstever@eecs.umich.edu ex_str = '512MB' 6513101Sstever@eecs.umich.edu size = 32 6523101Sstever@eecs.umich.edu unsigned = True 6533101Sstever@eecs.umich.edu def __init__(self, value): 6543101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 6553101Sstever@eecs.umich.edu self.value = value.value 6563101Sstever@eecs.umich.edu else: 6573101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 6583101Sstever@eecs.umich.edu self._check() 6593101Sstever@eecs.umich.edu 6603101Sstever@eecs.umich.educlass Addr(CheckedInt): 6613101Sstever@eecs.umich.edu cxx_type = 'Addr' 6623101Sstever@eecs.umich.edu size = 64 6633101Sstever@eecs.umich.edu unsigned = True 6643101Sstever@eecs.umich.edu def __init__(self, value): 6653101Sstever@eecs.umich.edu if isinstance(value, Addr): 6663101Sstever@eecs.umich.edu self.value = value.value 6673101Sstever@eecs.umich.edu else: 6683101Sstever@eecs.umich.edu try: 6693101Sstever@eecs.umich.edu # Often addresses are referred to with sizes. Ex: A device 6703101Sstever@eecs.umich.edu # base address is at "512MB". Use toMemorySize() to convert 6713101Sstever@eecs.umich.edu # these into addresses. If the address is not specified with a 6723101Sstever@eecs.umich.edu # "size", an exception will occur and numeric translation will 6733101Sstever@eecs.umich.edu # proceed below. 6743101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 6753101Sstever@eecs.umich.edu except (TypeError, ValueError): 6763101Sstever@eecs.umich.edu # Convert number to string and use long() to do automatic 6773101Sstever@eecs.umich.edu # base conversion (requires base=0 for auto-conversion) 6783101Sstever@eecs.umich.edu self.value = long(str(value), base=0) 6793101Sstever@eecs.umich.edu 6803101Sstever@eecs.umich.edu self._check() 6813101Sstever@eecs.umich.edu def __add__(self, other): 6823101Sstever@eecs.umich.edu if isinstance(other, Addr): 6833102Sstever@eecs.umich.edu return self.value + other.value 6843101Sstever@eecs.umich.edu else: 6853101Sstever@eecs.umich.edu return self.value + other 6863101Sstever@eecs.umich.edu def pretty_print(self, value): 6873101Sstever@eecs.umich.edu try: 6883101Sstever@eecs.umich.edu val = convert.toMemorySize(value) 6893101Sstever@eecs.umich.edu except TypeError: 6903101Sstever@eecs.umich.edu val = long(value) 6913101Sstever@eecs.umich.edu return "0x%x" % long(val) 6923101Sstever@eecs.umich.edu 6933101Sstever@eecs.umich.educlass AddrRange(ParamValue): 6943101Sstever@eecs.umich.edu cxx_type = 'AddrRange' 6953102Sstever@eecs.umich.edu 6963101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 6973101Sstever@eecs.umich.edu # Disable interleaving and hashing by default 6983101Sstever@eecs.umich.edu self.intlvHighBit = 0 6993101Sstever@eecs.umich.edu self.xorHighBit = 0 7003101Sstever@eecs.umich.edu self.intlvBits = 0 7013101Sstever@eecs.umich.edu self.intlvMatch = 0 7023101Sstever@eecs.umich.edu 7033101Sstever@eecs.umich.edu def handle_kwargs(self, kwargs): 7043101Sstever@eecs.umich.edu # An address range needs to have an upper limit, specified 7053101Sstever@eecs.umich.edu # either explicitly with an end, or as an offset using the 7063101Sstever@eecs.umich.edu # size keyword. 7073101Sstever@eecs.umich.edu if 'end' in kwargs: 7083102Sstever@eecs.umich.edu self.end = Addr(kwargs.pop('end')) 7093102Sstever@eecs.umich.edu elif 'size' in kwargs: 7103102Sstever@eecs.umich.edu self.end = self.start + Addr(kwargs.pop('size')) - 1 7113102Sstever@eecs.umich.edu else: 7123102Sstever@eecs.umich.edu raise TypeError, "Either end or size must be specified" 7133102Sstever@eecs.umich.edu 7143102Sstever@eecs.umich.edu # Now on to the optional bit 7153102Sstever@eecs.umich.edu if 'intlvHighBit' in kwargs: 7163102Sstever@eecs.umich.edu self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 7173102Sstever@eecs.umich.edu if 'xorHighBit' in kwargs: 7183102Sstever@eecs.umich.edu self.xorHighBit = int(kwargs.pop('xorHighBit')) 7193102Sstever@eecs.umich.edu if 'intlvBits' in kwargs: 7203102Sstever@eecs.umich.edu self.intlvBits = int(kwargs.pop('intlvBits')) 7213102Sstever@eecs.umich.edu if 'intlvMatch' in kwargs: 7223102Sstever@eecs.umich.edu self.intlvMatch = int(kwargs.pop('intlvMatch')) 7233102Sstever@eecs.umich.edu 7243102Sstever@eecs.umich.edu if len(args) == 0: 7253102Sstever@eecs.umich.edu self.start = Addr(kwargs.pop('start')) 7263102Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 7273102Sstever@eecs.umich.edu 7283102Sstever@eecs.umich.edu elif len(args) == 1: 7293102Sstever@eecs.umich.edu if kwargs: 7303102Sstever@eecs.umich.edu self.start = Addr(args[0]) 7313102Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 7323102Sstever@eecs.umich.edu elif isinstance(args[0], (list, tuple)): 7333102Sstever@eecs.umich.edu self.start = Addr(args[0][0]) 7343102Sstever@eecs.umich.edu self.end = Addr(args[0][1]) 7353102Sstever@eecs.umich.edu else: 7363102Sstever@eecs.umich.edu self.start = Addr(0) 7373102Sstever@eecs.umich.edu self.end = Addr(args[0]) - 1 7383101Sstever@eecs.umich.edu 7393101Sstever@eecs.umich.edu elif len(args) == 2: 7403101Sstever@eecs.umich.edu self.start = Addr(args[0]) 7413101Sstever@eecs.umich.edu self.end = Addr(args[1]) 7423101Sstever@eecs.umich.edu else: 7433101Sstever@eecs.umich.edu raise TypeError, "Too many arguments specified" 7443101Sstever@eecs.umich.edu 7453101Sstever@eecs.umich.edu if kwargs: 7463101Sstever@eecs.umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 7473101Sstever@eecs.umich.edu 7483101Sstever@eecs.umich.edu def __str__(self): 7493101Sstever@eecs.umich.edu return '%s:%s:%s:%s:%s:%s' \ 7503101Sstever@eecs.umich.edu % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\ 7513101Sstever@eecs.umich.edu self.intlvBits, self.intlvMatch) 7523101Sstever@eecs.umich.edu 7533101Sstever@eecs.umich.edu def size(self): 7543101Sstever@eecs.umich.edu # Divide the size by the size of the interleaving slice 7553105Sstever@eecs.umich.edu return (long(self.end) - long(self.start) + 1) >> self.intlvBits 7563105Sstever@eecs.umich.edu 7573101Sstever@eecs.umich.edu @classmethod 7583101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 7593101Sstever@eecs.umich.edu Addr.cxx_predecls(code) 7603101Sstever@eecs.umich.edu code('#include "base/addr_range.hh"') 7613105Sstever@eecs.umich.edu 7623101Sstever@eecs.umich.edu @classmethod 7633103Sstever@eecs.umich.edu def pybind_predecls(cls, code): 7643105Sstever@eecs.umich.edu Addr.pybind_predecls(code) 7653103Sstever@eecs.umich.edu code('#include "base/addr_range.hh"') 7663105Sstever@eecs.umich.edu 7673105Sstever@eecs.umich.edu @classmethod 7683105Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 7693105Sstever@eecs.umich.edu code('#include <sstream>') 7703105Sstever@eecs.umich.edu 7713105Sstever@eecs.umich.edu @classmethod 7723105Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 7733105Sstever@eecs.umich.edu code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;') 7743105Sstever@eecs.umich.edu code('uint64_t _intlvBits = 0, _intlvMatch = 0;') 7753105Sstever@eecs.umich.edu code('char _sep;') 7763105Sstever@eecs.umich.edu code('std::istringstream _stream(${src});') 7773105Sstever@eecs.umich.edu code('_stream >> _start;') 7783105Sstever@eecs.umich.edu code('_stream.get(_sep);') 7793105Sstever@eecs.umich.edu code('_stream >> _end;') 7803105Sstever@eecs.umich.edu code('if (!_stream.fail() && !_stream.eof()) {') 7813105Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7823105Sstever@eecs.umich.edu code(' _stream >> _intlvHighBit;') 7833105Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7843105Sstever@eecs.umich.edu code(' _stream >> _xorHighBit;') 7853105Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7863105Sstever@eecs.umich.edu code(' _stream >> _intlvBits;') 7873105Sstever@eecs.umich.edu code(' _stream.get(_sep);') 7883105Sstever@eecs.umich.edu code(' _stream >> _intlvMatch;') 7893105Sstever@eecs.umich.edu code('}') 7903105Sstever@eecs.umich.edu code('bool _ret = !_stream.fail() &&' 7913105Sstever@eecs.umich.edu '_stream.eof() && _sep == \':\';') 7923101Sstever@eecs.umich.edu code('if (_ret)') 7933105Sstever@eecs.umich.edu code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \ 7943105Sstever@eecs.umich.edu _xorHighBit, _intlvBits, _intlvMatch);') 7953105Sstever@eecs.umich.edu code('${ret} _ret;') 7963101Sstever@eecs.umich.edu 7973105Sstever@eecs.umich.edu def getValue(self): 7983105Sstever@eecs.umich.edu # Go from the Python class to the wrapped C++ class 7993105Sstever@eecs.umich.edu from _m5.range import AddrRange 8003101Sstever@eecs.umich.edu 8013105Sstever@eecs.umich.edu return AddrRange(long(self.start), long(self.end), 8023105Sstever@eecs.umich.edu int(self.intlvHighBit), int(self.xorHighBit), 8033101Sstever@eecs.umich.edu int(self.intlvBits), int(self.intlvMatch)) 8043105Sstever@eecs.umich.edu 8053105Sstever@eecs.umich.edu# Boolean parameter type. Python doesn't let you subclass bool, since 8063105Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and 8073105Sstever@eecs.umich.edu# False. Thus this is a little more complicated than String. 8083101Sstever@eecs.umich.educlass Bool(ParamValue): 8093101Sstever@eecs.umich.edu cxx_type = 'bool' 8103105Sstever@eecs.umich.edu cmd_line_settable = True 8113105Sstever@eecs.umich.edu 8123105Sstever@eecs.umich.edu def __init__(self, value): 8133105Sstever@eecs.umich.edu try: 8143105Sstever@eecs.umich.edu self.value = convert.toBool(value) 8153105Sstever@eecs.umich.edu except TypeError: 8163105Sstever@eecs.umich.edu self.value = bool(value) 8173105Sstever@eecs.umich.edu 8183105Sstever@eecs.umich.edu def __call__(self, value): 8193105Sstever@eecs.umich.edu self.__init__(value) 8203105Sstever@eecs.umich.edu return value 8213101Sstever@eecs.umich.edu 8223101Sstever@eecs.umich.edu def getValue(self): 8233101Sstever@eecs.umich.edu return bool(self.value) 8243101Sstever@eecs.umich.edu 8253101Sstever@eecs.umich.edu def __str__(self): 8263101Sstever@eecs.umich.edu return str(self.value) 8273101Sstever@eecs.umich.edu 8283101Sstever@eecs.umich.edu # implement truth value testing for Bool parameters so that these params 8293101Sstever@eecs.umich.edu # evaluate correctly during the python configuration phase 8303101Sstever@eecs.umich.edu def __nonzero__(self): 8313105Sstever@eecs.umich.edu return bool(self.value) 8323105Sstever@eecs.umich.edu 8333105Sstever@eecs.umich.edu def ini_str(self): 8343105Sstever@eecs.umich.edu if self.value: 8353105Sstever@eecs.umich.edu return 'true' 8363105Sstever@eecs.umich.edu return 'false' 8373105Sstever@eecs.umich.edu 8383105Sstever@eecs.umich.edu def config_value(self): 8393105Sstever@eecs.umich.edu return self.value 8403105Sstever@eecs.umich.edu 8413105Sstever@eecs.umich.edu @classmethod 8423105Sstever@eecs.umich.edu def cxx_ini_predecls(cls, code): 8433105Sstever@eecs.umich.edu # Assume that base/str.hh will be included anyway 8443105Sstever@eecs.umich.edu # code('#include "base/str.hh"') 8453105Sstever@eecs.umich.edu pass 8463105Sstever@eecs.umich.edu 8473105Sstever@eecs.umich.edu @classmethod 8483105Sstever@eecs.umich.edu def cxx_ini_parse(cls, code, src, dest, ret): 8493105Sstever@eecs.umich.edu code('%s to_bool(%s, %s);' % (ret, src, dest)) 8503105Sstever@eecs.umich.edu 8513105Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1): 8523105Sstever@eecs.umich.edu bytes = map(lambda x: int(x, 16), addr.split(':')) 8533105Sstever@eecs.umich.edu bytes[5] += val 8543105Sstever@eecs.umich.edu for i in (5, 4, 3, 2, 1): 8553105Sstever@eecs.umich.edu val,rem = divmod(bytes[i], 256) 8563105Sstever@eecs.umich.edu bytes[i] = rem 8573105Sstever@eecs.umich.edu if val == 0: 8583105Sstever@eecs.umich.edu break 8593105Sstever@eecs.umich.edu bytes[i - 1] += val 8603105Sstever@eecs.umich.edu assert(bytes[0] <= 255) 8613105Sstever@eecs.umich.edu return ':'.join(map(lambda x: '%02x' % x, bytes)) 8623105Sstever@eecs.umich.edu 8633105Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01" 8643105Sstever@eecs.umich.edudef NextEthernetAddr(): 8653105Sstever@eecs.umich.edu global _NextEthernetAddr 8663105Sstever@eecs.umich.edu 8673105Sstever@eecs.umich.edu value = _NextEthernetAddr 8683105Sstever@eecs.umich.edu _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 8693105Sstever@eecs.umich.edu return value 8703105Sstever@eecs.umich.edu 8713105Sstever@eecs.umich.educlass EthernetAddr(ParamValue): 8723105Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 8733105Sstever@eecs.umich.edu ex_str = "00:90:00:00:00:01" 8743105Sstever@eecs.umich.edu cmd_line_settable = True 8753105Sstever@eecs.umich.edu 8763105Sstever@eecs.umich.edu @classmethod 8773105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 8783105Sstever@eecs.umich.edu code('#include "base/inet.hh"') 8793105Sstever@eecs.umich.edu 8803105Sstever@eecs.umich.edu def __init__(self, value): 8813105Sstever@eecs.umich.edu if value == NextEthernetAddr: 8823101Sstever@eecs.umich.edu self.value = value 8833101Sstever@eecs.umich.edu return 8843101Sstever@eecs.umich.edu 8853101Sstever@eecs.umich.edu if not isinstance(value, str): 8863105Sstever@eecs.umich.edu raise TypeError, "expected an ethernet address and didn't get one" 8873105Sstever@eecs.umich.edu 8883105Sstever@eecs.umich.edu bytes = value.split(':') 8893105Sstever@eecs.umich.edu if len(bytes) != 6: 8903105Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 8913105Sstever@eecs.umich.edu 8923105Sstever@eecs.umich.edu for byte in bytes: 8933105Sstever@eecs.umich.edu if not 0 <= int(byte, base=16) <= 0xff: 8943105Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 8953105Sstever@eecs.umich.edu 8963105Sstever@eecs.umich.edu self.value = value 8973101Sstever@eecs.umich.edu 8983101Sstever@eecs.umich.edu def __call__(self, value): 8993101Sstever@eecs.umich.edu self.__init__(value) 9003105Sstever@eecs.umich.edu return value 9013105Sstever@eecs.umich.edu 9023101Sstever@eecs.umich.edu def unproxy(self, base): 9033101Sstever@eecs.umich.edu if self.value == NextEthernetAddr: 9043101Sstever@eecs.umich.edu return EthernetAddr(self.value()) 9053105Sstever@eecs.umich.edu return self 9063105Sstever@eecs.umich.edu 9073101Sstever@eecs.umich.edu def getValue(self): 9083101Sstever@eecs.umich.edu from _m5.net import EthAddr 9093101Sstever@eecs.umich.edu return EthAddr(self.value) 9103101Sstever@eecs.umich.edu 9113105Sstever@eecs.umich.edu def __str__(self): 9123105Sstever@eecs.umich.edu return self.value 9133101Sstever@eecs.umich.edu 9143101Sstever@eecs.umich.edu def ini_str(self): 9153105Sstever@eecs.umich.edu return self.value 9163105Sstever@eecs.umich.edu 9173105Sstever@eecs.umich.edu @classmethod 9183105Sstever@eecs.umich.edu def cxx_ini_parse(self, code, src, dest, ret): 9193101Sstever@eecs.umich.edu code('%s = Net::EthAddr(%s);' % (dest, src)) 9203101Sstever@eecs.umich.edu code('%s true;' % ret) 9213101Sstever@eecs.umich.edu 9223101Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of 9233101Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP. 9243101Sstever@eecs.umich.educlass IpAddress(ParamValue): 9253101Sstever@eecs.umich.edu cxx_type = 'Net::IpAddress' 9263101Sstever@eecs.umich.edu ex_str = "127.0.0.1" 9273101Sstever@eecs.umich.edu cmd_line_settable = True 9283101Sstever@eecs.umich.edu 9293101Sstever@eecs.umich.edu @classmethod 9303101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 9313102Sstever@eecs.umich.edu code('#include "base/inet.hh"') 9323101Sstever@eecs.umich.edu 9333101Sstever@eecs.umich.edu def __init__(self, value): 9343101Sstever@eecs.umich.edu if isinstance(value, IpAddress): 9353102Sstever@eecs.umich.edu self.ip = value.ip 9363101Sstever@eecs.umich.edu else: 9373102Sstever@eecs.umich.edu try: 9383102Sstever@eecs.umich.edu self.ip = convert.toIpAddress(value) 939 except TypeError: 940 self.ip = long(value) 941 self.verifyIp() 942 943 def __call__(self, value): 944 self.__init__(value) 945 return value 946 947 def __str__(self): 948 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 949 return '%d.%d.%d.%d' % tuple(tup) 950 951 def __eq__(self, other): 952 if isinstance(other, IpAddress): 953 return self.ip == other.ip 954 elif isinstance(other, str): 955 try: 956 return self.ip == convert.toIpAddress(other) 957 except: 958 return False 959 else: 960 return self.ip == other 961 962 def __ne__(self, other): 963 return not (self == other) 964 965 def verifyIp(self): 966 if self.ip < 0 or self.ip >= (1 << 32): 967 raise TypeError, "invalid ip address %#08x" % self.ip 968 969 def getValue(self): 970 from _m5.net import IpAddress 971 return IpAddress(self.ip) 972 973# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 974# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 975# positional or keyword arguments. 976class IpNetmask(IpAddress): 977 cxx_type = 'Net::IpNetmask' 978 ex_str = "127.0.0.0/24" 979 cmd_line_settable = True 980 981 @classmethod 982 def cxx_predecls(cls, code): 983 code('#include "base/inet.hh"') 984 985 def __init__(self, *args, **kwargs): 986 def handle_kwarg(self, kwargs, key, elseVal = None): 987 if key in kwargs: 988 setattr(self, key, kwargs.pop(key)) 989 elif elseVal: 990 setattr(self, key, elseVal) 991 else: 992 raise TypeError, "No value set for %s" % key 993 994 if len(args) == 0: 995 handle_kwarg(self, kwargs, 'ip') 996 handle_kwarg(self, kwargs, 'netmask') 997 998 elif len(args) == 1: 999 if kwargs: 1000 if not 'ip' in kwargs and not 'netmask' in kwargs: 1001 raise TypeError, "Invalid arguments" 1002 handle_kwarg(self, kwargs, 'ip', args[0]) 1003 handle_kwarg(self, kwargs, 'netmask', args[0]) 1004 elif isinstance(args[0], IpNetmask): 1005 self.ip = args[0].ip 1006 self.netmask = args[0].netmask 1007 else: 1008 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 1009 1010 elif len(args) == 2: 1011 self.ip = args[0] 1012 self.netmask = args[1] 1013 else: 1014 raise TypeError, "Too many arguments specified" 1015 1016 if kwargs: 1017 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1018 1019 self.verify() 1020 1021 def __call__(self, value): 1022 self.__init__(value) 1023 return value 1024 1025 def __str__(self): 1026 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 1027 1028 def __eq__(self, other): 1029 if isinstance(other, IpNetmask): 1030 return self.ip == other.ip and self.netmask == other.netmask 1031 elif isinstance(other, str): 1032 try: 1033 return (self.ip, self.netmask) == convert.toIpNetmask(other) 1034 except: 1035 return False 1036 else: 1037 return False 1038 1039 def verify(self): 1040 self.verifyIp() 1041 if self.netmask < 0 or self.netmask > 32: 1042 raise TypeError, "invalid netmask %d" % netmask 1043 1044 def getValue(self): 1045 from _m5.net import IpNetmask 1046 return IpNetmask(self.ip, self.netmask) 1047 1048# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 1049# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 1050class IpWithPort(IpAddress): 1051 cxx_type = 'Net::IpWithPort' 1052 ex_str = "127.0.0.1:80" 1053 cmd_line_settable = True 1054 1055 @classmethod 1056 def cxx_predecls(cls, code): 1057 code('#include "base/inet.hh"') 1058 1059 def __init__(self, *args, **kwargs): 1060 def handle_kwarg(self, kwargs, key, elseVal = None): 1061 if key in kwargs: 1062 setattr(self, key, kwargs.pop(key)) 1063 elif elseVal: 1064 setattr(self, key, elseVal) 1065 else: 1066 raise TypeError, "No value set for %s" % key 1067 1068 if len(args) == 0: 1069 handle_kwarg(self, kwargs, 'ip') 1070 handle_kwarg(self, kwargs, 'port') 1071 1072 elif len(args) == 1: 1073 if kwargs: 1074 if not 'ip' in kwargs and not 'port' in kwargs: 1075 raise TypeError, "Invalid arguments" 1076 handle_kwarg(self, kwargs, 'ip', args[0]) 1077 handle_kwarg(self, kwargs, 'port', args[0]) 1078 elif isinstance(args[0], IpWithPort): 1079 self.ip = args[0].ip 1080 self.port = args[0].port 1081 else: 1082 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1083 1084 elif len(args) == 2: 1085 self.ip = args[0] 1086 self.port = args[1] 1087 else: 1088 raise TypeError, "Too many arguments specified" 1089 1090 if kwargs: 1091 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1092 1093 self.verify() 1094 1095 def __call__(self, value): 1096 self.__init__(value) 1097 return value 1098 1099 def __str__(self): 1100 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1101 1102 def __eq__(self, other): 1103 if isinstance(other, IpWithPort): 1104 return self.ip == other.ip and self.port == other.port 1105 elif isinstance(other, str): 1106 try: 1107 return (self.ip, self.port) == convert.toIpWithPort(other) 1108 except: 1109 return False 1110 else: 1111 return False 1112 1113 def verify(self): 1114 self.verifyIp() 1115 if self.port < 0 or self.port > 0xffff: 1116 raise TypeError, "invalid port %d" % self.port 1117 1118 def getValue(self): 1119 from _m5.net import IpWithPort 1120 return IpWithPort(self.ip, self.port) 1121 1122time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1123 "%a %b %d %H:%M:%S %Y", 1124 "%Y/%m/%d %H:%M:%S", 1125 "%Y/%m/%d %H:%M", 1126 "%Y/%m/%d", 1127 "%m/%d/%Y %H:%M:%S", 1128 "%m/%d/%Y %H:%M", 1129 "%m/%d/%Y", 1130 "%m/%d/%y %H:%M:%S", 1131 "%m/%d/%y %H:%M", 1132 "%m/%d/%y"] 1133 1134 1135def parse_time(value): 1136 from time import gmtime, strptime, struct_time, time 1137 from datetime import datetime, date 1138 1139 if isinstance(value, struct_time): 1140 return value 1141 1142 if isinstance(value, (int, long)): 1143 return gmtime(value) 1144 1145 if isinstance(value, (datetime, date)): 1146 return value.timetuple() 1147 1148 if isinstance(value, str): 1149 if value in ('Now', 'Today'): 1150 return time.gmtime(time.time()) 1151 1152 for format in time_formats: 1153 try: 1154 return strptime(value, format) 1155 except ValueError: 1156 pass 1157 1158 raise ValueError, "Could not parse '%s' as a time" % value 1159 1160class Time(ParamValue): 1161 cxx_type = 'tm' 1162 1163 @classmethod 1164 def cxx_predecls(cls, code): 1165 code('#include <time.h>') 1166 1167 def __init__(self, value): 1168 self.value = parse_time(value) 1169 1170 def __call__(self, value): 1171 self.__init__(value) 1172 return value 1173 1174 def getValue(self): 1175 from _m5.core import tm 1176 import calendar 1177 1178 return tm.gmtime(calendar.timegm(self.value)) 1179 1180 def __str__(self): 1181 return time.asctime(self.value) 1182 1183 def ini_str(self): 1184 return str(self) 1185 1186 def get_config_as_dict(self): 1187 assert false 1188 return str(self) 1189 1190 @classmethod 1191 def cxx_ini_predecls(cls, code): 1192 code('#include <time.h>') 1193 1194 @classmethod 1195 def cxx_ini_parse(cls, code, src, dest, ret): 1196 code('char *_parse_ret = strptime((${src}).c_str(),') 1197 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));') 1198 code('${ret} _parse_ret && *_parse_ret == \'\\0\';'); 1199 1200# Enumerated types are a little more complex. The user specifies the 1201# type as Enum(foo) where foo is either a list or dictionary of 1202# alternatives (typically strings, but not necessarily so). (In the 1203# long run, the integer value of the parameter will be the list index 1204# or the corresponding dictionary value. For now, since we only check 1205# that the alternative is valid and then spit it into a .ini file, 1206# there's not much point in using the dictionary.) 1207 1208# What Enum() must do is generate a new type encapsulating the 1209# provided list/dictionary so that specific values of the parameter 1210# can be instances of that type. We define two hidden internal 1211# classes (_ListEnum and _DictEnum) to serve as base classes, then 1212# derive the new type from the appropriate base class on the fly. 1213 1214allEnums = {} 1215# Metaclass for Enum types 1216class MetaEnum(MetaParamValue): 1217 def __new__(mcls, name, bases, dict): 1218 assert name not in allEnums 1219 1220 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1221 allEnums[name] = cls 1222 return cls 1223 1224 def __init__(cls, name, bases, init_dict): 1225 if init_dict.has_key('map'): 1226 if not isinstance(cls.map, dict): 1227 raise TypeError, "Enum-derived class attribute 'map' " \ 1228 "must be of type dict" 1229 # build list of value strings from map 1230 cls.vals = cls.map.keys() 1231 cls.vals.sort() 1232 elif init_dict.has_key('vals'): 1233 if not isinstance(cls.vals, list): 1234 raise TypeError, "Enum-derived class attribute 'vals' " \ 1235 "must be of type list" 1236 # build string->value map from vals sequence 1237 cls.map = {} 1238 for idx,val in enumerate(cls.vals): 1239 cls.map[val] = idx 1240 else: 1241 raise TypeError, "Enum-derived class must define "\ 1242 "attribute 'map' or 'vals'" 1243 1244 cls.cxx_type = 'Enums::%s' % name 1245 1246 super(MetaEnum, cls).__init__(name, bases, init_dict) 1247 1248 # Generate C++ class declaration for this enum type. 1249 # Note that we wrap the enum in a class/struct to act as a namespace, 1250 # so that the enum strings can be brief w/o worrying about collisions. 1251 def cxx_decl(cls, code): 1252 wrapper_name = cls.wrapper_name 1253 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1254 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1255 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1256 1257 code('''\ 1258#ifndef $idem_macro 1259#define $idem_macro 1260 1261$wrapper $wrapper_name { 1262 enum $name { 1263''') 1264 code.indent(2) 1265 for val in cls.vals: 1266 code('$val = ${{cls.map[val]}},') 1267 code('Num_$name = ${{len(cls.vals)}}') 1268 code.dedent(2) 1269 code(' };') 1270 1271 if cls.wrapper_is_struct: 1272 code(' static const char *${name}Strings[Num_${name}];') 1273 code('};') 1274 else: 1275 code('extern const char *${name}Strings[Num_${name}];') 1276 code('}') 1277 1278 code() 1279 code('#endif // $idem_macro') 1280 1281 def cxx_def(cls, code): 1282 wrapper_name = cls.wrapper_name 1283 file_name = cls.__name__ 1284 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1285 1286 code('#include "enums/$file_name.hh"') 1287 if cls.wrapper_is_struct: 1288 code('const char *${wrapper_name}::${name}Strings' 1289 '[Num_${name}] =') 1290 else: 1291 code('namespace Enums {') 1292 code.indent(1) 1293 code(' const char *${name}Strings[Num_${name}] =') 1294 1295 code('{') 1296 code.indent(1) 1297 for val in cls.vals: 1298 code('"$val",') 1299 code.dedent(1) 1300 code('};') 1301 1302 if not cls.wrapper_is_struct: 1303 code('} // namespace $wrapper_name') 1304 code.dedent(1) 1305 1306 def pybind_def(cls, code): 1307 name = cls.__name__ 1308 wrapper_name = cls.wrapper_name 1309 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name 1310 1311 code('''#include "pybind11/pybind11.h" 1312#include "pybind11/stl.h" 1313 1314#include <sim/init.hh> 1315 1316namespace py = pybind11; 1317 1318static void 1319module_init(py::module &m_internal) 1320{ 1321 py::module m = m_internal.def_submodule("enum_${name}"); 1322 1323 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}") 1324''') 1325 1326 code.indent() 1327 code.indent() 1328 for val in cls.vals: 1329 code('.value("${val}", ${wrapper_name}::${val})') 1330 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})') 1331 code('.export_values()') 1332 code(';') 1333 code.dedent() 1334 1335 code('}') 1336 code.dedent() 1337 code() 1338 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);') 1339 1340 1341# Base class for enum types. 1342class Enum(ParamValue): 1343 __metaclass__ = MetaEnum 1344 vals = [] 1345 cmd_line_settable = True 1346 1347 # The name of the wrapping namespace or struct 1348 wrapper_name = 'Enums' 1349 1350 # If true, the enum is wrapped in a struct rather than a namespace 1351 wrapper_is_struct = False 1352 1353 # If not None, use this as the enum name rather than this class name 1354 enum_name = None 1355 1356 def __init__(self, value): 1357 if value not in self.map: 1358 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1359 % (value, self.vals) 1360 self.value = value 1361 1362 def __call__(self, value): 1363 self.__init__(value) 1364 return value 1365 1366 @classmethod 1367 def cxx_predecls(cls, code): 1368 code('#include "enums/$0.hh"', cls.__name__) 1369 1370 @classmethod 1371 def cxx_ini_parse(cls, code, src, dest, ret): 1372 code('if (false) {') 1373 for elem_name in cls.map.iterkeys(): 1374 code('} else if (%s == "%s") {' % (src, elem_name)) 1375 code.indent() 1376 code('%s = Enums::%s;' % (dest, elem_name)) 1377 code('%s true;' % ret) 1378 code.dedent() 1379 code('} else {') 1380 code(' %s false;' % ret) 1381 code('}') 1382 1383 def getValue(self): 1384 import m5.internal.params 1385 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__) 1386 return e(self.map[self.value]) 1387 1388 def __str__(self): 1389 return self.value 1390 1391# how big does a rounding error need to be before we warn about it? 1392frequency_tolerance = 0.001 # 0.1% 1393 1394class TickParamValue(NumericParamValue): 1395 cxx_type = 'Tick' 1396 ex_str = "1MHz" 1397 cmd_line_settable = True 1398 1399 @classmethod 1400 def cxx_predecls(cls, code): 1401 code('#include "base/types.hh"') 1402 1403 def __call__(self, value): 1404 self.__init__(value) 1405 return value 1406 1407 def getValue(self): 1408 return long(self.value) 1409 1410 @classmethod 1411 def cxx_ini_predecls(cls, code): 1412 code('#include <sstream>') 1413 1414 # Ticks are expressed in seconds in JSON files and in plain 1415 # Ticks in .ini files. Switch based on a config flag 1416 @classmethod 1417 def cxx_ini_parse(self, code, src, dest, ret): 1418 code('${ret} to_number(${src}, ${dest});') 1419 1420class Latency(TickParamValue): 1421 ex_str = "100ns" 1422 1423 def __init__(self, value): 1424 if isinstance(value, (Latency, Clock)): 1425 self.ticks = value.ticks 1426 self.value = value.value 1427 elif isinstance(value, Frequency): 1428 self.ticks = value.ticks 1429 self.value = 1.0 / value.value 1430 elif value.endswith('t'): 1431 self.ticks = True 1432 self.value = int(value[:-1]) 1433 else: 1434 self.ticks = False 1435 self.value = convert.toLatency(value) 1436 1437 def __call__(self, value): 1438 self.__init__(value) 1439 return value 1440 1441 def __getattr__(self, attr): 1442 if attr in ('latency', 'period'): 1443 return self 1444 if attr == 'frequency': 1445 return Frequency(self) 1446 raise AttributeError, "Latency object has no attribute '%s'" % attr 1447 1448 def getValue(self): 1449 if self.ticks or self.value == 0: 1450 value = self.value 1451 else: 1452 value = ticks.fromSeconds(self.value) 1453 return long(value) 1454 1455 def config_value(self): 1456 return self.getValue() 1457 1458 # convert latency to ticks 1459 def ini_str(self): 1460 return '%d' % self.getValue() 1461 1462class Frequency(TickParamValue): 1463 ex_str = "1GHz" 1464 1465 def __init__(self, value): 1466 if isinstance(value, (Latency, Clock)): 1467 if value.value == 0: 1468 self.value = 0 1469 else: 1470 self.value = 1.0 / value.value 1471 self.ticks = value.ticks 1472 elif isinstance(value, Frequency): 1473 self.value = value.value 1474 self.ticks = value.ticks 1475 else: 1476 self.ticks = False 1477 self.value = convert.toFrequency(value) 1478 1479 def __call__(self, value): 1480 self.__init__(value) 1481 return value 1482 1483 def __getattr__(self, attr): 1484 if attr == 'frequency': 1485 return self 1486 if attr in ('latency', 'period'): 1487 return Latency(self) 1488 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1489 1490 # convert latency to ticks 1491 def getValue(self): 1492 if self.ticks or self.value == 0: 1493 value = self.value 1494 else: 1495 value = ticks.fromSeconds(1.0 / self.value) 1496 return long(value) 1497 1498 def config_value(self): 1499 return self.getValue() 1500 1501 def ini_str(self): 1502 return '%d' % self.getValue() 1503 1504# A generic Frequency and/or Latency value. Value is stored as a 1505# latency, just like Latency and Frequency. 1506class Clock(TickParamValue): 1507 def __init__(self, value): 1508 if isinstance(value, (Latency, Clock)): 1509 self.ticks = value.ticks 1510 self.value = value.value 1511 elif isinstance(value, Frequency): 1512 self.ticks = value.ticks 1513 self.value = 1.0 / value.value 1514 elif value.endswith('t'): 1515 self.ticks = True 1516 self.value = int(value[:-1]) 1517 else: 1518 self.ticks = False 1519 self.value = convert.anyToLatency(value) 1520 1521 def __call__(self, value): 1522 self.__init__(value) 1523 return value 1524 1525 def __str__(self): 1526 return "%s" % Latency(self) 1527 1528 def __getattr__(self, attr): 1529 if attr == 'frequency': 1530 return Frequency(self) 1531 if attr in ('latency', 'period'): 1532 return Latency(self) 1533 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1534 1535 def getValue(self): 1536 return self.period.getValue() 1537 1538 def config_value(self): 1539 return self.period.config_value() 1540 1541 def ini_str(self): 1542 return self.period.ini_str() 1543 1544class Voltage(float,ParamValue): 1545 cxx_type = 'double' 1546 ex_str = "1V" 1547 cmd_line_settable = True 1548 1549 def __new__(cls, value): 1550 # convert to voltage 1551 val = convert.toVoltage(value) 1552 return super(cls, Voltage).__new__(cls, val) 1553 1554 def __call__(self, value): 1555 val = convert.toVoltage(value) 1556 self.__init__(val) 1557 return value 1558 1559 def __str__(self): 1560 return str(self.getValue()) 1561 1562 def getValue(self): 1563 value = float(self) 1564 return value 1565 1566 def ini_str(self): 1567 return '%f' % self.getValue() 1568 1569 @classmethod 1570 def cxx_ini_predecls(cls, code): 1571 code('#include <sstream>') 1572 1573 @classmethod 1574 def cxx_ini_parse(self, code, src, dest, ret): 1575 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1576 1577class Current(float, ParamValue): 1578 cxx_type = 'double' 1579 ex_str = "1mA" 1580 cmd_line_settable = False 1581 1582 def __new__(cls, value): 1583 # convert to current 1584 val = convert.toCurrent(value) 1585 return super(cls, Current).__new__(cls, val) 1586 1587 def __call__(self, value): 1588 val = convert.toCurrent(value) 1589 self.__init__(val) 1590 return value 1591 1592 def __str__(self): 1593 return str(self.getValue()) 1594 1595 def getValue(self): 1596 value = float(self) 1597 return value 1598 1599 def ini_str(self): 1600 return '%f' % self.getValue() 1601 1602 @classmethod 1603 def cxx_ini_predecls(cls, code): 1604 code('#include <sstream>') 1605 1606 @classmethod 1607 def cxx_ini_parse(self, code, src, dest, ret): 1608 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1609 1610class NetworkBandwidth(float,ParamValue): 1611 cxx_type = 'float' 1612 ex_str = "1Gbps" 1613 cmd_line_settable = True 1614 1615 def __new__(cls, value): 1616 # convert to bits per second 1617 val = convert.toNetworkBandwidth(value) 1618 return super(cls, NetworkBandwidth).__new__(cls, val) 1619 1620 def __str__(self): 1621 return str(self.val) 1622 1623 def __call__(self, value): 1624 val = convert.toNetworkBandwidth(value) 1625 self.__init__(val) 1626 return value 1627 1628 def getValue(self): 1629 # convert to seconds per byte 1630 value = 8.0 / float(self) 1631 # convert to ticks per byte 1632 value = ticks.fromSeconds(value) 1633 return float(value) 1634 1635 def ini_str(self): 1636 return '%f' % self.getValue() 1637 1638 def config_value(self): 1639 return '%f' % self.getValue() 1640 1641 @classmethod 1642 def cxx_ini_predecls(cls, code): 1643 code('#include <sstream>') 1644 1645 @classmethod 1646 def cxx_ini_parse(self, code, src, dest, ret): 1647 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1648 1649class MemoryBandwidth(float,ParamValue): 1650 cxx_type = 'float' 1651 ex_str = "1GB/s" 1652 cmd_line_settable = True 1653 1654 def __new__(cls, value): 1655 # convert to bytes per second 1656 val = convert.toMemoryBandwidth(value) 1657 return super(cls, MemoryBandwidth).__new__(cls, val) 1658 1659 def __call__(self, value): 1660 val = convert.toMemoryBandwidth(value) 1661 self.__init__(val) 1662 return value 1663 1664 def getValue(self): 1665 # convert to seconds per byte 1666 value = float(self) 1667 if value: 1668 value = 1.0 / float(self) 1669 # convert to ticks per byte 1670 value = ticks.fromSeconds(value) 1671 return float(value) 1672 1673 def ini_str(self): 1674 return '%f' % self.getValue() 1675 1676 def config_value(self): 1677 return '%f' % self.getValue() 1678 1679 @classmethod 1680 def cxx_ini_predecls(cls, code): 1681 code('#include <sstream>') 1682 1683 @classmethod 1684 def cxx_ini_parse(self, code, src, dest, ret): 1685 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest)) 1686 1687# 1688# "Constants"... handy aliases for various values. 1689# 1690 1691# Special class for NULL pointers. Note the special check in 1692# make_param_value() above that lets these be assigned where a 1693# SimObject is required. 1694# only one copy of a particular node 1695class NullSimObject(object): 1696 __metaclass__ = Singleton 1697 _name = 'Null' 1698 1699 def __call__(cls): 1700 return cls 1701 1702 def _instantiate(self, parent = None, path = ''): 1703 pass 1704 1705 def ini_str(self): 1706 return 'Null' 1707 1708 def unproxy(self, base): 1709 return self 1710 1711 def set_path(self, parent, name): 1712 pass 1713 1714 def set_parent(self, parent, name): 1715 pass 1716 1717 def clear_parent(self, old_parent): 1718 pass 1719 1720 def descendants(self): 1721 return 1722 yield None 1723 1724 def get_config_as_dict(self): 1725 return {} 1726 1727 def __str__(self): 1728 return self._name 1729 1730 def config_value(self): 1731 return None 1732 1733 def getValue(self): 1734 return None 1735 1736# The only instance you'll ever need... 1737NULL = NullSimObject() 1738 1739def isNullPointer(value): 1740 return isinstance(value, NullSimObject) 1741 1742# Some memory range specifications use this as a default upper bound. 1743MaxAddr = Addr.max 1744MaxTick = Tick.max 1745AllMemory = AddrRange(0, MaxAddr) 1746 1747 1748##################################################################### 1749# 1750# Port objects 1751# 1752# Ports are used to interconnect objects in the memory system. 1753# 1754##################################################################### 1755 1756# Port reference: encapsulates a reference to a particular port on a 1757# particular SimObject. 1758class PortRef(object): 1759 def __init__(self, simobj, name, role): 1760 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1761 self.simobj = simobj 1762 self.name = name 1763 self.role = role 1764 self.peer = None # not associated with another port yet 1765 self.ccConnected = False # C++ port connection done? 1766 self.index = -1 # always -1 for non-vector ports 1767 1768 def __str__(self): 1769 return '%s.%s' % (self.simobj, self.name) 1770 1771 def __len__(self): 1772 # Return the number of connected ports, i.e. 0 is we have no 1773 # peer and 1 if we do. 1774 return int(self.peer != None) 1775 1776 # for config.ini, print peer's name (not ours) 1777 def ini_str(self): 1778 return str(self.peer) 1779 1780 # for config.json 1781 def get_config_as_dict(self): 1782 return {'role' : self.role, 'peer' : str(self.peer)} 1783 1784 def __getattr__(self, attr): 1785 if attr == 'peerObj': 1786 # shorthand for proxies 1787 return self.peer.simobj 1788 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1789 (self.__class__.__name__, attr) 1790 1791 # Full connection is symmetric (both ways). Called via 1792 # SimObject.__setattr__ as a result of a port assignment, e.g., 1793 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1794 # e.g., "obj1.portA[3] = obj2.portB". 1795 def connect(self, other): 1796 if isinstance(other, VectorPortRef): 1797 # reference to plain VectorPort is implicit append 1798 other = other._get_next() 1799 if self.peer and not proxy.isproxy(self.peer): 1800 fatal("Port %s is already connected to %s, cannot connect %s\n", 1801 self, self.peer, other); 1802 self.peer = other 1803 if proxy.isproxy(other): 1804 other.set_param_desc(PortParamDesc()) 1805 elif isinstance(other, PortRef): 1806 if other.peer is not self: 1807 other.connect(self) 1808 else: 1809 raise TypeError, \ 1810 "assigning non-port reference '%s' to port '%s'" \ 1811 % (other, self) 1812 1813 # Allow a master/slave port pair to be spliced between 1814 # a port and its connected peer. Useful operation for connecting 1815 # instrumentation structures into a system when it is necessary 1816 # to connect the instrumentation after the full system has been 1817 # constructed. 1818 def splice(self, new_master_peer, new_slave_peer): 1819 if self.peer and not proxy.isproxy(self.peer): 1820 if isinstance(new_master_peer, PortRef) and \ 1821 isinstance(new_slave_peer, PortRef): 1822 old_peer = self.peer 1823 if self.role == 'SLAVE': 1824 self.peer = new_master_peer 1825 old_peer.peer = new_slave_peer 1826 new_master_peer.connect(self) 1827 new_slave_peer.connect(old_peer) 1828 elif self.role == 'MASTER': 1829 self.peer = new_slave_peer 1830 old_peer.peer = new_master_peer 1831 new_slave_peer.connect(self) 1832 new_master_peer.connect(old_peer) 1833 else: 1834 panic("Port %s has unknown role, "+\ 1835 "cannot splice in new peers\n", self) 1836 else: 1837 raise TypeError, \ 1838 "Splicing non-port references '%s','%s' to port '%s'"\ 1839 % (new_peer, peers_new_peer, self) 1840 else: 1841 fatal("Port %s not connected, cannot splice in new peers\n", self) 1842 1843 def clone(self, simobj, memo): 1844 if memo.has_key(self): 1845 return memo[self] 1846 newRef = copy.copy(self) 1847 memo[self] = newRef 1848 newRef.simobj = simobj 1849 assert(isSimObject(newRef.simobj)) 1850 if self.peer and not proxy.isproxy(self.peer): 1851 peerObj = self.peer.simobj(_memo=memo) 1852 newRef.peer = self.peer.clone(peerObj, memo) 1853 assert(not isinstance(newRef.peer, VectorPortRef)) 1854 return newRef 1855 1856 def unproxy(self, simobj): 1857 assert(simobj is self.simobj) 1858 if proxy.isproxy(self.peer): 1859 try: 1860 realPeer = self.peer.unproxy(self.simobj) 1861 except: 1862 print "Error in unproxying port '%s' of %s" % \ 1863 (self.name, self.simobj.path()) 1864 raise 1865 self.connect(realPeer) 1866 1867 # Call C++ to create corresponding port connection between C++ objects 1868 def ccConnect(self): 1869 from _m5.pyobject import connectPorts 1870 1871 if self.role == 'SLAVE': 1872 # do nothing and let the master take care of it 1873 return 1874 1875 if self.ccConnected: # already done this 1876 return 1877 peer = self.peer 1878 if not self.peer: # nothing to connect to 1879 return 1880 1881 # check that we connect a master to a slave 1882 if self.role == peer.role: 1883 raise TypeError, \ 1884 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1885 % (peer, self, self.role) 1886 1887 try: 1888 # self is always the master and peer the slave 1889 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1890 peer.simobj.getCCObject(), peer.name, peer.index) 1891 except: 1892 print "Error connecting port %s.%s to %s.%s" % \ 1893 (self.simobj.path(), self.name, 1894 peer.simobj.path(), peer.name) 1895 raise 1896 self.ccConnected = True 1897 peer.ccConnected = True 1898 1899# A reference to an individual element of a VectorPort... much like a 1900# PortRef, but has an index. 1901class VectorPortElementRef(PortRef): 1902 def __init__(self, simobj, name, role, index): 1903 PortRef.__init__(self, simobj, name, role) 1904 self.index = index 1905 1906 def __str__(self): 1907 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1908 1909# A reference to a complete vector-valued port (not just a single element). 1910# Can be indexed to retrieve individual VectorPortElementRef instances. 1911class VectorPortRef(object): 1912 def __init__(self, simobj, name, role): 1913 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1914 self.simobj = simobj 1915 self.name = name 1916 self.role = role 1917 self.elements = [] 1918 1919 def __str__(self): 1920 return '%s.%s[:]' % (self.simobj, self.name) 1921 1922 def __len__(self): 1923 # Return the number of connected peers, corresponding the the 1924 # length of the elements. 1925 return len(self.elements) 1926 1927 # for config.ini, print peer's name (not ours) 1928 def ini_str(self): 1929 return ' '.join([el.ini_str() for el in self.elements]) 1930 1931 # for config.json 1932 def get_config_as_dict(self): 1933 return {'role' : self.role, 1934 'peer' : [el.ini_str() for el in self.elements]} 1935 1936 def __getitem__(self, key): 1937 if not isinstance(key, int): 1938 raise TypeError, "VectorPort index must be integer" 1939 if key >= len(self.elements): 1940 # need to extend list 1941 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1942 for i in range(len(self.elements), key+1)] 1943 self.elements.extend(ext) 1944 return self.elements[key] 1945 1946 def _get_next(self): 1947 return self[len(self.elements)] 1948 1949 def __setitem__(self, key, value): 1950 if not isinstance(key, int): 1951 raise TypeError, "VectorPort index must be integer" 1952 self[key].connect(value) 1953 1954 def connect(self, other): 1955 if isinstance(other, (list, tuple)): 1956 # Assign list of port refs to vector port. 1957 # For now, append them... not sure if that's the right semantics 1958 # or if it should replace the current vector. 1959 for ref in other: 1960 self._get_next().connect(ref) 1961 else: 1962 # scalar assignment to plain VectorPort is implicit append 1963 self._get_next().connect(other) 1964 1965 def clone(self, simobj, memo): 1966 if memo.has_key(self): 1967 return memo[self] 1968 newRef = copy.copy(self) 1969 memo[self] = newRef 1970 newRef.simobj = simobj 1971 assert(isSimObject(newRef.simobj)) 1972 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1973 return newRef 1974 1975 def unproxy(self, simobj): 1976 [el.unproxy(simobj) for el in self.elements] 1977 1978 def ccConnect(self): 1979 [el.ccConnect() for el in self.elements] 1980 1981# Port description object. Like a ParamDesc object, this represents a 1982# logical port in the SimObject class, not a particular port on a 1983# SimObject instance. The latter are represented by PortRef objects. 1984class Port(object): 1985 # Generate a PortRef for this port on the given SimObject with the 1986 # given name 1987 def makeRef(self, simobj): 1988 return PortRef(simobj, self.name, self.role) 1989 1990 # Connect an instance of this port (on the given SimObject with 1991 # the given name) with the port described by the supplied PortRef 1992 def connect(self, simobj, ref): 1993 self.makeRef(simobj).connect(ref) 1994 1995 # No need for any pre-declarations at the moment as we merely rely 1996 # on an unsigned int. 1997 def cxx_predecls(self, code): 1998 pass 1999 2000 def pybind_predecls(self, code): 2001 cls.cxx_predecls(self, code) 2002 2003 # Declare an unsigned int with the same name as the port, that 2004 # will eventually hold the number of connected ports (and thus the 2005 # number of elements for a VectorPort). 2006 def cxx_decl(self, code): 2007 code('unsigned int port_${{self.name}}_connection_count;') 2008 2009class MasterPort(Port): 2010 # MasterPort("description") 2011 def __init__(self, *args): 2012 if len(args) == 1: 2013 self.desc = args[0] 2014 self.role = 'MASTER' 2015 else: 2016 raise TypeError, 'wrong number of arguments' 2017 2018class SlavePort(Port): 2019 # SlavePort("description") 2020 def __init__(self, *args): 2021 if len(args) == 1: 2022 self.desc = args[0] 2023 self.role = 'SLAVE' 2024 else: 2025 raise TypeError, 'wrong number of arguments' 2026 2027# VectorPort description object. Like Port, but represents a vector 2028# of connections (e.g., as on a XBar). 2029class VectorPort(Port): 2030 def __init__(self, *args): 2031 self.isVec = True 2032 2033 def makeRef(self, simobj): 2034 return VectorPortRef(simobj, self.name, self.role) 2035 2036class VectorMasterPort(VectorPort): 2037 # VectorMasterPort("description") 2038 def __init__(self, *args): 2039 if len(args) == 1: 2040 self.desc = args[0] 2041 self.role = 'MASTER' 2042 VectorPort.__init__(self, *args) 2043 else: 2044 raise TypeError, 'wrong number of arguments' 2045 2046class VectorSlavePort(VectorPort): 2047 # VectorSlavePort("description") 2048 def __init__(self, *args): 2049 if len(args) == 1: 2050 self.desc = args[0] 2051 self.role = 'SLAVE' 2052 VectorPort.__init__(self, *args) 2053 else: 2054 raise TypeError, 'wrong number of arguments' 2055 2056# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 2057# proxy objects (via set_param_desc()) so that proxy error messages 2058# make sense. 2059class PortParamDesc(object): 2060 __metaclass__ = Singleton 2061 2062 ptype_str = 'Port' 2063 ptype = Port 2064 2065baseEnums = allEnums.copy() 2066baseParams = allParams.copy() 2067 2068def clear(): 2069 global allEnums, allParams 2070 2071 allEnums = baseEnums.copy() 2072 allParams = baseParams.copy() 2073 2074__all__ = ['Param', 'VectorParam', 2075 'Enum', 'Bool', 'String', 'Float', 2076 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 2077 'Int32', 'UInt32', 'Int64', 'UInt64', 2078 'Counter', 'Addr', 'Tick', 'Percent', 2079 'TcpPort', 'UdpPort', 'EthernetAddr', 2080 'IpAddress', 'IpNetmask', 'IpWithPort', 2081 'MemorySize', 'MemorySize32', 2082 'Latency', 'Frequency', 'Clock', 'Voltage', 2083 'NetworkBandwidth', 'MemoryBandwidth', 2084 'AddrRange', 2085 'MaxAddr', 'MaxTick', 'AllMemory', 2086 'Time', 2087 'NextEthernetAddr', 'NULL', 2088 'MasterPort', 'SlavePort', 2089 'VectorMasterPort', 'VectorSlavePort'] 2090 2091import SimObject 2092