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