params.py (7675:2221ec64132f) params.py (7677:c6e283904437)
1# Copyright (c) 2004-2006 The Regents of The University of Michigan
2# Copyright (c) 2010 Advanced Micro Devices, Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28# Authors: Steve Reinhardt
29# Nathan Binkert
30
31#####################################################################
32#
33# Parameter description classes
34#
35# The _params dictionary in each class maps parameter names to either
36# a Param or a VectorParam object. These objects contain the
37# parameter description string, the parameter type, and the default
38# value (if any). The convert() method on these objects is used to
39# force whatever value is assigned to the parameter to the appropriate
40# type.
41#
42# Note that the default values are loaded into the class's attribute
43# space when the parameter dictionary is initialized (in
44# MetaSimObject._new_param()); after that point they aren't used.
45#
46#####################################################################
47
48import copy
49import datetime
50import re
51import sys
52import time
53import math
54
55import proxy
56import ticks
57from util import *
58
59def isSimObject(*args, **kwargs):
60 return SimObject.isSimObject(*args, **kwargs)
61
62def isSimObjectSequence(*args, **kwargs):
63 return SimObject.isSimObjectSequence(*args, **kwargs)
64
65def isSimObjectClass(*args, **kwargs):
66 return SimObject.isSimObjectClass(*args, **kwargs)
67
68allParams = {}
69
70class MetaParamValue(type):
71 def __new__(mcls, name, bases, dct):
72 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
73 assert name not in allParams
74 allParams[name] = cls
75 return cls
76
77
78# Dummy base class to identify types that are legitimate for SimObject
79# parameters.
80class ParamValue(object):
81 __metaclass__ = MetaParamValue
82
83 @classmethod
84 def cxx_predecls(cls, code):
85 pass
86
87 @classmethod
88 def swig_predecls(cls, code):
89 pass
90
91 # default for printing to .ini file is regular string conversion.
92 # will be overridden in some cases
93 def ini_str(self):
94 return str(self)
95
96 # allows us to blithely call unproxy() on things without checking
97 # if they're really proxies or not
98 def unproxy(self, base):
99 return self
100
101# Regular parameter description.
102class ParamDesc(object):
103 file_ext = 'ptype'
104
105 def __init__(self, ptype_str, ptype, *args, **kwargs):
106 self.ptype_str = ptype_str
107 # remember ptype only if it is provided
108 if ptype != None:
109 self.ptype = ptype
110
111 if args:
112 if len(args) == 1:
113 self.desc = args[0]
114 elif len(args) == 2:
115 self.default = args[0]
116 self.desc = args[1]
117 else:
118 raise TypeError, 'too many arguments'
119
120 if kwargs.has_key('desc'):
121 assert(not hasattr(self, 'desc'))
122 self.desc = kwargs['desc']
123 del kwargs['desc']
124
125 if kwargs.has_key('default'):
126 assert(not hasattr(self, 'default'))
127 self.default = kwargs['default']
128 del kwargs['default']
129
130 if kwargs:
131 raise TypeError, 'extra unknown kwargs %s' % kwargs
132
133 if not hasattr(self, 'desc'):
134 raise TypeError, 'desc attribute missing'
135
136 def __getattr__(self, attr):
137 if attr == 'ptype':
138 ptype = SimObject.allClasses[self.ptype_str]
139 assert isSimObjectClass(ptype)
140 self.ptype = ptype
141 return ptype
142
143 raise AttributeError, "'%s' object has no attribute '%s'" % \
144 (type(self).__name__, attr)
145
146 def convert(self, value):
147 if isinstance(value, proxy.BaseProxy):
148 value.set_param_desc(self)
149 return value
150 if not hasattr(self, 'ptype') and isNullPointer(value):
151 # deferred evaluation of SimObject; continue to defer if
152 # we're just assigning a null pointer
153 return value
154 if isinstance(value, self.ptype):
155 return value
156 if isNullPointer(value) and isSimObjectClass(self.ptype):
157 return value
158 return self.ptype(value)
159
160 def cxx_predecls(self, code):
161 self.ptype.cxx_predecls(code)
162
163 def swig_predecls(self, code):
164 self.ptype.swig_predecls(code)
165
166 def cxx_decl(self, code):
167 code('${{self.ptype.cxx_type}} ${{self.name}};')
168
169# Vector-valued parameter description. Just like ParamDesc, except
170# that the value is a vector (list) of the specified type instead of a
171# single value.
172
173class VectorParamValue(list):
174 __metaclass__ = MetaParamValue
175 def __setattr__(self, attr, value):
176 raise AttributeError, \
177 "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
178
179 def ini_str(self):
180 return ' '.join([v.ini_str() for v in self])
181
182 def getValue(self):
183 return [ v.getValue() for v in self ]
184
185 def unproxy(self, base):
186 return [v.unproxy(base) for v in self]
187
188class SimObjectVector(VectorParamValue):
189 # support clone operation
190 def __call__(self, **kwargs):
191 return SimObjectVector([v(**kwargs) for v in self])
192
193 def clear_parent(self, old_parent):
194 for v in self:
195 v.clear_parent(old_parent)
196
197 def set_parent(self, parent, name):
198 if len(self) == 1:
199 self[0].set_parent(parent, name)
200 else:
201 width = int(math.ceil(math.log(len(self))/math.log(10)))
202 for i,v in enumerate(self):
203 v.set_parent(parent, "%s%0*d" % (name, width, i))
204
205 def get_parent(self):
206 parent_set = set(v._parent for v in self)
207 if len(parent_set) != 1:
208 raise RuntimeError, \
209 "SimObjectVector elements have inconsistent parent value."
210 return parent_set.pop()
211
212 # return 'cpu0 cpu1' etc. for print_ini()
213 def get_name(self):
214 return ' '.join([v._name for v in self])
215
216 # By iterating through the constituent members of the vector here
217 # we can nicely handle iterating over all a SimObject's children
218 # without having to provide lots of special functions on
219 # SimObjectVector directly.
220 def descendants(self):
221 for v in self:
222 for obj in v.descendants():
223 yield obj
224
225class VectorParamDesc(ParamDesc):
226 file_ext = 'vptype'
227
228 # Convert assigned value to appropriate type. If the RHS is not a
229 # list or tuple, it generates a single-element list.
230 def convert(self, value):
231 if isinstance(value, (list, tuple)):
232 # list: coerce each element into new list
233 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
234 else:
235 # singleton: coerce to a single-element list
236 tmp_list = [ ParamDesc.convert(self, value) ]
237
238 if isSimObjectSequence(tmp_list):
239 return SimObjectVector(tmp_list)
240 else:
241 return VectorParamValue(tmp_list)
242
243 def swig_predecls(self, code):
1# Copyright (c) 2004-2006 The Regents of The University of Michigan
2# Copyright (c) 2010 Advanced Micro Devices, Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28# Authors: Steve Reinhardt
29# Nathan Binkert
30
31#####################################################################
32#
33# Parameter description classes
34#
35# The _params dictionary in each class maps parameter names to either
36# a Param or a VectorParam object. These objects contain the
37# parameter description string, the parameter type, and the default
38# value (if any). The convert() method on these objects is used to
39# force whatever value is assigned to the parameter to the appropriate
40# type.
41#
42# Note that the default values are loaded into the class's attribute
43# space when the parameter dictionary is initialized (in
44# MetaSimObject._new_param()); after that point they aren't used.
45#
46#####################################################################
47
48import copy
49import datetime
50import re
51import sys
52import time
53import math
54
55import proxy
56import ticks
57from util import *
58
59def isSimObject(*args, **kwargs):
60 return SimObject.isSimObject(*args, **kwargs)
61
62def isSimObjectSequence(*args, **kwargs):
63 return SimObject.isSimObjectSequence(*args, **kwargs)
64
65def isSimObjectClass(*args, **kwargs):
66 return SimObject.isSimObjectClass(*args, **kwargs)
67
68allParams = {}
69
70class MetaParamValue(type):
71 def __new__(mcls, name, bases, dct):
72 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
73 assert name not in allParams
74 allParams[name] = cls
75 return cls
76
77
78# Dummy base class to identify types that are legitimate for SimObject
79# parameters.
80class ParamValue(object):
81 __metaclass__ = MetaParamValue
82
83 @classmethod
84 def cxx_predecls(cls, code):
85 pass
86
87 @classmethod
88 def swig_predecls(cls, code):
89 pass
90
91 # default for printing to .ini file is regular string conversion.
92 # will be overridden in some cases
93 def ini_str(self):
94 return str(self)
95
96 # allows us to blithely call unproxy() on things without checking
97 # if they're really proxies or not
98 def unproxy(self, base):
99 return self
100
101# Regular parameter description.
102class ParamDesc(object):
103 file_ext = 'ptype'
104
105 def __init__(self, ptype_str, ptype, *args, **kwargs):
106 self.ptype_str = ptype_str
107 # remember ptype only if it is provided
108 if ptype != None:
109 self.ptype = ptype
110
111 if args:
112 if len(args) == 1:
113 self.desc = args[0]
114 elif len(args) == 2:
115 self.default = args[0]
116 self.desc = args[1]
117 else:
118 raise TypeError, 'too many arguments'
119
120 if kwargs.has_key('desc'):
121 assert(not hasattr(self, 'desc'))
122 self.desc = kwargs['desc']
123 del kwargs['desc']
124
125 if kwargs.has_key('default'):
126 assert(not hasattr(self, 'default'))
127 self.default = kwargs['default']
128 del kwargs['default']
129
130 if kwargs:
131 raise TypeError, 'extra unknown kwargs %s' % kwargs
132
133 if not hasattr(self, 'desc'):
134 raise TypeError, 'desc attribute missing'
135
136 def __getattr__(self, attr):
137 if attr == 'ptype':
138 ptype = SimObject.allClasses[self.ptype_str]
139 assert isSimObjectClass(ptype)
140 self.ptype = ptype
141 return ptype
142
143 raise AttributeError, "'%s' object has no attribute '%s'" % \
144 (type(self).__name__, attr)
145
146 def convert(self, value):
147 if isinstance(value, proxy.BaseProxy):
148 value.set_param_desc(self)
149 return value
150 if not hasattr(self, 'ptype') and isNullPointer(value):
151 # deferred evaluation of SimObject; continue to defer if
152 # we're just assigning a null pointer
153 return value
154 if isinstance(value, self.ptype):
155 return value
156 if isNullPointer(value) and isSimObjectClass(self.ptype):
157 return value
158 return self.ptype(value)
159
160 def cxx_predecls(self, code):
161 self.ptype.cxx_predecls(code)
162
163 def swig_predecls(self, code):
164 self.ptype.swig_predecls(code)
165
166 def cxx_decl(self, code):
167 code('${{self.ptype.cxx_type}} ${{self.name}};')
168
169# Vector-valued parameter description. Just like ParamDesc, except
170# that the value is a vector (list) of the specified type instead of a
171# single value.
172
173class VectorParamValue(list):
174 __metaclass__ = MetaParamValue
175 def __setattr__(self, attr, value):
176 raise AttributeError, \
177 "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
178
179 def ini_str(self):
180 return ' '.join([v.ini_str() for v in self])
181
182 def getValue(self):
183 return [ v.getValue() for v in self ]
184
185 def unproxy(self, base):
186 return [v.unproxy(base) for v in self]
187
188class SimObjectVector(VectorParamValue):
189 # support clone operation
190 def __call__(self, **kwargs):
191 return SimObjectVector([v(**kwargs) for v in self])
192
193 def clear_parent(self, old_parent):
194 for v in self:
195 v.clear_parent(old_parent)
196
197 def set_parent(self, parent, name):
198 if len(self) == 1:
199 self[0].set_parent(parent, name)
200 else:
201 width = int(math.ceil(math.log(len(self))/math.log(10)))
202 for i,v in enumerate(self):
203 v.set_parent(parent, "%s%0*d" % (name, width, i))
204
205 def get_parent(self):
206 parent_set = set(v._parent for v in self)
207 if len(parent_set) != 1:
208 raise RuntimeError, \
209 "SimObjectVector elements have inconsistent parent value."
210 return parent_set.pop()
211
212 # return 'cpu0 cpu1' etc. for print_ini()
213 def get_name(self):
214 return ' '.join([v._name for v in self])
215
216 # By iterating through the constituent members of the vector here
217 # we can nicely handle iterating over all a SimObject's children
218 # without having to provide lots of special functions on
219 # SimObjectVector directly.
220 def descendants(self):
221 for v in self:
222 for obj in v.descendants():
223 yield obj
224
225class VectorParamDesc(ParamDesc):
226 file_ext = 'vptype'
227
228 # Convert assigned value to appropriate type. If the RHS is not a
229 # list or tuple, it generates a single-element list.
230 def convert(self, value):
231 if isinstance(value, (list, tuple)):
232 # list: coerce each element into new list
233 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
234 else:
235 # singleton: coerce to a single-element list
236 tmp_list = [ ParamDesc.convert(self, value) ]
237
238 if isSimObjectSequence(tmp_list):
239 return SimObjectVector(tmp_list)
240 else:
241 return VectorParamValue(tmp_list)
242
243 def swig_predecls(self, code):
244 code('%import "${{self.ptype_str}}_vptype.i"')
244 code('%import "vptype_${{self.ptype_str}}.i"')
245
246 def swig_decl(self, code):
247 code('%{')
248 self.ptype.cxx_predecls(code)
249 code('%}')
250 code()
251 self.ptype.swig_predecls(code)
252 code()
253 code('%include "std_vector.i"')
254 code()
255
256 ptype = self.ptype_str
257 cxx_type = self.ptype.cxx_type
258
259 code('''\
260%typemap(in) std::vector< $cxx_type >::value_type {
261 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
262 if (SWIG_ConvertPtr($$input, (void **)&$$1,
263 $$descriptor($cxx_type), 0) == -1) {
264 return NULL;
265 }
266 }
267}
268
269%typemap(in) std::vector< $cxx_type >::value_type * {
270 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
271 if (SWIG_ConvertPtr($$input, (void **)&$$1,
272 $$descriptor($cxx_type *), 0) == -1) {
273 return NULL;
274 }
275 }
276}
277''')
278
279 code('%template(vector_$ptype) std::vector< $cxx_type >;')
280
281 def cxx_predecls(self, code):
282 code('#include <vector>')
283 self.ptype.cxx_predecls(code)
284
285 def cxx_decl(self, code):
286 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
287
288class ParamFactory(object):
289 def __init__(self, param_desc_class, ptype_str = None):
290 self.param_desc_class = param_desc_class
291 self.ptype_str = ptype_str
292
293 def __getattr__(self, attr):
294 if self.ptype_str:
295 attr = self.ptype_str + '.' + attr
296 return ParamFactory(self.param_desc_class, attr)
297
298 # E.g., Param.Int(5, "number of widgets")
299 def __call__(self, *args, **kwargs):
300 ptype = None
301 try:
302 ptype = allParams[self.ptype_str]
303 except KeyError:
304 # if name isn't defined yet, assume it's a SimObject, and
305 # try to resolve it later
306 pass
307 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
308
309Param = ParamFactory(ParamDesc)
310VectorParam = ParamFactory(VectorParamDesc)
311
312#####################################################################
313#
314# Parameter Types
315#
316# Though native Python types could be used to specify parameter types
317# (the 'ptype' field of the Param and VectorParam classes), it's more
318# flexible to define our own set of types. This gives us more control
319# over how Python expressions are converted to values (via the
320# __init__() constructor) and how these values are printed out (via
321# the __str__() conversion method).
322#
323#####################################################################
324
325# String-valued parameter. Just mixin the ParamValue class with the
326# built-in str class.
327class String(ParamValue,str):
328 cxx_type = 'std::string'
329
330 @classmethod
331 def cxx_predecls(self, code):
332 code('#include <string>')
333
334 @classmethod
335 def swig_predecls(cls, code):
336 code('%include "std_string.i"')
337
338 def getValue(self):
339 return self
340
341# superclass for "numeric" parameter values, to emulate math
342# operations in a type-safe way. e.g., a Latency times an int returns
343# a new Latency object.
344class NumericParamValue(ParamValue):
345 def __str__(self):
346 return str(self.value)
347
348 def __float__(self):
349 return float(self.value)
350
351 def __long__(self):
352 return long(self.value)
353
354 def __int__(self):
355 return int(self.value)
356
357 # hook for bounds checking
358 def _check(self):
359 return
360
361 def __mul__(self, other):
362 newobj = self.__class__(self)
363 newobj.value *= other
364 newobj._check()
365 return newobj
366
367 __rmul__ = __mul__
368
369 def __div__(self, other):
370 newobj = self.__class__(self)
371 newobj.value /= other
372 newobj._check()
373 return newobj
374
375 def __sub__(self, other):
376 newobj = self.__class__(self)
377 newobj.value -= other
378 newobj._check()
379 return newobj
380
381# Metaclass for bounds-checked integer parameters. See CheckedInt.
382class CheckedIntType(MetaParamValue):
383 def __init__(cls, name, bases, dict):
384 super(CheckedIntType, cls).__init__(name, bases, dict)
385
386 # CheckedInt is an abstract base class, so we actually don't
387 # want to do any processing on it... the rest of this code is
388 # just for classes that derive from CheckedInt.
389 if name == 'CheckedInt':
390 return
391
392 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
393 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
394 panic("CheckedInt subclass %s must define either\n" \
395 " 'min' and 'max' or 'size' and 'unsigned'\n",
396 name);
397 if cls.unsigned:
398 cls.min = 0
399 cls.max = 2 ** cls.size - 1
400 else:
401 cls.min = -(2 ** (cls.size - 1))
402 cls.max = (2 ** (cls.size - 1)) - 1
403
404# Abstract superclass for bounds-checked integer parameters. This
405# class is subclassed to generate parameter classes with specific
406# bounds. Initialization of the min and max bounds is done in the
407# metaclass CheckedIntType.__init__.
408class CheckedInt(NumericParamValue):
409 __metaclass__ = CheckedIntType
410
411 def _check(self):
412 if not self.min <= self.value <= self.max:
413 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
414 (self.min, self.value, self.max)
415
416 def __init__(self, value):
417 if isinstance(value, str):
418 self.value = convert.toInteger(value)
419 elif isinstance(value, (int, long, float, NumericParamValue)):
420 self.value = long(value)
421 else:
422 raise TypeError, "Can't convert object of type %s to CheckedInt" \
423 % type(value).__name__
424 self._check()
425
426 @classmethod
427 def cxx_predecls(cls, code):
428 # most derived types require this, so we just do it here once
429 code('#include "base/types.hh"')
430
431 @classmethod
432 def swig_predecls(cls, code):
433 # most derived types require this, so we just do it here once
434 code('%import "stdint.i"')
435 code('%import "base/types.hh"')
436
437 def getValue(self):
438 return long(self.value)
439
440class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
441class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
442
443class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
444class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
445class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
446class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
447class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
448class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
449class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
450class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
451
452class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
453class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
454class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
455class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
456
457class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
458
459class Float(ParamValue, float):
460 cxx_type = 'double'
461
462 def __init__(self, value):
463 if isinstance(value, (int, long, float, NumericParamValue, Float)):
464 self.value = float(value)
465 else:
466 raise TypeError, "Can't convert object of type %s to Float" \
467 % type(value).__name__
468
469 def getValue(self):
470 return float(self.value)
471
472class MemorySize(CheckedInt):
473 cxx_type = 'uint64_t'
474 size = 64
475 unsigned = True
476 def __init__(self, value):
477 if isinstance(value, MemorySize):
478 self.value = value.value
479 else:
480 self.value = convert.toMemorySize(value)
481 self._check()
482
483class MemorySize32(CheckedInt):
484 cxx_type = 'uint32_t'
485 size = 32
486 unsigned = True
487 def __init__(self, value):
488 if isinstance(value, MemorySize):
489 self.value = value.value
490 else:
491 self.value = convert.toMemorySize(value)
492 self._check()
493
494class Addr(CheckedInt):
495 cxx_type = 'Addr'
496 size = 64
497 unsigned = True
498 def __init__(self, value):
499 if isinstance(value, Addr):
500 self.value = value.value
501 else:
502 try:
503 self.value = convert.toMemorySize(value)
504 except TypeError:
505 self.value = long(value)
506 self._check()
507 def __add__(self, other):
508 if isinstance(other, Addr):
509 return self.value + other.value
510 else:
511 return self.value + other
512
513
514class MetaRange(MetaParamValue):
515 def __init__(cls, name, bases, dict):
516 super(MetaRange, cls).__init__(name, bases, dict)
517 if name == 'Range':
518 return
519 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
520
521class Range(ParamValue):
522 __metaclass__ = MetaRange
523 type = Int # default; can be overridden in subclasses
524 def __init__(self, *args, **kwargs):
525 def handle_kwargs(self, kwargs):
526 if 'end' in kwargs:
527 self.second = self.type(kwargs.pop('end'))
528 elif 'size' in kwargs:
529 self.second = self.first + self.type(kwargs.pop('size')) - 1
530 else:
531 raise TypeError, "Either end or size must be specified"
532
533 if len(args) == 0:
534 self.first = self.type(kwargs.pop('start'))
535 handle_kwargs(self, kwargs)
536
537 elif len(args) == 1:
538 if kwargs:
539 self.first = self.type(args[0])
540 handle_kwargs(self, kwargs)
541 elif isinstance(args[0], Range):
542 self.first = self.type(args[0].first)
543 self.second = self.type(args[0].second)
544 elif isinstance(args[0], (list, tuple)):
545 self.first = self.type(args[0][0])
546 self.second = self.type(args[0][1])
547 else:
548 self.first = self.type(0)
549 self.second = self.type(args[0]) - 1
550
551 elif len(args) == 2:
552 self.first = self.type(args[0])
553 self.second = self.type(args[1])
554 else:
555 raise TypeError, "Too many arguments specified"
556
557 if kwargs:
558 raise TypeError, "too many keywords: %s" % kwargs.keys()
559
560 def __str__(self):
561 return '%s:%s' % (self.first, self.second)
562
563 @classmethod
564 def cxx_predecls(cls, code):
565 cls.type.cxx_predecls(code)
566 code('#include "base/range.hh"')
567
568 @classmethod
569 def swig_predecls(cls, code):
570 cls.type.swig_predecls(code)
571 code('%import "python/swig/range.i"')
572
573class AddrRange(Range):
574 type = Addr
575
576 def getValue(self):
577 from m5.internal.range import AddrRange
578
579 value = AddrRange()
580 value.start = long(self.first)
581 value.end = long(self.second)
582 return value
583
584class TickRange(Range):
585 type = Tick
586
587 def getValue(self):
588 from m5.internal.range import TickRange
589
590 value = TickRange()
591 value.start = long(self.first)
592 value.end = long(self.second)
593 return value
594
595# Boolean parameter type. Python doesn't let you subclass bool, since
596# it doesn't want to let you create multiple instances of True and
597# False. Thus this is a little more complicated than String.
598class Bool(ParamValue):
599 cxx_type = 'bool'
600 def __init__(self, value):
601 try:
602 self.value = convert.toBool(value)
603 except TypeError:
604 self.value = bool(value)
605
606 def getValue(self):
607 return bool(self.value)
608
609 def __str__(self):
610 return str(self.value)
611
612 def ini_str(self):
613 if self.value:
614 return 'true'
615 return 'false'
616
617def IncEthernetAddr(addr, val = 1):
618 bytes = map(lambda x: int(x, 16), addr.split(':'))
619 bytes[5] += val
620 for i in (5, 4, 3, 2, 1):
621 val,rem = divmod(bytes[i], 256)
622 bytes[i] = rem
623 if val == 0:
624 break
625 bytes[i - 1] += val
626 assert(bytes[0] <= 255)
627 return ':'.join(map(lambda x: '%02x' % x, bytes))
628
629_NextEthernetAddr = "00:90:00:00:00:01"
630def NextEthernetAddr():
631 global _NextEthernetAddr
632
633 value = _NextEthernetAddr
634 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
635 return value
636
637class EthernetAddr(ParamValue):
638 cxx_type = 'Net::EthAddr'
639
640 @classmethod
641 def cxx_predecls(cls, code):
642 code('#include "base/inet.hh"')
643
644 @classmethod
645 def swig_predecls(cls, code):
646 code('%include "python/swig/inet.i"')
647
648 def __init__(self, value):
649 if value == NextEthernetAddr:
650 self.value = value
651 return
652
653 if not isinstance(value, str):
654 raise TypeError, "expected an ethernet address and didn't get one"
655
656 bytes = value.split(':')
657 if len(bytes) != 6:
658 raise TypeError, 'invalid ethernet address %s' % value
659
660 for byte in bytes:
661 if not 0 <= int(byte) <= 256:
662 raise TypeError, 'invalid ethernet address %s' % value
663
664 self.value = value
665
666 def unproxy(self, base):
667 if self.value == NextEthernetAddr:
668 return EthernetAddr(self.value())
669 return self
670
671 def getValue(self):
245
246 def swig_decl(self, code):
247 code('%{')
248 self.ptype.cxx_predecls(code)
249 code('%}')
250 code()
251 self.ptype.swig_predecls(code)
252 code()
253 code('%include "std_vector.i"')
254 code()
255
256 ptype = self.ptype_str
257 cxx_type = self.ptype.cxx_type
258
259 code('''\
260%typemap(in) std::vector< $cxx_type >::value_type {
261 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
262 if (SWIG_ConvertPtr($$input, (void **)&$$1,
263 $$descriptor($cxx_type), 0) == -1) {
264 return NULL;
265 }
266 }
267}
268
269%typemap(in) std::vector< $cxx_type >::value_type * {
270 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
271 if (SWIG_ConvertPtr($$input, (void **)&$$1,
272 $$descriptor($cxx_type *), 0) == -1) {
273 return NULL;
274 }
275 }
276}
277''')
278
279 code('%template(vector_$ptype) std::vector< $cxx_type >;')
280
281 def cxx_predecls(self, code):
282 code('#include <vector>')
283 self.ptype.cxx_predecls(code)
284
285 def cxx_decl(self, code):
286 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
287
288class ParamFactory(object):
289 def __init__(self, param_desc_class, ptype_str = None):
290 self.param_desc_class = param_desc_class
291 self.ptype_str = ptype_str
292
293 def __getattr__(self, attr):
294 if self.ptype_str:
295 attr = self.ptype_str + '.' + attr
296 return ParamFactory(self.param_desc_class, attr)
297
298 # E.g., Param.Int(5, "number of widgets")
299 def __call__(self, *args, **kwargs):
300 ptype = None
301 try:
302 ptype = allParams[self.ptype_str]
303 except KeyError:
304 # if name isn't defined yet, assume it's a SimObject, and
305 # try to resolve it later
306 pass
307 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
308
309Param = ParamFactory(ParamDesc)
310VectorParam = ParamFactory(VectorParamDesc)
311
312#####################################################################
313#
314# Parameter Types
315#
316# Though native Python types could be used to specify parameter types
317# (the 'ptype' field of the Param and VectorParam classes), it's more
318# flexible to define our own set of types. This gives us more control
319# over how Python expressions are converted to values (via the
320# __init__() constructor) and how these values are printed out (via
321# the __str__() conversion method).
322#
323#####################################################################
324
325# String-valued parameter. Just mixin the ParamValue class with the
326# built-in str class.
327class String(ParamValue,str):
328 cxx_type = 'std::string'
329
330 @classmethod
331 def cxx_predecls(self, code):
332 code('#include <string>')
333
334 @classmethod
335 def swig_predecls(cls, code):
336 code('%include "std_string.i"')
337
338 def getValue(self):
339 return self
340
341# superclass for "numeric" parameter values, to emulate math
342# operations in a type-safe way. e.g., a Latency times an int returns
343# a new Latency object.
344class NumericParamValue(ParamValue):
345 def __str__(self):
346 return str(self.value)
347
348 def __float__(self):
349 return float(self.value)
350
351 def __long__(self):
352 return long(self.value)
353
354 def __int__(self):
355 return int(self.value)
356
357 # hook for bounds checking
358 def _check(self):
359 return
360
361 def __mul__(self, other):
362 newobj = self.__class__(self)
363 newobj.value *= other
364 newobj._check()
365 return newobj
366
367 __rmul__ = __mul__
368
369 def __div__(self, other):
370 newobj = self.__class__(self)
371 newobj.value /= other
372 newobj._check()
373 return newobj
374
375 def __sub__(self, other):
376 newobj = self.__class__(self)
377 newobj.value -= other
378 newobj._check()
379 return newobj
380
381# Metaclass for bounds-checked integer parameters. See CheckedInt.
382class CheckedIntType(MetaParamValue):
383 def __init__(cls, name, bases, dict):
384 super(CheckedIntType, cls).__init__(name, bases, dict)
385
386 # CheckedInt is an abstract base class, so we actually don't
387 # want to do any processing on it... the rest of this code is
388 # just for classes that derive from CheckedInt.
389 if name == 'CheckedInt':
390 return
391
392 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
393 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
394 panic("CheckedInt subclass %s must define either\n" \
395 " 'min' and 'max' or 'size' and 'unsigned'\n",
396 name);
397 if cls.unsigned:
398 cls.min = 0
399 cls.max = 2 ** cls.size - 1
400 else:
401 cls.min = -(2 ** (cls.size - 1))
402 cls.max = (2 ** (cls.size - 1)) - 1
403
404# Abstract superclass for bounds-checked integer parameters. This
405# class is subclassed to generate parameter classes with specific
406# bounds. Initialization of the min and max bounds is done in the
407# metaclass CheckedIntType.__init__.
408class CheckedInt(NumericParamValue):
409 __metaclass__ = CheckedIntType
410
411 def _check(self):
412 if not self.min <= self.value <= self.max:
413 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
414 (self.min, self.value, self.max)
415
416 def __init__(self, value):
417 if isinstance(value, str):
418 self.value = convert.toInteger(value)
419 elif isinstance(value, (int, long, float, NumericParamValue)):
420 self.value = long(value)
421 else:
422 raise TypeError, "Can't convert object of type %s to CheckedInt" \
423 % type(value).__name__
424 self._check()
425
426 @classmethod
427 def cxx_predecls(cls, code):
428 # most derived types require this, so we just do it here once
429 code('#include "base/types.hh"')
430
431 @classmethod
432 def swig_predecls(cls, code):
433 # most derived types require this, so we just do it here once
434 code('%import "stdint.i"')
435 code('%import "base/types.hh"')
436
437 def getValue(self):
438 return long(self.value)
439
440class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
441class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
442
443class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
444class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
445class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
446class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
447class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
448class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
449class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
450class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
451
452class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
453class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
454class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
455class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
456
457class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
458
459class Float(ParamValue, float):
460 cxx_type = 'double'
461
462 def __init__(self, value):
463 if isinstance(value, (int, long, float, NumericParamValue, Float)):
464 self.value = float(value)
465 else:
466 raise TypeError, "Can't convert object of type %s to Float" \
467 % type(value).__name__
468
469 def getValue(self):
470 return float(self.value)
471
472class MemorySize(CheckedInt):
473 cxx_type = 'uint64_t'
474 size = 64
475 unsigned = True
476 def __init__(self, value):
477 if isinstance(value, MemorySize):
478 self.value = value.value
479 else:
480 self.value = convert.toMemorySize(value)
481 self._check()
482
483class MemorySize32(CheckedInt):
484 cxx_type = 'uint32_t'
485 size = 32
486 unsigned = True
487 def __init__(self, value):
488 if isinstance(value, MemorySize):
489 self.value = value.value
490 else:
491 self.value = convert.toMemorySize(value)
492 self._check()
493
494class Addr(CheckedInt):
495 cxx_type = 'Addr'
496 size = 64
497 unsigned = True
498 def __init__(self, value):
499 if isinstance(value, Addr):
500 self.value = value.value
501 else:
502 try:
503 self.value = convert.toMemorySize(value)
504 except TypeError:
505 self.value = long(value)
506 self._check()
507 def __add__(self, other):
508 if isinstance(other, Addr):
509 return self.value + other.value
510 else:
511 return self.value + other
512
513
514class MetaRange(MetaParamValue):
515 def __init__(cls, name, bases, dict):
516 super(MetaRange, cls).__init__(name, bases, dict)
517 if name == 'Range':
518 return
519 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
520
521class Range(ParamValue):
522 __metaclass__ = MetaRange
523 type = Int # default; can be overridden in subclasses
524 def __init__(self, *args, **kwargs):
525 def handle_kwargs(self, kwargs):
526 if 'end' in kwargs:
527 self.second = self.type(kwargs.pop('end'))
528 elif 'size' in kwargs:
529 self.second = self.first + self.type(kwargs.pop('size')) - 1
530 else:
531 raise TypeError, "Either end or size must be specified"
532
533 if len(args) == 0:
534 self.first = self.type(kwargs.pop('start'))
535 handle_kwargs(self, kwargs)
536
537 elif len(args) == 1:
538 if kwargs:
539 self.first = self.type(args[0])
540 handle_kwargs(self, kwargs)
541 elif isinstance(args[0], Range):
542 self.first = self.type(args[0].first)
543 self.second = self.type(args[0].second)
544 elif isinstance(args[0], (list, tuple)):
545 self.first = self.type(args[0][0])
546 self.second = self.type(args[0][1])
547 else:
548 self.first = self.type(0)
549 self.second = self.type(args[0]) - 1
550
551 elif len(args) == 2:
552 self.first = self.type(args[0])
553 self.second = self.type(args[1])
554 else:
555 raise TypeError, "Too many arguments specified"
556
557 if kwargs:
558 raise TypeError, "too many keywords: %s" % kwargs.keys()
559
560 def __str__(self):
561 return '%s:%s' % (self.first, self.second)
562
563 @classmethod
564 def cxx_predecls(cls, code):
565 cls.type.cxx_predecls(code)
566 code('#include "base/range.hh"')
567
568 @classmethod
569 def swig_predecls(cls, code):
570 cls.type.swig_predecls(code)
571 code('%import "python/swig/range.i"')
572
573class AddrRange(Range):
574 type = Addr
575
576 def getValue(self):
577 from m5.internal.range import AddrRange
578
579 value = AddrRange()
580 value.start = long(self.first)
581 value.end = long(self.second)
582 return value
583
584class TickRange(Range):
585 type = Tick
586
587 def getValue(self):
588 from m5.internal.range import TickRange
589
590 value = TickRange()
591 value.start = long(self.first)
592 value.end = long(self.second)
593 return value
594
595# Boolean parameter type. Python doesn't let you subclass bool, since
596# it doesn't want to let you create multiple instances of True and
597# False. Thus this is a little more complicated than String.
598class Bool(ParamValue):
599 cxx_type = 'bool'
600 def __init__(self, value):
601 try:
602 self.value = convert.toBool(value)
603 except TypeError:
604 self.value = bool(value)
605
606 def getValue(self):
607 return bool(self.value)
608
609 def __str__(self):
610 return str(self.value)
611
612 def ini_str(self):
613 if self.value:
614 return 'true'
615 return 'false'
616
617def IncEthernetAddr(addr, val = 1):
618 bytes = map(lambda x: int(x, 16), addr.split(':'))
619 bytes[5] += val
620 for i in (5, 4, 3, 2, 1):
621 val,rem = divmod(bytes[i], 256)
622 bytes[i] = rem
623 if val == 0:
624 break
625 bytes[i - 1] += val
626 assert(bytes[0] <= 255)
627 return ':'.join(map(lambda x: '%02x' % x, bytes))
628
629_NextEthernetAddr = "00:90:00:00:00:01"
630def NextEthernetAddr():
631 global _NextEthernetAddr
632
633 value = _NextEthernetAddr
634 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
635 return value
636
637class EthernetAddr(ParamValue):
638 cxx_type = 'Net::EthAddr'
639
640 @classmethod
641 def cxx_predecls(cls, code):
642 code('#include "base/inet.hh"')
643
644 @classmethod
645 def swig_predecls(cls, code):
646 code('%include "python/swig/inet.i"')
647
648 def __init__(self, value):
649 if value == NextEthernetAddr:
650 self.value = value
651 return
652
653 if not isinstance(value, str):
654 raise TypeError, "expected an ethernet address and didn't get one"
655
656 bytes = value.split(':')
657 if len(bytes) != 6:
658 raise TypeError, 'invalid ethernet address %s' % value
659
660 for byte in bytes:
661 if not 0 <= int(byte) <= 256:
662 raise TypeError, 'invalid ethernet address %s' % value
663
664 self.value = value
665
666 def unproxy(self, base):
667 if self.value == NextEthernetAddr:
668 return EthernetAddr(self.value())
669 return self
670
671 def getValue(self):
672 from m5.objects.params import EthAddr
672 from m5.internal.params import EthAddr
673 return EthAddr(self.value)
674
675 def ini_str(self):
676 return self.value
677
678time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
679 "%a %b %d %H:%M:%S %Z %Y",
680 "%Y/%m/%d %H:%M:%S",
681 "%Y/%m/%d %H:%M",
682 "%Y/%m/%d",
683 "%m/%d/%Y %H:%M:%S",
684 "%m/%d/%Y %H:%M",
685 "%m/%d/%Y",
686 "%m/%d/%y %H:%M:%S",
687 "%m/%d/%y %H:%M",
688 "%m/%d/%y"]
689
690
691def parse_time(value):
692 from time import gmtime, strptime, struct_time, time
693 from datetime import datetime, date
694
695 if isinstance(value, struct_time):
696 return value
697
698 if isinstance(value, (int, long)):
699 return gmtime(value)
700
701 if isinstance(value, (datetime, date)):
702 return value.timetuple()
703
704 if isinstance(value, str):
705 if value in ('Now', 'Today'):
706 return time.gmtime(time.time())
707
708 for format in time_formats:
709 try:
710 return strptime(value, format)
711 except ValueError:
712 pass
713
714 raise ValueError, "Could not parse '%s' as a time" % value
715
716class Time(ParamValue):
717 cxx_type = 'tm'
718
719 @classmethod
720 def cxx_predecls(cls, code):
721 code('#include <time.h>')
722
723 @classmethod
724 def swig_predecls(cls, code):
725 code('%include "python/swig/time.i"')
726
727 def __init__(self, value):
728 self.value = parse_time(value)
729
730 def getValue(self):
673 return EthAddr(self.value)
674
675 def ini_str(self):
676 return self.value
677
678time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
679 "%a %b %d %H:%M:%S %Z %Y",
680 "%Y/%m/%d %H:%M:%S",
681 "%Y/%m/%d %H:%M",
682 "%Y/%m/%d",
683 "%m/%d/%Y %H:%M:%S",
684 "%m/%d/%Y %H:%M",
685 "%m/%d/%Y",
686 "%m/%d/%y %H:%M:%S",
687 "%m/%d/%y %H:%M",
688 "%m/%d/%y"]
689
690
691def parse_time(value):
692 from time import gmtime, strptime, struct_time, time
693 from datetime import datetime, date
694
695 if isinstance(value, struct_time):
696 return value
697
698 if isinstance(value, (int, long)):
699 return gmtime(value)
700
701 if isinstance(value, (datetime, date)):
702 return value.timetuple()
703
704 if isinstance(value, str):
705 if value in ('Now', 'Today'):
706 return time.gmtime(time.time())
707
708 for format in time_formats:
709 try:
710 return strptime(value, format)
711 except ValueError:
712 pass
713
714 raise ValueError, "Could not parse '%s' as a time" % value
715
716class Time(ParamValue):
717 cxx_type = 'tm'
718
719 @classmethod
720 def cxx_predecls(cls, code):
721 code('#include <time.h>')
722
723 @classmethod
724 def swig_predecls(cls, code):
725 code('%include "python/swig/time.i"')
726
727 def __init__(self, value):
728 self.value = parse_time(value)
729
730 def getValue(self):
731 from m5.objects.params import tm
731 from m5.internal.params import tm
732
733 c_time = tm()
734 py_time = self.value
735
736 # UNIX is years since 1900
737 c_time.tm_year = py_time.tm_year - 1900;
738
739 # Python starts at 1, UNIX starts at 0
740 c_time.tm_mon = py_time.tm_mon - 1;
741 c_time.tm_mday = py_time.tm_mday;
742 c_time.tm_hour = py_time.tm_hour;
743 c_time.tm_min = py_time.tm_min;
744 c_time.tm_sec = py_time.tm_sec;
745
746 # Python has 0 as Monday, UNIX is 0 as sunday
747 c_time.tm_wday = py_time.tm_wday + 1
748 if c_time.tm_wday > 6:
749 c_time.tm_wday -= 7;
750
751 # Python starts at 1, Unix starts at 0
752 c_time.tm_yday = py_time.tm_yday - 1;
753
754 return c_time
755
756 def __str__(self):
757 return time.asctime(self.value)
758
759 def ini_str(self):
760 return str(self)
761
762# Enumerated types are a little more complex. The user specifies the
763# type as Enum(foo) where foo is either a list or dictionary of
764# alternatives (typically strings, but not necessarily so). (In the
765# long run, the integer value of the parameter will be the list index
766# or the corresponding dictionary value. For now, since we only check
767# that the alternative is valid and then spit it into a .ini file,
768# there's not much point in using the dictionary.)
769
770# What Enum() must do is generate a new type encapsulating the
771# provided list/dictionary so that specific values of the parameter
772# can be instances of that type. We define two hidden internal
773# classes (_ListEnum and _DictEnum) to serve as base classes, then
774# derive the new type from the appropriate base class on the fly.
775
776allEnums = {}
777# Metaclass for Enum types
778class MetaEnum(MetaParamValue):
779 def __new__(mcls, name, bases, dict):
780 assert name not in allEnums
781
782 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
783 allEnums[name] = cls
784 return cls
785
786 def __init__(cls, name, bases, init_dict):
787 if init_dict.has_key('map'):
788 if not isinstance(cls.map, dict):
789 raise TypeError, "Enum-derived class attribute 'map' " \
790 "must be of type dict"
791 # build list of value strings from map
792 cls.vals = cls.map.keys()
793 cls.vals.sort()
794 elif init_dict.has_key('vals'):
795 if not isinstance(cls.vals, list):
796 raise TypeError, "Enum-derived class attribute 'vals' " \
797 "must be of type list"
798 # build string->value map from vals sequence
799 cls.map = {}
800 for idx,val in enumerate(cls.vals):
801 cls.map[val] = idx
802 else:
803 raise TypeError, "Enum-derived class must define "\
804 "attribute 'map' or 'vals'"
805
806 cls.cxx_type = 'Enums::%s' % name
807
808 super(MetaEnum, cls).__init__(name, bases, init_dict)
809
810 # Generate C++ class declaration for this enum type.
811 # Note that we wrap the enum in a class/struct to act as a namespace,
812 # so that the enum strings can be brief w/o worrying about collisions.
813 def cxx_decl(cls, code):
814 name = cls.__name__
815 code('''\
816#ifndef __ENUM__${name}__
817#define __ENUM__${name}__
818
819namespace Enums {
820 enum $name {
821''')
822 code.indent(2)
823 for val in cls.vals:
824 code('$val = ${{cls.map[val]}},')
825 code('Num_$name = ${{len(cls.vals)}},')
826 code.dedent(2)
827 code('''\
828 };
829extern const char *${name}Strings[Num_${name}];
830}
831
832#endif // __ENUM__${name}__
833''')
834
835 def cxx_def(cls, code):
836 name = cls.__name__
837 code('''\
732
733 c_time = tm()
734 py_time = self.value
735
736 # UNIX is years since 1900
737 c_time.tm_year = py_time.tm_year - 1900;
738
739 # Python starts at 1, UNIX starts at 0
740 c_time.tm_mon = py_time.tm_mon - 1;
741 c_time.tm_mday = py_time.tm_mday;
742 c_time.tm_hour = py_time.tm_hour;
743 c_time.tm_min = py_time.tm_min;
744 c_time.tm_sec = py_time.tm_sec;
745
746 # Python has 0 as Monday, UNIX is 0 as sunday
747 c_time.tm_wday = py_time.tm_wday + 1
748 if c_time.tm_wday > 6:
749 c_time.tm_wday -= 7;
750
751 # Python starts at 1, Unix starts at 0
752 c_time.tm_yday = py_time.tm_yday - 1;
753
754 return c_time
755
756 def __str__(self):
757 return time.asctime(self.value)
758
759 def ini_str(self):
760 return str(self)
761
762# Enumerated types are a little more complex. The user specifies the
763# type as Enum(foo) where foo is either a list or dictionary of
764# alternatives (typically strings, but not necessarily so). (In the
765# long run, the integer value of the parameter will be the list index
766# or the corresponding dictionary value. For now, since we only check
767# that the alternative is valid and then spit it into a .ini file,
768# there's not much point in using the dictionary.)
769
770# What Enum() must do is generate a new type encapsulating the
771# provided list/dictionary so that specific values of the parameter
772# can be instances of that type. We define two hidden internal
773# classes (_ListEnum and _DictEnum) to serve as base classes, then
774# derive the new type from the appropriate base class on the fly.
775
776allEnums = {}
777# Metaclass for Enum types
778class MetaEnum(MetaParamValue):
779 def __new__(mcls, name, bases, dict):
780 assert name not in allEnums
781
782 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
783 allEnums[name] = cls
784 return cls
785
786 def __init__(cls, name, bases, init_dict):
787 if init_dict.has_key('map'):
788 if not isinstance(cls.map, dict):
789 raise TypeError, "Enum-derived class attribute 'map' " \
790 "must be of type dict"
791 # build list of value strings from map
792 cls.vals = cls.map.keys()
793 cls.vals.sort()
794 elif init_dict.has_key('vals'):
795 if not isinstance(cls.vals, list):
796 raise TypeError, "Enum-derived class attribute 'vals' " \
797 "must be of type list"
798 # build string->value map from vals sequence
799 cls.map = {}
800 for idx,val in enumerate(cls.vals):
801 cls.map[val] = idx
802 else:
803 raise TypeError, "Enum-derived class must define "\
804 "attribute 'map' or 'vals'"
805
806 cls.cxx_type = 'Enums::%s' % name
807
808 super(MetaEnum, cls).__init__(name, bases, init_dict)
809
810 # Generate C++ class declaration for this enum type.
811 # Note that we wrap the enum in a class/struct to act as a namespace,
812 # so that the enum strings can be brief w/o worrying about collisions.
813 def cxx_decl(cls, code):
814 name = cls.__name__
815 code('''\
816#ifndef __ENUM__${name}__
817#define __ENUM__${name}__
818
819namespace Enums {
820 enum $name {
821''')
822 code.indent(2)
823 for val in cls.vals:
824 code('$val = ${{cls.map[val]}},')
825 code('Num_$name = ${{len(cls.vals)}},')
826 code.dedent(2)
827 code('''\
828 };
829extern const char *${name}Strings[Num_${name}];
830}
831
832#endif // __ENUM__${name}__
833''')
834
835 def cxx_def(cls, code):
836 name = cls.__name__
837 code('''\
838#include "enums/${name}.hh"
838#include "enums/$name.hh"
839namespace Enums {
840 const char *${name}Strings[Num_${name}] =
841 {
842''')
843 code.indent(2)
844 for val in cls.vals:
845 code('"$val",')
846 code.dedent(2)
847 code('''
848 };
849/* namespace Enums */ }
850''')
851
852# Base class for enum types.
853class Enum(ParamValue):
854 __metaclass__ = MetaEnum
855 vals = []
856
857 def __init__(self, value):
858 if value not in self.map:
859 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
860 % (value, self.vals)
861 self.value = value
862
863 @classmethod
864 def cxx_predecls(cls, code):
865 code('#include "enums/$0.hh"', cls.__name__)
866
867 @classmethod
868 def swig_predecls(cls, code):
839namespace Enums {
840 const char *${name}Strings[Num_${name}] =
841 {
842''')
843 code.indent(2)
844 for val in cls.vals:
845 code('"$val",')
846 code.dedent(2)
847 code('''
848 };
849/* namespace Enums */ }
850''')
851
852# Base class for enum types.
853class Enum(ParamValue):
854 __metaclass__ = MetaEnum
855 vals = []
856
857 def __init__(self, value):
858 if value not in self.map:
859 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
860 % (value, self.vals)
861 self.value = value
862
863 @classmethod
864 def cxx_predecls(cls, code):
865 code('#include "enums/$0.hh"', cls.__name__)
866
867 @classmethod
868 def swig_predecls(cls, code):
869 code('%import "enums/$0.i"', cls.__name__)
869 code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
870
871 def getValue(self):
872 return int(self.map[self.value])
873
874 def __str__(self):
875 return self.value
876
877# how big does a rounding error need to be before we warn about it?
878frequency_tolerance = 0.001 # 0.1%
879
880class TickParamValue(NumericParamValue):
881 cxx_type = 'Tick'
882
883 @classmethod
884 def cxx_predecls(cls, code):
885 code('#include "base/types.hh"')
886
887 @classmethod
888 def swig_predecls(cls, code):
889 code('%import "stdint.i"')
890 code('%import "base/types.hh"')
891
892 def getValue(self):
893 return long(self.value)
894
895class Latency(TickParamValue):
896 def __init__(self, value):
897 if isinstance(value, (Latency, Clock)):
898 self.ticks = value.ticks
899 self.value = value.value
900 elif isinstance(value, Frequency):
901 self.ticks = value.ticks
902 self.value = 1.0 / value.value
903 elif value.endswith('t'):
904 self.ticks = True
905 self.value = int(value[:-1])
906 else:
907 self.ticks = False
908 self.value = convert.toLatency(value)
909
910 def __getattr__(self, attr):
911 if attr in ('latency', 'period'):
912 return self
913 if attr == 'frequency':
914 return Frequency(self)
915 raise AttributeError, "Latency object has no attribute '%s'" % attr
916
917 def getValue(self):
918 if self.ticks or self.value == 0:
919 value = self.value
920 else:
921 value = ticks.fromSeconds(self.value)
922 return long(value)
923
924 # convert latency to ticks
925 def ini_str(self):
926 return '%d' % self.getValue()
927
928class Frequency(TickParamValue):
929 def __init__(self, value):
930 if isinstance(value, (Latency, Clock)):
931 if value.value == 0:
932 self.value = 0
933 else:
934 self.value = 1.0 / value.value
935 self.ticks = value.ticks
936 elif isinstance(value, Frequency):
937 self.value = value.value
938 self.ticks = value.ticks
939 else:
940 self.ticks = False
941 self.value = convert.toFrequency(value)
942
943 def __getattr__(self, attr):
944 if attr == 'frequency':
945 return self
946 if attr in ('latency', 'period'):
947 return Latency(self)
948 raise AttributeError, "Frequency object has no attribute '%s'" % attr
949
950 # convert latency to ticks
951 def getValue(self):
952 if self.ticks or self.value == 0:
953 value = self.value
954 else:
955 value = ticks.fromSeconds(1.0 / self.value)
956 return long(value)
957
958 def ini_str(self):
959 return '%d' % self.getValue()
960
961# A generic frequency and/or Latency value. Value is stored as a latency,
962# but to avoid ambiguity this object does not support numeric ops (* or /).
963# An explicit conversion to a Latency or Frequency must be made first.
964class Clock(ParamValue):
965 cxx_type = 'Tick'
966
967 @classmethod
968 def cxx_predecls(cls, code):
969 code('#include "base/types.hh"')
970
971 @classmethod
972 def swig_predecls(cls, code):
973 code('%import "stdint.i"')
974 code('%import "base/types.hh"')
975
976 def __init__(self, value):
977 if isinstance(value, (Latency, Clock)):
978 self.ticks = value.ticks
979 self.value = value.value
980 elif isinstance(value, Frequency):
981 self.ticks = value.ticks
982 self.value = 1.0 / value.value
983 elif value.endswith('t'):
984 self.ticks = True
985 self.value = int(value[:-1])
986 else:
987 self.ticks = False
988 self.value = convert.anyToLatency(value)
989
990 def __getattr__(self, attr):
991 if attr == 'frequency':
992 return Frequency(self)
993 if attr in ('latency', 'period'):
994 return Latency(self)
995 raise AttributeError, "Frequency object has no attribute '%s'" % attr
996
997 def getValue(self):
998 return self.period.getValue()
999
1000 def ini_str(self):
1001 return self.period.ini_str()
1002
1003class NetworkBandwidth(float,ParamValue):
1004 cxx_type = 'float'
1005 def __new__(cls, value):
1006 # convert to bits per second
1007 val = convert.toNetworkBandwidth(value)
1008 return super(cls, NetworkBandwidth).__new__(cls, val)
1009
1010 def __str__(self):
1011 return str(self.val)
1012
1013 def getValue(self):
1014 # convert to seconds per byte
1015 value = 8.0 / float(self)
1016 # convert to ticks per byte
1017 value = ticks.fromSeconds(value)
1018 return float(value)
1019
1020 def ini_str(self):
1021 return '%f' % self.getValue()
1022
1023class MemoryBandwidth(float,ParamValue):
1024 cxx_type = 'float'
1025 def __new__(cls, value):
1026 # we want the number of ticks per byte of data
1027 val = convert.toMemoryBandwidth(value)
1028 return super(cls, MemoryBandwidth).__new__(cls, val)
1029
1030 def __str__(self):
1031 return str(self.val)
1032
1033 def getValue(self):
1034 # convert to seconds per byte
1035 value = float(self)
1036 if value:
1037 value = 1.0 / float(self)
1038 # convert to ticks per byte
1039 value = ticks.fromSeconds(value)
1040 return float(value)
1041
1042 def ini_str(self):
1043 return '%f' % self.getValue()
1044
1045#
1046# "Constants"... handy aliases for various values.
1047#
1048
1049# Special class for NULL pointers. Note the special check in
1050# make_param_value() above that lets these be assigned where a
1051# SimObject is required.
1052# only one copy of a particular node
1053class NullSimObject(object):
1054 __metaclass__ = Singleton
1055
1056 def __call__(cls):
1057 return cls
1058
1059 def _instantiate(self, parent = None, path = ''):
1060 pass
1061
1062 def ini_str(self):
1063 return 'Null'
1064
1065 def unproxy(self, base):
1066 return self
1067
1068 def set_path(self, parent, name):
1069 pass
1070
1071 def __str__(self):
1072 return 'Null'
1073
1074 def getValue(self):
1075 return None
1076
1077# The only instance you'll ever need...
1078NULL = NullSimObject()
1079
1080def isNullPointer(value):
1081 return isinstance(value, NullSimObject)
1082
1083# Some memory range specifications use this as a default upper bound.
1084MaxAddr = Addr.max
1085MaxTick = Tick.max
1086AllMemory = AddrRange(0, MaxAddr)
1087
1088
1089#####################################################################
1090#
1091# Port objects
1092#
1093# Ports are used to interconnect objects in the memory system.
1094#
1095#####################################################################
1096
1097# Port reference: encapsulates a reference to a particular port on a
1098# particular SimObject.
1099class PortRef(object):
1100 def __init__(self, simobj, name):
1101 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1102 self.simobj = simobj
1103 self.name = name
1104 self.peer = None # not associated with another port yet
1105 self.ccConnected = False # C++ port connection done?
1106 self.index = -1 # always -1 for non-vector ports
1107
1108 def __str__(self):
1109 return '%s.%s' % (self.simobj, self.name)
1110
1111 # for config.ini, print peer's name (not ours)
1112 def ini_str(self):
1113 return str(self.peer)
1114
1115 def __getattr__(self, attr):
1116 if attr == 'peerObj':
1117 # shorthand for proxies
1118 return self.peer.simobj
1119 raise AttributeError, "'%s' object has no attribute '%s'" % \
1120 (self.__class__.__name__, attr)
1121
1122 # Full connection is symmetric (both ways). Called via
1123 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1124 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1125 # e.g., "obj1.portA[3] = obj2.portB".
1126 def connect(self, other):
1127 if isinstance(other, VectorPortRef):
1128 # reference to plain VectorPort is implicit append
1129 other = other._get_next()
1130 if self.peer and not proxy.isproxy(self.peer):
1131 print "warning: overwriting port", self, \
1132 "value", self.peer, "with", other
1133 self.peer.peer = None
1134 self.peer = other
1135 if proxy.isproxy(other):
1136 other.set_param_desc(PortParamDesc())
1137 elif isinstance(other, PortRef):
1138 if other.peer is not self:
1139 other.connect(self)
1140 else:
1141 raise TypeError, \
1142 "assigning non-port reference '%s' to port '%s'" \
1143 % (other, self)
1144
1145 def clone(self, simobj, memo):
1146 if memo.has_key(self):
1147 return memo[self]
1148 newRef = copy.copy(self)
1149 memo[self] = newRef
1150 newRef.simobj = simobj
1151 assert(isSimObject(newRef.simobj))
1152 if self.peer and not proxy.isproxy(self.peer):
1153 peerObj = self.peer.simobj(_memo=memo)
1154 newRef.peer = self.peer.clone(peerObj, memo)
1155 assert(not isinstance(newRef.peer, VectorPortRef))
1156 return newRef
1157
1158 def unproxy(self, simobj):
1159 assert(simobj is self.simobj)
1160 if proxy.isproxy(self.peer):
1161 try:
1162 realPeer = self.peer.unproxy(self.simobj)
1163 except:
1164 print "Error in unproxying port '%s' of %s" % \
1165 (self.name, self.simobj.path())
1166 raise
1167 self.connect(realPeer)
1168
1169 # Call C++ to create corresponding port connection between C++ objects
1170 def ccConnect(self):
870
871 def getValue(self):
872 return int(self.map[self.value])
873
874 def __str__(self):
875 return self.value
876
877# how big does a rounding error need to be before we warn about it?
878frequency_tolerance = 0.001 # 0.1%
879
880class TickParamValue(NumericParamValue):
881 cxx_type = 'Tick'
882
883 @classmethod
884 def cxx_predecls(cls, code):
885 code('#include "base/types.hh"')
886
887 @classmethod
888 def swig_predecls(cls, code):
889 code('%import "stdint.i"')
890 code('%import "base/types.hh"')
891
892 def getValue(self):
893 return long(self.value)
894
895class Latency(TickParamValue):
896 def __init__(self, value):
897 if isinstance(value, (Latency, Clock)):
898 self.ticks = value.ticks
899 self.value = value.value
900 elif isinstance(value, Frequency):
901 self.ticks = value.ticks
902 self.value = 1.0 / value.value
903 elif value.endswith('t'):
904 self.ticks = True
905 self.value = int(value[:-1])
906 else:
907 self.ticks = False
908 self.value = convert.toLatency(value)
909
910 def __getattr__(self, attr):
911 if attr in ('latency', 'period'):
912 return self
913 if attr == 'frequency':
914 return Frequency(self)
915 raise AttributeError, "Latency object has no attribute '%s'" % attr
916
917 def getValue(self):
918 if self.ticks or self.value == 0:
919 value = self.value
920 else:
921 value = ticks.fromSeconds(self.value)
922 return long(value)
923
924 # convert latency to ticks
925 def ini_str(self):
926 return '%d' % self.getValue()
927
928class Frequency(TickParamValue):
929 def __init__(self, value):
930 if isinstance(value, (Latency, Clock)):
931 if value.value == 0:
932 self.value = 0
933 else:
934 self.value = 1.0 / value.value
935 self.ticks = value.ticks
936 elif isinstance(value, Frequency):
937 self.value = value.value
938 self.ticks = value.ticks
939 else:
940 self.ticks = False
941 self.value = convert.toFrequency(value)
942
943 def __getattr__(self, attr):
944 if attr == 'frequency':
945 return self
946 if attr in ('latency', 'period'):
947 return Latency(self)
948 raise AttributeError, "Frequency object has no attribute '%s'" % attr
949
950 # convert latency to ticks
951 def getValue(self):
952 if self.ticks or self.value == 0:
953 value = self.value
954 else:
955 value = ticks.fromSeconds(1.0 / self.value)
956 return long(value)
957
958 def ini_str(self):
959 return '%d' % self.getValue()
960
961# A generic frequency and/or Latency value. Value is stored as a latency,
962# but to avoid ambiguity this object does not support numeric ops (* or /).
963# An explicit conversion to a Latency or Frequency must be made first.
964class Clock(ParamValue):
965 cxx_type = 'Tick'
966
967 @classmethod
968 def cxx_predecls(cls, code):
969 code('#include "base/types.hh"')
970
971 @classmethod
972 def swig_predecls(cls, code):
973 code('%import "stdint.i"')
974 code('%import "base/types.hh"')
975
976 def __init__(self, value):
977 if isinstance(value, (Latency, Clock)):
978 self.ticks = value.ticks
979 self.value = value.value
980 elif isinstance(value, Frequency):
981 self.ticks = value.ticks
982 self.value = 1.0 / value.value
983 elif value.endswith('t'):
984 self.ticks = True
985 self.value = int(value[:-1])
986 else:
987 self.ticks = False
988 self.value = convert.anyToLatency(value)
989
990 def __getattr__(self, attr):
991 if attr == 'frequency':
992 return Frequency(self)
993 if attr in ('latency', 'period'):
994 return Latency(self)
995 raise AttributeError, "Frequency object has no attribute '%s'" % attr
996
997 def getValue(self):
998 return self.period.getValue()
999
1000 def ini_str(self):
1001 return self.period.ini_str()
1002
1003class NetworkBandwidth(float,ParamValue):
1004 cxx_type = 'float'
1005 def __new__(cls, value):
1006 # convert to bits per second
1007 val = convert.toNetworkBandwidth(value)
1008 return super(cls, NetworkBandwidth).__new__(cls, val)
1009
1010 def __str__(self):
1011 return str(self.val)
1012
1013 def getValue(self):
1014 # convert to seconds per byte
1015 value = 8.0 / float(self)
1016 # convert to ticks per byte
1017 value = ticks.fromSeconds(value)
1018 return float(value)
1019
1020 def ini_str(self):
1021 return '%f' % self.getValue()
1022
1023class MemoryBandwidth(float,ParamValue):
1024 cxx_type = 'float'
1025 def __new__(cls, value):
1026 # we want the number of ticks per byte of data
1027 val = convert.toMemoryBandwidth(value)
1028 return super(cls, MemoryBandwidth).__new__(cls, val)
1029
1030 def __str__(self):
1031 return str(self.val)
1032
1033 def getValue(self):
1034 # convert to seconds per byte
1035 value = float(self)
1036 if value:
1037 value = 1.0 / float(self)
1038 # convert to ticks per byte
1039 value = ticks.fromSeconds(value)
1040 return float(value)
1041
1042 def ini_str(self):
1043 return '%f' % self.getValue()
1044
1045#
1046# "Constants"... handy aliases for various values.
1047#
1048
1049# Special class for NULL pointers. Note the special check in
1050# make_param_value() above that lets these be assigned where a
1051# SimObject is required.
1052# only one copy of a particular node
1053class NullSimObject(object):
1054 __metaclass__ = Singleton
1055
1056 def __call__(cls):
1057 return cls
1058
1059 def _instantiate(self, parent = None, path = ''):
1060 pass
1061
1062 def ini_str(self):
1063 return 'Null'
1064
1065 def unproxy(self, base):
1066 return self
1067
1068 def set_path(self, parent, name):
1069 pass
1070
1071 def __str__(self):
1072 return 'Null'
1073
1074 def getValue(self):
1075 return None
1076
1077# The only instance you'll ever need...
1078NULL = NullSimObject()
1079
1080def isNullPointer(value):
1081 return isinstance(value, NullSimObject)
1082
1083# Some memory range specifications use this as a default upper bound.
1084MaxAddr = Addr.max
1085MaxTick = Tick.max
1086AllMemory = AddrRange(0, MaxAddr)
1087
1088
1089#####################################################################
1090#
1091# Port objects
1092#
1093# Ports are used to interconnect objects in the memory system.
1094#
1095#####################################################################
1096
1097# Port reference: encapsulates a reference to a particular port on a
1098# particular SimObject.
1099class PortRef(object):
1100 def __init__(self, simobj, name):
1101 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1102 self.simobj = simobj
1103 self.name = name
1104 self.peer = None # not associated with another port yet
1105 self.ccConnected = False # C++ port connection done?
1106 self.index = -1 # always -1 for non-vector ports
1107
1108 def __str__(self):
1109 return '%s.%s' % (self.simobj, self.name)
1110
1111 # for config.ini, print peer's name (not ours)
1112 def ini_str(self):
1113 return str(self.peer)
1114
1115 def __getattr__(self, attr):
1116 if attr == 'peerObj':
1117 # shorthand for proxies
1118 return self.peer.simobj
1119 raise AttributeError, "'%s' object has no attribute '%s'" % \
1120 (self.__class__.__name__, attr)
1121
1122 # Full connection is symmetric (both ways). Called via
1123 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1124 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1125 # e.g., "obj1.portA[3] = obj2.portB".
1126 def connect(self, other):
1127 if isinstance(other, VectorPortRef):
1128 # reference to plain VectorPort is implicit append
1129 other = other._get_next()
1130 if self.peer and not proxy.isproxy(self.peer):
1131 print "warning: overwriting port", self, \
1132 "value", self.peer, "with", other
1133 self.peer.peer = None
1134 self.peer = other
1135 if proxy.isproxy(other):
1136 other.set_param_desc(PortParamDesc())
1137 elif isinstance(other, PortRef):
1138 if other.peer is not self:
1139 other.connect(self)
1140 else:
1141 raise TypeError, \
1142 "assigning non-port reference '%s' to port '%s'" \
1143 % (other, self)
1144
1145 def clone(self, simobj, memo):
1146 if memo.has_key(self):
1147 return memo[self]
1148 newRef = copy.copy(self)
1149 memo[self] = newRef
1150 newRef.simobj = simobj
1151 assert(isSimObject(newRef.simobj))
1152 if self.peer and not proxy.isproxy(self.peer):
1153 peerObj = self.peer.simobj(_memo=memo)
1154 newRef.peer = self.peer.clone(peerObj, memo)
1155 assert(not isinstance(newRef.peer, VectorPortRef))
1156 return newRef
1157
1158 def unproxy(self, simobj):
1159 assert(simobj is self.simobj)
1160 if proxy.isproxy(self.peer):
1161 try:
1162 realPeer = self.peer.unproxy(self.simobj)
1163 except:
1164 print "Error in unproxying port '%s' of %s" % \
1165 (self.name, self.simobj.path())
1166 raise
1167 self.connect(realPeer)
1168
1169 # Call C++ to create corresponding port connection between C++ objects
1170 def ccConnect(self):
1171 from m5.objects.params import connectPorts
1171 from m5.internal.params import connectPorts
1172
1173 if self.ccConnected: # already done this
1174 return
1175 peer = self.peer
1176 if not self.peer: # nothing to connect to
1177 return
1178 try:
1179 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1180 peer.simobj.getCCObject(), peer.name, peer.index)
1181 except:
1182 print "Error connecting port %s.%s to %s.%s" % \
1183 (self.simobj.path(), self.name,
1184 peer.simobj.path(), peer.name)
1185 raise
1186 self.ccConnected = True
1187 peer.ccConnected = True
1188
1189# A reference to an individual element of a VectorPort... much like a
1190# PortRef, but has an index.
1191class VectorPortElementRef(PortRef):
1192 def __init__(self, simobj, name, index):
1193 PortRef.__init__(self, simobj, name)
1194 self.index = index
1195
1196 def __str__(self):
1197 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1198
1199# A reference to a complete vector-valued port (not just a single element).
1200# Can be indexed to retrieve individual VectorPortElementRef instances.
1201class VectorPortRef(object):
1202 def __init__(self, simobj, name):
1203 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1204 self.simobj = simobj
1205 self.name = name
1206 self.elements = []
1207
1208 def __str__(self):
1209 return '%s.%s[:]' % (self.simobj, self.name)
1210
1211 # for config.ini, print peer's name (not ours)
1212 def ini_str(self):
1213 return ' '.join([el.ini_str() for el in self.elements])
1214
1215 def __getitem__(self, key):
1216 if not isinstance(key, int):
1217 raise TypeError, "VectorPort index must be integer"
1218 if key >= len(self.elements):
1219 # need to extend list
1220 ext = [VectorPortElementRef(self.simobj, self.name, i)
1221 for i in range(len(self.elements), key+1)]
1222 self.elements.extend(ext)
1223 return self.elements[key]
1224
1225 def _get_next(self):
1226 return self[len(self.elements)]
1227
1228 def __setitem__(self, key, value):
1229 if not isinstance(key, int):
1230 raise TypeError, "VectorPort index must be integer"
1231 self[key].connect(value)
1232
1233 def connect(self, other):
1234 if isinstance(other, (list, tuple)):
1235 # Assign list of port refs to vector port.
1236 # For now, append them... not sure if that's the right semantics
1237 # or if it should replace the current vector.
1238 for ref in other:
1239 self._get_next().connect(ref)
1240 else:
1241 # scalar assignment to plain VectorPort is implicit append
1242 self._get_next().connect(other)
1243
1244 def clone(self, simobj, memo):
1245 if memo.has_key(self):
1246 return memo[self]
1247 newRef = copy.copy(self)
1248 memo[self] = newRef
1249 newRef.simobj = simobj
1250 assert(isSimObject(newRef.simobj))
1251 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1252 return newRef
1253
1254 def unproxy(self, simobj):
1255 [el.unproxy(simobj) for el in self.elements]
1256
1257 def ccConnect(self):
1258 [el.ccConnect() for el in self.elements]
1259
1260# Port description object. Like a ParamDesc object, this represents a
1261# logical port in the SimObject class, not a particular port on a
1262# SimObject instance. The latter are represented by PortRef objects.
1263class Port(object):
1264 # Port("description") or Port(default, "description")
1265 def __init__(self, *args):
1266 if len(args) == 1:
1267 self.desc = args[0]
1268 elif len(args) == 2:
1269 self.default = args[0]
1270 self.desc = args[1]
1271 else:
1272 raise TypeError, 'wrong number of arguments'
1273 # self.name is set by SimObject class on assignment
1274 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1275
1276 # Generate a PortRef for this port on the given SimObject with the
1277 # given name
1278 def makeRef(self, simobj):
1279 return PortRef(simobj, self.name)
1280
1281 # Connect an instance of this port (on the given SimObject with
1282 # the given name) with the port described by the supplied PortRef
1283 def connect(self, simobj, ref):
1284 self.makeRef(simobj).connect(ref)
1285
1286# VectorPort description object. Like Port, but represents a vector
1287# of connections (e.g., as on a Bus).
1288class VectorPort(Port):
1289 def __init__(self, *args):
1290 Port.__init__(self, *args)
1291 self.isVec = True
1292
1293 def makeRef(self, simobj):
1294 return VectorPortRef(simobj, self.name)
1295
1296# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1297# proxy objects (via set_param_desc()) so that proxy error messages
1298# make sense.
1299class PortParamDesc(object):
1300 __metaclass__ = Singleton
1301
1302 ptype_str = 'Port'
1303 ptype = Port
1304
1305baseEnums = allEnums.copy()
1306baseParams = allParams.copy()
1307
1308def clear():
1309 global allEnums, allParams
1310
1311 allEnums = baseEnums.copy()
1312 allParams = baseParams.copy()
1313
1314__all__ = ['Param', 'VectorParam',
1315 'Enum', 'Bool', 'String', 'Float',
1316 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1317 'Int32', 'UInt32', 'Int64', 'UInt64',
1318 'Counter', 'Addr', 'Tick', 'Percent',
1319 'TcpPort', 'UdpPort', 'EthernetAddr',
1320 'MemorySize', 'MemorySize32',
1321 'Latency', 'Frequency', 'Clock',
1322 'NetworkBandwidth', 'MemoryBandwidth',
1323 'Range', 'AddrRange', 'TickRange',
1324 'MaxAddr', 'MaxTick', 'AllMemory',
1325 'Time',
1326 'NextEthernetAddr', 'NULL',
1327 'Port', 'VectorPort']
1328
1329import SimObject
1172
1173 if self.ccConnected: # already done this
1174 return
1175 peer = self.peer
1176 if not self.peer: # nothing to connect to
1177 return
1178 try:
1179 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1180 peer.simobj.getCCObject(), peer.name, peer.index)
1181 except:
1182 print "Error connecting port %s.%s to %s.%s" % \
1183 (self.simobj.path(), self.name,
1184 peer.simobj.path(), peer.name)
1185 raise
1186 self.ccConnected = True
1187 peer.ccConnected = True
1188
1189# A reference to an individual element of a VectorPort... much like a
1190# PortRef, but has an index.
1191class VectorPortElementRef(PortRef):
1192 def __init__(self, simobj, name, index):
1193 PortRef.__init__(self, simobj, name)
1194 self.index = index
1195
1196 def __str__(self):
1197 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1198
1199# A reference to a complete vector-valued port (not just a single element).
1200# Can be indexed to retrieve individual VectorPortElementRef instances.
1201class VectorPortRef(object):
1202 def __init__(self, simobj, name):
1203 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1204 self.simobj = simobj
1205 self.name = name
1206 self.elements = []
1207
1208 def __str__(self):
1209 return '%s.%s[:]' % (self.simobj, self.name)
1210
1211 # for config.ini, print peer's name (not ours)
1212 def ini_str(self):
1213 return ' '.join([el.ini_str() for el in self.elements])
1214
1215 def __getitem__(self, key):
1216 if not isinstance(key, int):
1217 raise TypeError, "VectorPort index must be integer"
1218 if key >= len(self.elements):
1219 # need to extend list
1220 ext = [VectorPortElementRef(self.simobj, self.name, i)
1221 for i in range(len(self.elements), key+1)]
1222 self.elements.extend(ext)
1223 return self.elements[key]
1224
1225 def _get_next(self):
1226 return self[len(self.elements)]
1227
1228 def __setitem__(self, key, value):
1229 if not isinstance(key, int):
1230 raise TypeError, "VectorPort index must be integer"
1231 self[key].connect(value)
1232
1233 def connect(self, other):
1234 if isinstance(other, (list, tuple)):
1235 # Assign list of port refs to vector port.
1236 # For now, append them... not sure if that's the right semantics
1237 # or if it should replace the current vector.
1238 for ref in other:
1239 self._get_next().connect(ref)
1240 else:
1241 # scalar assignment to plain VectorPort is implicit append
1242 self._get_next().connect(other)
1243
1244 def clone(self, simobj, memo):
1245 if memo.has_key(self):
1246 return memo[self]
1247 newRef = copy.copy(self)
1248 memo[self] = newRef
1249 newRef.simobj = simobj
1250 assert(isSimObject(newRef.simobj))
1251 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1252 return newRef
1253
1254 def unproxy(self, simobj):
1255 [el.unproxy(simobj) for el in self.elements]
1256
1257 def ccConnect(self):
1258 [el.ccConnect() for el in self.elements]
1259
1260# Port description object. Like a ParamDesc object, this represents a
1261# logical port in the SimObject class, not a particular port on a
1262# SimObject instance. The latter are represented by PortRef objects.
1263class Port(object):
1264 # Port("description") or Port(default, "description")
1265 def __init__(self, *args):
1266 if len(args) == 1:
1267 self.desc = args[0]
1268 elif len(args) == 2:
1269 self.default = args[0]
1270 self.desc = args[1]
1271 else:
1272 raise TypeError, 'wrong number of arguments'
1273 # self.name is set by SimObject class on assignment
1274 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1275
1276 # Generate a PortRef for this port on the given SimObject with the
1277 # given name
1278 def makeRef(self, simobj):
1279 return PortRef(simobj, self.name)
1280
1281 # Connect an instance of this port (on the given SimObject with
1282 # the given name) with the port described by the supplied PortRef
1283 def connect(self, simobj, ref):
1284 self.makeRef(simobj).connect(ref)
1285
1286# VectorPort description object. Like Port, but represents a vector
1287# of connections (e.g., as on a Bus).
1288class VectorPort(Port):
1289 def __init__(self, *args):
1290 Port.__init__(self, *args)
1291 self.isVec = True
1292
1293 def makeRef(self, simobj):
1294 return VectorPortRef(simobj, self.name)
1295
1296# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1297# proxy objects (via set_param_desc()) so that proxy error messages
1298# make sense.
1299class PortParamDesc(object):
1300 __metaclass__ = Singleton
1301
1302 ptype_str = 'Port'
1303 ptype = Port
1304
1305baseEnums = allEnums.copy()
1306baseParams = allParams.copy()
1307
1308def clear():
1309 global allEnums, allParams
1310
1311 allEnums = baseEnums.copy()
1312 allParams = baseParams.copy()
1313
1314__all__ = ['Param', 'VectorParam',
1315 'Enum', 'Bool', 'String', 'Float',
1316 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1317 'Int32', 'UInt32', 'Int64', 'UInt64',
1318 'Counter', 'Addr', 'Tick', 'Percent',
1319 'TcpPort', 'UdpPort', 'EthernetAddr',
1320 'MemorySize', 'MemorySize32',
1321 'Latency', 'Frequency', 'Clock',
1322 'NetworkBandwidth', 'MemoryBandwidth',
1323 'Range', 'AddrRange', 'TickRange',
1324 'MaxAddr', 'MaxTick', 'AllMemory',
1325 'Time',
1326 'NextEthernetAddr', 'NULL',
1327 'Port', 'VectorPort']
1328
1329import SimObject