params.py (11620:57f21c16adde) params.py (11802:be62996c95d1)
1# Copyright (c) 2012-2014 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2004-2006 The Regents of The University of Michigan
14# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Steve Reinhardt
41# Nathan Binkert
42# Gabe Black
43# Andreas Hansson
44
45#####################################################################
46#
47# Parameter description classes
48#
49# The _params dictionary in each class maps parameter names to either
50# a Param or a VectorParam object. These objects contain the
51# parameter description string, the parameter type, and the default
52# value (if any). The convert() method on these objects is used to
53# force whatever value is assigned to the parameter to the appropriate
54# type.
55#
56# Note that the default values are loaded into the class's attribute
57# space when the parameter dictionary is initialized (in
58# MetaSimObject._new_param()); after that point they aren't used.
59#
60#####################################################################
61
62import copy
63import datetime
64import re
65import sys
66import time
67import math
68
69import proxy
70import ticks
71from util import *
72
73def isSimObject(*args, **kwargs):
74 return SimObject.isSimObject(*args, **kwargs)
75
76def isSimObjectSequence(*args, **kwargs):
77 return SimObject.isSimObjectSequence(*args, **kwargs)
78
79def isSimObjectClass(*args, **kwargs):
80 return SimObject.isSimObjectClass(*args, **kwargs)
81
82allParams = {}
83
84class MetaParamValue(type):
85 def __new__(mcls, name, bases, dct):
86 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
87 assert name not in allParams
88 allParams[name] = cls
89 return cls
90
91
92# Dummy base class to identify types that are legitimate for SimObject
93# parameters.
94class ParamValue(object):
95 __metaclass__ = MetaParamValue
96 cmd_line_settable = False
97
98 # Generate the code needed as a prerequisite for declaring a C++
99 # object of this type. Typically generates one or more #include
100 # statements. Used when declaring parameters of this type.
101 @classmethod
102 def cxx_predecls(cls, code):
103 pass
104
105 # Generate the code needed as a prerequisite for including a
106 # reference to a C++ object of this type in a SWIG .i file.
107 # Typically generates one or more %import or %include statements.
108 @classmethod
109 def swig_predecls(cls, code):
110 pass
111
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
114 def ini_str(self):
115 return str(self)
116
117 # default for printing to .json file is regular string conversion.
118 # will be overridden in some cases, mostly to use native Python
119 # types where there are similar JSON types
120 def config_value(self):
121 return str(self)
122
123 # Prerequisites for .ini parsing with cxx_ini_parse
124 @classmethod
125 def cxx_ini_predecls(cls, code):
126 pass
127
128 # parse a .ini file entry for this param from string expression
129 # src into lvalue dest (of the param's C++ type)
130 @classmethod
131 def cxx_ini_parse(cls, code, src, dest, ret):
132 code('// Unhandled param type: %s' % cls.__name__)
133 code('%s false;' % ret)
134
135 # allows us to blithely call unproxy() on things without checking
136 # if they're really proxies or not
137 def unproxy(self, base):
138 return self
139
140 # Produce a human readable version of the stored value
141 def pretty_print(self, value):
142 return str(value)
143
144# Regular parameter description.
145class ParamDesc(object):
146 def __init__(self, ptype_str, ptype, *args, **kwargs):
147 self.ptype_str = ptype_str
148 # remember ptype only if it is provided
149 if ptype != None:
150 self.ptype = ptype
151
152 if args:
153 if len(args) == 1:
154 self.desc = args[0]
155 elif len(args) == 2:
156 self.default = args[0]
157 self.desc = args[1]
158 else:
159 raise TypeError, 'too many arguments'
160
161 if kwargs.has_key('desc'):
162 assert(not hasattr(self, 'desc'))
163 self.desc = kwargs['desc']
164 del kwargs['desc']
165
166 if kwargs.has_key('default'):
167 assert(not hasattr(self, 'default'))
168 self.default = kwargs['default']
169 del kwargs['default']
170
171 if kwargs:
172 raise TypeError, 'extra unknown kwargs %s' % kwargs
173
174 if not hasattr(self, 'desc'):
175 raise TypeError, 'desc attribute missing'
176
177 def __getattr__(self, attr):
178 if attr == 'ptype':
179 ptype = SimObject.allClasses[self.ptype_str]
180 assert isSimObjectClass(ptype)
181 self.ptype = ptype
182 return ptype
183
184 raise AttributeError, "'%s' object has no attribute '%s'" % \
185 (type(self).__name__, attr)
186
187 def example_str(self):
188 if hasattr(self.ptype, "ex_str"):
189 return self.ptype.ex_str
190 else:
191 return self.ptype_str
192
193 # Is the param available to be exposed on the command line
194 def isCmdLineSettable(self):
195 if hasattr(self.ptype, "cmd_line_settable"):
196 return self.ptype.cmd_line_settable
197 else:
198 return False
199
200 def convert(self, value):
201 if isinstance(value, proxy.BaseProxy):
202 value.set_param_desc(self)
203 return value
204 if not hasattr(self, 'ptype') and isNullPointer(value):
205 # deferred evaluation of SimObject; continue to defer if
206 # we're just assigning a null pointer
207 return value
208 if isinstance(value, self.ptype):
209 return value
210 if isNullPointer(value) and isSimObjectClass(self.ptype):
211 return value
212 return self.ptype(value)
213
214 def pretty_print(self, value):
215 if isinstance(value, proxy.BaseProxy):
216 return str(value)
217 if isNullPointer(value):
218 return NULL
219 return self.ptype(value).pretty_print(value)
220
221 def cxx_predecls(self, code):
222 code('#include <cstddef>')
223 self.ptype.cxx_predecls(code)
224
225 def swig_predecls(self, code):
226 self.ptype.swig_predecls(code)
227
228 def cxx_decl(self, code):
229 code('${{self.ptype.cxx_type}} ${{self.name}};')
230
231# Vector-valued parameter description. Just like ParamDesc, except
232# that the value is a vector (list) of the specified type instead of a
233# single value.
234
235class VectorParamValue(list):
236 __metaclass__ = MetaParamValue
237 def __setattr__(self, attr, value):
238 raise AttributeError, \
239 "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
240
241 def config_value(self):
242 return [v.config_value() for v in self]
243
244 def ini_str(self):
245 return ' '.join([v.ini_str() for v in self])
246
247 def getValue(self):
248 return [ v.getValue() for v in self ]
249
250 def unproxy(self, base):
251 if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
252 return self[0].unproxy(base)
253 else:
254 return [v.unproxy(base) for v in self]
255
256class SimObjectVector(VectorParamValue):
257 # support clone operation
258 def __call__(self, **kwargs):
259 return SimObjectVector([v(**kwargs) for v in self])
260
261 def clear_parent(self, old_parent):
262 for v in self:
263 v.clear_parent(old_parent)
264
265 def set_parent(self, parent, name):
266 if len(self) == 1:
267 self[0].set_parent(parent, name)
268 else:
269 width = int(math.ceil(math.log(len(self))/math.log(10)))
270 for i,v in enumerate(self):
271 v.set_parent(parent, "%s%0*d" % (name, width, i))
272
273 def has_parent(self):
274 return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
275
276 # return 'cpu0 cpu1' etc. for print_ini()
277 def get_name(self):
278 return ' '.join([v._name for v in self])
279
280 # By iterating through the constituent members of the vector here
281 # we can nicely handle iterating over all a SimObject's children
282 # without having to provide lots of special functions on
283 # SimObjectVector directly.
284 def descendants(self):
285 for v in self:
286 for obj in v.descendants():
287 yield obj
288
289 def get_config_as_dict(self):
290 a = []
291 for v in self:
292 a.append(v.get_config_as_dict())
293 return a
294
295 # If we are replacing an item in the vector, make sure to set the
296 # parent reference of the new SimObject to be the same as the parent
297 # of the SimObject being replaced. Useful to have if we created
298 # a SimObjectVector of temporary objects that will be modified later in
299 # configuration scripts.
300 def __setitem__(self, key, value):
301 val = self[key]
302 if value.has_parent():
303 warn("SimObject %s already has a parent" % value.get_name() +\
304 " that is being overwritten by a SimObjectVector")
305 value.set_parent(val.get_parent(), val._name)
306 super(SimObjectVector, self).__setitem__(key, value)
307
308 # Enumerate the params of each member of the SimObject vector. Creates
309 # strings that will allow indexing into the vector by the python code and
310 # allow it to be specified on the command line.
311 def enumerateParams(self, flags_dict = {},
312 cmd_line_str = "",
313 access_str = ""):
314 if hasattr(self, "_paramEnumed"):
315 print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
316 else:
317 x = 0
318 for vals in self:
319 # Each entry in the SimObjectVector should be an
320 # instance of a SimObject
321 flags_dict = vals.enumerateParams(flags_dict,
322 cmd_line_str + "%d." % x,
323 access_str + "[%d]." % x)
324 x = x + 1
325
326 return flags_dict
327
328class VectorParamDesc(ParamDesc):
329 # Convert assigned value to appropriate type. If the RHS is not a
330 # list or tuple, it generates a single-element list.
331 def convert(self, value):
332 if isinstance(value, (list, tuple)):
333 # list: coerce each element into new list
334 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
335 elif isinstance(value, str):
336 # If input is a csv string
337 tmp_list = [ ParamDesc.convert(self, v) \
338 for v in value.strip('[').strip(']').split(',') ]
339 else:
340 # singleton: coerce to a single-element list
341 tmp_list = [ ParamDesc.convert(self, value) ]
342
343 if isSimObjectSequence(tmp_list):
344 return SimObjectVector(tmp_list)
345 else:
346 return VectorParamValue(tmp_list)
347
348 # Produce a human readable example string that describes
349 # how to set this vector parameter in the absence of a default
350 # value.
351 def example_str(self):
352 s = super(VectorParamDesc, self).example_str()
353 help_str = "[" + s + "," + s + ", ...]"
354 return help_str
355
356 # Produce a human readable representation of the value of this vector param.
357 def pretty_print(self, value):
358 if isinstance(value, (list, tuple)):
359 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
360 elif isinstance(value, str):
361 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
362 else:
363 tmp_list = [ ParamDesc.pretty_print(self, value) ]
364
365 return tmp_list
366
367 # This is a helper function for the new config system
368 def __call__(self, value):
369 if isinstance(value, (list, tuple)):
370 # list: coerce each element into new list
371 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
372 elif isinstance(value, str):
373 # If input is a csv string
374 tmp_list = [ ParamDesc.convert(self, v) \
375 for v in value.strip('[').strip(']').split(',') ]
376 else:
377 # singleton: coerce to a single-element list
378 tmp_list = [ ParamDesc.convert(self, value) ]
379
380 return VectorParamValue(tmp_list)
381
382 def swig_module_name(self):
383 return "%s_vector" % self.ptype_str
384
385 def swig_predecls(self, code):
386 code('%import "${{self.swig_module_name()}}.i"')
387
388 def swig_decl(self, code):
1# Copyright (c) 2012-2014 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2004-2006 The Regents of The University of Michigan
14# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Steve Reinhardt
41# Nathan Binkert
42# Gabe Black
43# Andreas Hansson
44
45#####################################################################
46#
47# Parameter description classes
48#
49# The _params dictionary in each class maps parameter names to either
50# a Param or a VectorParam object. These objects contain the
51# parameter description string, the parameter type, and the default
52# value (if any). The convert() method on these objects is used to
53# force whatever value is assigned to the parameter to the appropriate
54# type.
55#
56# Note that the default values are loaded into the class's attribute
57# space when the parameter dictionary is initialized (in
58# MetaSimObject._new_param()); after that point they aren't used.
59#
60#####################################################################
61
62import copy
63import datetime
64import re
65import sys
66import time
67import math
68
69import proxy
70import ticks
71from util import *
72
73def isSimObject(*args, **kwargs):
74 return SimObject.isSimObject(*args, **kwargs)
75
76def isSimObjectSequence(*args, **kwargs):
77 return SimObject.isSimObjectSequence(*args, **kwargs)
78
79def isSimObjectClass(*args, **kwargs):
80 return SimObject.isSimObjectClass(*args, **kwargs)
81
82allParams = {}
83
84class MetaParamValue(type):
85 def __new__(mcls, name, bases, dct):
86 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
87 assert name not in allParams
88 allParams[name] = cls
89 return cls
90
91
92# Dummy base class to identify types that are legitimate for SimObject
93# parameters.
94class ParamValue(object):
95 __metaclass__ = MetaParamValue
96 cmd_line_settable = False
97
98 # Generate the code needed as a prerequisite for declaring a C++
99 # object of this type. Typically generates one or more #include
100 # statements. Used when declaring parameters of this type.
101 @classmethod
102 def cxx_predecls(cls, code):
103 pass
104
105 # Generate the code needed as a prerequisite for including a
106 # reference to a C++ object of this type in a SWIG .i file.
107 # Typically generates one or more %import or %include statements.
108 @classmethod
109 def swig_predecls(cls, code):
110 pass
111
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
114 def ini_str(self):
115 return str(self)
116
117 # default for printing to .json file is regular string conversion.
118 # will be overridden in some cases, mostly to use native Python
119 # types where there are similar JSON types
120 def config_value(self):
121 return str(self)
122
123 # Prerequisites for .ini parsing with cxx_ini_parse
124 @classmethod
125 def cxx_ini_predecls(cls, code):
126 pass
127
128 # parse a .ini file entry for this param from string expression
129 # src into lvalue dest (of the param's C++ type)
130 @classmethod
131 def cxx_ini_parse(cls, code, src, dest, ret):
132 code('// Unhandled param type: %s' % cls.__name__)
133 code('%s false;' % ret)
134
135 # allows us to blithely call unproxy() on things without checking
136 # if they're really proxies or not
137 def unproxy(self, base):
138 return self
139
140 # Produce a human readable version of the stored value
141 def pretty_print(self, value):
142 return str(value)
143
144# Regular parameter description.
145class ParamDesc(object):
146 def __init__(self, ptype_str, ptype, *args, **kwargs):
147 self.ptype_str = ptype_str
148 # remember ptype only if it is provided
149 if ptype != None:
150 self.ptype = ptype
151
152 if args:
153 if len(args) == 1:
154 self.desc = args[0]
155 elif len(args) == 2:
156 self.default = args[0]
157 self.desc = args[1]
158 else:
159 raise TypeError, 'too many arguments'
160
161 if kwargs.has_key('desc'):
162 assert(not hasattr(self, 'desc'))
163 self.desc = kwargs['desc']
164 del kwargs['desc']
165
166 if kwargs.has_key('default'):
167 assert(not hasattr(self, 'default'))
168 self.default = kwargs['default']
169 del kwargs['default']
170
171 if kwargs:
172 raise TypeError, 'extra unknown kwargs %s' % kwargs
173
174 if not hasattr(self, 'desc'):
175 raise TypeError, 'desc attribute missing'
176
177 def __getattr__(self, attr):
178 if attr == 'ptype':
179 ptype = SimObject.allClasses[self.ptype_str]
180 assert isSimObjectClass(ptype)
181 self.ptype = ptype
182 return ptype
183
184 raise AttributeError, "'%s' object has no attribute '%s'" % \
185 (type(self).__name__, attr)
186
187 def example_str(self):
188 if hasattr(self.ptype, "ex_str"):
189 return self.ptype.ex_str
190 else:
191 return self.ptype_str
192
193 # Is the param available to be exposed on the command line
194 def isCmdLineSettable(self):
195 if hasattr(self.ptype, "cmd_line_settable"):
196 return self.ptype.cmd_line_settable
197 else:
198 return False
199
200 def convert(self, value):
201 if isinstance(value, proxy.BaseProxy):
202 value.set_param_desc(self)
203 return value
204 if not hasattr(self, 'ptype') and isNullPointer(value):
205 # deferred evaluation of SimObject; continue to defer if
206 # we're just assigning a null pointer
207 return value
208 if isinstance(value, self.ptype):
209 return value
210 if isNullPointer(value) and isSimObjectClass(self.ptype):
211 return value
212 return self.ptype(value)
213
214 def pretty_print(self, value):
215 if isinstance(value, proxy.BaseProxy):
216 return str(value)
217 if isNullPointer(value):
218 return NULL
219 return self.ptype(value).pretty_print(value)
220
221 def cxx_predecls(self, code):
222 code('#include <cstddef>')
223 self.ptype.cxx_predecls(code)
224
225 def swig_predecls(self, code):
226 self.ptype.swig_predecls(code)
227
228 def cxx_decl(self, code):
229 code('${{self.ptype.cxx_type}} ${{self.name}};')
230
231# Vector-valued parameter description. Just like ParamDesc, except
232# that the value is a vector (list) of the specified type instead of a
233# single value.
234
235class VectorParamValue(list):
236 __metaclass__ = MetaParamValue
237 def __setattr__(self, attr, value):
238 raise AttributeError, \
239 "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
240
241 def config_value(self):
242 return [v.config_value() for v in self]
243
244 def ini_str(self):
245 return ' '.join([v.ini_str() for v in self])
246
247 def getValue(self):
248 return [ v.getValue() for v in self ]
249
250 def unproxy(self, base):
251 if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
252 return self[0].unproxy(base)
253 else:
254 return [v.unproxy(base) for v in self]
255
256class SimObjectVector(VectorParamValue):
257 # support clone operation
258 def __call__(self, **kwargs):
259 return SimObjectVector([v(**kwargs) for v in self])
260
261 def clear_parent(self, old_parent):
262 for v in self:
263 v.clear_parent(old_parent)
264
265 def set_parent(self, parent, name):
266 if len(self) == 1:
267 self[0].set_parent(parent, name)
268 else:
269 width = int(math.ceil(math.log(len(self))/math.log(10)))
270 for i,v in enumerate(self):
271 v.set_parent(parent, "%s%0*d" % (name, width, i))
272
273 def has_parent(self):
274 return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
275
276 # return 'cpu0 cpu1' etc. for print_ini()
277 def get_name(self):
278 return ' '.join([v._name for v in self])
279
280 # By iterating through the constituent members of the vector here
281 # we can nicely handle iterating over all a SimObject's children
282 # without having to provide lots of special functions on
283 # SimObjectVector directly.
284 def descendants(self):
285 for v in self:
286 for obj in v.descendants():
287 yield obj
288
289 def get_config_as_dict(self):
290 a = []
291 for v in self:
292 a.append(v.get_config_as_dict())
293 return a
294
295 # If we are replacing an item in the vector, make sure to set the
296 # parent reference of the new SimObject to be the same as the parent
297 # of the SimObject being replaced. Useful to have if we created
298 # a SimObjectVector of temporary objects that will be modified later in
299 # configuration scripts.
300 def __setitem__(self, key, value):
301 val = self[key]
302 if value.has_parent():
303 warn("SimObject %s already has a parent" % value.get_name() +\
304 " that is being overwritten by a SimObjectVector")
305 value.set_parent(val.get_parent(), val._name)
306 super(SimObjectVector, self).__setitem__(key, value)
307
308 # Enumerate the params of each member of the SimObject vector. Creates
309 # strings that will allow indexing into the vector by the python code and
310 # allow it to be specified on the command line.
311 def enumerateParams(self, flags_dict = {},
312 cmd_line_str = "",
313 access_str = ""):
314 if hasattr(self, "_paramEnumed"):
315 print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
316 else:
317 x = 0
318 for vals in self:
319 # Each entry in the SimObjectVector should be an
320 # instance of a SimObject
321 flags_dict = vals.enumerateParams(flags_dict,
322 cmd_line_str + "%d." % x,
323 access_str + "[%d]." % x)
324 x = x + 1
325
326 return flags_dict
327
328class VectorParamDesc(ParamDesc):
329 # Convert assigned value to appropriate type. If the RHS is not a
330 # list or tuple, it generates a single-element list.
331 def convert(self, value):
332 if isinstance(value, (list, tuple)):
333 # list: coerce each element into new list
334 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
335 elif isinstance(value, str):
336 # If input is a csv string
337 tmp_list = [ ParamDesc.convert(self, v) \
338 for v in value.strip('[').strip(']').split(',') ]
339 else:
340 # singleton: coerce to a single-element list
341 tmp_list = [ ParamDesc.convert(self, value) ]
342
343 if isSimObjectSequence(tmp_list):
344 return SimObjectVector(tmp_list)
345 else:
346 return VectorParamValue(tmp_list)
347
348 # Produce a human readable example string that describes
349 # how to set this vector parameter in the absence of a default
350 # value.
351 def example_str(self):
352 s = super(VectorParamDesc, self).example_str()
353 help_str = "[" + s + "," + s + ", ...]"
354 return help_str
355
356 # Produce a human readable representation of the value of this vector param.
357 def pretty_print(self, value):
358 if isinstance(value, (list, tuple)):
359 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
360 elif isinstance(value, str):
361 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
362 else:
363 tmp_list = [ ParamDesc.pretty_print(self, value) ]
364
365 return tmp_list
366
367 # This is a helper function for the new config system
368 def __call__(self, value):
369 if isinstance(value, (list, tuple)):
370 # list: coerce each element into new list
371 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
372 elif isinstance(value, str):
373 # If input is a csv string
374 tmp_list = [ ParamDesc.convert(self, v) \
375 for v in value.strip('[').strip(']').split(',') ]
376 else:
377 # singleton: coerce to a single-element list
378 tmp_list = [ ParamDesc.convert(self, value) ]
379
380 return VectorParamValue(tmp_list)
381
382 def swig_module_name(self):
383 return "%s_vector" % self.ptype_str
384
385 def swig_predecls(self, code):
386 code('%import "${{self.swig_module_name()}}.i"')
387
388 def swig_decl(self, code):
389 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
389 code('%module(package="_m5") ${{self.swig_module_name()}}')
390 code('%{')
391 self.ptype.cxx_predecls(code)
392 code('%}')
393 code()
394 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
395 code('%include "std_container.i"')
396 code()
397 self.ptype.swig_predecls(code)
398 code()
399 code('%include "std_vector.i"')
400 code()
401
402 ptype = self.ptype_str
403 cxx_type = self.ptype.cxx_type
404
405 code('%template(vector_$ptype) std::vector< $cxx_type >;')
406
407 def cxx_predecls(self, code):
408 code('#include <vector>')
409 self.ptype.cxx_predecls(code)
410
411 def cxx_decl(self, code):
412 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
413
414class ParamFactory(object):
415 def __init__(self, param_desc_class, ptype_str = None):
416 self.param_desc_class = param_desc_class
417 self.ptype_str = ptype_str
418
419 def __getattr__(self, attr):
420 if self.ptype_str:
421 attr = self.ptype_str + '.' + attr
422 return ParamFactory(self.param_desc_class, attr)
423
424 # E.g., Param.Int(5, "number of widgets")
425 def __call__(self, *args, **kwargs):
426 ptype = None
427 try:
428 ptype = allParams[self.ptype_str]
429 except KeyError:
430 # if name isn't defined yet, assume it's a SimObject, and
431 # try to resolve it later
432 pass
433 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
434
435Param = ParamFactory(ParamDesc)
436VectorParam = ParamFactory(VectorParamDesc)
437
438#####################################################################
439#
440# Parameter Types
441#
442# Though native Python types could be used to specify parameter types
443# (the 'ptype' field of the Param and VectorParam classes), it's more
444# flexible to define our own set of types. This gives us more control
445# over how Python expressions are converted to values (via the
446# __init__() constructor) and how these values are printed out (via
447# the __str__() conversion method).
448#
449#####################################################################
450
451# String-valued parameter. Just mixin the ParamValue class with the
452# built-in str class.
453class String(ParamValue,str):
454 cxx_type = 'std::string'
455 cmd_line_settable = True
456
457 @classmethod
458 def cxx_predecls(self, code):
459 code('#include <string>')
460
461 @classmethod
462 def swig_predecls(cls, code):
463 code('%include "std_string.i"')
464
465 def __call__(self, value):
466 self = value
467 return value
468
469 @classmethod
470 def cxx_ini_parse(self, code, src, dest, ret):
471 code('%s = %s;' % (dest, src))
472 code('%s true;' % ret)
473
474 def getValue(self):
475 return self
476
477# superclass for "numeric" parameter values, to emulate math
478# operations in a type-safe way. e.g., a Latency times an int returns
479# a new Latency object.
480class NumericParamValue(ParamValue):
481 def __str__(self):
482 return str(self.value)
483
484 def __float__(self):
485 return float(self.value)
486
487 def __long__(self):
488 return long(self.value)
489
490 def __int__(self):
491 return int(self.value)
492
493 # hook for bounds checking
494 def _check(self):
495 return
496
497 def __mul__(self, other):
498 newobj = self.__class__(self)
499 newobj.value *= other
500 newobj._check()
501 return newobj
502
503 __rmul__ = __mul__
504
505 def __div__(self, other):
506 newobj = self.__class__(self)
507 newobj.value /= other
508 newobj._check()
509 return newobj
510
511 def __sub__(self, other):
512 newobj = self.__class__(self)
513 newobj.value -= other
514 newobj._check()
515 return newobj
516
517 def config_value(self):
518 return self.value
519
520 @classmethod
521 def cxx_ini_predecls(cls, code):
522 # Assume that base/str.hh will be included anyway
523 # code('#include "base/str.hh"')
524 pass
525
526 # The default for parsing PODs from an .ini entry is to extract from an
527 # istringstream and let overloading choose the right type according to
528 # the dest type.
529 @classmethod
530 def cxx_ini_parse(self, code, src, dest, ret):
531 code('%s to_number(%s, %s);' % (ret, src, dest))
532
533# Metaclass for bounds-checked integer parameters. See CheckedInt.
534class CheckedIntType(MetaParamValue):
535 def __init__(cls, name, bases, dict):
536 super(CheckedIntType, cls).__init__(name, bases, dict)
537
538 # CheckedInt is an abstract base class, so we actually don't
539 # want to do any processing on it... the rest of this code is
540 # just for classes that derive from CheckedInt.
541 if name == 'CheckedInt':
542 return
543
544 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
545 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
546 panic("CheckedInt subclass %s must define either\n" \
547 " 'min' and 'max' or 'size' and 'unsigned'\n",
548 name);
549 if cls.unsigned:
550 cls.min = 0
551 cls.max = 2 ** cls.size - 1
552 else:
553 cls.min = -(2 ** (cls.size - 1))
554 cls.max = (2 ** (cls.size - 1)) - 1
555
556# Abstract superclass for bounds-checked integer parameters. This
557# class is subclassed to generate parameter classes with specific
558# bounds. Initialization of the min and max bounds is done in the
559# metaclass CheckedIntType.__init__.
560class CheckedInt(NumericParamValue):
561 __metaclass__ = CheckedIntType
562 cmd_line_settable = True
563
564 def _check(self):
565 if not self.min <= self.value <= self.max:
566 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
567 (self.min, self.value, self.max)
568
569 def __init__(self, value):
570 if isinstance(value, str):
571 self.value = convert.toInteger(value)
572 elif isinstance(value, (int, long, float, NumericParamValue)):
573 self.value = long(value)
574 else:
575 raise TypeError, "Can't convert object of type %s to CheckedInt" \
576 % type(value).__name__
577 self._check()
578
579 def __call__(self, value):
580 self.__init__(value)
581 return value
582
583 @classmethod
584 def cxx_predecls(cls, code):
585 # most derived types require this, so we just do it here once
586 code('#include "base/types.hh"')
587
588 @classmethod
589 def swig_predecls(cls, code):
590 # most derived types require this, so we just do it here once
591 code('%import "stdint.i"')
592 code('%import "base/types.hh"')
593
594 def getValue(self):
595 return long(self.value)
596
597class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
598class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
599
600class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
601class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
602class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
603class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
604class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
605class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
606class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
607class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
608
609class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
610class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
611class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
612class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
613
614class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
615
616class Cycles(CheckedInt):
617 cxx_type = 'Cycles'
618 size = 64
619 unsigned = True
620
621 def getValue(self):
390 code('%{')
391 self.ptype.cxx_predecls(code)
392 code('%}')
393 code()
394 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
395 code('%include "std_container.i"')
396 code()
397 self.ptype.swig_predecls(code)
398 code()
399 code('%include "std_vector.i"')
400 code()
401
402 ptype = self.ptype_str
403 cxx_type = self.ptype.cxx_type
404
405 code('%template(vector_$ptype) std::vector< $cxx_type >;')
406
407 def cxx_predecls(self, code):
408 code('#include <vector>')
409 self.ptype.cxx_predecls(code)
410
411 def cxx_decl(self, code):
412 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
413
414class ParamFactory(object):
415 def __init__(self, param_desc_class, ptype_str = None):
416 self.param_desc_class = param_desc_class
417 self.ptype_str = ptype_str
418
419 def __getattr__(self, attr):
420 if self.ptype_str:
421 attr = self.ptype_str + '.' + attr
422 return ParamFactory(self.param_desc_class, attr)
423
424 # E.g., Param.Int(5, "number of widgets")
425 def __call__(self, *args, **kwargs):
426 ptype = None
427 try:
428 ptype = allParams[self.ptype_str]
429 except KeyError:
430 # if name isn't defined yet, assume it's a SimObject, and
431 # try to resolve it later
432 pass
433 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
434
435Param = ParamFactory(ParamDesc)
436VectorParam = ParamFactory(VectorParamDesc)
437
438#####################################################################
439#
440# Parameter Types
441#
442# Though native Python types could be used to specify parameter types
443# (the 'ptype' field of the Param and VectorParam classes), it's more
444# flexible to define our own set of types. This gives us more control
445# over how Python expressions are converted to values (via the
446# __init__() constructor) and how these values are printed out (via
447# the __str__() conversion method).
448#
449#####################################################################
450
451# String-valued parameter. Just mixin the ParamValue class with the
452# built-in str class.
453class String(ParamValue,str):
454 cxx_type = 'std::string'
455 cmd_line_settable = True
456
457 @classmethod
458 def cxx_predecls(self, code):
459 code('#include <string>')
460
461 @classmethod
462 def swig_predecls(cls, code):
463 code('%include "std_string.i"')
464
465 def __call__(self, value):
466 self = value
467 return value
468
469 @classmethod
470 def cxx_ini_parse(self, code, src, dest, ret):
471 code('%s = %s;' % (dest, src))
472 code('%s true;' % ret)
473
474 def getValue(self):
475 return self
476
477# superclass for "numeric" parameter values, to emulate math
478# operations in a type-safe way. e.g., a Latency times an int returns
479# a new Latency object.
480class NumericParamValue(ParamValue):
481 def __str__(self):
482 return str(self.value)
483
484 def __float__(self):
485 return float(self.value)
486
487 def __long__(self):
488 return long(self.value)
489
490 def __int__(self):
491 return int(self.value)
492
493 # hook for bounds checking
494 def _check(self):
495 return
496
497 def __mul__(self, other):
498 newobj = self.__class__(self)
499 newobj.value *= other
500 newobj._check()
501 return newobj
502
503 __rmul__ = __mul__
504
505 def __div__(self, other):
506 newobj = self.__class__(self)
507 newobj.value /= other
508 newobj._check()
509 return newobj
510
511 def __sub__(self, other):
512 newobj = self.__class__(self)
513 newobj.value -= other
514 newobj._check()
515 return newobj
516
517 def config_value(self):
518 return self.value
519
520 @classmethod
521 def cxx_ini_predecls(cls, code):
522 # Assume that base/str.hh will be included anyway
523 # code('#include "base/str.hh"')
524 pass
525
526 # The default for parsing PODs from an .ini entry is to extract from an
527 # istringstream and let overloading choose the right type according to
528 # the dest type.
529 @classmethod
530 def cxx_ini_parse(self, code, src, dest, ret):
531 code('%s to_number(%s, %s);' % (ret, src, dest))
532
533# Metaclass for bounds-checked integer parameters. See CheckedInt.
534class CheckedIntType(MetaParamValue):
535 def __init__(cls, name, bases, dict):
536 super(CheckedIntType, cls).__init__(name, bases, dict)
537
538 # CheckedInt is an abstract base class, so we actually don't
539 # want to do any processing on it... the rest of this code is
540 # just for classes that derive from CheckedInt.
541 if name == 'CheckedInt':
542 return
543
544 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
545 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
546 panic("CheckedInt subclass %s must define either\n" \
547 " 'min' and 'max' or 'size' and 'unsigned'\n",
548 name);
549 if cls.unsigned:
550 cls.min = 0
551 cls.max = 2 ** cls.size - 1
552 else:
553 cls.min = -(2 ** (cls.size - 1))
554 cls.max = (2 ** (cls.size - 1)) - 1
555
556# Abstract superclass for bounds-checked integer parameters. This
557# class is subclassed to generate parameter classes with specific
558# bounds. Initialization of the min and max bounds is done in the
559# metaclass CheckedIntType.__init__.
560class CheckedInt(NumericParamValue):
561 __metaclass__ = CheckedIntType
562 cmd_line_settable = True
563
564 def _check(self):
565 if not self.min <= self.value <= self.max:
566 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
567 (self.min, self.value, self.max)
568
569 def __init__(self, value):
570 if isinstance(value, str):
571 self.value = convert.toInteger(value)
572 elif isinstance(value, (int, long, float, NumericParamValue)):
573 self.value = long(value)
574 else:
575 raise TypeError, "Can't convert object of type %s to CheckedInt" \
576 % type(value).__name__
577 self._check()
578
579 def __call__(self, value):
580 self.__init__(value)
581 return value
582
583 @classmethod
584 def cxx_predecls(cls, code):
585 # most derived types require this, so we just do it here once
586 code('#include "base/types.hh"')
587
588 @classmethod
589 def swig_predecls(cls, code):
590 # most derived types require this, so we just do it here once
591 code('%import "stdint.i"')
592 code('%import "base/types.hh"')
593
594 def getValue(self):
595 return long(self.value)
596
597class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
598class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
599
600class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
601class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
602class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
603class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
604class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
605class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
606class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
607class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
608
609class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
610class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
611class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
612class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
613
614class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
615
616class Cycles(CheckedInt):
617 cxx_type = 'Cycles'
618 size = 64
619 unsigned = True
620
621 def getValue(self):
622 from m5.internal.core import Cycles
622 from _m5.core import Cycles
623 return Cycles(self.value)
624
625 @classmethod
626 def cxx_ini_predecls(cls, code):
627 # Assume that base/str.hh will be included anyway
628 # code('#include "base/str.hh"')
629 pass
630
631 @classmethod
632 def cxx_ini_parse(cls, code, src, dest, ret):
633 code('uint64_t _temp;')
634 code('bool _ret = to_number(%s, _temp);' % src)
635 code('if (_ret)')
636 code(' %s = Cycles(_temp);' % dest)
637 code('%s _ret;' % ret)
638
639class Float(ParamValue, float):
640 cxx_type = 'double'
641 cmd_line_settable = True
642
643 def __init__(self, value):
644 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
645 self.value = float(value)
646 else:
647 raise TypeError, "Can't convert object of type %s to Float" \
648 % type(value).__name__
649
650 def __call__(self, value):
651 self.__init__(value)
652 return value
653
654 def getValue(self):
655 return float(self.value)
656
657 def config_value(self):
658 return self
659
660 @classmethod
661 def cxx_ini_predecls(cls, code):
662 code('#include <sstream>')
663
664 @classmethod
665 def cxx_ini_parse(self, code, src, dest, ret):
666 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
667
668class MemorySize(CheckedInt):
669 cxx_type = 'uint64_t'
670 ex_str = '512MB'
671 size = 64
672 unsigned = True
673 def __init__(self, value):
674 if isinstance(value, MemorySize):
675 self.value = value.value
676 else:
677 self.value = convert.toMemorySize(value)
678 self._check()
679
680class MemorySize32(CheckedInt):
681 cxx_type = 'uint32_t'
682 ex_str = '512MB'
683 size = 32
684 unsigned = True
685 def __init__(self, value):
686 if isinstance(value, MemorySize):
687 self.value = value.value
688 else:
689 self.value = convert.toMemorySize(value)
690 self._check()
691
692class Addr(CheckedInt):
693 cxx_type = 'Addr'
694 size = 64
695 unsigned = True
696 def __init__(self, value):
697 if isinstance(value, Addr):
698 self.value = value.value
699 else:
700 try:
701 # Often addresses are referred to with sizes. Ex: A device
702 # base address is at "512MB". Use toMemorySize() to convert
703 # these into addresses. If the address is not specified with a
704 # "size", an exception will occur and numeric translation will
705 # proceed below.
706 self.value = convert.toMemorySize(value)
707 except (TypeError, ValueError):
708 # Convert number to string and use long() to do automatic
709 # base conversion (requires base=0 for auto-conversion)
710 self.value = long(str(value), base=0)
711
712 self._check()
713 def __add__(self, other):
714 if isinstance(other, Addr):
715 return self.value + other.value
716 else:
717 return self.value + other
718 def pretty_print(self, value):
719 try:
720 val = convert.toMemorySize(value)
721 except TypeError:
722 val = long(value)
723 return "0x%x" % long(val)
724
725class AddrRange(ParamValue):
726 cxx_type = 'AddrRange'
727
728 def __init__(self, *args, **kwargs):
729 # Disable interleaving and hashing by default
730 self.intlvHighBit = 0
731 self.xorHighBit = 0
732 self.intlvBits = 0
733 self.intlvMatch = 0
734
735 def handle_kwargs(self, kwargs):
736 # An address range needs to have an upper limit, specified
737 # either explicitly with an end, or as an offset using the
738 # size keyword.
739 if 'end' in kwargs:
740 self.end = Addr(kwargs.pop('end'))
741 elif 'size' in kwargs:
742 self.end = self.start + Addr(kwargs.pop('size')) - 1
743 else:
744 raise TypeError, "Either end or size must be specified"
745
746 # Now on to the optional bit
747 if 'intlvHighBit' in kwargs:
748 self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
749 if 'xorHighBit' in kwargs:
750 self.xorHighBit = int(kwargs.pop('xorHighBit'))
751 if 'intlvBits' in kwargs:
752 self.intlvBits = int(kwargs.pop('intlvBits'))
753 if 'intlvMatch' in kwargs:
754 self.intlvMatch = int(kwargs.pop('intlvMatch'))
755
756 if len(args) == 0:
757 self.start = Addr(kwargs.pop('start'))
758 handle_kwargs(self, kwargs)
759
760 elif len(args) == 1:
761 if kwargs:
762 self.start = Addr(args[0])
763 handle_kwargs(self, kwargs)
764 elif isinstance(args[0], (list, tuple)):
765 self.start = Addr(args[0][0])
766 self.end = Addr(args[0][1])
767 else:
768 self.start = Addr(0)
769 self.end = Addr(args[0]) - 1
770
771 elif len(args) == 2:
772 self.start = Addr(args[0])
773 self.end = Addr(args[1])
774 else:
775 raise TypeError, "Too many arguments specified"
776
777 if kwargs:
778 raise TypeError, "Too many keywords: %s" % kwargs.keys()
779
780 def __str__(self):
781 return '%s:%s:%s:%s:%s:%s' \
782 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
783 self.intlvBits, self.intlvMatch)
784
785 def size(self):
786 # Divide the size by the size of the interleaving slice
787 return (long(self.end) - long(self.start) + 1) >> self.intlvBits
788
789 @classmethod
790 def cxx_predecls(cls, code):
791 Addr.cxx_predecls(code)
792 code('#include "base/addr_range.hh"')
793
794 @classmethod
795 def swig_predecls(cls, code):
796 Addr.swig_predecls(code)
797
798 @classmethod
799 def cxx_ini_predecls(cls, code):
800 code('#include <sstream>')
801
802 @classmethod
803 def cxx_ini_parse(cls, code, src, dest, ret):
804 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
805 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
806 code('char _sep;')
807 code('std::istringstream _stream(${src});')
808 code('_stream >> _start;')
809 code('_stream.get(_sep);')
810 code('_stream >> _end;')
811 code('if (!_stream.fail() && !_stream.eof()) {')
812 code(' _stream.get(_sep);')
813 code(' _stream >> _intlvHighBit;')
814 code(' _stream.get(_sep);')
815 code(' _stream >> _xorHighBit;')
816 code(' _stream.get(_sep);')
817 code(' _stream >> _intlvBits;')
818 code(' _stream.get(_sep);')
819 code(' _stream >> _intlvMatch;')
820 code('}')
821 code('bool _ret = !_stream.fail() &&'
822 '_stream.eof() && _sep == \':\';')
823 code('if (_ret)')
824 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
825 _xorHighBit, _intlvBits, _intlvMatch);')
826 code('${ret} _ret;')
827
828 def getValue(self):
829 # Go from the Python class to the wrapped C++ class generated
830 # by swig
623 return Cycles(self.value)
624
625 @classmethod
626 def cxx_ini_predecls(cls, code):
627 # Assume that base/str.hh will be included anyway
628 # code('#include "base/str.hh"')
629 pass
630
631 @classmethod
632 def cxx_ini_parse(cls, code, src, dest, ret):
633 code('uint64_t _temp;')
634 code('bool _ret = to_number(%s, _temp);' % src)
635 code('if (_ret)')
636 code(' %s = Cycles(_temp);' % dest)
637 code('%s _ret;' % ret)
638
639class Float(ParamValue, float):
640 cxx_type = 'double'
641 cmd_line_settable = True
642
643 def __init__(self, value):
644 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
645 self.value = float(value)
646 else:
647 raise TypeError, "Can't convert object of type %s to Float" \
648 % type(value).__name__
649
650 def __call__(self, value):
651 self.__init__(value)
652 return value
653
654 def getValue(self):
655 return float(self.value)
656
657 def config_value(self):
658 return self
659
660 @classmethod
661 def cxx_ini_predecls(cls, code):
662 code('#include <sstream>')
663
664 @classmethod
665 def cxx_ini_parse(self, code, src, dest, ret):
666 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
667
668class MemorySize(CheckedInt):
669 cxx_type = 'uint64_t'
670 ex_str = '512MB'
671 size = 64
672 unsigned = True
673 def __init__(self, value):
674 if isinstance(value, MemorySize):
675 self.value = value.value
676 else:
677 self.value = convert.toMemorySize(value)
678 self._check()
679
680class MemorySize32(CheckedInt):
681 cxx_type = 'uint32_t'
682 ex_str = '512MB'
683 size = 32
684 unsigned = True
685 def __init__(self, value):
686 if isinstance(value, MemorySize):
687 self.value = value.value
688 else:
689 self.value = convert.toMemorySize(value)
690 self._check()
691
692class Addr(CheckedInt):
693 cxx_type = 'Addr'
694 size = 64
695 unsigned = True
696 def __init__(self, value):
697 if isinstance(value, Addr):
698 self.value = value.value
699 else:
700 try:
701 # Often addresses are referred to with sizes. Ex: A device
702 # base address is at "512MB". Use toMemorySize() to convert
703 # these into addresses. If the address is not specified with a
704 # "size", an exception will occur and numeric translation will
705 # proceed below.
706 self.value = convert.toMemorySize(value)
707 except (TypeError, ValueError):
708 # Convert number to string and use long() to do automatic
709 # base conversion (requires base=0 for auto-conversion)
710 self.value = long(str(value), base=0)
711
712 self._check()
713 def __add__(self, other):
714 if isinstance(other, Addr):
715 return self.value + other.value
716 else:
717 return self.value + other
718 def pretty_print(self, value):
719 try:
720 val = convert.toMemorySize(value)
721 except TypeError:
722 val = long(value)
723 return "0x%x" % long(val)
724
725class AddrRange(ParamValue):
726 cxx_type = 'AddrRange'
727
728 def __init__(self, *args, **kwargs):
729 # Disable interleaving and hashing by default
730 self.intlvHighBit = 0
731 self.xorHighBit = 0
732 self.intlvBits = 0
733 self.intlvMatch = 0
734
735 def handle_kwargs(self, kwargs):
736 # An address range needs to have an upper limit, specified
737 # either explicitly with an end, or as an offset using the
738 # size keyword.
739 if 'end' in kwargs:
740 self.end = Addr(kwargs.pop('end'))
741 elif 'size' in kwargs:
742 self.end = self.start + Addr(kwargs.pop('size')) - 1
743 else:
744 raise TypeError, "Either end or size must be specified"
745
746 # Now on to the optional bit
747 if 'intlvHighBit' in kwargs:
748 self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
749 if 'xorHighBit' in kwargs:
750 self.xorHighBit = int(kwargs.pop('xorHighBit'))
751 if 'intlvBits' in kwargs:
752 self.intlvBits = int(kwargs.pop('intlvBits'))
753 if 'intlvMatch' in kwargs:
754 self.intlvMatch = int(kwargs.pop('intlvMatch'))
755
756 if len(args) == 0:
757 self.start = Addr(kwargs.pop('start'))
758 handle_kwargs(self, kwargs)
759
760 elif len(args) == 1:
761 if kwargs:
762 self.start = Addr(args[0])
763 handle_kwargs(self, kwargs)
764 elif isinstance(args[0], (list, tuple)):
765 self.start = Addr(args[0][0])
766 self.end = Addr(args[0][1])
767 else:
768 self.start = Addr(0)
769 self.end = Addr(args[0]) - 1
770
771 elif len(args) == 2:
772 self.start = Addr(args[0])
773 self.end = Addr(args[1])
774 else:
775 raise TypeError, "Too many arguments specified"
776
777 if kwargs:
778 raise TypeError, "Too many keywords: %s" % kwargs.keys()
779
780 def __str__(self):
781 return '%s:%s:%s:%s:%s:%s' \
782 % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
783 self.intlvBits, self.intlvMatch)
784
785 def size(self):
786 # Divide the size by the size of the interleaving slice
787 return (long(self.end) - long(self.start) + 1) >> self.intlvBits
788
789 @classmethod
790 def cxx_predecls(cls, code):
791 Addr.cxx_predecls(code)
792 code('#include "base/addr_range.hh"')
793
794 @classmethod
795 def swig_predecls(cls, code):
796 Addr.swig_predecls(code)
797
798 @classmethod
799 def cxx_ini_predecls(cls, code):
800 code('#include <sstream>')
801
802 @classmethod
803 def cxx_ini_parse(cls, code, src, dest, ret):
804 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
805 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
806 code('char _sep;')
807 code('std::istringstream _stream(${src});')
808 code('_stream >> _start;')
809 code('_stream.get(_sep);')
810 code('_stream >> _end;')
811 code('if (!_stream.fail() && !_stream.eof()) {')
812 code(' _stream.get(_sep);')
813 code(' _stream >> _intlvHighBit;')
814 code(' _stream.get(_sep);')
815 code(' _stream >> _xorHighBit;')
816 code(' _stream.get(_sep);')
817 code(' _stream >> _intlvBits;')
818 code(' _stream.get(_sep);')
819 code(' _stream >> _intlvMatch;')
820 code('}')
821 code('bool _ret = !_stream.fail() &&'
822 '_stream.eof() && _sep == \':\';')
823 code('if (_ret)')
824 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
825 _xorHighBit, _intlvBits, _intlvMatch);')
826 code('${ret} _ret;')
827
828 def getValue(self):
829 # Go from the Python class to the wrapped C++ class generated
830 # by swig
831 from m5.internal.range import AddrRange
831 from _m5.range import AddrRange
832
833 return AddrRange(long(self.start), long(self.end),
834 int(self.intlvHighBit), int(self.xorHighBit),
835 int(self.intlvBits), int(self.intlvMatch))
836
837# Boolean parameter type. Python doesn't let you subclass bool, since
838# it doesn't want to let you create multiple instances of True and
839# False. Thus this is a little more complicated than String.
840class Bool(ParamValue):
841 cxx_type = 'bool'
842 cmd_line_settable = True
843
844 def __init__(self, value):
845 try:
846 self.value = convert.toBool(value)
847 except TypeError:
848 self.value = bool(value)
849
850 def __call__(self, value):
851 self.__init__(value)
852 return value
853
854 def getValue(self):
855 return bool(self.value)
856
857 def __str__(self):
858 return str(self.value)
859
860 # implement truth value testing for Bool parameters so that these params
861 # evaluate correctly during the python configuration phase
862 def __nonzero__(self):
863 return bool(self.value)
864
865 def ini_str(self):
866 if self.value:
867 return 'true'
868 return 'false'
869
870 def config_value(self):
871 return self.value
872
873 @classmethod
874 def cxx_ini_predecls(cls, code):
875 # Assume that base/str.hh will be included anyway
876 # code('#include "base/str.hh"')
877 pass
878
879 @classmethod
880 def cxx_ini_parse(cls, code, src, dest, ret):
881 code('%s to_bool(%s, %s);' % (ret, src, dest))
882
883def IncEthernetAddr(addr, val = 1):
884 bytes = map(lambda x: int(x, 16), addr.split(':'))
885 bytes[5] += val
886 for i in (5, 4, 3, 2, 1):
887 val,rem = divmod(bytes[i], 256)
888 bytes[i] = rem
889 if val == 0:
890 break
891 bytes[i - 1] += val
892 assert(bytes[0] <= 255)
893 return ':'.join(map(lambda x: '%02x' % x, bytes))
894
895_NextEthernetAddr = "00:90:00:00:00:01"
896def NextEthernetAddr():
897 global _NextEthernetAddr
898
899 value = _NextEthernetAddr
900 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
901 return value
902
903class EthernetAddr(ParamValue):
904 cxx_type = 'Net::EthAddr'
905 ex_str = "00:90:00:00:00:01"
906 cmd_line_settable = True
907
908 @classmethod
909 def cxx_predecls(cls, code):
910 code('#include "base/inet.hh"')
911
912 @classmethod
913 def swig_predecls(cls, code):
914 code('%include "python/swig/inet.i"')
915
916 def __init__(self, value):
917 if value == NextEthernetAddr:
918 self.value = value
919 return
920
921 if not isinstance(value, str):
922 raise TypeError, "expected an ethernet address and didn't get one"
923
924 bytes = value.split(':')
925 if len(bytes) != 6:
926 raise TypeError, 'invalid ethernet address %s' % value
927
928 for byte in bytes:
929 if not 0 <= int(byte, base=16) <= 0xff:
930 raise TypeError, 'invalid ethernet address %s' % value
931
932 self.value = value
933
934 def __call__(self, value):
935 self.__init__(value)
936 return value
937
938 def unproxy(self, base):
939 if self.value == NextEthernetAddr:
940 return EthernetAddr(self.value())
941 return self
942
943 def getValue(self):
944 from m5.internal.params import EthAddr
945 return EthAddr(self.value)
946
947 def __str__(self):
948 return self.value
949
950 def ini_str(self):
951 return self.value
952
953 @classmethod
954 def cxx_ini_parse(self, code, src, dest, ret):
955 code('%s = Net::EthAddr(%s);' % (dest, src))
956 code('%s true;' % ret)
957
958# When initializing an IpAddress, pass in an existing IpAddress, a string of
959# the form "a.b.c.d", or an integer representing an IP.
960class IpAddress(ParamValue):
961 cxx_type = 'Net::IpAddress'
962 ex_str = "127.0.0.1"
963 cmd_line_settable = True
964
965 @classmethod
966 def cxx_predecls(cls, code):
967 code('#include "base/inet.hh"')
968
969 @classmethod
970 def swig_predecls(cls, code):
971 code('%include "python/swig/inet.i"')
972
973 def __init__(self, value):
974 if isinstance(value, IpAddress):
975 self.ip = value.ip
976 else:
977 try:
978 self.ip = convert.toIpAddress(value)
979 except TypeError:
980 self.ip = long(value)
981 self.verifyIp()
982
983 def __call__(self, value):
984 self.__init__(value)
985 return value
986
987 def __str__(self):
988 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
989 return '%d.%d.%d.%d' % tuple(tup)
990
991 def __eq__(self, other):
992 if isinstance(other, IpAddress):
993 return self.ip == other.ip
994 elif isinstance(other, str):
995 try:
996 return self.ip == convert.toIpAddress(other)
997 except:
998 return False
999 else:
1000 return self.ip == other
1001
1002 def __ne__(self, other):
1003 return not (self == other)
1004
1005 def verifyIp(self):
1006 if self.ip < 0 or self.ip >= (1 << 32):
1007 raise TypeError, "invalid ip address %#08x" % self.ip
1008
1009 def getValue(self):
1010 from m5.internal.params import IpAddress
1011 return IpAddress(self.ip)
1012
1013# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1014# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1015# positional or keyword arguments.
1016class IpNetmask(IpAddress):
1017 cxx_type = 'Net::IpNetmask'
1018 ex_str = "127.0.0.0/24"
1019 cmd_line_settable = True
1020
1021 @classmethod
1022 def cxx_predecls(cls, code):
1023 code('#include "base/inet.hh"')
1024
1025 @classmethod
1026 def swig_predecls(cls, code):
1027 code('%include "python/swig/inet.i"')
1028
1029 def __init__(self, *args, **kwargs):
1030 def handle_kwarg(self, kwargs, key, elseVal = None):
1031 if key in kwargs:
1032 setattr(self, key, kwargs.pop(key))
1033 elif elseVal:
1034 setattr(self, key, elseVal)
1035 else:
1036 raise TypeError, "No value set for %s" % key
1037
1038 if len(args) == 0:
1039 handle_kwarg(self, kwargs, 'ip')
1040 handle_kwarg(self, kwargs, 'netmask')
1041
1042 elif len(args) == 1:
1043 if kwargs:
1044 if not 'ip' in kwargs and not 'netmask' in kwargs:
1045 raise TypeError, "Invalid arguments"
1046 handle_kwarg(self, kwargs, 'ip', args[0])
1047 handle_kwarg(self, kwargs, 'netmask', args[0])
1048 elif isinstance(args[0], IpNetmask):
1049 self.ip = args[0].ip
1050 self.netmask = args[0].netmask
1051 else:
1052 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1053
1054 elif len(args) == 2:
1055 self.ip = args[0]
1056 self.netmask = args[1]
1057 else:
1058 raise TypeError, "Too many arguments specified"
1059
1060 if kwargs:
1061 raise TypeError, "Too many keywords: %s" % kwargs.keys()
1062
1063 self.verify()
1064
1065 def __call__(self, value):
1066 self.__init__(value)
1067 return value
1068
1069 def __str__(self):
1070 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1071
1072 def __eq__(self, other):
1073 if isinstance(other, IpNetmask):
1074 return self.ip == other.ip and self.netmask == other.netmask
1075 elif isinstance(other, str):
1076 try:
1077 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1078 except:
1079 return False
1080 else:
1081 return False
1082
1083 def verify(self):
1084 self.verifyIp()
1085 if self.netmask < 0 or self.netmask > 32:
1086 raise TypeError, "invalid netmask %d" % netmask
1087
1088 def getValue(self):
1089 from m5.internal.params import IpNetmask
1090 return IpNetmask(self.ip, self.netmask)
1091
1092# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1093# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1094class IpWithPort(IpAddress):
1095 cxx_type = 'Net::IpWithPort'
1096 ex_str = "127.0.0.1:80"
1097 cmd_line_settable = True
1098
1099 @classmethod
1100 def cxx_predecls(cls, code):
1101 code('#include "base/inet.hh"')
1102
1103 @classmethod
1104 def swig_predecls(cls, code):
1105 code('%include "python/swig/inet.i"')
1106
1107 def __init__(self, *args, **kwargs):
1108 def handle_kwarg(self, kwargs, key, elseVal = None):
1109 if key in kwargs:
1110 setattr(self, key, kwargs.pop(key))
1111 elif elseVal:
1112 setattr(self, key, elseVal)
1113 else:
1114 raise TypeError, "No value set for %s" % key
1115
1116 if len(args) == 0:
1117 handle_kwarg(self, kwargs, 'ip')
1118 handle_kwarg(self, kwargs, 'port')
1119
1120 elif len(args) == 1:
1121 if kwargs:
1122 if not 'ip' in kwargs and not 'port' in kwargs:
1123 raise TypeError, "Invalid arguments"
1124 handle_kwarg(self, kwargs, 'ip', args[0])
1125 handle_kwarg(self, kwargs, 'port', args[0])
1126 elif isinstance(args[0], IpWithPort):
1127 self.ip = args[0].ip
1128 self.port = args[0].port
1129 else:
1130 (self.ip, self.port) = convert.toIpWithPort(args[0])
1131
1132 elif len(args) == 2:
1133 self.ip = args[0]
1134 self.port = args[1]
1135 else:
1136 raise TypeError, "Too many arguments specified"
1137
1138 if kwargs:
1139 raise TypeError, "Too many keywords: %s" % kwargs.keys()
1140
1141 self.verify()
1142
1143 def __call__(self, value):
1144 self.__init__(value)
1145 return value
1146
1147 def __str__(self):
1148 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1149
1150 def __eq__(self, other):
1151 if isinstance(other, IpWithPort):
1152 return self.ip == other.ip and self.port == other.port
1153 elif isinstance(other, str):
1154 try:
1155 return (self.ip, self.port) == convert.toIpWithPort(other)
1156 except:
1157 return False
1158 else:
1159 return False
1160
1161 def verify(self):
1162 self.verifyIp()
1163 if self.port < 0 or self.port > 0xffff:
1164 raise TypeError, "invalid port %d" % self.port
1165
1166 def getValue(self):
1167 from m5.internal.params import IpWithPort
1168 return IpWithPort(self.ip, self.port)
1169
1170time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1171 "%a %b %d %H:%M:%S %Y",
1172 "%Y/%m/%d %H:%M:%S",
1173 "%Y/%m/%d %H:%M",
1174 "%Y/%m/%d",
1175 "%m/%d/%Y %H:%M:%S",
1176 "%m/%d/%Y %H:%M",
1177 "%m/%d/%Y",
1178 "%m/%d/%y %H:%M:%S",
1179 "%m/%d/%y %H:%M",
1180 "%m/%d/%y"]
1181
1182
1183def parse_time(value):
1184 from time import gmtime, strptime, struct_time, time
1185 from datetime import datetime, date
1186
1187 if isinstance(value, struct_time):
1188 return value
1189
1190 if isinstance(value, (int, long)):
1191 return gmtime(value)
1192
1193 if isinstance(value, (datetime, date)):
1194 return value.timetuple()
1195
1196 if isinstance(value, str):
1197 if value in ('Now', 'Today'):
1198 return time.gmtime(time.time())
1199
1200 for format in time_formats:
1201 try:
1202 return strptime(value, format)
1203 except ValueError:
1204 pass
1205
1206 raise ValueError, "Could not parse '%s' as a time" % value
1207
1208class Time(ParamValue):
1209 cxx_type = 'tm'
1210
1211 @classmethod
1212 def cxx_predecls(cls, code):
1213 code('#include <time.h>')
1214
1215 @classmethod
1216 def swig_predecls(cls, code):
1217 code('%include "python/swig/time.i"')
1218
1219 def __init__(self, value):
1220 self.value = parse_time(value)
1221
1222 def __call__(self, value):
1223 self.__init__(value)
1224 return value
1225
1226 def getValue(self):
1227 from m5.internal.params import tm
1228
1229 c_time = tm()
1230 py_time = self.value
1231
1232 # UNIX is years since 1900
1233 c_time.tm_year = py_time.tm_year - 1900;
1234
1235 # Python starts at 1, UNIX starts at 0
1236 c_time.tm_mon = py_time.tm_mon - 1;
1237 c_time.tm_mday = py_time.tm_mday;
1238 c_time.tm_hour = py_time.tm_hour;
1239 c_time.tm_min = py_time.tm_min;
1240 c_time.tm_sec = py_time.tm_sec;
1241
1242 # Python has 0 as Monday, UNIX is 0 as sunday
1243 c_time.tm_wday = py_time.tm_wday + 1
1244 if c_time.tm_wday > 6:
1245 c_time.tm_wday -= 7;
1246
1247 # Python starts at 1, Unix starts at 0
1248 c_time.tm_yday = py_time.tm_yday - 1;
1249
1250 return c_time
1251
1252 def __str__(self):
1253 return time.asctime(self.value)
1254
1255 def ini_str(self):
1256 return str(self)
1257
1258 def get_config_as_dict(self):
1259 assert false
1260 return str(self)
1261
1262 @classmethod
1263 def cxx_ini_predecls(cls, code):
1264 code('#include <time.h>')
1265
1266 @classmethod
1267 def cxx_ini_parse(cls, code, src, dest, ret):
1268 code('char *_parse_ret = strptime((${src}).c_str(),')
1269 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1270 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1271
1272# Enumerated types are a little more complex. The user specifies the
1273# type as Enum(foo) where foo is either a list or dictionary of
1274# alternatives (typically strings, but not necessarily so). (In the
1275# long run, the integer value of the parameter will be the list index
1276# or the corresponding dictionary value. For now, since we only check
1277# that the alternative is valid and then spit it into a .ini file,
1278# there's not much point in using the dictionary.)
1279
1280# What Enum() must do is generate a new type encapsulating the
1281# provided list/dictionary so that specific values of the parameter
1282# can be instances of that type. We define two hidden internal
1283# classes (_ListEnum and _DictEnum) to serve as base classes, then
1284# derive the new type from the appropriate base class on the fly.
1285
1286allEnums = {}
1287# Metaclass for Enum types
1288class MetaEnum(MetaParamValue):
1289 def __new__(mcls, name, bases, dict):
1290 assert name not in allEnums
1291
1292 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1293 allEnums[name] = cls
1294 return cls
1295
1296 def __init__(cls, name, bases, init_dict):
1297 if init_dict.has_key('map'):
1298 if not isinstance(cls.map, dict):
1299 raise TypeError, "Enum-derived class attribute 'map' " \
1300 "must be of type dict"
1301 # build list of value strings from map
1302 cls.vals = cls.map.keys()
1303 cls.vals.sort()
1304 elif init_dict.has_key('vals'):
1305 if not isinstance(cls.vals, list):
1306 raise TypeError, "Enum-derived class attribute 'vals' " \
1307 "must be of type list"
1308 # build string->value map from vals sequence
1309 cls.map = {}
1310 for idx,val in enumerate(cls.vals):
1311 cls.map[val] = idx
1312 else:
1313 raise TypeError, "Enum-derived class must define "\
1314 "attribute 'map' or 'vals'"
1315
1316 cls.cxx_type = 'Enums::%s' % name
1317
1318 super(MetaEnum, cls).__init__(name, bases, init_dict)
1319
1320 # Generate C++ class declaration for this enum type.
1321 # Note that we wrap the enum in a class/struct to act as a namespace,
1322 # so that the enum strings can be brief w/o worrying about collisions.
1323 def cxx_decl(cls, code):
1324 wrapper_name = cls.wrapper_name
1325 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1326 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1327 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1328
1329 code('''\
1330#ifndef $idem_macro
1331#define $idem_macro
1332
1333$wrapper $wrapper_name {
1334 enum $name {
1335''')
1336 code.indent(2)
1337 for val in cls.vals:
1338 code('$val = ${{cls.map[val]}},')
1339 code('Num_$name = ${{len(cls.vals)}}')
1340 code.dedent(2)
1341 code(' };')
1342
1343 if cls.wrapper_is_struct:
1344 code(' static const char *${name}Strings[Num_${name}];')
1345 code('};')
1346 else:
1347 code('extern const char *${name}Strings[Num_${name}];')
1348 code('}')
1349
1350 code()
1351 code('#endif // $idem_macro')
1352
1353 def cxx_def(cls, code):
1354 wrapper_name = cls.wrapper_name
1355 file_name = cls.__name__
1356 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1357
1358 code('#include "enums/$file_name.hh"')
1359 if cls.wrapper_is_struct:
1360 code('const char *${wrapper_name}::${name}Strings'
1361 '[Num_${name}] =')
1362 else:
1363 code('namespace Enums {')
1364 code.indent(1)
1365 code(' const char *${name}Strings[Num_${name}] =')
1366
1367 code('{')
1368 code.indent(1)
1369 for val in cls.vals:
1370 code('"$val",')
1371 code.dedent(1)
1372 code('};')
1373
1374 if not cls.wrapper_is_struct:
1375 code('} // namespace $wrapper_name')
1376 code.dedent(1)
1377
1378 def swig_decl(cls, code):
1379 name = cls.__name__
1380 code('''\
832
833 return AddrRange(long(self.start), long(self.end),
834 int(self.intlvHighBit), int(self.xorHighBit),
835 int(self.intlvBits), int(self.intlvMatch))
836
837# Boolean parameter type. Python doesn't let you subclass bool, since
838# it doesn't want to let you create multiple instances of True and
839# False. Thus this is a little more complicated than String.
840class Bool(ParamValue):
841 cxx_type = 'bool'
842 cmd_line_settable = True
843
844 def __init__(self, value):
845 try:
846 self.value = convert.toBool(value)
847 except TypeError:
848 self.value = bool(value)
849
850 def __call__(self, value):
851 self.__init__(value)
852 return value
853
854 def getValue(self):
855 return bool(self.value)
856
857 def __str__(self):
858 return str(self.value)
859
860 # implement truth value testing for Bool parameters so that these params
861 # evaluate correctly during the python configuration phase
862 def __nonzero__(self):
863 return bool(self.value)
864
865 def ini_str(self):
866 if self.value:
867 return 'true'
868 return 'false'
869
870 def config_value(self):
871 return self.value
872
873 @classmethod
874 def cxx_ini_predecls(cls, code):
875 # Assume that base/str.hh will be included anyway
876 # code('#include "base/str.hh"')
877 pass
878
879 @classmethod
880 def cxx_ini_parse(cls, code, src, dest, ret):
881 code('%s to_bool(%s, %s);' % (ret, src, dest))
882
883def IncEthernetAddr(addr, val = 1):
884 bytes = map(lambda x: int(x, 16), addr.split(':'))
885 bytes[5] += val
886 for i in (5, 4, 3, 2, 1):
887 val,rem = divmod(bytes[i], 256)
888 bytes[i] = rem
889 if val == 0:
890 break
891 bytes[i - 1] += val
892 assert(bytes[0] <= 255)
893 return ':'.join(map(lambda x: '%02x' % x, bytes))
894
895_NextEthernetAddr = "00:90:00:00:00:01"
896def NextEthernetAddr():
897 global _NextEthernetAddr
898
899 value = _NextEthernetAddr
900 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
901 return value
902
903class EthernetAddr(ParamValue):
904 cxx_type = 'Net::EthAddr'
905 ex_str = "00:90:00:00:00:01"
906 cmd_line_settable = True
907
908 @classmethod
909 def cxx_predecls(cls, code):
910 code('#include "base/inet.hh"')
911
912 @classmethod
913 def swig_predecls(cls, code):
914 code('%include "python/swig/inet.i"')
915
916 def __init__(self, value):
917 if value == NextEthernetAddr:
918 self.value = value
919 return
920
921 if not isinstance(value, str):
922 raise TypeError, "expected an ethernet address and didn't get one"
923
924 bytes = value.split(':')
925 if len(bytes) != 6:
926 raise TypeError, 'invalid ethernet address %s' % value
927
928 for byte in bytes:
929 if not 0 <= int(byte, base=16) <= 0xff:
930 raise TypeError, 'invalid ethernet address %s' % value
931
932 self.value = value
933
934 def __call__(self, value):
935 self.__init__(value)
936 return value
937
938 def unproxy(self, base):
939 if self.value == NextEthernetAddr:
940 return EthernetAddr(self.value())
941 return self
942
943 def getValue(self):
944 from m5.internal.params import EthAddr
945 return EthAddr(self.value)
946
947 def __str__(self):
948 return self.value
949
950 def ini_str(self):
951 return self.value
952
953 @classmethod
954 def cxx_ini_parse(self, code, src, dest, ret):
955 code('%s = Net::EthAddr(%s);' % (dest, src))
956 code('%s true;' % ret)
957
958# When initializing an IpAddress, pass in an existing IpAddress, a string of
959# the form "a.b.c.d", or an integer representing an IP.
960class IpAddress(ParamValue):
961 cxx_type = 'Net::IpAddress'
962 ex_str = "127.0.0.1"
963 cmd_line_settable = True
964
965 @classmethod
966 def cxx_predecls(cls, code):
967 code('#include "base/inet.hh"')
968
969 @classmethod
970 def swig_predecls(cls, code):
971 code('%include "python/swig/inet.i"')
972
973 def __init__(self, value):
974 if isinstance(value, IpAddress):
975 self.ip = value.ip
976 else:
977 try:
978 self.ip = convert.toIpAddress(value)
979 except TypeError:
980 self.ip = long(value)
981 self.verifyIp()
982
983 def __call__(self, value):
984 self.__init__(value)
985 return value
986
987 def __str__(self):
988 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
989 return '%d.%d.%d.%d' % tuple(tup)
990
991 def __eq__(self, other):
992 if isinstance(other, IpAddress):
993 return self.ip == other.ip
994 elif isinstance(other, str):
995 try:
996 return self.ip == convert.toIpAddress(other)
997 except:
998 return False
999 else:
1000 return self.ip == other
1001
1002 def __ne__(self, other):
1003 return not (self == other)
1004
1005 def verifyIp(self):
1006 if self.ip < 0 or self.ip >= (1 << 32):
1007 raise TypeError, "invalid ip address %#08x" % self.ip
1008
1009 def getValue(self):
1010 from m5.internal.params import IpAddress
1011 return IpAddress(self.ip)
1012
1013# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1014# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1015# positional or keyword arguments.
1016class IpNetmask(IpAddress):
1017 cxx_type = 'Net::IpNetmask'
1018 ex_str = "127.0.0.0/24"
1019 cmd_line_settable = True
1020
1021 @classmethod
1022 def cxx_predecls(cls, code):
1023 code('#include "base/inet.hh"')
1024
1025 @classmethod
1026 def swig_predecls(cls, code):
1027 code('%include "python/swig/inet.i"')
1028
1029 def __init__(self, *args, **kwargs):
1030 def handle_kwarg(self, kwargs, key, elseVal = None):
1031 if key in kwargs:
1032 setattr(self, key, kwargs.pop(key))
1033 elif elseVal:
1034 setattr(self, key, elseVal)
1035 else:
1036 raise TypeError, "No value set for %s" % key
1037
1038 if len(args) == 0:
1039 handle_kwarg(self, kwargs, 'ip')
1040 handle_kwarg(self, kwargs, 'netmask')
1041
1042 elif len(args) == 1:
1043 if kwargs:
1044 if not 'ip' in kwargs and not 'netmask' in kwargs:
1045 raise TypeError, "Invalid arguments"
1046 handle_kwarg(self, kwargs, 'ip', args[0])
1047 handle_kwarg(self, kwargs, 'netmask', args[0])
1048 elif isinstance(args[0], IpNetmask):
1049 self.ip = args[0].ip
1050 self.netmask = args[0].netmask
1051 else:
1052 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1053
1054 elif len(args) == 2:
1055 self.ip = args[0]
1056 self.netmask = args[1]
1057 else:
1058 raise TypeError, "Too many arguments specified"
1059
1060 if kwargs:
1061 raise TypeError, "Too many keywords: %s" % kwargs.keys()
1062
1063 self.verify()
1064
1065 def __call__(self, value):
1066 self.__init__(value)
1067 return value
1068
1069 def __str__(self):
1070 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1071
1072 def __eq__(self, other):
1073 if isinstance(other, IpNetmask):
1074 return self.ip == other.ip and self.netmask == other.netmask
1075 elif isinstance(other, str):
1076 try:
1077 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1078 except:
1079 return False
1080 else:
1081 return False
1082
1083 def verify(self):
1084 self.verifyIp()
1085 if self.netmask < 0 or self.netmask > 32:
1086 raise TypeError, "invalid netmask %d" % netmask
1087
1088 def getValue(self):
1089 from m5.internal.params import IpNetmask
1090 return IpNetmask(self.ip, self.netmask)
1091
1092# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1093# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1094class IpWithPort(IpAddress):
1095 cxx_type = 'Net::IpWithPort'
1096 ex_str = "127.0.0.1:80"
1097 cmd_line_settable = True
1098
1099 @classmethod
1100 def cxx_predecls(cls, code):
1101 code('#include "base/inet.hh"')
1102
1103 @classmethod
1104 def swig_predecls(cls, code):
1105 code('%include "python/swig/inet.i"')
1106
1107 def __init__(self, *args, **kwargs):
1108 def handle_kwarg(self, kwargs, key, elseVal = None):
1109 if key in kwargs:
1110 setattr(self, key, kwargs.pop(key))
1111 elif elseVal:
1112 setattr(self, key, elseVal)
1113 else:
1114 raise TypeError, "No value set for %s" % key
1115
1116 if len(args) == 0:
1117 handle_kwarg(self, kwargs, 'ip')
1118 handle_kwarg(self, kwargs, 'port')
1119
1120 elif len(args) == 1:
1121 if kwargs:
1122 if not 'ip' in kwargs and not 'port' in kwargs:
1123 raise TypeError, "Invalid arguments"
1124 handle_kwarg(self, kwargs, 'ip', args[0])
1125 handle_kwarg(self, kwargs, 'port', args[0])
1126 elif isinstance(args[0], IpWithPort):
1127 self.ip = args[0].ip
1128 self.port = args[0].port
1129 else:
1130 (self.ip, self.port) = convert.toIpWithPort(args[0])
1131
1132 elif len(args) == 2:
1133 self.ip = args[0]
1134 self.port = args[1]
1135 else:
1136 raise TypeError, "Too many arguments specified"
1137
1138 if kwargs:
1139 raise TypeError, "Too many keywords: %s" % kwargs.keys()
1140
1141 self.verify()
1142
1143 def __call__(self, value):
1144 self.__init__(value)
1145 return value
1146
1147 def __str__(self):
1148 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1149
1150 def __eq__(self, other):
1151 if isinstance(other, IpWithPort):
1152 return self.ip == other.ip and self.port == other.port
1153 elif isinstance(other, str):
1154 try:
1155 return (self.ip, self.port) == convert.toIpWithPort(other)
1156 except:
1157 return False
1158 else:
1159 return False
1160
1161 def verify(self):
1162 self.verifyIp()
1163 if self.port < 0 or self.port > 0xffff:
1164 raise TypeError, "invalid port %d" % self.port
1165
1166 def getValue(self):
1167 from m5.internal.params import IpWithPort
1168 return IpWithPort(self.ip, self.port)
1169
1170time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1171 "%a %b %d %H:%M:%S %Y",
1172 "%Y/%m/%d %H:%M:%S",
1173 "%Y/%m/%d %H:%M",
1174 "%Y/%m/%d",
1175 "%m/%d/%Y %H:%M:%S",
1176 "%m/%d/%Y %H:%M",
1177 "%m/%d/%Y",
1178 "%m/%d/%y %H:%M:%S",
1179 "%m/%d/%y %H:%M",
1180 "%m/%d/%y"]
1181
1182
1183def parse_time(value):
1184 from time import gmtime, strptime, struct_time, time
1185 from datetime import datetime, date
1186
1187 if isinstance(value, struct_time):
1188 return value
1189
1190 if isinstance(value, (int, long)):
1191 return gmtime(value)
1192
1193 if isinstance(value, (datetime, date)):
1194 return value.timetuple()
1195
1196 if isinstance(value, str):
1197 if value in ('Now', 'Today'):
1198 return time.gmtime(time.time())
1199
1200 for format in time_formats:
1201 try:
1202 return strptime(value, format)
1203 except ValueError:
1204 pass
1205
1206 raise ValueError, "Could not parse '%s' as a time" % value
1207
1208class Time(ParamValue):
1209 cxx_type = 'tm'
1210
1211 @classmethod
1212 def cxx_predecls(cls, code):
1213 code('#include <time.h>')
1214
1215 @classmethod
1216 def swig_predecls(cls, code):
1217 code('%include "python/swig/time.i"')
1218
1219 def __init__(self, value):
1220 self.value = parse_time(value)
1221
1222 def __call__(self, value):
1223 self.__init__(value)
1224 return value
1225
1226 def getValue(self):
1227 from m5.internal.params import tm
1228
1229 c_time = tm()
1230 py_time = self.value
1231
1232 # UNIX is years since 1900
1233 c_time.tm_year = py_time.tm_year - 1900;
1234
1235 # Python starts at 1, UNIX starts at 0
1236 c_time.tm_mon = py_time.tm_mon - 1;
1237 c_time.tm_mday = py_time.tm_mday;
1238 c_time.tm_hour = py_time.tm_hour;
1239 c_time.tm_min = py_time.tm_min;
1240 c_time.tm_sec = py_time.tm_sec;
1241
1242 # Python has 0 as Monday, UNIX is 0 as sunday
1243 c_time.tm_wday = py_time.tm_wday + 1
1244 if c_time.tm_wday > 6:
1245 c_time.tm_wday -= 7;
1246
1247 # Python starts at 1, Unix starts at 0
1248 c_time.tm_yday = py_time.tm_yday - 1;
1249
1250 return c_time
1251
1252 def __str__(self):
1253 return time.asctime(self.value)
1254
1255 def ini_str(self):
1256 return str(self)
1257
1258 def get_config_as_dict(self):
1259 assert false
1260 return str(self)
1261
1262 @classmethod
1263 def cxx_ini_predecls(cls, code):
1264 code('#include <time.h>')
1265
1266 @classmethod
1267 def cxx_ini_parse(cls, code, src, dest, ret):
1268 code('char *_parse_ret = strptime((${src}).c_str(),')
1269 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1270 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1271
1272# Enumerated types are a little more complex. The user specifies the
1273# type as Enum(foo) where foo is either a list or dictionary of
1274# alternatives (typically strings, but not necessarily so). (In the
1275# long run, the integer value of the parameter will be the list index
1276# or the corresponding dictionary value. For now, since we only check
1277# that the alternative is valid and then spit it into a .ini file,
1278# there's not much point in using the dictionary.)
1279
1280# What Enum() must do is generate a new type encapsulating the
1281# provided list/dictionary so that specific values of the parameter
1282# can be instances of that type. We define two hidden internal
1283# classes (_ListEnum and _DictEnum) to serve as base classes, then
1284# derive the new type from the appropriate base class on the fly.
1285
1286allEnums = {}
1287# Metaclass for Enum types
1288class MetaEnum(MetaParamValue):
1289 def __new__(mcls, name, bases, dict):
1290 assert name not in allEnums
1291
1292 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1293 allEnums[name] = cls
1294 return cls
1295
1296 def __init__(cls, name, bases, init_dict):
1297 if init_dict.has_key('map'):
1298 if not isinstance(cls.map, dict):
1299 raise TypeError, "Enum-derived class attribute 'map' " \
1300 "must be of type dict"
1301 # build list of value strings from map
1302 cls.vals = cls.map.keys()
1303 cls.vals.sort()
1304 elif init_dict.has_key('vals'):
1305 if not isinstance(cls.vals, list):
1306 raise TypeError, "Enum-derived class attribute 'vals' " \
1307 "must be of type list"
1308 # build string->value map from vals sequence
1309 cls.map = {}
1310 for idx,val in enumerate(cls.vals):
1311 cls.map[val] = idx
1312 else:
1313 raise TypeError, "Enum-derived class must define "\
1314 "attribute 'map' or 'vals'"
1315
1316 cls.cxx_type = 'Enums::%s' % name
1317
1318 super(MetaEnum, cls).__init__(name, bases, init_dict)
1319
1320 # Generate C++ class declaration for this enum type.
1321 # Note that we wrap the enum in a class/struct to act as a namespace,
1322 # so that the enum strings can be brief w/o worrying about collisions.
1323 def cxx_decl(cls, code):
1324 wrapper_name = cls.wrapper_name
1325 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1326 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1327 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1328
1329 code('''\
1330#ifndef $idem_macro
1331#define $idem_macro
1332
1333$wrapper $wrapper_name {
1334 enum $name {
1335''')
1336 code.indent(2)
1337 for val in cls.vals:
1338 code('$val = ${{cls.map[val]}},')
1339 code('Num_$name = ${{len(cls.vals)}}')
1340 code.dedent(2)
1341 code(' };')
1342
1343 if cls.wrapper_is_struct:
1344 code(' static const char *${name}Strings[Num_${name}];')
1345 code('};')
1346 else:
1347 code('extern const char *${name}Strings[Num_${name}];')
1348 code('}')
1349
1350 code()
1351 code('#endif // $idem_macro')
1352
1353 def cxx_def(cls, code):
1354 wrapper_name = cls.wrapper_name
1355 file_name = cls.__name__
1356 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1357
1358 code('#include "enums/$file_name.hh"')
1359 if cls.wrapper_is_struct:
1360 code('const char *${wrapper_name}::${name}Strings'
1361 '[Num_${name}] =')
1362 else:
1363 code('namespace Enums {')
1364 code.indent(1)
1365 code(' const char *${name}Strings[Num_${name}] =')
1366
1367 code('{')
1368 code.indent(1)
1369 for val in cls.vals:
1370 code('"$val",')
1371 code.dedent(1)
1372 code('};')
1373
1374 if not cls.wrapper_is_struct:
1375 code('} // namespace $wrapper_name')
1376 code.dedent(1)
1377
1378 def swig_decl(cls, code):
1379 name = cls.__name__
1380 code('''\
1381%module(package="m5.internal") enum_$name
1381%module(package="_m5") enum_$name
1382
1383%{
1384#include "enums/$name.hh"
1385%}
1386
1387%include "enums/$name.hh"
1388''')
1389
1390
1391# Base class for enum types.
1392class Enum(ParamValue):
1393 __metaclass__ = MetaEnum
1394 vals = []
1395 cmd_line_settable = True
1396
1397 # The name of the wrapping namespace or struct
1398 wrapper_name = 'Enums'
1399
1400 # If true, the enum is wrapped in a struct rather than a namespace
1401 wrapper_is_struct = False
1402
1403 # If not None, use this as the enum name rather than this class name
1404 enum_name = None
1405
1406 def __init__(self, value):
1407 if value not in self.map:
1408 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1409 % (value, self.vals)
1410 self.value = value
1411
1412 def __call__(self, value):
1413 self.__init__(value)
1414 return value
1415
1416 @classmethod
1417 def cxx_predecls(cls, code):
1418 code('#include "enums/$0.hh"', cls.__name__)
1419
1420 @classmethod
1421 def swig_predecls(cls, code):
1382
1383%{
1384#include "enums/$name.hh"
1385%}
1386
1387%include "enums/$name.hh"
1388''')
1389
1390
1391# Base class for enum types.
1392class Enum(ParamValue):
1393 __metaclass__ = MetaEnum
1394 vals = []
1395 cmd_line_settable = True
1396
1397 # The name of the wrapping namespace or struct
1398 wrapper_name = 'Enums'
1399
1400 # If true, the enum is wrapped in a struct rather than a namespace
1401 wrapper_is_struct = False
1402
1403 # If not None, use this as the enum name rather than this class name
1404 enum_name = None
1405
1406 def __init__(self, value):
1407 if value not in self.map:
1408 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1409 % (value, self.vals)
1410 self.value = value
1411
1412 def __call__(self, value):
1413 self.__init__(value)
1414 return value
1415
1416 @classmethod
1417 def cxx_predecls(cls, code):
1418 code('#include "enums/$0.hh"', cls.__name__)
1419
1420 @classmethod
1421 def swig_predecls(cls, code):
1422 code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1422 code('%import "python/_m5/enum_$0.i"', cls.__name__)
1423
1424 @classmethod
1425 def cxx_ini_parse(cls, code, src, dest, ret):
1426 code('if (false) {')
1427 for elem_name in cls.map.iterkeys():
1428 code('} else if (%s == "%s") {' % (src, elem_name))
1429 code.indent()
1430 code('%s = Enums::%s;' % (dest, elem_name))
1431 code('%s true;' % ret)
1432 code.dedent()
1433 code('} else {')
1434 code(' %s false;' % ret)
1435 code('}')
1436
1437 def getValue(self):
1438 return int(self.map[self.value])
1439
1440 def __str__(self):
1441 return self.value
1442
1443# how big does a rounding error need to be before we warn about it?
1444frequency_tolerance = 0.001 # 0.1%
1445
1446class TickParamValue(NumericParamValue):
1447 cxx_type = 'Tick'
1448 ex_str = "1MHz"
1449 cmd_line_settable = True
1450
1451 @classmethod
1452 def cxx_predecls(cls, code):
1453 code('#include "base/types.hh"')
1454
1455 @classmethod
1456 def swig_predecls(cls, code):
1457 code('%import "stdint.i"')
1458 code('%import "base/types.hh"')
1459
1460 def __call__(self, value):
1461 self.__init__(value)
1462 return value
1463
1464 def getValue(self):
1465 return long(self.value)
1466
1467 @classmethod
1468 def cxx_ini_predecls(cls, code):
1469 code('#include <sstream>')
1470
1471 # Ticks are expressed in seconds in JSON files and in plain
1472 # Ticks in .ini files. Switch based on a config flag
1473 @classmethod
1474 def cxx_ini_parse(self, code, src, dest, ret):
1475 code('${ret} to_number(${src}, ${dest});')
1476
1477class Latency(TickParamValue):
1478 ex_str = "100ns"
1479
1480 def __init__(self, value):
1481 if isinstance(value, (Latency, Clock)):
1482 self.ticks = value.ticks
1483 self.value = value.value
1484 elif isinstance(value, Frequency):
1485 self.ticks = value.ticks
1486 self.value = 1.0 / value.value
1487 elif value.endswith('t'):
1488 self.ticks = True
1489 self.value = int(value[:-1])
1490 else:
1491 self.ticks = False
1492 self.value = convert.toLatency(value)
1493
1494 def __call__(self, value):
1495 self.__init__(value)
1496 return value
1497
1498 def __getattr__(self, attr):
1499 if attr in ('latency', 'period'):
1500 return self
1501 if attr == 'frequency':
1502 return Frequency(self)
1503 raise AttributeError, "Latency object has no attribute '%s'" % attr
1504
1505 def getValue(self):
1506 if self.ticks or self.value == 0:
1507 value = self.value
1508 else:
1509 value = ticks.fromSeconds(self.value)
1510 return long(value)
1511
1512 def config_value(self):
1513 return self.getValue()
1514
1515 # convert latency to ticks
1516 def ini_str(self):
1517 return '%d' % self.getValue()
1518
1519class Frequency(TickParamValue):
1520 ex_str = "1GHz"
1521
1522 def __init__(self, value):
1523 if isinstance(value, (Latency, Clock)):
1524 if value.value == 0:
1525 self.value = 0
1526 else:
1527 self.value = 1.0 / value.value
1528 self.ticks = value.ticks
1529 elif isinstance(value, Frequency):
1530 self.value = value.value
1531 self.ticks = value.ticks
1532 else:
1533 self.ticks = False
1534 self.value = convert.toFrequency(value)
1535
1536 def __call__(self, value):
1537 self.__init__(value)
1538 return value
1539
1540 def __getattr__(self, attr):
1541 if attr == 'frequency':
1542 return self
1543 if attr in ('latency', 'period'):
1544 return Latency(self)
1545 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1546
1547 # convert latency to ticks
1548 def getValue(self):
1549 if self.ticks or self.value == 0:
1550 value = self.value
1551 else:
1552 value = ticks.fromSeconds(1.0 / self.value)
1553 return long(value)
1554
1555 def config_value(self):
1556 return self.getValue()
1557
1558 def ini_str(self):
1559 return '%d' % self.getValue()
1560
1561# A generic Frequency and/or Latency value. Value is stored as a
1562# latency, just like Latency and Frequency.
1563class Clock(TickParamValue):
1564 def __init__(self, value):
1565 if isinstance(value, (Latency, Clock)):
1566 self.ticks = value.ticks
1567 self.value = value.value
1568 elif isinstance(value, Frequency):
1569 self.ticks = value.ticks
1570 self.value = 1.0 / value.value
1571 elif value.endswith('t'):
1572 self.ticks = True
1573 self.value = int(value[:-1])
1574 else:
1575 self.ticks = False
1576 self.value = convert.anyToLatency(value)
1577
1578 def __call__(self, value):
1579 self.__init__(value)
1580 return value
1581
1582 def __str__(self):
1583 return "%s" % Latency(self)
1584
1585 def __getattr__(self, attr):
1586 if attr == 'frequency':
1587 return Frequency(self)
1588 if attr in ('latency', 'period'):
1589 return Latency(self)
1590 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1591
1592 def getValue(self):
1593 return self.period.getValue()
1594
1595 def config_value(self):
1596 return self.period.config_value()
1597
1598 def ini_str(self):
1599 return self.period.ini_str()
1600
1601class Voltage(float,ParamValue):
1602 cxx_type = 'double'
1603 ex_str = "1V"
1604 cmd_line_settable = True
1605
1606 def __new__(cls, value):
1607 # convert to voltage
1608 val = convert.toVoltage(value)
1609 return super(cls, Voltage).__new__(cls, val)
1610
1611 def __call__(self, value):
1612 val = convert.toVoltage(value)
1613 self.__init__(val)
1614 return value
1615
1616 def __str__(self):
1617 return str(self.getValue())
1618
1619 def getValue(self):
1620 value = float(self)
1621 return value
1622
1623 def ini_str(self):
1624 return '%f' % self.getValue()
1625
1626 @classmethod
1627 def cxx_ini_predecls(cls, code):
1628 code('#include <sstream>')
1629
1630 @classmethod
1631 def cxx_ini_parse(self, code, src, dest, ret):
1632 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1633
1634class Current(float, ParamValue):
1635 cxx_type = 'double'
1636 ex_str = "1mA"
1637 cmd_line_settable = False
1638
1639 def __new__(cls, value):
1640 # convert to current
1641 val = convert.toCurrent(value)
1642 return super(cls, Current).__new__(cls, val)
1643
1644 def __call__(self, value):
1645 val = convert.toCurrent(value)
1646 self.__init__(val)
1647 return value
1648
1649 def __str__(self):
1650 return str(self.getValue())
1651
1652 def getValue(self):
1653 value = float(self)
1654 return value
1655
1656 def ini_str(self):
1657 return '%f' % self.getValue()
1658
1659 @classmethod
1660 def cxx_ini_predecls(cls, code):
1661 code('#include <sstream>')
1662
1663 @classmethod
1664 def cxx_ini_parse(self, code, src, dest, ret):
1665 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1666
1667class NetworkBandwidth(float,ParamValue):
1668 cxx_type = 'float'
1669 ex_str = "1Gbps"
1670 cmd_line_settable = True
1671
1672 def __new__(cls, value):
1673 # convert to bits per second
1674 val = convert.toNetworkBandwidth(value)
1675 return super(cls, NetworkBandwidth).__new__(cls, val)
1676
1677 def __str__(self):
1678 return str(self.val)
1679
1680 def __call__(self, value):
1681 val = convert.toNetworkBandwidth(value)
1682 self.__init__(val)
1683 return value
1684
1685 def getValue(self):
1686 # convert to seconds per byte
1687 value = 8.0 / float(self)
1688 # convert to ticks per byte
1689 value = ticks.fromSeconds(value)
1690 return float(value)
1691
1692 def ini_str(self):
1693 return '%f' % self.getValue()
1694
1695 def config_value(self):
1696 return '%f' % self.getValue()
1697
1698 @classmethod
1699 def cxx_ini_predecls(cls, code):
1700 code('#include <sstream>')
1701
1702 @classmethod
1703 def cxx_ini_parse(self, code, src, dest, ret):
1704 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1705
1706class MemoryBandwidth(float,ParamValue):
1707 cxx_type = 'float'
1708 ex_str = "1GB/s"
1709 cmd_line_settable = True
1710
1711 def __new__(cls, value):
1712 # convert to bytes per second
1713 val = convert.toMemoryBandwidth(value)
1714 return super(cls, MemoryBandwidth).__new__(cls, val)
1715
1716 def __call__(self, value):
1717 val = convert.toMemoryBandwidth(value)
1718 self.__init__(val)
1719 return value
1720
1721 def getValue(self):
1722 # convert to seconds per byte
1723 value = float(self)
1724 if value:
1725 value = 1.0 / float(self)
1726 # convert to ticks per byte
1727 value = ticks.fromSeconds(value)
1728 return float(value)
1729
1730 def ini_str(self):
1731 return '%f' % self.getValue()
1732
1733 def config_value(self):
1734 return '%f' % self.getValue()
1735
1736 @classmethod
1737 def cxx_ini_predecls(cls, code):
1738 code('#include <sstream>')
1739
1740 @classmethod
1741 def cxx_ini_parse(self, code, src, dest, ret):
1742 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1743
1744#
1745# "Constants"... handy aliases for various values.
1746#
1747
1748# Special class for NULL pointers. Note the special check in
1749# make_param_value() above that lets these be assigned where a
1750# SimObject is required.
1751# only one copy of a particular node
1752class NullSimObject(object):
1753 __metaclass__ = Singleton
1754
1755 def __call__(cls):
1756 return cls
1757
1758 def _instantiate(self, parent = None, path = ''):
1759 pass
1760
1761 def ini_str(self):
1762 return 'Null'
1763
1764 def unproxy(self, base):
1765 return self
1766
1767 def set_path(self, parent, name):
1768 pass
1769
1770 def __str__(self):
1771 return 'Null'
1772
1773 def config_value(self):
1774 return None
1775
1776 def getValue(self):
1777 return None
1778
1779# The only instance you'll ever need...
1780NULL = NullSimObject()
1781
1782def isNullPointer(value):
1783 return isinstance(value, NullSimObject)
1784
1785# Some memory range specifications use this as a default upper bound.
1786MaxAddr = Addr.max
1787MaxTick = Tick.max
1788AllMemory = AddrRange(0, MaxAddr)
1789
1790
1791#####################################################################
1792#
1793# Port objects
1794#
1795# Ports are used to interconnect objects in the memory system.
1796#
1797#####################################################################
1798
1799# Port reference: encapsulates a reference to a particular port on a
1800# particular SimObject.
1801class PortRef(object):
1802 def __init__(self, simobj, name, role):
1803 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1804 self.simobj = simobj
1805 self.name = name
1806 self.role = role
1807 self.peer = None # not associated with another port yet
1808 self.ccConnected = False # C++ port connection done?
1809 self.index = -1 # always -1 for non-vector ports
1810
1811 def __str__(self):
1812 return '%s.%s' % (self.simobj, self.name)
1813
1814 def __len__(self):
1815 # Return the number of connected ports, i.e. 0 is we have no
1816 # peer and 1 if we do.
1817 return int(self.peer != None)
1818
1819 # for config.ini, print peer's name (not ours)
1820 def ini_str(self):
1821 return str(self.peer)
1822
1823 # for config.json
1824 def get_config_as_dict(self):
1825 return {'role' : self.role, 'peer' : str(self.peer)}
1826
1827 def __getattr__(self, attr):
1828 if attr == 'peerObj':
1829 # shorthand for proxies
1830 return self.peer.simobj
1831 raise AttributeError, "'%s' object has no attribute '%s'" % \
1832 (self.__class__.__name__, attr)
1833
1834 # Full connection is symmetric (both ways). Called via
1835 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1836 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1837 # e.g., "obj1.portA[3] = obj2.portB".
1838 def connect(self, other):
1839 if isinstance(other, VectorPortRef):
1840 # reference to plain VectorPort is implicit append
1841 other = other._get_next()
1842 if self.peer and not proxy.isproxy(self.peer):
1843 fatal("Port %s is already connected to %s, cannot connect %s\n",
1844 self, self.peer, other);
1845 self.peer = other
1846 if proxy.isproxy(other):
1847 other.set_param_desc(PortParamDesc())
1848 elif isinstance(other, PortRef):
1849 if other.peer is not self:
1850 other.connect(self)
1851 else:
1852 raise TypeError, \
1853 "assigning non-port reference '%s' to port '%s'" \
1854 % (other, self)
1855
1856 # Allow a master/slave port pair to be spliced between
1857 # a port and its connected peer. Useful operation for connecting
1858 # instrumentation structures into a system when it is necessary
1859 # to connect the instrumentation after the full system has been
1860 # constructed.
1861 def splice(self, new_master_peer, new_slave_peer):
1862 if self.peer and not proxy.isproxy(self.peer):
1863 if isinstance(new_master_peer, PortRef) and \
1864 isinstance(new_slave_peer, PortRef):
1865 old_peer = self.peer
1866 if self.role == 'SLAVE':
1867 self.peer = new_master_peer
1868 old_peer.peer = new_slave_peer
1869 new_master_peer.connect(self)
1870 new_slave_peer.connect(old_peer)
1871 elif self.role == 'MASTER':
1872 self.peer = new_slave_peer
1873 old_peer.peer = new_master_peer
1874 new_slave_peer.connect(self)
1875 new_master_peer.connect(old_peer)
1876 else:
1877 panic("Port %s has unknown role, "+\
1878 "cannot splice in new peers\n", self)
1879 else:
1880 raise TypeError, \
1881 "Splicing non-port references '%s','%s' to port '%s'"\
1882 % (new_peer, peers_new_peer, self)
1883 else:
1884 fatal("Port %s not connected, cannot splice in new peers\n", self)
1885
1886 def clone(self, simobj, memo):
1887 if memo.has_key(self):
1888 return memo[self]
1889 newRef = copy.copy(self)
1890 memo[self] = newRef
1891 newRef.simobj = simobj
1892 assert(isSimObject(newRef.simobj))
1893 if self.peer and not proxy.isproxy(self.peer):
1894 peerObj = self.peer.simobj(_memo=memo)
1895 newRef.peer = self.peer.clone(peerObj, memo)
1896 assert(not isinstance(newRef.peer, VectorPortRef))
1897 return newRef
1898
1899 def unproxy(self, simobj):
1900 assert(simobj is self.simobj)
1901 if proxy.isproxy(self.peer):
1902 try:
1903 realPeer = self.peer.unproxy(self.simobj)
1904 except:
1905 print "Error in unproxying port '%s' of %s" % \
1906 (self.name, self.simobj.path())
1907 raise
1908 self.connect(realPeer)
1909
1910 # Call C++ to create corresponding port connection between C++ objects
1911 def ccConnect(self):
1423
1424 @classmethod
1425 def cxx_ini_parse(cls, code, src, dest, ret):
1426 code('if (false) {')
1427 for elem_name in cls.map.iterkeys():
1428 code('} else if (%s == "%s") {' % (src, elem_name))
1429 code.indent()
1430 code('%s = Enums::%s;' % (dest, elem_name))
1431 code('%s true;' % ret)
1432 code.dedent()
1433 code('} else {')
1434 code(' %s false;' % ret)
1435 code('}')
1436
1437 def getValue(self):
1438 return int(self.map[self.value])
1439
1440 def __str__(self):
1441 return self.value
1442
1443# how big does a rounding error need to be before we warn about it?
1444frequency_tolerance = 0.001 # 0.1%
1445
1446class TickParamValue(NumericParamValue):
1447 cxx_type = 'Tick'
1448 ex_str = "1MHz"
1449 cmd_line_settable = True
1450
1451 @classmethod
1452 def cxx_predecls(cls, code):
1453 code('#include "base/types.hh"')
1454
1455 @classmethod
1456 def swig_predecls(cls, code):
1457 code('%import "stdint.i"')
1458 code('%import "base/types.hh"')
1459
1460 def __call__(self, value):
1461 self.__init__(value)
1462 return value
1463
1464 def getValue(self):
1465 return long(self.value)
1466
1467 @classmethod
1468 def cxx_ini_predecls(cls, code):
1469 code('#include <sstream>')
1470
1471 # Ticks are expressed in seconds in JSON files and in plain
1472 # Ticks in .ini files. Switch based on a config flag
1473 @classmethod
1474 def cxx_ini_parse(self, code, src, dest, ret):
1475 code('${ret} to_number(${src}, ${dest});')
1476
1477class Latency(TickParamValue):
1478 ex_str = "100ns"
1479
1480 def __init__(self, value):
1481 if isinstance(value, (Latency, Clock)):
1482 self.ticks = value.ticks
1483 self.value = value.value
1484 elif isinstance(value, Frequency):
1485 self.ticks = value.ticks
1486 self.value = 1.0 / value.value
1487 elif value.endswith('t'):
1488 self.ticks = True
1489 self.value = int(value[:-1])
1490 else:
1491 self.ticks = False
1492 self.value = convert.toLatency(value)
1493
1494 def __call__(self, value):
1495 self.__init__(value)
1496 return value
1497
1498 def __getattr__(self, attr):
1499 if attr in ('latency', 'period'):
1500 return self
1501 if attr == 'frequency':
1502 return Frequency(self)
1503 raise AttributeError, "Latency object has no attribute '%s'" % attr
1504
1505 def getValue(self):
1506 if self.ticks or self.value == 0:
1507 value = self.value
1508 else:
1509 value = ticks.fromSeconds(self.value)
1510 return long(value)
1511
1512 def config_value(self):
1513 return self.getValue()
1514
1515 # convert latency to ticks
1516 def ini_str(self):
1517 return '%d' % self.getValue()
1518
1519class Frequency(TickParamValue):
1520 ex_str = "1GHz"
1521
1522 def __init__(self, value):
1523 if isinstance(value, (Latency, Clock)):
1524 if value.value == 0:
1525 self.value = 0
1526 else:
1527 self.value = 1.0 / value.value
1528 self.ticks = value.ticks
1529 elif isinstance(value, Frequency):
1530 self.value = value.value
1531 self.ticks = value.ticks
1532 else:
1533 self.ticks = False
1534 self.value = convert.toFrequency(value)
1535
1536 def __call__(self, value):
1537 self.__init__(value)
1538 return value
1539
1540 def __getattr__(self, attr):
1541 if attr == 'frequency':
1542 return self
1543 if attr in ('latency', 'period'):
1544 return Latency(self)
1545 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1546
1547 # convert latency to ticks
1548 def getValue(self):
1549 if self.ticks or self.value == 0:
1550 value = self.value
1551 else:
1552 value = ticks.fromSeconds(1.0 / self.value)
1553 return long(value)
1554
1555 def config_value(self):
1556 return self.getValue()
1557
1558 def ini_str(self):
1559 return '%d' % self.getValue()
1560
1561# A generic Frequency and/or Latency value. Value is stored as a
1562# latency, just like Latency and Frequency.
1563class Clock(TickParamValue):
1564 def __init__(self, value):
1565 if isinstance(value, (Latency, Clock)):
1566 self.ticks = value.ticks
1567 self.value = value.value
1568 elif isinstance(value, Frequency):
1569 self.ticks = value.ticks
1570 self.value = 1.0 / value.value
1571 elif value.endswith('t'):
1572 self.ticks = True
1573 self.value = int(value[:-1])
1574 else:
1575 self.ticks = False
1576 self.value = convert.anyToLatency(value)
1577
1578 def __call__(self, value):
1579 self.__init__(value)
1580 return value
1581
1582 def __str__(self):
1583 return "%s" % Latency(self)
1584
1585 def __getattr__(self, attr):
1586 if attr == 'frequency':
1587 return Frequency(self)
1588 if attr in ('latency', 'period'):
1589 return Latency(self)
1590 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1591
1592 def getValue(self):
1593 return self.period.getValue()
1594
1595 def config_value(self):
1596 return self.period.config_value()
1597
1598 def ini_str(self):
1599 return self.period.ini_str()
1600
1601class Voltage(float,ParamValue):
1602 cxx_type = 'double'
1603 ex_str = "1V"
1604 cmd_line_settable = True
1605
1606 def __new__(cls, value):
1607 # convert to voltage
1608 val = convert.toVoltage(value)
1609 return super(cls, Voltage).__new__(cls, val)
1610
1611 def __call__(self, value):
1612 val = convert.toVoltage(value)
1613 self.__init__(val)
1614 return value
1615
1616 def __str__(self):
1617 return str(self.getValue())
1618
1619 def getValue(self):
1620 value = float(self)
1621 return value
1622
1623 def ini_str(self):
1624 return '%f' % self.getValue()
1625
1626 @classmethod
1627 def cxx_ini_predecls(cls, code):
1628 code('#include <sstream>')
1629
1630 @classmethod
1631 def cxx_ini_parse(self, code, src, dest, ret):
1632 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1633
1634class Current(float, ParamValue):
1635 cxx_type = 'double'
1636 ex_str = "1mA"
1637 cmd_line_settable = False
1638
1639 def __new__(cls, value):
1640 # convert to current
1641 val = convert.toCurrent(value)
1642 return super(cls, Current).__new__(cls, val)
1643
1644 def __call__(self, value):
1645 val = convert.toCurrent(value)
1646 self.__init__(val)
1647 return value
1648
1649 def __str__(self):
1650 return str(self.getValue())
1651
1652 def getValue(self):
1653 value = float(self)
1654 return value
1655
1656 def ini_str(self):
1657 return '%f' % self.getValue()
1658
1659 @classmethod
1660 def cxx_ini_predecls(cls, code):
1661 code('#include <sstream>')
1662
1663 @classmethod
1664 def cxx_ini_parse(self, code, src, dest, ret):
1665 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1666
1667class NetworkBandwidth(float,ParamValue):
1668 cxx_type = 'float'
1669 ex_str = "1Gbps"
1670 cmd_line_settable = True
1671
1672 def __new__(cls, value):
1673 # convert to bits per second
1674 val = convert.toNetworkBandwidth(value)
1675 return super(cls, NetworkBandwidth).__new__(cls, val)
1676
1677 def __str__(self):
1678 return str(self.val)
1679
1680 def __call__(self, value):
1681 val = convert.toNetworkBandwidth(value)
1682 self.__init__(val)
1683 return value
1684
1685 def getValue(self):
1686 # convert to seconds per byte
1687 value = 8.0 / float(self)
1688 # convert to ticks per byte
1689 value = ticks.fromSeconds(value)
1690 return float(value)
1691
1692 def ini_str(self):
1693 return '%f' % self.getValue()
1694
1695 def config_value(self):
1696 return '%f' % self.getValue()
1697
1698 @classmethod
1699 def cxx_ini_predecls(cls, code):
1700 code('#include <sstream>')
1701
1702 @classmethod
1703 def cxx_ini_parse(self, code, src, dest, ret):
1704 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1705
1706class MemoryBandwidth(float,ParamValue):
1707 cxx_type = 'float'
1708 ex_str = "1GB/s"
1709 cmd_line_settable = True
1710
1711 def __new__(cls, value):
1712 # convert to bytes per second
1713 val = convert.toMemoryBandwidth(value)
1714 return super(cls, MemoryBandwidth).__new__(cls, val)
1715
1716 def __call__(self, value):
1717 val = convert.toMemoryBandwidth(value)
1718 self.__init__(val)
1719 return value
1720
1721 def getValue(self):
1722 # convert to seconds per byte
1723 value = float(self)
1724 if value:
1725 value = 1.0 / float(self)
1726 # convert to ticks per byte
1727 value = ticks.fromSeconds(value)
1728 return float(value)
1729
1730 def ini_str(self):
1731 return '%f' % self.getValue()
1732
1733 def config_value(self):
1734 return '%f' % self.getValue()
1735
1736 @classmethod
1737 def cxx_ini_predecls(cls, code):
1738 code('#include <sstream>')
1739
1740 @classmethod
1741 def cxx_ini_parse(self, code, src, dest, ret):
1742 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1743
1744#
1745# "Constants"... handy aliases for various values.
1746#
1747
1748# Special class for NULL pointers. Note the special check in
1749# make_param_value() above that lets these be assigned where a
1750# SimObject is required.
1751# only one copy of a particular node
1752class NullSimObject(object):
1753 __metaclass__ = Singleton
1754
1755 def __call__(cls):
1756 return cls
1757
1758 def _instantiate(self, parent = None, path = ''):
1759 pass
1760
1761 def ini_str(self):
1762 return 'Null'
1763
1764 def unproxy(self, base):
1765 return self
1766
1767 def set_path(self, parent, name):
1768 pass
1769
1770 def __str__(self):
1771 return 'Null'
1772
1773 def config_value(self):
1774 return None
1775
1776 def getValue(self):
1777 return None
1778
1779# The only instance you'll ever need...
1780NULL = NullSimObject()
1781
1782def isNullPointer(value):
1783 return isinstance(value, NullSimObject)
1784
1785# Some memory range specifications use this as a default upper bound.
1786MaxAddr = Addr.max
1787MaxTick = Tick.max
1788AllMemory = AddrRange(0, MaxAddr)
1789
1790
1791#####################################################################
1792#
1793# Port objects
1794#
1795# Ports are used to interconnect objects in the memory system.
1796#
1797#####################################################################
1798
1799# Port reference: encapsulates a reference to a particular port on a
1800# particular SimObject.
1801class PortRef(object):
1802 def __init__(self, simobj, name, role):
1803 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1804 self.simobj = simobj
1805 self.name = name
1806 self.role = role
1807 self.peer = None # not associated with another port yet
1808 self.ccConnected = False # C++ port connection done?
1809 self.index = -1 # always -1 for non-vector ports
1810
1811 def __str__(self):
1812 return '%s.%s' % (self.simobj, self.name)
1813
1814 def __len__(self):
1815 # Return the number of connected ports, i.e. 0 is we have no
1816 # peer and 1 if we do.
1817 return int(self.peer != None)
1818
1819 # for config.ini, print peer's name (not ours)
1820 def ini_str(self):
1821 return str(self.peer)
1822
1823 # for config.json
1824 def get_config_as_dict(self):
1825 return {'role' : self.role, 'peer' : str(self.peer)}
1826
1827 def __getattr__(self, attr):
1828 if attr == 'peerObj':
1829 # shorthand for proxies
1830 return self.peer.simobj
1831 raise AttributeError, "'%s' object has no attribute '%s'" % \
1832 (self.__class__.__name__, attr)
1833
1834 # Full connection is symmetric (both ways). Called via
1835 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1836 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1837 # e.g., "obj1.portA[3] = obj2.portB".
1838 def connect(self, other):
1839 if isinstance(other, VectorPortRef):
1840 # reference to plain VectorPort is implicit append
1841 other = other._get_next()
1842 if self.peer and not proxy.isproxy(self.peer):
1843 fatal("Port %s is already connected to %s, cannot connect %s\n",
1844 self, self.peer, other);
1845 self.peer = other
1846 if proxy.isproxy(other):
1847 other.set_param_desc(PortParamDesc())
1848 elif isinstance(other, PortRef):
1849 if other.peer is not self:
1850 other.connect(self)
1851 else:
1852 raise TypeError, \
1853 "assigning non-port reference '%s' to port '%s'" \
1854 % (other, self)
1855
1856 # Allow a master/slave port pair to be spliced between
1857 # a port and its connected peer. Useful operation for connecting
1858 # instrumentation structures into a system when it is necessary
1859 # to connect the instrumentation after the full system has been
1860 # constructed.
1861 def splice(self, new_master_peer, new_slave_peer):
1862 if self.peer and not proxy.isproxy(self.peer):
1863 if isinstance(new_master_peer, PortRef) and \
1864 isinstance(new_slave_peer, PortRef):
1865 old_peer = self.peer
1866 if self.role == 'SLAVE':
1867 self.peer = new_master_peer
1868 old_peer.peer = new_slave_peer
1869 new_master_peer.connect(self)
1870 new_slave_peer.connect(old_peer)
1871 elif self.role == 'MASTER':
1872 self.peer = new_slave_peer
1873 old_peer.peer = new_master_peer
1874 new_slave_peer.connect(self)
1875 new_master_peer.connect(old_peer)
1876 else:
1877 panic("Port %s has unknown role, "+\
1878 "cannot splice in new peers\n", self)
1879 else:
1880 raise TypeError, \
1881 "Splicing non-port references '%s','%s' to port '%s'"\
1882 % (new_peer, peers_new_peer, self)
1883 else:
1884 fatal("Port %s not connected, cannot splice in new peers\n", self)
1885
1886 def clone(self, simobj, memo):
1887 if memo.has_key(self):
1888 return memo[self]
1889 newRef = copy.copy(self)
1890 memo[self] = newRef
1891 newRef.simobj = simobj
1892 assert(isSimObject(newRef.simobj))
1893 if self.peer and not proxy.isproxy(self.peer):
1894 peerObj = self.peer.simobj(_memo=memo)
1895 newRef.peer = self.peer.clone(peerObj, memo)
1896 assert(not isinstance(newRef.peer, VectorPortRef))
1897 return newRef
1898
1899 def unproxy(self, simobj):
1900 assert(simobj is self.simobj)
1901 if proxy.isproxy(self.peer):
1902 try:
1903 realPeer = self.peer.unproxy(self.simobj)
1904 except:
1905 print "Error in unproxying port '%s' of %s" % \
1906 (self.name, self.simobj.path())
1907 raise
1908 self.connect(realPeer)
1909
1910 # Call C++ to create corresponding port connection between C++ objects
1911 def ccConnect(self):
1912 from m5.internal.pyobject import connectPorts
1912 from _m5.pyobject import connectPorts
1913
1914 if self.role == 'SLAVE':
1915 # do nothing and let the master take care of it
1916 return
1917
1918 if self.ccConnected: # already done this
1919 return
1920 peer = self.peer
1921 if not self.peer: # nothing to connect to
1922 return
1923
1924 # check that we connect a master to a slave
1925 if self.role == peer.role:
1926 raise TypeError, \
1927 "cannot connect '%s' and '%s' due to identical role '%s'" \
1928 % (peer, self, self.role)
1929
1930 try:
1931 # self is always the master and peer the slave
1932 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1933 peer.simobj.getCCObject(), peer.name, peer.index)
1934 except:
1935 print "Error connecting port %s.%s to %s.%s" % \
1936 (self.simobj.path(), self.name,
1937 peer.simobj.path(), peer.name)
1938 raise
1939 self.ccConnected = True
1940 peer.ccConnected = True
1941
1942# A reference to an individual element of a VectorPort... much like a
1943# PortRef, but has an index.
1944class VectorPortElementRef(PortRef):
1945 def __init__(self, simobj, name, role, index):
1946 PortRef.__init__(self, simobj, name, role)
1947 self.index = index
1948
1949 def __str__(self):
1950 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1951
1952# A reference to a complete vector-valued port (not just a single element).
1953# Can be indexed to retrieve individual VectorPortElementRef instances.
1954class VectorPortRef(object):
1955 def __init__(self, simobj, name, role):
1956 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1957 self.simobj = simobj
1958 self.name = name
1959 self.role = role
1960 self.elements = []
1961
1962 def __str__(self):
1963 return '%s.%s[:]' % (self.simobj, self.name)
1964
1965 def __len__(self):
1966 # Return the number of connected peers, corresponding the the
1967 # length of the elements.
1968 return len(self.elements)
1969
1970 # for config.ini, print peer's name (not ours)
1971 def ini_str(self):
1972 return ' '.join([el.ini_str() for el in self.elements])
1973
1974 # for config.json
1975 def get_config_as_dict(self):
1976 return {'role' : self.role,
1977 'peer' : [el.ini_str() for el in self.elements]}
1978
1979 def __getitem__(self, key):
1980 if not isinstance(key, int):
1981 raise TypeError, "VectorPort index must be integer"
1982 if key >= len(self.elements):
1983 # need to extend list
1984 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1985 for i in range(len(self.elements), key+1)]
1986 self.elements.extend(ext)
1987 return self.elements[key]
1988
1989 def _get_next(self):
1990 return self[len(self.elements)]
1991
1992 def __setitem__(self, key, value):
1993 if not isinstance(key, int):
1994 raise TypeError, "VectorPort index must be integer"
1995 self[key].connect(value)
1996
1997 def connect(self, other):
1998 if isinstance(other, (list, tuple)):
1999 # Assign list of port refs to vector port.
2000 # For now, append them... not sure if that's the right semantics
2001 # or if it should replace the current vector.
2002 for ref in other:
2003 self._get_next().connect(ref)
2004 else:
2005 # scalar assignment to plain VectorPort is implicit append
2006 self._get_next().connect(other)
2007
2008 def clone(self, simobj, memo):
2009 if memo.has_key(self):
2010 return memo[self]
2011 newRef = copy.copy(self)
2012 memo[self] = newRef
2013 newRef.simobj = simobj
2014 assert(isSimObject(newRef.simobj))
2015 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2016 return newRef
2017
2018 def unproxy(self, simobj):
2019 [el.unproxy(simobj) for el in self.elements]
2020
2021 def ccConnect(self):
2022 [el.ccConnect() for el in self.elements]
2023
2024# Port description object. Like a ParamDesc object, this represents a
2025# logical port in the SimObject class, not a particular port on a
2026# SimObject instance. The latter are represented by PortRef objects.
2027class Port(object):
2028 # Generate a PortRef for this port on the given SimObject with the
2029 # given name
2030 def makeRef(self, simobj):
2031 return PortRef(simobj, self.name, self.role)
2032
2033 # Connect an instance of this port (on the given SimObject with
2034 # the given name) with the port described by the supplied PortRef
2035 def connect(self, simobj, ref):
2036 self.makeRef(simobj).connect(ref)
2037
2038 # No need for any pre-declarations at the moment as we merely rely
2039 # on an unsigned int.
2040 def cxx_predecls(self, code):
2041 pass
2042
2043 # Declare an unsigned int with the same name as the port, that
2044 # will eventually hold the number of connected ports (and thus the
2045 # number of elements for a VectorPort).
2046 def cxx_decl(self, code):
2047 code('unsigned int port_${{self.name}}_connection_count;')
2048
2049class MasterPort(Port):
2050 # MasterPort("description")
2051 def __init__(self, *args):
2052 if len(args) == 1:
2053 self.desc = args[0]
2054 self.role = 'MASTER'
2055 else:
2056 raise TypeError, 'wrong number of arguments'
2057
2058class SlavePort(Port):
2059 # SlavePort("description")
2060 def __init__(self, *args):
2061 if len(args) == 1:
2062 self.desc = args[0]
2063 self.role = 'SLAVE'
2064 else:
2065 raise TypeError, 'wrong number of arguments'
2066
2067# VectorPort description object. Like Port, but represents a vector
2068# of connections (e.g., as on a XBar).
2069class VectorPort(Port):
2070 def __init__(self, *args):
2071 self.isVec = True
2072
2073 def makeRef(self, simobj):
2074 return VectorPortRef(simobj, self.name, self.role)
2075
2076class VectorMasterPort(VectorPort):
2077 # VectorMasterPort("description")
2078 def __init__(self, *args):
2079 if len(args) == 1:
2080 self.desc = args[0]
2081 self.role = 'MASTER'
2082 VectorPort.__init__(self, *args)
2083 else:
2084 raise TypeError, 'wrong number of arguments'
2085
2086class VectorSlavePort(VectorPort):
2087 # VectorSlavePort("description")
2088 def __init__(self, *args):
2089 if len(args) == 1:
2090 self.desc = args[0]
2091 self.role = 'SLAVE'
2092 VectorPort.__init__(self, *args)
2093 else:
2094 raise TypeError, 'wrong number of arguments'
2095
2096# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2097# proxy objects (via set_param_desc()) so that proxy error messages
2098# make sense.
2099class PortParamDesc(object):
2100 __metaclass__ = Singleton
2101
2102 ptype_str = 'Port'
2103 ptype = Port
2104
2105baseEnums = allEnums.copy()
2106baseParams = allParams.copy()
2107
2108def clear():
2109 global allEnums, allParams
2110
2111 allEnums = baseEnums.copy()
2112 allParams = baseParams.copy()
2113
2114__all__ = ['Param', 'VectorParam',
2115 'Enum', 'Bool', 'String', 'Float',
2116 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2117 'Int32', 'UInt32', 'Int64', 'UInt64',
2118 'Counter', 'Addr', 'Tick', 'Percent',
2119 'TcpPort', 'UdpPort', 'EthernetAddr',
2120 'IpAddress', 'IpNetmask', 'IpWithPort',
2121 'MemorySize', 'MemorySize32',
2122 'Latency', 'Frequency', 'Clock', 'Voltage',
2123 'NetworkBandwidth', 'MemoryBandwidth',
2124 'AddrRange',
2125 'MaxAddr', 'MaxTick', 'AllMemory',
2126 'Time',
2127 'NextEthernetAddr', 'NULL',
2128 'MasterPort', 'SlavePort',
2129 'VectorMasterPort', 'VectorSlavePort']
2130
2131import SimObject
1913
1914 if self.role == 'SLAVE':
1915 # do nothing and let the master take care of it
1916 return
1917
1918 if self.ccConnected: # already done this
1919 return
1920 peer = self.peer
1921 if not self.peer: # nothing to connect to
1922 return
1923
1924 # check that we connect a master to a slave
1925 if self.role == peer.role:
1926 raise TypeError, \
1927 "cannot connect '%s' and '%s' due to identical role '%s'" \
1928 % (peer, self, self.role)
1929
1930 try:
1931 # self is always the master and peer the slave
1932 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1933 peer.simobj.getCCObject(), peer.name, peer.index)
1934 except:
1935 print "Error connecting port %s.%s to %s.%s" % \
1936 (self.simobj.path(), self.name,
1937 peer.simobj.path(), peer.name)
1938 raise
1939 self.ccConnected = True
1940 peer.ccConnected = True
1941
1942# A reference to an individual element of a VectorPort... much like a
1943# PortRef, but has an index.
1944class VectorPortElementRef(PortRef):
1945 def __init__(self, simobj, name, role, index):
1946 PortRef.__init__(self, simobj, name, role)
1947 self.index = index
1948
1949 def __str__(self):
1950 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1951
1952# A reference to a complete vector-valued port (not just a single element).
1953# Can be indexed to retrieve individual VectorPortElementRef instances.
1954class VectorPortRef(object):
1955 def __init__(self, simobj, name, role):
1956 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1957 self.simobj = simobj
1958 self.name = name
1959 self.role = role
1960 self.elements = []
1961
1962 def __str__(self):
1963 return '%s.%s[:]' % (self.simobj, self.name)
1964
1965 def __len__(self):
1966 # Return the number of connected peers, corresponding the the
1967 # length of the elements.
1968 return len(self.elements)
1969
1970 # for config.ini, print peer's name (not ours)
1971 def ini_str(self):
1972 return ' '.join([el.ini_str() for el in self.elements])
1973
1974 # for config.json
1975 def get_config_as_dict(self):
1976 return {'role' : self.role,
1977 'peer' : [el.ini_str() for el in self.elements]}
1978
1979 def __getitem__(self, key):
1980 if not isinstance(key, int):
1981 raise TypeError, "VectorPort index must be integer"
1982 if key >= len(self.elements):
1983 # need to extend list
1984 ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1985 for i in range(len(self.elements), key+1)]
1986 self.elements.extend(ext)
1987 return self.elements[key]
1988
1989 def _get_next(self):
1990 return self[len(self.elements)]
1991
1992 def __setitem__(self, key, value):
1993 if not isinstance(key, int):
1994 raise TypeError, "VectorPort index must be integer"
1995 self[key].connect(value)
1996
1997 def connect(self, other):
1998 if isinstance(other, (list, tuple)):
1999 # Assign list of port refs to vector port.
2000 # For now, append them... not sure if that's the right semantics
2001 # or if it should replace the current vector.
2002 for ref in other:
2003 self._get_next().connect(ref)
2004 else:
2005 # scalar assignment to plain VectorPort is implicit append
2006 self._get_next().connect(other)
2007
2008 def clone(self, simobj, memo):
2009 if memo.has_key(self):
2010 return memo[self]
2011 newRef = copy.copy(self)
2012 memo[self] = newRef
2013 newRef.simobj = simobj
2014 assert(isSimObject(newRef.simobj))
2015 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2016 return newRef
2017
2018 def unproxy(self, simobj):
2019 [el.unproxy(simobj) for el in self.elements]
2020
2021 def ccConnect(self):
2022 [el.ccConnect() for el in self.elements]
2023
2024# Port description object. Like a ParamDesc object, this represents a
2025# logical port in the SimObject class, not a particular port on a
2026# SimObject instance. The latter are represented by PortRef objects.
2027class Port(object):
2028 # Generate a PortRef for this port on the given SimObject with the
2029 # given name
2030 def makeRef(self, simobj):
2031 return PortRef(simobj, self.name, self.role)
2032
2033 # Connect an instance of this port (on the given SimObject with
2034 # the given name) with the port described by the supplied PortRef
2035 def connect(self, simobj, ref):
2036 self.makeRef(simobj).connect(ref)
2037
2038 # No need for any pre-declarations at the moment as we merely rely
2039 # on an unsigned int.
2040 def cxx_predecls(self, code):
2041 pass
2042
2043 # Declare an unsigned int with the same name as the port, that
2044 # will eventually hold the number of connected ports (and thus the
2045 # number of elements for a VectorPort).
2046 def cxx_decl(self, code):
2047 code('unsigned int port_${{self.name}}_connection_count;')
2048
2049class MasterPort(Port):
2050 # MasterPort("description")
2051 def __init__(self, *args):
2052 if len(args) == 1:
2053 self.desc = args[0]
2054 self.role = 'MASTER'
2055 else:
2056 raise TypeError, 'wrong number of arguments'
2057
2058class SlavePort(Port):
2059 # SlavePort("description")
2060 def __init__(self, *args):
2061 if len(args) == 1:
2062 self.desc = args[0]
2063 self.role = 'SLAVE'
2064 else:
2065 raise TypeError, 'wrong number of arguments'
2066
2067# VectorPort description object. Like Port, but represents a vector
2068# of connections (e.g., as on a XBar).
2069class VectorPort(Port):
2070 def __init__(self, *args):
2071 self.isVec = True
2072
2073 def makeRef(self, simobj):
2074 return VectorPortRef(simobj, self.name, self.role)
2075
2076class VectorMasterPort(VectorPort):
2077 # VectorMasterPort("description")
2078 def __init__(self, *args):
2079 if len(args) == 1:
2080 self.desc = args[0]
2081 self.role = 'MASTER'
2082 VectorPort.__init__(self, *args)
2083 else:
2084 raise TypeError, 'wrong number of arguments'
2085
2086class VectorSlavePort(VectorPort):
2087 # VectorSlavePort("description")
2088 def __init__(self, *args):
2089 if len(args) == 1:
2090 self.desc = args[0]
2091 self.role = 'SLAVE'
2092 VectorPort.__init__(self, *args)
2093 else:
2094 raise TypeError, 'wrong number of arguments'
2095
2096# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2097# proxy objects (via set_param_desc()) so that proxy error messages
2098# make sense.
2099class PortParamDesc(object):
2100 __metaclass__ = Singleton
2101
2102 ptype_str = 'Port'
2103 ptype = Port
2104
2105baseEnums = allEnums.copy()
2106baseParams = allParams.copy()
2107
2108def clear():
2109 global allEnums, allParams
2110
2111 allEnums = baseEnums.copy()
2112 allParams = baseParams.copy()
2113
2114__all__ = ['Param', 'VectorParam',
2115 'Enum', 'Bool', 'String', 'Float',
2116 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2117 'Int32', 'UInt32', 'Int64', 'UInt64',
2118 'Counter', 'Addr', 'Tick', 'Percent',
2119 'TcpPort', 'UdpPort', 'EthernetAddr',
2120 'IpAddress', 'IpNetmask', 'IpWithPort',
2121 'MemorySize', 'MemorySize32',
2122 'Latency', 'Frequency', 'Clock', 'Voltage',
2123 'NetworkBandwidth', 'MemoryBandwidth',
2124 'AddrRange',
2125 'MaxAddr', 'MaxTick', 'AllMemory',
2126 'Time',
2127 'NextEthernetAddr', 'NULL',
2128 'MasterPort', 'SlavePort',
2129 'VectorMasterPort', 'VectorSlavePort']
2130
2131import SimObject