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