params.py revision 9941
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# 473885Sbinkertn@umich.edu# Parameter description classes 483885Sbinkertn@umich.edu# 494762Snate@binkert.org# The _params dictionary in each class maps parameter names to either 503885Sbinkertn@umich.edu# a Param or a VectorParam object. These objects contain the 513885Sbinkertn@umich.edu# parameter description string, the parameter type, and the default 523885Sbinkertn@umich.edu# value (if any). The convert() method on these objects is used to 533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 544380Sbinkertn@umich.edu# type. 554167Sbinkertn@umich.edu# 563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute 573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in 584762Snate@binkert.org# MetaSimObject._new_param()); after that point they aren't used. 594762Snate@binkert.org# 604762Snate@binkert.org##################################################################### 614762Snate@binkert.org 624762Snate@binkert.orgimport copy 634762Snate@binkert.orgimport datetime 644762Snate@binkert.orgimport re 654762Snate@binkert.orgimport sys 664762Snate@binkert.orgimport time 674762Snate@binkert.orgimport math 684762Snate@binkert.org 695033Smilesck@eecs.umich.eduimport proxy 705033Smilesck@eecs.umich.eduimport ticks 715033Smilesck@eecs.umich.edufrom util import * 725033Smilesck@eecs.umich.edu 735033Smilesck@eecs.umich.edudef isSimObject(*args, **kwargs): 745033Smilesck@eecs.umich.edu return SimObject.isSimObject(*args, **kwargs) 755033Smilesck@eecs.umich.edu 765033Smilesck@eecs.umich.edudef isSimObjectSequence(*args, **kwargs): 775033Smilesck@eecs.umich.edu return SimObject.isSimObjectSequence(*args, **kwargs) 785033Smilesck@eecs.umich.edu 793101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs): 803101Sstever@eecs.umich.edu return SimObject.isSimObjectClass(*args, **kwargs) 813101Sstever@eecs.umich.edu 825033Smilesck@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: 1325033Smilesck@eecs.umich.edu self.desc = args[0] 1335033Smilesck@eecs.umich.edu elif len(args) == 2: 1345033Smilesck@eecs.umich.edu self.default = args[0] 1355033Smilesck@eecs.umich.edu self.desc = args[1] 1365033Smilesck@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: 1503102Sstever@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) 1685033Smilesck@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 1724762Snate@binkert.org return value 1734762Snate@binkert.org if isinstance(value, self.ptype): 1744762Snate@binkert.org 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 1795037Smilesck@eecs.umich.edu def cxx_predecls(self, code): 1803101Sstever@eecs.umich.edu code('#include <cstddef>') 1815037Smilesck@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 1914762Snate@binkert.org# single value. 1924762Snate@binkert.org 1934762Snate@binkert.orgclass VectorParamValue(list): 1944762Snate@binkert.org __metaclass__ = MetaParamValue 1954762Snate@binkert.org def __setattr__(self, attr, value): 1964762Snate@binkert.org raise AttributeError, \ 1974762Snate@binkert.org "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 1984762Snate@binkert.org 1994762Snate@binkert.org def ini_str(self): 2004762Snate@binkert.org return ' '.join([v.ini_str() for v in self]) 2014762Snate@binkert.org 2024762Snate@binkert.org def getValue(self): 2034762Snate@binkert.org return [ v.getValue() for v in self ] 2044762Snate@binkert.org 2054762Snate@binkert.org def unproxy(self, base): 2064762Snate@binkert.org 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 2285033Smilesck@eecs.umich.edu def has_parent(self): 2295033Smilesck@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: 2584762Snate@binkert.org # singleton: coerce to a single-element list 2594762Snate@binkert.org tmp_list = [ ParamDesc.convert(self, value) ] 2604762Snate@binkert.org 2614762Snate@binkert.org 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): 2733714Sstever@eecs.umich.edu code('%module(package="m5.internal") ${{self.swig_module_name()}}') 2743714Sstever@eecs.umich.edu code('%{') 2753714Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2763714Sstever@eecs.umich.edu code('%}') 2773714Sstever@eecs.umich.edu code() 2783714Sstever@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; 3045033Smilesck@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): 3204762Snate@binkert.org 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 3493102Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the 3503714Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via 3513101Sstever@eecs.umich.edu# the __str__() conversion method). 3523714Sstever@eecs.umich.edu# 3533714Sstever@eecs.umich.edu##################################################################### 3543714Sstever@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. 3574762Snate@binkert.orgclass String(ParamValue,str): 3584762Snate@binkert.org cxx_type = 'std::string' 3594762Snate@binkert.org 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) 3804446Sbinkertn@umich.edu 3813101Sstever@eecs.umich.edu def __long__(self): 3824762Snate@binkert.org return long(self.value) 3834762Snate@binkert.org 3844762Snate@binkert.org 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) 3933102Sstever@eecs.umich.edu newobj.value *= other 3943101Sstever@eecs.umich.edu newobj._check() 3953101Sstever@eecs.umich.edu return newobj 3963101Sstever@eecs.umich.edu 3974168Sbinkertn@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 4043102Sstever@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() 4094762Snate@binkert.org 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 4173102Sstever@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 4213584Ssaidi@eecs.umich.edu 4223584Ssaidi@eecs.umich.edu if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 4233584Ssaidi@eecs.umich.edu if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 4243584Ssaidi@eecs.umich.edu panic("CheckedInt subclass %s must define either\n" \ 4253584Ssaidi@eecs.umich.edu " 'min' and 'max' or 'size' and 'unsigned'\n", 4263101Sstever@eecs.umich.edu name); 4273101Sstever@eecs.umich.edu if cls.unsigned: 4285033Smilesck@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 4784762Snate@binkert.orgclass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 4794762Snate@binkert.orgclass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 4804762Snate@binkert.orgclass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 4814762Snate@binkert.org 4824762Snate@binkert.orgclass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 4834762Snate@binkert.orgclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 4844762Snate@binkert.orgclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4854762Snate@binkert.orgclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4864762Snate@binkert.org 4873101Sstever@eecs.umich.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 4883101Sstever@eecs.umich.edu 4893101Sstever@eecs.umich.educlass Cycles(CheckedInt): 4904762Snate@binkert.org cxx_type = 'Cycles' 4914762Snate@binkert.org size = 64 4924762Snate@binkert.org unsigned = True 4934762Snate@binkert.org 4944762Snate@binkert.org def getValue(self): 4954762Snate@binkert.org from m5.internal.core import Cycles 4964762Snate@binkert.org return Cycles(self.value) 4974762Snate@binkert.org 4984762Snate@binkert.orgclass 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__ 5073102Sstever@eecs.umich.edu 5083101Sstever@eecs.umich.edu def getValue(self): 5093101Sstever@eecs.umich.edu return float(self.value) 5103101Sstever@eecs.umich.edu 5114762Snate@binkert.orgclass MemorySize(CheckedInt): 5124762Snate@binkert.org cxx_type = 'uint64_t' 5134762Snate@binkert.org 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): 5344380Sbinkertn@umich.edu cxx_type = 'Addr' 5354380Sbinkertn@umich.edu size = 64 5364380Sbinkertn@umich.edu unsigned = True 5373101Sstever@eecs.umich.edu def __init__(self, value): 5384380Sbinkertn@umich.edu if isinstance(value, Addr): 5394380Sbinkertn@umich.edu self.value = value.value 5404380Sbinkertn@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) 5454762Snate@binkert.org 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: 5664380Sbinkertn@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 5694762Snate@binkert.org else: 5704762Snate@binkert.org raise TypeError, "Either end or size must be specified" 5714762Snate@binkert.org 5724762Snate@binkert.org # Now on to the optional bit 5734380Sbinkertn@umich.edu if 'intlvHighBit' in kwargs: 5744380Sbinkertn@umich.edu self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 5753101Sstever@eecs.umich.edu if 'intlvBits' in kwargs: 5763932Sbinkertn@umich.edu self.intlvBits = int(kwargs.pop('intlvBits')) 5773932Sbinkertn@umich.edu if 'intlvMatch' in kwargs: 5783932Sbinkertn@umich.edu self.intlvMatch = int(kwargs.pop('intlvMatch')) 5793932Sbinkertn@umich.edu 5803932Sbinkertn@umich.edu if len(args) == 0: 5813932Sbinkertn@umich.edu self.start = Addr(kwargs.pop('start')) 5823932Sbinkertn@umich.edu handle_kwargs(self, kwargs) 5833932Sbinkertn@umich.edu 5843932Sbinkertn@umich.edu elif len(args) == 1: 5853932Sbinkertn@umich.edu if kwargs: 5863932Sbinkertn@umich.edu self.start = Addr(args[0]) 5873932Sbinkertn@umich.edu handle_kwargs(self, kwargs) 5883932Sbinkertn@umich.edu elif isinstance(args[0], (list, tuple)): 5893885Sbinkertn@umich.edu self.start = Addr(args[0][0]) 5903932Sbinkertn@umich.edu self.end = Addr(args[0][1]) 5913932Sbinkertn@umich.edu else: 5923885Sbinkertn@umich.edu self.start = Addr(0) 5933932Sbinkertn@umich.edu self.end = Addr(args[0]) - 1 5943932Sbinkertn@umich.edu 5953932Sbinkertn@umich.edu elif len(args) == 2: 5963932Sbinkertn@umich.edu self.start = Addr(args[0]) 5973932Sbinkertn@umich.edu self.end = Addr(args[1]) 5983932Sbinkertn@umich.edu else: 5993932Sbinkertn@umich.edu raise TypeError, "Too many arguments specified" 6003932Sbinkertn@umich.edu 6013932Sbinkertn@umich.edu if kwargs: 6023932Sbinkertn@umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 6033932Sbinkertn@umich.edu 6043932Sbinkertn@umich.edu def __str__(self): 6053932Sbinkertn@umich.edu return '%s:%s' % (self.start, self.end) 6063932Sbinkertn@umich.edu 6073932Sbinkertn@umich.edu def size(self): 6083932Sbinkertn@umich.edu # Divide the size by the size of the interleaving slice 6093932Sbinkertn@umich.edu return (long(self.end) - long(self.start) + 1) >> self.intlvBits 6103932Sbinkertn@umich.edu 6113885Sbinkertn@umich.edu @classmethod 6123885Sbinkertn@umich.edu def cxx_predecls(cls, code): 6133885Sbinkertn@umich.edu Addr.cxx_predecls(code) 6143885Sbinkertn@umich.edu code('#include "base/addr_range.hh"') 6154762Snate@binkert.org 6164762Snate@binkert.org @classmethod 6174762Snate@binkert.org def swig_predecls(cls, code): 6183885Sbinkertn@umich.edu Addr.swig_predecls(code) 6193932Sbinkertn@umich.edu 6203885Sbinkertn@umich.edu def getValue(self): 6214762Snate@binkert.org # Go from the Python class to the wrapped C++ class generated 6224762Snate@binkert.org # by swig 6234762Snate@binkert.org from m5.internal.range import AddrRange 6244762Snate@binkert.org 6254762Snate@binkert.org return AddrRange(long(self.start), long(self.end), 6264762Snate@binkert.org int(self.intlvHighBit), int(self.intlvBits), 6274762Snate@binkert.org int(self.intlvMatch)) 6284762Snate@binkert.org 6294762Snate@binkert.org# Boolean parameter type. Python doesn't let you subclass bool, since 6304762Snate@binkert.org# it doesn't want to let you create multiple instances of True and 6314762Snate@binkert.org# False. Thus this is a little more complicated than String. 6324762Snate@binkert.orgclass Bool(ParamValue): 6334762Snate@binkert.org cxx_type = 'bool' 6344762Snate@binkert.org def __init__(self, value): 6354762Snate@binkert.org try: 6364762Snate@binkert.org self.value = convert.toBool(value) 6374762Snate@binkert.org except TypeError: 6384762Snate@binkert.org self.value = bool(value) 6394762Snate@binkert.org 6404762Snate@binkert.org def getValue(self): 6414762Snate@binkert.org return bool(self.value) 6424762Snate@binkert.org 6434762Snate@binkert.org def __str__(self): 6444762Snate@binkert.org return str(self.value) 6454762Snate@binkert.org 6464762Snate@binkert.org # implement truth value testing for Bool parameters so that these params 6473885Sbinkertn@umich.edu # evaluate correctly during the python configuration phase 6484762Snate@binkert.org def __nonzero__(self): 6493885Sbinkertn@umich.edu return bool(self.value) 6503885Sbinkertn@umich.edu 6513932Sbinkertn@umich.edu def ini_str(self): 6523885Sbinkertn@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)) 6674762Snate@binkert.org 6683101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01" 6695033Smilesck@eecs.umich.edudef NextEthernetAddr(): 6704762Snate@binkert.org global _NextEthernetAddr 6714762Snate@binkert.org 6724762Snate@binkert.org value = _NextEthernetAddr 6734762Snate@binkert.org _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 6744762Snate@binkert.org return value 6754762Snate@binkert.org 6764762Snate@binkert.orgclass 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: 6974762Snate@binkert.org 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, base=16) <= 0xff: 7014762Snate@binkert.org raise TypeError, 'invalid ethernet address %s' % value 7024762Snate@binkert.org 7034762Snate@binkert.org 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()) 7084762Snate@binkert.org return self 7094762Snate@binkert.org 7104762Snate@binkert.org def getValue(self): 7114762Snate@binkert.org from m5.internal.params import EthAddr 7124762Snate@binkert.org return EthAddr(self.value) 7134762Snate@binkert.org 7144762Snate@binkert.org def ini_str(self): 7154762Snate@binkert.org return self.value 7164762Snate@binkert.org 7174762Snate@binkert.org# When initializing an IpAddress, pass in an existing IpAddress, a string of 7184762Snate@binkert.org# the form "a.b.c.d", or an integer representing an IP. 7194762Snate@binkert.orgclass IpAddress(ParamValue): 7204762Snate@binkert.org cxx_type = 'Net::IpAddress' 7214762Snate@binkert.org 7224762Snate@binkert.org @classmethod 7234762Snate@binkert.org def cxx_predecls(cls, code): 7244762Snate@binkert.org code('#include "base/inet.hh"') 7254762Snate@binkert.org 7264762Snate@binkert.org @classmethod 7274762Snate@binkert.org def swig_predecls(cls, code): 7284762Snate@binkert.org code('%include "python/swig/inet.i"') 7294762Snate@binkert.org 7304762Snate@binkert.org def __init__(self, value): 7314762Snate@binkert.org if isinstance(value, IpAddress): 7324762Snate@binkert.org 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): 7454762Snate@binkert.org if isinstance(other, IpAddress): 7464762Snate@binkert.org return self.ip == other.ip 7474762Snate@binkert.org 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 7544167Sbinkertn@umich.edu 7553101Sstever@eecs.umich.edu def __ne__(self, other): 7563101Sstever@eecs.umich.edu return not (self == other) 7574762Snate@binkert.org 7583101Sstever@eecs.umich.edu def verifyIp(self): 7594167Sbinkertn@umich.edu if self.ip < 0 or self.ip >= (1 << 32): 7604762Snate@binkert.org raise TypeError, "invalid ip address %#08x" % self.ip 7614762Snate@binkert.org 7624762Snate@binkert.org def getValue(self): 7634167Sbinkertn@umich.edu from m5.internal.params import IpAddress 7643101Sstever@eecs.umich.edu return IpAddress(self.ip) 7654167Sbinkertn@umich.edu 7664167Sbinkertn@umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 7674167Sbinkertn@umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 7684167Sbinkertn@umich.edu# positional or keyword arguments. 7694167Sbinkertn@umich.educlass IpNetmask(IpAddress): 7704167Sbinkertn@umich.edu cxx_type = 'Net::IpNetmask' 7714167Sbinkertn@umich.edu 7724167Sbinkertn@umich.edu @classmethod 7734167Sbinkertn@umich.edu def cxx_predecls(cls, code): 7744167Sbinkertn@umich.edu code('#include "base/inet.hh"') 7754167Sbinkertn@umich.edu 7764167Sbinkertn@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: 7854762Snate@binkert.org setattr(self, key, elseVal) 7864762Snate@binkert.org else: 7874762Snate@binkert.org raise TypeError, "No value set for %s" % key 7884762Snate@binkert.org 7894762Snate@binkert.org if len(args) == 0: 7904762Snate@binkert.org handle_kwarg(self, kwargs, 'ip') 7914762Snate@binkert.org handle_kwarg(self, kwargs, 'netmask') 7923101Sstever@eecs.umich.edu 7933101Sstever@eecs.umich.edu elif len(args) == 1: 7944762Snate@binkert.org if kwargs: 7953101Sstever@eecs.umich.edu if not 'ip' in kwargs and not 'netmask' in kwargs: 7964167Sbinkertn@umich.edu raise TypeError, "Invalid arguments" 7973101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 7984167Sbinkertn@umich.edu handle_kwarg(self, kwargs, 'netmask', args[0]) 7994167Sbinkertn@umich.edu elif isinstance(args[0], IpNetmask): 8004167Sbinkertn@umich.edu self.ip = args[0].ip 8014167Sbinkertn@umich.edu self.netmask = args[0].netmask 8024167Sbinkertn@umich.edu else: 8034167Sbinkertn@umich.edu (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 8044167Sbinkertn@umich.edu 8054167Sbinkertn@umich.edu elif len(args) == 2: 8064167Sbinkertn@umich.edu self.ip = args[0] 8074167Sbinkertn@umich.edu self.netmask = args[1] 8084167Sbinkertn@umich.edu else: 8094167Sbinkertn@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) 8184167Sbinkertn@umich.edu 8194762Snate@binkert.org def __eq__(self, other): 8204762Snate@binkert.org if isinstance(other, IpNetmask): 8214762Snate@binkert.org return self.ip == other.ip and self.netmask == other.netmask 8224762Snate@binkert.org elif isinstance(other, str): 8234762Snate@binkert.org try: 8244762Snate@binkert.org return (self.ip, self.netmask) == convert.toIpNetmask(other) 8254762Snate@binkert.org except: 8263101Sstever@eecs.umich.edu return False 8274762Snate@binkert.org else: 8283101Sstever@eecs.umich.edu return False 8293101Sstever@eecs.umich.edu 8303101Sstever@eecs.umich.edu def verify(self): 8313101Sstever@eecs.umich.edu self.verifyIp() 8323101Sstever@eecs.umich.edu if self.netmask < 0 or self.netmask > 32: 8333101Sstever@eecs.umich.edu raise TypeError, "invalid netmask %d" % netmask 8343101Sstever@eecs.umich.edu 8354762Snate@binkert.org def getValue(self): 8363101Sstever@eecs.umich.edu from m5.internal.params import IpNetmask 8373101Sstever@eecs.umich.edu return IpNetmask(self.ip, self.netmask) 8384167Sbinkertn@umich.edu 8394167Sbinkertn@umich.edu# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 8404167Sbinkertn@umich.edu# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 8414167Sbinkertn@umich.educlass IpWithPort(IpAddress): 8424167Sbinkertn@umich.edu cxx_type = 'Net::IpWithPort' 8434167Sbinkertn@umich.edu 8444167Sbinkertn@umich.edu @classmethod 8454167Sbinkertn@umich.edu def cxx_predecls(cls, code): 8464167Sbinkertn@umich.edu code('#include "base/inet.hh"') 8474167Sbinkertn@umich.edu 8484167Sbinkertn@umich.edu @classmethod 8494167Sbinkertn@umich.edu def swig_predecls(cls, code): 8503101Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 8513101Sstever@eecs.umich.edu 8523101Sstever@eecs.umich.edu def __init__(self, *args, **kwargs): 8533101Sstever@eecs.umich.edu def handle_kwarg(self, kwargs, key, elseVal = None): 8543101Sstever@eecs.umich.edu if key in kwargs: 8553101Sstever@eecs.umich.edu setattr(self, key, kwargs.pop(key)) 8563101Sstever@eecs.umich.edu elif elseVal: 8573101Sstever@eecs.umich.edu setattr(self, key, elseVal) 8584762Snate@binkert.org else: 8594762Snate@binkert.org raise TypeError, "No value set for %s" % key 8604762Snate@binkert.org 8613101Sstever@eecs.umich.edu if len(args) == 0: 8623101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip') 8633101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'port') 8643101Sstever@eecs.umich.edu 8653101Sstever@eecs.umich.edu elif len(args) == 1: 8663101Sstever@eecs.umich.edu if kwargs: 8674167Sbinkertn@umich.edu if not 'ip' in kwargs and not 'port' in kwargs: 8684167Sbinkertn@umich.edu raise TypeError, "Invalid arguments" 8693101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'ip', args[0]) 8703101Sstever@eecs.umich.edu handle_kwarg(self, kwargs, 'port', args[0]) 8713101Sstever@eecs.umich.edu elif isinstance(args[0], IpWithPort): 8723101Sstever@eecs.umich.edu self.ip = args[0].ip 8733101Sstever@eecs.umich.edu self.port = args[0].port 8744762Snate@binkert.org else: 8754167Sbinkertn@umich.edu (self.ip, self.port) = convert.toIpWithPort(args[0]) 8764167Sbinkertn@umich.edu 8774167Sbinkertn@umich.edu elif len(args) == 2: 8784762Snate@binkert.org self.ip = args[0] 8794762Snate@binkert.org self.port = args[1] 8804762Snate@binkert.org else: 8814762Snate@binkert.org raise TypeError, "Too many arguments specified" 8824762Snate@binkert.org 8833101Sstever@eecs.umich.edu if kwargs: 8843101Sstever@eecs.umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 8853101Sstever@eecs.umich.edu 8863101Sstever@eecs.umich.edu self.verify() 8874167Sbinkertn@umich.edu 8883102Sstever@eecs.umich.edu def __str__(self): 8893101Sstever@eecs.umich.edu return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 8903101Sstever@eecs.umich.edu 8913101Sstever@eecs.umich.edu def __eq__(self, other): 8923101Sstever@eecs.umich.edu if isinstance(other, IpWithPort): 8933101Sstever@eecs.umich.edu return self.ip == other.ip and self.port == other.port 8944762Snate@binkert.org elif isinstance(other, str): 8954167Sbinkertn@umich.edu try: 8964167Sbinkertn@umich.edu return (self.ip, self.port) == convert.toIpWithPort(other) 8974167Sbinkertn@umich.edu except: 8984762Snate@binkert.org return False 8994762Snate@binkert.org else: 9004762Snate@binkert.org return False 9014762Snate@binkert.org 9024762Snate@binkert.org def verify(self): 9033101Sstever@eecs.umich.edu self.verifyIp() 9043101Sstever@eecs.umich.edu if self.port < 0 or self.port > 0xffff: 9053101Sstever@eecs.umich.edu raise TypeError, "invalid port %d" % self.port 9063101Sstever@eecs.umich.edu 9073101Sstever@eecs.umich.edu def getValue(self): 9083102Sstever@eecs.umich.edu from m5.internal.params import IpWithPort 9093102Sstever@eecs.umich.edu return IpWithPort(self.ip, self.port) 9103102Sstever@eecs.umich.edu 9113102Sstever@eecs.umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y", 9123102Sstever@eecs.umich.edu "%a %b %d %H:%M:%S %Z %Y", 9133102Sstever@eecs.umich.edu "%Y/%m/%d %H:%M:%S", 9143102Sstever@eecs.umich.edu "%Y/%m/%d %H:%M", 9153102Sstever@eecs.umich.edu "%Y/%m/%d", 9163102Sstever@eecs.umich.edu "%m/%d/%Y %H:%M:%S", 9173102Sstever@eecs.umich.edu "%m/%d/%Y %H:%M", 9183102Sstever@eecs.umich.edu "%m/%d/%Y", 9193102Sstever@eecs.umich.edu "%m/%d/%y %H:%M:%S", 9203102Sstever@eecs.umich.edu "%m/%d/%y %H:%M", 9213102Sstever@eecs.umich.edu "%m/%d/%y"] 9223102Sstever@eecs.umich.edu 9233102Sstever@eecs.umich.edu 9243102Sstever@eecs.umich.edudef parse_time(value): 9253102Sstever@eecs.umich.edu from time import gmtime, strptime, struct_time, time 9263102Sstever@eecs.umich.edu from datetime import datetime, date 9273102Sstever@eecs.umich.edu 9283102Sstever@eecs.umich.edu if isinstance(value, struct_time): 9294762Snate@binkert.org return value 9303102Sstever@eecs.umich.edu 9313102Sstever@eecs.umich.edu if isinstance(value, (int, long)): 9323102Sstever@eecs.umich.edu return gmtime(value) 9334762Snate@binkert.org 9344762Snate@binkert.org if isinstance(value, (datetime, date)): 9354762Snate@binkert.org return value.timetuple() 9363102Sstever@eecs.umich.edu 9373102Sstever@eecs.umich.edu if isinstance(value, str): 9383102Sstever@eecs.umich.edu if value in ('Now', 'Today'): 9393102Sstever@eecs.umich.edu return time.gmtime(time.time()) 9403102Sstever@eecs.umich.edu 9413102Sstever@eecs.umich.edu for format in time_formats: 9423101Sstever@eecs.umich.edu try: 9433101Sstever@eecs.umich.edu return strptime(value, format) 9443101Sstever@eecs.umich.edu except ValueError: 9453101Sstever@eecs.umich.edu pass 9463101Sstever@eecs.umich.edu 9473101Sstever@eecs.umich.edu raise ValueError, "Could not parse '%s' as a time" % value 9483101Sstever@eecs.umich.edu 9493101Sstever@eecs.umich.educlass Time(ParamValue): 9503101Sstever@eecs.umich.edu cxx_type = 'tm' 9513101Sstever@eecs.umich.edu 9523101Sstever@eecs.umich.edu @classmethod 9533101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 9543101Sstever@eecs.umich.edu code('#include <time.h>') 9553101Sstever@eecs.umich.edu 9563101Sstever@eecs.umich.edu @classmethod 9573101Sstever@eecs.umich.edu def swig_predecls(cls, code): 9583101Sstever@eecs.umich.edu code('%include "python/swig/time.i"') 9593105Sstever@eecs.umich.edu 9603105Sstever@eecs.umich.edu def __init__(self, value): 9613101Sstever@eecs.umich.edu self.value = parse_time(value) 9623101Sstever@eecs.umich.edu 9633101Sstever@eecs.umich.edu def getValue(self): 9643101Sstever@eecs.umich.edu from m5.internal.params import tm 9653105Sstever@eecs.umich.edu 9663101Sstever@eecs.umich.edu c_time = tm() 9673103Sstever@eecs.umich.edu py_time = self.value 9683105Sstever@eecs.umich.edu 9693103Sstever@eecs.umich.edu # UNIX is years since 1900 9703105Sstever@eecs.umich.edu c_time.tm_year = py_time.tm_year - 1900; 9713105Sstever@eecs.umich.edu 9723105Sstever@eecs.umich.edu # Python starts at 1, UNIX starts at 0 9733105Sstever@eecs.umich.edu c_time.tm_mon = py_time.tm_mon - 1; 9743105Sstever@eecs.umich.edu c_time.tm_mday = py_time.tm_mday; 9753105Sstever@eecs.umich.edu c_time.tm_hour = py_time.tm_hour; 9763105Sstever@eecs.umich.edu c_time.tm_min = py_time.tm_min; 9773105Sstever@eecs.umich.edu c_time.tm_sec = py_time.tm_sec; 9783105Sstever@eecs.umich.edu 9793105Sstever@eecs.umich.edu # Python has 0 as Monday, UNIX is 0 as sunday 9803105Sstever@eecs.umich.edu c_time.tm_wday = py_time.tm_wday + 1 9813105Sstever@eecs.umich.edu if c_time.tm_wday > 6: 9823105Sstever@eecs.umich.edu c_time.tm_wday -= 7; 9833109Sstever@eecs.umich.edu 9843105Sstever@eecs.umich.edu # Python starts at 1, Unix starts at 0 9853105Sstever@eecs.umich.edu c_time.tm_yday = py_time.tm_yday - 1; 9863105Sstever@eecs.umich.edu 9873105Sstever@eecs.umich.edu return c_time 9883105Sstever@eecs.umich.edu 9893105Sstever@eecs.umich.edu def __str__(self): 9903105Sstever@eecs.umich.edu return time.asctime(self.value) 9913105Sstever@eecs.umich.edu 9923101Sstever@eecs.umich.edu def ini_str(self): 9933109Sstever@eecs.umich.edu return str(self) 9943109Sstever@eecs.umich.edu 9953109Sstever@eecs.umich.edu def get_config_as_dict(self): 9963109Sstever@eecs.umich.edu return str(self) 9973109Sstever@eecs.umich.edu 9983109Sstever@eecs.umich.edu# Enumerated types are a little more complex. The user specifies the 9993109Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of 10003109Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so). (In the 10013109Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index 10023101Sstever@eecs.umich.edu# or the corresponding dictionary value. For now, since we only check 10033105Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file, 10043105Sstever@eecs.umich.edu# there's not much point in using the dictionary.) 10053105Sstever@eecs.umich.edu 10063101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the 10073105Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter 10083105Sstever@eecs.umich.edu# can be instances of that type. We define two hidden internal 10093101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then 10103105Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly. 10113179Sstever@eecs.umich.edu 10123105Sstever@eecs.umich.eduallEnums = {} 10133105Sstever@eecs.umich.edu# Metaclass for Enum types 10143101Sstever@eecs.umich.educlass MetaEnum(MetaParamValue): 10153101Sstever@eecs.umich.edu def __new__(mcls, name, bases, dict): 10163105Sstever@eecs.umich.edu assert name not in allEnums 10173105Sstever@eecs.umich.edu 10183105Sstever@eecs.umich.edu cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 10193105Sstever@eecs.umich.edu allEnums[name] = cls 10203105Sstever@eecs.umich.edu return cls 10213105Sstever@eecs.umich.edu 10223105Sstever@eecs.umich.edu def __init__(cls, name, bases, init_dict): 10233105Sstever@eecs.umich.edu if init_dict.has_key('map'): 10243105Sstever@eecs.umich.edu if not isinstance(cls.map, dict): 10253105Sstever@eecs.umich.edu raise TypeError, "Enum-derived class attribute 'map' " \ 10263105Sstever@eecs.umich.edu "must be of type dict" 10273101Sstever@eecs.umich.edu # build list of value strings from map 10283101Sstever@eecs.umich.edu cls.vals = cls.map.keys() 10294859Snate@binkert.org cls.vals.sort() 10304762Snate@binkert.org elif init_dict.has_key('vals'): 10313101Sstever@eecs.umich.edu if not isinstance(cls.vals, list): 10323101Sstever@eecs.umich.edu raise TypeError, "Enum-derived class attribute 'vals' " \ 10333101Sstever@eecs.umich.edu "must be of type list" 10344859Snate@binkert.org # build string->value map from vals sequence 10354859Snate@binkert.org cls.map = {} 10363101Sstever@eecs.umich.edu for idx,val in enumerate(cls.vals): 10373101Sstever@eecs.umich.edu cls.map[val] = idx 10383101Sstever@eecs.umich.edu else: 10393105Sstever@eecs.umich.edu raise TypeError, "Enum-derived class must define "\ 10403105Sstever@eecs.umich.edu "attribute 'map' or 'vals'" 10413105Sstever@eecs.umich.edu 10423105Sstever@eecs.umich.edu cls.cxx_type = 'Enums::%s' % name 10433105Sstever@eecs.umich.edu 10443105Sstever@eecs.umich.edu super(MetaEnum, cls).__init__(name, bases, init_dict) 10453105Sstever@eecs.umich.edu 10463105Sstever@eecs.umich.edu # Generate C++ class declaration for this enum type. 10473105Sstever@eecs.umich.edu # Note that we wrap the enum in a class/struct to act as a namespace, 10483105Sstever@eecs.umich.edu # so that the enum strings can be brief w/o worrying about collisions. 10493105Sstever@eecs.umich.edu def cxx_decl(cls, code): 10503105Sstever@eecs.umich.edu name = cls.__name__ 10513105Sstever@eecs.umich.edu code('''\ 10523105Sstever@eecs.umich.edu#ifndef __ENUM__${name}__ 10533105Sstever@eecs.umich.edu#define __ENUM__${name}__ 10543105Sstever@eecs.umich.edu 10553105Sstever@eecs.umich.edunamespace Enums { 10563105Sstever@eecs.umich.edu enum $name { 10573105Sstever@eecs.umich.edu''') 10583109Sstever@eecs.umich.edu code.indent(2) 10593109Sstever@eecs.umich.edu for val in cls.vals: 10603109Sstever@eecs.umich.edu code('$val = ${{cls.map[val]}},') 10613105Sstever@eecs.umich.edu code('Num_$name = ${{len(cls.vals)}}') 10623105Sstever@eecs.umich.edu code.dedent(2) 10633105Sstever@eecs.umich.edu code('''\ 10643105Sstever@eecs.umich.edu }; 10653105Sstever@eecs.umich.eduextern const char *${name}Strings[Num_${name}]; 10663105Sstever@eecs.umich.edu} 10673105Sstever@eecs.umich.edu 10683105Sstever@eecs.umich.edu#endif // __ENUM__${name}__ 10693105Sstever@eecs.umich.edu''') 10703105Sstever@eecs.umich.edu 10713105Sstever@eecs.umich.edu def cxx_def(cls, code): 10723105Sstever@eecs.umich.edu name = cls.__name__ 10733105Sstever@eecs.umich.edu code('''\ 10743105Sstever@eecs.umich.edu#include "enums/$name.hh" 10753105Sstever@eecs.umich.edunamespace Enums { 10763105Sstever@eecs.umich.edu const char *${name}Strings[Num_${name}] = 10773105Sstever@eecs.umich.edu { 10783105Sstever@eecs.umich.edu''') 10793105Sstever@eecs.umich.edu code.indent(2) 10803105Sstever@eecs.umich.edu for val in cls.vals: 10813105Sstever@eecs.umich.edu code('"$val",') 10823105Sstever@eecs.umich.edu code.dedent(2) 10833105Sstever@eecs.umich.edu code(''' 10843109Sstever@eecs.umich.edu }; 10853109Sstever@eecs.umich.edu} // namespace Enums 10863109Sstever@eecs.umich.edu''') 10873109Sstever@eecs.umich.edu 10883109Sstever@eecs.umich.edu def swig_decl(cls, code): 10893109Sstever@eecs.umich.edu name = cls.__name__ 10903109Sstever@eecs.umich.edu code('''\ 10913109Sstever@eecs.umich.edu%module(package="m5.internal") enum_$name 10923109Sstever@eecs.umich.edu 10933109Sstever@eecs.umich.edu%{ 10943109Sstever@eecs.umich.edu#include "enums/$name.hh" 10953109Sstever@eecs.umich.edu%} 10963109Sstever@eecs.umich.edu 10973109Sstever@eecs.umich.edu%include "enums/$name.hh" 10983109Sstever@eecs.umich.edu''') 10993109Sstever@eecs.umich.edu 11003109Sstever@eecs.umich.edu 11013109Sstever@eecs.umich.edu# Base class for enum types. 11023109Sstever@eecs.umich.educlass Enum(ParamValue): 11033105Sstever@eecs.umich.edu __metaclass__ = MetaEnum 11043105Sstever@eecs.umich.edu vals = [] 11053105Sstever@eecs.umich.edu 11063105Sstever@eecs.umich.edu def __init__(self, value): 11073105Sstever@eecs.umich.edu if value not in self.map: 11083105Sstever@eecs.umich.edu raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 11093105Sstever@eecs.umich.edu % (value, self.vals) 11103101Sstever@eecs.umich.edu self.value = value 11113101Sstever@eecs.umich.edu 11123101Sstever@eecs.umich.edu @classmethod 11133101Sstever@eecs.umich.edu def cxx_predecls(cls, code): 11143105Sstever@eecs.umich.edu code('#include "enums/$0.hh"', cls.__name__) 11153105Sstever@eecs.umich.edu 11163105Sstever@eecs.umich.edu @classmethod 11173105Sstever@eecs.umich.edu def swig_predecls(cls, code): 11183105Sstever@eecs.umich.edu code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 11193105Sstever@eecs.umich.edu 11203105Sstever@eecs.umich.edu def getValue(self): 11213105Sstever@eecs.umich.edu return int(self.map[self.value]) 11223105Sstever@eecs.umich.edu 11233105Sstever@eecs.umich.edu def __str__(self): 11243105Sstever@eecs.umich.edu return self.value 11253101Sstever@eecs.umich.edu 11263101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it? 11273101Sstever@eecs.umich.edufrequency_tolerance = 0.001 # 0.1% 11283105Sstever@eecs.umich.edu 11293105Sstever@eecs.umich.educlass TickParamValue(NumericParamValue): 11303101Sstever@eecs.umich.edu cxx_type = 'Tick' 11313101Sstever@eecs.umich.edu 11323101Sstever@eecs.umich.edu @classmethod 11333105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 11343105Sstever@eecs.umich.edu code('#include "base/types.hh"') 11353101Sstever@eecs.umich.edu 11363101Sstever@eecs.umich.edu @classmethod 11373101Sstever@eecs.umich.edu def swig_predecls(cls, code): 11383101Sstever@eecs.umich.edu code('%import "stdint.i"') 11393105Sstever@eecs.umich.edu code('%import "base/types.hh"') 11403105Sstever@eecs.umich.edu 11413101Sstever@eecs.umich.edu def getValue(self): 11423101Sstever@eecs.umich.edu return long(self.value) 11433105Sstever@eecs.umich.edu 11443105Sstever@eecs.umich.educlass Latency(TickParamValue): 11453105Sstever@eecs.umich.edu def __init__(self, value): 11463109Sstever@eecs.umich.edu if isinstance(value, (Latency, Clock)): 11473109Sstever@eecs.umich.edu self.ticks = value.ticks 11483109Sstever@eecs.umich.edu self.value = value.value 11493109Sstever@eecs.umich.edu elif isinstance(value, Frequency): 11503109Sstever@eecs.umich.edu self.ticks = value.ticks 11513109Sstever@eecs.umich.edu self.value = 1.0 / value.value 11523109Sstever@eecs.umich.edu elif value.endswith('t'): 11533109Sstever@eecs.umich.edu self.ticks = True 11543105Sstever@eecs.umich.edu self.value = int(value[:-1]) 11553101Sstever@eecs.umich.edu else: 11563101Sstever@eecs.umich.edu self.ticks = False 11573101Sstever@eecs.umich.edu self.value = convert.toLatency(value) 11583101Sstever@eecs.umich.edu 11593101Sstever@eecs.umich.edu def __getattr__(self, attr): 11603101Sstever@eecs.umich.edu if attr in ('latency', 'period'): 11613101Sstever@eecs.umich.edu return self 11624167Sbinkertn@umich.edu if attr == 'frequency': 11633101Sstever@eecs.umich.edu return Frequency(self) 11643101Sstever@eecs.umich.edu raise AttributeError, "Latency object has no attribute '%s'" % attr 11653101Sstever@eecs.umich.edu 11663885Sbinkertn@umich.edu def getValue(self): 11673102Sstever@eecs.umich.edu if self.ticks or self.value == 0: 11683101Sstever@eecs.umich.edu 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 getValue(self): 1248 return self.period.getValue() 1249 1250 def ini_str(self): 1251 return self.period.ini_str() 1252 1253class Voltage(float,ParamValue): 1254 cxx_type = 'double' 1255 def __new__(cls, value): 1256 # convert to voltage 1257 val = convert.toVoltage(value) 1258 return super(cls, Voltage).__new__(cls, val) 1259 1260 def __str__(self): 1261 return str(self.val) 1262 1263 def getValue(self): 1264 value = float(self) 1265 return value 1266 1267 def ini_str(self): 1268 return '%f' % self.getValue() 1269 1270class NetworkBandwidth(float,ParamValue): 1271 cxx_type = 'float' 1272 def __new__(cls, value): 1273 # convert to bits per second 1274 val = convert.toNetworkBandwidth(value) 1275 return super(cls, NetworkBandwidth).__new__(cls, val) 1276 1277 def __str__(self): 1278 return str(self.val) 1279 1280 def getValue(self): 1281 # convert to seconds per byte 1282 value = 8.0 / float(self) 1283 # convert to ticks per byte 1284 value = ticks.fromSeconds(value) 1285 return float(value) 1286 1287 def ini_str(self): 1288 return '%f' % self.getValue() 1289 1290class MemoryBandwidth(float,ParamValue): 1291 cxx_type = 'float' 1292 def __new__(cls, value): 1293 # convert to bytes per second 1294 val = convert.toMemoryBandwidth(value) 1295 return super(cls, MemoryBandwidth).__new__(cls, val) 1296 1297 def __str__(self): 1298 return str(self.val) 1299 1300 def getValue(self): 1301 # convert to seconds per byte 1302 value = float(self) 1303 if value: 1304 value = 1.0 / float(self) 1305 # convert to ticks per byte 1306 value = ticks.fromSeconds(value) 1307 return float(value) 1308 1309 def ini_str(self): 1310 return '%f' % self.getValue() 1311 1312# 1313# "Constants"... handy aliases for various values. 1314# 1315 1316# Special class for NULL pointers. Note the special check in 1317# make_param_value() above that lets these be assigned where a 1318# SimObject is required. 1319# only one copy of a particular node 1320class NullSimObject(object): 1321 __metaclass__ = Singleton 1322 1323 def __call__(cls): 1324 return cls 1325 1326 def _instantiate(self, parent = None, path = ''): 1327 pass 1328 1329 def ini_str(self): 1330 return 'Null' 1331 1332 def unproxy(self, base): 1333 return self 1334 1335 def set_path(self, parent, name): 1336 pass 1337 1338 def __str__(self): 1339 return 'Null' 1340 1341 def getValue(self): 1342 return None 1343 1344# The only instance you'll ever need... 1345NULL = NullSimObject() 1346 1347def isNullPointer(value): 1348 return isinstance(value, NullSimObject) 1349 1350# Some memory range specifications use this as a default upper bound. 1351MaxAddr = Addr.max 1352MaxTick = Tick.max 1353AllMemory = AddrRange(0, MaxAddr) 1354 1355 1356##################################################################### 1357# 1358# Port objects 1359# 1360# Ports are used to interconnect objects in the memory system. 1361# 1362##################################################################### 1363 1364# Port reference: encapsulates a reference to a particular port on a 1365# particular SimObject. 1366class PortRef(object): 1367 def __init__(self, simobj, name, role): 1368 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1369 self.simobj = simobj 1370 self.name = name 1371 self.role = role 1372 self.peer = None # not associated with another port yet 1373 self.ccConnected = False # C++ port connection done? 1374 self.index = -1 # always -1 for non-vector ports 1375 1376 def __str__(self): 1377 return '%s.%s' % (self.simobj, self.name) 1378 1379 def __len__(self): 1380 # Return the number of connected ports, i.e. 0 is we have no 1381 # peer and 1 if we do. 1382 return int(self.peer != None) 1383 1384 # for config.ini, print peer's name (not ours) 1385 def ini_str(self): 1386 return str(self.peer) 1387 1388 # for config.json 1389 def get_config_as_dict(self): 1390 return {'role' : self.role, 'peer' : str(self.peer)} 1391 1392 def __getattr__(self, attr): 1393 if attr == 'peerObj': 1394 # shorthand for proxies 1395 return self.peer.simobj 1396 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1397 (self.__class__.__name__, attr) 1398 1399 # Full connection is symmetric (both ways). Called via 1400 # SimObject.__setattr__ as a result of a port assignment, e.g., 1401 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1402 # e.g., "obj1.portA[3] = obj2.portB". 1403 def connect(self, other): 1404 if isinstance(other, VectorPortRef): 1405 # reference to plain VectorPort is implicit append 1406 other = other._get_next() 1407 if self.peer and not proxy.isproxy(self.peer): 1408 fatal("Port %s is already connected to %s, cannot connect %s\n", 1409 self, self.peer, other); 1410 self.peer = other 1411 if proxy.isproxy(other): 1412 other.set_param_desc(PortParamDesc()) 1413 elif isinstance(other, PortRef): 1414 if other.peer is not self: 1415 other.connect(self) 1416 else: 1417 raise TypeError, \ 1418 "assigning non-port reference '%s' to port '%s'" \ 1419 % (other, self) 1420 1421 def clone(self, simobj, memo): 1422 if memo.has_key(self): 1423 return memo[self] 1424 newRef = copy.copy(self) 1425 memo[self] = newRef 1426 newRef.simobj = simobj 1427 assert(isSimObject(newRef.simobj)) 1428 if self.peer and not proxy.isproxy(self.peer): 1429 peerObj = self.peer.simobj(_memo=memo) 1430 newRef.peer = self.peer.clone(peerObj, memo) 1431 assert(not isinstance(newRef.peer, VectorPortRef)) 1432 return newRef 1433 1434 def unproxy(self, simobj): 1435 assert(simobj is self.simobj) 1436 if proxy.isproxy(self.peer): 1437 try: 1438 realPeer = self.peer.unproxy(self.simobj) 1439 except: 1440 print "Error in unproxying port '%s' of %s" % \ 1441 (self.name, self.simobj.path()) 1442 raise 1443 self.connect(realPeer) 1444 1445 # Call C++ to create corresponding port connection between C++ objects 1446 def ccConnect(self): 1447 from m5.internal.pyobject import connectPorts 1448 1449 if self.role == 'SLAVE': 1450 # do nothing and let the master take care of it 1451 return 1452 1453 if self.ccConnected: # already done this 1454 return 1455 peer = self.peer 1456 if not self.peer: # nothing to connect to 1457 return 1458 1459 # check that we connect a master to a slave 1460 if self.role == peer.role: 1461 raise TypeError, \ 1462 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1463 % (peer, self, self.role) 1464 1465 try: 1466 # self is always the master and peer the slave 1467 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1468 peer.simobj.getCCObject(), peer.name, peer.index) 1469 except: 1470 print "Error connecting port %s.%s to %s.%s" % \ 1471 (self.simobj.path(), self.name, 1472 peer.simobj.path(), peer.name) 1473 raise 1474 self.ccConnected = True 1475 peer.ccConnected = True 1476 1477# A reference to an individual element of a VectorPort... much like a 1478# PortRef, but has an index. 1479class VectorPortElementRef(PortRef): 1480 def __init__(self, simobj, name, role, index): 1481 PortRef.__init__(self, simobj, name, role) 1482 self.index = index 1483 1484 def __str__(self): 1485 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1486 1487# A reference to a complete vector-valued port (not just a single element). 1488# Can be indexed to retrieve individual VectorPortElementRef instances. 1489class VectorPortRef(object): 1490 def __init__(self, simobj, name, role): 1491 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1492 self.simobj = simobj 1493 self.name = name 1494 self.role = role 1495 self.elements = [] 1496 1497 def __str__(self): 1498 return '%s.%s[:]' % (self.simobj, self.name) 1499 1500 def __len__(self): 1501 # Return the number of connected peers, corresponding the the 1502 # length of the elements. 1503 return len(self.elements) 1504 1505 # for config.ini, print peer's name (not ours) 1506 def ini_str(self): 1507 return ' '.join([el.ini_str() for el in self.elements]) 1508 1509 # for config.json 1510 def get_config_as_dict(self): 1511 return {'role' : self.role, 1512 'peer' : [el.ini_str() for el in self.elements]} 1513 1514 def __getitem__(self, key): 1515 if not isinstance(key, int): 1516 raise TypeError, "VectorPort index must be integer" 1517 if key >= len(self.elements): 1518 # need to extend list 1519 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1520 for i in range(len(self.elements), key+1)] 1521 self.elements.extend(ext) 1522 return self.elements[key] 1523 1524 def _get_next(self): 1525 return self[len(self.elements)] 1526 1527 def __setitem__(self, key, value): 1528 if not isinstance(key, int): 1529 raise TypeError, "VectorPort index must be integer" 1530 self[key].connect(value) 1531 1532 def connect(self, other): 1533 if isinstance(other, (list, tuple)): 1534 # Assign list of port refs to vector port. 1535 # For now, append them... not sure if that's the right semantics 1536 # or if it should replace the current vector. 1537 for ref in other: 1538 self._get_next().connect(ref) 1539 else: 1540 # scalar assignment to plain VectorPort is implicit append 1541 self._get_next().connect(other) 1542 1543 def clone(self, simobj, memo): 1544 if memo.has_key(self): 1545 return memo[self] 1546 newRef = copy.copy(self) 1547 memo[self] = newRef 1548 newRef.simobj = simobj 1549 assert(isSimObject(newRef.simobj)) 1550 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1551 return newRef 1552 1553 def unproxy(self, simobj): 1554 [el.unproxy(simobj) for el in self.elements] 1555 1556 def ccConnect(self): 1557 [el.ccConnect() for el in self.elements] 1558 1559# Port description object. Like a ParamDesc object, this represents a 1560# logical port in the SimObject class, not a particular port on a 1561# SimObject instance. The latter are represented by PortRef objects. 1562class Port(object): 1563 # Generate a PortRef for this port on the given SimObject with the 1564 # given name 1565 def makeRef(self, simobj): 1566 return PortRef(simobj, self.name, self.role) 1567 1568 # Connect an instance of this port (on the given SimObject with 1569 # the given name) with the port described by the supplied PortRef 1570 def connect(self, simobj, ref): 1571 self.makeRef(simobj).connect(ref) 1572 1573 # No need for any pre-declarations at the moment as we merely rely 1574 # on an unsigned int. 1575 def cxx_predecls(self, code): 1576 pass 1577 1578 # Declare an unsigned int with the same name as the port, that 1579 # will eventually hold the number of connected ports (and thus the 1580 # number of elements for a VectorPort). 1581 def cxx_decl(self, code): 1582 code('unsigned int port_${{self.name}}_connection_count;') 1583 1584class MasterPort(Port): 1585 # MasterPort("description") 1586 def __init__(self, *args): 1587 if len(args) == 1: 1588 self.desc = args[0] 1589 self.role = 'MASTER' 1590 else: 1591 raise TypeError, 'wrong number of arguments' 1592 1593class SlavePort(Port): 1594 # SlavePort("description") 1595 def __init__(self, *args): 1596 if len(args) == 1: 1597 self.desc = args[0] 1598 self.role = 'SLAVE' 1599 else: 1600 raise TypeError, 'wrong number of arguments' 1601 1602# VectorPort description object. Like Port, but represents a vector 1603# of connections (e.g., as on a Bus). 1604class VectorPort(Port): 1605 def __init__(self, *args): 1606 self.isVec = True 1607 1608 def makeRef(self, simobj): 1609 return VectorPortRef(simobj, self.name, self.role) 1610 1611class VectorMasterPort(VectorPort): 1612 # VectorMasterPort("description") 1613 def __init__(self, *args): 1614 if len(args) == 1: 1615 self.desc = args[0] 1616 self.role = 'MASTER' 1617 VectorPort.__init__(self, *args) 1618 else: 1619 raise TypeError, 'wrong number of arguments' 1620 1621class VectorSlavePort(VectorPort): 1622 # VectorSlavePort("description") 1623 def __init__(self, *args): 1624 if len(args) == 1: 1625 self.desc = args[0] 1626 self.role = 'SLAVE' 1627 VectorPort.__init__(self, *args) 1628 else: 1629 raise TypeError, 'wrong number of arguments' 1630 1631# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1632# proxy objects (via set_param_desc()) so that proxy error messages 1633# make sense. 1634class PortParamDesc(object): 1635 __metaclass__ = Singleton 1636 1637 ptype_str = 'Port' 1638 ptype = Port 1639 1640baseEnums = allEnums.copy() 1641baseParams = allParams.copy() 1642 1643def clear(): 1644 global allEnums, allParams 1645 1646 allEnums = baseEnums.copy() 1647 allParams = baseParams.copy() 1648 1649__all__ = ['Param', 'VectorParam', 1650 'Enum', 'Bool', 'String', 'Float', 1651 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1652 'Int32', 'UInt32', 'Int64', 'UInt64', 1653 'Counter', 'Addr', 'Tick', 'Percent', 1654 'TcpPort', 'UdpPort', 'EthernetAddr', 1655 'IpAddress', 'IpNetmask', 'IpWithPort', 1656 'MemorySize', 'MemorySize32', 1657 'Latency', 'Frequency', 'Clock', 'Voltage', 1658 'NetworkBandwidth', 'MemoryBandwidth', 1659 'AddrRange', 1660 'MaxAddr', 'MaxTick', 'AllMemory', 1661 'Time', 1662 'NextEthernetAddr', 'NULL', 1663 'MasterPort', 'SlavePort', 1664 'VectorMasterPort', 'VectorSlavePort'] 1665 1666import SimObject 1667