params.py revision 9941
12740SN/A# Copyright (c) 2012-2013 ARM Limited 21046SN/A# All rights reserved. 31046SN/A# 41046SN/A# The license below extends only to copyright in the software and shall 51046SN/A# not be construed as granting a license to any other intellectual 61046SN/A# property including but not limited to intellectual property relating 71046SN/A# to a hardware implementation of the functionality of the software 81046SN/A# licensed hereunder. You may use the software subject to the license 91046SN/A# terms below provided that you ensure that this notice is replicated 101046SN/A# unmodified and in its entirety in all distributions of the software, 111046SN/A# modified or unmodified, in source code or in binary form. 121046SN/A# 131046SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan 141046SN/A# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 151046SN/A# All rights reserved. 161046SN/A# 171046SN/A# Redistribution and use in source and binary forms, with or without 181046SN/A# modification, are permitted provided that the following conditions are 191046SN/A# met: redistributions of source code must retain the above copyright 201046SN/A# notice, this list of conditions and the following disclaimer; 211046SN/A# redistributions in binary form must reproduce the above copyright 221046SN/A# notice, this list of conditions and the following disclaimer in the 231046SN/A# documentation and/or other materials provided with the distribution; 241046SN/A# neither the name of the copyright holders nor the names of its 251046SN/A# contributors may be used to endorse or promote products derived from 262665SN/A# this software without specific prior written permission. 272665SN/A# 282665SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 291046SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305766Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315766Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 325766Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 331438SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344762Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354762Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 363102Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 371438SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 383102Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 393102Sstever@eecs.umich.edu# 403102Sstever@eecs.umich.edu# Authors: Steve Reinhardt 413102Sstever@eecs.umich.edu# Nathan Binkert 423102Sstever@eecs.umich.edu# Gabe Black 433102Sstever@eecs.umich.edu# Andreas Hansson 443102Sstever@eecs.umich.edu 453102Sstever@eecs.umich.edu##################################################################### 463102Sstever@eecs.umich.edu# 473102Sstever@eecs.umich.edu# Parameter description classes 483102Sstever@eecs.umich.edu# 493102Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either 503102Sstever@eecs.umich.edu# a Param or a VectorParam object. These objects contain the 513102Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default 523102Sstever@eecs.umich.edu# value (if any). The convert() method on these objects is used to 533102Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 543102Sstever@eecs.umich.edu# type. 553102Sstever@eecs.umich.edu# 563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute 573102Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in 583102Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used. 593102Sstever@eecs.umich.edu# 603102Sstever@eecs.umich.edu##################################################################### 613102Sstever@eecs.umich.edu 623102Sstever@eecs.umich.eduimport copy 633102Sstever@eecs.umich.eduimport datetime 643102Sstever@eecs.umich.eduimport re 653102Sstever@eecs.umich.eduimport sys 663102Sstever@eecs.umich.eduimport time 674762Snate@binkert.orgimport math 683102Sstever@eecs.umich.edu 691342SN/Aimport proxy 701342SN/Aimport ticks 711378SN/Afrom util import * 721342SN/A 731378SN/Adef isSimObject(*args, **kwargs): 74679SN/A return SimObject.isSimObject(*args, **kwargs) 75679SN/A 76679SN/Adef isSimObjectSequence(*args, **kwargs): 77679SN/A return SimObject.isSimObjectSequence(*args, **kwargs) 78679SN/A 79679SN/Adef isSimObjectClass(*args, **kwargs): 801692SN/A return SimObject.isSimObjectClass(*args, **kwargs) 81679SN/A 82679SN/AallParams = {} 83679SN/A 84679SN/Aclass MetaParamValue(type): 85679SN/A def __new__(mcls, name, bases, dct): 86679SN/A cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 87679SN/A assert name not in allParams 88679SN/A allParams[name] = cls 89679SN/A return cls 90679SN/A 91679SN/A 92679SN/A# Dummy base class to identify types that are legitimate for SimObject 93679SN/A# parameters. 94679SN/Aclass ParamValue(object): 951692SN/A __metaclass__ = MetaParamValue 96679SN/A 97679SN/A 98679SN/A # Generate the code needed as a prerequisite for declaring a C++ 99679SN/A # object of this type. Typically generates one or more #include 100679SN/A # statements. Used when declaring parameters of this type. 101679SN/A @classmethod 102679SN/A def cxx_predecls(cls, code): 103679SN/A pass 104679SN/A 105679SN/A # Generate the code needed as a prerequisite for including a 106679SN/A # reference to a C++ object of this type in a SWIG .i file. 107679SN/A # Typically generates one or more %import or %include statements. 108679SN/A @classmethod 109679SN/A def swig_predecls(cls, code): 110679SN/A pass 1112740SN/A 112679SN/A # default for printing to .ini file is regular string conversion. 113679SN/A # will be overridden in some cases 114679SN/A def ini_str(self): 1154762Snate@binkert.org return str(self) 1164762Snate@binkert.org 1174762Snate@binkert.org # allows us to blithely call unproxy() on things without checking 1182738SN/A # if they're really proxies or not 1192738SN/A def unproxy(self, base): 1202738SN/A return self 1212740SN/A 1222740SN/A# Regular parameter description. 1232740SN/Aclass ParamDesc(object): 1242740SN/A def __init__(self, ptype_str, ptype, *args, **kwargs): 1251692SN/A self.ptype_str = ptype_str 1261427SN/A # remember ptype only if it is provided 1271692SN/A if ptype != None: 1284762Snate@binkert.org self.ptype = ptype 1294762Snate@binkert.org 1304762Snate@binkert.org if args: 1314859Snate@binkert.org if len(args) == 1: 1324762Snate@binkert.org self.desc = args[0] 1331692SN/A elif len(args) == 2: 1341427SN/A self.default = args[0] 1354762Snate@binkert.org self.desc = args[1] 136679SN/A else: 137679SN/A raise TypeError, 'too many arguments' 138679SN/A 1392740SN/A if kwargs.has_key('desc'): 140679SN/A assert(not hasattr(self, 'desc')) 141679SN/A self.desc = kwargs['desc'] 1421310SN/A del kwargs['desc'] 1434762Snate@binkert.org 1444762Snate@binkert.org if kwargs.has_key('default'): 1452740SN/A assert(not hasattr(self, 'default')) 1462740SN/A self.default = kwargs['default'] 1472740SN/A del kwargs['default'] 1482740SN/A 1492740SN/A if kwargs: 1502740SN/A raise TypeError, 'extra unknown kwargs %s' % kwargs 1512740SN/A 1522740SN/A if not hasattr(self, 'desc'): 1532740SN/A raise TypeError, 'desc attribute missing' 1542740SN/A 1552740SN/A def __getattr__(self, attr): 1562740SN/A if attr == 'ptype': 1574762Snate@binkert.org ptype = SimObject.allClasses[self.ptype_str] 1584762Snate@binkert.org assert isSimObjectClass(ptype) 1592740SN/A self.ptype = ptype 1604762Snate@binkert.org return ptype 1614762Snate@binkert.org 1624762Snate@binkert.org raise AttributeError, "'%s' object has no attribute '%s'" % \ 1634762Snate@binkert.org (type(self).__name__, attr) 164679SN/A 1652711SN/A def convert(self, value): 166679SN/A if isinstance(value, proxy.BaseProxy): 1672711SN/A value.set_param_desc(self) 1682711SN/A return value 1691692SN/A if not hasattr(self, 'ptype') and isNullPointer(value): 1701310SN/A # deferred evaluation of SimObject; continue to defer if 1711427SN/A # we're just assigning a null pointer 1722740SN/A return value 1732740SN/A if isinstance(value, self.ptype): 1742740SN/A return value 1752740SN/A if isNullPointer(value) and isSimObjectClass(self.ptype): 1762740SN/A return value 1772740SN/A return self.ptype(value) 1782740SN/A 1793105Sstever@eecs.umich.edu def cxx_predecls(self, code): 1802740SN/A code('#include <cstddef>') 1811310SN/A self.ptype.cxx_predecls(code) 1821692SN/A 1831585SN/A def swig_predecls(self, code): 1841692SN/A self.ptype.swig_predecls(code) 1851692SN/A 1861692SN/A def cxx_decl(self, code): 1871692SN/A code('${{self.ptype.cxx_type}} ${{self.name}};') 1881692SN/A 1892740SN/A# Vector-valued parameter description. Just like ParamDesc, except 1902740SN/A# that the value is a vector (list) of the specified type instead of a 1912740SN/A# single value. 1922740SN/A 1931692SN/Aclass VectorParamValue(list): 1945610Snate@binkert.org __metaclass__ = MetaParamValue 1951692SN/A def __setattr__(self, attr, value): 1962740SN/A raise AttributeError, \ 1971692SN/A "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 1983105Sstever@eecs.umich.edu 1992740SN/A def ini_str(self): 2002712SN/A return ' '.join([v.ini_str() for v in self]) 2015610Snate@binkert.org 2025610Snate@binkert.org def getValue(self): 2031692SN/A 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): 2075610Snate@binkert.org return self[0].unproxy(base) 2084762Snate@binkert.org else: 2095610Snate@binkert.org return [v.unproxy(base) for v in self] 2105610Snate@binkert.org 2114762Snate@binkert.orgclass SimObjectVector(VectorParamValue): 2124762Snate@binkert.org # support clone operation 2134762Snate@binkert.org def __call__(self, **kwargs): 2145610Snate@binkert.org return SimObjectVector([v(**kwargs) for v in self]) 2155610Snate@binkert.org 2165610Snate@binkert.org def clear_parent(self, old_parent): 2175610Snate@binkert.org for v in self: 2185610Snate@binkert.org v.clear_parent(old_parent) 2194762Snate@binkert.org 2204762Snate@binkert.org def set_parent(self, parent, name): 2214762Snate@binkert.org if len(self) == 1: 2224762Snate@binkert.org self[0].set_parent(parent, name) 2234762Snate@binkert.org else: 2244762Snate@binkert.org width = int(math.ceil(math.log(len(self))/math.log(10))) 2254762Snate@binkert.org for i,v in enumerate(self): 2264762Snate@binkert.org v.set_parent(parent, "%s%0*d" % (name, width, i)) 2274859Snate@binkert.org 2284859Snate@binkert.org def has_parent(self): 2294859Snate@binkert.org return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 2302740SN/A 2312740SN/A # return 'cpu0 cpu1' etc. for print_ini() 2322740SN/A def get_name(self): 2332740SN/A return ' '.join([v._name for v in self]) 2342740SN/A 2352740SN/A # By iterating through the constituent members of the vector here 2362740SN/A # we can nicely handle iterating over all a SimObject's children 2372740SN/A # without having to provide lots of special functions on 2381527SN/A # SimObjectVector directly. 2392740SN/A def descendants(self): 2401585SN/A for v in self: 2411427SN/A for obj in v.descendants(): 2422738SN/A yield obj 2432738SN/A 2443105Sstever@eecs.umich.edu def get_config_as_dict(self): 2452738SN/A a = [] 2461427SN/A for v in self: 2471427SN/A a.append(v.get_config_as_dict()) 2481427SN/A return a 2491427SN/A 2501427SN/Aclass VectorParamDesc(ParamDesc): 2511427SN/A # Convert assigned value to appropriate type. If the RHS is not a 2521427SN/A # list or tuple, it generates a single-element list. 2531427SN/A def convert(self, value): 2541427SN/A if isinstance(value, (list, tuple)): 2551427SN/A # list: coerce each element into new list 2561427SN/A tmp_list = [ ParamDesc.convert(self, v) for v in value ] 2571427SN/A else: 2581427SN/A # singleton: coerce to a single-element list 2591427SN/A tmp_list = [ ParamDesc.convert(self, value) ] 2601427SN/A 2611427SN/A if isSimObjectSequence(tmp_list): 2623100SN/A return SimObjectVector(tmp_list) 2633100SN/A else: 2643100SN/A return VectorParamValue(tmp_list) 2653100SN/A 2663100SN/A def swig_module_name(self): 2673100SN/A return "%s_vector" % self.ptype_str 2683105Sstever@eecs.umich.edu 2693105Sstever@eecs.umich.edu def swig_predecls(self, code): 2703105Sstever@eecs.umich.edu code('%import "${{self.swig_module_name()}}.i"') 2713105Sstever@eecs.umich.edu 2723105Sstever@eecs.umich.edu def swig_decl(self, code): 2733105Sstever@eecs.umich.edu code('%module(package="m5.internal") ${{self.swig_module_name()}}') 2743105Sstever@eecs.umich.edu code('%{') 2753105Sstever@eecs.umich.edu self.ptype.cxx_predecls(code) 2763105Sstever@eecs.umich.edu code('%}') 2773105Sstever@eecs.umich.edu code() 2783105Sstever@eecs.umich.edu # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 2793105Sstever@eecs.umich.edu code('%include "std_container.i"') 2803105Sstever@eecs.umich.edu code() 2813105Sstever@eecs.umich.edu self.ptype.swig_predecls(code) 2823105Sstever@eecs.umich.edu code() 2833105Sstever@eecs.umich.edu code('%include "std_vector.i"') 2843105Sstever@eecs.umich.edu code() 2853105Sstever@eecs.umich.edu 2863105Sstever@eecs.umich.edu ptype = self.ptype_str 2873105Sstever@eecs.umich.edu cxx_type = self.ptype.cxx_type 2883105Sstever@eecs.umich.edu 2893105Sstever@eecs.umich.edu code('''\ 2903105Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type { 2913105Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 2923105Sstever@eecs.umich.edu if (SWIG_ConvertPtr($$input, (void **)&$$1, 2933105Sstever@eecs.umich.edu $$descriptor($cxx_type), 0) == -1) { 2943105Sstever@eecs.umich.edu return NULL; 2953105Sstever@eecs.umich.edu } 2963105Sstever@eecs.umich.edu } 2973105Sstever@eecs.umich.edu} 2981585SN/A 2991310SN/A%typemap(in) std::vector< $cxx_type >::value_type * { 3001310SN/A if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) { 3011310SN/A if (SWIG_ConvertPtr($$input, (void **)&$$1, 3021310SN/A $$descriptor($cxx_type *), 0) == -1) { 3031310SN/A return NULL; 3041310SN/A } 3051310SN/A } 3061310SN/A} 3071310SN/A''') 3081427SN/A 3091310SN/A code('%template(vector_$ptype) std::vector< $cxx_type >;') 3101310SN/A 3112738SN/A def cxx_predecls(self, code): 3123105Sstever@eecs.umich.edu code('#include <vector>') 3132738SN/A self.ptype.cxx_predecls(code) 3142738SN/A 3152740SN/A def cxx_decl(self, code): 3162740SN/A code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 3172740SN/A 3182740SN/Aclass ParamFactory(object): 3192740SN/A def __init__(self, param_desc_class, ptype_str = None): 3202740SN/A self.param_desc_class = param_desc_class 3212740SN/A self.ptype_str = ptype_str 3223105Sstever@eecs.umich.edu 3231310SN/A def __getattr__(self, attr): 3243105Sstever@eecs.umich.edu if self.ptype_str: 3253105Sstever@eecs.umich.edu attr = self.ptype_str + '.' + attr 3263105Sstever@eecs.umich.edu return ParamFactory(self.param_desc_class, attr) 3273105Sstever@eecs.umich.edu 3283105Sstever@eecs.umich.edu # E.g., Param.Int(5, "number of widgets") 3293105Sstever@eecs.umich.edu def __call__(self, *args, **kwargs): 3303105Sstever@eecs.umich.edu ptype = None 3313105Sstever@eecs.umich.edu try: 3323105Sstever@eecs.umich.edu ptype = allParams[self.ptype_str] 3332740SN/A except KeyError: 3343105Sstever@eecs.umich.edu # if name isn't defined yet, assume it's a SimObject, and 3353105Sstever@eecs.umich.edu # try to resolve it later 3363105Sstever@eecs.umich.edu pass 3373105Sstever@eecs.umich.edu return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 3383105Sstever@eecs.umich.edu 3391310SN/AParam = ParamFactory(ParamDesc) 3401585SN/AVectorParam = ParamFactory(VectorParamDesc) 3411692SN/A 3421692SN/A##################################################################### 3431585SN/A# 3441585SN/A# Parameter Types 3451585SN/A# 3461585SN/A# Though native Python types could be used to specify parameter types 3473100SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more 3483100SN/A# flexible to define our own set of types. This gives us more control 3493100SN/A# over how Python expressions are converted to values (via the 3503100SN/A# __init__() constructor) and how these values are printed out (via 3514762Snate@binkert.org# the __str__() conversion method). 3524762Snate@binkert.org# 3534762Snate@binkert.org##################################################################### 3543100SN/A 3553100SN/A# String-valued parameter. Just mixin the ParamValue class with the 3563100SN/A# built-in str class. 3573100SN/Aclass String(ParamValue,str): 3584762Snate@binkert.org cxx_type = 'std::string' 3593100SN/A 3603100SN/A @classmethod 3613100SN/A def cxx_predecls(self, code): 3623100SN/A code('#include <string>') 3633100SN/A 3643100SN/A @classmethod 3653100SN/A def swig_predecls(cls, code): 3663100SN/A code('%include "std_string.i"') 3674762Snate@binkert.org 3684762Snate@binkert.org def getValue(self): 3694762Snate@binkert.org return self 3704762Snate@binkert.org 3714762Snate@binkert.org# superclass for "numeric" parameter values, to emulate math 3724762Snate@binkert.org# operations in a type-safe way. e.g., a Latency times an int returns 3734762Snate@binkert.org# a new Latency object. 3744762Snate@binkert.orgclass NumericParamValue(ParamValue): 3754762Snate@binkert.org def __str__(self): 3764762Snate@binkert.org return str(self.value) 3774762Snate@binkert.org 3784762Snate@binkert.org def __float__(self): 3794762Snate@binkert.org return float(self.value) 3805610Snate@binkert.org 3815610Snate@binkert.org def __long__(self): 3824762Snate@binkert.org return long(self.value) 3834762Snate@binkert.org 3844762Snate@binkert.org def __int__(self): 3854762Snate@binkert.org return int(self.value) 3864762Snate@binkert.org 3874762Snate@binkert.org # hook for bounds checking 3885610Snate@binkert.org def _check(self): 3895488Snate@binkert.org return 3905488Snate@binkert.org 3915488Snate@binkert.org def __mul__(self, other): 3925488Snate@binkert.org newobj = self.__class__(self) 3935488Snate@binkert.org newobj.value *= other 3945488Snate@binkert.org newobj._check() 3955488Snate@binkert.org return newobj 3965488Snate@binkert.org 3975488Snate@binkert.org __rmul__ = __mul__ 3984762Snate@binkert.org 3995488Snate@binkert.org def __div__(self, other): 4004762Snate@binkert.org newobj = self.__class__(self) 4015610Snate@binkert.org newobj.value /= other 4024762Snate@binkert.org newobj._check() 4034762Snate@binkert.org return newobj 4044762Snate@binkert.org 4054762Snate@binkert.org def __sub__(self, other): 4064762Snate@binkert.org newobj = self.__class__(self) 4074762Snate@binkert.org newobj.value -= other 4084762Snate@binkert.org newobj._check() 4094762Snate@binkert.org return newobj 4104762Snate@binkert.org 4114762Snate@binkert.org# Metaclass for bounds-checked integer parameters. See CheckedInt. 4124762Snate@binkert.orgclass CheckedIntType(MetaParamValue): 4134762Snate@binkert.org def __init__(cls, name, bases, dict): 4144762Snate@binkert.org super(CheckedIntType, cls).__init__(name, bases, dict) 4154762Snate@binkert.org 4164762Snate@binkert.org # CheckedInt is an abstract base class, so we actually don't 4174762Snate@binkert.org # want to do any processing on it... the rest of this code is 4184762Snate@binkert.org # just for classes that derive from CheckedInt. 4194762Snate@binkert.org if name == 'CheckedInt': 4204762Snate@binkert.org return 4214762Snate@binkert.org 4224762Snate@binkert.org if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 4234762Snate@binkert.org if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 4244762Snate@binkert.org panic("CheckedInt subclass %s must define either\n" \ 4254762Snate@binkert.org " 'min' and 'max' or 'size' and 'unsigned'\n", 4264762Snate@binkert.org name); 4274762Snate@binkert.org if cls.unsigned: 4284762Snate@binkert.org cls.min = 0 4294762Snate@binkert.org cls.max = 2 ** cls.size - 1 4303100SN/A else: 4313100SN/A cls.min = -(2 ** (cls.size - 1)) 4323100SN/A cls.max = (2 ** (cls.size - 1)) - 1 4333100SN/A 4343100SN/A# Abstract superclass for bounds-checked integer parameters. This 4353100SN/A# class is subclassed to generate parameter classes with specific 4363100SN/A# bounds. Initialization of the min and max bounds is done in the 4373100SN/A# metaclass CheckedIntType.__init__. 4383100SN/Aclass CheckedInt(NumericParamValue): 4393100SN/A __metaclass__ = CheckedIntType 4403100SN/A 4415610Snate@binkert.org def _check(self): 4425610Snate@binkert.org if not self.min <= self.value <= self.max: 4433100SN/A raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 4444762Snate@binkert.org (self.min, self.value, self.max) 4454762Snate@binkert.org 4464762Snate@binkert.org def __init__(self, value): 4474762Snate@binkert.org if isinstance(value, str): 4483100SN/A self.value = convert.toInteger(value) 4494762Snate@binkert.org elif isinstance(value, (int, long, float, NumericParamValue)): 4503100SN/A self.value = long(value) 4513100SN/A else: 4523100SN/A raise TypeError, "Can't convert object of type %s to CheckedInt" \ 4533100SN/A % type(value).__name__ 4542740SN/A self._check() 455679SN/A 456679SN/A @classmethod 4571692SN/A def cxx_predecls(cls, code): 4581692SN/A # most derived types require this, so we just do it here once 459679SN/A code('#include "base/types.hh"') 4601692SN/A 4613100SN/A @classmethod 4624762Snate@binkert.org def swig_predecls(cls, code): 4633100SN/A # most derived types require this, so we just do it here once 4644859Snate@binkert.org code('%import "stdint.i"') 465679SN/A code('%import "base/types.hh"') 4662740SN/A 4672740SN/A def getValue(self): 4682740SN/A return long(self.value) 4692740SN/A 4702740SN/Aclass Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 4712740SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 4722740SN/A 4732740SN/Aclass Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 4742740SN/Aclass UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 4752740SN/Aclass Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 4762740SN/Aclass UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4772740SN/Aclass Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 4782740SN/Aclass UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 4792740SN/Aclass Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 4802740SN/Aclass UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 4812740SN/A 4822711SN/Aclass Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 4832740SN/Aclass Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 4842740SN/Aclass TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4852740SN/Aclass UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 4862711SN/A 4872740SN/Aclass Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 4882740SN/A 4892740SN/Aclass Cycles(CheckedInt): 4902740SN/A cxx_type = 'Cycles' 4914762Snate@binkert.org size = 64 4922740SN/A unsigned = True 4932712SN/A 4942711SN/A def getValue(self): 4952711SN/A from m5.internal.core import Cycles 4962740SN/A return Cycles(self.value) 4972740SN/A 4982740SN/Aclass Float(ParamValue, float): 4992740SN/A cxx_type = 'double' 5002740SN/A 5012740SN/A def __init__(self, value): 5022740SN/A if isinstance(value, (int, long, float, NumericParamValue, Float)): 5032740SN/A self.value = float(value) 5042740SN/A else: 5053105Sstever@eecs.umich.edu raise TypeError, "Can't convert object of type %s to Float" \ 5063105Sstever@eecs.umich.edu % type(value).__name__ 5073105Sstever@eecs.umich.edu 5081692SN/A def getValue(self): 5091692SN/A return float(self.value) 5101692SN/A 511679SN/Aclass MemorySize(CheckedInt): 5122740SN/A cxx_type = 'uint64_t' 5132740SN/A size = 64 5142740SN/A unsigned = True 5152740SN/A def __init__(self, value): 5162740SN/A if isinstance(value, MemorySize): 5171692SN/A self.value = value.value 5182740SN/A else: 5192740SN/A self.value = convert.toMemorySize(value) 5202740SN/A self._check() 5212740SN/A 5222740SN/Aclass MemorySize32(CheckedInt): 5232740SN/A cxx_type = 'uint32_t' 5242740SN/A size = 32 5252740SN/A unsigned = True 5262740SN/A def __init__(self, value): 5272740SN/A if isinstance(value, MemorySize): 5282740SN/A self.value = value.value 5292740SN/A else: 5302740SN/A self.value = convert.toMemorySize(value) 5312740SN/A self._check() 5322740SN/A 5331343SN/Aclass Addr(CheckedInt): 5343105Sstever@eecs.umich.edu cxx_type = 'Addr' 5353105Sstever@eecs.umich.edu size = 64 5363105Sstever@eecs.umich.edu unsigned = True 5373105Sstever@eecs.umich.edu def __init__(self, value): 5383105Sstever@eecs.umich.edu if isinstance(value, Addr): 5393105Sstever@eecs.umich.edu self.value = value.value 5403105Sstever@eecs.umich.edu else: 5413105Sstever@eecs.umich.edu try: 5423105Sstever@eecs.umich.edu self.value = convert.toMemorySize(value) 5433105Sstever@eecs.umich.edu except TypeError: 5441692SN/A self.value = long(value) 5452738SN/A self._check() 5463105Sstever@eecs.umich.edu def __add__(self, other): 5472738SN/A if isinstance(other, Addr): 5481692SN/A return self.value + other.value 5491692SN/A else: 5501427SN/A return self.value + other 5511692SN/A 5521692SN/Aclass AddrRange(ParamValue): 5531427SN/A cxx_type = 'AddrRange' 5541692SN/A 5551692SN/A def __init__(self, *args, **kwargs): 5561692SN/A # Disable interleaving by default 5571692SN/A self.intlvHighBit = 0 5581692SN/A self.intlvBits = 0 5591692SN/A self.intlvMatch = 0 5601692SN/A 5611427SN/A def handle_kwargs(self, kwargs): 5622738SN/A # An address range needs to have an upper limit, specified 5632738SN/A # either explicitly with an end, or as an offset using the 5643105Sstever@eecs.umich.edu # size keyword. 5652738SN/A if 'end' in kwargs: 5662738SN/A self.end = Addr(kwargs.pop('end')) 5672740SN/A elif 'size' in kwargs: 5682740SN/A self.end = self.start + Addr(kwargs.pop('size')) - 1 5692740SN/A else: 5702740SN/A raise TypeError, "Either end or size must be specified" 5712740SN/A 5721692SN/A # Now on to the optional bit 5733105Sstever@eecs.umich.edu if 'intlvHighBit' in kwargs: 5741692SN/A self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 5751310SN/A if 'intlvBits' in kwargs: 5761692SN/A self.intlvBits = int(kwargs.pop('intlvBits')) 5771587SN/A if 'intlvMatch' in kwargs: 5781692SN/A self.intlvMatch = int(kwargs.pop('intlvMatch')) 5791692SN/A 5801605SN/A if len(args) == 0: 5811605SN/A self.start = Addr(kwargs.pop('start')) 5823105Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 5833105Sstever@eecs.umich.edu 5841310SN/A elif len(args) == 1: 5853105Sstever@eecs.umich.edu if kwargs: 5863105Sstever@eecs.umich.edu self.start = Addr(args[0]) 5873105Sstever@eecs.umich.edu handle_kwargs(self, kwargs) 5881693SN/A elif isinstance(args[0], (list, tuple)): 5893105Sstever@eecs.umich.edu self.start = Addr(args[0][0]) 5903105Sstever@eecs.umich.edu self.end = Addr(args[0][1]) 5913105Sstever@eecs.umich.edu else: 5921310SN/A self.start = Addr(0) 5931310SN/A self.end = Addr(args[0]) - 1 5941692SN/A 5951692SN/A elif len(args) == 2: 5961692SN/A self.start = Addr(args[0]) 5971692SN/A self.end = Addr(args[1]) 5981692SN/A else: 5991692SN/A raise TypeError, "Too many arguments specified" 6001310SN/A 6011693SN/A if kwargs: 6021693SN/A raise TypeError, "Too many keywords: %s" % kwargs.keys() 6031693SN/A 6041693SN/A def __str__(self): 6051693SN/A return '%s:%s' % (self.start, self.end) 6061693SN/A 6071693SN/A def size(self): 6081693SN/A # Divide the size by the size of the interleaving slice 6091693SN/A return (long(self.end) - long(self.start) + 1) >> self.intlvBits 6101693SN/A 6111692SN/A @classmethod 6121692SN/A def cxx_predecls(cls, code): 6131310SN/A Addr.cxx_predecls(code) 6143105Sstever@eecs.umich.edu code('#include "base/addr_range.hh"') 6152740SN/A 6161692SN/A @classmethod 6171692SN/A def swig_predecls(cls, code): 6181692SN/A Addr.swig_predecls(code) 6191310SN/A 6203105Sstever@eecs.umich.edu def getValue(self): 6213105Sstever@eecs.umich.edu # Go from the Python class to the wrapped C++ class generated 6223105Sstever@eecs.umich.edu # by swig 6233105Sstever@eecs.umich.edu from m5.internal.range import AddrRange 6243105Sstever@eecs.umich.edu 6253105Sstever@eecs.umich.edu return AddrRange(long(self.start), long(self.end), 6263105Sstever@eecs.umich.edu int(self.intlvHighBit), int(self.intlvBits), 6273105Sstever@eecs.umich.edu int(self.intlvMatch)) 6283105Sstever@eecs.umich.edu 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. 6325766Snate@binkert.orgclass Bool(ParamValue): 6334762Snate@binkert.org cxx_type = 'bool' 6345766Snate@binkert.org def __init__(self, value): 6353105Sstever@eecs.umich.edu try: 6363105Sstever@eecs.umich.edu self.value = convert.toBool(value) 6373105Sstever@eecs.umich.edu except TypeError: 6381692SN/A self.value = bool(value) 6392740SN/A 6401692SN/A def getValue(self): 6411692SN/A return bool(self.value) 6421692SN/A 6431692SN/A def __str__(self): 6441692SN/A return str(self.value) 6451310SN/A 6461692SN/A # implement truth value testing for Bool parameters so that these params 6471692SN/A # evaluate correctly during the python configuration phase 6481310SN/A def __nonzero__(self): 6491692SN/A return bool(self.value) 6501692SN/A 6511310SN/A def ini_str(self): 6521692SN/A if self.value: 6531692SN/A return 'true' 6541692SN/A return 'false' 6551310SN/A 6561692SN/Adef IncEthernetAddr(addr, val = 1): 6571692SN/A bytes = map(lambda x: int(x, 16), addr.split(':')) 6581692SN/A bytes[5] += val 6591692SN/A for i in (5, 4, 3, 2, 1): 6601692SN/A val,rem = divmod(bytes[i], 256) 6611692SN/A bytes[i] = rem 6621814SN/A if val == 0: 6631692SN/A break 6641692SN/A bytes[i - 1] += val 6651692SN/A assert(bytes[0] <= 255) 6661692SN/A return ':'.join(map(lambda x: '%02x' % x, bytes)) 6671692SN/A 6681692SN/A_NextEthernetAddr = "00:90:00:00:00:01" 6691692SN/Adef NextEthernetAddr(): 6701692SN/A global _NextEthernetAddr 6711692SN/A 6721692SN/A value = _NextEthernetAddr 6731692SN/A _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 6741815SN/A return value 6751815SN/A 6761815SN/Aclass EthernetAddr(ParamValue): 6773105Sstever@eecs.umich.edu cxx_type = 'Net::EthAddr' 6783105Sstever@eecs.umich.edu 6793105Sstever@eecs.umich.edu @classmethod 6803105Sstever@eecs.umich.edu def cxx_predecls(cls, code): 6813105Sstever@eecs.umich.edu code('#include "base/inet.hh"') 6823105Sstever@eecs.umich.edu 6833105Sstever@eecs.umich.edu @classmethod 6843105Sstever@eecs.umich.edu def swig_predecls(cls, code): 6853105Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 6863105Sstever@eecs.umich.edu 6873105Sstever@eecs.umich.edu def __init__(self, value): 6883105Sstever@eecs.umich.edu if value == NextEthernetAddr: 6893107Sstever@eecs.umich.edu self.value = value 6903107Sstever@eecs.umich.edu return 6913107Sstever@eecs.umich.edu 6923107Sstever@eecs.umich.edu if not isinstance(value, str): 6933107Sstever@eecs.umich.edu raise TypeError, "expected an ethernet address and didn't get one" 6943105Sstever@eecs.umich.edu 6953105Sstever@eecs.umich.edu bytes = value.split(':') 6963105Sstever@eecs.umich.edu if len(bytes) != 6: 6973105Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 6983107Sstever@eecs.umich.edu 6993107Sstever@eecs.umich.edu for byte in bytes: 7003107Sstever@eecs.umich.edu if not 0 <= int(byte, base=16) <= 0xff: 7013107Sstever@eecs.umich.edu raise TypeError, 'invalid ethernet address %s' % value 7023107Sstever@eecs.umich.edu 7033105Sstever@eecs.umich.edu self.value = value 7045037Smilesck@eecs.umich.edu 7055543Ssaidi@eecs.umich.edu def unproxy(self, base): 7061692SN/A if self.value == NextEthernetAddr: 7072738SN/A return EthernetAddr(self.value()) 7082738SN/A return self 7094081Sbinkertn@umich.edu 7105037Smilesck@eecs.umich.edu def getValue(self): 7111692SN/A from m5.internal.params import EthAddr 7121692SN/A return EthAddr(self.value) 7131692SN/A 7144081Sbinkertn@umich.edu def ini_str(self): 7155037Smilesck@eecs.umich.edu return self.value 7161692SN/A 7171692SN/A# When initializing an IpAddress, pass in an existing IpAddress, a string of 7181692SN/A# the form "a.b.c.d", or an integer representing an IP. 7191692SN/Aclass IpAddress(ParamValue): 7203105Sstever@eecs.umich.edu cxx_type = 'Net::IpAddress' 7211692SN/A 7225037Smilesck@eecs.umich.edu @classmethod 7235037Smilesck@eecs.umich.edu def cxx_predecls(cls, code): 7241692SN/A code('#include "base/inet.hh"') 7253103Sstever@eecs.umich.edu 7263103Sstever@eecs.umich.edu @classmethod 7273103Sstever@eecs.umich.edu def swig_predecls(cls, code): 7283105Sstever@eecs.umich.edu code('%include "python/swig/inet.i"') 7293105Sstever@eecs.umich.edu 7305037Smilesck@eecs.umich.edu def __init__(self, value): 7313103Sstever@eecs.umich.edu if isinstance(value, IpAddress): 7325543Ssaidi@eecs.umich.edu self.ip = value.ip 7331692SN/A else: 7341692SN/A try: 7355037Smilesck@eecs.umich.edu self.ip = convert.toIpAddress(value) 7361692SN/A except TypeError: 7374762Snate@binkert.org self.ip = long(value) 7384762Snate@binkert.org self.verifyIp() 7394762Snate@binkert.org 7404762Snate@binkert.org def __str__(self): 7415033Smilesck@eecs.umich.edu tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 7424762Snate@binkert.org return '%d.%d.%d.%d' % tuple(tup) 7435488Snate@binkert.org 7444762Snate@binkert.org 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): 7484762Snate@binkert.org try: 7494762Snate@binkert.org return self.ip == convert.toIpAddress(other) 7504762Snate@binkert.org except: 7514762Snate@binkert.org return False 7524762Snate@binkert.org else: 7534762Snate@binkert.org return self.ip == other 7544762Snate@binkert.org 7554762Snate@binkert.org def __ne__(self, other): 7564762Snate@binkert.org return not (self == other) 7574762Snate@binkert.org 7584762Snate@binkert.org def verifyIp(self): 7594762Snate@binkert.org 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): 7634762Snate@binkert.org from m5.internal.params import IpAddress 7644762Snate@binkert.org return IpAddress(self.ip) 7654762Snate@binkert.org 7664762Snate@binkert.org# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 7674762Snate@binkert.org# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 7684762Snate@binkert.org# positional or keyword arguments. 7694762Snate@binkert.orgclass IpNetmask(IpAddress): 7704762Snate@binkert.org cxx_type = 'Net::IpNetmask' 7712738SN/A 7722740SN/A @classmethod 7732740SN/A def cxx_predecls(cls, code): 7742740SN/A code('#include "base/inet.hh"') 7752740SN/A 7762740SN/A @classmethod 7775244Sgblack@eecs.umich.edu def swig_predecls(cls, code): 7785244Sgblack@eecs.umich.edu code('%include "python/swig/inet.i"') 7795244Sgblack@eecs.umich.edu 7805244Sgblack@eecs.umich.edu def __init__(self, *args, **kwargs): 7814762Snate@binkert.org def handle_kwarg(self, kwargs, key, elseVal = None): 7822740SN/A if key in kwargs: 7835244Sgblack@eecs.umich.edu setattr(self, key, kwargs.pop(key)) 7842740SN/A elif elseVal: 7852740SN/A setattr(self, key, elseVal) 7862740SN/A 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') 7924762Snate@binkert.org 7934762Snate@binkert.org elif len(args) == 1: 7944762Snate@binkert.org if kwargs: 7954762Snate@binkert.org if not 'ip' in kwargs and not 'netmask' in kwargs: 7964762Snate@binkert.org raise TypeError, "Invalid arguments" 7974762Snate@binkert.org handle_kwarg(self, kwargs, 'ip', args[0]) 7982738SN/A handle_kwarg(self, kwargs, 'netmask', args[0]) 7993105Sstever@eecs.umich.edu elif isinstance(args[0], IpNetmask): 8002738SN/A self.ip = args[0].ip 8013105Sstever@eecs.umich.edu self.netmask = args[0].netmask 8023105Sstever@eecs.umich.edu else: 8032738SN/A (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 8042738SN/A 8052738SN/A elif len(args) == 2: 8062839SN/A self.ip = args[0] 8072797SN/A self.netmask = args[1] 8084081Sbinkertn@umich.edu else: 8092901SN/A raise TypeError, "Too many arguments specified" 8102797SN/A 8112797SN/A if kwargs: 8122839SN/A raise TypeError, "Too many keywords: %s" % kwargs.keys() 8132797SN/A 8142797SN/A self.verify() 8152797SN/A 8164081Sbinkertn@umich.edu def __str__(self): 8172797SN/A return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 8182797SN/A 8192797SN/A def __eq__(self, other): 8202797SN/A if isinstance(other, IpNetmask): 8214553Sbinkertn@umich.edu return self.ip == other.ip and self.netmask == other.netmask 8224553Sbinkertn@umich.edu elif isinstance(other, str): 8234553Sbinkertn@umich.edu try: 8244553Sbinkertn@umich.edu return (self.ip, self.netmask) == convert.toIpNetmask(other) 8254859Snate@binkert.org except: 8264553Sbinkertn@umich.edu return False 8272797SN/A else: 8283202Shsul@eecs.umich.edu return False 8293202Shsul@eecs.umich.edu 8303202Shsul@eecs.umich.edu def verify(self): 8313202Shsul@eecs.umich.edu self.verifyIp() 8324859Snate@binkert.org if self.netmask < 0 or self.netmask > 32: 8332797SN/A raise TypeError, "invalid netmask %d" % netmask 8342797SN/A 8352797SN/A def getValue(self): 8362797SN/A from m5.internal.params import IpNetmask 8374859Snate@binkert.org return IpNetmask(self.ip, self.netmask) 8382797SN/A 8391692SN/A# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 8401692SN/A# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 8411342SN/Aclass IpWithPort(IpAddress): 8421342SN/A cxx_type = 'Net::IpWithPort' 8431342SN/A 8441342SN/A @classmethod 8451342SN/A def cxx_predecls(cls, code): 8461342SN/A code('#include "base/inet.hh"') 8471342SN/A 8481342SN/A @classmethod 8491342SN/A def swig_predecls(cls, code): 8501342SN/A code('%include "python/swig/inet.i"') 8511342SN/A 8521342SN/A def __init__(self, *args, **kwargs): 8531342SN/A def handle_kwarg(self, kwargs, key, elseVal = None): 8541342SN/A if key in kwargs: 8551342SN/A setattr(self, key, kwargs.pop(key)) 8561342SN/A elif elseVal: 8571342SN/A setattr(self, key, elseVal) 8581342SN/A else: 8591692SN/A raise TypeError, "No value set for %s" % key 8601342SN/A 8611587SN/A if len(args) == 0: 8621605SN/A handle_kwarg(self, kwargs, 'ip') 8631605SN/A handle_kwarg(self, kwargs, 'port') 8641342SN/A 8651605SN/A elif len(args) == 1: 8661692SN/A if kwargs: 8671342SN/A if not 'ip' in kwargs and not 'port' in kwargs: 8681342SN/A raise TypeError, "Invalid arguments" 8691342SN/A handle_kwarg(self, kwargs, 'ip', args[0]) 8701342SN/A handle_kwarg(self, kwargs, 'port', args[0]) 8711342SN/A elif isinstance(args[0], IpWithPort): 8721342SN/A self.ip = args[0].ip 8731587SN/A self.port = args[0].port 8741587SN/A else: 8751342SN/A (self.ip, self.port) = convert.toIpWithPort(args[0]) 8761342SN/A 8771342SN/A elif len(args) == 2: 8781342SN/A self.ip = args[0] 8791342SN/A self.port = args[1] 8801342SN/A else: 8811342SN/A raise TypeError, "Too many arguments specified" 8823101Sstever@eecs.umich.edu 8833101Sstever@eecs.umich.edu if kwargs: 8843101Sstever@eecs.umich.edu raise TypeError, "Too many keywords: %s" % kwargs.keys() 8853101Sstever@eecs.umich.edu 886679SN/A self.verify() 8871528SN/A 8881528SN/A def __str__(self): 8891528SN/A return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 8904762Snate@binkert.org 891 def __eq__(self, other): 892 if isinstance(other, IpWithPort): 893 return self.ip == other.ip and self.port == other.port 894 elif isinstance(other, str): 895 try: 896 return (self.ip, self.port) == convert.toIpWithPort(other) 897 except: 898 return False 899 else: 900 return False 901 902 def verify(self): 903 self.verifyIp() 904 if self.port < 0 or self.port > 0xffff: 905 raise TypeError, "invalid port %d" % self.port 906 907 def getValue(self): 908 from m5.internal.params import IpWithPort 909 return IpWithPort(self.ip, self.port) 910 911time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 912 "%a %b %d %H:%M:%S %Z %Y", 913 "%Y/%m/%d %H:%M:%S", 914 "%Y/%m/%d %H:%M", 915 "%Y/%m/%d", 916 "%m/%d/%Y %H:%M:%S", 917 "%m/%d/%Y %H:%M", 918 "%m/%d/%Y", 919 "%m/%d/%y %H:%M:%S", 920 "%m/%d/%y %H:%M", 921 "%m/%d/%y"] 922 923 924def parse_time(value): 925 from time import gmtime, strptime, struct_time, time 926 from datetime import datetime, date 927 928 if isinstance(value, struct_time): 929 return value 930 931 if isinstance(value, (int, long)): 932 return gmtime(value) 933 934 if isinstance(value, (datetime, date)): 935 return value.timetuple() 936 937 if isinstance(value, str): 938 if value in ('Now', 'Today'): 939 return time.gmtime(time.time()) 940 941 for format in time_formats: 942 try: 943 return strptime(value, format) 944 except ValueError: 945 pass 946 947 raise ValueError, "Could not parse '%s' as a time" % value 948 949class Time(ParamValue): 950 cxx_type = 'tm' 951 952 @classmethod 953 def cxx_predecls(cls, code): 954 code('#include <time.h>') 955 956 @classmethod 957 def swig_predecls(cls, code): 958 code('%include "python/swig/time.i"') 959 960 def __init__(self, value): 961 self.value = parse_time(value) 962 963 def getValue(self): 964 from m5.internal.params import tm 965 966 c_time = tm() 967 py_time = self.value 968 969 # UNIX is years since 1900 970 c_time.tm_year = py_time.tm_year - 1900; 971 972 # Python starts at 1, UNIX starts at 0 973 c_time.tm_mon = py_time.tm_mon - 1; 974 c_time.tm_mday = py_time.tm_mday; 975 c_time.tm_hour = py_time.tm_hour; 976 c_time.tm_min = py_time.tm_min; 977 c_time.tm_sec = py_time.tm_sec; 978 979 # Python has 0 as Monday, UNIX is 0 as sunday 980 c_time.tm_wday = py_time.tm_wday + 1 981 if c_time.tm_wday > 6: 982 c_time.tm_wday -= 7; 983 984 # Python starts at 1, Unix starts at 0 985 c_time.tm_yday = py_time.tm_yday - 1; 986 987 return c_time 988 989 def __str__(self): 990 return time.asctime(self.value) 991 992 def ini_str(self): 993 return str(self) 994 995 def get_config_as_dict(self): 996 return str(self) 997 998# Enumerated types are a little more complex. The user specifies the 999# type as Enum(foo) where foo is either a list or dictionary of 1000# alternatives (typically strings, but not necessarily so). (In the 1001# long run, the integer value of the parameter will be the list index 1002# or the corresponding dictionary value. For now, since we only check 1003# that the alternative is valid and then spit it into a .ini file, 1004# there's not much point in using the dictionary.) 1005 1006# What Enum() must do is generate a new type encapsulating the 1007# provided list/dictionary so that specific values of the parameter 1008# can be instances of that type. We define two hidden internal 1009# classes (_ListEnum and _DictEnum) to serve as base classes, then 1010# derive the new type from the appropriate base class on the fly. 1011 1012allEnums = {} 1013# Metaclass for Enum types 1014class MetaEnum(MetaParamValue): 1015 def __new__(mcls, name, bases, dict): 1016 assert name not in allEnums 1017 1018 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1019 allEnums[name] = cls 1020 return cls 1021 1022 def __init__(cls, name, bases, init_dict): 1023 if init_dict.has_key('map'): 1024 if not isinstance(cls.map, dict): 1025 raise TypeError, "Enum-derived class attribute 'map' " \ 1026 "must be of type dict" 1027 # build list of value strings from map 1028 cls.vals = cls.map.keys() 1029 cls.vals.sort() 1030 elif init_dict.has_key('vals'): 1031 if not isinstance(cls.vals, list): 1032 raise TypeError, "Enum-derived class attribute 'vals' " \ 1033 "must be of type list" 1034 # build string->value map from vals sequence 1035 cls.map = {} 1036 for idx,val in enumerate(cls.vals): 1037 cls.map[val] = idx 1038 else: 1039 raise TypeError, "Enum-derived class must define "\ 1040 "attribute 'map' or 'vals'" 1041 1042 cls.cxx_type = 'Enums::%s' % name 1043 1044 super(MetaEnum, cls).__init__(name, bases, init_dict) 1045 1046 # Generate C++ class declaration for this enum type. 1047 # Note that we wrap the enum in a class/struct to act as a namespace, 1048 # so that the enum strings can be brief w/o worrying about collisions. 1049 def cxx_decl(cls, code): 1050 name = cls.__name__ 1051 code('''\ 1052#ifndef __ENUM__${name}__ 1053#define __ENUM__${name}__ 1054 1055namespace Enums { 1056 enum $name { 1057''') 1058 code.indent(2) 1059 for val in cls.vals: 1060 code('$val = ${{cls.map[val]}},') 1061 code('Num_$name = ${{len(cls.vals)}}') 1062 code.dedent(2) 1063 code('''\ 1064 }; 1065extern const char *${name}Strings[Num_${name}]; 1066} 1067 1068#endif // __ENUM__${name}__ 1069''') 1070 1071 def cxx_def(cls, code): 1072 name = cls.__name__ 1073 code('''\ 1074#include "enums/$name.hh" 1075namespace Enums { 1076 const char *${name}Strings[Num_${name}] = 1077 { 1078''') 1079 code.indent(2) 1080 for val in cls.vals: 1081 code('"$val",') 1082 code.dedent(2) 1083 code(''' 1084 }; 1085} // namespace Enums 1086''') 1087 1088 def swig_decl(cls, code): 1089 name = cls.__name__ 1090 code('''\ 1091%module(package="m5.internal") enum_$name 1092 1093%{ 1094#include "enums/$name.hh" 1095%} 1096 1097%include "enums/$name.hh" 1098''') 1099 1100 1101# Base class for enum types. 1102class Enum(ParamValue): 1103 __metaclass__ = MetaEnum 1104 vals = [] 1105 1106 def __init__(self, value): 1107 if value not in self.map: 1108 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1109 % (value, self.vals) 1110 self.value = value 1111 1112 @classmethod 1113 def cxx_predecls(cls, code): 1114 code('#include "enums/$0.hh"', cls.__name__) 1115 1116 @classmethod 1117 def swig_predecls(cls, code): 1118 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1119 1120 def getValue(self): 1121 return int(self.map[self.value]) 1122 1123 def __str__(self): 1124 return self.value 1125 1126# how big does a rounding error need to be before we warn about it? 1127frequency_tolerance = 0.001 # 0.1% 1128 1129class TickParamValue(NumericParamValue): 1130 cxx_type = 'Tick' 1131 1132 @classmethod 1133 def cxx_predecls(cls, code): 1134 code('#include "base/types.hh"') 1135 1136 @classmethod 1137 def swig_predecls(cls, code): 1138 code('%import "stdint.i"') 1139 code('%import "base/types.hh"') 1140 1141 def getValue(self): 1142 return long(self.value) 1143 1144class Latency(TickParamValue): 1145 def __init__(self, value): 1146 if isinstance(value, (Latency, Clock)): 1147 self.ticks = value.ticks 1148 self.value = value.value 1149 elif isinstance(value, Frequency): 1150 self.ticks = value.ticks 1151 self.value = 1.0 / value.value 1152 elif value.endswith('t'): 1153 self.ticks = True 1154 self.value = int(value[:-1]) 1155 else: 1156 self.ticks = False 1157 self.value = convert.toLatency(value) 1158 1159 def __getattr__(self, attr): 1160 if attr in ('latency', 'period'): 1161 return self 1162 if attr == 'frequency': 1163 return Frequency(self) 1164 raise AttributeError, "Latency object has no attribute '%s'" % attr 1165 1166 def getValue(self): 1167 if self.ticks or self.value == 0: 1168 value = self.value 1169 else: 1170 value = ticks.fromSeconds(self.value) 1171 return long(value) 1172 1173 # convert latency to ticks 1174 def ini_str(self): 1175 return '%d' % self.getValue() 1176 1177class Frequency(TickParamValue): 1178 def __init__(self, value): 1179 if isinstance(value, (Latency, Clock)): 1180 if value.value == 0: 1181 self.value = 0 1182 else: 1183 self.value = 1.0 / value.value 1184 self.ticks = value.ticks 1185 elif isinstance(value, Frequency): 1186 self.value = value.value 1187 self.ticks = value.ticks 1188 else: 1189 self.ticks = False 1190 self.value = convert.toFrequency(value) 1191 1192 def __getattr__(self, attr): 1193 if attr == 'frequency': 1194 return self 1195 if attr in ('latency', 'period'): 1196 return Latency(self) 1197 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1198 1199 # convert latency to ticks 1200 def getValue(self): 1201 if self.ticks or self.value == 0: 1202 value = self.value 1203 else: 1204 value = ticks.fromSeconds(1.0 / self.value) 1205 return long(value) 1206 1207 def ini_str(self): 1208 return '%d' % self.getValue() 1209 1210# A generic frequency and/or Latency value. Value is stored as a 1211# latency, and any manipulation using a multiplier thus scales the 1212# clock period, i.e. a 2x multiplier doubles the clock period and thus 1213# halves the clock frequency. 1214class Clock(ParamValue): 1215 cxx_type = 'Tick' 1216 1217 @classmethod 1218 def cxx_predecls(cls, code): 1219 code('#include "base/types.hh"') 1220 1221 @classmethod 1222 def swig_predecls(cls, code): 1223 code('%import "stdint.i"') 1224 code('%import "base/types.hh"') 1225 1226 def __init__(self, value): 1227 if isinstance(value, (Latency, Clock)): 1228 self.ticks = value.ticks 1229 self.value = value.value 1230 elif isinstance(value, Frequency): 1231 self.ticks = value.ticks 1232 self.value = 1.0 / value.value 1233 elif value.endswith('t'): 1234 self.ticks = True 1235 self.value = int(value[:-1]) 1236 else: 1237 self.ticks = False 1238 self.value = convert.anyToLatency(value) 1239 1240 def __getattr__(self, attr): 1241 if attr == 'frequency': 1242 return Frequency(self) 1243 if attr in ('latency', 'period'): 1244 return Latency(self) 1245 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1246 1247 def 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