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):
382 def __init__(self
, value
):
383 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
384 self
.value
= float(value
)
386 raise TypeError, "Can't convert object of type %s to Float" \
387 % type(value
).__name
__
390 return float(self
.value
)
392 class MemorySize(CheckedInt
):
393 cxx_type
= 'uint64_t'
396 def __init__(self
, value
):
397 if isinstance(value
, MemorySize
):
398 self
.value
= value
.value
400 self
.value
= convert
.toMemorySize(value
)
403 class MemorySize32(CheckedInt
):
404 cxx_type
= 'uint32_t'
407 def __init__(self
, value
):
408 if isinstance(value
, MemorySize
):
409 self
.value
= value
.value
411 self
.value
= convert
.toMemorySize(value
)
414 class Addr(CheckedInt
):
418 def __init__(self
, value
):
419 if isinstance(value
, Addr
):
420 self
.value
= value
.value
423 self
.value
= convert
.toMemorySize(value
)
425 self
.value
= long(value
)
427 def __add__(self
, other
):
428 if isinstance(other
, Addr
):
429 return self
.value
+ other
.value
431 return self
.value
+ other
434 class MetaRange(MetaParamValue
):
435 def __init__(cls
, name
, bases
, dict):
436 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
439 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
441 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
443 class Range(ParamValue
):
444 __metaclass__
= MetaRange
445 type = Int
# default; can be overridden in subclasses
446 def __init__(self
, *args
, **kwargs
):
447 def handle_kwargs(self
, kwargs
):
449 self
.second
= self
.type(kwargs
.pop('end'))
450 elif 'size' in kwargs
:
451 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
453 raise TypeError, "Either end or size must be specified"
456 self
.first
= self
.type(kwargs
.pop('start'))
457 handle_kwargs(self
, kwargs
)
461 self
.first
= self
.type(args
[0])
462 handle_kwargs(self
, kwargs
)
463 elif isinstance(args
[0], Range
):
464 self
.first
= self
.type(args
[0].first
)
465 self
.second
= self
.type(args
[0].second
)
466 elif isinstance(args
[0], (list, tuple)):
467 self
.first
= self
.type(args
[0][0])
468 self
.second
= self
.type(args
[0][1])
470 self
.first
= self
.type(0)
471 self
.second
= self
.type(args
[0]) - 1
474 self
.first
= self
.type(args
[0])
475 self
.second
= self
.type(args
[1])
477 raise TypeError, "Too many arguments specified"
480 raise TypeError, "too many keywords: %s" % kwargs
.keys()
483 return '%s:%s' % (self
.first
, self
.second
)
485 class AddrRange(Range
):
487 swig_predecls
= ['%include "python/swig/range.i"']
490 from m5
.objects
.params
import AddrRange
493 value
.start
= long(self
.first
)
494 value
.end
= long(self
.second
)
497 class TickRange(Range
):
499 swig_predecls
= ['%include "python/swig/range.i"']
502 from m5
.objects
.params
import TickRange
505 value
.start
= long(self
.first
)
506 value
.end
= long(self
.second
)
509 # Boolean parameter type. Python doesn't let you subclass bool, since
510 # it doesn't want to let you create multiple instances of True and
511 # False. Thus this is a little more complicated than String.
512 class Bool(ParamValue
):
514 def __init__(self
, value
):
516 self
.value
= convert
.toBool(value
)
518 self
.value
= bool(value
)
521 return bool(self
.value
)
524 return str(self
.value
)
531 def IncEthernetAddr(addr
, val
= 1):
532 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
534 for i
in (5, 4, 3, 2, 1):
535 val
,rem
= divmod(bytes
[i
], 256)
540 assert(bytes
[0] <= 255)
541 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
543 _NextEthernetAddr
= "00:90:00:00:00:01"
544 def NextEthernetAddr():
545 global _NextEthernetAddr
547 value
= _NextEthernetAddr
548 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
551 class EthernetAddr(ParamValue
):
552 cxx_type
= 'Net::EthAddr'
553 cxx_predecls
= ['#include "base/inet.hh"']
554 swig_predecls
= ['%include "python/swig/inet.i"']
555 def __init__(self
, value
):
556 if value
== NextEthernetAddr
:
560 if not isinstance(value
, str):
561 raise TypeError, "expected an ethernet address and didn't get one"
563 bytes
= value
.split(':')
565 raise TypeError, 'invalid ethernet address %s' % value
568 if not 0 <= int(byte
) <= 256:
569 raise TypeError, 'invalid ethernet address %s' % value
573 def unproxy(self
, base
):
574 if self
.value
== NextEthernetAddr
:
575 return EthernetAddr(self
.value())
579 from m5
.objects
.params
import EthAddr
580 return EthAddr(self
.value
)
585 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
586 "%a %b %d %H:%M:%S %Z %Y",
598 def parse_time(value
):
599 from time
import gmtime
, strptime
, struct_time
, time
600 from datetime
import datetime
, date
602 if isinstance(value
, struct_time
):
605 if isinstance(value
, (int, long)):
608 if isinstance(value
, (datetime
, date
)):
609 return value
.timetuple()
611 if isinstance(value
, str):
612 if value
in ('Now', 'Today'):
613 return time
.gmtime(time
.time())
615 for format
in time_formats
:
617 return strptime(value
, format
)
621 raise ValueError, "Could not parse '%s' as a time" % value
623 class Time(ParamValue
):
625 cxx_predecls
= [ '#include <time.h>' ]
626 swig_predecls
= [ '%include "python/swig/time.i"' ]
627 def __init__(self
, value
):
628 self
.value
= parse_time(value
)
631 from m5
.objects
.params
import tm
636 # UNIX is years since 1900
637 c_time
.tm_year
= py_time
.tm_year
- 1900;
639 # Python starts at 1, UNIX starts at 0
640 c_time
.tm_mon
= py_time
.tm_mon
- 1;
641 c_time
.tm_mday
= py_time
.tm_mday
;
642 c_time
.tm_hour
= py_time
.tm_hour
;
643 c_time
.tm_min
= py_time
.tm_min
;
644 c_time
.tm_sec
= py_time
.tm_sec
;
646 # Python has 0 as Monday, UNIX is 0 as sunday
647 c_time
.tm_wday
= py_time
.tm_wday
+ 1
648 if c_time
.tm_wday
> 6:
651 # Python starts at 1, Unix starts at 0
652 c_time
.tm_yday
= py_time
.tm_yday
- 1;
657 return time
.asctime(self
.value
)
662 # Enumerated types are a little more complex. The user specifies the
663 # type as Enum(foo) where foo is either a list or dictionary of
664 # alternatives (typically strings, but not necessarily so). (In the
665 # long run, the integer value of the parameter will be the list index
666 # or the corresponding dictionary value. For now, since we only check
667 # that the alternative is valid and then spit it into a .ini file,
668 # there's not much point in using the dictionary.)
670 # What Enum() must do is generate a new type encapsulating the
671 # provided list/dictionary so that specific values of the parameter
672 # can be instances of that type. We define two hidden internal
673 # classes (_ListEnum and _DictEnum) to serve as base classes, then
674 # derive the new type from the appropriate base class on the fly.
677 # Metaclass for Enum types
678 class MetaEnum(MetaParamValue
):
679 def __new__(mcls
, name
, bases
, dict):
680 assert name
not in allEnums
682 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
686 def __init__(cls
, name
, bases
, init_dict
):
687 if init_dict
.has_key('map'):
688 if not isinstance(cls
.map, dict):
689 raise TypeError, "Enum-derived class attribute 'map' " \
690 "must be of type dict"
691 # build list of value strings from map
692 cls
.vals
= cls
.map.keys()
694 elif init_dict
.has_key('vals'):
695 if not isinstance(cls
.vals
, list):
696 raise TypeError, "Enum-derived class attribute 'vals' " \
697 "must be of type list"
698 # build string->value map from vals sequence
700 for idx
,val
in enumerate(cls
.vals
):
703 raise TypeError, "Enum-derived class must define "\
704 "attribute 'map' or 'vals'"
706 cls
.cxx_type
= 'Enums::%s' % name
708 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
713 # Generate C++ class declaration for this enum type.
714 # Note that we wrap the enum in a class/struct to act as a namespace,
715 # so that the enum strings can be brief w/o worrying about collisions.
717 code
= "#ifndef __ENUM__%s\n" % cls
718 code
+= '#define __ENUM__%s\n' % cls
720 code
+= 'namespace Enums {\n'
721 code
+= ' enum %s {\n' % cls
723 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
724 code
+= ' Num_%s = %d,\n' % (cls
, len(cls
.vals
))
726 code
+= ' extern const char *%sStrings[Num_%s];\n' % (cls
, cls
)
733 code
= '#include "enums/%s.hh"\n' % cls
734 code
+= 'namespace Enums {\n'
735 code
+= ' const char *%sStrings[Num_%s] =\n' % (cls
, cls
)
738 code
+= ' "%s",\n' % val
743 # Base class for enum types.
744 class Enum(ParamValue
):
745 __metaclass__
= MetaEnum
748 def __init__(self
, value
):
749 if value
not in self
.map:
750 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
755 return int(self
.map[self
.value
])
760 # how big does a rounding error need to be before we warn about it?
761 frequency_tolerance
= 0.001 # 0.1%
763 class TickParamValue(NumericParamValue
):
765 cxx_predecls
= ['#include "sim/host.hh"']
766 swig_predecls
= ['%import "stdint.i"\n' +
767 '%import "sim/host.hh"']
770 return long(self
.value
)
772 class Latency(TickParamValue
):
773 def __init__(self
, value
):
774 if isinstance(value
, (Latency
, Clock
)):
775 self
.ticks
= value
.ticks
776 self
.value
= value
.value
777 elif isinstance(value
, Frequency
):
778 self
.ticks
= value
.ticks
779 self
.value
= 1.0 / value
.value
780 elif value
.endswith('t'):
782 self
.value
= int(value
[:-1])
785 self
.value
= convert
.toLatency(value
)
787 def __getattr__(self
, attr
):
788 if attr
in ('latency', 'period'):
790 if attr
== 'frequency':
791 return Frequency(self
)
792 raise AttributeError, "Latency object has no attribute '%s'" % attr
795 if self
.ticks
or self
.value
== 0:
798 value
= ticks
.fromSeconds(self
.value
)
801 # convert latency to ticks
803 return '%d' % self
.getValue()
805 class Frequency(TickParamValue
):
806 def __init__(self
, value
):
807 if isinstance(value
, (Latency
, Clock
)):
811 self
.value
= 1.0 / value
.value
812 self
.ticks
= value
.ticks
813 elif isinstance(value
, Frequency
):
814 self
.value
= value
.value
815 self
.ticks
= value
.ticks
818 self
.value
= convert
.toFrequency(value
)
820 def __getattr__(self
, attr
):
821 if attr
== 'frequency':
823 if attr
in ('latency', 'period'):
825 raise AttributeError, "Frequency object has no attribute '%s'" % attr
827 # convert latency to ticks
829 if self
.ticks
or self
.value
== 0:
832 value
= ticks
.fromSeconds(1.0 / self
.value
)
836 return '%d' % self
.getValue()
838 # A generic frequency and/or Latency value. Value is stored as a latency,
839 # but to avoid ambiguity this object does not support numeric ops (* or /).
840 # An explicit conversion to a Latency or Frequency must be made first.
841 class Clock(ParamValue
):
843 cxx_predecls
= ['#include "sim/host.hh"']
844 swig_predecls
= ['%import "stdint.i"\n' +
845 '%import "sim/host.hh"']
846 def __init__(self
, value
):
847 if isinstance(value
, (Latency
, Clock
)):
848 self
.ticks
= value
.ticks
849 self
.value
= value
.value
850 elif isinstance(value
, Frequency
):
851 self
.ticks
= value
.ticks
852 self
.value
= 1.0 / value
.value
853 elif value
.endswith('t'):
855 self
.value
= int(value
[:-1])
858 self
.value
= convert
.anyToLatency(value
)
860 def __getattr__(self
, attr
):
861 if attr
== 'frequency':
862 return Frequency(self
)
863 if attr
in ('latency', 'period'):
865 raise AttributeError, "Frequency object has no attribute '%s'" % attr
868 return self
.period
.getValue()
871 return self
.period
.ini_str()
873 class NetworkBandwidth(float,ParamValue
):
875 def __new__(cls
, value
):
876 # convert to bits per second
877 val
= convert
.toNetworkBandwidth(value
)
878 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
884 # convert to seconds per byte
885 value
= 8.0 / float(self
)
886 # convert to ticks per byte
887 value
= ticks
.fromSeconds(value
)
891 return '%f' % self
.getValue()
893 class MemoryBandwidth(float,ParamValue
):
895 def __new__(cls
, value
):
896 # we want the number of ticks per byte of data
897 val
= convert
.toMemoryBandwidth(value
)
898 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
904 # convert to seconds per byte
907 value
= 1.0 / float(self
)
908 # convert to ticks per byte
909 value
= ticks
.fromSeconds(value
)
913 return '%f' % self
.getValue()
916 # "Constants"... handy aliases for various values.
919 # Special class for NULL pointers. Note the special check in
920 # make_param_value() above that lets these be assigned where a
921 # SimObject is required.
922 # only one copy of a particular node
923 class NullSimObject(object):
924 __metaclass__
= Singleton
929 def _instantiate(self
, parent
= None, path
= ''):
935 def unproxy(self
, base
):
938 def set_path(self
, parent
, name
):
947 # The only instance you'll ever need...
948 NULL
= NullSimObject()
950 def isNullPointer(value
):
951 return isinstance(value
, NullSimObject
)
953 # Some memory range specifications use this as a default upper bound.
956 AllMemory
= AddrRange(0, MaxAddr
)
959 #####################################################################
963 # Ports are used to interconnect objects in the memory system.
965 #####################################################################
967 # Port reference: encapsulates a reference to a particular port on a
968 # particular SimObject.
969 class PortRef(object):
970 def __init__(self
, simobj
, name
):
971 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
974 self
.peer
= None # not associated with another port yet
975 self
.ccConnected
= False # C++ port connection done?
976 self
.index
= -1 # always -1 for non-vector ports
979 return '%s.%s' % (self
.simobj
, self
.name
)
981 # for config.ini, print peer's name (not ours)
983 return str(self
.peer
)
985 def __getattr__(self
, attr
):
986 if attr
== 'peerObj':
987 # shorthand for proxies
988 return self
.peer
.simobj
989 raise AttributeError, "'%s' object has no attribute '%s'" % \
990 (self
.__class
__.__name
__, attr
)
992 # Full connection is symmetric (both ways). Called via
993 # SimObject.__setattr__ as a result of a port assignment, e.g.,
994 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
995 # e.g., "obj1.portA[3] = obj2.portB".
996 def connect(self
, other
):
997 if isinstance(other
, VectorPortRef
):
998 # reference to plain VectorPort is implicit append
999 other
= other
._get
_next
()
1000 if self
.peer
and not proxy
.isproxy(self
.peer
):
1001 print "warning: overwriting port", self
, \
1002 "value", self
.peer
, "with", other
1004 if proxy
.isproxy(other
):
1005 other
.set_param_desc(PortParamDesc())
1006 elif isinstance(other
, PortRef
):
1007 if other
.peer
is not self
:
1011 "assigning non-port reference '%s' to port '%s'" \
1014 def clone(self
, simobj
, memo
):
1015 if memo
.has_key(self
):
1017 newRef
= copy
.copy(self
)
1019 newRef
.simobj
= simobj
1020 assert(isSimObject(newRef
.simobj
))
1021 if self
.peer
and not proxy
.isproxy(self
.peer
):
1022 peerObj
= self
.peer
.simobj(_memo
=memo
)
1023 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1024 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1027 def unproxy(self
, simobj
):
1028 assert(simobj
is self
.simobj
)
1029 if proxy
.isproxy(self
.peer
):
1031 realPeer
= self
.peer
.unproxy(self
.simobj
)
1033 print "Error in unproxying port '%s' of %s" % \
1034 (self
.name
, self
.simobj
.path())
1036 self
.connect(realPeer
)
1038 # Call C++ to create corresponding port connection between C++ objects
1039 def ccConnect(self
):
1040 from m5
.objects
.params
import connectPorts
1042 if self
.ccConnected
: # already done this
1045 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1046 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1047 self
.ccConnected
= True
1048 peer
.ccConnected
= True
1050 # A reference to an individual element of a VectorPort... much like a
1051 # PortRef, but has an index.
1052 class VectorPortElementRef(PortRef
):
1053 def __init__(self
, simobj
, name
, index
):
1054 PortRef
.__init
__(self
, simobj
, name
)
1058 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1060 # A reference to a complete vector-valued port (not just a single element).
1061 # Can be indexed to retrieve individual VectorPortElementRef instances.
1062 class VectorPortRef(object):
1063 def __init__(self
, simobj
, name
):
1064 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1065 self
.simobj
= simobj
1070 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1072 # for config.ini, print peer's name (not ours)
1074 return ' '.join([el
.ini_str() for el
in self
.elements
])
1076 def __getitem__(self
, key
):
1077 if not isinstance(key
, int):
1078 raise TypeError, "VectorPort index must be integer"
1079 if key
>= len(self
.elements
):
1080 # need to extend list
1081 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1082 for i
in range(len(self
.elements
), key
+1)]
1083 self
.elements
.extend(ext
)
1084 return self
.elements
[key
]
1086 def _get_next(self
):
1087 return self
[len(self
.elements
)]
1089 def __setitem__(self
, key
, value
):
1090 if not isinstance(key
, int):
1091 raise TypeError, "VectorPort index must be integer"
1092 self
[key
].connect(value
)
1094 def connect(self
, other
):
1095 if isinstance(other
, (list, tuple)):
1096 # Assign list of port refs to vector port.
1097 # For now, append them... not sure if that's the right semantics
1098 # or if it should replace the current vector.
1100 self
._get
_next
().connect(ref
)
1102 # scalar assignment to plain VectorPort is implicit append
1103 self
._get
_next
().connect(other
)
1105 def clone(self
, simobj
, memo
):
1106 if memo
.has_key(self
):
1108 newRef
= copy
.copy(self
)
1110 newRef
.simobj
= simobj
1111 assert(isSimObject(newRef
.simobj
))
1112 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1115 def unproxy(self
, simobj
):
1116 [el
.unproxy(simobj
) for el
in self
.elements
]
1118 def ccConnect(self
):
1119 [el
.ccConnect() for el
in self
.elements
]
1121 # Port description object. Like a ParamDesc object, this represents a
1122 # logical port in the SimObject class, not a particular port on a
1123 # SimObject instance. The latter are represented by PortRef objects.
1125 # Port("description") or Port(default, "description")
1126 def __init__(self
, *args
):
1129 elif len(args
) == 2:
1130 self
.default
= args
[0]
1133 raise TypeError, 'wrong number of arguments'
1134 # self.name is set by SimObject class on assignment
1135 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1137 # Generate a PortRef for this port on the given SimObject with the
1139 def makeRef(self
, simobj
):
1140 return PortRef(simobj
, self
.name
)
1142 # Connect an instance of this port (on the given SimObject with
1143 # the given name) with the port described by the supplied PortRef
1144 def connect(self
, simobj
, ref
):
1145 self
.makeRef(simobj
).connect(ref
)
1147 # VectorPort description object. Like Port, but represents a vector
1148 # of connections (e.g., as on a Bus).
1149 class VectorPort(Port
):
1150 def __init__(self
, *args
):
1151 Port
.__init
__(self
, *args
)
1154 def makeRef(self
, simobj
):
1155 return VectorPortRef(simobj
, self
.name
)
1157 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1158 # proxy objects (via set_param_desc()) so that proxy error messages
1160 class PortParamDesc(object):
1161 __metaclass__
= Singleton
1166 __all__
= ['Param', 'VectorParam',
1167 'Enum', 'Bool', 'String', 'Float',
1168 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1169 'Int32', 'UInt32', 'Int64', 'UInt64',
1170 'Counter', 'Addr', 'Tick', 'Percent',
1171 'TcpPort', 'UdpPort', 'EthernetAddr',
1172 'MemorySize', 'MemorySize32',
1173 'Latency', 'Frequency', 'Clock',
1174 'NetworkBandwidth', 'MemoryBandwidth',
1175 'Range', 'AddrRange', 'TickRange',
1176 'MaxAddr', 'MaxTick', 'AllMemory',
1178 'NextEthernetAddr', 'NULL',
1179 'Port', 'VectorPort']