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