params.py revision 10427:26fee6c20087
14680Sgblack@eecs.umich.edu# Copyright (c) 2012-2014 ARM Limited 25442Sgblack@eecs.umich.edu# All rights reserved. 34680Sgblack@eecs.umich.edu# 44680Sgblack@eecs.umich.edu# The license below extends only to copyright in the software and shall 54680Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual 64680Sgblack@eecs.umich.edu# property including but not limited to intellectual property relating 74680Sgblack@eecs.umich.edu# to a hardware implementation of the functionality of the software 84680Sgblack@eecs.umich.edu# licensed hereunder. You may use the software subject to the license 94680Sgblack@eecs.umich.edu# terms below provided that you ensure that this notice is replicated 104680Sgblack@eecs.umich.edu# unmodified and in its entirety in all distributions of the software, 114680Sgblack@eecs.umich.edu# modified or unmodified, in source code or in binary form. 124680Sgblack@eecs.umich.edu# 134680Sgblack@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 144680Sgblack@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc. 154680Sgblack@eecs.umich.edu# All rights reserved. 164680Sgblack@eecs.umich.edu# 174680Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 184680Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are 194680Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright 204680Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 214680Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 224680Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 234680Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution; 244680Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its 254680Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from 264680Sgblack@eecs.umich.edu# this software without specific prior written permission. 274680Sgblack@eecs.umich.edu# 284680Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294680Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304680Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314680Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324680Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334680Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344680Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354680Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364680Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 375543Ssaidi@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384680Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394680Sgblack@eecs.umich.edu# 404680Sgblack@eecs.umich.edu# Authors: Steve Reinhardt 414680Sgblack@eecs.umich.edu# Nathan Binkert 424680Sgblack@eecs.umich.edu# Gabe Black 434680Sgblack@eecs.umich.edu# Andreas Hansson 444680Sgblack@eecs.umich.edu 454680Sgblack@eecs.umich.edu##################################################################### 464680Sgblack@eecs.umich.edu# 474680Sgblack@eecs.umich.edu# Parameter description classes 484680Sgblack@eecs.umich.edu# 494680Sgblack@eecs.umich.edu# The _params dictionary in each class maps parameter names to either 504680Sgblack@eecs.umich.edu# a Param or a VectorParam object. These objects contain the 514680Sgblack@eecs.umich.edu# parameter description string, the parameter type, and the default 524680Sgblack@eecs.umich.edu# value (if any). The convert() method on these objects is used to 534680Sgblack@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate 544680Sgblack@eecs.umich.edu# type. 554680Sgblack@eecs.umich.edu# 564680Sgblack@eecs.umich.edu# Note that the default values are loaded into the class's attribute 574680Sgblack@eecs.umich.edu# space when the parameter dictionary is initialized (in 584680Sgblack@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used. 594680Sgblack@eecs.umich.edu# 604680Sgblack@eecs.umich.edu##################################################################### 614680Sgblack@eecs.umich.edu 624680Sgblack@eecs.umich.eduimport copy 634680Sgblack@eecs.umich.eduimport datetime 644680Sgblack@eecs.umich.eduimport re 654680Sgblack@eecs.umich.eduimport sys 664680Sgblack@eecs.umich.eduimport time 674680Sgblack@eecs.umich.eduimport math 684680Sgblack@eecs.umich.edu 694680Sgblack@eecs.umich.eduimport proxy 704680Sgblack@eecs.umich.eduimport ticks 714680Sgblack@eecs.umich.edufrom util import * 724680Sgblack@eecs.umich.edu 734680Sgblack@eecs.umich.edudef isSimObject(*args, **kwargs): 744680Sgblack@eecs.umich.edu return SimObject.isSimObject(*args, **kwargs) 754680Sgblack@eecs.umich.edu 764680Sgblack@eecs.umich.edudef isSimObjectSequence(*args, **kwargs): 774680Sgblack@eecs.umich.edu return SimObject.isSimObjectSequence(*args, **kwargs) 784680Sgblack@eecs.umich.edu 794680Sgblack@eecs.umich.edudef isSimObjectClass(*args, **kwargs): 804680Sgblack@eecs.umich.edu return SimObject.isSimObjectClass(*args, **kwargs) 814680Sgblack@eecs.umich.edu 824680Sgblack@eecs.umich.eduallParams = {} 834680Sgblack@eecs.umich.edu 844680Sgblack@eecs.umich.educlass MetaParamValue(type): 854680Sgblack@eecs.umich.edu def __new__(mcls, name, bases, dct): 864680Sgblack@eecs.umich.edu cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct) 874680Sgblack@eecs.umich.edu assert name not in allParams 884680Sgblack@eecs.umich.edu allParams[name] = cls 894680Sgblack@eecs.umich.edu return cls 904680Sgblack@eecs.umich.edu 914680Sgblack@eecs.umich.edu 924680Sgblack@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject 934680Sgblack@eecs.umich.edu# parameters. 944680Sgblack@eecs.umich.educlass ParamValue(object): 954680Sgblack@eecs.umich.edu __metaclass__ = MetaParamValue 964680Sgblack@eecs.umich.edu cmd_line_settable = False 974680Sgblack@eecs.umich.edu 984680Sgblack@eecs.umich.edu # Generate the code needed as a prerequisite for declaring a C++ 994680Sgblack@eecs.umich.edu # object of this type. Typically generates one or more #include 1004680Sgblack@eecs.umich.edu # statements. Used when declaring parameters of this type. 1014680Sgblack@eecs.umich.edu @classmethod 1024680Sgblack@eecs.umich.edu def cxx_predecls(cls, code): 1034680Sgblack@eecs.umich.edu pass 1044680Sgblack@eecs.umich.edu 1054680Sgblack@eecs.umich.edu # Generate the code needed as a prerequisite for including a 1064680Sgblack@eecs.umich.edu # reference to a C++ object of this type in a SWIG .i file. 1074680Sgblack@eecs.umich.edu # Typically generates one or more %import or %include statements. 1084680Sgblack@eecs.umich.edu @classmethod 1094680Sgblack@eecs.umich.edu def swig_predecls(cls, code): 1104680Sgblack@eecs.umich.edu pass 1114680Sgblack@eecs.umich.edu 1124680Sgblack@eecs.umich.edu # default for printing to .ini file is regular string conversion. 1134680Sgblack@eecs.umich.edu # will be overridden in some cases 1144680Sgblack@eecs.umich.edu def ini_str(self): 1154680Sgblack@eecs.umich.edu return str(self) 1164680Sgblack@eecs.umich.edu 1174680Sgblack@eecs.umich.edu # default for printing to .json file is regular string conversion. 1184680Sgblack@eecs.umich.edu # will be overridden in some cases, mostly to use native Python 1194680Sgblack@eecs.umich.edu # types where there are similar JSON types 1204680Sgblack@eecs.umich.edu def config_value(self): 1214680Sgblack@eecs.umich.edu return str(self) 1224680Sgblack@eecs.umich.edu 1234680Sgblack@eecs.umich.edu # allows us to blithely call unproxy() on things without checking 1244680Sgblack@eecs.umich.edu # if they're really proxies or not 1254680Sgblack@eecs.umich.edu def unproxy(self, base): 1264680Sgblack@eecs.umich.edu return self 1274680Sgblack@eecs.umich.edu 1284680Sgblack@eecs.umich.edu # Produce a human readable version of the stored value 1294680Sgblack@eecs.umich.edu def pretty_print(self, value): 1304680Sgblack@eecs.umich.edu return str(value) 1314680Sgblack@eecs.umich.edu 1324680Sgblack@eecs.umich.edu# Regular parameter description. 1334680Sgblack@eecs.umich.educlass ParamDesc(object): 1344680Sgblack@eecs.umich.edu def __init__(self, ptype_str, ptype, *args, **kwargs): 1354680Sgblack@eecs.umich.edu self.ptype_str = ptype_str 1364680Sgblack@eecs.umich.edu # remember ptype only if it is provided 1374680Sgblack@eecs.umich.edu if ptype != None: 1384680Sgblack@eecs.umich.edu self.ptype = ptype 1394680Sgblack@eecs.umich.edu 1404680Sgblack@eecs.umich.edu if args: 1414680Sgblack@eecs.umich.edu if len(args) == 1: 1424680Sgblack@eecs.umich.edu self.desc = args[0] 1434680Sgblack@eecs.umich.edu elif len(args) == 2: 1444680Sgblack@eecs.umich.edu self.default = args[0] 1454680Sgblack@eecs.umich.edu self.desc = args[1] 1464680Sgblack@eecs.umich.edu else: 1474680Sgblack@eecs.umich.edu raise TypeError, 'too many arguments' 1484680Sgblack@eecs.umich.edu 1494680Sgblack@eecs.umich.edu if kwargs.has_key('desc'): 1504680Sgblack@eecs.umich.edu assert(not hasattr(self, 'desc')) 1514680Sgblack@eecs.umich.edu self.desc = kwargs['desc'] 1524680Sgblack@eecs.umich.edu del kwargs['desc'] 1534680Sgblack@eecs.umich.edu 1544680Sgblack@eecs.umich.edu if kwargs.has_key('default'): 1554680Sgblack@eecs.umich.edu assert(not hasattr(self, 'default')) 1564680Sgblack@eecs.umich.edu self.default = kwargs['default'] 1574680Sgblack@eecs.umich.edu del kwargs['default'] 1584680Sgblack@eecs.umich.edu 1594680Sgblack@eecs.umich.edu if kwargs: 1604680Sgblack@eecs.umich.edu raise TypeError, 'extra unknown kwargs %s' % kwargs 1614680Sgblack@eecs.umich.edu 1624680Sgblack@eecs.umich.edu if not hasattr(self, 'desc'): 1634680Sgblack@eecs.umich.edu raise TypeError, 'desc attribute missing' 1644680Sgblack@eecs.umich.edu 1654680Sgblack@eecs.umich.edu def __getattr__(self, attr): 1664680Sgblack@eecs.umich.edu if attr == 'ptype': 1674680Sgblack@eecs.umich.edu ptype = SimObject.allClasses[self.ptype_str] 1684680Sgblack@eecs.umich.edu assert isSimObjectClass(ptype) 1694680Sgblack@eecs.umich.edu self.ptype = ptype 1704680Sgblack@eecs.umich.edu return ptype 1714680Sgblack@eecs.umich.edu 1724680Sgblack@eecs.umich.edu raise AttributeError, "'%s' object has no attribute '%s'" % \ 1734680Sgblack@eecs.umich.edu (type(self).__name__, attr) 1744680Sgblack@eecs.umich.edu 1754680Sgblack@eecs.umich.edu def example_str(self): 1764680Sgblack@eecs.umich.edu if hasattr(self.ptype, "ex_str"): 1774680Sgblack@eecs.umich.edu return self.ptype.ex_str 1784680Sgblack@eecs.umich.edu else: 1794680Sgblack@eecs.umich.edu return self.ptype_str 1804680Sgblack@eecs.umich.edu 1814680Sgblack@eecs.umich.edu # Is the param available to be exposed on the command line 1824680Sgblack@eecs.umich.edu def isCmdLineSettable(self): 1834680Sgblack@eecs.umich.edu if hasattr(self.ptype, "cmd_line_settable"): 1844680Sgblack@eecs.umich.edu return self.ptype.cmd_line_settable 1854680Sgblack@eecs.umich.edu else: 1864680Sgblack@eecs.umich.edu return False 1874680Sgblack@eecs.umich.edu 1884680Sgblack@eecs.umich.edu def convert(self, value): 1894680Sgblack@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 1904680Sgblack@eecs.umich.edu value.set_param_desc(self) 1914680Sgblack@eecs.umich.edu return value 1924680Sgblack@eecs.umich.edu if not hasattr(self, 'ptype') and isNullPointer(value): 1934680Sgblack@eecs.umich.edu # deferred evaluation of SimObject; continue to defer if 1944680Sgblack@eecs.umich.edu # we're just assigning a null pointer 1954680Sgblack@eecs.umich.edu return value 1965136Sgblack@eecs.umich.edu if isinstance(value, self.ptype): 1974681Sgblack@eecs.umich.edu return value 1984681Sgblack@eecs.umich.edu if isNullPointer(value) and isSimObjectClass(self.ptype): 1994681Sgblack@eecs.umich.edu return value 2004681Sgblack@eecs.umich.edu return self.ptype(value) 2014681Sgblack@eecs.umich.edu 2024681Sgblack@eecs.umich.edu def pretty_print(self, value): 2034680Sgblack@eecs.umich.edu if isinstance(value, proxy.BaseProxy): 2044680Sgblack@eecs.umich.edu return str(value) 2054680Sgblack@eecs.umich.edu if isNullPointer(value): 2064680Sgblack@eecs.umich.edu return NULL 2074680Sgblack@eecs.umich.edu return self.ptype(value).pretty_print(value) 2084680Sgblack@eecs.umich.edu 2095136Sgblack@eecs.umich.edu def cxx_predecls(self, code): 2104680Sgblack@eecs.umich.edu code('#include <cstddef>') 2114680Sgblack@eecs.umich.edu self.ptype.cxx_predecls(code) 2124680Sgblack@eecs.umich.edu 2134680Sgblack@eecs.umich.edu def swig_predecls(self, code): 2144680Sgblack@eecs.umich.edu self.ptype.swig_predecls(code) 2154680Sgblack@eecs.umich.edu 2165136Sgblack@eecs.umich.edu def cxx_decl(self, code): 2174680Sgblack@eecs.umich.edu code('${{self.ptype.cxx_type}} ${{self.name}};') 2184680Sgblack@eecs.umich.edu 2194680Sgblack@eecs.umich.edu# Vector-valued parameter description. Just like ParamDesc, except 2204680Sgblack@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a 2214680Sgblack@eecs.umich.edu# single value. 2225136Sgblack@eecs.umich.edu 2234680Sgblack@eecs.umich.educlass VectorParamValue(list): 2244680Sgblack@eecs.umich.edu __metaclass__ = MetaParamValue 2254680Sgblack@eecs.umich.edu def __setattr__(self, attr, value): 2264680Sgblack@eecs.umich.edu raise AttributeError, \ 2274680Sgblack@eecs.umich.edu "Not allowed to set %s on '%s'" % (attr, type(self).__name__) 2284680Sgblack@eecs.umich.edu 2294680Sgblack@eecs.umich.edu def config_value(self): 2304680Sgblack@eecs.umich.edu return [v.config_value() for v in self] 2314680Sgblack@eecs.umich.edu 2324680Sgblack@eecs.umich.edu def ini_str(self): 2334680Sgblack@eecs.umich.edu return ' '.join([v.ini_str() for v in self]) 2344680Sgblack@eecs.umich.edu 2354680Sgblack@eecs.umich.edu def getValue(self): 2364680Sgblack@eecs.umich.edu return [ v.getValue() for v in self ] 2374680Sgblack@eecs.umich.edu 2384680Sgblack@eecs.umich.edu def unproxy(self, base): 2394680Sgblack@eecs.umich.edu if len(self) == 1 and isinstance(self[0], proxy.AllProxy): 2404680Sgblack@eecs.umich.edu return self[0].unproxy(base) 2414680Sgblack@eecs.umich.edu else: 2424680Sgblack@eecs.umich.edu return [v.unproxy(base) for v in self] 2434680Sgblack@eecs.umich.edu 2444680Sgblack@eecs.umich.educlass SimObjectVector(VectorParamValue): 2455442Sgblack@eecs.umich.edu # support clone operation 2464680Sgblack@eecs.umich.edu def __call__(self, **kwargs): 2474680Sgblack@eecs.umich.edu return SimObjectVector([v(**kwargs) for v in self]) 2484680Sgblack@eecs.umich.edu 2494680Sgblack@eecs.umich.edu def clear_parent(self, old_parent): 2504680Sgblack@eecs.umich.edu for v in self: 2514680Sgblack@eecs.umich.edu v.clear_parent(old_parent) 2524680Sgblack@eecs.umich.edu 2534680Sgblack@eecs.umich.edu def set_parent(self, parent, name): 2544680Sgblack@eecs.umich.edu if len(self) == 1: 2554680Sgblack@eecs.umich.edu self[0].set_parent(parent, name) 2564680Sgblack@eecs.umich.edu else: 2574680Sgblack@eecs.umich.edu width = int(math.ceil(math.log(len(self))/math.log(10))) 2584680Sgblack@eecs.umich.edu for i,v in enumerate(self): 2594680Sgblack@eecs.umich.edu v.set_parent(parent, "%s%0*d" % (name, width, i)) 2604680Sgblack@eecs.umich.edu 2615442Sgblack@eecs.umich.edu def has_parent(self): 2625442Sgblack@eecs.umich.edu return reduce(lambda x,y: x and y, [v.has_parent() for v in self]) 2634680Sgblack@eecs.umich.edu 2644680Sgblack@eecs.umich.edu # return 'cpu0 cpu1' etc. for print_ini() 2654680Sgblack@eecs.umich.edu def get_name(self): 2664680Sgblack@eecs.umich.edu return ' '.join([v._name for v in self]) 2674680Sgblack@eecs.umich.edu 2684680Sgblack@eecs.umich.edu # By iterating through the constituent members of the vector here 2694680Sgblack@eecs.umich.edu # we can nicely handle iterating over all a SimObject's children 2704680Sgblack@eecs.umich.edu # without having to provide lots of special functions on 2714680Sgblack@eecs.umich.edu # SimObjectVector directly. 2724680Sgblack@eecs.umich.edu def descendants(self): 2734680Sgblack@eecs.umich.edu for v in self: 2744680Sgblack@eecs.umich.edu for obj in v.descendants(): 2754680Sgblack@eecs.umich.edu yield obj 2764680Sgblack@eecs.umich.edu 2774680Sgblack@eecs.umich.edu def get_config_as_dict(self): 2784680Sgblack@eecs.umich.edu a = [] 2794680Sgblack@eecs.umich.edu for v in self: 2804680Sgblack@eecs.umich.edu a.append(v.get_config_as_dict()) 2814680Sgblack@eecs.umich.edu return a 2824680Sgblack@eecs.umich.edu 2834680Sgblack@eecs.umich.edu # If we are replacing an item in the vector, make sure to set the 2844680Sgblack@eecs.umich.edu # parent reference of the new SimObject to be the same as the parent 2854680Sgblack@eecs.umich.edu # of the SimObject being replaced. Useful to have if we created 2864680Sgblack@eecs.umich.edu # a SimObjectVector of temporary objects that will be modified later in 2874698Sgblack@eecs.umich.edu # configuration scripts. 2884680Sgblack@eecs.umich.edu def __setitem__(self, key, value): 2894680Sgblack@eecs.umich.edu val = self[key] 2904680Sgblack@eecs.umich.edu if value.has_parent(): 2914680Sgblack@eecs.umich.edu warn("SimObject %s already has a parent" % value.get_name() +\ 2924680Sgblack@eecs.umich.edu " that is being overwritten by a SimObjectVector") 2934680Sgblack@eecs.umich.edu value.set_parent(val.get_parent(), val._name) 2944680Sgblack@eecs.umich.edu super(SimObjectVector, self).__setitem__(key, value) 2954680Sgblack@eecs.umich.edu 2964680Sgblack@eecs.umich.edu # Enumerate the params of each member of the SimObject vector. Creates 2974680Sgblack@eecs.umich.edu # strings that will allow indexing into the vector by the python code and 2984680Sgblack@eecs.umich.edu # allow it to be specified on the command line. 2994680Sgblack@eecs.umich.edu def enumerateParams(self, flags_dict = {}, 3004680Sgblack@eecs.umich.edu cmd_line_str = "", 3014680Sgblack@eecs.umich.edu access_str = ""): 3024680Sgblack@eecs.umich.edu if hasattr(self, "_paramEnumed"): 3034680Sgblack@eecs.umich.edu print "Cycle detected enumerating params at %s?!" % (cmd_line_str) 3044680Sgblack@eecs.umich.edu else: 3054680Sgblack@eecs.umich.edu x = 0 3064680Sgblack@eecs.umich.edu for vals in self: 3074680Sgblack@eecs.umich.edu # Each entry in the SimObjectVector should be an 3084680Sgblack@eecs.umich.edu # instance of a SimObject 3094680Sgblack@eecs.umich.edu flags_dict = vals.enumerateParams(flags_dict, 310 cmd_line_str + "%d." % x, 311 access_str + "[%d]." % x) 312 x = x + 1 313 314 return flags_dict 315 316class VectorParamDesc(ParamDesc): 317 # Convert assigned value to appropriate type. If the RHS is not a 318 # list or tuple, it generates a single-element list. 319 def convert(self, value): 320 if isinstance(value, (list, tuple)): 321 # list: coerce each element into new list 322 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 323 elif isinstance(value, str): 324 # If input is a csv string 325 tmp_list = [ ParamDesc.convert(self, v) \ 326 for v in value.strip('[').strip(']').split(',') ] 327 else: 328 # singleton: coerce to a single-element list 329 tmp_list = [ ParamDesc.convert(self, value) ] 330 331 if isSimObjectSequence(tmp_list): 332 return SimObjectVector(tmp_list) 333 else: 334 return VectorParamValue(tmp_list) 335 336 # Produce a human readable example string that describes 337 # how to set this vector parameter in the absence of a default 338 # value. 339 def example_str(self): 340 s = super(VectorParamDesc, self).example_str() 341 help_str = "[" + s + "," + s + ", ...]" 342 return help_str 343 344 # Produce a human readable representation of the value of this vector param. 345 def pretty_print(self, value): 346 if isinstance(value, (list, tuple)): 347 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ] 348 elif isinstance(value, str): 349 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ] 350 else: 351 tmp_list = [ ParamDesc.pretty_print(self, value) ] 352 353 return tmp_list 354 355 # This is a helper function for the new config system 356 def __call__(self, value): 357 if isinstance(value, (list, tuple)): 358 # list: coerce each element into new list 359 tmp_list = [ ParamDesc.convert(self, v) for v in value ] 360 elif isinstance(value, str): 361 # If input is a csv string 362 tmp_list = [ ParamDesc.convert(self, v) \ 363 for v in value.strip('[').strip(']').split(',') ] 364 else: 365 # singleton: coerce to a single-element list 366 tmp_list = [ ParamDesc.convert(self, value) ] 367 368 return VectorParamValue(tmp_list) 369 370 def swig_module_name(self): 371 return "%s_vector" % self.ptype_str 372 373 def swig_predecls(self, code): 374 code('%import "${{self.swig_module_name()}}.i"') 375 376 def swig_decl(self, code): 377 code('%module(package="m5.internal") ${{self.swig_module_name()}}') 378 code('%{') 379 self.ptype.cxx_predecls(code) 380 code('%}') 381 code() 382 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion 383 code('%include "std_container.i"') 384 code() 385 self.ptype.swig_predecls(code) 386 code() 387 code('%include "std_vector.i"') 388 code() 389 390 ptype = self.ptype_str 391 cxx_type = self.ptype.cxx_type 392 393 code('%template(vector_$ptype) std::vector< $cxx_type >;') 394 395 def cxx_predecls(self, code): 396 code('#include <vector>') 397 self.ptype.cxx_predecls(code) 398 399 def cxx_decl(self, code): 400 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};') 401 402class ParamFactory(object): 403 def __init__(self, param_desc_class, ptype_str = None): 404 self.param_desc_class = param_desc_class 405 self.ptype_str = ptype_str 406 407 def __getattr__(self, attr): 408 if self.ptype_str: 409 attr = self.ptype_str + '.' + attr 410 return ParamFactory(self.param_desc_class, attr) 411 412 # E.g., Param.Int(5, "number of widgets") 413 def __call__(self, *args, **kwargs): 414 ptype = None 415 try: 416 ptype = allParams[self.ptype_str] 417 except KeyError: 418 # if name isn't defined yet, assume it's a SimObject, and 419 # try to resolve it later 420 pass 421 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) 422 423Param = ParamFactory(ParamDesc) 424VectorParam = ParamFactory(VectorParamDesc) 425 426##################################################################### 427# 428# Parameter Types 429# 430# Though native Python types could be used to specify parameter types 431# (the 'ptype' field of the Param and VectorParam classes), it's more 432# flexible to define our own set of types. This gives us more control 433# over how Python expressions are converted to values (via the 434# __init__() constructor) and how these values are printed out (via 435# the __str__() conversion method). 436# 437##################################################################### 438 439# String-valued parameter. Just mixin the ParamValue class with the 440# built-in str class. 441class String(ParamValue,str): 442 cxx_type = 'std::string' 443 cmd_line_settable = True 444 445 @classmethod 446 def cxx_predecls(self, code): 447 code('#include <string>') 448 449 @classmethod 450 def swig_predecls(cls, code): 451 code('%include "std_string.i"') 452 453 def __call__(self, value): 454 self = value 455 return value 456 457 def getValue(self): 458 return self 459 460# superclass for "numeric" parameter values, to emulate math 461# operations in a type-safe way. e.g., a Latency times an int returns 462# a new Latency object. 463class NumericParamValue(ParamValue): 464 def __str__(self): 465 return str(self.value) 466 467 def __float__(self): 468 return float(self.value) 469 470 def __long__(self): 471 return long(self.value) 472 473 def __int__(self): 474 return int(self.value) 475 476 # hook for bounds checking 477 def _check(self): 478 return 479 480 def __mul__(self, other): 481 newobj = self.__class__(self) 482 newobj.value *= other 483 newobj._check() 484 return newobj 485 486 __rmul__ = __mul__ 487 488 def __div__(self, other): 489 newobj = self.__class__(self) 490 newobj.value /= other 491 newobj._check() 492 return newobj 493 494 def __sub__(self, other): 495 newobj = self.__class__(self) 496 newobj.value -= other 497 newobj._check() 498 return newobj 499 500 def config_value(self): 501 return self.value 502 503# Metaclass for bounds-checked integer parameters. See CheckedInt. 504class CheckedIntType(MetaParamValue): 505 def __init__(cls, name, bases, dict): 506 super(CheckedIntType, cls).__init__(name, bases, dict) 507 508 # CheckedInt is an abstract base class, so we actually don't 509 # want to do any processing on it... the rest of this code is 510 # just for classes that derive from CheckedInt. 511 if name == 'CheckedInt': 512 return 513 514 if not (hasattr(cls, 'min') and hasattr(cls, 'max')): 515 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): 516 panic("CheckedInt subclass %s must define either\n" \ 517 " 'min' and 'max' or 'size' and 'unsigned'\n", 518 name); 519 if cls.unsigned: 520 cls.min = 0 521 cls.max = 2 ** cls.size - 1 522 else: 523 cls.min = -(2 ** (cls.size - 1)) 524 cls.max = (2 ** (cls.size - 1)) - 1 525 526# Abstract superclass for bounds-checked integer parameters. This 527# class is subclassed to generate parameter classes with specific 528# bounds. Initialization of the min and max bounds is done in the 529# metaclass CheckedIntType.__init__. 530class CheckedInt(NumericParamValue): 531 __metaclass__ = CheckedIntType 532 cmd_line_settable = True 533 534 def _check(self): 535 if not self.min <= self.value <= self.max: 536 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ 537 (self.min, self.value, self.max) 538 539 def __init__(self, value): 540 if isinstance(value, str): 541 self.value = convert.toInteger(value) 542 elif isinstance(value, (int, long, float, NumericParamValue)): 543 self.value = long(value) 544 else: 545 raise TypeError, "Can't convert object of type %s to CheckedInt" \ 546 % type(value).__name__ 547 self._check() 548 549 def __call__(self, value): 550 self.__init__(value) 551 return value 552 553 @classmethod 554 def cxx_predecls(cls, code): 555 # most derived types require this, so we just do it here once 556 code('#include "base/types.hh"') 557 558 @classmethod 559 def swig_predecls(cls, code): 560 # most derived types require this, so we just do it here once 561 code('%import "stdint.i"') 562 code('%import "base/types.hh"') 563 564 def getValue(self): 565 return long(self.value) 566 567class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False 568class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True 569 570class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False 571class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True 572class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False 573class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 574class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False 575class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True 576class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False 577class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True 578 579class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True 580class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True 581class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 582class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True 583 584class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 585 586class Cycles(CheckedInt): 587 cxx_type = 'Cycles' 588 size = 64 589 unsigned = True 590 591 def getValue(self): 592 from m5.internal.core import Cycles 593 return Cycles(self.value) 594 595class Float(ParamValue, float): 596 cxx_type = 'double' 597 cmdLineSettable = True 598 599 def __init__(self, value): 600 if isinstance(value, (int, long, float, NumericParamValue, Float, str)): 601 self.value = float(value) 602 else: 603 raise TypeError, "Can't convert object of type %s to Float" \ 604 % type(value).__name__ 605 606 def __call__(self, value): 607 self.__init__(value) 608 return value 609 610 def getValue(self): 611 return float(self.value) 612 613 def config_value(self): 614 return self 615 616class MemorySize(CheckedInt): 617 cxx_type = 'uint64_t' 618 ex_str = '512MB' 619 size = 64 620 unsigned = True 621 def __init__(self, value): 622 if isinstance(value, MemorySize): 623 self.value = value.value 624 else: 625 self.value = convert.toMemorySize(value) 626 self._check() 627 628class MemorySize32(CheckedInt): 629 cxx_type = 'uint32_t' 630 ex_str = '512MB' 631 size = 32 632 unsigned = True 633 def __init__(self, value): 634 if isinstance(value, MemorySize): 635 self.value = value.value 636 else: 637 self.value = convert.toMemorySize(value) 638 self._check() 639 640class Addr(CheckedInt): 641 cxx_type = 'Addr' 642 size = 64 643 unsigned = True 644 def __init__(self, value): 645 if isinstance(value, Addr): 646 self.value = value.value 647 else: 648 try: 649 # Often addresses are referred to with sizes. Ex: A device 650 # base address is at "512MB". Use toMemorySize() to convert 651 # these into addresses. If the address is not specified with a 652 # "size", an exception will occur and numeric translation will 653 # proceed below. 654 self.value = convert.toMemorySize(value) 655 except (TypeError, ValueError): 656 # Convert number to string and use long() to do automatic 657 # base conversion (requires base=0 for auto-conversion) 658 self.value = long(str(value), base=0) 659 660 self._check() 661 def __add__(self, other): 662 if isinstance(other, Addr): 663 return self.value + other.value 664 else: 665 return self.value + other 666 def pretty_print(self, value): 667 try: 668 val = convert.toMemorySize(value) 669 except TypeError: 670 val = long(value) 671 return "0x%x" % long(val) 672 673class AddrRange(ParamValue): 674 cxx_type = 'AddrRange' 675 676 def __init__(self, *args, **kwargs): 677 # Disable interleaving by default 678 self.intlvHighBit = 0 679 self.intlvBits = 0 680 self.intlvMatch = 0 681 682 def handle_kwargs(self, kwargs): 683 # An address range needs to have an upper limit, specified 684 # either explicitly with an end, or as an offset using the 685 # size keyword. 686 if 'end' in kwargs: 687 self.end = Addr(kwargs.pop('end')) 688 elif 'size' in kwargs: 689 self.end = self.start + Addr(kwargs.pop('size')) - 1 690 else: 691 raise TypeError, "Either end or size must be specified" 692 693 # Now on to the optional bit 694 if 'intlvHighBit' in kwargs: 695 self.intlvHighBit = int(kwargs.pop('intlvHighBit')) 696 if 'intlvBits' in kwargs: 697 self.intlvBits = int(kwargs.pop('intlvBits')) 698 if 'intlvMatch' in kwargs: 699 self.intlvMatch = int(kwargs.pop('intlvMatch')) 700 701 if len(args) == 0: 702 self.start = Addr(kwargs.pop('start')) 703 handle_kwargs(self, kwargs) 704 705 elif len(args) == 1: 706 if kwargs: 707 self.start = Addr(args[0]) 708 handle_kwargs(self, kwargs) 709 elif isinstance(args[0], (list, tuple)): 710 self.start = Addr(args[0][0]) 711 self.end = Addr(args[0][1]) 712 else: 713 self.start = Addr(0) 714 self.end = Addr(args[0]) - 1 715 716 elif len(args) == 2: 717 self.start = Addr(args[0]) 718 self.end = Addr(args[1]) 719 else: 720 raise TypeError, "Too many arguments specified" 721 722 if kwargs: 723 raise TypeError, "Too many keywords: %s" % kwargs.keys() 724 725 def __str__(self): 726 return '%s:%s' % (self.start, self.end) 727 728 def size(self): 729 # Divide the size by the size of the interleaving slice 730 return (long(self.end) - long(self.start) + 1) >> self.intlvBits 731 732 @classmethod 733 def cxx_predecls(cls, code): 734 Addr.cxx_predecls(code) 735 code('#include "base/addr_range.hh"') 736 737 @classmethod 738 def swig_predecls(cls, code): 739 Addr.swig_predecls(code) 740 741 def getValue(self): 742 # Go from the Python class to the wrapped C++ class generated 743 # by swig 744 from m5.internal.range import AddrRange 745 746 return AddrRange(long(self.start), long(self.end), 747 int(self.intlvHighBit), int(self.intlvBits), 748 int(self.intlvMatch)) 749 750# Boolean parameter type. Python doesn't let you subclass bool, since 751# it doesn't want to let you create multiple instances of True and 752# False. Thus this is a little more complicated than String. 753class Bool(ParamValue): 754 cxx_type = 'bool' 755 cmd_line_settable = True 756 757 def __init__(self, value): 758 try: 759 self.value = convert.toBool(value) 760 except TypeError: 761 self.value = bool(value) 762 763 def __call__(self, value): 764 self.__init__(value) 765 return value 766 767 def getValue(self): 768 return bool(self.value) 769 770 def __str__(self): 771 return str(self.value) 772 773 # implement truth value testing for Bool parameters so that these params 774 # evaluate correctly during the python configuration phase 775 def __nonzero__(self): 776 return bool(self.value) 777 778 def ini_str(self): 779 if self.value: 780 return 'true' 781 return 'false' 782 783 def config_value(self): 784 return self.value 785 786def IncEthernetAddr(addr, val = 1): 787 bytes = map(lambda x: int(x, 16), addr.split(':')) 788 bytes[5] += val 789 for i in (5, 4, 3, 2, 1): 790 val,rem = divmod(bytes[i], 256) 791 bytes[i] = rem 792 if val == 0: 793 break 794 bytes[i - 1] += val 795 assert(bytes[0] <= 255) 796 return ':'.join(map(lambda x: '%02x' % x, bytes)) 797 798_NextEthernetAddr = "00:90:00:00:00:01" 799def NextEthernetAddr(): 800 global _NextEthernetAddr 801 802 value = _NextEthernetAddr 803 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1) 804 return value 805 806class EthernetAddr(ParamValue): 807 cxx_type = 'Net::EthAddr' 808 ex_str = "00:90:00:00:00:01" 809 cmd_line_settable = True 810 811 @classmethod 812 def cxx_predecls(cls, code): 813 code('#include "base/inet.hh"') 814 815 @classmethod 816 def swig_predecls(cls, code): 817 code('%include "python/swig/inet.i"') 818 819 def __init__(self, value): 820 if value == NextEthernetAddr: 821 self.value = value 822 return 823 824 if not isinstance(value, str): 825 raise TypeError, "expected an ethernet address and didn't get one" 826 827 bytes = value.split(':') 828 if len(bytes) != 6: 829 raise TypeError, 'invalid ethernet address %s' % value 830 831 for byte in bytes: 832 if not 0 <= int(byte, base=16) <= 0xff: 833 raise TypeError, 'invalid ethernet address %s' % value 834 835 self.value = value 836 837 def __call__(self, value): 838 self.__init__(value) 839 return value 840 841 def unproxy(self, base): 842 if self.value == NextEthernetAddr: 843 return EthernetAddr(self.value()) 844 return self 845 846 def getValue(self): 847 from m5.internal.params import EthAddr 848 return EthAddr(self.value) 849 850 def ini_str(self): 851 return self.value 852 853# When initializing an IpAddress, pass in an existing IpAddress, a string of 854# the form "a.b.c.d", or an integer representing an IP. 855class IpAddress(ParamValue): 856 cxx_type = 'Net::IpAddress' 857 ex_str = "127.0.0.1" 858 cmd_line_settable = True 859 860 @classmethod 861 def cxx_predecls(cls, code): 862 code('#include "base/inet.hh"') 863 864 @classmethod 865 def swig_predecls(cls, code): 866 code('%include "python/swig/inet.i"') 867 868 def __init__(self, value): 869 if isinstance(value, IpAddress): 870 self.ip = value.ip 871 else: 872 try: 873 self.ip = convert.toIpAddress(value) 874 except TypeError: 875 self.ip = long(value) 876 self.verifyIp() 877 878 def __call__(self, value): 879 self.__init__(value) 880 return value 881 882 def __str__(self): 883 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)] 884 return '%d.%d.%d.%d' % tuple(tup) 885 886 def __eq__(self, other): 887 if isinstance(other, IpAddress): 888 return self.ip == other.ip 889 elif isinstance(other, str): 890 try: 891 return self.ip == convert.toIpAddress(other) 892 except: 893 return False 894 else: 895 return self.ip == other 896 897 def __ne__(self, other): 898 return not (self == other) 899 900 def verifyIp(self): 901 if self.ip < 0 or self.ip >= (1 << 32): 902 raise TypeError, "invalid ip address %#08x" % self.ip 903 904 def getValue(self): 905 from m5.internal.params import IpAddress 906 return IpAddress(self.ip) 907 908# When initializing an IpNetmask, pass in an existing IpNetmask, a string of 909# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as 910# positional or keyword arguments. 911class IpNetmask(IpAddress): 912 cxx_type = 'Net::IpNetmask' 913 ex_str = "127.0.0.0/24" 914 cmd_line_settable = True 915 916 @classmethod 917 def cxx_predecls(cls, code): 918 code('#include "base/inet.hh"') 919 920 @classmethod 921 def swig_predecls(cls, code): 922 code('%include "python/swig/inet.i"') 923 924 def __init__(self, *args, **kwargs): 925 def handle_kwarg(self, kwargs, key, elseVal = None): 926 if key in kwargs: 927 setattr(self, key, kwargs.pop(key)) 928 elif elseVal: 929 setattr(self, key, elseVal) 930 else: 931 raise TypeError, "No value set for %s" % key 932 933 if len(args) == 0: 934 handle_kwarg(self, kwargs, 'ip') 935 handle_kwarg(self, kwargs, 'netmask') 936 937 elif len(args) == 1: 938 if kwargs: 939 if not 'ip' in kwargs and not 'netmask' in kwargs: 940 raise TypeError, "Invalid arguments" 941 handle_kwarg(self, kwargs, 'ip', args[0]) 942 handle_kwarg(self, kwargs, 'netmask', args[0]) 943 elif isinstance(args[0], IpNetmask): 944 self.ip = args[0].ip 945 self.netmask = args[0].netmask 946 else: 947 (self.ip, self.netmask) = convert.toIpNetmask(args[0]) 948 949 elif len(args) == 2: 950 self.ip = args[0] 951 self.netmask = args[1] 952 else: 953 raise TypeError, "Too many arguments specified" 954 955 if kwargs: 956 raise TypeError, "Too many keywords: %s" % kwargs.keys() 957 958 self.verify() 959 960 def __call__(self, value): 961 self.__init__(value) 962 return value 963 964 def __str__(self): 965 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask) 966 967 def __eq__(self, other): 968 if isinstance(other, IpNetmask): 969 return self.ip == other.ip and self.netmask == other.netmask 970 elif isinstance(other, str): 971 try: 972 return (self.ip, self.netmask) == convert.toIpNetmask(other) 973 except: 974 return False 975 else: 976 return False 977 978 def verify(self): 979 self.verifyIp() 980 if self.netmask < 0 or self.netmask > 32: 981 raise TypeError, "invalid netmask %d" % netmask 982 983 def getValue(self): 984 from m5.internal.params import IpNetmask 985 return IpNetmask(self.ip, self.netmask) 986 987# When initializing an IpWithPort, pass in an existing IpWithPort, a string of 988# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments. 989class IpWithPort(IpAddress): 990 cxx_type = 'Net::IpWithPort' 991 ex_str = "127.0.0.1:80" 992 cmd_line_settable = True 993 994 @classmethod 995 def cxx_predecls(cls, code): 996 code('#include "base/inet.hh"') 997 998 @classmethod 999 def swig_predecls(cls, code): 1000 code('%include "python/swig/inet.i"') 1001 1002 def __init__(self, *args, **kwargs): 1003 def handle_kwarg(self, kwargs, key, elseVal = None): 1004 if key in kwargs: 1005 setattr(self, key, kwargs.pop(key)) 1006 elif elseVal: 1007 setattr(self, key, elseVal) 1008 else: 1009 raise TypeError, "No value set for %s" % key 1010 1011 if len(args) == 0: 1012 handle_kwarg(self, kwargs, 'ip') 1013 handle_kwarg(self, kwargs, 'port') 1014 1015 elif len(args) == 1: 1016 if kwargs: 1017 if not 'ip' in kwargs and not 'port' in kwargs: 1018 raise TypeError, "Invalid arguments" 1019 handle_kwarg(self, kwargs, 'ip', args[0]) 1020 handle_kwarg(self, kwargs, 'port', args[0]) 1021 elif isinstance(args[0], IpWithPort): 1022 self.ip = args[0].ip 1023 self.port = args[0].port 1024 else: 1025 (self.ip, self.port) = convert.toIpWithPort(args[0]) 1026 1027 elif len(args) == 2: 1028 self.ip = args[0] 1029 self.port = args[1] 1030 else: 1031 raise TypeError, "Too many arguments specified" 1032 1033 if kwargs: 1034 raise TypeError, "Too many keywords: %s" % kwargs.keys() 1035 1036 self.verify() 1037 1038 def __call__(self, value): 1039 self.__init__(value) 1040 return value 1041 1042 def __str__(self): 1043 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port) 1044 1045 def __eq__(self, other): 1046 if isinstance(other, IpWithPort): 1047 return self.ip == other.ip and self.port == other.port 1048 elif isinstance(other, str): 1049 try: 1050 return (self.ip, self.port) == convert.toIpWithPort(other) 1051 except: 1052 return False 1053 else: 1054 return False 1055 1056 def verify(self): 1057 self.verifyIp() 1058 if self.port < 0 or self.port > 0xffff: 1059 raise TypeError, "invalid port %d" % self.port 1060 1061 def getValue(self): 1062 from m5.internal.params import IpWithPort 1063 return IpWithPort(self.ip, self.port) 1064 1065time_formats = [ "%a %b %d %H:%M:%S %Z %Y", 1066 "%a %b %d %H:%M:%S %Y", 1067 "%Y/%m/%d %H:%M:%S", 1068 "%Y/%m/%d %H:%M", 1069 "%Y/%m/%d", 1070 "%m/%d/%Y %H:%M:%S", 1071 "%m/%d/%Y %H:%M", 1072 "%m/%d/%Y", 1073 "%m/%d/%y %H:%M:%S", 1074 "%m/%d/%y %H:%M", 1075 "%m/%d/%y"] 1076 1077 1078def parse_time(value): 1079 from time import gmtime, strptime, struct_time, time 1080 from datetime import datetime, date 1081 1082 if isinstance(value, struct_time): 1083 return value 1084 1085 if isinstance(value, (int, long)): 1086 return gmtime(value) 1087 1088 if isinstance(value, (datetime, date)): 1089 return value.timetuple() 1090 1091 if isinstance(value, str): 1092 if value in ('Now', 'Today'): 1093 return time.gmtime(time.time()) 1094 1095 for format in time_formats: 1096 try: 1097 return strptime(value, format) 1098 except ValueError: 1099 pass 1100 1101 raise ValueError, "Could not parse '%s' as a time" % value 1102 1103class Time(ParamValue): 1104 cxx_type = 'tm' 1105 1106 @classmethod 1107 def cxx_predecls(cls, code): 1108 code('#include <time.h>') 1109 1110 @classmethod 1111 def swig_predecls(cls, code): 1112 code('%include "python/swig/time.i"') 1113 1114 def __init__(self, value): 1115 self.value = parse_time(value) 1116 1117 def __call__(self, value): 1118 self.__init__(value) 1119 return value 1120 1121 def getValue(self): 1122 from m5.internal.params import tm 1123 1124 c_time = tm() 1125 py_time = self.value 1126 1127 # UNIX is years since 1900 1128 c_time.tm_year = py_time.tm_year - 1900; 1129 1130 # Python starts at 1, UNIX starts at 0 1131 c_time.tm_mon = py_time.tm_mon - 1; 1132 c_time.tm_mday = py_time.tm_mday; 1133 c_time.tm_hour = py_time.tm_hour; 1134 c_time.tm_min = py_time.tm_min; 1135 c_time.tm_sec = py_time.tm_sec; 1136 1137 # Python has 0 as Monday, UNIX is 0 as sunday 1138 c_time.tm_wday = py_time.tm_wday + 1 1139 if c_time.tm_wday > 6: 1140 c_time.tm_wday -= 7; 1141 1142 # Python starts at 1, Unix starts at 0 1143 c_time.tm_yday = py_time.tm_yday - 1; 1144 1145 return c_time 1146 1147 def __str__(self): 1148 return time.asctime(self.value) 1149 1150 def ini_str(self): 1151 return str(self) 1152 1153 def get_config_as_dict(self): 1154 assert false 1155 return str(self) 1156 1157# Enumerated types are a little more complex. The user specifies the 1158# type as Enum(foo) where foo is either a list or dictionary of 1159# alternatives (typically strings, but not necessarily so). (In the 1160# long run, the integer value of the parameter will be the list index 1161# or the corresponding dictionary value. For now, since we only check 1162# that the alternative is valid and then spit it into a .ini file, 1163# there's not much point in using the dictionary.) 1164 1165# What Enum() must do is generate a new type encapsulating the 1166# provided list/dictionary so that specific values of the parameter 1167# can be instances of that type. We define two hidden internal 1168# classes (_ListEnum and _DictEnum) to serve as base classes, then 1169# derive the new type from the appropriate base class on the fly. 1170 1171allEnums = {} 1172# Metaclass for Enum types 1173class MetaEnum(MetaParamValue): 1174 def __new__(mcls, name, bases, dict): 1175 assert name not in allEnums 1176 1177 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) 1178 allEnums[name] = cls 1179 return cls 1180 1181 def __init__(cls, name, bases, init_dict): 1182 if init_dict.has_key('map'): 1183 if not isinstance(cls.map, dict): 1184 raise TypeError, "Enum-derived class attribute 'map' " \ 1185 "must be of type dict" 1186 # build list of value strings from map 1187 cls.vals = cls.map.keys() 1188 cls.vals.sort() 1189 elif init_dict.has_key('vals'): 1190 if not isinstance(cls.vals, list): 1191 raise TypeError, "Enum-derived class attribute 'vals' " \ 1192 "must be of type list" 1193 # build string->value map from vals sequence 1194 cls.map = {} 1195 for idx,val in enumerate(cls.vals): 1196 cls.map[val] = idx 1197 else: 1198 raise TypeError, "Enum-derived class must define "\ 1199 "attribute 'map' or 'vals'" 1200 1201 cls.cxx_type = 'Enums::%s' % name 1202 1203 super(MetaEnum, cls).__init__(name, bases, init_dict) 1204 1205 # Generate C++ class declaration for this enum type. 1206 # Note that we wrap the enum in a class/struct to act as a namespace, 1207 # so that the enum strings can be brief w/o worrying about collisions. 1208 def cxx_decl(cls, code): 1209 wrapper_name = cls.wrapper_name 1210 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace' 1211 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1212 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name) 1213 1214 code('''\ 1215#ifndef $idem_macro 1216#define $idem_macro 1217 1218$wrapper $wrapper_name { 1219 enum $name { 1220''') 1221 code.indent(2) 1222 for val in cls.vals: 1223 code('$val = ${{cls.map[val]}},') 1224 code('Num_$name = ${{len(cls.vals)}}') 1225 code.dedent(2) 1226 code(' };') 1227 1228 if cls.wrapper_is_struct: 1229 code(' static const char *${name}Strings[Num_${name}];') 1230 code('};') 1231 else: 1232 code('extern const char *${name}Strings[Num_${name}];') 1233 code('}') 1234 1235 code() 1236 code('#endif // $idem_macro') 1237 1238 def cxx_def(cls, code): 1239 wrapper_name = cls.wrapper_name 1240 file_name = cls.__name__ 1241 name = cls.__name__ if cls.enum_name is None else cls.enum_name 1242 1243 code('#include "enums/$file_name.hh"') 1244 if cls.wrapper_is_struct: 1245 code('const char *${wrapper_name}::${name}Strings' 1246 '[Num_${name}] =') 1247 else: 1248 code('namespace Enums {') 1249 code.indent(1) 1250 code(' const char *${name}Strings[Num_${name}] =') 1251 1252 code('{') 1253 code.indent(1) 1254 for val in cls.vals: 1255 code('"$val",') 1256 code.dedent(1) 1257 code('};') 1258 1259 if not cls.wrapper_is_struct: 1260 code('} // namespace $wrapper_name') 1261 code.dedent(1) 1262 1263 def swig_decl(cls, code): 1264 name = cls.__name__ 1265 code('''\ 1266%module(package="m5.internal") enum_$name 1267 1268%{ 1269#include "enums/$name.hh" 1270%} 1271 1272%include "enums/$name.hh" 1273''') 1274 1275 1276# Base class for enum types. 1277class Enum(ParamValue): 1278 __metaclass__ = MetaEnum 1279 vals = [] 1280 cmd_line_settable = True 1281 1282 # The name of the wrapping namespace or struct 1283 wrapper_name = 'Enums' 1284 1285 # If true, the enum is wrapped in a struct rather than a namespace 1286 wrapper_is_struct = False 1287 1288 # If not None, use this as the enum name rather than this class name 1289 enum_name = None 1290 1291 def __init__(self, value): 1292 if value not in self.map: 1293 raise TypeError, "Enum param got bad value '%s' (not in %s)" \ 1294 % (value, self.vals) 1295 self.value = value 1296 1297 def __call__(self, value): 1298 self.__init__(value) 1299 return value 1300 1301 @classmethod 1302 def cxx_predecls(cls, code): 1303 code('#include "enums/$0.hh"', cls.__name__) 1304 1305 @classmethod 1306 def swig_predecls(cls, code): 1307 code('%import "python/m5/internal/enum_$0.i"', cls.__name__) 1308 1309 def getValue(self): 1310 return int(self.map[self.value]) 1311 1312 def __str__(self): 1313 return self.value 1314 1315# how big does a rounding error need to be before we warn about it? 1316frequency_tolerance = 0.001 # 0.1% 1317 1318class TickParamValue(NumericParamValue): 1319 cxx_type = 'Tick' 1320 ex_str = "1MHz" 1321 cmd_line_settable = True 1322 1323 @classmethod 1324 def cxx_predecls(cls, code): 1325 code('#include "base/types.hh"') 1326 1327 @classmethod 1328 def swig_predecls(cls, code): 1329 code('%import "stdint.i"') 1330 code('%import "base/types.hh"') 1331 1332 def __call__(self, value): 1333 self.__init__(value) 1334 return value 1335 1336 def getValue(self): 1337 return long(self.value) 1338 1339class Latency(TickParamValue): 1340 ex_str = "100ns" 1341 1342 def __init__(self, value): 1343 if isinstance(value, (Latency, Clock)): 1344 self.ticks = value.ticks 1345 self.value = value.value 1346 elif isinstance(value, Frequency): 1347 self.ticks = value.ticks 1348 self.value = 1.0 / value.value 1349 elif value.endswith('t'): 1350 self.ticks = True 1351 self.value = int(value[:-1]) 1352 else: 1353 self.ticks = False 1354 self.value = convert.toLatency(value) 1355 1356 def __call__(self, value): 1357 self.__init__(value) 1358 return value 1359 1360 def __getattr__(self, attr): 1361 if attr in ('latency', 'period'): 1362 return self 1363 if attr == 'frequency': 1364 return Frequency(self) 1365 raise AttributeError, "Latency object has no attribute '%s'" % attr 1366 1367 def getValue(self): 1368 if self.ticks or self.value == 0: 1369 value = self.value 1370 else: 1371 value = ticks.fromSeconds(self.value) 1372 return long(value) 1373 1374 def config_value(self): 1375 return self.getValue() 1376 1377 # convert latency to ticks 1378 def ini_str(self): 1379 return '%d' % self.getValue() 1380 1381class Frequency(TickParamValue): 1382 ex_str = "1GHz" 1383 1384 def __init__(self, value): 1385 if isinstance(value, (Latency, Clock)): 1386 if value.value == 0: 1387 self.value = 0 1388 else: 1389 self.value = 1.0 / value.value 1390 self.ticks = value.ticks 1391 elif isinstance(value, Frequency): 1392 self.value = value.value 1393 self.ticks = value.ticks 1394 else: 1395 self.ticks = False 1396 self.value = convert.toFrequency(value) 1397 1398 def __call__(self, value): 1399 self.__init__(value) 1400 return value 1401 1402 def __getattr__(self, attr): 1403 if attr == 'frequency': 1404 return self 1405 if attr in ('latency', 'period'): 1406 return Latency(self) 1407 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1408 1409 # convert latency to ticks 1410 def getValue(self): 1411 if self.ticks or self.value == 0: 1412 value = self.value 1413 else: 1414 value = ticks.fromSeconds(1.0 / self.value) 1415 return long(value) 1416 1417 def config_value(self): 1418 return self.getValue() 1419 1420 def ini_str(self): 1421 return '%d' % self.getValue() 1422 1423# A generic Frequency and/or Latency value. Value is stored as a 1424# latency, just like Latency and Frequency. 1425class Clock(TickParamValue): 1426 def __init__(self, value): 1427 if isinstance(value, (Latency, Clock)): 1428 self.ticks = value.ticks 1429 self.value = value.value 1430 elif isinstance(value, Frequency): 1431 self.ticks = value.ticks 1432 self.value = 1.0 / value.value 1433 elif value.endswith('t'): 1434 self.ticks = True 1435 self.value = int(value[:-1]) 1436 else: 1437 self.ticks = False 1438 self.value = convert.anyToLatency(value) 1439 1440 def __call__(self, value): 1441 self.__init__(value) 1442 return value 1443 1444 def __str__(self): 1445 return "%s" % Latency(self) 1446 1447 def __getattr__(self, attr): 1448 if attr == 'frequency': 1449 return Frequency(self) 1450 if attr in ('latency', 'period'): 1451 return Latency(self) 1452 raise AttributeError, "Frequency object has no attribute '%s'" % attr 1453 1454 def getValue(self): 1455 return self.period.getValue() 1456 1457 def config_value(self): 1458 return self.period.config_value() 1459 1460 def ini_str(self): 1461 return self.period.ini_str() 1462 1463class Voltage(float,ParamValue): 1464 cxx_type = 'double' 1465 ex_str = "1V" 1466 cmd_line_settable = False 1467 1468 def __new__(cls, value): 1469 # convert to voltage 1470 val = convert.toVoltage(value) 1471 return super(cls, Voltage).__new__(cls, val) 1472 1473 def __call__(self, value): 1474 val = convert.toVoltage(value) 1475 self.__init__(val) 1476 return value 1477 1478 def __str__(self): 1479 return str(self.getValue()) 1480 1481 def getValue(self): 1482 value = float(self) 1483 return value 1484 1485 def ini_str(self): 1486 return '%f' % self.getValue() 1487 1488class Current(float, ParamValue): 1489 cxx_type = 'double' 1490 ex_str = "1mA" 1491 cmd_line_settable = False 1492 1493 def __new__(cls, value): 1494 # convert to current 1495 val = convert.toCurrent(value) 1496 return super(cls, Current).__new__(cls, val) 1497 1498 def __call__(self, value): 1499 val = convert.toCurrent(value) 1500 self.__init__(val) 1501 return value 1502 1503 def __str__(self): 1504 return str(self.getValue()) 1505 1506 def getValue(self): 1507 value = float(self) 1508 return value 1509 1510 def ini_str(self): 1511 return '%f' % self.getValue() 1512 1513class NetworkBandwidth(float,ParamValue): 1514 cxx_type = 'float' 1515 ex_str = "1Gbps" 1516 cmd_line_settable = True 1517 1518 def __new__(cls, value): 1519 # convert to bits per second 1520 val = convert.toNetworkBandwidth(value) 1521 return super(cls, NetworkBandwidth).__new__(cls, val) 1522 1523 def __str__(self): 1524 return str(self.val) 1525 1526 def __call__(self, value): 1527 val = convert.toNetworkBandwidth(value) 1528 self.__init__(val) 1529 return value 1530 1531 def getValue(self): 1532 # convert to seconds per byte 1533 value = 8.0 / float(self) 1534 # convert to ticks per byte 1535 value = ticks.fromSeconds(value) 1536 return float(value) 1537 1538 def ini_str(self): 1539 return '%f' % self.getValue() 1540 1541 def config_value(self): 1542 return '%f' % self.getValue() 1543 1544class MemoryBandwidth(float,ParamValue): 1545 cxx_type = 'float' 1546 ex_str = "1GB/s" 1547 cmd_line_settable = True 1548 1549 def __new__(cls, value): 1550 # convert to bytes per second 1551 val = convert.toMemoryBandwidth(value) 1552 return super(cls, MemoryBandwidth).__new__(cls, val) 1553 1554 def __call__(self, value): 1555 val = convert.toMemoryBandwidth(value) 1556 self.__init__(val) 1557 return value 1558 1559 def getValue(self): 1560 # convert to seconds per byte 1561 value = float(self) 1562 if value: 1563 value = 1.0 / float(self) 1564 # convert to ticks per byte 1565 value = ticks.fromSeconds(value) 1566 return float(value) 1567 1568 def ini_str(self): 1569 return '%f' % self.getValue() 1570 1571 def config_value(self): 1572 return '%f' % self.getValue() 1573 1574# 1575# "Constants"... handy aliases for various values. 1576# 1577 1578# Special class for NULL pointers. Note the special check in 1579# make_param_value() above that lets these be assigned where a 1580# SimObject is required. 1581# only one copy of a particular node 1582class NullSimObject(object): 1583 __metaclass__ = Singleton 1584 1585 def __call__(cls): 1586 return cls 1587 1588 def _instantiate(self, parent = None, path = ''): 1589 pass 1590 1591 def ini_str(self): 1592 return 'Null' 1593 1594 def unproxy(self, base): 1595 return self 1596 1597 def set_path(self, parent, name): 1598 pass 1599 1600 def __str__(self): 1601 return 'Null' 1602 1603 def config_value(self): 1604 return None 1605 1606 def getValue(self): 1607 return None 1608 1609# The only instance you'll ever need... 1610NULL = NullSimObject() 1611 1612def isNullPointer(value): 1613 return isinstance(value, NullSimObject) 1614 1615# Some memory range specifications use this as a default upper bound. 1616MaxAddr = Addr.max 1617MaxTick = Tick.max 1618AllMemory = AddrRange(0, MaxAddr) 1619 1620 1621##################################################################### 1622# 1623# Port objects 1624# 1625# Ports are used to interconnect objects in the memory system. 1626# 1627##################################################################### 1628 1629# Port reference: encapsulates a reference to a particular port on a 1630# particular SimObject. 1631class PortRef(object): 1632 def __init__(self, simobj, name, role): 1633 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1634 self.simobj = simobj 1635 self.name = name 1636 self.role = role 1637 self.peer = None # not associated with another port yet 1638 self.ccConnected = False # C++ port connection done? 1639 self.index = -1 # always -1 for non-vector ports 1640 1641 def __str__(self): 1642 return '%s.%s' % (self.simobj, self.name) 1643 1644 def __len__(self): 1645 # Return the number of connected ports, i.e. 0 is we have no 1646 # peer and 1 if we do. 1647 return int(self.peer != None) 1648 1649 # for config.ini, print peer's name (not ours) 1650 def ini_str(self): 1651 return str(self.peer) 1652 1653 # for config.json 1654 def get_config_as_dict(self): 1655 return {'role' : self.role, 'peer' : str(self.peer)} 1656 1657 def __getattr__(self, attr): 1658 if attr == 'peerObj': 1659 # shorthand for proxies 1660 return self.peer.simobj 1661 raise AttributeError, "'%s' object has no attribute '%s'" % \ 1662 (self.__class__.__name__, attr) 1663 1664 # Full connection is symmetric (both ways). Called via 1665 # SimObject.__setattr__ as a result of a port assignment, e.g., 1666 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__, 1667 # e.g., "obj1.portA[3] = obj2.portB". 1668 def connect(self, other): 1669 if isinstance(other, VectorPortRef): 1670 # reference to plain VectorPort is implicit append 1671 other = other._get_next() 1672 if self.peer and not proxy.isproxy(self.peer): 1673 fatal("Port %s is already connected to %s, cannot connect %s\n", 1674 self, self.peer, other); 1675 self.peer = other 1676 if proxy.isproxy(other): 1677 other.set_param_desc(PortParamDesc()) 1678 elif isinstance(other, PortRef): 1679 if other.peer is not self: 1680 other.connect(self) 1681 else: 1682 raise TypeError, \ 1683 "assigning non-port reference '%s' to port '%s'" \ 1684 % (other, self) 1685 1686 # Allow a master/slave port pair to be spliced between 1687 # a port and its connected peer. Useful operation for connecting 1688 # instrumentation structures into a system when it is necessary 1689 # to connect the instrumentation after the full system has been 1690 # constructed. 1691 def splice(self, new_master_peer, new_slave_peer): 1692 if self.peer and not proxy.isproxy(self.peer): 1693 if isinstance(new_master_peer, PortRef) and \ 1694 isinstance(new_slave_peer, PortRef): 1695 old_peer = self.peer 1696 if self.role == 'SLAVE': 1697 self.peer = new_master_peer 1698 old_peer.peer = new_slave_peer 1699 new_master_peer.connect(self) 1700 new_slave_peer.connect(old_peer) 1701 elif self.role == 'MASTER': 1702 self.peer = new_slave_peer 1703 old_peer.peer = new_master_peer 1704 new_slave_peer.connect(self) 1705 new_master_peer.connect(old_peer) 1706 else: 1707 panic("Port %s has unknown role, "+\ 1708 "cannot splice in new peers\n", self) 1709 else: 1710 raise TypeError, \ 1711 "Splicing non-port references '%s','%s' to port '%s'"\ 1712 % (new_peer, peers_new_peer, self) 1713 else: 1714 fatal("Port %s not connected, cannot splice in new peers\n", self) 1715 1716 def clone(self, simobj, memo): 1717 if memo.has_key(self): 1718 return memo[self] 1719 newRef = copy.copy(self) 1720 memo[self] = newRef 1721 newRef.simobj = simobj 1722 assert(isSimObject(newRef.simobj)) 1723 if self.peer and not proxy.isproxy(self.peer): 1724 peerObj = self.peer.simobj(_memo=memo) 1725 newRef.peer = self.peer.clone(peerObj, memo) 1726 assert(not isinstance(newRef.peer, VectorPortRef)) 1727 return newRef 1728 1729 def unproxy(self, simobj): 1730 assert(simobj is self.simobj) 1731 if proxy.isproxy(self.peer): 1732 try: 1733 realPeer = self.peer.unproxy(self.simobj) 1734 except: 1735 print "Error in unproxying port '%s' of %s" % \ 1736 (self.name, self.simobj.path()) 1737 raise 1738 self.connect(realPeer) 1739 1740 # Call C++ to create corresponding port connection between C++ objects 1741 def ccConnect(self): 1742 from m5.internal.pyobject import connectPorts 1743 1744 if self.role == 'SLAVE': 1745 # do nothing and let the master take care of it 1746 return 1747 1748 if self.ccConnected: # already done this 1749 return 1750 peer = self.peer 1751 if not self.peer: # nothing to connect to 1752 return 1753 1754 # check that we connect a master to a slave 1755 if self.role == peer.role: 1756 raise TypeError, \ 1757 "cannot connect '%s' and '%s' due to identical role '%s'" \ 1758 % (peer, self, self.role) 1759 1760 try: 1761 # self is always the master and peer the slave 1762 connectPorts(self.simobj.getCCObject(), self.name, self.index, 1763 peer.simobj.getCCObject(), peer.name, peer.index) 1764 except: 1765 print "Error connecting port %s.%s to %s.%s" % \ 1766 (self.simobj.path(), self.name, 1767 peer.simobj.path(), peer.name) 1768 raise 1769 self.ccConnected = True 1770 peer.ccConnected = True 1771 1772# A reference to an individual element of a VectorPort... much like a 1773# PortRef, but has an index. 1774class VectorPortElementRef(PortRef): 1775 def __init__(self, simobj, name, role, index): 1776 PortRef.__init__(self, simobj, name, role) 1777 self.index = index 1778 1779 def __str__(self): 1780 return '%s.%s[%d]' % (self.simobj, self.name, self.index) 1781 1782# A reference to a complete vector-valued port (not just a single element). 1783# Can be indexed to retrieve individual VectorPortElementRef instances. 1784class VectorPortRef(object): 1785 def __init__(self, simobj, name, role): 1786 assert(isSimObject(simobj) or isSimObjectClass(simobj)) 1787 self.simobj = simobj 1788 self.name = name 1789 self.role = role 1790 self.elements = [] 1791 1792 def __str__(self): 1793 return '%s.%s[:]' % (self.simobj, self.name) 1794 1795 def __len__(self): 1796 # Return the number of connected peers, corresponding the the 1797 # length of the elements. 1798 return len(self.elements) 1799 1800 # for config.ini, print peer's name (not ours) 1801 def ini_str(self): 1802 return ' '.join([el.ini_str() for el in self.elements]) 1803 1804 # for config.json 1805 def get_config_as_dict(self): 1806 return {'role' : self.role, 1807 'peer' : [el.ini_str() for el in self.elements]} 1808 1809 def __getitem__(self, key): 1810 if not isinstance(key, int): 1811 raise TypeError, "VectorPort index must be integer" 1812 if key >= len(self.elements): 1813 # need to extend list 1814 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i) 1815 for i in range(len(self.elements), key+1)] 1816 self.elements.extend(ext) 1817 return self.elements[key] 1818 1819 def _get_next(self): 1820 return self[len(self.elements)] 1821 1822 def __setitem__(self, key, value): 1823 if not isinstance(key, int): 1824 raise TypeError, "VectorPort index must be integer" 1825 self[key].connect(value) 1826 1827 def connect(self, other): 1828 if isinstance(other, (list, tuple)): 1829 # Assign list of port refs to vector port. 1830 # For now, append them... not sure if that's the right semantics 1831 # or if it should replace the current vector. 1832 for ref in other: 1833 self._get_next().connect(ref) 1834 else: 1835 # scalar assignment to plain VectorPort is implicit append 1836 self._get_next().connect(other) 1837 1838 def clone(self, simobj, memo): 1839 if memo.has_key(self): 1840 return memo[self] 1841 newRef = copy.copy(self) 1842 memo[self] = newRef 1843 newRef.simobj = simobj 1844 assert(isSimObject(newRef.simobj)) 1845 newRef.elements = [el.clone(simobj, memo) for el in self.elements] 1846 return newRef 1847 1848 def unproxy(self, simobj): 1849 [el.unproxy(simobj) for el in self.elements] 1850 1851 def ccConnect(self): 1852 [el.ccConnect() for el in self.elements] 1853 1854# Port description object. Like a ParamDesc object, this represents a 1855# logical port in the SimObject class, not a particular port on a 1856# SimObject instance. The latter are represented by PortRef objects. 1857class Port(object): 1858 # Generate a PortRef for this port on the given SimObject with the 1859 # given name 1860 def makeRef(self, simobj): 1861 return PortRef(simobj, self.name, self.role) 1862 1863 # Connect an instance of this port (on the given SimObject with 1864 # the given name) with the port described by the supplied PortRef 1865 def connect(self, simobj, ref): 1866 self.makeRef(simobj).connect(ref) 1867 1868 # No need for any pre-declarations at the moment as we merely rely 1869 # on an unsigned int. 1870 def cxx_predecls(self, code): 1871 pass 1872 1873 # Declare an unsigned int with the same name as the port, that 1874 # will eventually hold the number of connected ports (and thus the 1875 # number of elements for a VectorPort). 1876 def cxx_decl(self, code): 1877 code('unsigned int port_${{self.name}}_connection_count;') 1878 1879class MasterPort(Port): 1880 # MasterPort("description") 1881 def __init__(self, *args): 1882 if len(args) == 1: 1883 self.desc = args[0] 1884 self.role = 'MASTER' 1885 else: 1886 raise TypeError, 'wrong number of arguments' 1887 1888class SlavePort(Port): 1889 # SlavePort("description") 1890 def __init__(self, *args): 1891 if len(args) == 1: 1892 self.desc = args[0] 1893 self.role = 'SLAVE' 1894 else: 1895 raise TypeError, 'wrong number of arguments' 1896 1897# VectorPort description object. Like Port, but represents a vector 1898# of connections (e.g., as on a XBar). 1899class VectorPort(Port): 1900 def __init__(self, *args): 1901 self.isVec = True 1902 1903 def makeRef(self, simobj): 1904 return VectorPortRef(simobj, self.name, self.role) 1905 1906class VectorMasterPort(VectorPort): 1907 # VectorMasterPort("description") 1908 def __init__(self, *args): 1909 if len(args) == 1: 1910 self.desc = args[0] 1911 self.role = 'MASTER' 1912 VectorPort.__init__(self, *args) 1913 else: 1914 raise TypeError, 'wrong number of arguments' 1915 1916class VectorSlavePort(VectorPort): 1917 # VectorSlavePort("description") 1918 def __init__(self, *args): 1919 if len(args) == 1: 1920 self.desc = args[0] 1921 self.role = 'SLAVE' 1922 VectorPort.__init__(self, *args) 1923 else: 1924 raise TypeError, 'wrong number of arguments' 1925 1926# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of 1927# proxy objects (via set_param_desc()) so that proxy error messages 1928# make sense. 1929class PortParamDesc(object): 1930 __metaclass__ = Singleton 1931 1932 ptype_str = 'Port' 1933 ptype = Port 1934 1935baseEnums = allEnums.copy() 1936baseParams = allParams.copy() 1937 1938def clear(): 1939 global allEnums, allParams 1940 1941 allEnums = baseEnums.copy() 1942 allParams = baseParams.copy() 1943 1944__all__ = ['Param', 'VectorParam', 1945 'Enum', 'Bool', 'String', 'Float', 1946 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 1947 'Int32', 'UInt32', 'Int64', 'UInt64', 1948 'Counter', 'Addr', 'Tick', 'Percent', 1949 'TcpPort', 'UdpPort', 'EthernetAddr', 1950 'IpAddress', 'IpNetmask', 'IpWithPort', 1951 'MemorySize', 'MemorySize32', 1952 'Latency', 'Frequency', 'Clock', 'Voltage', 1953 'NetworkBandwidth', 'MemoryBandwidth', 1954 'AddrRange', 1955 'MaxAddr', 'MaxTick', 'AllMemory', 1956 'Time', 1957 'NextEthernetAddr', 'NULL', 1958 'MasterPort', 'SlavePort', 1959 'VectorMasterPort', 'VectorSlavePort'] 1960 1961import SimObject 1962