params.py revision 10181:6270235e0585
16167SN/A# Copyright (c) 2012-2013 ARM Limited 26167SN/A# All rights reserved. 36167SN/A# 410036SAli.Saidi@ARM.com# The license below extends only to copyright in the software and shall 58835SAli.Saidi@ARM.com# not be construed as granting a license to any other intellectual 610036SAli.Saidi@ARM.com# property including but not limited to intellectual property relating 77935SN/A# to a hardware implementation of the functionality of the software 87935SN/A# licensed hereunder. You may use the software subject to the license 97935SN/A# terms below provided that you ensure that this notice is replicated 106167SN/A# unmodified and in its entirety in all distributions of the software, 116167SN/A# modified or unmodified, in source code or in binary form. 126167SN/A# 1310526Snilay@cs.wisc.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 148835SAli.Saidi@ARM.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 159864Snilay@cs.wisc.edu# All rights reserved. 169864Snilay@cs.wisc.edu# 1710036SAli.Saidi@ARM.com# Redistribution and use in source and binary forms, with or without 188835SAli.Saidi@ARM.com# modification, are permitted provided that the following conditions are 198835SAli.Saidi@ARM.com# met: redistributions of source code must retain the above copyright 2010315Snilay@cs.wisc.edu# notice, this list of conditions and the following disclaimer; 218835SAli.Saidi@ARM.com# redistributions in binary form must reproduce the above copyright 2210093Snilay@cs.wisc.edu# notice, this list of conditions and the following disclaimer in the 237935SN/A# documentation and/or other materials provided with the distribution; 249864Snilay@cs.wisc.edu# neither the name of the copyright holders nor the names of its 2510526Snilay@cs.wisc.edu# contributors may be used to endorse or promote products derived from 2610736Snilay@cs.wisc.edu# this software without specific prior written permission. 278721SN/A# 288835SAli.Saidi@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 298835SAli.Saidi@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307935SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 317935SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 327935SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337935SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 347935SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 357935SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 367935SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 378983Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386167SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 399864Snilay@cs.wisc.edu# 409864Snilay@cs.wisc.edu# Authors: Steve Reinhardt 419864Snilay@cs.wisc.edu# Nathan Binkert 4210315Snilay@cs.wisc.edu# Gabe Black 4310036SAli.Saidi@ARM.com# Andreas Hansson 4410315Snilay@cs.wisc.edu 459864Snilay@cs.wisc.edu##################################################################### 469864Snilay@cs.wisc.edu# 476167SN/A# Parameter description classes 486167SN/A# 499864Snilay@cs.wisc.edu# The _params dictionary in each class maps parameter names to either 5010093Snilay@cs.wisc.edu# a Param or a VectorParam object. These objects contain the 516167SN/A# parameter description string, the parameter type, and the default 529864Snilay@cs.wisc.edu# value (if any). The convert() method on these objects is used to 536167SN/A# force whatever value is assigned to the parameter to the appropriate 546167SN/A# type. 558835SAli.Saidi@ARM.com# 566167SN/A# Note that the default values are loaded into the class's attribute 576167SN/A# space when the parameter dictionary is initialized (in 5810036SAli.Saidi@ARM.com# MetaSimObject._new_param()); after that point they aren't used. 596167SN/A# 606167SN/A##################################################################### 618835SAli.Saidi@ARM.com 629469Snilay@cs.wisc.eduimport copy 636167SN/Aimport datetime 646167SN/Aimport re 656167SN/Aimport sys 666167SN/Aimport time 676167SN/Aimport math 686167SN/A 698835SAli.Saidi@ARM.comimport proxy 706167SN/Aimport ticks 719864Snilay@cs.wisc.edufrom util import * 7210229Snilay@cs.wisc.edu 739469Snilay@cs.wisc.edudef isSimObject(*args, **kwargs): 746167SN/A return SimObject.isSimObject(*args, **kwargs) 756167SN/A 766167SN/Adef isSimObjectSequence(*args, **kwargs): 779469Snilay@cs.wisc.edu return SimObject.isSimObjectSequence(*args, **kwargs) 789469Snilay@cs.wisc.edu 796167SN/Adef isSimObjectClass(*args, **kwargs): 809864Snilay@cs.wisc.edu return SimObject.isSimObjectClass(*args, **kwargs) 819864Snilay@cs.wisc.edu 829864Snilay@cs.wisc.eduallParams = {} 8310315Snilay@cs.wisc.edu 8410036SAli.Saidi@ARM.comclass MetaParamValue(type): 8510315Snilay@cs.wisc.edu def __new__(mcls, name, bases, dct): 869864Snilay@cs.wisc.edu cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 879864Snilay@cs.wisc.edu assert name not in allParams 886167SN/A allParams[name] = cls 896167SN/A return cls 9010036SAli.Saidi@ARM.com 916167SN/A 926167SN/A# Dummy base class to identify types that are legitimate for SimObject 938835SAli.Saidi@ARM.com# parameters. 948835SAli.Saidi@ARM.comclass ParamValue(object): 9510036SAli.Saidi@ARM.com __metaclass__ = MetaParamValue 968835SAli.Saidi@ARM.com 979469Snilay@cs.wisc.edu 989469Snilay@cs.wisc.edu # Generate the code needed as a prerequisite for declaring a C++ 9910036SAli.Saidi@ARM.com # object of this type. Typically generates one or more #include 1009469Snilay@cs.wisc.edu # statements. Used when declaring parameters of this type. 1019469Snilay@cs.wisc.edu @classmethod 10210036SAli.Saidi@ARM.com def cxx_predecls(cls, code): 1039469Snilay@cs.wisc.edu pass 1046167SN/A 1056167SN/A # Generate the code needed as a prerequisite for including a 10610036SAli.Saidi@ARM.com # reference to a C++ object of this type in a SWIG .i file. 1076167SN/A # Typically generates one or more %import or %include statements. 1086167SN/A @classmethod 1096167SN/A def swig_predecls(cls, code): 1106167SN/A pass 11110036SAli.Saidi@ARM.com 1126167SN/A # default for printing to .ini file is regular string conversion. 1136167SN/A # will be overridden in some cases 1146167SN/A def ini_str(self): 1156167SN/A return str(self) 1166167SN/A 11710736Snilay@cs.wisc.edu # allows us to blithely call unproxy() on things without checking 1186167SN/A # if they're really proxies or not 1196167SN/A def unproxy(self, base): 1206167SN/A return self 1216167SN/A 12210036SAli.Saidi@ARM.com# Regular parameter description. 12311066Snilay@cs.wisc.educlass ParamDesc(object): 1246167SN/A def __init__(self, ptype_str, ptype, *args, **kwargs): 1256167SN/A self.ptype_str = ptype_str 12610736Snilay@cs.wisc.edu # remember ptype only if it is provided 1276167SN/A if ptype != None: 1286167SN/A self.ptype = ptype 1296167SN/A 1306167SN/A if args: 1316167SN/A if len(args) == 1: 1326167SN/A self.desc = args[0] 1336167SN/A elif len(args) == 2: 13410451Snilay@cs.wisc.edu self.default = args[0] 1356167SN/A self.desc = args[1] 13610315Snilay@cs.wisc.edu else: 13710315Snilay@cs.wisc.edu raise TypeError, 'too many arguments' 13810315Snilay@cs.wisc.edu 13910315Snilay@cs.wisc.edu if kwargs.has_key('desc'): 14010315Snilay@cs.wisc.edu assert(not hasattr(self, 'desc')) 14110315Snilay@cs.wisc.edu self.desc = kwargs['desc'] 14210315Snilay@cs.wisc.edu del kwargs['desc'] 14310315Snilay@cs.wisc.edu 14410526Snilay@cs.wisc.edu if kwargs.has_key('default'): 14510526Snilay@cs.wisc.edu assert(not hasattr(self, 'default')) 14610526Snilay@cs.wisc.edu self.default = kwargs['default'] 14710526Snilay@cs.wisc.edu del kwargs['default'] 14810526Snilay@cs.wisc.edu 14910526Snilay@cs.wisc.edu if kwargs: 15010526Snilay@cs.wisc.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 15110526Snilay@cs.wisc.edu 15210526Snilay@cs.wisc.edu if not hasattr(self, 'desc'): 15310526Snilay@cs.wisc.edu raise TypeError, 'desc attribute missing' 15410526Snilay@cs.wisc.edu 15510526Snilay@cs.wisc.edu def __getattr__(self, attr): 15610526Snilay@cs.wisc.edu if attr == 'ptype': 15710526Snilay@cs.wisc.edu ptype = SimObject.allClasses[self.ptype_str] 15810526Snilay@cs.wisc.edu assert isSimObjectClass(ptype) 15910526Snilay@cs.wisc.edu self.ptype = ptype 16010526Snilay@cs.wisc.edu return ptype 16110526Snilay@cs.wisc.edu 16210526Snilay@cs.wisc.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 16310526Snilay@cs.wisc.edu (type(self).__name__, attr) 16410526Snilay@cs.wisc.edu 16510526Snilay@cs.wisc.edu def convert(self, value): 16610526Snilay@cs.wisc.edu if isinstance(value, proxy.BaseProxy): 16710526Snilay@cs.wisc.edu value.set_param_desc(self) 16810526Snilay@cs.wisc.edu return value 16910526Snilay@cs.wisc.edu if not hasattr(self, 'ptype') and isNullPointer(value): 17010526Snilay@cs.wisc.edu # deferred evaluation of SimObject; continue to defer if 17110736Snilay@cs.wisc.edu # we're just assigning a null pointer 17210526Snilay@cs.wisc.edu return value 17310526Snilay@cs.wisc.edu if isinstance(value, self.ptype): 17410526Snilay@cs.wisc.edu return value 17510526Snilay@cs.wisc.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 1769864Snilay@cs.wisc.edu return value 1779864Snilay@cs.wisc.edu return self.ptype(value) 17810526Snilay@cs.wisc.edu 17910526Snilay@cs.wisc.edu def cxx_predecls(self, code): 18010526Snilay@cs.wisc.edu code('#include <cstddef>') 18110526Snilay@cs.wisc.edu self.ptype.cxx_predecls(code) 18210526Snilay@cs.wisc.edu 18310036SAli.Saidi@ARM.com def swig_predecls(self, code): 1849469Snilay@cs.wisc.edu self.ptype.swig_predecls(code) 18510526Snilay@cs.wisc.edu 18610526Snilay@cs.wisc.edu def cxx_decl(self, code): 18710526Snilay@cs.wisc.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 18810526Snilay@cs.wisc.edu 18910526Snilay@cs.wisc.edu# Vector-valued parameter description. Just like ParamDesc, except 19010526Snilay@cs.wisc.edu# that the value is a vector (list) of the specified type instead of a 19110526Snilay@cs.wisc.edu# single value. 19210526Snilay@cs.wisc.edu 19310526Snilay@cs.wisc.educlass VectorParamValue(list): 19410526Snilay@cs.wisc.edu __metaclass__ = MetaParamValue 19510526Snilay@cs.wisc.edu def __setattr__(self, attr, value): 19610526Snilay@cs.wisc.edu raise AttributeError, \ 19710526Snilay@cs.wisc.edu "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 19810526Snilay@cs.wisc.edu 19910526Snilay@cs.wisc.edu def ini_str(self): 20010526Snilay@cs.wisc.edu return ' '.join([v.ini_str() for v in self]) 20110526Snilay@cs.wisc.edu 20210526Snilay@cs.wisc.edu def getValue(self): 20310526Snilay@cs.wisc.edu return [ v.getValue() for v in self ] 20410526Snilay@cs.wisc.edu 20510526Snilay@cs.wisc.edu def unproxy(self, base): 20610526Snilay@cs.wisc.edu if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 20710526Snilay@cs.wisc.edu return self[0].unproxy(base) 20810526Snilay@cs.wisc.edu else: 20910526Snilay@cs.wisc.edu return [v.unproxy(base) for v in self] 21010526Snilay@cs.wisc.edu 21110526Snilay@cs.wisc.educlass SimObjectVector(VectorParamValue): 21210526Snilay@cs.wisc.edu # support clone operation 21310526Snilay@cs.wisc.edu def __call__(self, **kwargs): 21410526Snilay@cs.wisc.edu return SimObjectVector([v(**kwargs) for v in self]) 21510526Snilay@cs.wisc.edu 21610526Snilay@cs.wisc.edu def clear_parent(self, old_parent): 21710526Snilay@cs.wisc.edu for v in self: 21810526Snilay@cs.wisc.edu v.clear_parent(old_parent) 21910526Snilay@cs.wisc.edu 2209469Snilay@cs.wisc.edu def set_parent(self, parent, name): 2219469Snilay@cs.wisc.edu if len(self) == 1: 2229469Snilay@cs.wisc.edu self[0].set_parent(parent, name) 22310036SAli.Saidi@ARM.com else: 22410736Snilay@cs.wisc.edu width = int(math.ceil(math.log(len(self))/math.log(10))) 22510036SAli.Saidi@ARM.com for i,v in enumerate(self): 2269469Snilay@cs.wisc.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2279864Snilay@cs.wisc.edu 22810036SAli.Saidi@ARM.com def has_parent(self): 22910036SAli.Saidi@ARM.com return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 23010526Snilay@cs.wisc.edu 23110036SAli.Saidi@ARM.com # return 'cpu0 cpu1' etc. for print_ini() 23210526Snilay@cs.wisc.edu def get_name(self): 2339469Snilay@cs.wisc.edu return ' '.join([v._name for v in self]) 2349469Snilay@cs.wisc.edu 2359469Snilay@cs.wisc.edu # By iterating through the constituent members of the vector here 2369864Snilay@cs.wisc.edu # we can nicely handle iterating over all a SimObject's children 2379864Snilay@cs.wisc.edu # without having to provide lots of special functions on 2389864Snilay@cs.wisc.edu # SimObjectVector directly. 23910315Snilay@cs.wisc.edu def descendants(self): 24010036SAli.Saidi@ARM.com for v in self: 24110315Snilay@cs.wisc.edu for obj in v.descendants(): 2429864Snilay@cs.wisc.edu yield obj 2439864Snilay@cs.wisc.edu 2449469Snilay@cs.wisc.edu def get_config_as_dict(self): 2456928SN/A a = [] 24611023Sjthestness@gmail.com for v in self: 2476928SN/A a.append(v.get_config_as_dict()) 2489864Snilay@cs.wisc.edu return a 24910036SAli.Saidi@ARM.com 2509469Snilay@cs.wisc.edu # If we are replacing an item in the vector, make sure to set the 2516928SN/A # parent reference of the new SimObject to be the same as the parent 25211023Sjthestness@gmail.com # of the SimObject being replaced. Useful to have if we created 25311023Sjthestness@gmail.com # a SimObjectVector of temporary objects that will be modified later in 25410036SAli.Saidi@ARM.com # configuration scripts. 25511023Sjthestness@gmail.com def __setitem__(self, key, value): 2566928SN/A val = self[key] 2576928SN/A if value.has_parent(): 25811023Sjthestness@gmail.com warn("SimObject %s already has a parent" % value.get_name() +\ 25911023Sjthestness@gmail.com " that is being overwritten by a SimObjectVector") 26011023Sjthestness@gmail.com value.set_parent(val.get_parent(), val._name) 2618540SN/A super(SimObjectVector, self).__setitem__(key, value) 26210526Snilay@cs.wisc.edu 26310526Snilay@cs.wisc.educlass VectorParamDesc(ParamDesc): 2649864Snilay@cs.wisc.edu # Convert assigned value to appropriate type. If the RHS is not a 2656928SN/A # list or tuple, it generates a single-element list. 26610526Snilay@cs.wisc.edu def convert(self, value): 2676928SN/A if isinstance(value, (list, tuple)): 2689469Snilay@cs.wisc.edu # list: coerce each element into new list 2696928SN/A tmp_list = [ ParamDesc.convert(self, v) for v in value ] 27010036SAli.Saidi@ARM.com else: 2719469Snilay@cs.wisc.edu # singleton: coerce to a single-element list 2729864Snilay@cs.wisc.edu tmp_list = [ ParamDesc.convert(self, value) ] 2736928SN/A 2746928SN/A if isSimObjectSequence(tmp_list): 27511023Sjthestness@gmail.com return SimObjectVector(tmp_list) 27611023Sjthestness@gmail.com else: 27711023Sjthestness@gmail.com return VectorParamValue(tmp_list) 27811023Sjthestness@gmail.com 27911023Sjthestness@gmail.com def swig_module_name(self): 28011023Sjthestness@gmail.com return "%s_vector" % self.ptype_str 28111023Sjthestness@gmail.com 28211023Sjthestness@gmail.com def swig_predecls(self, code): 28311023Sjthestness@gmail.com code('%import "${{self.swig_module_name()}}.i"') 28411023Sjthestness@gmail.com 28511023Sjthestness@gmail.com def swig_decl(self, code): 28611023Sjthestness@gmail.com code('%module(package="m5.internal") ${{self.swig_module_name()}}') 28711023Sjthestness@gmail.com code('%{') 28811023Sjthestness@gmail.com self.ptype.cxx_predecls(code) 28911023Sjthestness@gmail.com code('%}') 29011023Sjthestness@gmail.com code() 29111023Sjthestness@gmail.com # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 29211023Sjthestness@gmail.com code('%include "std_container.i"') 29311023Sjthestness@gmail.com code() 29411023Sjthestness@gmail.com self.ptype.swig_predecls(code) 29511023Sjthestness@gmail.com code() 29611023Sjthestness@gmail.com code('%include "std_vector.i"') 29711023Sjthestness@gmail.com code() 29811023Sjthestness@gmail.com 29911023Sjthestness@gmail.com ptype = self.ptype_str 30011023Sjthestness@gmail.com cxx_type = self.ptype.cxx_type 30111023Sjthestness@gmail.com 30211023Sjthestness@gmail.com code('%template(vector_$ptype) std::vector< $cxx_type >;') 30311023Sjthestness@gmail.com 30411023Sjthestness@gmail.com def cxx_predecls(self, code): 30511023Sjthestness@gmail.com code('#include <vector>') 30611023Sjthestness@gmail.com self.ptype.cxx_predecls(code) 30711023Sjthestness@gmail.com 30811023Sjthestness@gmail.com def cxx_decl(self, code): 30911023Sjthestness@gmail.com code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 31011023Sjthestness@gmail.com 31111023Sjthestness@gmail.comclass ParamFactory(object): 31211023Sjthestness@gmail.com def __init__(self, param_desc_class, ptype_str = None): 31311023Sjthestness@gmail.com self.param_desc_class = param_desc_class 31411023Sjthestness@gmail.com self.ptype_str = ptype_str 31511023Sjthestness@gmail.com 31611023Sjthestness@gmail.com def __getattr__(self, attr): 31711023Sjthestness@gmail.com if self.ptype_str: 31811023Sjthestness@gmail.com attr = self.ptype_str + '.' + attr 31911023Sjthestness@gmail.com return ParamFactory(self.param_desc_class, attr) 32011023Sjthestness@gmail.com 32111023Sjthestness@gmail.com # E.g., Param.Int(5, "number of widgets") 32211023Sjthestness@gmail.com def __call__(self, *args, **kwargs): 32311023Sjthestness@gmail.com ptype = None 32411023Sjthestness@gmail.com try: 32511023Sjthestness@gmail.com ptype = allParams[self.ptype_str] 32611023Sjthestness@gmail.com except KeyError: 32711023Sjthestness@gmail.com # if name isn't defined yet, assume it's a SimObject, and 3289469Snilay@cs.wisc.edu # try to resolve it later 3297935SN/A pass 33011023Sjthestness@gmail.com return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 3317935SN/A 3329469Snilay@cs.wisc.eduParam = ParamFactory(ParamDesc) 3337935SN/AVectorParam = ParamFactory(VectorParamDesc) 33410315Snilay@cs.wisc.edu 33510036SAli.Saidi@ARM.com##################################################################### 33610036SAli.Saidi@ARM.com# 33711023Sjthestness@gmail.com# Parameter Types 3387935SN/A# 33911023Sjthestness@gmail.com# Though native Python types could be used to specify parameter types 3407935SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more 3417935SN/A# flexible to define our own set of types. This gives us more control 34211023Sjthestness@gmail.com# over how Python expressions are converted to values (via the 34311023Sjthestness@gmail.com# __init__() constructor) and how these values are printed out (via 34411023Sjthestness@gmail.com# the __str__() conversion method). 3458540SN/A# 3468835SAli.Saidi@ARM.com##################################################################### 3479469Snilay@cs.wisc.edu 34810526Snilay@cs.wisc.edu# String-valued parameter. Just mixin the ParamValue class with the 3499864Snilay@cs.wisc.edu# built-in str class. 3507935SN/Aclass String(ParamValue,str): 3517935SN/A cxx_type = 'std::string' 3529469Snilay@cs.wisc.edu 3538540SN/A @classmethod 35411023Sjthestness@gmail.com def cxx_predecls(self, code): 3558540SN/A code('#include <string>') 3569113SBrad.Beckmann@amd.com 3579113SBrad.Beckmann@amd.com @classmethod 35810036SAli.Saidi@ARM.com def swig_predecls(cls, code): 3598721SN/A code('%include "std_string.i"') 36011023Sjthestness@gmail.com 3619113SBrad.Beckmann@amd.com def getValue(self): 36211023Sjthestness@gmail.com return self 3638540SN/A 3648540SN/A# superclass for "numeric" parameter values, to emulate math 3659113SBrad.Beckmann@amd.com# operations in a type-safe way. e.g., a Latency times an int returns 3669113SBrad.Beckmann@amd.com# a new Latency object. 3678540SN/Aclass NumericParamValue(ParamValue): 36811023Sjthestness@gmail.com def __str__(self): 36911023Sjthestness@gmail.com return str(self.value) 37011023Sjthestness@gmail.com 37111023Sjthestness@gmail.com def __float__(self): 37211023Sjthestness@gmail.com return float(self.value) 37311023Sjthestness@gmail.com 37411023Sjthestness@gmail.com def __long__(self): 37511023Sjthestness@gmail.com return long(self.value) 37611023Sjthestness@gmail.com 37711023Sjthestness@gmail.com def __int__(self): 37811023Sjthestness@gmail.com return int(self.value) 37911023Sjthestness@gmail.com 38011023Sjthestness@gmail.com # hook for bounds checking 38111023Sjthestness@gmail.com def _check(self): 38211023Sjthestness@gmail.com return 38311023Sjthestness@gmail.com 38411023Sjthestness@gmail.com def __mul__(self, other): 38511023Sjthestness@gmail.com newobj = self.__class__(self) 38611023Sjthestness@gmail.com newobj.value *= other 38711023Sjthestness@gmail.com newobj._check() 38811023Sjthestness@gmail.com return newobj 38911023Sjthestness@gmail.com 39011023Sjthestness@gmail.com __rmul__ = __mul__ 39111023Sjthestness@gmail.com 39211023Sjthestness@gmail.com def __div__(self, other): 39311023Sjthestness@gmail.com newobj = self.__class__(self) 39411023Sjthestness@gmail.com newobj.value /= other 39511023Sjthestness@gmail.com newobj._check() 39611023Sjthestness@gmail.com return newobj 39711023Sjthestness@gmail.com 39811023Sjthestness@gmail.com def __sub__(self, other): 39911023Sjthestness@gmail.com newobj = self.__class__(self) 40011023Sjthestness@gmail.com newobj.value -= other 40111023Sjthestness@gmail.com newobj._check() 40211023Sjthestness@gmail.com return newobj 40311023Sjthestness@gmail.com 40411023Sjthestness@gmail.com# Metaclass for bounds-checked integer parameters. See CheckedInt. 40511023Sjthestness@gmail.comclass CheckedIntType(MetaParamValue): 40611023Sjthestness@gmail.com def __init__(cls, name, bases, dict): 40711023Sjthestness@gmail.com super(CheckedIntType, cls).__init__(name, bases, dict) 40811023Sjthestness@gmail.com 40911023Sjthestness@gmail.com # CheckedInt is an abstract base class, so we actually don't 41011023Sjthestness@gmail.com # want to do any processing on it... the rest of this code is 41111023Sjthestness@gmail.com # just for classes that derive from CheckedInt. 41211023Sjthestness@gmail.com if name == 'CheckedInt': 41311023Sjthestness@gmail.com return 41411023Sjthestness@gmail.com 41511023Sjthestness@gmail.com if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 41611023Sjthestness@gmail.com if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 41711023Sjthestness@gmail.com panic("CheckedInt subclass %s must define either\n" \ 41811023Sjthestness@gmail.com " 'min' and 'max' or 'size' and 'unsigned'\n", 4199469Snilay@cs.wisc.edu name); 4208540SN/A if cls.unsigned: 42110315Snilay@cs.wisc.edu cls.min = 0 4229469Snilay@cs.wisc.edu cls.max = 2 ** cls.size - 1 42311023Sjthestness@gmail.com else: 4248540SN/A cls.min = -(2 ** (cls.size - 1)) 42510036SAli.Saidi@ARM.com cls.max = (2 ** (cls.size - 1)) - 1 4269469Snilay@cs.wisc.edu 42711023Sjthestness@gmail.com# Abstract superclass for bounds-checked integer parameters. This 4288540SN/A# class is subclassed to generate parameter classes with specific 4298540SN/A# bounds. Initialization of the min and max bounds is done in the 4308983Snate@binkert.org# metaclass CheckedIntType.__init__. 4318983Snate@binkert.orgclass CheckedInt(NumericParamValue): 4328983Snate@binkert.org __metaclass__ = CheckedIntType 4338540SN/A 4348540SN/A def _check(self): 4358540SN/A if not self.min <= self.value <= self.max: 4368983Snate@binkert.org raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 4378540SN/A (self.min, self.value, self.max) 4389864Snilay@cs.wisc.edu 4399864Snilay@cs.wisc.edu def __init__(self, value): 4409864Snilay@cs.wisc.edu if isinstance(value, str): 4419864Snilay@cs.wisc.edu self.value = convert.toInteger(value) 44210036SAli.Saidi@ARM.com elif isinstance(value, (int, long, float, NumericParamValue)): 4439864Snilay@cs.wisc.edu self.value = long(value) 4447935SN/A else: 4457935SN/A raise TypeError, "Can't convert object of type %s to CheckedInt" \ 44611066Snilay@cs.wisc.edu % type(value).__name__ 4477935SN/A self._check() 4487935SN/A 4499864Snilay@cs.wisc.edu @classmethod 4507935SN/A def cxx_predecls(cls, code): 4518540SN/A # most derived types require this, so we just do it here once 45210036SAli.Saidi@ARM.com code('#include "base/types.hh"') 4539605Snilay@cs.wisc.edu 45411066Snilay@cs.wisc.edu @classmethod 4559605Snilay@cs.wisc.edu def swig_predecls(cls, code): 45610229Snilay@cs.wisc.edu # most derived types require this, so we just do it here once 45711066Snilay@cs.wisc.edu code('%import "stdint.i"') 45811023Sjthestness@gmail.com code('%import "base/types.hh"') 4599864Snilay@cs.wisc.edu 4608540SN/A def getValue(self): 4619605Snilay@cs.wisc.edu return long(self.value) 46211023Sjthestness@gmail.com 46311023Sjthestness@gmail.comclass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 4647935SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 4659605Snilay@cs.wisc.edu 4668540SN/Aclass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 4678540SN/Aclass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 46810036SAli.Saidi@ARM.comclass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 4699469Snilay@cs.wisc.educlass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4709864Snilay@cs.wisc.educlass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 4717935SN/Aclass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 4728540SN/Aclass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 4737935SN/Aclass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 4747935SN/A 4759605Snilay@cs.wisc.educlass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 4768540SN/Aclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 4778540SN/Aclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 47810036SAli.Saidi@ARM.comclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4799469Snilay@cs.wisc.edu 4809864Snilay@cs.wisc.educlass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 4817935SN/A 4828540SN/Aclass Cycles(CheckedInt): 4837935SN/A cxx_type = 'Cycles' 4847935SN/A size = 64 48511023Sjthestness@gmail.com unsigned = True 48611023Sjthestness@gmail.com 48711023Sjthestness@gmail.com def getValue(self): 48811023Sjthestness@gmail.com from m5.internal.core import Cycles 48911023Sjthestness@gmail.com return Cycles(self.value) 49011023Sjthestness@gmail.com 49111023Sjthestness@gmail.comclass Float(ParamValue, float): 49211023Sjthestness@gmail.com cxx_type = 'double' 49311023Sjthestness@gmail.com 49411023Sjthestness@gmail.com def __init__(self, value): 49511023Sjthestness@gmail.com if isinstance(value, (int, long, float, NumericParamValue, Float)): 49611023Sjthestness@gmail.com self.value = float(value) 49711023Sjthestness@gmail.com else: 49811023Sjthestness@gmail.com raise TypeError, "Can't convert object of type %s to Float" \ 49911023Sjthestness@gmail.com % type(value).__name__ 50011023Sjthestness@gmail.com 50111023Sjthestness@gmail.com def getValue(self): 50211023Sjthestness@gmail.com return float(self.value) 50311023Sjthestness@gmail.com 50411023Sjthestness@gmail.comclass MemorySize(CheckedInt): 50511023Sjthestness@gmail.com cxx_type = 'uint64_t' 50611023Sjthestness@gmail.com size = 64 50711023Sjthestness@gmail.com unsigned = True 50811023Sjthestness@gmail.com def __init__(self, value): 50911023Sjthestness@gmail.com if isinstance(value, MemorySize): 51011023Sjthestness@gmail.com self.value = value.value 51111023Sjthestness@gmail.com else: 51211023Sjthestness@gmail.com self.value = convert.toMemorySize(value) 51311023Sjthestness@gmail.com self._check() 51411023Sjthestness@gmail.com 51511023Sjthestness@gmail.comclass MemorySize32(CheckedInt): 51611023Sjthestness@gmail.com cxx_type = 'uint32_t' 51711023Sjthestness@gmail.com size = 32 51811023Sjthestness@gmail.com unsigned = True 51911023Sjthestness@gmail.com def __init__(self, value): 52011023Sjthestness@gmail.com if isinstance(value, MemorySize): 52111023Sjthestness@gmail.com self.value = value.value 52211023Sjthestness@gmail.com else: 52311023Sjthestness@gmail.com self.value = convert.toMemorySize(value) 52411023Sjthestness@gmail.com self._check() 52511023Sjthestness@gmail.com 52611023Sjthestness@gmail.comclass Addr(CheckedInt): 52711023Sjthestness@gmail.com cxx_type = 'Addr' 52811023Sjthestness@gmail.com size = 64 52911023Sjthestness@gmail.com unsigned = True 53011023Sjthestness@gmail.com def __init__(self, value): 53111023Sjthestness@gmail.com if isinstance(value, Addr): 53211023Sjthestness@gmail.com self.value = value.value 53311023Sjthestness@gmail.com else: 53411023Sjthestness@gmail.com try: 53511023Sjthestness@gmail.com self.value = convert.toMemorySize(value) 53611023Sjthestness@gmail.com except TypeError: 53711023Sjthestness@gmail.com self.value = long(value) 53811023Sjthestness@gmail.com self._check() 53911023Sjthestness@gmail.com def __add__(self, other): 54011023Sjthestness@gmail.com if isinstance(other, Addr): 54111023Sjthestness@gmail.com return self.value + other.value 54211023Sjthestness@gmail.com else: 54311023Sjthestness@gmail.com return self.value + other 54411023Sjthestness@gmail.com 54511023Sjthestness@gmail.comclass AddrRange(ParamValue): 54611023Sjthestness@gmail.com cxx_type = 'AddrRange' 54711023Sjthestness@gmail.com 54811023Sjthestness@gmail.com def __init__(self, *args, **kwargs): 54911023Sjthestness@gmail.com # Disable interleaving by default 55011023Sjthestness@gmail.com self.intlvHighBit = 0 55111023Sjthestness@gmail.com self.intlvBits = 0 55211023Sjthestness@gmail.com self.intlvMatch = 0 55311023Sjthestness@gmail.com 55411023Sjthestness@gmail.com def handle_kwargs(self, kwargs): 55511023Sjthestness@gmail.com # An address range needs to have an upper limit, specified 55611023Sjthestness@gmail.com # either explicitly with an end, or as an offset using the 55711023Sjthestness@gmail.com # size keyword. 55811023Sjthestness@gmail.com if 'end' in kwargs: 55911023Sjthestness@gmail.com self.end = Addr(kwargs.pop('end')) 56011023Sjthestness@gmail.com elif 'size' in kwargs: 56111023Sjthestness@gmail.com self.end = self.start + Addr(kwargs.pop('size')) - 1 56211023Sjthestness@gmail.com else: 56311023Sjthestness@gmail.com raise TypeError, "Either end or size must be specified" 56411023Sjthestness@gmail.com 56511023Sjthestness@gmail.com # Now on to the optional bit 56611023Sjthestness@gmail.com if 'intlvHighBit' in kwargs: 56711023Sjthestness@gmail.com self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 56811023Sjthestness@gmail.com if 'intlvBits' in kwargs: 56911023Sjthestness@gmail.com self.intlvBits = int(kwargs.pop('intlvBits')) 57011023Sjthestness@gmail.com if 'intlvMatch' in kwargs: 57111023Sjthestness@gmail.com self.intlvMatch = int(kwargs.pop('intlvMatch')) 57211023Sjthestness@gmail.com 57311023Sjthestness@gmail.com if len(args) == 0: 57411023Sjthestness@gmail.com self.start = Addr(kwargs.pop('start')) 57511023Sjthestness@gmail.com handle_kwargs(self, kwargs) 57611023Sjthestness@gmail.com 57711023Sjthestness@gmail.com elif len(args) == 1: 57811023Sjthestness@gmail.com if kwargs: 57911023Sjthestness@gmail.com self.start = Addr(args[0]) 58011023Sjthestness@gmail.com handle_kwargs(self, kwargs) 58111023Sjthestness@gmail.com elif isinstance(args[0], (list, tuple)): 58211023Sjthestness@gmail.com self.start = Addr(args[0][0]) 58311023Sjthestness@gmail.com self.end = Addr(args[0][1]) 58411023Sjthestness@gmail.com else: 58511023Sjthestness@gmail.com self.start = Addr(0) 58611023Sjthestness@gmail.com self.end = Addr(args[0]) - 1 58711023Sjthestness@gmail.com 58811023Sjthestness@gmail.com elif len(args) == 2: 58911023Sjthestness@gmail.com self.start = Addr(args[0]) 59011023Sjthestness@gmail.com self.end = Addr(args[1]) 59111023Sjthestness@gmail.com else: 59211023Sjthestness@gmail.com raise TypeError, "Too many arguments specified" 59311023Sjthestness@gmail.com 59411023Sjthestness@gmail.com if kwargs: 59511023Sjthestness@gmail.com raise TypeError, "Too many keywords: %s" % kwargs.keys() 59611023Sjthestness@gmail.com 59711023Sjthestness@gmail.com def __str__(self): 59811023Sjthestness@gmail.com return '%s:%s' % (self.start, self.end) 59911023Sjthestness@gmail.com 60011023Sjthestness@gmail.com def size(self): 60111023Sjthestness@gmail.com # Divide the size by the size of the interleaving slice 60211023Sjthestness@gmail.com return (long(self.end) - long(self.start) + 1) >> self.intlvBits 60311023Sjthestness@gmail.com 60411023Sjthestness@gmail.com @classmethod 60511023Sjthestness@gmail.com def cxx_predecls(cls, code): 60611023Sjthestness@gmail.com Addr.cxx_predecls(code) 60711023Sjthestness@gmail.com code('#include "base/addr_range.hh"') 60811023Sjthestness@gmail.com 60911023Sjthestness@gmail.com @classmethod 61011023Sjthestness@gmail.com def swig_predecls(cls, code): 61111023Sjthestness@gmail.com Addr.swig_predecls(code) 61211023Sjthestness@gmail.com 61311023Sjthestness@gmail.com def getValue(self): 61411023Sjthestness@gmail.com # Go from the Python class to the wrapped C++ class generated 61511023Sjthestness@gmail.com # by swig 61611023Sjthestness@gmail.com from m5.internal.range import AddrRange 61711023Sjthestness@gmail.com 61811023Sjthestness@gmail.com return AddrRange(long(self.start), long(self.end), 61911023Sjthestness@gmail.com int(self.intlvHighBit), int(self.intlvBits), 62011023Sjthestness@gmail.com int(self.intlvMatch)) 62111023Sjthestness@gmail.com 62211023Sjthestness@gmail.com# Boolean parameter type. Python doesn't let you subclass bool, since 62311023Sjthestness@gmail.com# it doesn't want to let you create multiple instances of True and 62411023Sjthestness@gmail.com# False. Thus this is a little more complicated than String. 62511023Sjthestness@gmail.comclass Bool(ParamValue): 62611023Sjthestness@gmail.com cxx_type = 'bool' 62711023Sjthestness@gmail.com def __init__(self, value): 62811023Sjthestness@gmail.com try: 62911023Sjthestness@gmail.com self.value = convert.toBool(value) 63011023Sjthestness@gmail.com except TypeError: 63111023Sjthestness@gmail.com self.value = bool(value) 63211023Sjthestness@gmail.com 63311023Sjthestness@gmail.com def getValue(self): 63411023Sjthestness@gmail.com return bool(self.value) 63511023Sjthestness@gmail.com 63611023Sjthestness@gmail.com def __str__(self): 63711023Sjthestness@gmail.com return str(self.value) 63811023Sjthestness@gmail.com 63911023Sjthestness@gmail.com # implement truth value testing for Bool parameters so that these params 64011023Sjthestness@gmail.com # evaluate correctly during the python configuration phase 64111023Sjthestness@gmail.com def __nonzero__(self): 64211023Sjthestness@gmail.com return bool(self.value) 64311023Sjthestness@gmail.com 64411023Sjthestness@gmail.com def ini_str(self): 6459605Snilay@cs.wisc.edu if self.value: 6468540SN/A return 'true' 6478540SN/A return 'false' 64810036SAli.Saidi@ARM.com 6496928SN/Adef IncEthernetAddr(addr, val = 1): 6508540SN/A bytes = map(lambda x: int(x, 16), addr.split(':')) 6519864Snilay@cs.wisc.edu bytes[5] += val 6529864Snilay@cs.wisc.edu for i in (5, 4, 3, 2, 1): 6536928SN/A val,rem = divmod(bytes[i], 256) 6546928SN/A bytes[i] = rem 6559605Snilay@cs.wisc.edu if val == 0: 6568540SN/A break 6578540SN/A bytes[i - 1] += val 65810036SAli.Saidi@ARM.com assert(bytes[0] <= 255) 6596928SN/A return ':'.join(map(lambda x: '%02x' % x, bytes)) 6608540SN/A 6619864Snilay@cs.wisc.edu_NextEthernetAddr = "00:90:00:00:00:01" 6629864Snilay@cs.wisc.edudef NextEthernetAddr(): 6636928SN/A global _NextEthernetAddr 6646928SN/A 6659864Snilay@cs.wisc.edu value = _NextEthernetAddr 6669864Snilay@cs.wisc.edu _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 66711066Snilay@cs.wisc.edu return value 6689864Snilay@cs.wisc.edu 66910036SAli.Saidi@ARM.comclass EthernetAddr(ParamValue): 67011066Snilay@cs.wisc.edu cxx_type = 'Net::EthAddr' 67111023Sjthestness@gmail.com 6729864Snilay@cs.wisc.edu @classmethod 67311066Snilay@cs.wisc.edu def cxx_predecls(cls, code): 6749864Snilay@cs.wisc.edu code('#include "base/inet.hh"') 67511023Sjthestness@gmail.com 67611023Sjthestness@gmail.com @classmethod 67711023Sjthestness@gmail.com def swig_predecls(cls, code): 67811023Sjthestness@gmail.com code('%include "python/swig/inet.i"') 67911023Sjthestness@gmail.com 68011023Sjthestness@gmail.com def __init__(self, value): 68111023Sjthestness@gmail.com if value == NextEthernetAddr: 68211023Sjthestness@gmail.com self.value = value 68311023Sjthestness@gmail.com return 68411023Sjthestness@gmail.com 68511023Sjthestness@gmail.com if not isinstance(value, str): 68611023Sjthestness@gmail.com raise TypeError, "expected an ethernet address and didn't get one" 68711023Sjthestness@gmail.com 68811023Sjthestness@gmail.com bytes = value.split(':') 68911023Sjthestness@gmail.com if len(bytes) != 6: 69011023Sjthestness@gmail.com raise TypeError, 'invalid ethernet address %s' % value 69111023Sjthestness@gmail.com 69211023Sjthestness@gmail.com for byte in bytes: 69311023Sjthestness@gmail.com if not 0 <= int(byte, base=16) <= 0xff: 69411023Sjthestness@gmail.com raise TypeError, 'invalid ethernet address %s' % value 69511023Sjthestness@gmail.com 69611023Sjthestness@gmail.com self.value = value 69711023Sjthestness@gmail.com 69811023Sjthestness@gmail.com def unproxy(self, base): 69911023Sjthestness@gmail.com if self.value == NextEthernetAddr: 70011023Sjthestness@gmail.com return EthernetAddr(self.value()) 70111023Sjthestness@gmail.com return self 70211023Sjthestness@gmail.com 70311023Sjthestness@gmail.com def getValue(self): 70411023Sjthestness@gmail.com from m5.internal.params import EthAddr 70511023Sjthestness@gmail.com return EthAddr(self.value) 70611023Sjthestness@gmail.com 70711023Sjthestness@gmail.com def ini_str(self): 70811023Sjthestness@gmail.com return self.value 70911023Sjthestness@gmail.com 71011023Sjthestness@gmail.com# When initializing an IpAddress, pass in an existing IpAddress, a string of 71111023Sjthestness@gmail.com# the form "a.b.c.d", or an integer representing an IP. 71211023Sjthestness@gmail.comclass IpAddress(ParamValue): 71311023Sjthestness@gmail.com cxx_type = 'Net::IpAddress' 71411023Sjthestness@gmail.com 71511023Sjthestness@gmail.com @classmethod 71611023Sjthestness@gmail.com def cxx_predecls(cls, code): 71711023Sjthestness@gmail.com code('#include "base/inet.hh"') 71811023Sjthestness@gmail.com 71911023Sjthestness@gmail.com @classmethod 72011023Sjthestness@gmail.com def swig_predecls(cls, code): 72111023Sjthestness@gmail.com code('%include "python/swig/inet.i"') 72211023Sjthestness@gmail.com 72311023Sjthestness@gmail.com def __init__(self, value): 72411023Sjthestness@gmail.com if isinstance(value, IpAddress): 72511023Sjthestness@gmail.com self.ip = value.ip 72611023Sjthestness@gmail.com else: 72711023Sjthestness@gmail.com try: 72811023Sjthestness@gmail.com self.ip = convert.toIpAddress(value) 72911023Sjthestness@gmail.com except TypeError: 73011023Sjthestness@gmail.com self.ip = long(value) 73111023Sjthestness@gmail.com self.verifyIp() 73211023Sjthestness@gmail.com 73311023Sjthestness@gmail.com def __str__(self): 73411023Sjthestness@gmail.com tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 73511023Sjthestness@gmail.com return '%d.%d.%d.%d' % tuple(tup) 73611023Sjthestness@gmail.com 73711023Sjthestness@gmail.com def __eq__(self, other): 73811023Sjthestness@gmail.com if isinstance(other, IpAddress): 73911023Sjthestness@gmail.com return self.ip == other.ip 74011023Sjthestness@gmail.com elif isinstance(other, str): 74111023Sjthestness@gmail.com try: 74211023Sjthestness@gmail.com return self.ip == convert.toIpAddress(other) 74311023Sjthestness@gmail.com except: 74411023Sjthestness@gmail.com return False 74511023Sjthestness@gmail.com else: 74611023Sjthestness@gmail.com return self.ip == other 74711023Sjthestness@gmail.com 74811023Sjthestness@gmail.com def __ne__(self, other): 74911023Sjthestness@gmail.com return not (self == other) 75011023Sjthestness@gmail.com 75111023Sjthestness@gmail.com def verifyIp(self): 75211023Sjthestness@gmail.com if self.ip < 0 or self.ip >= (1 << 32): 75311023Sjthestness@gmail.com raise TypeError, "invalid ip address %#08x" % self.ip 75411023Sjthestness@gmail.com 75511023Sjthestness@gmail.com def getValue(self): 75611023Sjthestness@gmail.com from m5.internal.params import IpAddress 75711023Sjthestness@gmail.com return IpAddress(self.ip) 75811023Sjthestness@gmail.com 75911023Sjthestness@gmail.com# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 76011023Sjthestness@gmail.com# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 76111023Sjthestness@gmail.com# positional or keyword arguments. 76211023Sjthestness@gmail.comclass IpNetmask(IpAddress): 76311023Sjthestness@gmail.com cxx_type = 'Net::IpNetmask' 76411023Sjthestness@gmail.com 76511023Sjthestness@gmail.com @classmethod 76611023Sjthestness@gmail.com def cxx_predecls(cls, code): 76711023Sjthestness@gmail.com code('#include "base/inet.hh"') 76811023Sjthestness@gmail.com 76911023Sjthestness@gmail.com @classmethod 77011023Sjthestness@gmail.com def swig_predecls(cls, code): 77111023Sjthestness@gmail.com code('%include "python/swig/inet.i"') 77211023Sjthestness@gmail.com 77311023Sjthestness@gmail.com def __init__(self, *args, **kwargs): 77411023Sjthestness@gmail.com def handle_kwarg(self, kwargs, key, elseVal = None): 77511023Sjthestness@gmail.com if key in kwargs: 77611023Sjthestness@gmail.com setattr(self, key, kwargs.pop(key)) 77711023Sjthestness@gmail.com elif elseVal: 77811023Sjthestness@gmail.com setattr(self, key, elseVal) 77911023Sjthestness@gmail.com else: 78011023Sjthestness@gmail.com raise TypeError, "No value set for %s" % key 78111023Sjthestness@gmail.com 78211023Sjthestness@gmail.com if len(args) == 0: 78311023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'ip') 78411023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'netmask') 78511023Sjthestness@gmail.com 78611023Sjthestness@gmail.com elif len(args) == 1: 78711023Sjthestness@gmail.com if kwargs: 78811023Sjthestness@gmail.com if not 'ip' in kwargs and not 'netmask' in kwargs: 78911023Sjthestness@gmail.com raise TypeError, "Invalid arguments" 79011023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'ip', args[0]) 79111023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'netmask', args[0]) 79211023Sjthestness@gmail.com elif isinstance(args[0], IpNetmask): 79311023Sjthestness@gmail.com self.ip = args[0].ip 79411023Sjthestness@gmail.com self.netmask = args[0].netmask 7959864Snilay@cs.wisc.edu else: 7969864Snilay@cs.wisc.edu (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 79711066Snilay@cs.wisc.edu 7989864Snilay@cs.wisc.edu elif len(args) == 2: 79910036SAli.Saidi@ARM.com self.ip = args[0] 80011066Snilay@cs.wisc.edu self.netmask = args[1] 80111023Sjthestness@gmail.com else: 8029864Snilay@cs.wisc.edu raise TypeError, "Too many arguments specified" 80311066Snilay@cs.wisc.edu 8049864Snilay@cs.wisc.edu if kwargs: 80511023Sjthestness@gmail.com raise TypeError, "Too many keywords: %s" % kwargs.keys() 80611023Sjthestness@gmail.com 80711023Sjthestness@gmail.com self.verify() 80811023Sjthestness@gmail.com 80911023Sjthestness@gmail.com def __str__(self): 81011023Sjthestness@gmail.com return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 81111023Sjthestness@gmail.com 81211023Sjthestness@gmail.com def __eq__(self, other): 81311023Sjthestness@gmail.com if isinstance(other, IpNetmask): 81411023Sjthestness@gmail.com return self.ip == other.ip and self.netmask == other.netmask 81511023Sjthestness@gmail.com elif isinstance(other, str): 81611023Sjthestness@gmail.com try: 81711023Sjthestness@gmail.com return (self.ip, self.netmask) == convert.toIpNetmask(other) 81811023Sjthestness@gmail.com except: 81911023Sjthestness@gmail.com return False 82011023Sjthestness@gmail.com else: 82111023Sjthestness@gmail.com return False 82211023Sjthestness@gmail.com 82311023Sjthestness@gmail.com def verify(self): 82411023Sjthestness@gmail.com self.verifyIp() 82511023Sjthestness@gmail.com if self.netmask < 0 or self.netmask > 32: 82611023Sjthestness@gmail.com raise TypeError, "invalid netmask %d" % netmask 82711023Sjthestness@gmail.com 82811023Sjthestness@gmail.com def getValue(self): 82911023Sjthestness@gmail.com from m5.internal.params import IpNetmask 83011023Sjthestness@gmail.com return IpNetmask(self.ip, self.netmask) 83111023Sjthestness@gmail.com 83211023Sjthestness@gmail.com# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 83311023Sjthestness@gmail.com# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 83411023Sjthestness@gmail.comclass IpWithPort(IpAddress): 83511023Sjthestness@gmail.com cxx_type = 'Net::IpWithPort' 83611023Sjthestness@gmail.com 83711023Sjthestness@gmail.com @classmethod 83811023Sjthestness@gmail.com def cxx_predecls(cls, code): 83911023Sjthestness@gmail.com code('#include "base/inet.hh"') 84011023Sjthestness@gmail.com 84111023Sjthestness@gmail.com @classmethod 84211023Sjthestness@gmail.com def swig_predecls(cls, code): 84311023Sjthestness@gmail.com code('%include "python/swig/inet.i"') 84411023Sjthestness@gmail.com 84511023Sjthestness@gmail.com def __init__(self, *args, **kwargs): 84611023Sjthestness@gmail.com def handle_kwarg(self, kwargs, key, elseVal = None): 84711023Sjthestness@gmail.com if key in kwargs: 84811023Sjthestness@gmail.com setattr(self, key, kwargs.pop(key)) 84911023Sjthestness@gmail.com elif elseVal: 85011023Sjthestness@gmail.com setattr(self, key, elseVal) 85111023Sjthestness@gmail.com else: 85211023Sjthestness@gmail.com raise TypeError, "No value set for %s" % key 85311023Sjthestness@gmail.com 85411023Sjthestness@gmail.com if len(args) == 0: 85511023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'ip') 85611023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'port') 85711023Sjthestness@gmail.com 85811023Sjthestness@gmail.com elif len(args) == 1: 85911023Sjthestness@gmail.com if kwargs: 86011023Sjthestness@gmail.com if not 'ip' in kwargs and not 'port' in kwargs: 86111023Sjthestness@gmail.com raise TypeError, "Invalid arguments" 86211023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'ip', args[0]) 86311023Sjthestness@gmail.com handle_kwarg(self, kwargs, 'port', args[0]) 86411023Sjthestness@gmail.com elif isinstance(args[0], IpWithPort): 86511023Sjthestness@gmail.com self.ip = args[0].ip 86611023Sjthestness@gmail.com self.port = args[0].port 86711023Sjthestness@gmail.com else: 86811023Sjthestness@gmail.com (self.ip, self.port) = convert.toIpWithPort(args[0]) 86911023Sjthestness@gmail.com 87011023Sjthestness@gmail.com elif len(args) == 2: 87111023Sjthestness@gmail.com self.ip = args[0] 87211023Sjthestness@gmail.com self.port = args[1] 87311023Sjthestness@gmail.com else: 87411023Sjthestness@gmail.com raise TypeError, "Too many arguments specified" 87511023Sjthestness@gmail.com 87611023Sjthestness@gmail.com if kwargs: 87711023Sjthestness@gmail.com raise TypeError, "Too many keywords: %s" % kwargs.keys() 87811023Sjthestness@gmail.com 87911023Sjthestness@gmail.com self.verify() 88011023Sjthestness@gmail.com 88111023Sjthestness@gmail.com def __str__(self): 88211023Sjthestness@gmail.com return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 88311023Sjthestness@gmail.com 88411023Sjthestness@gmail.com def __eq__(self, other): 88511023Sjthestness@gmail.com if isinstance(other, IpWithPort): 88611023Sjthestness@gmail.com return self.ip == other.ip and self.port == other.port 88711023Sjthestness@gmail.com elif isinstance(other, str): 88811023Sjthestness@gmail.com try: 88911023Sjthestness@gmail.com return (self.ip, self.port) == convert.toIpWithPort(other) 89011023Sjthestness@gmail.com except: 89111023Sjthestness@gmail.com return False 89211023Sjthestness@gmail.com else: 89311023Sjthestness@gmail.com return False 89411023Sjthestness@gmail.com 89511023Sjthestness@gmail.com def verify(self): 89611023Sjthestness@gmail.com self.verifyIp() 89711023Sjthestness@gmail.com if self.port < 0 or self.port > 0xffff: 89811023Sjthestness@gmail.com raise TypeError, "invalid port %d" % self.port 89911023Sjthestness@gmail.com 90011023Sjthestness@gmail.com def getValue(self): 90111023Sjthestness@gmail.com from m5.internal.params import IpWithPort 90211023Sjthestness@gmail.com return IpWithPort(self.ip, self.port) 90311023Sjthestness@gmail.com 90411023Sjthestness@gmail.comtime_formats = [ "%a %b %d %H:%M:%S %Z %Y", 90511023Sjthestness@gmail.com "%a %b %d %H:%M:%S %Z %Y", 90611023Sjthestness@gmail.com "%Y/%m/%d %H:%M:%S", 90711023Sjthestness@gmail.com "%Y/%m/%d %H:%M", 90811023Sjthestness@gmail.com "%Y/%m/%d", 90911023Sjthestness@gmail.com "%m/%d/%Y %H:%M:%S", 91011023Sjthestness@gmail.com "%m/%d/%Y %H:%M", 91111023Sjthestness@gmail.com "%m/%d/%Y", 91211023Sjthestness@gmail.com "%m/%d/%y %H:%M:%S", 91311023Sjthestness@gmail.com "%m/%d/%y %H:%M", 91411023Sjthestness@gmail.com "%m/%d/%y"] 91511023Sjthestness@gmail.com 91611023Sjthestness@gmail.com 91711023Sjthestness@gmail.comdef parse_time(value): 91811023Sjthestness@gmail.com from time import gmtime, strptime, struct_time, time 91911023Sjthestness@gmail.com from datetime import datetime, date 92011023Sjthestness@gmail.com 92111023Sjthestness@gmail.com if isinstance(value, struct_time): 92211023Sjthestness@gmail.com return value 92311023Sjthestness@gmail.com 92411023Sjthestness@gmail.com if isinstance(value, (int, long)): 9259864Snilay@cs.wisc.edu return gmtime(value) 9269864Snilay@cs.wisc.edu 92711066Snilay@cs.wisc.edu if isinstance(value, (datetime, date)): 9289864Snilay@cs.wisc.edu return value.timetuple() 92910036SAli.Saidi@ARM.com 93011066Snilay@cs.wisc.edu if isinstance(value, str): 93111023Sjthestness@gmail.com if value in ('Now', 'Today'): 9329864Snilay@cs.wisc.edu return time.gmtime(time.time()) 93311066Snilay@cs.wisc.edu 9349864Snilay@cs.wisc.edu for format in time_formats: 93511023Sjthestness@gmail.com try: 93611023Sjthestness@gmail.com return strptime(value, format) 93711023Sjthestness@gmail.com except ValueError: 93811023Sjthestness@gmail.com pass 93911023Sjthestness@gmail.com 94011023Sjthestness@gmail.com raise ValueError, "Could not parse '%s' as a time" % value 94111023Sjthestness@gmail.com 94211023Sjthestness@gmail.comclass Time(ParamValue): 94311023Sjthestness@gmail.com cxx_type = 'tm' 94411023Sjthestness@gmail.com 94511023Sjthestness@gmail.com @classmethod 94611023Sjthestness@gmail.com def cxx_predecls(cls, code): 94711023Sjthestness@gmail.com code('#include <time.h>') 94811023Sjthestness@gmail.com 94911023Sjthestness@gmail.com @classmethod 95011023Sjthestness@gmail.com def swig_predecls(cls, code): 95111023Sjthestness@gmail.com code('%include "python/swig/time.i"') 95211023Sjthestness@gmail.com 95311023Sjthestness@gmail.com def __init__(self, value): 95411023Sjthestness@gmail.com self.value = parse_time(value) 95511023Sjthestness@gmail.com 95611023Sjthestness@gmail.com def getValue(self): 95711023Sjthestness@gmail.com from m5.internal.params import tm 95811023Sjthestness@gmail.com 95911023Sjthestness@gmail.com c_time = tm() 96011023Sjthestness@gmail.com py_time = self.value 96111023Sjthestness@gmail.com 96211023Sjthestness@gmail.com # UNIX is years since 1900 96311023Sjthestness@gmail.com c_time.tm_year = py_time.tm_year - 1900; 96411023Sjthestness@gmail.com 96511023Sjthestness@gmail.com # Python starts at 1, UNIX starts at 0 96611023Sjthestness@gmail.com c_time.tm_mon = py_time.tm_mon - 1; 96711023Sjthestness@gmail.com c_time.tm_mday = py_time.tm_mday; 96811023Sjthestness@gmail.com c_time.tm_hour = py_time.tm_hour; 96911023Sjthestness@gmail.com c_time.tm_min = py_time.tm_min; 97011023Sjthestness@gmail.com c_time.tm_sec = py_time.tm_sec; 97111023Sjthestness@gmail.com 97211023Sjthestness@gmail.com # Python has 0 as Monday, UNIX is 0 as sunday 97311023Sjthestness@gmail.com c_time.tm_wday = py_time.tm_wday + 1 97411023Sjthestness@gmail.com if c_time.tm_wday > 6: 97511023Sjthestness@gmail.com c_time.tm_wday -= 7; 97611023Sjthestness@gmail.com 97711023Sjthestness@gmail.com # Python starts at 1, Unix starts at 0 97811023Sjthestness@gmail.com c_time.tm_yday = py_time.tm_yday - 1; 97911023Sjthestness@gmail.com 98011023Sjthestness@gmail.com return c_time 98111023Sjthestness@gmail.com 98211023Sjthestness@gmail.com def __str__(self): 98311023Sjthestness@gmail.com return time.asctime(self.value) 98411023Sjthestness@gmail.com 98511023Sjthestness@gmail.com def ini_str(self): 98611023Sjthestness@gmail.com return str(self) 98711023Sjthestness@gmail.com 98811023Sjthestness@gmail.com def get_config_as_dict(self): 98911023Sjthestness@gmail.com return str(self) 99011023Sjthestness@gmail.com 99111023Sjthestness@gmail.com# Enumerated types are a little more complex. The user specifies the 99211023Sjthestness@gmail.com# type as Enum(foo) where foo is either a list or dictionary of 99311023Sjthestness@gmail.com# alternatives (typically strings, but not necessarily so). (In the 99411023Sjthestness@gmail.com# long run, the integer value of the parameter will be the list index 99511023Sjthestness@gmail.com# or the corresponding dictionary value. For now, since we only check 99611023Sjthestness@gmail.com# that the alternative is valid and then spit it into a .ini file, 99711023Sjthestness@gmail.com# there's not much point in using the dictionary.) 99811023Sjthestness@gmail.com 99911023Sjthestness@gmail.com# What Enum() must do is generate a new type encapsulating the 100011023Sjthestness@gmail.com# provided list/dictionary so that specific values of the parameter 100111023Sjthestness@gmail.com# can be instances of that type. We define two hidden internal 100211023Sjthestness@gmail.com# classes (_ListEnum and _DictEnum) to serve as base classes, then 100311023Sjthestness@gmail.com# derive the new type from the appropriate base class on the fly. 100411023Sjthestness@gmail.com 100511023Sjthestness@gmail.comallEnums = {} 100611023Sjthestness@gmail.com# Metaclass for Enum types 100711023Sjthestness@gmail.comclass MetaEnum(MetaParamValue): 100811023Sjthestness@gmail.com def __new__(mcls, name, bases, dict): 100911023Sjthestness@gmail.com assert name not in allEnums 101011023Sjthestness@gmail.com 101111023Sjthestness@gmail.com cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 101211023Sjthestness@gmail.com allEnums[name] = cls 101311023Sjthestness@gmail.com return cls 101411023Sjthestness@gmail.com 101511023Sjthestness@gmail.com def __init__(cls, name, bases, init_dict): 101611023Sjthestness@gmail.com if init_dict.has_key('map'): 101711023Sjthestness@gmail.com if not isinstance(cls.map, dict): 101811023Sjthestness@gmail.com raise TypeError, "Enum-derived class attribute 'map' " \ 101911023Sjthestness@gmail.com "must be of type dict" 102011023Sjthestness@gmail.com # build list of value strings from map 102111023Sjthestness@gmail.com cls.vals = cls.map.keys() 102211023Sjthestness@gmail.com cls.vals.sort() 102311023Sjthestness@gmail.com elif init_dict.has_key('vals'): 102411023Sjthestness@gmail.com if not isinstance(cls.vals, list): 102511023Sjthestness@gmail.com raise TypeError, "Enum-derived class attribute 'vals' " \ 102611023Sjthestness@gmail.com "must be of type list" 102711023Sjthestness@gmail.com # build string->value map from vals sequence 102811023Sjthestness@gmail.com cls.map = {} 102911023Sjthestness@gmail.com for idx,val in enumerate(cls.vals): 103011023Sjthestness@gmail.com cls.map[val] = idx 103111023Sjthestness@gmail.com else: 103211023Sjthestness@gmail.com raise TypeError, "Enum-derived class must define "\ 103311023Sjthestness@gmail.com "attribute 'map' or 'vals'" 103411023Sjthestness@gmail.com 103511023Sjthestness@gmail.com cls.cxx_type = 'Enums::%s' % name 103611023Sjthestness@gmail.com 103711023Sjthestness@gmail.com super(MetaEnum, cls).__init__(name, bases, init_dict) 103811023Sjthestness@gmail.com 103911023Sjthestness@gmail.com # Generate C++ class declaration for this enum type. 104011023Sjthestness@gmail.com # Note that we wrap the enum in a class/struct to act as a namespace, 104111023Sjthestness@gmail.com # so that the enum strings can be brief w/o worrying about collisions. 104211023Sjthestness@gmail.com def cxx_decl(cls, code): 104311023Sjthestness@gmail.com name = cls.__name__ 104411023Sjthestness@gmail.com code('''\ 104511023Sjthestness@gmail.com#ifndef __ENUM__${name}__ 104611023Sjthestness@gmail.com#define __ENUM__${name}__ 104711023Sjthestness@gmail.com 104811023Sjthestness@gmail.comnamespace Enums { 104911023Sjthestness@gmail.com enum $name { 105011023Sjthestness@gmail.com''') 105111023Sjthestness@gmail.com code.indent(2) 105211023Sjthestness@gmail.com for val in cls.vals: 105311023Sjthestness@gmail.com code('$val = ${{cls.map[val]}},') 105411023Sjthestness@gmail.com code('Num_$name = ${{len(cls.vals)}}') 105511023Sjthestness@gmail.com code.dedent(2) 105611023Sjthestness@gmail.com code('''\ 105711023Sjthestness@gmail.com }; 105811023Sjthestness@gmail.comextern const char *${name}Strings[Num_${name}]; 105911023Sjthestness@gmail.com} 106011023Sjthestness@gmail.com 106111023Sjthestness@gmail.com#endif // __ENUM__${name}__ 106211023Sjthestness@gmail.com''') 106311023Sjthestness@gmail.com 106411023Sjthestness@gmail.com def cxx_def(cls, code): 106511023Sjthestness@gmail.com name = cls.__name__ 106611023Sjthestness@gmail.com code('''\ 106711023Sjthestness@gmail.com#include "enums/$name.hh" 106811023Sjthestness@gmail.comnamespace Enums { 106911023Sjthestness@gmail.com const char *${name}Strings[Num_${name}] = 107011023Sjthestness@gmail.com { 107111023Sjthestness@gmail.com''') 107211023Sjthestness@gmail.com code.indent(2) 107311023Sjthestness@gmail.com for val in cls.vals: 107411023Sjthestness@gmail.com code('"$val",') 107511023Sjthestness@gmail.com code.dedent(2) 107611023Sjthestness@gmail.com code(''' 107711023Sjthestness@gmail.com }; 107811023Sjthestness@gmail.com} // namespace Enums 107911023Sjthestness@gmail.com''') 108011023Sjthestness@gmail.com 108111023Sjthestness@gmail.com def swig_decl(cls, code): 108211023Sjthestness@gmail.com name = cls.__name__ 108311023Sjthestness@gmail.com code('''\ 108411023Sjthestness@gmail.com%module(package="m5.internal") enum_$name 108511023Sjthestness@gmail.com 108611023Sjthestness@gmail.com%{ 108711023Sjthestness@gmail.com#include "enums/$name.hh" 108811023Sjthestness@gmail.com%} 108911023Sjthestness@gmail.com 109011023Sjthestness@gmail.com%include "enums/$name.hh" 109111023Sjthestness@gmail.com''') 109211023Sjthestness@gmail.com 109311023Sjthestness@gmail.com 109411023Sjthestness@gmail.com# Base class for enum types. 10958721SN/Aclass Enum(ParamValue): 10968721SN/A __metaclass__ = MetaEnum 10979864Snilay@cs.wisc.edu vals = [] 109810036SAli.Saidi@ARM.com 10998540SN/A def __init__(self, value): 11008983Snate@binkert.org if value not in self.map: 11018983Snate@binkert.org raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 11028983Snate@binkert.org % (value, self.vals) 11038721SN/A self.value = value 11048721SN/A 11058983Snate@binkert.org @classmethod 11066928SN/A def cxx_predecls(cls, code): 11079864Snilay@cs.wisc.edu code('#include "enums/$0.hh"', cls.__name__) 11089864Snilay@cs.wisc.edu 110910036SAli.Saidi@ARM.com @classmethod 11109864Snilay@cs.wisc.edu def swig_predecls(cls, code): 11119864Snilay@cs.wisc.edu code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1112 1113 def getValue(self): 1114 return int(self.map[self.value]) 1115 1116 def __str__(self): 1117 return self.value 1118 1119# how big does a rounding error need to be before we warn about it? 1120frequency_tolerance = 0.001 # 0.1% 1121 1122class TickParamValue(NumericParamValue): 1123 cxx_type = 'Tick' 1124 1125 @classmethod 1126 def cxx_predecls(cls, code): 1127 code('#include "base/types.hh"') 1128 1129 @classmethod 1130 def swig_predecls(cls, code): 1131 code('%import "stdint.i"') 1132 code('%import "base/types.hh"') 1133 1134 def getValue(self): 1135 return long(self.value) 1136 1137class Latency(TickParamValue): 1138 def __init__(self, value): 1139 if isinstance(value, (Latency, Clock)): 1140 self.ticks = value.ticks 1141 self.value = value.value 1142 elif isinstance(value, Frequency): 1143 self.ticks = value.ticks 1144 self.value = 1.0 / value.value 1145 elif value.endswith('t'): 1146 self.ticks = True 1147 self.value = int(value[:-1]) 1148 else: 1149 self.ticks = False 1150 self.value = convert.toLatency(value) 1151 1152 def __getattr__(self, attr): 1153 if attr in ('latency', 'period'): 1154 return self 1155 if attr == 'frequency': 1156 return Frequency(self) 1157 raise AttributeError, "Latency object has no attribute '%s'" % attr 1158 1159 def getValue(self): 1160 if self.ticks or self.value == 0: 1161 value = self.value 1162 else: 1163 value = ticks.fromSeconds(self.value) 1164 return long(value) 1165 1166 # convert latency to ticks 1167 def ini_str(self): 1168 return '%d' % self.getValue() 1169 1170class Frequency(TickParamValue): 1171 def __init__(self, value): 1172 if isinstance(value, (Latency, Clock)): 1173 if value.value == 0: 1174 self.value = 0 1175 else: 1176 self.value = 1.0 / value.value 1177 self.ticks = value.ticks 1178 elif isinstance(value, Frequency): 1179 self.value = value.value 1180 self.ticks = value.ticks 1181 else: 1182 self.ticks = False 1183 self.value = convert.toFrequency(value) 1184 1185 def __getattr__(self, attr): 1186 if attr == 'frequency': 1187 return self 1188 if attr in ('latency', 'period'): 1189 return Latency(self) 1190 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1191 1192 # convert latency to ticks 1193 def getValue(self): 1194 if self.ticks or self.value == 0: 1195 value = self.value 1196 else: 1197 value = ticks.fromSeconds(1.0 / self.value) 1198 return long(value) 1199 1200 def ini_str(self): 1201 return '%d' % self.getValue() 1202 1203# A generic Frequency and/or Latency value. Value is stored as a 1204# latency, just like Latency and Frequency. 1205class Clock(TickParamValue): 1206 def __init__(self, value): 1207 if isinstance(value, (Latency, Clock)): 1208 self.ticks = value.ticks 1209 self.value = value.value 1210 elif isinstance(value, Frequency): 1211 self.ticks = value.ticks 1212 self.value = 1.0 / value.value 1213 elif value.endswith('t'): 1214 self.ticks = True 1215 self.value = int(value[:-1]) 1216 else: 1217 self.ticks = False 1218 self.value = convert.anyToLatency(value) 1219 1220 def __getattr__(self, attr): 1221 if attr == 'frequency': 1222 return Frequency(self) 1223 if attr in ('latency', 'period'): 1224 return Latency(self) 1225 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1226 1227 def getValue(self): 1228 return self.period.getValue() 1229 1230 def ini_str(self): 1231 return self.period.ini_str() 1232 1233class Voltage(float,ParamValue): 1234 cxx_type = 'double' 1235 def __new__(cls, value): 1236 # convert to voltage 1237 val = convert.toVoltage(value) 1238 return super(cls, Voltage).__new__(cls, val) 1239 1240 def __str__(self): 1241 return str(self.val) 1242 1243 def getValue(self): 1244 value = float(self) 1245 return value 1246 1247 def ini_str(self): 1248 return '%f' % self.getValue() 1249 1250class NetworkBandwidth(float,ParamValue): 1251 cxx_type = 'float' 1252 def __new__(cls, value): 1253 # convert to bits per second 1254 val = convert.toNetworkBandwidth(value) 1255 return super(cls, NetworkBandwidth).__new__(cls, val) 1256 1257 def __str__(self): 1258 return str(self.val) 1259 1260 def getValue(self): 1261 # convert to seconds per byte 1262 value = 8.0 / float(self) 1263 # convert to ticks per byte 1264 value = ticks.fromSeconds(value) 1265 return float(value) 1266 1267 def ini_str(self): 1268 return '%f' % self.getValue() 1269 1270class MemoryBandwidth(float,ParamValue): 1271 cxx_type = 'float' 1272 def __new__(cls, value): 1273 # convert to bytes per second 1274 val = convert.toMemoryBandwidth(value) 1275 return super(cls, MemoryBandwidth).__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 = float(self) 1283 if value: 1284 value = 1.0 / float(self) 1285 # convert to ticks per byte 1286 value = ticks.fromSeconds(value) 1287 return float(value) 1288 1289 def ini_str(self): 1290 return '%f' % self.getValue() 1291 1292# 1293# "Constants"... handy aliases for various values. 1294# 1295 1296# Special class for NULL pointers. Note the special check in 1297# make_param_value() above that lets these be assigned where a 1298# SimObject is required. 1299# only one copy of a particular node 1300class NullSimObject(object): 1301 __metaclass__ = Singleton 1302 1303 def __call__(cls): 1304 return cls 1305 1306 def _instantiate(self, parent = None, path = ''): 1307 pass 1308 1309 def ini_str(self): 1310 return 'Null' 1311 1312 def unproxy(self, base): 1313 return self 1314 1315 def set_path(self, parent, name): 1316 pass 1317 1318 def __str__(self): 1319 return 'Null' 1320 1321 def getValue(self): 1322 return None 1323 1324# The only instance you'll ever need... 1325NULL = NullSimObject() 1326 1327def isNullPointer(value): 1328 return isinstance(value, NullSimObject) 1329 1330# Some memory range specifications use this as a default upper bound. 1331MaxAddr = Addr.max 1332MaxTick = Tick.max 1333AllMemory = AddrRange(0, MaxAddr) 1334 1335 1336##################################################################### 1337# 1338# Port objects 1339# 1340# Ports are used to interconnect objects in the memory system. 1341# 1342##################################################################### 1343 1344# Port reference: encapsulates a reference to a particular port on a 1345# particular SimObject. 1346class PortRef(object): 1347 def __init__(self, simobj, name, role): 1348 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1349 self.simobj = simobj 1350 self.name = name 1351 self.role = role 1352 self.peer = None # not associated with another port yet 1353 self.ccConnected = False # C++ port connection done? 1354 self.index = -1 # always -1 for non-vector ports 1355 1356 def __str__(self): 1357 return '%s.%s' % (self.simobj, self.name) 1358 1359 def __len__(self): 1360 # Return the number of connected ports, i.e. 0 is we have no 1361 # peer and 1 if we do. 1362 return int(self.peer != None) 1363 1364 # for config.ini, print peer's name (not ours) 1365 def ini_str(self): 1366 return str(self.peer) 1367 1368 # for config.json 1369 def get_config_as_dict(self): 1370 return {'role' : self.role, 'peer' : str(self.peer)} 1371 1372 def __getattr__(self, attr): 1373 if attr == 'peerObj': 1374 # shorthand for proxies 1375 return self.peer.simobj 1376 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1377 (self.__class__.__name__, attr) 1378 1379 # Full connection is symmetric (both ways). Called via 1380 # SimObject.__setattr__ as a result of a port assignment, e.g., 1381 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1382 # e.g., "obj1.portA[3] = obj2.portB". 1383 def connect(self, other): 1384 if isinstance(other, VectorPortRef): 1385 # reference to plain VectorPort is implicit append 1386 other = other._get_next() 1387 if self.peer and not proxy.isproxy(self.peer): 1388 fatal("Port %s is already connected to %s, cannot connect %s\n", 1389 self, self.peer, other); 1390 self.peer = other 1391 if proxy.isproxy(other): 1392 other.set_param_desc(PortParamDesc()) 1393 elif isinstance(other, PortRef): 1394 if other.peer is not self: 1395 other.connect(self) 1396 else: 1397 raise TypeError, \ 1398 "assigning non-port reference '%s' to port '%s'" \ 1399 % (other, self) 1400 1401 def clone(self, simobj, memo): 1402 if memo.has_key(self): 1403 return memo[self] 1404 newRef = copy.copy(self) 1405 memo[self] = newRef 1406 newRef.simobj = simobj 1407 assert(isSimObject(newRef.simobj)) 1408 if self.peer and not proxy.isproxy(self.peer): 1409 peerObj = self.peer.simobj(_memo=memo) 1410 newRef.peer = self.peer.clone(peerObj, memo) 1411 assert(not isinstance(newRef.peer, VectorPortRef)) 1412 return newRef 1413 1414 def unproxy(self, simobj): 1415 assert(simobj is self.simobj) 1416 if proxy.isproxy(self.peer): 1417 try: 1418 realPeer = self.peer.unproxy(self.simobj) 1419 except: 1420 print "Error in unproxying port '%s' of %s" % \ 1421 (self.name, self.simobj.path()) 1422 raise 1423 self.connect(realPeer) 1424 1425 # Call C++ to create corresponding port connection between C++ objects 1426 def ccConnect(self): 1427 from m5.internal.pyobject import connectPorts 1428 1429 if self.role == 'SLAVE': 1430 # do nothing and let the master take care of it 1431 return 1432 1433 if self.ccConnected: # already done this 1434 return 1435 peer = self.peer 1436 if not self.peer: # nothing to connect to 1437 return 1438 1439 # check that we connect a master to a slave 1440 if self.role == peer.role: 1441 raise TypeError, \ 1442 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1443 % (peer, self, self.role) 1444 1445 try: 1446 # self is always the master and peer the slave 1447 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1448 peer.simobj.getCCObject(), peer.name, peer.index) 1449 except: 1450 print "Error connecting port %s.%s to %s.%s" % \ 1451 (self.simobj.path(), self.name, 1452 peer.simobj.path(), peer.name) 1453 raise 1454 self.ccConnected = True 1455 peer.ccConnected = True 1456 1457# A reference to an individual element of a VectorPort... much like a 1458# PortRef, but has an index. 1459class VectorPortElementRef(PortRef): 1460 def __init__(self, simobj, name, role, index): 1461 PortRef.__init__(self, simobj, name, role) 1462 self.index = index 1463 1464 def __str__(self): 1465 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1466 1467# A reference to a complete vector-valued port (not just a single element). 1468# Can be indexed to retrieve individual VectorPortElementRef instances. 1469class VectorPortRef(object): 1470 def __init__(self, simobj, name, role): 1471 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1472 self.simobj = simobj 1473 self.name = name 1474 self.role = role 1475 self.elements = [] 1476 1477 def __str__(self): 1478 return '%s.%s[:]' % (self.simobj, self.name) 1479 1480 def __len__(self): 1481 # Return the number of connected peers, corresponding the the 1482 # length of the elements. 1483 return len(self.elements) 1484 1485 # for config.ini, print peer's name (not ours) 1486 def ini_str(self): 1487 return ' '.join([el.ini_str() for el in self.elements]) 1488 1489 # for config.json 1490 def get_config_as_dict(self): 1491 return {'role' : self.role, 1492 'peer' : [el.ini_str() for el in self.elements]} 1493 1494 def __getitem__(self, key): 1495 if not isinstance(key, int): 1496 raise TypeError, "VectorPort index must be integer" 1497 if key >= len(self.elements): 1498 # need to extend list 1499 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1500 for i in range(len(self.elements), key+1)] 1501 self.elements.extend(ext) 1502 return self.elements[key] 1503 1504 def _get_next(self): 1505 return self[len(self.elements)] 1506 1507 def __setitem__(self, key, value): 1508 if not isinstance(key, int): 1509 raise TypeError, "VectorPort index must be integer" 1510 self[key].connect(value) 1511 1512 def connect(self, other): 1513 if isinstance(other, (list, tuple)): 1514 # Assign list of port refs to vector port. 1515 # For now, append them... not sure if that's the right semantics 1516 # or if it should replace the current vector. 1517 for ref in other: 1518 self._get_next().connect(ref) 1519 else: 1520 # scalar assignment to plain VectorPort is implicit append 1521 self._get_next().connect(other) 1522 1523 def clone(self, simobj, memo): 1524 if memo.has_key(self): 1525 return memo[self] 1526 newRef = copy.copy(self) 1527 memo[self] = newRef 1528 newRef.simobj = simobj 1529 assert(isSimObject(newRef.simobj)) 1530 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1531 return newRef 1532 1533 def unproxy(self, simobj): 1534 [el.unproxy(simobj) for el in self.elements] 1535 1536 def ccConnect(self): 1537 [el.ccConnect() for el in self.elements] 1538 1539# Port description object. Like a ParamDesc object, this represents a 1540# logical port in the SimObject class, not a particular port on a 1541# SimObject instance. The latter are represented by PortRef objects. 1542class Port(object): 1543 # Generate a PortRef for this port on the given SimObject with the 1544 # given name 1545 def makeRef(self, simobj): 1546 return PortRef(simobj, self.name, self.role) 1547 1548 # Connect an instance of this port (on the given SimObject with 1549 # the given name) with the port described by the supplied PortRef 1550 def connect(self, simobj, ref): 1551 self.makeRef(simobj).connect(ref) 1552 1553 # No need for any pre-declarations at the moment as we merely rely 1554 # on an unsigned int. 1555 def cxx_predecls(self, code): 1556 pass 1557 1558 # Declare an unsigned int with the same name as the port, that 1559 # will eventually hold the number of connected ports (and thus the 1560 # number of elements for a VectorPort). 1561 def cxx_decl(self, code): 1562 code('unsigned int port_${{self.name}}_connection_count;') 1563 1564class MasterPort(Port): 1565 # MasterPort("description") 1566 def __init__(self, *args): 1567 if len(args) == 1: 1568 self.desc = args[0] 1569 self.role = 'MASTER' 1570 else: 1571 raise TypeError, 'wrong number of arguments' 1572 1573class SlavePort(Port): 1574 # SlavePort("description") 1575 def __init__(self, *args): 1576 if len(args) == 1: 1577 self.desc = args[0] 1578 self.role = 'SLAVE' 1579 else: 1580 raise TypeError, 'wrong number of arguments' 1581 1582# VectorPort description object. Like Port, but represents a vector 1583# of connections (e.g., as on a Bus). 1584class VectorPort(Port): 1585 def __init__(self, *args): 1586 self.isVec = True 1587 1588 def makeRef(self, simobj): 1589 return VectorPortRef(simobj, self.name, self.role) 1590 1591class VectorMasterPort(VectorPort): 1592 # VectorMasterPort("description") 1593 def __init__(self, *args): 1594 if len(args) == 1: 1595 self.desc = args[0] 1596 self.role = 'MASTER' 1597 VectorPort.__init__(self, *args) 1598 else: 1599 raise TypeError, 'wrong number of arguments' 1600 1601class VectorSlavePort(VectorPort): 1602 # VectorSlavePort("description") 1603 def __init__(self, *args): 1604 if len(args) == 1: 1605 self.desc = args[0] 1606 self.role = 'SLAVE' 1607 VectorPort.__init__(self, *args) 1608 else: 1609 raise TypeError, 'wrong number of arguments' 1610 1611# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1612# proxy objects (via set_param_desc()) so that proxy error messages 1613# make sense. 1614class PortParamDesc(object): 1615 __metaclass__ = Singleton 1616 1617 ptype_str = 'Port' 1618 ptype = Port 1619 1620baseEnums = allEnums.copy() 1621baseParams = allParams.copy() 1622 1623def clear(): 1624 global allEnums, allParams 1625 1626 allEnums = baseEnums.copy() 1627 allParams = baseParams.copy() 1628 1629__all__ = ['Param', 'VectorParam', 1630 'Enum', 'Bool', 'String', 'Float', 1631 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1632 'Int32', 'UInt32', 'Int64', 'UInt64', 1633 'Counter', 'Addr', 'Tick', 'Percent', 1634 'TcpPort', 'UdpPort', 'EthernetAddr', 1635 'IpAddress', 'IpNetmask', 'IpWithPort', 1636 'MemorySize', 'MemorySize32', 1637 'Latency', 'Frequency', 'Clock', 'Voltage', 1638 'NetworkBandwidth', 'MemoryBandwidth', 1639 'AddrRange', 1640 'MaxAddr', 'MaxTick', 'AllMemory', 1641 'Time', 1642 'NextEthernetAddr', 'NULL', 1643 'MasterPort', 'SlavePort', 1644 'VectorMasterPort', 'VectorSlavePort'] 1645 1646import SimObject 1647