params.py revision 9544:1a075d9bc1bc
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2013 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# 493101Sstever@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 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 1043101Sstever@eecs.umich.edu 1053101Sstever@eecs.umich.edu # Generate the code needed as a prerequisite for including a 1063101Sstever@eecs.umich.edu # reference to a C++ object of this type in a SWIG .i file. 1073101Sstever@eecs.umich.edu # Typically generates one or more %import or %include statements. 1083101Sstever@eecs.umich.edu @classmethod 1093101Sstever@eecs.umich.edu def swig_predecls(cls, code): 1103101Sstever@eecs.umich.edu pass 1113101Sstever@eecs.umich.edu 1123101Sstever@eecs.umich.edu # default for printing to .ini file is regular string conversion. 1133101Sstever@eecs.umich.edu # will be overridden in some cases 1143101Sstever@eecs.umich.edu def ini_str(self): 1153101Sstever@eecs.umich.edu return str(self) 1163101Sstever@eecs.umich.edu 1173101Sstever@eecs.umich.edu # allows us to blithely call unproxy() on things without checking 1183101Sstever@eecs.umich.edu # if they're really proxies or not 1193101Sstever@eecs.umich.edu def unproxy(self, base): 1203101Sstever@eecs.umich.edu return self 1213101Sstever@eecs.umich.edu 1223101Sstever@eecs.umich.edu# Regular parameter description. 1233101Sstever@eecs.umich.educlass ParamDesc(object): 1243101Sstever@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 1253101Sstever@eecs.umich.edu self.ptype_str = ptype_str 1263101Sstever@eecs.umich.edu # remember ptype only if it is provided 1273101Sstever@eecs.umich.edu if ptype != None: 1283101Sstever@eecs.umich.edu self.ptype = ptype 1293101Sstever@eecs.umich.edu 1303101Sstever@eecs.umich.edu if args: 1313101Sstever@eecs.umich.edu if len(args) == 1: 1323101Sstever@eecs.umich.edu self.desc = args[0] 1333101Sstever@eecs.umich.edu elif len(args) == 2: 1343101Sstever@eecs.umich.edu self.default = args[0] 1353101Sstever@eecs.umich.edu self.desc = args[1] 1363101Sstever@eecs.umich.edu else: 1373101Sstever@eecs.umich.edu raise TypeError, 'too many arguments' 1383101Sstever@eecs.umich.edu 1393101Sstever@eecs.umich.edu if kwargs.has_key('desc'): 1403101Sstever@eecs.umich.edu assert(not hasattr(self, 'desc')) 1413101Sstever@eecs.umich.edu self.desc = kwargs['desc'] 1423101Sstever@eecs.umich.edu del kwargs['desc'] 1433101Sstever@eecs.umich.edu 1443101Sstever@eecs.umich.edu if kwargs.has_key('default'): 1453101Sstever@eecs.umich.edu assert(not hasattr(self, 'default')) 1463101Sstever@eecs.umich.edu self.default = kwargs['default'] 1473101Sstever@eecs.umich.edu del kwargs['default'] 1483101Sstever@eecs.umich.edu 1493101Sstever@eecs.umich.edu if kwargs: 1503101Sstever@eecs.umich.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 1513101Sstever@eecs.umich.edu 1523101Sstever@eecs.umich.edu if not hasattr(self, 'desc'): 1533101Sstever@eecs.umich.edu raise TypeError, 'desc attribute missing' 1543101Sstever@eecs.umich.edu 1553101Sstever@eecs.umich.edu def __getattr__(self, attr): 1563101Sstever@eecs.umich.edu if attr == 'ptype': 1573101Sstever@eecs.umich.edu ptype = SimObject.allClasses[self.ptype_str] 1583101Sstever@eecs.umich.edu assert isSimObjectClass(ptype) 1593101Sstever@eecs.umich.edu self.ptype = ptype 1603101Sstever@eecs.umich.edu return ptype 1613101Sstever@eecs.umich.edu 1623101Sstever@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 1633101Sstever@eecs.umich.edu (type(self).__name__, attr) 1643101Sstever@eecs.umich.edu 1653101Sstever@eecs.umich.edu def convert(self, value): 1663101Sstever@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 1673101Sstever@eecs.umich.edu value.set_param_desc(self) 1683101Sstever@eecs.umich.edu return value 1693101Sstever@eecs.umich.edu if not hasattr(self, 'ptype') and isNullPointer(value): 1703101Sstever@eecs.umich.edu # deferred evaluation of SimObject; continue to defer if 1713101Sstever@eecs.umich.edu # we're just assigning a null pointer 1723101Sstever@eecs.umich.edu return value 1733101Sstever@eecs.umich.edu if isinstance(value, self.ptype): 1743101Sstever@eecs.umich.edu return value 1753101Sstever@eecs.umich.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 1763101Sstever@eecs.umich.edu return value 1773101Sstever@eecs.umich.edu return self.ptype(value) 1783101Sstever@eecs.umich.edu 1793101Sstever@eecs.umich.edu def cxx_predecls(self, code): 1803101Sstever@eecs.umich.edu code('#include <cstddef>') 1813101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 1823101Sstever@eecs.umich.edu 1833101Sstever@eecs.umich.edu def swig_predecls(self, code): 1843101Sstever@eecs.umich.edu self.ptype.swig_predecls(code) 1853101Sstever@eecs.umich.edu 1863101Sstever@eecs.umich.edu def cxx_decl(self, code): 1873101Sstever@eecs.umich.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 1883101Sstever@eecs.umich.edu 1893101Sstever@eecs.umich.edu# Vector-valued parameter description. Just like ParamDesc, except 1903101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a 1913101Sstever@eecs.umich.edu# single value. 1923101Sstever@eecs.umich.edu 1933101Sstever@eecs.umich.educlass VectorParamValue(list): 1943101Sstever@eecs.umich.edu __metaclass__ = MetaParamValue 1953101Sstever@eecs.umich.edu def __setattr__(self, attr, value): 1963101Sstever@eecs.umich.edu raise AttributeError, \ 1973101Sstever@eecs.umich.edu "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 1983101Sstever@eecs.umich.edu 1993101Sstever@eecs.umich.edu def ini_str(self): 2003101Sstever@eecs.umich.edu return ' '.join([v.ini_str() for v in self]) 2013101Sstever@eecs.umich.edu 2023101Sstever@eecs.umich.edu def getValue(self): 2033101Sstever@eecs.umich.edu return [ v.getValue() for v in self ] 2043101Sstever@eecs.umich.edu 2053101Sstever@eecs.umich.edu def unproxy(self, base): 2063101Sstever@eecs.umich.edu if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 2073101Sstever@eecs.umich.edu return self[0].unproxy(base) 2083101Sstever@eecs.umich.edu else: 2093101Sstever@eecs.umich.edu return [v.unproxy(base) for v in self] 2103101Sstever@eecs.umich.edu 2113101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue): 2123101Sstever@eecs.umich.edu # support clone operation 2133101Sstever@eecs.umich.edu def __call__(self, **kwargs): 2143101Sstever@eecs.umich.edu return SimObjectVector([v(**kwargs) for v in self]) 2153101Sstever@eecs.umich.edu 2163101Sstever@eecs.umich.edu def clear_parent(self, old_parent): 2173101Sstever@eecs.umich.edu for v in self: 2183101Sstever@eecs.umich.edu v.clear_parent(old_parent) 2193101Sstever@eecs.umich.edu 2203101Sstever@eecs.umich.edu def set_parent(self, parent, name): 2213101Sstever@eecs.umich.edu if len(self) == 1: 2223101Sstever@eecs.umich.edu self[0].set_parent(parent, name) 2233101Sstever@eecs.umich.edu else: 2243101Sstever@eecs.umich.edu width = int(math.ceil(math.log(len(self))/math.log(10))) 2253101Sstever@eecs.umich.edu for i,v in enumerate(self): 2263101Sstever@eecs.umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2273101Sstever@eecs.umich.edu 2283101Sstever@eecs.umich.edu def has_parent(self): 2293101Sstever@eecs.umich.edu return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 2303101Sstever@eecs.umich.edu 2313101Sstever@eecs.umich.edu # return 'cpu0 cpu1' etc. for print_ini() 2323101Sstever@eecs.umich.edu def get_name(self): 2333101Sstever@eecs.umich.edu return ' '.join([v._name for v in self]) 2343101Sstever@eecs.umich.edu 2353101Sstever@eecs.umich.edu # By iterating through the constituent members of the vector here 2363101Sstever@eecs.umich.edu # we can nicely handle iterating over all a SimObject's children 2373101Sstever@eecs.umich.edu # without having to provide lots of special functions on 2383101Sstever@eecs.umich.edu # SimObjectVector directly. 2393101Sstever@eecs.umich.edu def descendants(self): 2403101Sstever@eecs.umich.edu for v in self: 2413101Sstever@eecs.umich.edu for obj in v.descendants(): 2423101Sstever@eecs.umich.edu yield obj 2433101Sstever@eecs.umich.edu 2443101Sstever@eecs.umich.edu def get_config_as_dict(self): 2453101Sstever@eecs.umich.edu a = [] 2463101Sstever@eecs.umich.edu for v in self: 2473101Sstever@eecs.umich.edu a.append(v.get_config_as_dict()) 2483101Sstever@eecs.umich.edu return a 2493101Sstever@eecs.umich.edu 2503101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc): 2513101Sstever@eecs.umich.edu # Convert assigned value to appropriate type. If the RHS is not a 2523101Sstever@eecs.umich.edu # list or tuple, it generates a single-element list. 2533101Sstever@eecs.umich.edu def convert(self, value): 2543101Sstever@eecs.umich.edu if isinstance(value, (list, tuple)): 2553101Sstever@eecs.umich.edu # list: coerce each element into new list 2563101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, v) for v in value ] 2573101Sstever@eecs.umich.edu else: 2583101Sstever@eecs.umich.edu # singleton: coerce to a single-element list 2593101Sstever@eecs.umich.edu tmp_list = [ ParamDesc.convert(self, value) ] 2603101Sstever@eecs.umich.edu 2613101Sstever@eecs.umich.edu if isSimObjectSequence(tmp_list): 2623101Sstever@eecs.umich.edu return SimObjectVector(tmp_list) 2633101Sstever@eecs.umich.edu else: 2643101Sstever@eecs.umich.edu return VectorParamValue(tmp_list) 2653101Sstever@eecs.umich.edu 2663101Sstever@eecs.umich.edu def swig_module_name(self): 2673101Sstever@eecs.umich.edu return "%s_vector" % self.ptype_str 2683101Sstever@eecs.umich.edu 2693101Sstever@eecs.umich.edu def swig_predecls(self, code): 2703101Sstever@eecs.umich.edu code('%import "${{self.swig_module_name()}}.i"') 2713101Sstever@eecs.umich.edu 2723101Sstever@eecs.umich.edu def swig_decl(self, code): 2733101Sstever@eecs.umich.edu code('%module(package="m5.internal") ${{self.swig_module_name()}}') 2743101Sstever@eecs.umich.edu code('%{') 2753101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2763101Sstever@eecs.umich.edu code('%}') 2773101Sstever@eecs.umich.edu code() 2783101Sstever@eecs.umich.edu # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 2793101Sstever@eecs.umich.edu code('%include "std_container.i"') 2803101Sstever@eecs.umich.edu code() 2813101Sstever@eecs.umich.edu self.ptype.swig_predecls(code) 2823101Sstever@eecs.umich.edu code() 2833101Sstever@eecs.umich.edu code('%include "std_vector.i"') 2843101Sstever@eecs.umich.edu code() 2853101Sstever@eecs.umich.edu 2863101Sstever@eecs.umich.edu ptype = self.ptype_str 2873101Sstever@eecs.umich.edu cxx_type = self.ptype.cxx_type 2883101Sstever@eecs.umich.edu 2893101Sstever@eecs.umich.edu code('''\ 2903101Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type { 2913101Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 2923101Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, 2933101Sstever@eecs.umich.edu $$descriptor($cxx_type), 0) == -1) { 2943101Sstever@eecs.umich.edu return NULL; 2953101Sstever@eecs.umich.edu } 2963101Sstever@eecs.umich.edu } 2973101Sstever@eecs.umich.edu} 2983101Sstever@eecs.umich.edu 2993101Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type * { 3003101Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 3013101Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, 3023101Sstever@eecs.umich.edu $$descriptor($cxx_type *), 0) == -1) { 3033101Sstever@eecs.umich.edu return NULL; 3043101Sstever@eecs.umich.edu } 3053101Sstever@eecs.umich.edu } 3063101Sstever@eecs.umich.edu} 3073101Sstever@eecs.umich.edu''') 3083101Sstever@eecs.umich.edu 3093101Sstever@eecs.umich.edu code('%template(vector_$ptype) std::vector< $cxx_type >;') 3103101Sstever@eecs.umich.edu 3113101Sstever@eecs.umich.edu def cxx_predecls(self, code): 3123101Sstever@eecs.umich.edu code('#include <vector>') 3133101Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 3143101Sstever@eecs.umich.edu 3153101Sstever@eecs.umich.edu def cxx_decl(self, code): 3163101Sstever@eecs.umich.edu code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 3173101Sstever@eecs.umich.edu 3183101Sstever@eecs.umich.educlass ParamFactory(object): 3193101Sstever@eecs.umich.edu def __init__(self, param_desc_class, ptype_str = None): 3203101Sstever@eecs.umich.edu self.param_desc_class = param_desc_class 3213101Sstever@eecs.umich.edu self.ptype_str = ptype_str 3223101Sstever@eecs.umich.edu 3233101Sstever@eecs.umich.edu def __getattr__(self, attr): 3243101Sstever@eecs.umich.edu if self.ptype_str: 3253101Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 3263101Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 3273101Sstever@eecs.umich.edu 3283101Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 3293101Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 3303101Sstever@eecs.umich.edu ptype = None 3313101Sstever@eecs.umich.edu try: 3323101Sstever@eecs.umich.edu ptype = allParams[self.ptype_str] 3333101Sstever@eecs.umich.edu except KeyError: 3343101Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 3353101Sstever@eecs.umich.edu # try to resolve it later 3363101Sstever@eecs.umich.edu pass 3373101Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 3383101Sstever@eecs.umich.edu 3393101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc) 3403101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc) 3413101Sstever@eecs.umich.edu 3423101Sstever@eecs.umich.edu##################################################################### 3433101Sstever@eecs.umich.edu# 3443101Sstever@eecs.umich.edu# Parameter Types 3453101Sstever@eecs.umich.edu# 3463101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types 3473101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more 3483101Sstever@eecs.umich.edu# flexible to define our own set of types. This gives us more control 3493101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the 3503101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via 3513101Sstever@eecs.umich.edu# the __str__() conversion method). 3523101Sstever@eecs.umich.edu# 3533101Sstever@eecs.umich.edu##################################################################### 3543101Sstever@eecs.umich.edu 3553101Sstever@eecs.umich.edu# String-valued parameter. Just mixin the ParamValue class with the 3563101Sstever@eecs.umich.edu# built-in str class. 3573101Sstever@eecs.umich.educlass String(ParamValue,str): 3583101Sstever@eecs.umich.edu cxx_type = 'std::string' 3593101Sstever@eecs.umich.edu 3603101Sstever@eecs.umich.edu @classmethod 3613101Sstever@eecs.umich.edu def cxx_predecls(self, code): 3623101Sstever@eecs.umich.edu code('#include <string>') 3633101Sstever@eecs.umich.edu 3643101Sstever@eecs.umich.edu @classmethod 3653101Sstever@eecs.umich.edu def swig_predecls(cls, code): 3663101Sstever@eecs.umich.edu code('%include "std_string.i"') 3673101Sstever@eecs.umich.edu 3683101Sstever@eecs.umich.edu def getValue(self): 3693101Sstever@eecs.umich.edu return self 3703101Sstever@eecs.umich.edu 3713101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math 3723101Sstever@eecs.umich.edu# operations in a type-safe way. e.g., a Latency times an int returns 3733101Sstever@eecs.umich.edu# a new Latency object. 3743101Sstever@eecs.umich.educlass NumericParamValue(ParamValue): 3753101Sstever@eecs.umich.edu def __str__(self): 3763101Sstever@eecs.umich.edu return str(self.value) 3773101Sstever@eecs.umich.edu 3783101Sstever@eecs.umich.edu def __float__(self): 3793101Sstever@eecs.umich.edu return float(self.value) 3803101Sstever@eecs.umich.edu 3813101Sstever@eecs.umich.edu def __long__(self): 3823101Sstever@eecs.umich.edu return long(self.value) 3833101Sstever@eecs.umich.edu 3843101Sstever@eecs.umich.edu def __int__(self): 3853101Sstever@eecs.umich.edu return int(self.value) 3863101Sstever@eecs.umich.edu 3873101Sstever@eecs.umich.edu # hook for bounds checking 3883101Sstever@eecs.umich.edu def _check(self): 3893101Sstever@eecs.umich.edu return 3903101Sstever@eecs.umich.edu 3913101Sstever@eecs.umich.edu def __mul__(self, other): 3923101Sstever@eecs.umich.edu newobj = self.__class__(self) 3933101Sstever@eecs.umich.edu newobj.value *= other 3943101Sstever@eecs.umich.edu newobj._check() 3953101Sstever@eecs.umich.edu return newobj 3963101Sstever@eecs.umich.edu 3973101Sstever@eecs.umich.edu __rmul__ = __mul__ 3983101Sstever@eecs.umich.edu 3993101Sstever@eecs.umich.edu def __div__(self, other): 4003101Sstever@eecs.umich.edu newobj = self.__class__(self) 4013101Sstever@eecs.umich.edu newobj.value /= other 4023101Sstever@eecs.umich.edu newobj._check() 4033101Sstever@eecs.umich.edu return newobj 4043101Sstever@eecs.umich.edu 4053101Sstever@eecs.umich.edu def __sub__(self, other): 4063101Sstever@eecs.umich.edu newobj = self.__class__(self) 4073101Sstever@eecs.umich.edu newobj.value -= other 4083101Sstever@eecs.umich.edu newobj._check() 4093101Sstever@eecs.umich.edu return newobj 4103101Sstever@eecs.umich.edu 4113101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters. See CheckedInt. 4123101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue): 4133101Sstever@eecs.umich.edu def __init__(cls, name, bases, dict): 4143101Sstever@eecs.umich.edu super(CheckedIntType, cls).__init__(name, bases, dict) 4153101Sstever@eecs.umich.edu 4163101Sstever@eecs.umich.edu # CheckedInt is an abstract base class, so we actually don't 4173101Sstever@eecs.umich.edu # want to do any processing on it... the rest of this code is 4183101Sstever@eecs.umich.edu # just for classes that derive from CheckedInt. 4193101Sstever@eecs.umich.edu if name == 'CheckedInt': 4203101Sstever@eecs.umich.edu return 4213101Sstever@eecs.umich.edu 4223101Sstever@eecs.umich.edu if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 4233101Sstever@eecs.umich.edu if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 4243101Sstever@eecs.umich.edu panic("CheckedInt subclass %s must define either\n" \ 4253101Sstever@eecs.umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n", 4263101Sstever@eecs.umich.edu name); 4273101Sstever@eecs.umich.edu if cls.unsigned: 4283101Sstever@eecs.umich.edu cls.min = 0 4293101Sstever@eecs.umich.edu cls.max = 2 ** cls.size - 1 4303101Sstever@eecs.umich.edu else: 4313101Sstever@eecs.umich.edu cls.min = -(2 ** (cls.size - 1)) 4323101Sstever@eecs.umich.edu cls.max = (2 ** (cls.size - 1)) - 1 4333101Sstever@eecs.umich.edu 4343101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters. This 4353101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific 4363101Sstever@eecs.umich.edu# bounds. Initialization of the min and max bounds is done in the 4373101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__. 4383101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue): 4393101Sstever@eecs.umich.edu __metaclass__ = CheckedIntType 4403101Sstever@eecs.umich.edu 4413101Sstever@eecs.umich.edu def _check(self): 4423101Sstever@eecs.umich.edu if not self.min <= self.value <= self.max: 4433101Sstever@eecs.umich.edu raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 4443101Sstever@eecs.umich.edu (self.min, self.value, self.max) 4453101Sstever@eecs.umich.edu 4463101Sstever@eecs.umich.edu def __init__(self, value): 4473101Sstever@eecs.umich.edu if isinstance(value, str): 4483101Sstever@eecs.umich.edu self.value = convert.toInteger(value) 4493101Sstever@eecs.umich.edu elif isinstance(value, (int, long, float, NumericParamValue)): 4503101Sstever@eecs.umich.edu self.value = long(value) 4513101Sstever@eecs.umich.edu else: 4523101Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to CheckedInt" \ 4533101Sstever@eecs.umich.edu % type(value).__name__ 4543101Sstever@eecs.umich.edu self._check() 4553101Sstever@eecs.umich.edu 4563101Sstever@eecs.umich.edu @classmethod 4573101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 4583101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 4593101Sstever@eecs.umich.edu code('#include "base/types.hh"') 4603101Sstever@eecs.umich.edu 4613101Sstever@eecs.umich.edu @classmethod 4623101Sstever@eecs.umich.edu def swig_predecls(cls, code): 4633101Sstever@eecs.umich.edu # most derived types require this, so we just do it here once 4643101Sstever@eecs.umich.edu code('%import "stdint.i"') 4653101Sstever@eecs.umich.edu code('%import "base/types.hh"') 4663101Sstever@eecs.umich.edu 4673101Sstever@eecs.umich.edu def getValue(self): 4683101Sstever@eecs.umich.edu return long(self.value) 4693101Sstever@eecs.umich.edu 4703101Sstever@eecs.umich.educlass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 4713101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 4723101Sstever@eecs.umich.edu 4733101Sstever@eecs.umich.educlass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 4743101Sstever@eecs.umich.educlass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 4753101Sstever@eecs.umich.educlass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 4763101Sstever@eecs.umich.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4773101Sstever@eecs.umich.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 4783101Sstever@eecs.umich.educlass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 4793101Sstever@eecs.umich.educlass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 4803101Sstever@eecs.umich.educlass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 4813101Sstever@eecs.umich.edu 4823101Sstever@eecs.umich.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 4833101Sstever@eecs.umich.educlass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 4843101Sstever@eecs.umich.educlass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4853101Sstever@eecs.umich.educlass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4863101Sstever@eecs.umich.edu 4873101Sstever@eecs.umich.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 4883101Sstever@eecs.umich.edu 4893101Sstever@eecs.umich.educlass Cycles(CheckedInt): 4903101Sstever@eecs.umich.edu cxx_type = 'Cycles' 4913101Sstever@eecs.umich.edu size = 64 4923101Sstever@eecs.umich.edu unsigned = True 4933101Sstever@eecs.umich.edu 4943101Sstever@eecs.umich.edu def getValue(self): 4953101Sstever@eecs.umich.edu from m5.internal.core import Cycles 4963101Sstever@eecs.umich.edu return Cycles(self.value) 4973101Sstever@eecs.umich.edu 4983101Sstever@eecs.umich.educlass Float(ParamValue, float): 4993101Sstever@eecs.umich.edu cxx_type = 'double' 5003101Sstever@eecs.umich.edu 5013101Sstever@eecs.umich.edu def __init__(self, value): 5023101Sstever@eecs.umich.edu if isinstance(value, (int, long, float, NumericParamValue, Float)): 5033101Sstever@eecs.umich.edu self.value = float(value) 5043101Sstever@eecs.umich.edu else: 5053101Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to Float" \ 5063101Sstever@eecs.umich.edu % type(value).__name__ 5073101Sstever@eecs.umich.edu 5083101Sstever@eecs.umich.edu def getValue(self): 5093101Sstever@eecs.umich.edu return float(self.value) 5103101Sstever@eecs.umich.edu 5113101Sstever@eecs.umich.educlass MemorySize(CheckedInt): 5123101Sstever@eecs.umich.edu cxx_type = 'uint64_t' 5133101Sstever@eecs.umich.edu size = 64 5143101Sstever@eecs.umich.edu unsigned = True 5153101Sstever@eecs.umich.edu def __init__(self, value): 5163101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 5173101Sstever@eecs.umich.edu self.value = value.value 5183101Sstever@eecs.umich.edu else: 5193101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 5203101Sstever@eecs.umich.edu self._check() 5213101Sstever@eecs.umich.edu 5223101Sstever@eecs.umich.educlass MemorySize32(CheckedInt): 5233101Sstever@eecs.umich.edu cxx_type = 'uint32_t' 5243101Sstever@eecs.umich.edu size = 32 5253101Sstever@eecs.umich.edu unsigned = True 5263101Sstever@eecs.umich.edu def __init__(self, value): 5273101Sstever@eecs.umich.edu if isinstance(value, MemorySize): 5283101Sstever@eecs.umich.edu self.value = value.value 5293101Sstever@eecs.umich.edu else: 5303101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 5313101Sstever@eecs.umich.edu self._check() 5323101Sstever@eecs.umich.edu 5333101Sstever@eecs.umich.educlass Addr(CheckedInt): 5343101Sstever@eecs.umich.edu cxx_type = 'Addr' 5353101Sstever@eecs.umich.edu size = 64 5363101Sstever@eecs.umich.edu unsigned = True 5373101Sstever@eecs.umich.edu def __init__(self, value): 5383101Sstever@eecs.umich.edu if isinstance(value, Addr): 5393101Sstever@eecs.umich.edu self.value = value.value 5403101Sstever@eecs.umich.edu else: 5413101Sstever@eecs.umich.edu try: 5423101Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 5433101Sstever@eecs.umich.edu except TypeError: 5443101Sstever@eecs.umich.edu self.value = long(value) 5453101Sstever@eecs.umich.edu self._check() 5463101Sstever@eecs.umich.edu def __add__(self, other): 5473101Sstever@eecs.umich.edu if isinstance(other, Addr): 5483101Sstever@eecs.umich.edu return self.value + other.value 5493101Sstever@eecs.umich.edu else: 5503101Sstever@eecs.umich.edu return self.value + other 5513101Sstever@eecs.umich.edu 5523101Sstever@eecs.umich.educlass AddrRange(ParamValue): 5533101Sstever@eecs.umich.edu cxx_type = 'AddrRange' 5543101Sstever@eecs.umich.edu 5553101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 5563101Sstever@eecs.umich.edu # Disable interleaving by default 5573101Sstever@eecs.umich.edu self.intlvHighBit = 0 5583101Sstever@eecs.umich.edu self.intlvBits = 0 5593101Sstever@eecs.umich.edu self.intlvMatch = 0 5603101Sstever@eecs.umich.edu 5613101Sstever@eecs.umich.edu def handle_kwargs(self, kwargs): 5623101Sstever@eecs.umich.edu # An address range needs to have an upper limit, specified 5633101Sstever@eecs.umich.edu # either explicitly with an end, or as an offset using the 5643101Sstever@eecs.umich.edu # size keyword. 5653101Sstever@eecs.umich.edu if 'end' in kwargs: 5663101Sstever@eecs.umich.edu self.end = Addr(kwargs.pop('end')) 5673101Sstever@eecs.umich.edu elif 'size' in kwargs: 5683101Sstever@eecs.umich.edu self.end = self.start + Addr(kwargs.pop('size')) - 1 5693101Sstever@eecs.umich.edu else: 5703101Sstever@eecs.umich.edu raise TypeError, "Either end or size must be specified" 5713101Sstever@eecs.umich.edu 5723101Sstever@eecs.umich.edu # Now on to the optional bit 5733101Sstever@eecs.umich.edu if 'intlvHighBit' in kwargs: 5743101Sstever@eecs.umich.edu self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 5753101Sstever@eecs.umich.edu if 'intlvBits' in kwargs: 5763101Sstever@eecs.umich.edu self.intlvBits = int(kwargs.pop('intlvBits')) 5773101Sstever@eecs.umich.edu if 'intlvMatch' in kwargs: 5783101Sstever@eecs.umich.edu self.intlvMatch = int(kwargs.pop('intlvMatch')) 5793101Sstever@eecs.umich.edu 5803101Sstever@eecs.umich.edu if len(args) == 0: 5813101Sstever@eecs.umich.edu self.start = Addr(kwargs.pop('start')) 5823101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 5833101Sstever@eecs.umich.edu 5843101Sstever@eecs.umich.edu elif len(args) == 1: 5853101Sstever@eecs.umich.edu if kwargs: 5863101Sstever@eecs.umich.edu self.start = Addr(args[0]) 5873101Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 5883101Sstever@eecs.umich.edu elif isinstance(args[0], (list, tuple)): 5893101Sstever@eecs.umich.edu self.start = Addr(args[0][0]) 5903101Sstever@eecs.umich.edu self.end = Addr(args[0][1]) 5913101Sstever@eecs.umich.edu else: 5923101Sstever@eecs.umich.edu self.start = Addr(0) 5933101Sstever@eecs.umich.edu self.end = Addr(args[0]) - 1 5943101Sstever@eecs.umich.edu 5953101Sstever@eecs.umich.edu elif len(args) == 2: 5963101Sstever@eecs.umich.edu self.start = Addr(args[0]) 5973101Sstever@eecs.umich.edu self.end = Addr(args[1]) 5983101Sstever@eecs.umich.edu else: 5993101Sstever@eecs.umich.edu raise TypeError, "Too many arguments specified" 6003101Sstever@eecs.umich.edu 6013101Sstever@eecs.umich.edu if kwargs: 6023101Sstever@eecs.umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 6033101Sstever@eecs.umich.edu 6043101Sstever@eecs.umich.edu def __str__(self): 6053101Sstever@eecs.umich.edu return '%s:%s' % (self.start, self.end) 6063101Sstever@eecs.umich.edu 6073101Sstever@eecs.umich.edu def size(self): 6083101Sstever@eecs.umich.edu # Divide the size by the size of the interleaving slice 6093101Sstever@eecs.umich.edu return (long(self.end) - long(self.start) + 1) >> self.intlvBits 6103101Sstever@eecs.umich.edu 6113101Sstever@eecs.umich.edu @classmethod 6123101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 6133101Sstever@eecs.umich.edu Addr.cxx_predecls(code) 6143101Sstever@eecs.umich.edu code('#include "base/addr_range.hh"') 6153101Sstever@eecs.umich.edu 6163101Sstever@eecs.umich.edu @classmethod 6173101Sstever@eecs.umich.edu def swig_predecls(cls, code): 6183101Sstever@eecs.umich.edu Addr.swig_predecls(code) 6193101Sstever@eecs.umich.edu 6203101Sstever@eecs.umich.edu def getValue(self): 6213101Sstever@eecs.umich.edu # Go from the Python class to the wrapped C++ class generated 6223101Sstever@eecs.umich.edu # by swig 6233101Sstever@eecs.umich.edu from m5.internal.range import AddrRange 6243101Sstever@eecs.umich.edu 6253101Sstever@eecs.umich.edu return AddrRange(long(self.start), long(self.end), 6263101Sstever@eecs.umich.edu int(self.intlvHighBit), int(self.intlvBits), 6273101Sstever@eecs.umich.edu int(self.intlvMatch)) 6283101Sstever@eecs.umich.edu 6293101Sstever@eecs.umich.edu# Boolean parameter type. Python doesn't let you subclass bool, since 6303101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and 6313101Sstever@eecs.umich.edu# False. Thus this is a little more complicated than String. 6323101Sstever@eecs.umich.educlass Bool(ParamValue): 6333101Sstever@eecs.umich.edu cxx_type = 'bool' 6343101Sstever@eecs.umich.edu def __init__(self, value): 6353101Sstever@eecs.umich.edu try: 6363101Sstever@eecs.umich.edu self.value = convert.toBool(value) 6373101Sstever@eecs.umich.edu except TypeError: 6383101Sstever@eecs.umich.edu self.value = bool(value) 6393101Sstever@eecs.umich.edu 6403101Sstever@eecs.umich.edu def getValue(self): 6413101Sstever@eecs.umich.edu return bool(self.value) 6423101Sstever@eecs.umich.edu 6433101Sstever@eecs.umich.edu def __str__(self): 6443101Sstever@eecs.umich.edu return str(self.value) 6453101Sstever@eecs.umich.edu 6463101Sstever@eecs.umich.edu # implement truth value testing for Bool parameters so that these params 6473101Sstever@eecs.umich.edu # evaluate correctly during the python configuration phase 6483101Sstever@eecs.umich.edu def __nonzero__(self): 6493101Sstever@eecs.umich.edu return bool(self.value) 6503101Sstever@eecs.umich.edu 6513101Sstever@eecs.umich.edu def ini_str(self): 6523101Sstever@eecs.umich.edu if self.value: 6533101Sstever@eecs.umich.edu return 'true' 6543101Sstever@eecs.umich.edu return 'false' 6553101Sstever@eecs.umich.edu 6563101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1): 6573101Sstever@eecs.umich.edu bytes = map(lambda x: int(x, 16), addr.split(':')) 6583101Sstever@eecs.umich.edu bytes[5] += val 6593101Sstever@eecs.umich.edu for i in (5, 4, 3, 2, 1): 6603101Sstever@eecs.umich.edu val,rem = divmod(bytes[i], 256) 6613101Sstever@eecs.umich.edu bytes[i] = rem 6623101Sstever@eecs.umich.edu if val == 0: 6633101Sstever@eecs.umich.edu break 6643101Sstever@eecs.umich.edu bytes[i - 1] += val 6653101Sstever@eecs.umich.edu assert(bytes[0] <= 255) 6663101Sstever@eecs.umich.edu return ':'.join(map(lambda x: '%02x' % x, bytes)) 6673101Sstever@eecs.umich.edu 6683101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01" 6693101Sstever@eecs.umich.edudef NextEthernetAddr(): 6703101Sstever@eecs.umich.edu global _NextEthernetAddr 6713101Sstever@eecs.umich.edu 6723101Sstever@eecs.umich.edu value = _NextEthernetAddr 6733101Sstever@eecs.umich.edu _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 6743101Sstever@eecs.umich.edu return value 6753101Sstever@eecs.umich.edu 6763101Sstever@eecs.umich.educlass EthernetAddr(ParamValue): 6773101Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 6783101Sstever@eecs.umich.edu 6793101Sstever@eecs.umich.edu @classmethod 6803101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 6813101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 6823101Sstever@eecs.umich.edu 6833101Sstever@eecs.umich.edu @classmethod 6843101Sstever@eecs.umich.edu def swig_predecls(cls, code): 6853101Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 6863101Sstever@eecs.umich.edu 6873101Sstever@eecs.umich.edu def __init__(self, value): 6883101Sstever@eecs.umich.edu if value == NextEthernetAddr: 6893101Sstever@eecs.umich.edu self.value = value 6903101Sstever@eecs.umich.edu return 6913101Sstever@eecs.umich.edu 6923101Sstever@eecs.umich.edu if not isinstance(value, str): 6933101Sstever@eecs.umich.edu raise TypeError, "expected an ethernet address and didn't get one" 6943101Sstever@eecs.umich.edu 6953101Sstever@eecs.umich.edu bytes = value.split(':') 6963101Sstever@eecs.umich.edu if len(bytes) != 6: 6973101Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 6983101Sstever@eecs.umich.edu 6993101Sstever@eecs.umich.edu for byte in bytes: 7003101Sstever@eecs.umich.edu if not 0 <= int(byte) <= 0xff: 7013101Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 7023101Sstever@eecs.umich.edu 7033101Sstever@eecs.umich.edu self.value = value 7043101Sstever@eecs.umich.edu 7053101Sstever@eecs.umich.edu def unproxy(self, base): 7063101Sstever@eecs.umich.edu if self.value == NextEthernetAddr: 7073101Sstever@eecs.umich.edu return EthernetAddr(self.value()) 7083101Sstever@eecs.umich.edu return self 7093101Sstever@eecs.umich.edu 7103101Sstever@eecs.umich.edu def getValue(self): 7113101Sstever@eecs.umich.edu from m5.internal.params import EthAddr 7123101Sstever@eecs.umich.edu return EthAddr(self.value) 7133101Sstever@eecs.umich.edu 7143101Sstever@eecs.umich.edu def ini_str(self): 7153101Sstever@eecs.umich.edu return self.value 7163101Sstever@eecs.umich.edu 7173101Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of 7183101Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP. 7193101Sstever@eecs.umich.educlass IpAddress(ParamValue): 7203101Sstever@eecs.umich.edu cxx_type = 'Net::IpAddress' 7213101Sstever@eecs.umich.edu 7223101Sstever@eecs.umich.edu @classmethod 7233101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 7243101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 7253101Sstever@eecs.umich.edu 7263101Sstever@eecs.umich.edu @classmethod 7273101Sstever@eecs.umich.edu def swig_predecls(cls, code): 7283101Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 7293101Sstever@eecs.umich.edu 7303101Sstever@eecs.umich.edu def __init__(self, value): 7313101Sstever@eecs.umich.edu if isinstance(value, IpAddress): 7323101Sstever@eecs.umich.edu self.ip = value.ip 7333101Sstever@eecs.umich.edu else: 7343101Sstever@eecs.umich.edu try: 7353101Sstever@eecs.umich.edu self.ip = convert.toIpAddress(value) 7363101Sstever@eecs.umich.edu except TypeError: 7373101Sstever@eecs.umich.edu self.ip = long(value) 7383101Sstever@eecs.umich.edu self.verifyIp() 7393101Sstever@eecs.umich.edu 7403101Sstever@eecs.umich.edu def __str__(self): 7413101Sstever@eecs.umich.edu tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 7423101Sstever@eecs.umich.edu return '%d.%d.%d.%d' % tuple(tup) 7433101Sstever@eecs.umich.edu 7443101Sstever@eecs.umich.edu def __eq__(self, other): 7453101Sstever@eecs.umich.edu if isinstance(other, IpAddress): 7463101Sstever@eecs.umich.edu return self.ip == other.ip 7473101Sstever@eecs.umich.edu elif isinstance(other, str): 7483101Sstever@eecs.umich.edu try: 7493101Sstever@eecs.umich.edu return self.ip == convert.toIpAddress(other) 7503101Sstever@eecs.umich.edu except: 7513101Sstever@eecs.umich.edu return False 7523101Sstever@eecs.umich.edu else: 7533101Sstever@eecs.umich.edu return self.ip == other 7543101Sstever@eecs.umich.edu 7553101Sstever@eecs.umich.edu def __ne__(self, other): 7563101Sstever@eecs.umich.edu return not (self == other) 7573101Sstever@eecs.umich.edu 7583101Sstever@eecs.umich.edu def verifyIp(self): 7593101Sstever@eecs.umich.edu if self.ip < 0 or self.ip >= (1 << 32): 7603101Sstever@eecs.umich.edu raise TypeError, "invalid ip address %#08x" % self.ip 7613101Sstever@eecs.umich.edu 7623101Sstever@eecs.umich.edu def getValue(self): 7633101Sstever@eecs.umich.edu from m5.internal.params import IpAddress 7643101Sstever@eecs.umich.edu return IpAddress(self.ip) 7653101Sstever@eecs.umich.edu 7663101Sstever@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 7673101Sstever@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 7683101Sstever@eecs.umich.edu# positional or keyword arguments. 7693101Sstever@eecs.umich.educlass IpNetmask(IpAddress): 7703101Sstever@eecs.umich.edu cxx_type = 'Net::IpNetmask' 7713101Sstever@eecs.umich.edu 7723101Sstever@eecs.umich.edu @classmethod 7733101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 7743101Sstever@eecs.umich.edu code('#include "base/inet.hh"') 7753101Sstever@eecs.umich.edu 7763101Sstever@eecs.umich.edu @classmethod 7773101Sstever@eecs.umich.edu def swig_predecls(cls, code): 7783101Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 7793101Sstever@eecs.umich.edu 7803101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 7813101Sstever@eecs.umich.edu def handle_kwarg(self, kwargs, key, elseVal = None): 7823101Sstever@eecs.umich.edu if key in kwargs: 7833101Sstever@eecs.umich.edu setattr(self, key, kwargs.pop(key)) 7843101Sstever@eecs.umich.edu elif elseVal: 7853101Sstever@eecs.umich.edu setattr(self, key, elseVal) 7863101Sstever@eecs.umich.edu else: 7873101Sstever@eecs.umich.edu raise TypeError, "No value set for %s" % key 7883101Sstever@eecs.umich.edu 7893101Sstever@eecs.umich.edu if len(args) == 0: 7903101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip') 7913101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'netmask') 7923101Sstever@eecs.umich.edu 7933101Sstever@eecs.umich.edu elif len(args) == 1: 7943101Sstever@eecs.umich.edu if kwargs: 7953101Sstever@eecs.umich.edu if not 'ip' in kwargs and not 'netmask' in kwargs: 7963101Sstever@eecs.umich.edu raise TypeError, "Invalid arguments" 7973101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 7983101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'netmask', args[0]) 7993101Sstever@eecs.umich.edu elif isinstance(args[0], IpNetmask): 8003101Sstever@eecs.umich.edu self.ip = args[0].ip 8013101Sstever@eecs.umich.edu self.netmask = args[0].netmask 8023101Sstever@eecs.umich.edu else: 8033101Sstever@eecs.umich.edu (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 8043101Sstever@eecs.umich.edu 8053101Sstever@eecs.umich.edu elif len(args) == 2: 8063101Sstever@eecs.umich.edu self.ip = args[0] 8073101Sstever@eecs.umich.edu self.netmask = args[1] 8083101Sstever@eecs.umich.edu else: 8093101Sstever@eecs.umich.edu raise TypeError, "Too many arguments specified" 8103101Sstever@eecs.umich.edu 8113101Sstever@eecs.umich.edu if kwargs: 8123101Sstever@eecs.umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 8133101Sstever@eecs.umich.edu 8143101Sstever@eecs.umich.edu self.verify() 8153101Sstever@eecs.umich.edu 8163101Sstever@eecs.umich.edu def __str__(self): 8173101Sstever@eecs.umich.edu return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 8183101Sstever@eecs.umich.edu 8193101Sstever@eecs.umich.edu def __eq__(self, other): 8203101Sstever@eecs.umich.edu if isinstance(other, IpNetmask): 8213101Sstever@eecs.umich.edu return self.ip == other.ip and self.netmask == other.netmask 8223101Sstever@eecs.umich.edu elif isinstance(other, str): 8233101Sstever@eecs.umich.edu try: 8243101Sstever@eecs.umich.edu return (self.ip, self.netmask) == convert.toIpNetmask(other) 8253101Sstever@eecs.umich.edu except: 8263101Sstever@eecs.umich.edu return False 8273101Sstever@eecs.umich.edu else: 8283101Sstever@eecs.umich.edu return False 8293101Sstever@eecs.umich.edu 8303101Sstever@eecs.umich.edu def verify(self): 8313101Sstever@eecs.umich.edu self.verifyIp() 832 if self.netmask < 0 or self.netmask > 32: 833 raise TypeError, "invalid netmask %d" % netmask 834 835 def getValue(self): 836 from m5.internal.params import IpNetmask 837 return IpNetmask(self.ip, self.netmask) 838 839# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 840# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 841class IpWithPort(IpAddress): 842 cxx_type = 'Net::IpWithPort' 843 844 @classmethod 845 def cxx_predecls(cls, code): 846 code('#include "base/inet.hh"') 847 848 @classmethod 849 def swig_predecls(cls, code): 850 code('%include "python/swig/inet.i"') 851 852 def __init__(self, *args, **kwargs): 853 def handle_kwarg(self, kwargs, key, elseVal = None): 854 if key in kwargs: 855 setattr(self, key, kwargs.pop(key)) 856 elif elseVal: 857 setattr(self, key, elseVal) 858 else: 859 raise TypeError, "No value set for %s" % key 860 861 if len(args) == 0: 862 handle_kwarg(self, kwargs, 'ip') 863 handle_kwarg(self, kwargs, 'port') 864 865 elif len(args) == 1: 866 if kwargs: 867 if not 'ip' in kwargs and not 'port' in kwargs: 868 raise TypeError, "Invalid arguments" 869 handle_kwarg(self, kwargs, 'ip', args[0]) 870 handle_kwarg(self, kwargs, 'port', args[0]) 871 elif isinstance(args[0], IpWithPort): 872 self.ip = args[0].ip 873 self.port = args[0].port 874 else: 875 (self.ip, self.port) = convert.toIpWithPort(args[0]) 876 877 elif len(args) == 2: 878 self.ip = args[0] 879 self.port = args[1] 880 else: 881 raise TypeError, "Too many arguments specified" 882 883 if kwargs: 884 raise TypeError, "Too many keywords: %s" % kwargs.keys() 885 886 self.verify() 887 888 def __str__(self): 889 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 890 891 def __eq__(self, other): 892 if isinstance(other, IpWithPort): 893 return self.ip == other.ip and self.port == other.port 894 elif isinstance(other, str): 895 try: 896 return (self.ip, self.port) == convert.toIpWithPort(other) 897 except: 898 return False 899 else: 900 return False 901 902 def verify(self): 903 self.verifyIp() 904 if self.port < 0 or self.port > 0xffff: 905 raise TypeError, "invalid port %d" % self.port 906 907 def getValue(self): 908 from m5.internal.params import IpWithPort 909 return IpWithPort(self.ip, self.port) 910 911time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 912 "%a %b %d %H:%M:%S %Z %Y", 913 "%Y/%m/%d %H:%M:%S", 914 "%Y/%m/%d %H:%M", 915 "%Y/%m/%d", 916 "%m/%d/%Y %H:%M:%S", 917 "%m/%d/%Y %H:%M", 918 "%m/%d/%Y", 919 "%m/%d/%y %H:%M:%S", 920 "%m/%d/%y %H:%M", 921 "%m/%d/%y"] 922 923 924def parse_time(value): 925 from time import gmtime, strptime, struct_time, time 926 from datetime import datetime, date 927 928 if isinstance(value, struct_time): 929 return value 930 931 if isinstance(value, (int, long)): 932 return gmtime(value) 933 934 if isinstance(value, (datetime, date)): 935 return value.timetuple() 936 937 if isinstance(value, str): 938 if value in ('Now', 'Today'): 939 return time.gmtime(time.time()) 940 941 for format in time_formats: 942 try: 943 return strptime(value, format) 944 except ValueError: 945 pass 946 947 raise ValueError, "Could not parse '%s' as a time" % value 948 949class Time(ParamValue): 950 cxx_type = 'tm' 951 952 @classmethod 953 def cxx_predecls(cls, code): 954 code('#include <time.h>') 955 956 @classmethod 957 def swig_predecls(cls, code): 958 code('%include "python/swig/time.i"') 959 960 def __init__(self, value): 961 self.value = parse_time(value) 962 963 def getValue(self): 964 from m5.internal.params import tm 965 966 c_time = tm() 967 py_time = self.value 968 969 # UNIX is years since 1900 970 c_time.tm_year = py_time.tm_year - 1900; 971 972 # Python starts at 1, UNIX starts at 0 973 c_time.tm_mon = py_time.tm_mon - 1; 974 c_time.tm_mday = py_time.tm_mday; 975 c_time.tm_hour = py_time.tm_hour; 976 c_time.tm_min = py_time.tm_min; 977 c_time.tm_sec = py_time.tm_sec; 978 979 # Python has 0 as Monday, UNIX is 0 as sunday 980 c_time.tm_wday = py_time.tm_wday + 1 981 if c_time.tm_wday > 6: 982 c_time.tm_wday -= 7; 983 984 # Python starts at 1, Unix starts at 0 985 c_time.tm_yday = py_time.tm_yday - 1; 986 987 return c_time 988 989 def __str__(self): 990 return time.asctime(self.value) 991 992 def ini_str(self): 993 return str(self) 994 995 def get_config_as_dict(self): 996 return str(self) 997 998# Enumerated types are a little more complex. The user specifies the 999# type as Enum(foo) where foo is either a list or dictionary of 1000# alternatives (typically strings, but not necessarily so). (In the 1001# long run, the integer value of the parameter will be the list index 1002# or the corresponding dictionary value. For now, since we only check 1003# that the alternative is valid and then spit it into a .ini file, 1004# there's not much point in using the dictionary.) 1005 1006# What Enum() must do is generate a new type encapsulating the 1007# provided list/dictionary so that specific values of the parameter 1008# can be instances of that type. We define two hidden internal 1009# classes (_ListEnum and _DictEnum) to serve as base classes, then 1010# derive the new type from the appropriate base class on the fly. 1011 1012allEnums = {} 1013# Metaclass for Enum types 1014class MetaEnum(MetaParamValue): 1015 def __new__(mcls, name, bases, dict): 1016 assert name not in allEnums 1017 1018 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1019 allEnums[name] = cls 1020 return cls 1021 1022 def __init__(cls, name, bases, init_dict): 1023 if init_dict.has_key('map'): 1024 if not isinstance(cls.map, dict): 1025 raise TypeError, "Enum-derived class attribute 'map' " \ 1026 "must be of type dict" 1027 # build list of value strings from map 1028 cls.vals = cls.map.keys() 1029 cls.vals.sort() 1030 elif init_dict.has_key('vals'): 1031 if not isinstance(cls.vals, list): 1032 raise TypeError, "Enum-derived class attribute 'vals' " \ 1033 "must be of type list" 1034 # build string->value map from vals sequence 1035 cls.map = {} 1036 for idx,val in enumerate(cls.vals): 1037 cls.map[val] = idx 1038 else: 1039 raise TypeError, "Enum-derived class must define "\ 1040 "attribute 'map' or 'vals'" 1041 1042 cls.cxx_type = 'Enums::%s' % name 1043 1044 super(MetaEnum, cls).__init__(name, bases, init_dict) 1045 1046 # Generate C++ class declaration for this enum type. 1047 # Note that we wrap the enum in a class/struct to act as a namespace, 1048 # so that the enum strings can be brief w/o worrying about collisions. 1049 def cxx_decl(cls, code): 1050 name = cls.__name__ 1051 code('''\ 1052#ifndef __ENUM__${name}__ 1053#define __ENUM__${name}__ 1054 1055namespace Enums { 1056 enum $name { 1057''') 1058 code.indent(2) 1059 for val in cls.vals: 1060 code('$val = ${{cls.map[val]}},') 1061 code('Num_$name = ${{len(cls.vals)}}') 1062 code.dedent(2) 1063 code('''\ 1064 }; 1065extern const char *${name}Strings[Num_${name}]; 1066} 1067 1068#endif // __ENUM__${name}__ 1069''') 1070 1071 def cxx_def(cls, code): 1072 name = cls.__name__ 1073 code('''\ 1074#include "enums/$name.hh" 1075namespace Enums { 1076 const char *${name}Strings[Num_${name}] = 1077 { 1078''') 1079 code.indent(2) 1080 for val in cls.vals: 1081 code('"$val",') 1082 code.dedent(2) 1083 code(''' 1084 }; 1085} // namespace Enums 1086''') 1087 1088 def swig_decl(cls, code): 1089 name = cls.__name__ 1090 code('''\ 1091%module(package="m5.internal") enum_$name 1092 1093%{ 1094#include "enums/$name.hh" 1095%} 1096 1097%include "enums/$name.hh" 1098''') 1099 1100 1101# Base class for enum types. 1102class Enum(ParamValue): 1103 __metaclass__ = MetaEnum 1104 vals = [] 1105 1106 def __init__(self, value): 1107 if value not in self.map: 1108 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1109 % (value, self.vals) 1110 self.value = value 1111 1112 @classmethod 1113 def cxx_predecls(cls, code): 1114 code('#include "enums/$0.hh"', cls.__name__) 1115 1116 @classmethod 1117 def swig_predecls(cls, code): 1118 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1119 1120 def getValue(self): 1121 return int(self.map[self.value]) 1122 1123 def __str__(self): 1124 return self.value 1125 1126# how big does a rounding error need to be before we warn about it? 1127frequency_tolerance = 0.001 # 0.1% 1128 1129class TickParamValue(NumericParamValue): 1130 cxx_type = 'Tick' 1131 1132 @classmethod 1133 def cxx_predecls(cls, code): 1134 code('#include "base/types.hh"') 1135 1136 @classmethod 1137 def swig_predecls(cls, code): 1138 code('%import "stdint.i"') 1139 code('%import "base/types.hh"') 1140 1141 def getValue(self): 1142 return long(self.value) 1143 1144class Latency(TickParamValue): 1145 def __init__(self, value): 1146 if isinstance(value, (Latency, Clock)): 1147 self.ticks = value.ticks 1148 self.value = value.value 1149 elif isinstance(value, Frequency): 1150 self.ticks = value.ticks 1151 self.value = 1.0 / value.value 1152 elif value.endswith('t'): 1153 self.ticks = True 1154 self.value = int(value[:-1]) 1155 else: 1156 self.ticks = False 1157 self.value = convert.toLatency(value) 1158 1159 def __getattr__(self, attr): 1160 if attr in ('latency', 'period'): 1161 return self 1162 if attr == 'frequency': 1163 return Frequency(self) 1164 raise AttributeError, "Latency object has no attribute '%s'" % attr 1165 1166 def getValue(self): 1167 if self.ticks or self.value == 0: 1168 value = self.value 1169 else: 1170 value = ticks.fromSeconds(self.value) 1171 return long(value) 1172 1173 # convert latency to ticks 1174 def ini_str(self): 1175 return '%d' % self.getValue() 1176 1177class Frequency(TickParamValue): 1178 def __init__(self, value): 1179 if isinstance(value, (Latency, Clock)): 1180 if value.value == 0: 1181 self.value = 0 1182 else: 1183 self.value = 1.0 / value.value 1184 self.ticks = value.ticks 1185 elif isinstance(value, Frequency): 1186 self.value = value.value 1187 self.ticks = value.ticks 1188 else: 1189 self.ticks = False 1190 self.value = convert.toFrequency(value) 1191 1192 def __getattr__(self, attr): 1193 if attr == 'frequency': 1194 return self 1195 if attr in ('latency', 'period'): 1196 return Latency(self) 1197 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1198 1199 # convert latency to ticks 1200 def getValue(self): 1201 if self.ticks or self.value == 0: 1202 value = self.value 1203 else: 1204 value = ticks.fromSeconds(1.0 / self.value) 1205 return long(value) 1206 1207 def ini_str(self): 1208 return '%d' % self.getValue() 1209 1210# A generic frequency and/or Latency value. Value is stored as a 1211# latency, and any manipulation using a multiplier thus scales the 1212# clock period, i.e. a 2x multiplier doubles the clock period and thus 1213# halves the clock frequency. 1214class Clock(ParamValue): 1215 cxx_type = 'Tick' 1216 1217 @classmethod 1218 def cxx_predecls(cls, code): 1219 code('#include "base/types.hh"') 1220 1221 @classmethod 1222 def swig_predecls(cls, code): 1223 code('%import "stdint.i"') 1224 code('%import "base/types.hh"') 1225 1226 def __init__(self, value): 1227 if isinstance(value, (Latency, Clock)): 1228 self.ticks = value.ticks 1229 self.value = value.value 1230 elif isinstance(value, Frequency): 1231 self.ticks = value.ticks 1232 self.value = 1.0 / value.value 1233 elif value.endswith('t'): 1234 self.ticks = True 1235 self.value = int(value[:-1]) 1236 else: 1237 self.ticks = False 1238 self.value = convert.anyToLatency(value) 1239 1240 def __getattr__(self, attr): 1241 if attr == 'frequency': 1242 return Frequency(self) 1243 if attr in ('latency', 'period'): 1244 return Latency(self) 1245 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1246 1247 def __mul__(self, other): 1248 # Always treat the clock as a period when scaling 1249 newobj = self.__class__(self) 1250 newobj.value *= other 1251 return newobj 1252 1253 __rmul__ = __mul__ 1254 1255 def getValue(self): 1256 return self.period.getValue() 1257 1258 def ini_str(self): 1259 return self.period.ini_str() 1260 1261class NetworkBandwidth(float,ParamValue): 1262 cxx_type = 'float' 1263 def __new__(cls, value): 1264 # convert to bits per second 1265 val = convert.toNetworkBandwidth(value) 1266 return super(cls, NetworkBandwidth).__new__(cls, val) 1267 1268 def __str__(self): 1269 return str(self.val) 1270 1271 def getValue(self): 1272 # convert to seconds per byte 1273 value = 8.0 / float(self) 1274 # convert to ticks per byte 1275 value = ticks.fromSeconds(value) 1276 return float(value) 1277 1278 def ini_str(self): 1279 return '%f' % self.getValue() 1280 1281class MemoryBandwidth(float,ParamValue): 1282 cxx_type = 'float' 1283 def __new__(cls, value): 1284 # convert to bytes per second 1285 val = convert.toMemoryBandwidth(value) 1286 return super(cls, MemoryBandwidth).__new__(cls, val) 1287 1288 def __str__(self): 1289 return str(self.val) 1290 1291 def getValue(self): 1292 # convert to seconds per byte 1293 value = float(self) 1294 if value: 1295 value = 1.0 / float(self) 1296 # convert to ticks per byte 1297 value = ticks.fromSeconds(value) 1298 return float(value) 1299 1300 def ini_str(self): 1301 return '%f' % self.getValue() 1302 1303# 1304# "Constants"... handy aliases for various values. 1305# 1306 1307# Special class for NULL pointers. Note the special check in 1308# make_param_value() above that lets these be assigned where a 1309# SimObject is required. 1310# only one copy of a particular node 1311class NullSimObject(object): 1312 __metaclass__ = Singleton 1313 1314 def __call__(cls): 1315 return cls 1316 1317 def _instantiate(self, parent = None, path = ''): 1318 pass 1319 1320 def ini_str(self): 1321 return 'Null' 1322 1323 def unproxy(self, base): 1324 return self 1325 1326 def set_path(self, parent, name): 1327 pass 1328 1329 def __str__(self): 1330 return 'Null' 1331 1332 def getValue(self): 1333 return None 1334 1335# The only instance you'll ever need... 1336NULL = NullSimObject() 1337 1338def isNullPointer(value): 1339 return isinstance(value, NullSimObject) 1340 1341# Some memory range specifications use this as a default upper bound. 1342MaxAddr = Addr.max 1343MaxTick = Tick.max 1344AllMemory = AddrRange(0, MaxAddr) 1345 1346 1347##################################################################### 1348# 1349# Port objects 1350# 1351# Ports are used to interconnect objects in the memory system. 1352# 1353##################################################################### 1354 1355# Port reference: encapsulates a reference to a particular port on a 1356# particular SimObject. 1357class PortRef(object): 1358 def __init__(self, simobj, name, role): 1359 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1360 self.simobj = simobj 1361 self.name = name 1362 self.role = role 1363 self.peer = None # not associated with another port yet 1364 self.ccConnected = False # C++ port connection done? 1365 self.index = -1 # always -1 for non-vector ports 1366 1367 def __str__(self): 1368 return '%s.%s' % (self.simobj, self.name) 1369 1370 def __len__(self): 1371 # Return the number of connected ports, i.e. 0 is we have no 1372 # peer and 1 if we do. 1373 return int(self.peer != None) 1374 1375 # for config.ini, print peer's name (not ours) 1376 def ini_str(self): 1377 return str(self.peer) 1378 1379 # for config.json 1380 def get_config_as_dict(self): 1381 return {'role' : self.role, 'peer' : str(self.peer)} 1382 1383 def __getattr__(self, attr): 1384 if attr == 'peerObj': 1385 # shorthand for proxies 1386 return self.peer.simobj 1387 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1388 (self.__class__.__name__, attr) 1389 1390 # Full connection is symmetric (both ways). Called via 1391 # SimObject.__setattr__ as a result of a port assignment, e.g., 1392 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1393 # e.g., "obj1.portA[3] = obj2.portB". 1394 def connect(self, other): 1395 if isinstance(other, VectorPortRef): 1396 # reference to plain VectorPort is implicit append 1397 other = other._get_next() 1398 if self.peer and not proxy.isproxy(self.peer): 1399 fatal("Port %s is already connected to %s, cannot connect %s\n", 1400 self, self.peer, other); 1401 self.peer = other 1402 if proxy.isproxy(other): 1403 other.set_param_desc(PortParamDesc()) 1404 elif isinstance(other, PortRef): 1405 if other.peer is not self: 1406 other.connect(self) 1407 else: 1408 raise TypeError, \ 1409 "assigning non-port reference '%s' to port '%s'" \ 1410 % (other, self) 1411 1412 def clone(self, simobj, memo): 1413 if memo.has_key(self): 1414 return memo[self] 1415 newRef = copy.copy(self) 1416 memo[self] = newRef 1417 newRef.simobj = simobj 1418 assert(isSimObject(newRef.simobj)) 1419 if self.peer and not proxy.isproxy(self.peer): 1420 peerObj = self.peer.simobj(_memo=memo) 1421 newRef.peer = self.peer.clone(peerObj, memo) 1422 assert(not isinstance(newRef.peer, VectorPortRef)) 1423 return newRef 1424 1425 def unproxy(self, simobj): 1426 assert(simobj is self.simobj) 1427 if proxy.isproxy(self.peer): 1428 try: 1429 realPeer = self.peer.unproxy(self.simobj) 1430 except: 1431 print "Error in unproxying port '%s' of %s" % \ 1432 (self.name, self.simobj.path()) 1433 raise 1434 self.connect(realPeer) 1435 1436 # Call C++ to create corresponding port connection between C++ objects 1437 def ccConnect(self): 1438 from m5.internal.pyobject import connectPorts 1439 1440 if self.role == 'SLAVE': 1441 # do nothing and let the master take care of it 1442 return 1443 1444 if self.ccConnected: # already done this 1445 return 1446 peer = self.peer 1447 if not self.peer: # nothing to connect to 1448 return 1449 1450 # check that we connect a master to a slave 1451 if self.role == peer.role: 1452 raise TypeError, \ 1453 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1454 % (peer, self, self.role) 1455 1456 try: 1457 # self is always the master and peer the slave 1458 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1459 peer.simobj.getCCObject(), peer.name, peer.index) 1460 except: 1461 print "Error connecting port %s.%s to %s.%s" % \ 1462 (self.simobj.path(), self.name, 1463 peer.simobj.path(), peer.name) 1464 raise 1465 self.ccConnected = True 1466 peer.ccConnected = True 1467 1468# A reference to an individual element of a VectorPort... much like a 1469# PortRef, but has an index. 1470class VectorPortElementRef(PortRef): 1471 def __init__(self, simobj, name, role, index): 1472 PortRef.__init__(self, simobj, name, role) 1473 self.index = index 1474 1475 def __str__(self): 1476 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1477 1478# A reference to a complete vector-valued port (not just a single element). 1479# Can be indexed to retrieve individual VectorPortElementRef instances. 1480class VectorPortRef(object): 1481 def __init__(self, simobj, name, role): 1482 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1483 self.simobj = simobj 1484 self.name = name 1485 self.role = role 1486 self.elements = [] 1487 1488 def __str__(self): 1489 return '%s.%s[:]' % (self.simobj, self.name) 1490 1491 def __len__(self): 1492 # Return the number of connected peers, corresponding the the 1493 # length of the elements. 1494 return len(self.elements) 1495 1496 # for config.ini, print peer's name (not ours) 1497 def ini_str(self): 1498 return ' '.join([el.ini_str() for el in self.elements]) 1499 1500 # for config.json 1501 def get_config_as_dict(self): 1502 return {'role' : self.role, 1503 'peer' : [el.ini_str() for el in self.elements]} 1504 1505 def __getitem__(self, key): 1506 if not isinstance(key, int): 1507 raise TypeError, "VectorPort index must be integer" 1508 if key >= len(self.elements): 1509 # need to extend list 1510 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1511 for i in range(len(self.elements), key+1)] 1512 self.elements.extend(ext) 1513 return self.elements[key] 1514 1515 def _get_next(self): 1516 return self[len(self.elements)] 1517 1518 def __setitem__(self, key, value): 1519 if not isinstance(key, int): 1520 raise TypeError, "VectorPort index must be integer" 1521 self[key].connect(value) 1522 1523 def connect(self, other): 1524 if isinstance(other, (list, tuple)): 1525 # Assign list of port refs to vector port. 1526 # For now, append them... not sure if that's the right semantics 1527 # or if it should replace the current vector. 1528 for ref in other: 1529 self._get_next().connect(ref) 1530 else: 1531 # scalar assignment to plain VectorPort is implicit append 1532 self._get_next().connect(other) 1533 1534 def clone(self, simobj, memo): 1535 if memo.has_key(self): 1536 return memo[self] 1537 newRef = copy.copy(self) 1538 memo[self] = newRef 1539 newRef.simobj = simobj 1540 assert(isSimObject(newRef.simobj)) 1541 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1542 return newRef 1543 1544 def unproxy(self, simobj): 1545 [el.unproxy(simobj) for el in self.elements] 1546 1547 def ccConnect(self): 1548 [el.ccConnect() for el in self.elements] 1549 1550# Port description object. Like a ParamDesc object, this represents a 1551# logical port in the SimObject class, not a particular port on a 1552# SimObject instance. The latter are represented by PortRef objects. 1553class Port(object): 1554 # Generate a PortRef for this port on the given SimObject with the 1555 # given name 1556 def makeRef(self, simobj): 1557 return PortRef(simobj, self.name, self.role) 1558 1559 # Connect an instance of this port (on the given SimObject with 1560 # the given name) with the port described by the supplied PortRef 1561 def connect(self, simobj, ref): 1562 self.makeRef(simobj).connect(ref) 1563 1564 # No need for any pre-declarations at the moment as we merely rely 1565 # on an unsigned int. 1566 def cxx_predecls(self, code): 1567 pass 1568 1569 # Declare an unsigned int with the same name as the port, that 1570 # will eventually hold the number of connected ports (and thus the 1571 # number of elements for a VectorPort). 1572 def cxx_decl(self, code): 1573 code('unsigned int port_${{self.name}}_connection_count;') 1574 1575class MasterPort(Port): 1576 # MasterPort("description") 1577 def __init__(self, *args): 1578 if len(args) == 1: 1579 self.desc = args[0] 1580 self.role = 'MASTER' 1581 else: 1582 raise TypeError, 'wrong number of arguments' 1583 1584class SlavePort(Port): 1585 # SlavePort("description") 1586 def __init__(self, *args): 1587 if len(args) == 1: 1588 self.desc = args[0] 1589 self.role = 'SLAVE' 1590 else: 1591 raise TypeError, 'wrong number of arguments' 1592 1593# VectorPort description object. Like Port, but represents a vector 1594# of connections (e.g., as on a Bus). 1595class VectorPort(Port): 1596 def __init__(self, *args): 1597 self.isVec = True 1598 1599 def makeRef(self, simobj): 1600 return VectorPortRef(simobj, self.name, self.role) 1601 1602class VectorMasterPort(VectorPort): 1603 # VectorMasterPort("description") 1604 def __init__(self, *args): 1605 if len(args) == 1: 1606 self.desc = args[0] 1607 self.role = 'MASTER' 1608 VectorPort.__init__(self, *args) 1609 else: 1610 raise TypeError, 'wrong number of arguments' 1611 1612class VectorSlavePort(VectorPort): 1613 # VectorSlavePort("description") 1614 def __init__(self, *args): 1615 if len(args) == 1: 1616 self.desc = args[0] 1617 self.role = 'SLAVE' 1618 VectorPort.__init__(self, *args) 1619 else: 1620 raise TypeError, 'wrong number of arguments' 1621 1622# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1623# proxy objects (via set_param_desc()) so that proxy error messages 1624# make sense. 1625class PortParamDesc(object): 1626 __metaclass__ = Singleton 1627 1628 ptype_str = 'Port' 1629 ptype = Port 1630 1631baseEnums = allEnums.copy() 1632baseParams = allParams.copy() 1633 1634def clear(): 1635 global allEnums, allParams 1636 1637 allEnums = baseEnums.copy() 1638 allParams = baseParams.copy() 1639 1640__all__ = ['Param', 'VectorParam', 1641 'Enum', 'Bool', 'String', 'Float', 1642 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1643 'Int32', 'UInt32', 'Int64', 'UInt64', 1644 'Counter', 'Addr', 'Tick', 'Percent', 1645 'TcpPort', 'UdpPort', 'EthernetAddr', 1646 'IpAddress', 'IpNetmask', 'IpWithPort', 1647 'MemorySize', 'MemorySize32', 1648 'Latency', 'Frequency', 'Clock', 1649 'NetworkBandwidth', 'MemoryBandwidth', 1650 'AddrRange', 1651 'MaxAddr', 'MaxTick', 'AllMemory', 1652 'Time', 1653 'NextEthernetAddr', 'NULL', 1654 'MasterPort', 'SlavePort', 1655 'VectorMasterPort', 'VectorSlavePort'] 1656 1657import SimObject 1658