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