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