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