params.py (6214:1ec0ec8933ae) params.py (6654:4c84e771cca7)
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
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
53import proxy
54import ticks
55from util import *
56
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
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 "base/types.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 "base/types.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
57def isSimObject(*args, **kwargs):
58 return SimObject.isSimObject(*args, **kwargs)
59
60def isSimObjectSequence(*args, **kwargs):
61 return SimObject.isSimObjectSequence(*args, **kwargs)
62
63def isSimObjectClass(*args, **kwargs):
64 return SimObject.isSimObjectClass(*args, **kwargs)
65
66allParams = {}
67
68class MetaParamValue(type):
69 def __new__(mcls, name, bases, dct):
70 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
71 assert name not in allParams
72 allParams[name] = cls
73 return cls
74
75
76# Dummy base class to identify types that are legitimate for SimObject
77# parameters.
78class ParamValue(object):
79 __metaclass__ = MetaParamValue
80
81 cxx_predecls = []
82 swig_predecls = []
83
84 # default for printing to .ini file is regular string conversion.
85 # will be overridden in some cases
86 def ini_str(self):
87 return str(self)
88
89 # allows us to blithely call unproxy() on things without checking
90 # if they're really proxies or not
91 def unproxy(self, base):
92 return self
93
94# Regular parameter description.
95class ParamDesc(object):
96 def __init__(self, ptype_str, ptype, *args, **kwargs):
97 self.ptype_str = ptype_str
98 # remember ptype only if it is provided
99 if ptype != None:
100 self.ptype = ptype
101
102 if args:
103 if len(args) == 1:
104 self.desc = args[0]
105 elif len(args) == 2:
106 self.default = args[0]
107 self.desc = args[1]
108 else:
109 raise TypeError, 'too many arguments'
110
111 if kwargs.has_key('desc'):
112 assert(not hasattr(self, 'desc'))
113 self.desc = kwargs['desc']
114 del kwargs['desc']
115
116 if kwargs.has_key('default'):
117 assert(not hasattr(self, 'default'))
118 self.default = kwargs['default']
119 del kwargs['default']
120
121 if kwargs:
122 raise TypeError, 'extra unknown kwargs %s' % kwargs
123
124 if not hasattr(self, 'desc'):
125 raise TypeError, 'desc attribute missing'
126
127 def __getattr__(self, attr):
128 if attr == 'ptype':
129 ptype = SimObject.allClasses[self.ptype_str]
130 assert issubclass(ptype, SimObject.SimObject)
131 self.ptype = ptype
132 return ptype
133
134 raise AttributeError, "'%s' object has no attribute '%s'" % \
135 (type(self).__name__, attr)
136
137 def convert(self, value):
138 if isinstance(value, proxy.BaseProxy):
139 value.set_param_desc(self)
140 return value
141 if not hasattr(self, 'ptype') and isNullPointer(value):
142 # deferred evaluation of SimObject; continue to defer if
143 # we're just assigning a null pointer
144 return value
145 if isinstance(value, self.ptype):
146 return value
147 if isNullPointer(value) and isSimObjectClass(self.ptype):
148 return value
149 return self.ptype(value)
150
151 def cxx_predecls(self):
152 return self.ptype.cxx_predecls
153
154 def swig_predecls(self):
155 return self.ptype.swig_predecls
156
157 def cxx_decl(self):
158 return '%s %s;' % (self.ptype.cxx_type, self.name)
159
160# Vector-valued parameter description. Just like ParamDesc, except
161# that the value is a vector (list) of the specified type instead of a
162# single value.
163
164class VectorParamValue(list):
165 __metaclass__ = MetaParamValue
166 def __setattr__(self, attr, value):
167 raise AttributeError, \
168 "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
169
170 def ini_str(self):
171 return ' '.join([v.ini_str() for v in self])
172
173 def getValue(self):
174 return [ v.getValue() for v in self ]
175
176 def unproxy(self, base):
177 return [v.unproxy(base) for v in self]
178
179class SimObjVector(VectorParamValue):
180 def print_ini(self, ini_file):
181 for v in self:
182 v.print_ini(ini_file)
183
184class VectorParamDesc(ParamDesc):
185 # Convert assigned value to appropriate type. If the RHS is not a
186 # list or tuple, it generates a single-element list.
187 def convert(self, value):
188 if isinstance(value, (list, tuple)):
189 # list: coerce each element into new list
190 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
191 else:
192 # singleton: coerce to a single-element list
193 tmp_list = [ ParamDesc.convert(self, value) ]
194
195 if isSimObjectSequence(tmp_list):
196 return SimObjVector(tmp_list)
197 else:
198 return VectorParamValue(tmp_list)
199
200 def swig_predecls(self):
201 return ['%%include "%s_vptype.i"' % self.ptype_str]
202
203 def swig_decl(self):
204 cxx_type = re.sub('std::', '', self.ptype.cxx_type)
205 vdecl = 'namespace std { %%template(vector_%s) vector< %s >; }' % \
206 (self.ptype_str, cxx_type)
207 return ['%include "std_vector.i"'] + self.ptype.swig_predecls + [vdecl]
208
209 def cxx_predecls(self):
210 return ['#include <vector>'] + self.ptype.cxx_predecls
211
212 def cxx_decl(self):
213 return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
214
215class ParamFactory(object):
216 def __init__(self, param_desc_class, ptype_str = None):
217 self.param_desc_class = param_desc_class
218 self.ptype_str = ptype_str
219
220 def __getattr__(self, attr):
221 if self.ptype_str:
222 attr = self.ptype_str + '.' + attr
223 return ParamFactory(self.param_desc_class, attr)
224
225 # E.g., Param.Int(5, "number of widgets")
226 def __call__(self, *args, **kwargs):
227 ptype = None
228 try:
229 ptype = allParams[self.ptype_str]
230 except KeyError:
231 # if name isn't defined yet, assume it's a SimObject, and
232 # try to resolve it later
233 pass
234 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
235
236Param = ParamFactory(ParamDesc)
237VectorParam = ParamFactory(VectorParamDesc)
238
239#####################################################################
240#
241# Parameter Types
242#
243# Though native Python types could be used to specify parameter types
244# (the 'ptype' field of the Param and VectorParam classes), it's more
245# flexible to define our own set of types. This gives us more control
246# over how Python expressions are converted to values (via the
247# __init__() constructor) and how these values are printed out (via
248# the __str__() conversion method).
249#
250#####################################################################
251
252# String-valued parameter. Just mixin the ParamValue class with the
253# built-in str class.
254class String(ParamValue,str):
255 cxx_type = 'std::string'
256 cxx_predecls = ['#include <string>']
257 swig_predecls = ['%include "std_string.i"\n' +
258 '%apply const std::string& {std::string *};']
259 swig_predecls = ['%include "std_string.i"' ]
260
261 def getValue(self):
262 return self
263
264# superclass for "numeric" parameter values, to emulate math
265# operations in a type-safe way. e.g., a Latency times an int returns
266# a new Latency object.
267class NumericParamValue(ParamValue):
268 def __str__(self):
269 return str(self.value)
270
271 def __float__(self):
272 return float(self.value)
273
274 def __long__(self):
275 return long(self.value)
276
277 def __int__(self):
278 return int(self.value)
279
280 # hook for bounds checking
281 def _check(self):
282 return
283
284 def __mul__(self, other):
285 newobj = self.__class__(self)
286 newobj.value *= other
287 newobj._check()
288 return newobj
289
290 __rmul__ = __mul__
291
292 def __div__(self, other):
293 newobj = self.__class__(self)
294 newobj.value /= other
295 newobj._check()
296 return newobj
297
298 def __sub__(self, other):
299 newobj = self.__class__(self)
300 newobj.value -= other
301 newobj._check()
302 return newobj
303
304# Metaclass for bounds-checked integer parameters. See CheckedInt.
305class CheckedIntType(MetaParamValue):
306 def __init__(cls, name, bases, dict):
307 super(CheckedIntType, cls).__init__(name, bases, dict)
308
309 # CheckedInt is an abstract base class, so we actually don't
310 # want to do any processing on it... the rest of this code is
311 # just for classes that derive from CheckedInt.
312 if name == 'CheckedInt':
313 return
314
315 if not cls.cxx_predecls:
316 # most derived types require this, so we just do it here once
317 cls.cxx_predecls = ['#include "base/types.hh"']
318
319 if not cls.swig_predecls:
320 # most derived types require this, so we just do it here once
321 cls.swig_predecls = ['%import "stdint.i"\n' +
322 '%import "base/types.hh"']
323
324 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
325 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
326 panic("CheckedInt subclass %s must define either\n" \
327 " 'min' and 'max' or 'size' and 'unsigned'\n",
328 name);
329 if cls.unsigned:
330 cls.min = 0
331 cls.max = 2 ** cls.size - 1
332 else:
333 cls.min = -(2 ** (cls.size - 1))
334 cls.max = (2 ** (cls.size - 1)) - 1
335
336# Abstract superclass for bounds-checked integer parameters. This
337# class is subclassed to generate parameter classes with specific
338# bounds. Initialization of the min and max bounds is done in the
339# metaclass CheckedIntType.__init__.
340class CheckedInt(NumericParamValue):
341 __metaclass__ = CheckedIntType
342
343 def _check(self):
344 if not self.min <= self.value <= self.max:
345 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
346 (self.min, self.value, self.max)
347
348 def __init__(self, value):
349 if isinstance(value, str):
350 self.value = convert.toInteger(value)
351 elif isinstance(value, (int, long, float, NumericParamValue)):
352 self.value = long(value)
353 else:
354 raise TypeError, "Can't convert object of type %s to CheckedInt" \
355 % type(value).__name__
356 self._check()
357
358 def getValue(self):
359 return long(self.value)
360
361class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
362class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
363
364class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
365class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
366class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
367class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
368class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
369class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
370class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
371class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
372
373class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
374class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
375class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
376class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
377
378class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
379
380class Float(ParamValue, float):
381 cxx_type = 'double'
382
383 def __init__(self, value):
384 if isinstance(value, (int, long, float, NumericParamValue, Float)):
385 self.value = float(value)
386 else:
387 raise TypeError, "Can't convert object of type %s to Float" \
388 % type(value).__name__
389
390 def getValue(self):
391 return float(self.value)
392
393class MemorySize(CheckedInt):
394 cxx_type = 'uint64_t'
395 size = 64
396 unsigned = True
397 def __init__(self, value):
398 if isinstance(value, MemorySize):
399 self.value = value.value
400 else:
401 self.value = convert.toMemorySize(value)
402 self._check()
403
404class MemorySize32(CheckedInt):
405 cxx_type = 'uint32_t'
406 size = 32
407 unsigned = True
408 def __init__(self, value):
409 if isinstance(value, MemorySize):
410 self.value = value.value
411 else:
412 self.value = convert.toMemorySize(value)
413 self._check()
414
415class Addr(CheckedInt):
416 cxx_type = 'Addr'
417 size = 64
418 unsigned = True
419 def __init__(self, value):
420 if isinstance(value, Addr):
421 self.value = value.value
422 else:
423 try:
424 self.value = convert.toMemorySize(value)
425 except TypeError:
426 self.value = long(value)
427 self._check()
428 def __add__(self, other):
429 if isinstance(other, Addr):
430 return self.value + other.value
431 else:
432 return self.value + other
433
434
435class MetaRange(MetaParamValue):
436 def __init__(cls, name, bases, dict):
437 super(MetaRange, cls).__init__(name, bases, dict)
438 if name == 'Range':
439 return
440 cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
441 cls.cxx_predecls = \
442 ['#include "base/range.hh"'] + cls.type.cxx_predecls
443
444class Range(ParamValue):
445 __metaclass__ = MetaRange
446 type = Int # default; can be overridden in subclasses
447 def __init__(self, *args, **kwargs):
448 def handle_kwargs(self, kwargs):
449 if 'end' in kwargs:
450 self.second = self.type(kwargs.pop('end'))
451 elif 'size' in kwargs:
452 self.second = self.first + self.type(kwargs.pop('size')) - 1
453 else:
454 raise TypeError, "Either end or size must be specified"
455
456 if len(args) == 0:
457 self.first = self.type(kwargs.pop('start'))
458 handle_kwargs(self, kwargs)
459
460 elif len(args) == 1:
461 if kwargs:
462 self.first = self.type(args[0])
463 handle_kwargs(self, kwargs)
464 elif isinstance(args[0], Range):
465 self.first = self.type(args[0].first)
466 self.second = self.type(args[0].second)
467 elif isinstance(args[0], (list, tuple)):
468 self.first = self.type(args[0][0])
469 self.second = self.type(args[0][1])
470 else:
471 self.first = self.type(0)
472 self.second = self.type(args[0]) - 1
473
474 elif len(args) == 2:
475 self.first = self.type(args[0])
476 self.second = self.type(args[1])
477 else:
478 raise TypeError, "Too many arguments specified"
479
480 if kwargs:
481 raise TypeError, "too many keywords: %s" % kwargs.keys()
482
483 def __str__(self):
484 return '%s:%s' % (self.first, self.second)
485
486class AddrRange(Range):
487 type = Addr
488 swig_predecls = ['%include "python/swig/range.i"']
489
490 def getValue(self):
491 from m5.objects.params import AddrRange
492
493 value = AddrRange()
494 value.start = long(self.first)
495 value.end = long(self.second)
496 return value
497
498class TickRange(Range):
499 type = Tick
500 swig_predecls = ['%include "python/swig/range.i"']
501
502 def getValue(self):
503 from m5.objects.params import TickRange
504
505 value = TickRange()
506 value.start = long(self.first)
507 value.end = long(self.second)
508 return value
509
510# Boolean parameter type. Python doesn't let you subclass bool, since
511# it doesn't want to let you create multiple instances of True and
512# False. Thus this is a little more complicated than String.
513class Bool(ParamValue):
514 cxx_type = 'bool'
515 def __init__(self, value):
516 try:
517 self.value = convert.toBool(value)
518 except TypeError:
519 self.value = bool(value)
520
521 def getValue(self):
522 return bool(self.value)
523
524 def __str__(self):
525 return str(self.value)
526
527 def ini_str(self):
528 if self.value:
529 return 'true'
530 return 'false'
531
532def IncEthernetAddr(addr, val = 1):
533 bytes = map(lambda x: int(x, 16), addr.split(':'))
534 bytes[5] += val
535 for i in (5, 4, 3, 2, 1):
536 val,rem = divmod(bytes[i], 256)
537 bytes[i] = rem
538 if val == 0:
539 break
540 bytes[i - 1] += val
541 assert(bytes[0] <= 255)
542 return ':'.join(map(lambda x: '%02x' % x, bytes))
543
544_NextEthernetAddr = "00:90:00:00:00:01"
545def NextEthernetAddr():
546 global _NextEthernetAddr
547
548 value = _NextEthernetAddr
549 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
550 return value
551
552class EthernetAddr(ParamValue):
553 cxx_type = 'Net::EthAddr'
554 cxx_predecls = ['#include "base/inet.hh"']
555 swig_predecls = ['%include "python/swig/inet.i"']
556 def __init__(self, value):
557 if value == NextEthernetAddr:
558 self.value = value
559 return
560
561 if not isinstance(value, str):
562 raise TypeError, "expected an ethernet address and didn't get one"
563
564 bytes = value.split(':')
565 if len(bytes) != 6:
566 raise TypeError, 'invalid ethernet address %s' % value
567
568 for byte in bytes:
569 if not 0 <= int(byte) <= 256:
570 raise TypeError, 'invalid ethernet address %s' % value
571
572 self.value = value
573
574 def unproxy(self, base):
575 if self.value == NextEthernetAddr:
576 return EthernetAddr(self.value())
577 return self
578
579 def getValue(self):
580 from m5.objects.params import EthAddr
581 return EthAddr(self.value)
582
583 def ini_str(self):
584 return self.value
585
586time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
587 "%a %b %d %H:%M:%S %Z %Y",
588 "%Y/%m/%d %H:%M:%S",
589 "%Y/%m/%d %H:%M",
590 "%Y/%m/%d",
591 "%m/%d/%Y %H:%M:%S",
592 "%m/%d/%Y %H:%M",
593 "%m/%d/%Y",
594 "%m/%d/%y %H:%M:%S",
595 "%m/%d/%y %H:%M",
596 "%m/%d/%y"]
597
598
599def parse_time(value):
600 from time import gmtime, strptime, struct_time, time
601 from datetime import datetime, date
602
603 if isinstance(value, struct_time):
604 return value
605
606 if isinstance(value, (int, long)):
607 return gmtime(value)
608
609 if isinstance(value, (datetime, date)):
610 return value.timetuple()
611
612 if isinstance(value, str):
613 if value in ('Now', 'Today'):
614 return time.gmtime(time.time())
615
616 for format in time_formats:
617 try:
618 return strptime(value, format)
619 except ValueError:
620 pass
621
622 raise ValueError, "Could not parse '%s' as a time" % value
623
624class Time(ParamValue):
625 cxx_type = 'tm'
626 cxx_predecls = [ '#include <time.h>' ]
627 swig_predecls = [ '%include "python/swig/time.i"' ]
628 def __init__(self, value):
629 self.value = parse_time(value)
630
631 def getValue(self):
632 from m5.objects.params import tm
633
634 c_time = tm()
635 py_time = self.value
636
637 # UNIX is years since 1900
638 c_time.tm_year = py_time.tm_year - 1900;
639
640 # Python starts at 1, UNIX starts at 0
641 c_time.tm_mon = py_time.tm_mon - 1;
642 c_time.tm_mday = py_time.tm_mday;
643 c_time.tm_hour = py_time.tm_hour;
644 c_time.tm_min = py_time.tm_min;
645 c_time.tm_sec = py_time.tm_sec;
646
647 # Python has 0 as Monday, UNIX is 0 as sunday
648 c_time.tm_wday = py_time.tm_wday + 1
649 if c_time.tm_wday > 6:
650 c_time.tm_wday -= 7;
651
652 # Python starts at 1, Unix starts at 0
653 c_time.tm_yday = py_time.tm_yday - 1;
654
655 return c_time
656
657 def __str__(self):
658 return time.asctime(self.value)
659
660 def ini_str(self):
661 return str(self)
662
663# Enumerated types are a little more complex. The user specifies the
664# type as Enum(foo) where foo is either a list or dictionary of
665# alternatives (typically strings, but not necessarily so). (In the
666# long run, the integer value of the parameter will be the list index
667# or the corresponding dictionary value. For now, since we only check
668# that the alternative is valid and then spit it into a .ini file,
669# there's not much point in using the dictionary.)
670
671# What Enum() must do is generate a new type encapsulating the
672# provided list/dictionary so that specific values of the parameter
673# can be instances of that type. We define two hidden internal
674# classes (_ListEnum and _DictEnum) to serve as base classes, then
675# derive the new type from the appropriate base class on the fly.
676
677allEnums = {}
678# Metaclass for Enum types
679class MetaEnum(MetaParamValue):
680 def __new__(mcls, name, bases, dict):
681 assert name not in allEnums
682
683 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
684 allEnums[name] = cls
685 return cls
686
687 def __init__(cls, name, bases, init_dict):
688 if init_dict.has_key('map'):
689 if not isinstance(cls.map, dict):
690 raise TypeError, "Enum-derived class attribute 'map' " \
691 "must be of type dict"
692 # build list of value strings from map
693 cls.vals = cls.map.keys()
694 cls.vals.sort()
695 elif init_dict.has_key('vals'):
696 if not isinstance(cls.vals, list):
697 raise TypeError, "Enum-derived class attribute 'vals' " \
698 "must be of type list"
699 # build string->value map from vals sequence
700 cls.map = {}
701 for idx,val in enumerate(cls.vals):
702 cls.map[val] = idx
703 else:
704 raise TypeError, "Enum-derived class must define "\
705 "attribute 'map' or 'vals'"
706
707 cls.cxx_type = 'Enums::%s' % name
708
709 super(MetaEnum, cls).__init__(name, bases, init_dict)
710
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):
711 # Generate C++ class declaration for this enum type.
712 # Note that we wrap the enum in a class/struct to act as a namespace,
713 # so that the enum strings can be brief w/o worrying about collisions.
714 def cxx_decl(cls):
721 code = "#ifndef __ENUM__%s\n" % cls
722 code += '#define __ENUM__%s\n' % cls
715 name = cls.__name__
716 code = "#ifndef __ENUM__%s\n" % name
717 code += '#define __ENUM__%s\n' % name
723 code += '\n'
724 code += 'namespace Enums {\n'
718 code += '\n'
719 code += 'namespace Enums {\n'
725 code += ' enum %s {\n' % cls
720 code += ' enum %s {\n' % name
726 for val in cls.vals:
727 code += ' %s = %d,\n' % (val, cls.map[val])
721 for val in cls.vals:
722 code += ' %s = %d,\n' % (val, cls.map[val])
728 code += ' Num_%s = %d,\n' % (cls, len(cls.vals))
723 code += ' Num_%s = %d,\n' % (name, len(cls.vals))
729 code += ' };\n'
724 code += ' };\n'
730 code += ' extern const char *%sStrings[Num_%s];\n' % (cls, cls)
725 code += ' extern const char *%sStrings[Num_%s];\n' % (name, name)
731 code += '}\n'
732 code += '\n'
733 code += '#endif\n'
734 return code
735
736 def cxx_def(cls):
726 code += '}\n'
727 code += '\n'
728 code += '#endif\n'
729 return code
730
731 def cxx_def(cls):
737 code = '#include "enums/%s.hh"\n' % cls
732 name = cls.__name__
733 code = '#include "enums/%s.hh"\n' % name
738 code += 'namespace Enums {\n'
734 code += 'namespace Enums {\n'
739 code += ' const char *%sStrings[Num_%s] =\n' % (cls, cls)
735 code += ' const char *%sStrings[Num_%s] =\n' % (name, name)
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 "base/types.hh"']
770 swig_predecls = ['%import "stdint.i"\n' +
771 '%import "base/types.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 "base/types.hh"']
848 swig_predecls = ['%import "stdint.i"\n' +
849 '%import "base/types.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.peer = None
1008 self.peer = other
1009 if proxy.isproxy(other):
1010 other.set_param_desc(PortParamDesc())
1011 elif isinstance(other, PortRef):
1012 if other.peer is not self:
1013 other.connect(self)
1014 else:
1015 raise TypeError, \
1016 "assigning non-port reference '%s' to port '%s'" \
1017 % (other, self)
1018
1019 def clone(self, simobj, memo):
1020 if memo.has_key(self):
1021 return memo[self]
1022 newRef = copy.copy(self)
1023 memo[self] = newRef
1024 newRef.simobj = simobj
1025 assert(isSimObject(newRef.simobj))
1026 if self.peer and not proxy.isproxy(self.peer):
1027 peerObj = self.peer.simobj(_memo=memo)
1028 newRef.peer = self.peer.clone(peerObj, memo)
1029 assert(not isinstance(newRef.peer, VectorPortRef))
1030 return newRef
1031
1032 def unproxy(self, simobj):
1033 assert(simobj is self.simobj)
1034 if proxy.isproxy(self.peer):
1035 try:
1036 realPeer = self.peer.unproxy(self.simobj)
1037 except:
1038 print "Error in unproxying port '%s' of %s" % \
1039 (self.name, self.simobj.path())
1040 raise
1041 self.connect(realPeer)
1042
1043 # Call C++ to create corresponding port connection between C++ objects
1044 def ccConnect(self):
1045 from m5.objects.params import connectPorts
1046
1047 if self.ccConnected: # already done this
1048 return
1049 peer = self.peer
1050 if not self.peer: # nothing to connect to
1051 return
1052 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1053 peer.simobj.getCCObject(), peer.name, peer.index)
1054 self.ccConnected = True
1055 peer.ccConnected = True
1056
1057# A reference to an individual element of a VectorPort... much like a
1058# PortRef, but has an index.
1059class VectorPortElementRef(PortRef):
1060 def __init__(self, simobj, name, index):
1061 PortRef.__init__(self, simobj, name)
1062 self.index = index
1063
1064 def __str__(self):
1065 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1066
1067# A reference to a complete vector-valued port (not just a single element).
1068# Can be indexed to retrieve individual VectorPortElementRef instances.
1069class VectorPortRef(object):
1070 def __init__(self, simobj, name):
1071 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1072 self.simobj = simobj
1073 self.name = name
1074 self.elements = []
1075
1076 def __str__(self):
1077 return '%s.%s[:]' % (self.simobj, self.name)
1078
1079 # for config.ini, print peer's name (not ours)
1080 def ini_str(self):
1081 return ' '.join([el.ini_str() for el in self.elements])
1082
1083 def __getitem__(self, key):
1084 if not isinstance(key, int):
1085 raise TypeError, "VectorPort index must be integer"
1086 if key >= len(self.elements):
1087 # need to extend list
1088 ext = [VectorPortElementRef(self.simobj, self.name, i)
1089 for i in range(len(self.elements), key+1)]
1090 self.elements.extend(ext)
1091 return self.elements[key]
1092
1093 def _get_next(self):
1094 return self[len(self.elements)]
1095
1096 def __setitem__(self, key, value):
1097 if not isinstance(key, int):
1098 raise TypeError, "VectorPort index must be integer"
1099 self[key].connect(value)
1100
1101 def connect(self, other):
1102 if isinstance(other, (list, tuple)):
1103 # Assign list of port refs to vector port.
1104 # For now, append them... not sure if that's the right semantics
1105 # or if it should replace the current vector.
1106 for ref in other:
1107 self._get_next().connect(ref)
1108 else:
1109 # scalar assignment to plain VectorPort is implicit append
1110 self._get_next().connect(other)
1111
1112 def clone(self, simobj, memo):
1113 if memo.has_key(self):
1114 return memo[self]
1115 newRef = copy.copy(self)
1116 memo[self] = newRef
1117 newRef.simobj = simobj
1118 assert(isSimObject(newRef.simobj))
1119 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1120 return newRef
1121
1122 def unproxy(self, simobj):
1123 [el.unproxy(simobj) for el in self.elements]
1124
1125 def ccConnect(self):
1126 [el.ccConnect() for el in self.elements]
1127
1128# Port description object. Like a ParamDesc object, this represents a
1129# logical port in the SimObject class, not a particular port on a
1130# SimObject instance. The latter are represented by PortRef objects.
1131class Port(object):
1132 # Port("description") or Port(default, "description")
1133 def __init__(self, *args):
1134 if len(args) == 1:
1135 self.desc = args[0]
1136 elif len(args) == 2:
1137 self.default = args[0]
1138 self.desc = args[1]
1139 else:
1140 raise TypeError, 'wrong number of arguments'
1141 # self.name is set by SimObject class on assignment
1142 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1143
1144 # Generate a PortRef for this port on the given SimObject with the
1145 # given name
1146 def makeRef(self, simobj):
1147 return PortRef(simobj, self.name)
1148
1149 # Connect an instance of this port (on the given SimObject with
1150 # the given name) with the port described by the supplied PortRef
1151 def connect(self, simobj, ref):
1152 self.makeRef(simobj).connect(ref)
1153
1154# VectorPort description object. Like Port, but represents a vector
1155# of connections (e.g., as on a Bus).
1156class VectorPort(Port):
1157 def __init__(self, *args):
1158 Port.__init__(self, *args)
1159 self.isVec = True
1160
1161 def makeRef(self, simobj):
1162 return VectorPortRef(simobj, self.name)
1163
1164# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1165# proxy objects (via set_param_desc()) so that proxy error messages
1166# make sense.
1167class PortParamDesc(object):
1168 __metaclass__ = Singleton
1169
1170 ptype_str = 'Port'
1171 ptype = Port
1172
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 "base/types.hh"']
766 swig_predecls = ['%import "stdint.i"\n' +
767 '%import "base/types.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 "base/types.hh"']
844 swig_predecls = ['%import "stdint.i"\n' +
845 '%import "base/types.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.peer = None
1004 self.peer = other
1005 if proxy.isproxy(other):
1006 other.set_param_desc(PortParamDesc())
1007 elif isinstance(other, PortRef):
1008 if other.peer is not self:
1009 other.connect(self)
1010 else:
1011 raise TypeError, \
1012 "assigning non-port reference '%s' to port '%s'" \
1013 % (other, self)
1014
1015 def clone(self, simobj, memo):
1016 if memo.has_key(self):
1017 return memo[self]
1018 newRef = copy.copy(self)
1019 memo[self] = newRef
1020 newRef.simobj = simobj
1021 assert(isSimObject(newRef.simobj))
1022 if self.peer and not proxy.isproxy(self.peer):
1023 peerObj = self.peer.simobj(_memo=memo)
1024 newRef.peer = self.peer.clone(peerObj, memo)
1025 assert(not isinstance(newRef.peer, VectorPortRef))
1026 return newRef
1027
1028 def unproxy(self, simobj):
1029 assert(simobj is self.simobj)
1030 if proxy.isproxy(self.peer):
1031 try:
1032 realPeer = self.peer.unproxy(self.simobj)
1033 except:
1034 print "Error in unproxying port '%s' of %s" % \
1035 (self.name, self.simobj.path())
1036 raise
1037 self.connect(realPeer)
1038
1039 # Call C++ to create corresponding port connection between C++ objects
1040 def ccConnect(self):
1041 from m5.objects.params import connectPorts
1042
1043 if self.ccConnected: # already done this
1044 return
1045 peer = self.peer
1046 if not self.peer: # nothing to connect to
1047 return
1048 connectPorts(self.simobj.getCCObject(), self.name, self.index,
1049 peer.simobj.getCCObject(), peer.name, peer.index)
1050 self.ccConnected = True
1051 peer.ccConnected = True
1052
1053# A reference to an individual element of a VectorPort... much like a
1054# PortRef, but has an index.
1055class VectorPortElementRef(PortRef):
1056 def __init__(self, simobj, name, index):
1057 PortRef.__init__(self, simobj, name)
1058 self.index = index
1059
1060 def __str__(self):
1061 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1062
1063# A reference to a complete vector-valued port (not just a single element).
1064# Can be indexed to retrieve individual VectorPortElementRef instances.
1065class VectorPortRef(object):
1066 def __init__(self, simobj, name):
1067 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1068 self.simobj = simobj
1069 self.name = name
1070 self.elements = []
1071
1072 def __str__(self):
1073 return '%s.%s[:]' % (self.simobj, self.name)
1074
1075 # for config.ini, print peer's name (not ours)
1076 def ini_str(self):
1077 return ' '.join([el.ini_str() for el in self.elements])
1078
1079 def __getitem__(self, key):
1080 if not isinstance(key, int):
1081 raise TypeError, "VectorPort index must be integer"
1082 if key >= len(self.elements):
1083 # need to extend list
1084 ext = [VectorPortElementRef(self.simobj, self.name, i)
1085 for i in range(len(self.elements), key+1)]
1086 self.elements.extend(ext)
1087 return self.elements[key]
1088
1089 def _get_next(self):
1090 return self[len(self.elements)]
1091
1092 def __setitem__(self, key, value):
1093 if not isinstance(key, int):
1094 raise TypeError, "VectorPort index must be integer"
1095 self[key].connect(value)
1096
1097 def connect(self, other):
1098 if isinstance(other, (list, tuple)):
1099 # Assign list of port refs to vector port.
1100 # For now, append them... not sure if that's the right semantics
1101 # or if it should replace the current vector.
1102 for ref in other:
1103 self._get_next().connect(ref)
1104 else:
1105 # scalar assignment to plain VectorPort is implicit append
1106 self._get_next().connect(other)
1107
1108 def clone(self, simobj, memo):
1109 if memo.has_key(self):
1110 return memo[self]
1111 newRef = copy.copy(self)
1112 memo[self] = newRef
1113 newRef.simobj = simobj
1114 assert(isSimObject(newRef.simobj))
1115 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1116 return newRef
1117
1118 def unproxy(self, simobj):
1119 [el.unproxy(simobj) for el in self.elements]
1120
1121 def ccConnect(self):
1122 [el.ccConnect() for el in self.elements]
1123
1124# Port description object. Like a ParamDesc object, this represents a
1125# logical port in the SimObject class, not a particular port on a
1126# SimObject instance. The latter are represented by PortRef objects.
1127class Port(object):
1128 # Port("description") or Port(default, "description")
1129 def __init__(self, *args):
1130 if len(args) == 1:
1131 self.desc = args[0]
1132 elif len(args) == 2:
1133 self.default = args[0]
1134 self.desc = args[1]
1135 else:
1136 raise TypeError, 'wrong number of arguments'
1137 # self.name is set by SimObject class on assignment
1138 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1139
1140 # Generate a PortRef for this port on the given SimObject with the
1141 # given name
1142 def makeRef(self, simobj):
1143 return PortRef(simobj, self.name)
1144
1145 # Connect an instance of this port (on the given SimObject with
1146 # the given name) with the port described by the supplied PortRef
1147 def connect(self, simobj, ref):
1148 self.makeRef(simobj).connect(ref)
1149
1150# VectorPort description object. Like Port, but represents a vector
1151# of connections (e.g., as on a Bus).
1152class VectorPort(Port):
1153 def __init__(self, *args):
1154 Port.__init__(self, *args)
1155 self.isVec = True
1156
1157 def makeRef(self, simobj):
1158 return VectorPortRef(simobj, self.name)
1159
1160# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1161# proxy objects (via set_param_desc()) so that proxy error messages
1162# make sense.
1163class PortParamDesc(object):
1164 __metaclass__ = Singleton
1165
1166 ptype_str = 'Port'
1167 ptype = Port
1168
1169baseEnums = allEnums.copy()
1170baseParams = allParams.copy()
1171
1172def clear():
1173 global allEnums, allParams
1174
1175 allEnums = baseEnums.copy()
1176 allParams = baseParams.copy()
1177
1173__all__ = ['Param', 'VectorParam',
1174 'Enum', 'Bool', 'String', 'Float',
1175 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1176 'Int32', 'UInt32', 'Int64', 'UInt64',
1177 'Counter', 'Addr', 'Tick', 'Percent',
1178 'TcpPort', 'UdpPort', 'EthernetAddr',
1179 'MemorySize', 'MemorySize32',
1180 'Latency', 'Frequency', 'Clock',
1181 'NetworkBandwidth', 'MemoryBandwidth',
1182 'Range', 'AddrRange', 'TickRange',
1183 'MaxAddr', 'MaxTick', 'AllMemory',
1184 'Time',
1185 'NextEthernetAddr', 'NULL',
1186 'Port', 'VectorPort']
1178__all__ = ['Param', 'VectorParam',
1179 'Enum', 'Bool', 'String', 'Float',
1180 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1181 'Int32', 'UInt32', 'Int64', 'UInt64',
1182 'Counter', 'Addr', 'Tick', 'Percent',
1183 'TcpPort', 'UdpPort', 'EthernetAddr',
1184 'MemorySize', 'MemorySize32',
1185 'Latency', 'Frequency', 'Clock',
1186 'NetworkBandwidth', 'MemoryBandwidth',
1187 'Range', 'AddrRange', 'TickRange',
1188 'MaxAddr', 'MaxTick', 'AllMemory',
1189 'Time',
1190 'NextEthernetAddr', 'NULL',
1191 'Port', 'VectorPort']
1192
1193import SimObject