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