00bba636b6150ebf5dac2e9157a51f610cc83dd8
1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
2 # Copyright (c) 2010 Advanced Micro Devices, Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # Authors: Steve Reinhardt
31 #####################################################################
33 # Parameter description classes
35 # The _params dictionary in each class maps parameter names to either
36 # a Param or a VectorParam object. These objects contain the
37 # parameter description string, the parameter type, and the default
38 # value (if any). The convert() method on these objects is used to
39 # force whatever value is assigned to the parameter to the appropriate
42 # Note that the default values are loaded into the class's attribute
43 # space when the parameter dictionary is initialized (in
44 # MetaSimObject._new_param()); after that point they aren't used.
46 #####################################################################
59 def isSimObject(*args
, **kwargs
):
60 return SimObject
.isSimObject(*args
, **kwargs
)
62 def isSimObjectSequence(*args
, **kwargs
):
63 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
65 def isSimObjectClass(*args
, **kwargs
):
66 return SimObject
.isSimObjectClass(*args
, **kwargs
)
70 class MetaParamValue(type):
71 def __new__(mcls
, name
, bases
, dct
):
72 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
73 assert name
not in allParams
78 # Dummy base class to identify types that are legitimate for SimObject
80 class ParamValue(object):
81 __metaclass__
= MetaParamValue
84 def cxx_predecls(cls
, code
):
88 def swig_predecls(cls
, code
):
91 # default for printing to .ini file is regular string conversion.
92 # will be overridden in some cases
96 # allows us to blithely call unproxy() on things without checking
97 # if they're really proxies or not
98 def unproxy(self
, base
):
101 # Regular parameter description.
102 class ParamDesc(object):
105 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
106 self
.ptype_str
= ptype_str
107 # remember ptype only if it is provided
115 self
.default
= args
[0]
118 raise TypeError, 'too many arguments'
120 if kwargs
.has_key('desc'):
121 assert(not hasattr(self
, 'desc'))
122 self
.desc
= kwargs
['desc']
125 if kwargs
.has_key('default'):
126 assert(not hasattr(self
, 'default'))
127 self
.default
= kwargs
['default']
128 del kwargs
['default']
131 raise TypeError, 'extra unknown kwargs %s' % kwargs
133 if not hasattr(self
, 'desc'):
134 raise TypeError, 'desc attribute missing'
136 def __getattr__(self
, attr
):
138 ptype
= SimObject
.allClasses
[self
.ptype_str
]
139 assert isSimObjectClass(ptype
)
143 raise AttributeError, "'%s' object has no attribute '%s'" % \
144 (type(self
).__name
__, attr
)
146 def convert(self
, value
):
147 if isinstance(value
, proxy
.BaseProxy
):
148 value
.set_param_desc(self
)
150 if not hasattr(self
, 'ptype') and isNullPointer(value
):
151 # deferred evaluation of SimObject; continue to defer if
152 # we're just assigning a null pointer
154 if isinstance(value
, self
.ptype
):
156 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
158 return self
.ptype(value
)
160 def cxx_predecls(self
, code
):
161 self
.ptype
.cxx_predecls(code
)
163 def swig_predecls(self
, code
):
164 self
.ptype
.swig_predecls(code
)
166 def cxx_decl(self
, code
):
167 code('${{self.ptype.cxx_type}} ${{self.name}};')
169 # Vector-valued parameter description. Just like ParamDesc, except
170 # that the value is a vector (list) of the specified type instead of a
173 class VectorParamValue(list):
174 __metaclass__
= MetaParamValue
175 def __setattr__(self
, attr
, value
):
176 raise AttributeError, \
177 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
180 return ' '.join([v
.ini_str() for v
in self
])
183 return [ v
.getValue() for v
in self
]
185 def unproxy(self
, base
):
186 return [v
.unproxy(base
) for v
in self
]
188 class SimObjectVector(VectorParamValue
):
189 # support clone operation
190 def __call__(self
, **kwargs
):
191 return SimObjectVector([v(**kwargs
) for v
in self
])
193 def clear_parent(self
, old_parent
):
195 v
.clear_parent(old_parent
)
197 def set_parent(self
, parent
, name
):
199 self
[0].set_parent(parent
, name
)
201 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
202 for i
,v
in enumerate(self
):
203 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
205 def get_parent(self
):
206 parent_set
= set(v
._parent
for v
in self
)
207 if len(parent_set
) != 1:
208 raise RuntimeError, \
209 "SimObjectVector elements have inconsistent parent value."
210 return parent_set
.pop()
212 # return 'cpu0 cpu1' etc. for print_ini()
214 return ' '.join([v
._name
for v
in self
])
216 # By iterating through the constituent members of the vector here
217 # we can nicely handle iterating over all a SimObject's children
218 # without having to provide lots of special functions on
219 # SimObjectVector directly.
220 def descendants(self
):
222 for obj
in v
.descendants():
225 class VectorParamDesc(ParamDesc
):
228 # Convert assigned value to appropriate type. If the RHS is not a
229 # list or tuple, it generates a single-element list.
230 def convert(self
, value
):
231 if isinstance(value
, (list, tuple)):
232 # list: coerce each element into new list
233 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
235 # singleton: coerce to a single-element list
236 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
238 if isSimObjectSequence(tmp_list
):
239 return SimObjectVector(tmp_list
)
241 return VectorParamValue(tmp_list
)
243 def swig_predecls(self
, code
):
244 code('%include "${{self.ptype_str}}_vptype.i"')
246 def swig_decl(self
, code
):
247 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
248 code('%include "std_vector.i"')
249 self
.ptype
.swig_predecls(code
)
252 %template(vector_${{self.ptype_str}}) vector< $cxx_type >;
256 def cxx_predecls(self
, code
):
257 code('#include <vector>')
258 self
.ptype
.cxx_predecls(code
)
260 def cxx_decl(self
, code
):
261 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
263 class ParamFactory(object):
264 def __init__(self
, param_desc_class
, ptype_str
= None):
265 self
.param_desc_class
= param_desc_class
266 self
.ptype_str
= ptype_str
268 def __getattr__(self
, attr
):
270 attr
= self
.ptype_str
+ '.' + attr
271 return ParamFactory(self
.param_desc_class
, attr
)
273 # E.g., Param.Int(5, "number of widgets")
274 def __call__(self
, *args
, **kwargs
):
277 ptype
= allParams
[self
.ptype_str
]
279 # if name isn't defined yet, assume it's a SimObject, and
280 # try to resolve it later
282 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
284 Param
= ParamFactory(ParamDesc
)
285 VectorParam
= ParamFactory(VectorParamDesc
)
287 #####################################################################
291 # Though native Python types could be used to specify parameter types
292 # (the 'ptype' field of the Param and VectorParam classes), it's more
293 # flexible to define our own set of types. This gives us more control
294 # over how Python expressions are converted to values (via the
295 # __init__() constructor) and how these values are printed out (via
296 # the __str__() conversion method).
298 #####################################################################
300 # String-valued parameter. Just mixin the ParamValue class with the
301 # built-in str class.
302 class String(ParamValue
,str):
303 cxx_type
= 'std::string'
306 def cxx_predecls(self
, code
):
307 code('#include <string>')
310 def swig_predecls(cls
, code
):
311 code('%include "std_string.i"')
316 # superclass for "numeric" parameter values, to emulate math
317 # operations in a type-safe way. e.g., a Latency times an int returns
318 # a new Latency object.
319 class NumericParamValue(ParamValue
):
321 return str(self
.value
)
324 return float(self
.value
)
327 return long(self
.value
)
330 return int(self
.value
)
332 # hook for bounds checking
336 def __mul__(self
, other
):
337 newobj
= self
.__class
__(self
)
338 newobj
.value
*= other
344 def __div__(self
, other
):
345 newobj
= self
.__class
__(self
)
346 newobj
.value
/= other
350 def __sub__(self
, other
):
351 newobj
= self
.__class
__(self
)
352 newobj
.value
-= other
356 # Metaclass for bounds-checked integer parameters. See CheckedInt.
357 class CheckedIntType(MetaParamValue
):
358 def __init__(cls
, name
, bases
, dict):
359 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
361 # CheckedInt is an abstract base class, so we actually don't
362 # want to do any processing on it... the rest of this code is
363 # just for classes that derive from CheckedInt.
364 if name
== 'CheckedInt':
367 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
368 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
369 panic("CheckedInt subclass %s must define either\n" \
370 " 'min' and 'max' or 'size' and 'unsigned'\n",
374 cls
.max = 2 ** cls
.size
- 1
376 cls
.min = -(2 ** (cls
.size
- 1))
377 cls
.max = (2 ** (cls
.size
- 1)) - 1
379 # Abstract superclass for bounds-checked integer parameters. This
380 # class is subclassed to generate parameter classes with specific
381 # bounds. Initialization of the min and max bounds is done in the
382 # metaclass CheckedIntType.__init__.
383 class CheckedInt(NumericParamValue
):
384 __metaclass__
= CheckedIntType
387 if not self
.min <= self
.value
<= self
.max:
388 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
389 (self
.min, self
.value
, self
.max)
391 def __init__(self
, value
):
392 if isinstance(value
, str):
393 self
.value
= convert
.toInteger(value
)
394 elif isinstance(value
, (int, long, float, NumericParamValue
)):
395 self
.value
= long(value
)
397 raise TypeError, "Can't convert object of type %s to CheckedInt" \
398 % type(value
).__name
__
402 def cxx_predecls(cls
, code
):
403 # most derived types require this, so we just do it here once
404 code('#include "base/types.hh"')
407 def swig_predecls(cls
, code
):
408 # most derived types require this, so we just do it here once
409 code('%import "stdint.i"')
410 code('%import "base/types.hh"')
413 return long(self
.value
)
415 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
416 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
418 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
419 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
420 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
421 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
422 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
423 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
424 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
425 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
427 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
428 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
429 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
430 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
432 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
434 class Float(ParamValue
, float):
437 def __init__(self
, value
):
438 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
439 self
.value
= float(value
)
441 raise TypeError, "Can't convert object of type %s to Float" \
442 % type(value
).__name
__
445 return float(self
.value
)
447 class MemorySize(CheckedInt
):
448 cxx_type
= 'uint64_t'
451 def __init__(self
, value
):
452 if isinstance(value
, MemorySize
):
453 self
.value
= value
.value
455 self
.value
= convert
.toMemorySize(value
)
458 class MemorySize32(CheckedInt
):
459 cxx_type
= 'uint32_t'
462 def __init__(self
, value
):
463 if isinstance(value
, MemorySize
):
464 self
.value
= value
.value
466 self
.value
= convert
.toMemorySize(value
)
469 class Addr(CheckedInt
):
473 def __init__(self
, value
):
474 if isinstance(value
, Addr
):
475 self
.value
= value
.value
478 self
.value
= convert
.toMemorySize(value
)
480 self
.value
= long(value
)
482 def __add__(self
, other
):
483 if isinstance(other
, Addr
):
484 return self
.value
+ other
.value
486 return self
.value
+ other
489 class MetaRange(MetaParamValue
):
490 def __init__(cls
, name
, bases
, dict):
491 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
494 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
496 class Range(ParamValue
):
497 __metaclass__
= MetaRange
498 type = Int
# default; can be overridden in subclasses
499 def __init__(self
, *args
, **kwargs
):
500 def handle_kwargs(self
, kwargs
):
502 self
.second
= self
.type(kwargs
.pop('end'))
503 elif 'size' in kwargs
:
504 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
506 raise TypeError, "Either end or size must be specified"
509 self
.first
= self
.type(kwargs
.pop('start'))
510 handle_kwargs(self
, kwargs
)
514 self
.first
= self
.type(args
[0])
515 handle_kwargs(self
, kwargs
)
516 elif isinstance(args
[0], Range
):
517 self
.first
= self
.type(args
[0].first
)
518 self
.second
= self
.type(args
[0].second
)
519 elif isinstance(args
[0], (list, tuple)):
520 self
.first
= self
.type(args
[0][0])
521 self
.second
= self
.type(args
[0][1])
523 self
.first
= self
.type(0)
524 self
.second
= self
.type(args
[0]) - 1
527 self
.first
= self
.type(args
[0])
528 self
.second
= self
.type(args
[1])
530 raise TypeError, "Too many arguments specified"
533 raise TypeError, "too many keywords: %s" % kwargs
.keys()
536 return '%s:%s' % (self
.first
, self
.second
)
539 def cxx_predecls(cls
, code
):
540 code('#include "base/range.hh"')
541 cls
.type.cxx_predecls(code
)
543 class AddrRange(Range
):
547 def swig_predecls(cls
, code
):
548 code('%include "python/swig/range.i"')
551 from m5
.objects
.params
import AddrRange
554 value
.start
= long(self
.first
)
555 value
.end
= long(self
.second
)
558 class TickRange(Range
):
562 def swig_predecls(cls
, code
):
563 code('%include "python/swig/range.i"')
566 from m5
.objects
.params
import TickRange
569 value
.start
= long(self
.first
)
570 value
.end
= long(self
.second
)
573 # Boolean parameter type. Python doesn't let you subclass bool, since
574 # it doesn't want to let you create multiple instances of True and
575 # False. Thus this is a little more complicated than String.
576 class Bool(ParamValue
):
578 def __init__(self
, value
):
580 self
.value
= convert
.toBool(value
)
582 self
.value
= bool(value
)
585 return bool(self
.value
)
588 return str(self
.value
)
595 def IncEthernetAddr(addr
, val
= 1):
596 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
598 for i
in (5, 4, 3, 2, 1):
599 val
,rem
= divmod(bytes
[i
], 256)
604 assert(bytes
[0] <= 255)
605 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
607 _NextEthernetAddr
= "00:90:00:00:00:01"
608 def NextEthernetAddr():
609 global _NextEthernetAddr
611 value
= _NextEthernetAddr
612 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
615 class EthernetAddr(ParamValue
):
616 cxx_type
= 'Net::EthAddr'
619 def cxx_predecls(cls
, code
):
620 code('#include "base/inet.hh"')
623 def swig_predecls(cls
, code
):
624 code('%include "python/swig/inet.i"')
626 def __init__(self
, value
):
627 if value
== NextEthernetAddr
:
631 if not isinstance(value
, str):
632 raise TypeError, "expected an ethernet address and didn't get one"
634 bytes
= value
.split(':')
636 raise TypeError, 'invalid ethernet address %s' % value
639 if not 0 <= int(byte
) <= 256:
640 raise TypeError, 'invalid ethernet address %s' % value
644 def unproxy(self
, base
):
645 if self
.value
== NextEthernetAddr
:
646 return EthernetAddr(self
.value())
650 from m5
.objects
.params
import EthAddr
651 return EthAddr(self
.value
)
656 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
657 "%a %b %d %H:%M:%S %Z %Y",
669 def parse_time(value
):
670 from time
import gmtime
, strptime
, struct_time
, time
671 from datetime
import datetime
, date
673 if isinstance(value
, struct_time
):
676 if isinstance(value
, (int, long)):
679 if isinstance(value
, (datetime
, date
)):
680 return value
.timetuple()
682 if isinstance(value
, str):
683 if value
in ('Now', 'Today'):
684 return time
.gmtime(time
.time())
686 for format
in time_formats
:
688 return strptime(value
, format
)
692 raise ValueError, "Could not parse '%s' as a time" % value
694 class Time(ParamValue
):
698 def cxx_predecls(cls
, code
):
699 code('#include <time.h>')
702 def swig_predecls(cls
, code
):
703 code('%include "python/swig/time.i"')
705 def __init__(self
, value
):
706 self
.value
= parse_time(value
)
709 from m5
.objects
.params
import tm
714 # UNIX is years since 1900
715 c_time
.tm_year
= py_time
.tm_year
- 1900;
717 # Python starts at 1, UNIX starts at 0
718 c_time
.tm_mon
= py_time
.tm_mon
- 1;
719 c_time
.tm_mday
= py_time
.tm_mday
;
720 c_time
.tm_hour
= py_time
.tm_hour
;
721 c_time
.tm_min
= py_time
.tm_min
;
722 c_time
.tm_sec
= py_time
.tm_sec
;
724 # Python has 0 as Monday, UNIX is 0 as sunday
725 c_time
.tm_wday
= py_time
.tm_wday
+ 1
726 if c_time
.tm_wday
> 6:
729 # Python starts at 1, Unix starts at 0
730 c_time
.tm_yday
= py_time
.tm_yday
- 1;
735 return time
.asctime(self
.value
)
740 # Enumerated types are a little more complex. The user specifies the
741 # type as Enum(foo) where foo is either a list or dictionary of
742 # alternatives (typically strings, but not necessarily so). (In the
743 # long run, the integer value of the parameter will be the list index
744 # or the corresponding dictionary value. For now, since we only check
745 # that the alternative is valid and then spit it into a .ini file,
746 # there's not much point in using the dictionary.)
748 # What Enum() must do is generate a new type encapsulating the
749 # provided list/dictionary so that specific values of the parameter
750 # can be instances of that type. We define two hidden internal
751 # classes (_ListEnum and _DictEnum) to serve as base classes, then
752 # derive the new type from the appropriate base class on the fly.
755 # Metaclass for Enum types
756 class MetaEnum(MetaParamValue
):
757 def __new__(mcls
, name
, bases
, dict):
758 assert name
not in allEnums
760 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
764 def __init__(cls
, name
, bases
, init_dict
):
765 if init_dict
.has_key('map'):
766 if not isinstance(cls
.map, dict):
767 raise TypeError, "Enum-derived class attribute 'map' " \
768 "must be of type dict"
769 # build list of value strings from map
770 cls
.vals
= cls
.map.keys()
772 elif init_dict
.has_key('vals'):
773 if not isinstance(cls
.vals
, list):
774 raise TypeError, "Enum-derived class attribute 'vals' " \
775 "must be of type list"
776 # build string->value map from vals sequence
778 for idx
,val
in enumerate(cls
.vals
):
781 raise TypeError, "Enum-derived class must define "\
782 "attribute 'map' or 'vals'"
784 cls
.cxx_type
= 'Enums::%s' % name
786 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
788 # Generate C++ class declaration for this enum type.
789 # Note that we wrap the enum in a class/struct to act as a namespace,
790 # so that the enum strings can be brief w/o worrying about collisions.
791 def cxx_decl(cls
, code
):
794 #ifndef __ENUM__${name}__
795 #define __ENUM__${name}__
802 code('$val = ${{cls.map[val]}},')
803 code('Num_$name = ${{len(cls.vals)}},')
807 extern const char *${name}Strings[Num_${name}];
810 #endif // __ENUM__${name}__
813 def cxx_def(cls
, code
):
816 #include "enums/${name}.hh"
818 const char *${name}Strings[Num_${name}] =
827 /* namespace Enums */ }
830 # Base class for enum types.
831 class Enum(ParamValue
):
832 __metaclass__
= MetaEnum
835 def __init__(self
, value
):
836 if value
not in self
.map:
837 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
842 return int(self
.map[self
.value
])
847 # how big does a rounding error need to be before we warn about it?
848 frequency_tolerance
= 0.001 # 0.1%
850 class TickParamValue(NumericParamValue
):
854 def cxx_predecls(cls
, code
):
855 code('#include "base/types.hh"')
858 def swig_predecls(cls
, code
):
859 code('%import "stdint.i"')
860 code('%import "base/types.hh"')
863 return long(self
.value
)
865 class Latency(TickParamValue
):
866 def __init__(self
, value
):
867 if isinstance(value
, (Latency
, Clock
)):
868 self
.ticks
= value
.ticks
869 self
.value
= value
.value
870 elif isinstance(value
, Frequency
):
871 self
.ticks
= value
.ticks
872 self
.value
= 1.0 / value
.value
873 elif value
.endswith('t'):
875 self
.value
= int(value
[:-1])
878 self
.value
= convert
.toLatency(value
)
880 def __getattr__(self
, attr
):
881 if attr
in ('latency', 'period'):
883 if attr
== 'frequency':
884 return Frequency(self
)
885 raise AttributeError, "Latency object has no attribute '%s'" % attr
888 if self
.ticks
or self
.value
== 0:
891 value
= ticks
.fromSeconds(self
.value
)
894 # convert latency to ticks
896 return '%d' % self
.getValue()
898 class Frequency(TickParamValue
):
899 def __init__(self
, value
):
900 if isinstance(value
, (Latency
, Clock
)):
904 self
.value
= 1.0 / value
.value
905 self
.ticks
= value
.ticks
906 elif isinstance(value
, Frequency
):
907 self
.value
= value
.value
908 self
.ticks
= value
.ticks
911 self
.value
= convert
.toFrequency(value
)
913 def __getattr__(self
, attr
):
914 if attr
== 'frequency':
916 if attr
in ('latency', 'period'):
918 raise AttributeError, "Frequency object has no attribute '%s'" % attr
920 # convert latency to ticks
922 if self
.ticks
or self
.value
== 0:
925 value
= ticks
.fromSeconds(1.0 / self
.value
)
929 return '%d' % self
.getValue()
931 # A generic frequency and/or Latency value. Value is stored as a latency,
932 # but to avoid ambiguity this object does not support numeric ops (* or /).
933 # An explicit conversion to a Latency or Frequency must be made first.
934 class Clock(ParamValue
):
938 def cxx_predecls(cls
, code
):
939 code('#include "base/types.hh"')
942 def swig_predecls(cls
, code
):
943 code('%import "stdint.i"')
944 code('%import "base/types.hh"')
946 def __init__(self
, value
):
947 if isinstance(value
, (Latency
, Clock
)):
948 self
.ticks
= value
.ticks
949 self
.value
= value
.value
950 elif isinstance(value
, Frequency
):
951 self
.ticks
= value
.ticks
952 self
.value
= 1.0 / value
.value
953 elif value
.endswith('t'):
955 self
.value
= int(value
[:-1])
958 self
.value
= convert
.anyToLatency(value
)
960 def __getattr__(self
, attr
):
961 if attr
== 'frequency':
962 return Frequency(self
)
963 if attr
in ('latency', 'period'):
965 raise AttributeError, "Frequency object has no attribute '%s'" % attr
968 return self
.period
.getValue()
971 return self
.period
.ini_str()
973 class NetworkBandwidth(float,ParamValue
):
975 def __new__(cls
, value
):
976 # convert to bits per second
977 val
= convert
.toNetworkBandwidth(value
)
978 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
984 # convert to seconds per byte
985 value
= 8.0 / float(self
)
986 # convert to ticks per byte
987 value
= ticks
.fromSeconds(value
)
991 return '%f' % self
.getValue()
993 class MemoryBandwidth(float,ParamValue
):
995 def __new__(cls
, value
):
996 # we want the number of ticks per byte of data
997 val
= convert
.toMemoryBandwidth(value
)
998 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1001 return str(self
.val
)
1004 # convert to seconds per byte
1007 value
= 1.0 / float(self
)
1008 # convert to ticks per byte
1009 value
= ticks
.fromSeconds(value
)
1013 return '%f' % self
.getValue()
1016 # "Constants"... handy aliases for various values.
1019 # Special class for NULL pointers. Note the special check in
1020 # make_param_value() above that lets these be assigned where a
1021 # SimObject is required.
1022 # only one copy of a particular node
1023 class NullSimObject(object):
1024 __metaclass__
= Singleton
1029 def _instantiate(self
, parent
= None, path
= ''):
1035 def unproxy(self
, base
):
1038 def set_path(self
, parent
, name
):
1047 # The only instance you'll ever need...
1048 NULL
= NullSimObject()
1050 def isNullPointer(value
):
1051 return isinstance(value
, NullSimObject
)
1053 # Some memory range specifications use this as a default upper bound.
1056 AllMemory
= AddrRange(0, MaxAddr
)
1059 #####################################################################
1063 # Ports are used to interconnect objects in the memory system.
1065 #####################################################################
1067 # Port reference: encapsulates a reference to a particular port on a
1068 # particular SimObject.
1069 class PortRef(object):
1070 def __init__(self
, simobj
, name
):
1071 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1072 self
.simobj
= simobj
1074 self
.peer
= None # not associated with another port yet
1075 self
.ccConnected
= False # C++ port connection done?
1076 self
.index
= -1 # always -1 for non-vector ports
1079 return '%s.%s' % (self
.simobj
, self
.name
)
1081 # for config.ini, print peer's name (not ours)
1083 return str(self
.peer
)
1085 def __getattr__(self
, attr
):
1086 if attr
== 'peerObj':
1087 # shorthand for proxies
1088 return self
.peer
.simobj
1089 raise AttributeError, "'%s' object has no attribute '%s'" % \
1090 (self
.__class
__.__name
__, attr
)
1092 # Full connection is symmetric (both ways). Called via
1093 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1094 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1095 # e.g., "obj1.portA[3] = obj2.portB".
1096 def connect(self
, other
):
1097 if isinstance(other
, VectorPortRef
):
1098 # reference to plain VectorPort is implicit append
1099 other
= other
._get
_next
()
1100 if self
.peer
and not proxy
.isproxy(self
.peer
):
1101 print "warning: overwriting port", self
, \
1102 "value", self
.peer
, "with", other
1103 self
.peer
.peer
= None
1105 if proxy
.isproxy(other
):
1106 other
.set_param_desc(PortParamDesc())
1107 elif isinstance(other
, PortRef
):
1108 if other
.peer
is not self
:
1112 "assigning non-port reference '%s' to port '%s'" \
1115 def clone(self
, simobj
, memo
):
1116 if memo
.has_key(self
):
1118 newRef
= copy
.copy(self
)
1120 newRef
.simobj
= simobj
1121 assert(isSimObject(newRef
.simobj
))
1122 if self
.peer
and not proxy
.isproxy(self
.peer
):
1123 peerObj
= self
.peer
.simobj(_memo
=memo
)
1124 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1125 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1128 def unproxy(self
, simobj
):
1129 assert(simobj
is self
.simobj
)
1130 if proxy
.isproxy(self
.peer
):
1132 realPeer
= self
.peer
.unproxy(self
.simobj
)
1134 print "Error in unproxying port '%s' of %s" % \
1135 (self
.name
, self
.simobj
.path())
1137 self
.connect(realPeer
)
1139 # Call C++ to create corresponding port connection between C++ objects
1140 def ccConnect(self
):
1141 from m5
.objects
.params
import connectPorts
1143 if self
.ccConnected
: # already done this
1146 if not self
.peer
: # nothing to connect to
1149 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1150 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1152 print "Error connecting port %s.%s to %s.%s" % \
1153 (self
.simobj
.path(), self
.name
,
1154 peer
.simobj
.path(), peer
.name
)
1156 self
.ccConnected
= True
1157 peer
.ccConnected
= True
1159 # A reference to an individual element of a VectorPort... much like a
1160 # PortRef, but has an index.
1161 class VectorPortElementRef(PortRef
):
1162 def __init__(self
, simobj
, name
, index
):
1163 PortRef
.__init
__(self
, simobj
, name
)
1167 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1169 # A reference to a complete vector-valued port (not just a single element).
1170 # Can be indexed to retrieve individual VectorPortElementRef instances.
1171 class VectorPortRef(object):
1172 def __init__(self
, simobj
, name
):
1173 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1174 self
.simobj
= simobj
1179 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1181 # for config.ini, print peer's name (not ours)
1183 return ' '.join([el
.ini_str() for el
in self
.elements
])
1185 def __getitem__(self
, key
):
1186 if not isinstance(key
, int):
1187 raise TypeError, "VectorPort index must be integer"
1188 if key
>= len(self
.elements
):
1189 # need to extend list
1190 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1191 for i
in range(len(self
.elements
), key
+1)]
1192 self
.elements
.extend(ext
)
1193 return self
.elements
[key
]
1195 def _get_next(self
):
1196 return self
[len(self
.elements
)]
1198 def __setitem__(self
, key
, value
):
1199 if not isinstance(key
, int):
1200 raise TypeError, "VectorPort index must be integer"
1201 self
[key
].connect(value
)
1203 def connect(self
, other
):
1204 if isinstance(other
, (list, tuple)):
1205 # Assign list of port refs to vector port.
1206 # For now, append them... not sure if that's the right semantics
1207 # or if it should replace the current vector.
1209 self
._get
_next
().connect(ref
)
1211 # scalar assignment to plain VectorPort is implicit append
1212 self
._get
_next
().connect(other
)
1214 def clone(self
, simobj
, memo
):
1215 if memo
.has_key(self
):
1217 newRef
= copy
.copy(self
)
1219 newRef
.simobj
= simobj
1220 assert(isSimObject(newRef
.simobj
))
1221 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1224 def unproxy(self
, simobj
):
1225 [el
.unproxy(simobj
) for el
in self
.elements
]
1227 def ccConnect(self
):
1228 [el
.ccConnect() for el
in self
.elements
]
1230 # Port description object. Like a ParamDesc object, this represents a
1231 # logical port in the SimObject class, not a particular port on a
1232 # SimObject instance. The latter are represented by PortRef objects.
1234 # Port("description") or Port(default, "description")
1235 def __init__(self
, *args
):
1238 elif len(args
) == 2:
1239 self
.default
= args
[0]
1242 raise TypeError, 'wrong number of arguments'
1243 # self.name is set by SimObject class on assignment
1244 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1246 # Generate a PortRef for this port on the given SimObject with the
1248 def makeRef(self
, simobj
):
1249 return PortRef(simobj
, self
.name
)
1251 # Connect an instance of this port (on the given SimObject with
1252 # the given name) with the port described by the supplied PortRef
1253 def connect(self
, simobj
, ref
):
1254 self
.makeRef(simobj
).connect(ref
)
1256 # VectorPort description object. Like Port, but represents a vector
1257 # of connections (e.g., as on a Bus).
1258 class VectorPort(Port
):
1259 def __init__(self
, *args
):
1260 Port
.__init
__(self
, *args
)
1263 def makeRef(self
, simobj
):
1264 return VectorPortRef(simobj
, self
.name
)
1266 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1267 # proxy objects (via set_param_desc()) so that proxy error messages
1269 class PortParamDesc(object):
1270 __metaclass__
= Singleton
1275 baseEnums
= allEnums
.copy()
1276 baseParams
= allParams
.copy()
1279 global allEnums
, allParams
1281 allEnums
= baseEnums
.copy()
1282 allParams
= baseParams
.copy()
1284 __all__
= ['Param', 'VectorParam',
1285 'Enum', 'Bool', 'String', 'Float',
1286 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1287 'Int32', 'UInt32', 'Int64', 'UInt64',
1288 'Counter', 'Addr', 'Tick', 'Percent',
1289 'TcpPort', 'UdpPort', 'EthernetAddr',
1290 'MemorySize', 'MemorySize32',
1291 'Latency', 'Frequency', 'Clock',
1292 'NetworkBandwidth', 'MemoryBandwidth',
1293 'Range', 'AddrRange', 'TickRange',
1294 'MaxAddr', 'MaxTick', 'AllMemory',
1296 'NextEthernetAddr', 'NULL',
1297 'Port', 'VectorPort']