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