33ac742c8d6729c8a6fc1e9099eae9b67bb70bba
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('%import "vptype_${{self.ptype_str}}.i"')
246 def swig_decl(self
, code
):
248 self
.ptype
.cxx_predecls(code
)
251 self
.ptype
.swig_predecls(code
)
253 code('%include "std_vector.i"')
256 ptype
= self
.ptype_str
257 cxx_type
= self
.ptype
.cxx_type
260 %typemap(in) std::vector< $cxx_type >::value_type {
261 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
262 if (SWIG_ConvertPtr($$input, (void **)&$$1,
263 $$descriptor($cxx_type), 0) == -1) {
269 %typemap(in) std::vector< $cxx_type >::value_type * {
270 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
271 if (SWIG_ConvertPtr($$input, (void **)&$$1,
272 $$descriptor($cxx_type *), 0) == -1) {
279 code('%template(vector_$ptype) std::vector< $cxx_type >;')
281 def cxx_predecls(self
, code
):
282 code('#include <vector>')
283 self
.ptype
.cxx_predecls(code
)
285 def cxx_decl(self
, code
):
286 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
288 class ParamFactory(object):
289 def __init__(self
, param_desc_class
, ptype_str
= None):
290 self
.param_desc_class
= param_desc_class
291 self
.ptype_str
= ptype_str
293 def __getattr__(self
, attr
):
295 attr
= self
.ptype_str
+ '.' + attr
296 return ParamFactory(self
.param_desc_class
, attr
)
298 # E.g., Param.Int(5, "number of widgets")
299 def __call__(self
, *args
, **kwargs
):
302 ptype
= allParams
[self
.ptype_str
]
304 # if name isn't defined yet, assume it's a SimObject, and
305 # try to resolve it later
307 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
309 Param
= ParamFactory(ParamDesc
)
310 VectorParam
= ParamFactory(VectorParamDesc
)
312 #####################################################################
316 # Though native Python types could be used to specify parameter types
317 # (the 'ptype' field of the Param and VectorParam classes), it's more
318 # flexible to define our own set of types. This gives us more control
319 # over how Python expressions are converted to values (via the
320 # __init__() constructor) and how these values are printed out (via
321 # the __str__() conversion method).
323 #####################################################################
325 # String-valued parameter. Just mixin the ParamValue class with the
326 # built-in str class.
327 class String(ParamValue
,str):
328 cxx_type
= 'std::string'
331 def cxx_predecls(self
, code
):
332 code('#include <string>')
335 def swig_predecls(cls
, code
):
336 code('%include "std_string.i"')
341 # superclass for "numeric" parameter values, to emulate math
342 # operations in a type-safe way. e.g., a Latency times an int returns
343 # a new Latency object.
344 class NumericParamValue(ParamValue
):
346 return str(self
.value
)
349 return float(self
.value
)
352 return long(self
.value
)
355 return int(self
.value
)
357 # hook for bounds checking
361 def __mul__(self
, other
):
362 newobj
= self
.__class
__(self
)
363 newobj
.value
*= other
369 def __div__(self
, other
):
370 newobj
= self
.__class
__(self
)
371 newobj
.value
/= other
375 def __sub__(self
, other
):
376 newobj
= self
.__class
__(self
)
377 newobj
.value
-= other
381 # Metaclass for bounds-checked integer parameters. See CheckedInt.
382 class CheckedIntType(MetaParamValue
):
383 def __init__(cls
, name
, bases
, dict):
384 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
386 # CheckedInt is an abstract base class, so we actually don't
387 # want to do any processing on it... the rest of this code is
388 # just for classes that derive from CheckedInt.
389 if name
== 'CheckedInt':
392 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
393 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
394 panic("CheckedInt subclass %s must define either\n" \
395 " 'min' and 'max' or 'size' and 'unsigned'\n",
399 cls
.max = 2 ** cls
.size
- 1
401 cls
.min = -(2 ** (cls
.size
- 1))
402 cls
.max = (2 ** (cls
.size
- 1)) - 1
404 # Abstract superclass for bounds-checked integer parameters. This
405 # class is subclassed to generate parameter classes with specific
406 # bounds. Initialization of the min and max bounds is done in the
407 # metaclass CheckedIntType.__init__.
408 class CheckedInt(NumericParamValue
):
409 __metaclass__
= CheckedIntType
412 if not self
.min <= self
.value
<= self
.max:
413 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
414 (self
.min, self
.value
, self
.max)
416 def __init__(self
, value
):
417 if isinstance(value
, str):
418 self
.value
= convert
.toInteger(value
)
419 elif isinstance(value
, (int, long, float, NumericParamValue
)):
420 self
.value
= long(value
)
422 raise TypeError, "Can't convert object of type %s to CheckedInt" \
423 % type(value
).__name
__
427 def cxx_predecls(cls
, code
):
428 # most derived types require this, so we just do it here once
429 code('#include "base/types.hh"')
432 def swig_predecls(cls
, code
):
433 # most derived types require this, so we just do it here once
434 code('%import "stdint.i"')
435 code('%import "base/types.hh"')
438 return long(self
.value
)
440 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
441 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
443 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
444 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
445 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
446 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
447 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
448 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
449 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
450 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
452 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
453 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
454 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
455 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
457 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
459 class Float(ParamValue
, float):
462 def __init__(self
, value
):
463 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
464 self
.value
= float(value
)
466 raise TypeError, "Can't convert object of type %s to Float" \
467 % type(value
).__name
__
470 return float(self
.value
)
472 class MemorySize(CheckedInt
):
473 cxx_type
= 'uint64_t'
476 def __init__(self
, value
):
477 if isinstance(value
, MemorySize
):
478 self
.value
= value
.value
480 self
.value
= convert
.toMemorySize(value
)
483 class MemorySize32(CheckedInt
):
484 cxx_type
= 'uint32_t'
487 def __init__(self
, value
):
488 if isinstance(value
, MemorySize
):
489 self
.value
= value
.value
491 self
.value
= convert
.toMemorySize(value
)
494 class Addr(CheckedInt
):
498 def __init__(self
, value
):
499 if isinstance(value
, Addr
):
500 self
.value
= value
.value
503 self
.value
= convert
.toMemorySize(value
)
505 self
.value
= long(value
)
507 def __add__(self
, other
):
508 if isinstance(other
, Addr
):
509 return self
.value
+ other
.value
511 return self
.value
+ other
514 class MetaRange(MetaParamValue
):
515 def __init__(cls
, name
, bases
, dict):
516 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
519 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
521 class Range(ParamValue
):
522 __metaclass__
= MetaRange
523 type = Int
# default; can be overridden in subclasses
524 def __init__(self
, *args
, **kwargs
):
525 def handle_kwargs(self
, kwargs
):
527 self
.second
= self
.type(kwargs
.pop('end'))
528 elif 'size' in kwargs
:
529 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
531 raise TypeError, "Either end or size must be specified"
534 self
.first
= self
.type(kwargs
.pop('start'))
535 handle_kwargs(self
, kwargs
)
539 self
.first
= self
.type(args
[0])
540 handle_kwargs(self
, kwargs
)
541 elif isinstance(args
[0], Range
):
542 self
.first
= self
.type(args
[0].first
)
543 self
.second
= self
.type(args
[0].second
)
544 elif isinstance(args
[0], (list, tuple)):
545 self
.first
= self
.type(args
[0][0])
546 self
.second
= self
.type(args
[0][1])
548 self
.first
= self
.type(0)
549 self
.second
= self
.type(args
[0]) - 1
552 self
.first
= self
.type(args
[0])
553 self
.second
= self
.type(args
[1])
555 raise TypeError, "Too many arguments specified"
558 raise TypeError, "too many keywords: %s" % kwargs
.keys()
561 return '%s:%s' % (self
.first
, self
.second
)
564 def cxx_predecls(cls
, code
):
565 cls
.type.cxx_predecls(code
)
566 code('#include "base/range.hh"')
569 def swig_predecls(cls
, code
):
570 cls
.type.swig_predecls(code
)
571 code('%import "python/swig/range.i"')
573 class AddrRange(Range
):
577 from m5
.internal
.range import AddrRange
580 value
.start
= long(self
.first
)
581 value
.end
= long(self
.second
)
584 class TickRange(Range
):
588 from m5
.internal
.range import TickRange
591 value
.start
= long(self
.first
)
592 value
.end
= long(self
.second
)
595 # Boolean parameter type. Python doesn't let you subclass bool, since
596 # it doesn't want to let you create multiple instances of True and
597 # False. Thus this is a little more complicated than String.
598 class Bool(ParamValue
):
600 def __init__(self
, value
):
602 self
.value
= convert
.toBool(value
)
604 self
.value
= bool(value
)
607 return bool(self
.value
)
610 return str(self
.value
)
617 def IncEthernetAddr(addr
, val
= 1):
618 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
620 for i
in (5, 4, 3, 2, 1):
621 val
,rem
= divmod(bytes
[i
], 256)
626 assert(bytes
[0] <= 255)
627 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
629 _NextEthernetAddr
= "00:90:00:00:00:01"
630 def NextEthernetAddr():
631 global _NextEthernetAddr
633 value
= _NextEthernetAddr
634 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
637 class EthernetAddr(ParamValue
):
638 cxx_type
= 'Net::EthAddr'
641 def cxx_predecls(cls
, code
):
642 code('#include "base/inet.hh"')
645 def swig_predecls(cls
, code
):
646 code('%include "python/swig/inet.i"')
648 def __init__(self
, value
):
649 if value
== NextEthernetAddr
:
653 if not isinstance(value
, str):
654 raise TypeError, "expected an ethernet address and didn't get one"
656 bytes
= value
.split(':')
658 raise TypeError, 'invalid ethernet address %s' % value
661 if not 0 <= int(byte
) <= 0xff:
662 raise TypeError, 'invalid ethernet address %s' % value
666 def unproxy(self
, base
):
667 if self
.value
== NextEthernetAddr
:
668 return EthernetAddr(self
.value())
672 from m5
.internal
.params
import EthAddr
673 return EthAddr(self
.value
)
678 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
679 "%a %b %d %H:%M:%S %Z %Y",
691 def parse_time(value
):
692 from time
import gmtime
, strptime
, struct_time
, time
693 from datetime
import datetime
, date
695 if isinstance(value
, struct_time
):
698 if isinstance(value
, (int, long)):
701 if isinstance(value
, (datetime
, date
)):
702 return value
.timetuple()
704 if isinstance(value
, str):
705 if value
in ('Now', 'Today'):
706 return time
.gmtime(time
.time())
708 for format
in time_formats
:
710 return strptime(value
, format
)
714 raise ValueError, "Could not parse '%s' as a time" % value
716 class Time(ParamValue
):
720 def cxx_predecls(cls
, code
):
721 code('#include <time.h>')
724 def swig_predecls(cls
, code
):
725 code('%include "python/swig/time.i"')
727 def __init__(self
, value
):
728 self
.value
= parse_time(value
)
731 from m5
.internal
.params
import tm
736 # UNIX is years since 1900
737 c_time
.tm_year
= py_time
.tm_year
- 1900;
739 # Python starts at 1, UNIX starts at 0
740 c_time
.tm_mon
= py_time
.tm_mon
- 1;
741 c_time
.tm_mday
= py_time
.tm_mday
;
742 c_time
.tm_hour
= py_time
.tm_hour
;
743 c_time
.tm_min
= py_time
.tm_min
;
744 c_time
.tm_sec
= py_time
.tm_sec
;
746 # Python has 0 as Monday, UNIX is 0 as sunday
747 c_time
.tm_wday
= py_time
.tm_wday
+ 1
748 if c_time
.tm_wday
> 6:
751 # Python starts at 1, Unix starts at 0
752 c_time
.tm_yday
= py_time
.tm_yday
- 1;
757 return time
.asctime(self
.value
)
762 # Enumerated types are a little more complex. The user specifies the
763 # type as Enum(foo) where foo is either a list or dictionary of
764 # alternatives (typically strings, but not necessarily so). (In the
765 # long run, the integer value of the parameter will be the list index
766 # or the corresponding dictionary value. For now, since we only check
767 # that the alternative is valid and then spit it into a .ini file,
768 # there's not much point in using the dictionary.)
770 # What Enum() must do is generate a new type encapsulating the
771 # provided list/dictionary so that specific values of the parameter
772 # can be instances of that type. We define two hidden internal
773 # classes (_ListEnum and _DictEnum) to serve as base classes, then
774 # derive the new type from the appropriate base class on the fly.
777 # Metaclass for Enum types
778 class MetaEnum(MetaParamValue
):
779 def __new__(mcls
, name
, bases
, dict):
780 assert name
not in allEnums
782 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
786 def __init__(cls
, name
, bases
, init_dict
):
787 if init_dict
.has_key('map'):
788 if not isinstance(cls
.map, dict):
789 raise TypeError, "Enum-derived class attribute 'map' " \
790 "must be of type dict"
791 # build list of value strings from map
792 cls
.vals
= cls
.map.keys()
794 elif init_dict
.has_key('vals'):
795 if not isinstance(cls
.vals
, list):
796 raise TypeError, "Enum-derived class attribute 'vals' " \
797 "must be of type list"
798 # build string->value map from vals sequence
800 for idx
,val
in enumerate(cls
.vals
):
803 raise TypeError, "Enum-derived class must define "\
804 "attribute 'map' or 'vals'"
806 cls
.cxx_type
= 'Enums::%s' % name
808 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
810 # Generate C++ class declaration for this enum type.
811 # Note that we wrap the enum in a class/struct to act as a namespace,
812 # so that the enum strings can be brief w/o worrying about collisions.
813 def cxx_decl(cls
, code
):
816 #ifndef __ENUM__${name}__
817 #define __ENUM__${name}__
824 code('$val = ${{cls.map[val]}},')
825 code('Num_$name = ${{len(cls.vals)}},')
829 extern const char *${name}Strings[Num_${name}];
832 #endif // __ENUM__${name}__
835 def cxx_def(cls
, code
):
838 #include "enums/$name.hh"
840 const char *${name}Strings[Num_${name}] =
849 /* namespace Enums */ }
852 # Base class for enum types.
853 class Enum(ParamValue
):
854 __metaclass__
= MetaEnum
857 def __init__(self
, value
):
858 if value
not in self
.map:
859 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
864 def cxx_predecls(cls
, code
):
865 code('#include "enums/$0.hh"', cls
.__name
__)
868 def swig_predecls(cls
, code
):
869 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
872 return int(self
.map[self
.value
])
877 # how big does a rounding error need to be before we warn about it?
878 frequency_tolerance
= 0.001 # 0.1%
880 class TickParamValue(NumericParamValue
):
884 def cxx_predecls(cls
, code
):
885 code('#include "base/types.hh"')
888 def swig_predecls(cls
, code
):
889 code('%import "stdint.i"')
890 code('%import "base/types.hh"')
893 return long(self
.value
)
895 class Latency(TickParamValue
):
896 def __init__(self
, value
):
897 if isinstance(value
, (Latency
, Clock
)):
898 self
.ticks
= value
.ticks
899 self
.value
= value
.value
900 elif isinstance(value
, Frequency
):
901 self
.ticks
= value
.ticks
902 self
.value
= 1.0 / value
.value
903 elif value
.endswith('t'):
905 self
.value
= int(value
[:-1])
908 self
.value
= convert
.toLatency(value
)
910 def __getattr__(self
, attr
):
911 if attr
in ('latency', 'period'):
913 if attr
== 'frequency':
914 return Frequency(self
)
915 raise AttributeError, "Latency object has no attribute '%s'" % attr
918 if self
.ticks
or self
.value
== 0:
921 value
= ticks
.fromSeconds(self
.value
)
924 # convert latency to ticks
926 return '%d' % self
.getValue()
928 class Frequency(TickParamValue
):
929 def __init__(self
, value
):
930 if isinstance(value
, (Latency
, Clock
)):
934 self
.value
= 1.0 / value
.value
935 self
.ticks
= value
.ticks
936 elif isinstance(value
, Frequency
):
937 self
.value
= value
.value
938 self
.ticks
= value
.ticks
941 self
.value
= convert
.toFrequency(value
)
943 def __getattr__(self
, attr
):
944 if attr
== 'frequency':
946 if attr
in ('latency', 'period'):
948 raise AttributeError, "Frequency object has no attribute '%s'" % attr
950 # convert latency to ticks
952 if self
.ticks
or self
.value
== 0:
955 value
= ticks
.fromSeconds(1.0 / self
.value
)
959 return '%d' % self
.getValue()
961 # A generic frequency and/or Latency value. Value is stored as a latency,
962 # but to avoid ambiguity this object does not support numeric ops (* or /).
963 # An explicit conversion to a Latency or Frequency must be made first.
964 class Clock(ParamValue
):
968 def cxx_predecls(cls
, code
):
969 code('#include "base/types.hh"')
972 def swig_predecls(cls
, code
):
973 code('%import "stdint.i"')
974 code('%import "base/types.hh"')
976 def __init__(self
, value
):
977 if isinstance(value
, (Latency
, Clock
)):
978 self
.ticks
= value
.ticks
979 self
.value
= value
.value
980 elif isinstance(value
, Frequency
):
981 self
.ticks
= value
.ticks
982 self
.value
= 1.0 / value
.value
983 elif value
.endswith('t'):
985 self
.value
= int(value
[:-1])
988 self
.value
= convert
.anyToLatency(value
)
990 def __getattr__(self
, attr
):
991 if attr
== 'frequency':
992 return Frequency(self
)
993 if attr
in ('latency', 'period'):
995 raise AttributeError, "Frequency object has no attribute '%s'" % attr
998 return self
.period
.getValue()
1001 return self
.period
.ini_str()
1003 class NetworkBandwidth(float,ParamValue
):
1005 def __new__(cls
, value
):
1006 # convert to bits per second
1007 val
= convert
.toNetworkBandwidth(value
)
1008 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1011 return str(self
.val
)
1014 # convert to seconds per byte
1015 value
= 8.0 / float(self
)
1016 # convert to ticks per byte
1017 value
= ticks
.fromSeconds(value
)
1021 return '%f' % self
.getValue()
1023 class MemoryBandwidth(float,ParamValue
):
1025 def __new__(cls
, value
):
1026 # convert to bytes per second
1027 val
= convert
.toMemoryBandwidth(value
)
1028 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1031 return str(self
.val
)
1034 # convert to seconds per byte
1037 value
= 1.0 / float(self
)
1038 # convert to ticks per byte
1039 value
= ticks
.fromSeconds(value
)
1043 return '%f' % self
.getValue()
1046 # "Constants"... handy aliases for various values.
1049 # Special class for NULL pointers. Note the special check in
1050 # make_param_value() above that lets these be assigned where a
1051 # SimObject is required.
1052 # only one copy of a particular node
1053 class NullSimObject(object):
1054 __metaclass__
= Singleton
1059 def _instantiate(self
, parent
= None, path
= ''):
1065 def unproxy(self
, base
):
1068 def set_path(self
, parent
, name
):
1077 # The only instance you'll ever need...
1078 NULL
= NullSimObject()
1080 def isNullPointer(value
):
1081 return isinstance(value
, NullSimObject
)
1083 # Some memory range specifications use this as a default upper bound.
1086 AllMemory
= AddrRange(0, MaxAddr
)
1089 #####################################################################
1093 # Ports are used to interconnect objects in the memory system.
1095 #####################################################################
1097 # Port reference: encapsulates a reference to a particular port on a
1098 # particular SimObject.
1099 class PortRef(object):
1100 def __init__(self
, simobj
, name
):
1101 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1102 self
.simobj
= simobj
1104 self
.peer
= None # not associated with another port yet
1105 self
.ccConnected
= False # C++ port connection done?
1106 self
.index
= -1 # always -1 for non-vector ports
1109 return '%s.%s' % (self
.simobj
, self
.name
)
1111 # for config.ini, print peer's name (not ours)
1113 return str(self
.peer
)
1115 def __getattr__(self
, attr
):
1116 if attr
== 'peerObj':
1117 # shorthand for proxies
1118 return self
.peer
.simobj
1119 raise AttributeError, "'%s' object has no attribute '%s'" % \
1120 (self
.__class
__.__name
__, attr
)
1122 # Full connection is symmetric (both ways). Called via
1123 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1124 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1125 # e.g., "obj1.portA[3] = obj2.portB".
1126 def connect(self
, other
):
1127 if isinstance(other
, VectorPortRef
):
1128 # reference to plain VectorPort is implicit append
1129 other
= other
._get
_next
()
1130 if self
.peer
and not proxy
.isproxy(self
.peer
):
1131 print "warning: overwriting port", self
, \
1132 "value", self
.peer
, "with", other
1133 self
.peer
.peer
= None
1135 if proxy
.isproxy(other
):
1136 other
.set_param_desc(PortParamDesc())
1137 elif isinstance(other
, PortRef
):
1138 if other
.peer
is not self
:
1142 "assigning non-port reference '%s' to port '%s'" \
1145 def clone(self
, simobj
, memo
):
1146 if memo
.has_key(self
):
1148 newRef
= copy
.copy(self
)
1150 newRef
.simobj
= simobj
1151 assert(isSimObject(newRef
.simobj
))
1152 if self
.peer
and not proxy
.isproxy(self
.peer
):
1153 peerObj
= self
.peer
.simobj(_memo
=memo
)
1154 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1155 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1158 def unproxy(self
, simobj
):
1159 assert(simobj
is self
.simobj
)
1160 if proxy
.isproxy(self
.peer
):
1162 realPeer
= self
.peer
.unproxy(self
.simobj
)
1164 print "Error in unproxying port '%s' of %s" % \
1165 (self
.name
, self
.simobj
.path())
1167 self
.connect(realPeer
)
1169 # Call C++ to create corresponding port connection between C++ objects
1170 def ccConnect(self
):
1171 from m5
.internal
.params
import connectPorts
1173 if self
.ccConnected
: # already done this
1176 if not self
.peer
: # nothing to connect to
1179 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1180 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1182 print "Error connecting port %s.%s to %s.%s" % \
1183 (self
.simobj
.path(), self
.name
,
1184 peer
.simobj
.path(), peer
.name
)
1186 self
.ccConnected
= True
1187 peer
.ccConnected
= True
1189 # A reference to an individual element of a VectorPort... much like a
1190 # PortRef, but has an index.
1191 class VectorPortElementRef(PortRef
):
1192 def __init__(self
, simobj
, name
, index
):
1193 PortRef
.__init
__(self
, simobj
, name
)
1197 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1199 # A reference to a complete vector-valued port (not just a single element).
1200 # Can be indexed to retrieve individual VectorPortElementRef instances.
1201 class VectorPortRef(object):
1202 def __init__(self
, simobj
, name
):
1203 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1204 self
.simobj
= simobj
1209 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1211 # for config.ini, print peer's name (not ours)
1213 return ' '.join([el
.ini_str() for el
in self
.elements
])
1215 def __getitem__(self
, key
):
1216 if not isinstance(key
, int):
1217 raise TypeError, "VectorPort index must be integer"
1218 if key
>= len(self
.elements
):
1219 # need to extend list
1220 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1221 for i
in range(len(self
.elements
), key
+1)]
1222 self
.elements
.extend(ext
)
1223 return self
.elements
[key
]
1225 def _get_next(self
):
1226 return self
[len(self
.elements
)]
1228 def __setitem__(self
, key
, value
):
1229 if not isinstance(key
, int):
1230 raise TypeError, "VectorPort index must be integer"
1231 self
[key
].connect(value
)
1233 def connect(self
, other
):
1234 if isinstance(other
, (list, tuple)):
1235 # Assign list of port refs to vector port.
1236 # For now, append them... not sure if that's the right semantics
1237 # or if it should replace the current vector.
1239 self
._get
_next
().connect(ref
)
1241 # scalar assignment to plain VectorPort is implicit append
1242 self
._get
_next
().connect(other
)
1244 def clone(self
, simobj
, memo
):
1245 if memo
.has_key(self
):
1247 newRef
= copy
.copy(self
)
1249 newRef
.simobj
= simobj
1250 assert(isSimObject(newRef
.simobj
))
1251 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1254 def unproxy(self
, simobj
):
1255 [el
.unproxy(simobj
) for el
in self
.elements
]
1257 def ccConnect(self
):
1258 [el
.ccConnect() for el
in self
.elements
]
1260 # Port description object. Like a ParamDesc object, this represents a
1261 # logical port in the SimObject class, not a particular port on a
1262 # SimObject instance. The latter are represented by PortRef objects.
1264 # Port("description") or Port(default, "description")
1265 def __init__(self
, *args
):
1268 elif len(args
) == 2:
1269 self
.default
= args
[0]
1272 raise TypeError, 'wrong number of arguments'
1273 # self.name is set by SimObject class on assignment
1274 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1276 # Generate a PortRef for this port on the given SimObject with the
1278 def makeRef(self
, simobj
):
1279 return PortRef(simobj
, self
.name
)
1281 # Connect an instance of this port (on the given SimObject with
1282 # the given name) with the port described by the supplied PortRef
1283 def connect(self
, simobj
, ref
):
1284 self
.makeRef(simobj
).connect(ref
)
1286 # VectorPort description object. Like Port, but represents a vector
1287 # of connections (e.g., as on a Bus).
1288 class VectorPort(Port
):
1289 def __init__(self
, *args
):
1290 Port
.__init
__(self
, *args
)
1293 def makeRef(self
, simobj
):
1294 return VectorPortRef(simobj
, self
.name
)
1296 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1297 # proxy objects (via set_param_desc()) so that proxy error messages
1299 class PortParamDesc(object):
1300 __metaclass__
= Singleton
1305 baseEnums
= allEnums
.copy()
1306 baseParams
= allParams
.copy()
1309 global allEnums
, allParams
1311 allEnums
= baseEnums
.copy()
1312 allParams
= baseParams
.copy()
1314 __all__
= ['Param', 'VectorParam',
1315 'Enum', 'Bool', 'String', 'Float',
1316 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1317 'Int32', 'UInt32', 'Int64', 'UInt64',
1318 'Counter', 'Addr', 'Tick', 'Percent',
1319 'TcpPort', 'UdpPort', 'EthernetAddr',
1320 'MemorySize', 'MemorySize32',
1321 'Latency', 'Frequency', 'Clock',
1322 'NetworkBandwidth', 'MemoryBandwidth',
1323 'Range', 'AddrRange', 'TickRange',
1324 'MaxAddr', 'MaxTick', 'AllMemory',
1326 'NextEthernetAddr', 'NULL',
1327 'Port', 'VectorPort']