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