1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
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.
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.
27 # Authors: Steve Reinhardt
30 #####################################################################
32 # Parameter description classes
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
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.
45 #####################################################################
60 def isSimObject(*args
, **kwargs
):
61 return SimObject
.isSimObject(*args
, **kwargs
)
63 def isSimObjectSequence(*args
, **kwargs
):
64 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
66 def isSimObjectClass(*args
, **kwargs
):
67 return SimObject
.isSimObjectClass(*args
, **kwargs
)
71 class 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
79 # Dummy base class to identify types that are legitimate for SimObject
81 class ParamValue(object):
82 __metaclass__
= MetaParamValue
87 # default for printing to .ini file is regular string conversion.
88 # will be overridden in some cases
92 # allows us to blithely call unproxy() on things without checking
93 # if they're really proxies or not
94 def unproxy(self
, base
):
97 # Regular parameter description.
98 class 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
109 self
.default
= args
[0]
112 raise TypeError, 'too many arguments'
114 if kwargs
.has_key('desc'):
115 assert(not hasattr(self
, 'desc'))
116 self
.desc
= kwargs
['desc']
119 if kwargs
.has_key('default'):
120 assert(not hasattr(self
, 'default'))
121 self
.default
= kwargs
['default']
122 del kwargs
['default']
125 raise TypeError, 'extra unknown kwargs %s' % kwargs
127 if not hasattr(self
, 'desc'):
128 raise TypeError, 'desc attribute missing'
130 def __getattr__(self
, attr
):
132 ptype
= SimObject
.allClasses
[self
.ptype_str
]
133 assert issubclass(ptype
, SimObject
.SimObject
)
137 raise AttributeError, "'%s' object has no attribute '%s'" % \
138 (type(self
).__name
__, attr
)
140 def convert(self
, value
):
141 if isinstance(value
, proxy
.BaseProxy
):
142 value
.set_param_desc(self
)
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
148 if isinstance(value
, self
.ptype
):
150 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
152 return self
.ptype(value
)
154 def cxx_predecls(self
):
155 return self
.ptype
.cxx_predecls
157 def swig_predecls(self
):
158 return self
.ptype
.swig_predecls
161 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
163 # Vector-valued parameter description. Just like ParamDesc, except
164 # that the value is a vector (list) of the specified type instead of a
167 class VectorParamValue(list):
168 __metaclass__
= MetaParamValue
170 return ' '.join([v
.ini_str() for v
in self
])
173 return [ v
.getValue() for v
in self
]
175 def unproxy(self
, base
):
176 return [v
.unproxy(base
) for v
in self
]
178 class SimObjVector(VectorParamValue
):
179 def print_ini(self
, ini_file
):
181 v
.print_ini(ini_file
)
183 class VectorParamDesc(ParamDesc
):
184 # Convert assigned value to appropriate type. If the RHS is not a
185 # list or tuple, it generates a single-element list.
186 def convert(self
, value
):
187 if isinstance(value
, (list, tuple)):
188 # list: coerce each element into new list
189 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
191 # singleton: coerce to a single-element list
192 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
194 if isSimObjectSequence(tmp_list
):
195 return SimObjVector(tmp_list
)
197 return VectorParamValue(tmp_list
)
199 def swig_predecls(self
):
200 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
203 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
204 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
205 (self
.ptype_str
, cxx_type
)
206 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
208 def cxx_predecls(self
):
209 return ['#include <vector>'] + self
.ptype
.cxx_predecls
212 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
214 class ParamFactory(object):
215 def __init__(self
, param_desc_class
, ptype_str
= None):
216 self
.param_desc_class
= param_desc_class
217 self
.ptype_str
= ptype_str
219 def __getattr__(self
, attr
):
221 attr
= self
.ptype_str
+ '.' + attr
222 return ParamFactory(self
.param_desc_class
, attr
)
224 # E.g., Param.Int(5, "number of widgets")
225 def __call__(self
, *args
, **kwargs
):
228 ptype
= allParams
[self
.ptype_str
]
230 # if name isn't defined yet, assume it's a SimObject, and
231 # try to resolve it later
233 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
235 Param
= ParamFactory(ParamDesc
)
236 VectorParam
= ParamFactory(VectorParamDesc
)
238 #####################################################################
242 # Though native Python types could be used to specify parameter types
243 # (the 'ptype' field of the Param and VectorParam classes), it's more
244 # flexible to define our own set of types. This gives us more control
245 # over how Python expressions are converted to values (via the
246 # __init__() constructor) and how these values are printed out (via
247 # the __str__() conversion method).
249 #####################################################################
251 # String-valued parameter. Just mixin the ParamValue class with the
252 # built-in str class.
253 class String(ParamValue
,str):
254 cxx_type
= 'std::string'
255 cxx_predecls
= ['#include <string>']
256 swig_predecls
= ['%include "std_string.i"\n' +
257 '%apply const std::string& {std::string *};']
258 swig_predecls
= ['%include "std_string.i"' ]
263 # superclass for "numeric" parameter values, to emulate math
264 # operations in a type-safe way. e.g., a Latency times an int returns
265 # a new Latency object.
266 class NumericParamValue(ParamValue
):
268 return str(self
.value
)
271 return float(self
.value
)
274 return long(self
.value
)
277 return int(self
.value
)
279 # hook for bounds checking
283 def __mul__(self
, other
):
284 newobj
= self
.__class
__(self
)
285 newobj
.value
*= other
291 def __div__(self
, other
):
292 newobj
= self
.__class
__(self
)
293 newobj
.value
/= other
297 def __sub__(self
, other
):
298 newobj
= self
.__class
__(self
)
299 newobj
.value
-= other
303 # Metaclass for bounds-checked integer parameters. See CheckedInt.
304 class CheckedIntType(MetaParamValue
):
305 def __init__(cls
, name
, bases
, dict):
306 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
308 # CheckedInt is an abstract base class, so we actually don't
309 # want to do any processing on it... the rest of this code is
310 # just for classes that derive from CheckedInt.
311 if name
== 'CheckedInt':
314 if not cls
.cxx_predecls
:
315 # most derived types require this, so we just do it here once
316 cls
.cxx_predecls
= ['#include "sim/host.hh"']
318 if not cls
.swig_predecls
:
319 # most derived types require this, so we just do it here once
320 cls
.swig_predecls
= ['%import "stdint.i"\n' +
321 '%import "sim/host.hh"']
323 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
324 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
325 panic("CheckedInt subclass %s must define either\n" \
326 " 'min' and 'max' or 'size' and 'unsigned'\n" \
330 cls
.max = 2 ** cls
.size
- 1
332 cls
.min = -(2 ** (cls
.size
- 1))
333 cls
.max = (2 ** (cls
.size
- 1)) - 1
335 # Abstract superclass for bounds-checked integer parameters. This
336 # class is subclassed to generate parameter classes with specific
337 # bounds. Initialization of the min and max bounds is done in the
338 # metaclass CheckedIntType.__init__.
339 class CheckedInt(NumericParamValue
):
340 __metaclass__
= CheckedIntType
343 if not self
.min <= self
.value
<= self
.max:
344 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
345 (self
.min, self
.value
, self
.max)
347 def __init__(self
, value
):
348 if isinstance(value
, str):
349 self
.value
= convert
.toInteger(value
)
350 elif isinstance(value
, (int, long, float, NumericParamValue
)):
351 self
.value
= long(value
)
353 raise TypeError, "Can't convert object of type %s to CheckedInt" \
354 % type(value
).__name
__
358 return long(self
.value
)
360 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
361 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
363 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
364 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
365 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
366 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
367 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
368 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
369 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
370 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
372 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
373 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
374 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
375 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
377 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
379 class Float(ParamValue
, float):
383 return float(self
.value
)
385 class MemorySize(CheckedInt
):
386 cxx_type
= 'uint64_t'
389 def __init__(self
, value
):
390 if isinstance(value
, MemorySize
):
391 self
.value
= value
.value
393 self
.value
= convert
.toMemorySize(value
)
396 class MemorySize32(CheckedInt
):
397 cxx_type
= 'uint32_t'
400 def __init__(self
, value
):
401 if isinstance(value
, MemorySize
):
402 self
.value
= value
.value
404 self
.value
= convert
.toMemorySize(value
)
407 class Addr(CheckedInt
):
409 cxx_predecls
= ['#include "arch/isa_traits.hh"']
412 def __init__(self
, value
):
413 if isinstance(value
, Addr
):
414 self
.value
= value
.value
417 self
.value
= convert
.toMemorySize(value
)
419 self
.value
= long(value
)
421 def __add__(self
, other
):
422 if isinstance(other
, Addr
):
423 return self
.value
+ other
.value
425 return self
.value
+ other
428 class MetaRange(MetaParamValue
):
429 def __init__(cls
, name
, bases
, dict):
430 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
433 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
435 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
437 class Range(ParamValue
):
438 __metaclass__
= MetaRange
439 type = Int
# default; can be overridden in subclasses
440 def __init__(self
, *args
, **kwargs
):
441 def handle_kwargs(self
, kwargs
):
443 self
.second
= self
.type(kwargs
.pop('end'))
444 elif 'size' in kwargs
:
445 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
447 raise TypeError, "Either end or size must be specified"
450 self
.first
= self
.type(kwargs
.pop('start'))
451 handle_kwargs(self
, kwargs
)
455 self
.first
= self
.type(args
[0])
456 handle_kwargs(self
, kwargs
)
457 elif isinstance(args
[0], Range
):
458 self
.first
= self
.type(args
[0].first
)
459 self
.second
= self
.type(args
[0].second
)
460 elif isinstance(args
[0], (list, tuple)):
461 self
.first
= self
.type(args
[0][0])
462 self
.second
= self
.type(args
[0][1])
464 self
.first
= self
.type(0)
465 self
.second
= self
.type(args
[0]) - 1
468 self
.first
= self
.type(args
[0])
469 self
.second
= self
.type(args
[1])
471 raise TypeError, "Too many arguments specified"
474 raise TypeError, "too many keywords: %s" % kwargs
.keys()
477 return '%s:%s' % (self
.first
, self
.second
)
479 class AddrRange(Range
):
481 swig_predecls
= ['%include "python/swig/range.i"']
484 from m5
.objects
.params
import AddrRange
487 value
.start
= long(self
.first
)
488 value
.end
= long(self
.second
)
491 class TickRange(Range
):
493 swig_predecls
= ['%include "python/swig/range.i"']
496 from m5
.objects
.params
import TickRange
499 value
.start
= long(self
.first
)
500 value
.end
= long(self
.second
)
503 # Boolean parameter type. Python doesn't let you subclass bool, since
504 # it doesn't want to let you create multiple instances of True and
505 # False. Thus this is a little more complicated than String.
506 class Bool(ParamValue
):
508 def __init__(self
, value
):
510 self
.value
= convert
.toBool(value
)
512 self
.value
= bool(value
)
515 return bool(self
.value
)
518 return str(self
.value
)
525 def IncEthernetAddr(addr
, val
= 1):
526 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
528 for i
in (5, 4, 3, 2, 1):
529 val
,rem
= divmod(bytes
[i
], 256)
534 assert(bytes
[0] <= 255)
535 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
537 _NextEthernetAddr
= "00:90:00:00:00:01"
538 def NextEthernetAddr():
539 global _NextEthernetAddr
541 value
= _NextEthernetAddr
542 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
545 class EthernetAddr(ParamValue
):
546 cxx_type
= 'Net::EthAddr'
547 cxx_predecls
= ['#include "base/inet.hh"']
548 swig_predecls
= ['%include "python/swig/inet.i"']
549 def __init__(self
, value
):
550 if value
== NextEthernetAddr
:
554 if not isinstance(value
, str):
555 raise TypeError, "expected an ethernet address and didn't get one"
557 bytes
= value
.split(':')
559 raise TypeError, 'invalid ethernet address %s' % value
562 if not 0 <= int(byte
) <= 256:
563 raise TypeError, 'invalid ethernet address %s' % value
567 def unproxy(self
, base
):
568 if self
.value
== NextEthernetAddr
:
569 return EthernetAddr(self
.value())
573 from m5
.objects
.params
import EthAddr
574 return EthAddr(self
.value
)
579 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
580 "%a %b %d %H:%M:%S %Z %Y",
592 def parse_time(value
):
593 from time
import gmtime
, strptime
, struct_time
, time
594 from datetime
import datetime
, date
596 if isinstance(value
, struct_time
):
599 if isinstance(value
, (int, long)):
602 if isinstance(value
, (datetime
, date
)):
603 return value
.timetuple()
605 if isinstance(value
, str):
606 if value
in ('Now', 'Today'):
607 return time
.gmtime(time
.time())
609 for format
in time_formats
:
611 return strptime(value
, format
)
615 raise ValueError, "Could not parse '%s' as a time" % value
617 class Time(ParamValue
):
619 cxx_predecls
= [ '#include <time.h>' ]
620 swig_predecls
= [ '%include "python/swig/time.i"' ]
621 def __init__(self
, value
):
622 self
.value
= parse_time(value
)
625 from m5
.objects
.params
import tm
630 # UNIX is years since 1900
631 c_time
.tm_year
= py_time
.tm_year
- 1900;
633 # Python starts at 1, UNIX starts at 0
634 c_time
.tm_mon
= py_time
.tm_mon
- 1;
635 c_time
.tm_mday
= py_time
.tm_mday
;
636 c_time
.tm_hour
= py_time
.tm_hour
;
637 c_time
.tm_min
= py_time
.tm_min
;
638 c_time
.tm_sec
= py_time
.tm_sec
;
640 # Python has 0 as Monday, UNIX is 0 as sunday
641 c_time
.tm_wday
= py_time
.tm_wday
+ 1
642 if c_time
.tm_wday
> 6:
645 # Python starts at 1, Unix starts at 0
646 c_time
.tm_yday
= py_time
.tm_yday
- 1;
651 return time
.asctime(self
.value
)
656 # Enumerated types are a little more complex. The user specifies the
657 # type as Enum(foo) where foo is either a list or dictionary of
658 # alternatives (typically strings, but not necessarily so). (In the
659 # long run, the integer value of the parameter will be the list index
660 # or the corresponding dictionary value. For now, since we only check
661 # that the alternative is valid and then spit it into a .ini file,
662 # there's not much point in using the dictionary.)
664 # What Enum() must do is generate a new type encapsulating the
665 # provided list/dictionary so that specific values of the parameter
666 # can be instances of that type. We define two hidden internal
667 # classes (_ListEnum and _DictEnum) to serve as base classes, then
668 # derive the new type from the appropriate base class on the fly.
671 # Metaclass for Enum types
672 class MetaEnum(MetaParamValue
):
673 def __new__(mcls
, name
, bases
, dict):
674 assert name
not in allEnums
676 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
680 def __init__(cls
, name
, bases
, init_dict
):
681 if init_dict
.has_key('map'):
682 if not isinstance(cls
.map, dict):
683 raise TypeError, "Enum-derived class attribute 'map' " \
684 "must be of type dict"
685 # build list of value strings from map
686 cls
.vals
= cls
.map.keys()
688 elif init_dict
.has_key('vals'):
689 if not isinstance(cls
.vals
, list):
690 raise TypeError, "Enum-derived class attribute 'vals' " \
691 "must be of type list"
692 # build string->value map from vals sequence
694 for idx
,val
in enumerate(cls
.vals
):
697 raise TypeError, "Enum-derived class must define "\
698 "attribute 'map' or 'vals'"
700 cls
.cxx_type
= 'Enums::%s' % name
702 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
707 # Generate C++ class declaration for this enum type.
708 # Note that we wrap the enum in a class/struct to act as a namespace,
709 # so that the enum strings can be brief w/o worrying about collisions.
711 code
= "#ifndef __ENUM__%s\n" % cls
712 code
+= '#define __ENUM__%s\n' % cls
714 code
+= 'namespace Enums {\n'
715 code
+= ' enum %s {\n' % cls
717 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
718 code
+= ' Num_%s = %d,\n' % (cls
, len(cls
.vals
))
720 code
+= ' extern const char *%sStrings[Num_%s];\n' % (cls
, cls
)
727 code
= '#include "enums/%s.hh"\n' % cls
728 code
+= 'namespace Enums {\n'
729 code
+= ' const char *%sStrings[Num_%s] =\n' % (cls
, cls
)
732 code
+= ' "%s",\n' % val
737 # Base class for enum types.
738 class Enum(ParamValue
):
739 __metaclass__
= MetaEnum
742 def __init__(self
, value
):
743 if value
not in self
.map:
744 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
749 return int(self
.map[self
.value
])
754 # how big does a rounding error need to be before we warn about it?
755 frequency_tolerance
= 0.001 # 0.1%
757 class TickParamValue(NumericParamValue
):
759 cxx_predecls
= ['#include "sim/host.hh"']
760 swig_predecls
= ['%import "stdint.i"\n' +
761 '%import "sim/host.hh"']
764 return long(self
.value
)
766 class Latency(TickParamValue
):
767 def __init__(self
, value
):
768 if isinstance(value
, (Latency
, Clock
)):
769 self
.ticks
= value
.ticks
770 self
.value
= value
.value
771 elif isinstance(value
, Frequency
):
772 self
.ticks
= value
.ticks
773 self
.value
= 1.0 / value
.value
774 elif value
.endswith('t'):
776 self
.value
= int(value
[:-1])
779 self
.value
= convert
.toLatency(value
)
781 def __getattr__(self
, attr
):
782 if attr
in ('latency', 'period'):
784 if attr
== 'frequency':
785 return Frequency(self
)
786 raise AttributeError, "Latency object has no attribute '%s'" % attr
789 if self
.ticks
or self
.value
== 0:
792 value
= ticks
.fromSeconds(self
.value
)
795 # convert latency to ticks
797 return '%d' % self
.getValue()
799 class Frequency(TickParamValue
):
800 def __init__(self
, value
):
801 if isinstance(value
, (Latency
, Clock
)):
805 self
.value
= 1.0 / value
.value
806 self
.ticks
= value
.ticks
807 elif isinstance(value
, Frequency
):
808 self
.value
= value
.value
809 self
.ticks
= value
.ticks
812 self
.value
= convert
.toFrequency(value
)
814 def __getattr__(self
, attr
):
815 if attr
== 'frequency':
817 if attr
in ('latency', 'period'):
819 raise AttributeError, "Frequency object has no attribute '%s'" % attr
821 # convert latency to ticks
823 if self
.ticks
or self
.value
== 0:
826 value
= ticks
.fromSeconds(1.0 / self
.value
)
830 return '%d' % self
.getValue()
832 # A generic frequency and/or Latency value. Value is stored as a latency,
833 # but to avoid ambiguity this object does not support numeric ops (* or /).
834 # An explicit conversion to a Latency or Frequency must be made first.
835 class Clock(ParamValue
):
837 cxx_predecls
= ['#include "sim/host.hh"']
838 swig_predecls
= ['%import "stdint.i"\n' +
839 '%import "sim/host.hh"']
840 def __init__(self
, value
):
841 if isinstance(value
, (Latency
, Clock
)):
842 self
.ticks
= value
.ticks
843 self
.value
= value
.value
844 elif isinstance(value
, Frequency
):
845 self
.ticks
= value
.ticks
846 self
.value
= 1.0 / value
.value
847 elif value
.endswith('t'):
849 self
.value
= int(value
[:-1])
852 self
.value
= convert
.anyToLatency(value
)
854 def __getattr__(self
, attr
):
855 if attr
== 'frequency':
856 return Frequency(self
)
857 if attr
in ('latency', 'period'):
859 raise AttributeError, "Frequency object has no attribute '%s'" % attr
862 return self
.period
.getValue()
865 return self
.period
.ini_str()
867 class NetworkBandwidth(float,ParamValue
):
869 def __new__(cls
, value
):
870 # convert to bits per second
871 val
= convert
.toNetworkBandwidth(value
)
872 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
878 # convert to seconds per byte
879 value
= 8.0 / float(self
)
880 # convert to ticks per byte
881 value
= ticks
.fromSeconds(value
)
885 return '%f' % self
.getValue()
887 class MemoryBandwidth(float,ParamValue
):
889 def __new__(self
, value
):
890 # we want the number of ticks per byte of data
891 val
= convert
.toMemoryBandwidth(value
)
892 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
898 # convert to seconds per byte
899 value
= 1.0 / float(self
)
900 # convert to ticks per byte
901 value
= ticks
.fromSeconds(value
)
905 return '%f' % self
.getValue()
908 # "Constants"... handy aliases for various values.
911 # Special class for NULL pointers. Note the special check in
912 # make_param_value() above that lets these be assigned where a
913 # SimObject is required.
914 # only one copy of a particular node
915 class NullSimObject(object):
916 __metaclass__
= Singleton
921 def _instantiate(self
, parent
= None, path
= ''):
927 def unproxy(self
, base
):
930 def set_path(self
, parent
, name
):
939 # The only instance you'll ever need...
940 NULL
= NullSimObject()
942 def isNullPointer(value
):
943 return isinstance(value
, NullSimObject
)
945 # Some memory range specifications use this as a default upper bound.
948 AllMemory
= AddrRange(0, MaxAddr
)
951 #####################################################################
955 # Ports are used to interconnect objects in the memory system.
957 #####################################################################
959 # Port reference: encapsulates a reference to a particular port on a
960 # particular SimObject.
961 class PortRef(object):
962 def __init__(self
, simobj
, name
):
963 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
966 self
.peer
= None # not associated with another port yet
967 self
.ccConnected
= False # C++ port connection done?
968 self
.index
= -1 # always -1 for non-vector ports
971 return '%s.%s' % (self
.simobj
, self
.name
)
973 # for config.ini, print peer's name (not ours)
975 return str(self
.peer
)
977 def __getattr__(self
, attr
):
978 if attr
== 'peerObj':
979 # shorthand for proxies
980 return self
.peer
.simobj
981 raise AttributeError, "'%s' object has no attribute '%s'" % \
982 (self
.__class
__.__name
__, attr
)
984 # Full connection is symmetric (both ways). Called via
985 # SimObject.__setattr__ as a result of a port assignment, e.g.,
986 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
987 # e.g., "obj1.portA[3] = obj2.portB".
988 def connect(self
, other
):
989 if isinstance(other
, VectorPortRef
):
990 # reference to plain VectorPort is implicit append
991 other
= other
._get
_next
()
992 if self
.peer
and not proxy
.isproxy(self
.peer
):
993 print "warning: overwriting port", self
, \
994 "value", self
.peer
, "with", other
996 if proxy
.isproxy(other
):
997 other
.set_param_desc(PortParamDesc())
998 elif isinstance(other
, PortRef
):
999 if other
.peer
is not self
:
1003 "assigning non-port reference '%s' to port '%s'" \
1006 def clone(self
, simobj
, memo
):
1007 if memo
.has_key(self
):
1009 newRef
= copy
.copy(self
)
1011 newRef
.simobj
= simobj
1012 assert(isSimObject(newRef
.simobj
))
1013 if self
.peer
and not proxy
.isproxy(self
.peer
):
1014 peerObj
= self
.peer
.simobj(_memo
=memo
)
1015 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1016 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1019 def unproxy(self
, simobj
):
1020 assert(simobj
is self
.simobj
)
1021 if proxy
.isproxy(self
.peer
):
1023 realPeer
= self
.peer
.unproxy(self
.simobj
)
1025 print "Error in unproxying port '%s' of %s" % \
1026 (self
.name
, self
.simobj
.path())
1028 self
.connect(realPeer
)
1030 # Call C++ to create corresponding port connection between C++ objects
1031 def ccConnect(self
):
1032 from m5
.objects
.params
import connectPorts
1034 if self
.ccConnected
: # already done this
1037 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1038 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1039 self
.ccConnected
= True
1040 peer
.ccConnected
= True
1042 # A reference to an individual element of a VectorPort... much like a
1043 # PortRef, but has an index.
1044 class VectorPortElementRef(PortRef
):
1045 def __init__(self
, simobj
, name
, index
):
1046 PortRef
.__init
__(self
, simobj
, name
)
1050 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1052 # A reference to a complete vector-valued port (not just a single element).
1053 # Can be indexed to retrieve individual VectorPortElementRef instances.
1054 class VectorPortRef(object):
1055 def __init__(self
, simobj
, name
):
1056 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1057 self
.simobj
= simobj
1062 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1064 # for config.ini, print peer's name (not ours)
1066 return ' '.join([el
.ini_str() for el
in self
.elements
])
1068 def __getitem__(self
, key
):
1069 if not isinstance(key
, int):
1070 raise TypeError, "VectorPort index must be integer"
1071 if key
>= len(self
.elements
):
1072 # need to extend list
1073 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1074 for i
in range(len(self
.elements
), key
+1)]
1075 self
.elements
.extend(ext
)
1076 return self
.elements
[key
]
1078 def _get_next(self
):
1079 return self
[len(self
.elements
)]
1081 def __setitem__(self
, key
, value
):
1082 if not isinstance(key
, int):
1083 raise TypeError, "VectorPort index must be integer"
1084 self
[key
].connect(value
)
1086 def connect(self
, other
):
1087 if isinstance(other
, (list, tuple)):
1088 # Assign list of port refs to vector port.
1089 # For now, append them... not sure if that's the right semantics
1090 # or if it should replace the current vector.
1092 self
._get
_next
().connect(ref
)
1094 # scalar assignment to plain VectorPort is implicit append
1095 self
._get
_next
().connect(other
)
1097 def clone(self
, simobj
, memo
):
1098 if memo
.has_key(self
):
1100 newRef
= copy
.copy(self
)
1102 newRef
.simobj
= simobj
1103 assert(isSimObject(newRef
.simobj
))
1104 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1107 def unproxy(self
, simobj
):
1108 [el
.unproxy(simobj
) for el
in self
.elements
]
1110 def ccConnect(self
):
1111 [el
.ccConnect() for el
in self
.elements
]
1113 # Port description object. Like a ParamDesc object, this represents a
1114 # logical port in the SimObject class, not a particular port on a
1115 # SimObject instance. The latter are represented by PortRef objects.
1117 # Port("description") or Port(default, "description")
1118 def __init__(self
, *args
):
1121 elif len(args
) == 2:
1122 self
.default
= args
[0]
1125 raise TypeError, 'wrong number of arguments'
1126 # self.name is set by SimObject class on assignment
1127 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1129 # Generate a PortRef for this port on the given SimObject with the
1131 def makeRef(self
, simobj
):
1132 return PortRef(simobj
, self
.name
)
1134 # Connect an instance of this port (on the given SimObject with
1135 # the given name) with the port described by the supplied PortRef
1136 def connect(self
, simobj
, ref
):
1137 self
.makeRef(simobj
).connect(ref
)
1139 # VectorPort description object. Like Port, but represents a vector
1140 # of connections (e.g., as on a Bus).
1141 class VectorPort(Port
):
1142 def __init__(self
, *args
):
1143 Port
.__init
__(self
, *args
)
1146 def makeRef(self
, simobj
):
1147 return VectorPortRef(simobj
, self
.name
)
1149 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1150 # proxy objects (via set_param_desc()) so that proxy error messages
1152 class PortParamDesc(object):
1153 __metaclass__
= Singleton
1158 __all__
= ['Param', 'VectorParam',
1159 'Enum', 'Bool', 'String', 'Float',
1160 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1161 'Int32', 'UInt32', 'Int64', 'UInt64',
1162 'Counter', 'Addr', 'Tick', 'Percent',
1163 'TcpPort', 'UdpPort', 'EthernetAddr',
1164 'MemorySize', 'MemorySize32',
1165 'Latency', 'Frequency', 'Clock',
1166 'NetworkBandwidth', 'MemoryBandwidth',
1167 'Range', 'AddrRange', 'TickRange',
1168 'MaxAddr', 'MaxTick', 'AllMemory',
1170 'NextEthernetAddr', 'NULL',
1171 'Port', 'VectorPort']