3a3a300148219ab24f69c624504a6cd97787c4e8
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 #####################################################################
57 def isSimObject(*args
, **kwargs
):
58 return SimObject
.isSimObject(*args
, **kwargs
)
60 def isSimObjectSequence(*args
, **kwargs
):
61 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
63 def isSimObjectClass(*args
, **kwargs
):
64 return SimObject
.isSimObjectClass(*args
, **kwargs
)
68 class MetaParamValue(type):
69 def __new__(mcls
, name
, bases
, dct
):
70 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
71 assert name
not in allParams
76 # Dummy base class to identify types that are legitimate for SimObject
78 class ParamValue(object):
79 __metaclass__
= MetaParamValue
84 # default for printing to .ini file is regular string conversion.
85 # will be overridden in some cases
89 # allows us to blithely call unproxy() on things without checking
90 # if they're really proxies or not
91 def unproxy(self
, base
):
94 # Regular parameter description.
95 class ParamDesc(object):
96 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
97 self
.ptype_str
= ptype_str
98 # remember ptype only if it is provided
106 self
.default
= args
[0]
109 raise TypeError, 'too many arguments'
111 if kwargs
.has_key('desc'):
112 assert(not hasattr(self
, 'desc'))
113 self
.desc
= kwargs
['desc']
116 if kwargs
.has_key('default'):
117 assert(not hasattr(self
, 'default'))
118 self
.default
= kwargs
['default']
119 del kwargs
['default']
122 raise TypeError, 'extra unknown kwargs %s' % kwargs
124 if not hasattr(self
, 'desc'):
125 raise TypeError, 'desc attribute missing'
127 def __getattr__(self
, attr
):
129 ptype
= SimObject
.allClasses
[self
.ptype_str
]
130 assert issubclass(ptype
, SimObject
.SimObject
)
134 raise AttributeError, "'%s' object has no attribute '%s'" % \
135 (type(self
).__name
__, attr
)
137 def convert(self
, value
):
138 if isinstance(value
, proxy
.BaseProxy
):
139 value
.set_param_desc(self
)
141 if not hasattr(self
, 'ptype') and isNullPointer(value
):
142 # deferred evaluation of SimObject; continue to defer if
143 # we're just assigning a null pointer
145 if isinstance(value
, self
.ptype
):
147 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
149 return self
.ptype(value
)
151 def cxx_predecls(self
):
152 return self
.ptype
.cxx_predecls
154 def swig_predecls(self
):
155 return self
.ptype
.swig_predecls
158 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
160 # Vector-valued parameter description. Just like ParamDesc, except
161 # that the value is a vector (list) of the specified type instead of a
164 class VectorParamValue(list):
165 __metaclass__
= MetaParamValue
166 def __setattr__(self
, attr
, value
):
167 raise AttributeError, \
168 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
171 return ' '.join([v
.ini_str() for v
in self
])
174 return [ v
.getValue() for v
in self
]
176 def unproxy(self
, base
):
177 return [v
.unproxy(base
) for v
in self
]
179 class SimObjVector(VectorParamValue
):
180 def print_ini(self
, ini_file
):
182 v
.print_ini(ini_file
)
184 class VectorParamDesc(ParamDesc
):
185 # Convert assigned value to appropriate type. If the RHS is not a
186 # list or tuple, it generates a single-element list.
187 def convert(self
, value
):
188 if isinstance(value
, (list, tuple)):
189 # list: coerce each element into new list
190 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
192 # singleton: coerce to a single-element list
193 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
195 if isSimObjectSequence(tmp_list
):
196 return SimObjVector(tmp_list
)
198 return VectorParamValue(tmp_list
)
200 def swig_predecls(self
):
201 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
204 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
205 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
206 (self
.ptype_str
, cxx_type
)
207 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
209 def cxx_predecls(self
):
210 return ['#include <vector>'] + self
.ptype
.cxx_predecls
213 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
215 class ParamFactory(object):
216 def __init__(self
, param_desc_class
, ptype_str
= None):
217 self
.param_desc_class
= param_desc_class
218 self
.ptype_str
= ptype_str
220 def __getattr__(self
, attr
):
222 attr
= self
.ptype_str
+ '.' + attr
223 return ParamFactory(self
.param_desc_class
, attr
)
225 # E.g., Param.Int(5, "number of widgets")
226 def __call__(self
, *args
, **kwargs
):
229 ptype
= allParams
[self
.ptype_str
]
231 # if name isn't defined yet, assume it's a SimObject, and
232 # try to resolve it later
234 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
236 Param
= ParamFactory(ParamDesc
)
237 VectorParam
= ParamFactory(VectorParamDesc
)
239 #####################################################################
243 # Though native Python types could be used to specify parameter types
244 # (the 'ptype' field of the Param and VectorParam classes), it's more
245 # flexible to define our own set of types. This gives us more control
246 # over how Python expressions are converted to values (via the
247 # __init__() constructor) and how these values are printed out (via
248 # the __str__() conversion method).
250 #####################################################################
252 # String-valued parameter. Just mixin the ParamValue class with the
253 # built-in str class.
254 class String(ParamValue
,str):
255 cxx_type
= 'std::string'
256 cxx_predecls
= ['#include <string>']
257 swig_predecls
= ['%include "std_string.i"\n' +
258 '%apply const std::string& {std::string *};']
259 swig_predecls
= ['%include "std_string.i"' ]
264 # superclass for "numeric" parameter values, to emulate math
265 # operations in a type-safe way. e.g., a Latency times an int returns
266 # a new Latency object.
267 class NumericParamValue(ParamValue
):
269 return str(self
.value
)
272 return float(self
.value
)
275 return long(self
.value
)
278 return int(self
.value
)
280 # hook for bounds checking
284 def __mul__(self
, other
):
285 newobj
= self
.__class
__(self
)
286 newobj
.value
*= other
292 def __div__(self
, other
):
293 newobj
= self
.__class
__(self
)
294 newobj
.value
/= other
298 def __sub__(self
, other
):
299 newobj
= self
.__class
__(self
)
300 newobj
.value
-= other
304 # Metaclass for bounds-checked integer parameters. See CheckedInt.
305 class CheckedIntType(MetaParamValue
):
306 def __init__(cls
, name
, bases
, dict):
307 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
309 # CheckedInt is an abstract base class, so we actually don't
310 # want to do any processing on it... the rest of this code is
311 # just for classes that derive from CheckedInt.
312 if name
== 'CheckedInt':
315 if not cls
.cxx_predecls
:
316 # most derived types require this, so we just do it here once
317 cls
.cxx_predecls
= ['#include "base/types.hh"']
319 if not cls
.swig_predecls
:
320 # most derived types require this, so we just do it here once
321 cls
.swig_predecls
= ['%import "stdint.i"\n' +
322 '%import "base/types.hh"']
324 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
325 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
326 panic("CheckedInt subclass %s must define either\n" \
327 " 'min' and 'max' or 'size' and 'unsigned'\n",
331 cls
.max = 2 ** cls
.size
- 1
333 cls
.min = -(2 ** (cls
.size
- 1))
334 cls
.max = (2 ** (cls
.size
- 1)) - 1
336 # Abstract superclass for bounds-checked integer parameters. This
337 # class is subclassed to generate parameter classes with specific
338 # bounds. Initialization of the min and max bounds is done in the
339 # metaclass CheckedIntType.__init__.
340 class CheckedInt(NumericParamValue
):
341 __metaclass__
= CheckedIntType
344 if not self
.min <= self
.value
<= self
.max:
345 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
346 (self
.min, self
.value
, self
.max)
348 def __init__(self
, value
):
349 if isinstance(value
, str):
350 self
.value
= convert
.toInteger(value
)
351 elif isinstance(value
, (int, long, float, NumericParamValue
)):
352 self
.value
= long(value
)
354 raise TypeError, "Can't convert object of type %s to CheckedInt" \
355 % type(value
).__name
__
359 return long(self
.value
)
361 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
362 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
364 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
365 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
366 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
367 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
368 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
369 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
370 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
371 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
373 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
374 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
375 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
376 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
378 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
380 class Float(ParamValue
, float):
383 def __init__(self
, value
):
384 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
385 self
.value
= float(value
)
387 raise TypeError, "Can't convert object of type %s to Float" \
388 % type(value
).__name
__
391 return float(self
.value
)
393 class MemorySize(CheckedInt
):
394 cxx_type
= 'uint64_t'
397 def __init__(self
, value
):
398 if isinstance(value
, MemorySize
):
399 self
.value
= value
.value
401 self
.value
= convert
.toMemorySize(value
)
404 class MemorySize32(CheckedInt
):
405 cxx_type
= 'uint32_t'
408 def __init__(self
, value
):
409 if isinstance(value
, MemorySize
):
410 self
.value
= value
.value
412 self
.value
= convert
.toMemorySize(value
)
415 class Addr(CheckedInt
):
419 def __init__(self
, value
):
420 if isinstance(value
, Addr
):
421 self
.value
= value
.value
424 self
.value
= convert
.toMemorySize(value
)
426 self
.value
= long(value
)
428 def __add__(self
, other
):
429 if isinstance(other
, Addr
):
430 return self
.value
+ other
.value
432 return self
.value
+ other
435 class MetaRange(MetaParamValue
):
436 def __init__(cls
, name
, bases
, dict):
437 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
440 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
442 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
444 class Range(ParamValue
):
445 __metaclass__
= MetaRange
446 type = Int
# default; can be overridden in subclasses
447 def __init__(self
, *args
, **kwargs
):
448 def handle_kwargs(self
, kwargs
):
450 self
.second
= self
.type(kwargs
.pop('end'))
451 elif 'size' in kwargs
:
452 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
454 raise TypeError, "Either end or size must be specified"
457 self
.first
= self
.type(kwargs
.pop('start'))
458 handle_kwargs(self
, kwargs
)
462 self
.first
= self
.type(args
[0])
463 handle_kwargs(self
, kwargs
)
464 elif isinstance(args
[0], Range
):
465 self
.first
= self
.type(args
[0].first
)
466 self
.second
= self
.type(args
[0].second
)
467 elif isinstance(args
[0], (list, tuple)):
468 self
.first
= self
.type(args
[0][0])
469 self
.second
= self
.type(args
[0][1])
471 self
.first
= self
.type(0)
472 self
.second
= self
.type(args
[0]) - 1
475 self
.first
= self
.type(args
[0])
476 self
.second
= self
.type(args
[1])
478 raise TypeError, "Too many arguments specified"
481 raise TypeError, "too many keywords: %s" % kwargs
.keys()
484 return '%s:%s' % (self
.first
, self
.second
)
486 class AddrRange(Range
):
488 swig_predecls
= ['%include "python/swig/range.i"']
491 from m5
.objects
.params
import AddrRange
494 value
.start
= long(self
.first
)
495 value
.end
= long(self
.second
)
498 class TickRange(Range
):
500 swig_predecls
= ['%include "python/swig/range.i"']
503 from m5
.objects
.params
import TickRange
506 value
.start
= long(self
.first
)
507 value
.end
= long(self
.second
)
510 # Boolean parameter type. Python doesn't let you subclass bool, since
511 # it doesn't want to let you create multiple instances of True and
512 # False. Thus this is a little more complicated than String.
513 class Bool(ParamValue
):
515 def __init__(self
, value
):
517 self
.value
= convert
.toBool(value
)
519 self
.value
= bool(value
)
522 return bool(self
.value
)
525 return str(self
.value
)
532 def IncEthernetAddr(addr
, val
= 1):
533 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
535 for i
in (5, 4, 3, 2, 1):
536 val
,rem
= divmod(bytes
[i
], 256)
541 assert(bytes
[0] <= 255)
542 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
544 _NextEthernetAddr
= "00:90:00:00:00:01"
545 def NextEthernetAddr():
546 global _NextEthernetAddr
548 value
= _NextEthernetAddr
549 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
552 class EthernetAddr(ParamValue
):
553 cxx_type
= 'Net::EthAddr'
554 cxx_predecls
= ['#include "base/inet.hh"']
555 swig_predecls
= ['%include "python/swig/inet.i"']
556 def __init__(self
, value
):
557 if value
== NextEthernetAddr
:
561 if not isinstance(value
, str):
562 raise TypeError, "expected an ethernet address and didn't get one"
564 bytes
= value
.split(':')
566 raise TypeError, 'invalid ethernet address %s' % value
569 if not 0 <= int(byte
) <= 256:
570 raise TypeError, 'invalid ethernet address %s' % value
574 def unproxy(self
, base
):
575 if self
.value
== NextEthernetAddr
:
576 return EthernetAddr(self
.value())
580 from m5
.objects
.params
import EthAddr
581 return EthAddr(self
.value
)
586 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
587 "%a %b %d %H:%M:%S %Z %Y",
599 def parse_time(value
):
600 from time
import gmtime
, strptime
, struct_time
, time
601 from datetime
import datetime
, date
603 if isinstance(value
, struct_time
):
606 if isinstance(value
, (int, long)):
609 if isinstance(value
, (datetime
, date
)):
610 return value
.timetuple()
612 if isinstance(value
, str):
613 if value
in ('Now', 'Today'):
614 return time
.gmtime(time
.time())
616 for format
in time_formats
:
618 return strptime(value
, format
)
622 raise ValueError, "Could not parse '%s' as a time" % value
624 class Time(ParamValue
):
626 cxx_predecls
= [ '#include <time.h>' ]
627 swig_predecls
= [ '%include "python/swig/time.i"' ]
628 def __init__(self
, value
):
629 self
.value
= parse_time(value
)
632 from m5
.objects
.params
import tm
637 # UNIX is years since 1900
638 c_time
.tm_year
= py_time
.tm_year
- 1900;
640 # Python starts at 1, UNIX starts at 0
641 c_time
.tm_mon
= py_time
.tm_mon
- 1;
642 c_time
.tm_mday
= py_time
.tm_mday
;
643 c_time
.tm_hour
= py_time
.tm_hour
;
644 c_time
.tm_min
= py_time
.tm_min
;
645 c_time
.tm_sec
= py_time
.tm_sec
;
647 # Python has 0 as Monday, UNIX is 0 as sunday
648 c_time
.tm_wday
= py_time
.tm_wday
+ 1
649 if c_time
.tm_wday
> 6:
652 # Python starts at 1, Unix starts at 0
653 c_time
.tm_yday
= py_time
.tm_yday
- 1;
658 return time
.asctime(self
.value
)
663 # Enumerated types are a little more complex. The user specifies the
664 # type as Enum(foo) where foo is either a list or dictionary of
665 # alternatives (typically strings, but not necessarily so). (In the
666 # long run, the integer value of the parameter will be the list index
667 # or the corresponding dictionary value. For now, since we only check
668 # that the alternative is valid and then spit it into a .ini file,
669 # there's not much point in using the dictionary.)
671 # What Enum() must do is generate a new type encapsulating the
672 # provided list/dictionary so that specific values of the parameter
673 # can be instances of that type. We define two hidden internal
674 # classes (_ListEnum and _DictEnum) to serve as base classes, then
675 # derive the new type from the appropriate base class on the fly.
678 # Metaclass for Enum types
679 class MetaEnum(MetaParamValue
):
680 def __new__(mcls
, name
, bases
, dict):
681 assert name
not in allEnums
683 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
687 def __init__(cls
, name
, bases
, init_dict
):
688 if init_dict
.has_key('map'):
689 if not isinstance(cls
.map, dict):
690 raise TypeError, "Enum-derived class attribute 'map' " \
691 "must be of type dict"
692 # build list of value strings from map
693 cls
.vals
= cls
.map.keys()
695 elif init_dict
.has_key('vals'):
696 if not isinstance(cls
.vals
, list):
697 raise TypeError, "Enum-derived class attribute 'vals' " \
698 "must be of type list"
699 # build string->value map from vals sequence
701 for idx
,val
in enumerate(cls
.vals
):
704 raise TypeError, "Enum-derived class must define "\
705 "attribute 'map' or 'vals'"
707 cls
.cxx_type
= 'Enums::%s' % name
709 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
711 # Generate C++ class declaration for this enum type.
712 # Note that we wrap the enum in a class/struct to act as a namespace,
713 # so that the enum strings can be brief w/o worrying about collisions.
716 code
= "#ifndef __ENUM__%s\n" % name
717 code
+= '#define __ENUM__%s\n' % name
719 code
+= 'namespace Enums {\n'
720 code
+= ' enum %s {\n' % name
722 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
723 code
+= ' Num_%s = %d,\n' % (name
, len(cls
.vals
))
725 code
+= ' extern const char *%sStrings[Num_%s];\n' % (name
, name
)
733 code
= '#include "enums/%s.hh"\n' % name
734 code
+= 'namespace Enums {\n'
735 code
+= ' const char *%sStrings[Num_%s] =\n' % (name
, name
)
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 "base/types.hh"']
766 swig_predecls
= ['%import "stdint.i"\n' +
767 '%import "base/types.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 "base/types.hh"']
844 swig_predecls
= ['%import "stdint.i"\n' +
845 '%import "base/types.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
1003 self
.peer
.peer
= None
1005 if proxy
.isproxy(other
):
1006 other
.set_param_desc(PortParamDesc())
1007 elif isinstance(other
, PortRef
):
1008 if other
.peer
is not self
:
1012 "assigning non-port reference '%s' to port '%s'" \
1015 def clone(self
, simobj
, memo
):
1016 if memo
.has_key(self
):
1018 newRef
= copy
.copy(self
)
1020 newRef
.simobj
= simobj
1021 assert(isSimObject(newRef
.simobj
))
1022 if self
.peer
and not proxy
.isproxy(self
.peer
):
1023 peerObj
= self
.peer
.simobj(_memo
=memo
)
1024 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1025 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1028 def unproxy(self
, simobj
):
1029 assert(simobj
is self
.simobj
)
1030 if proxy
.isproxy(self
.peer
):
1032 realPeer
= self
.peer
.unproxy(self
.simobj
)
1034 print "Error in unproxying port '%s' of %s" % \
1035 (self
.name
, self
.simobj
.path())
1037 self
.connect(realPeer
)
1039 # Call C++ to create corresponding port connection between C++ objects
1040 def ccConnect(self
):
1041 from m5
.objects
.params
import connectPorts
1043 if self
.ccConnected
: # already done this
1046 if not self
.peer
: # nothing to connect to
1048 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1049 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1050 self
.ccConnected
= True
1051 peer
.ccConnected
= True
1053 # A reference to an individual element of a VectorPort... much like a
1054 # PortRef, but has an index.
1055 class VectorPortElementRef(PortRef
):
1056 def __init__(self
, simobj
, name
, index
):
1057 PortRef
.__init
__(self
, simobj
, name
)
1061 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1063 # A reference to a complete vector-valued port (not just a single element).
1064 # Can be indexed to retrieve individual VectorPortElementRef instances.
1065 class VectorPortRef(object):
1066 def __init__(self
, simobj
, name
):
1067 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1068 self
.simobj
= simobj
1073 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1075 # for config.ini, print peer's name (not ours)
1077 return ' '.join([el
.ini_str() for el
in self
.elements
])
1079 def __getitem__(self
, key
):
1080 if not isinstance(key
, int):
1081 raise TypeError, "VectorPort index must be integer"
1082 if key
>= len(self
.elements
):
1083 # need to extend list
1084 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1085 for i
in range(len(self
.elements
), key
+1)]
1086 self
.elements
.extend(ext
)
1087 return self
.elements
[key
]
1089 def _get_next(self
):
1090 return self
[len(self
.elements
)]
1092 def __setitem__(self
, key
, value
):
1093 if not isinstance(key
, int):
1094 raise TypeError, "VectorPort index must be integer"
1095 self
[key
].connect(value
)
1097 def connect(self
, other
):
1098 if isinstance(other
, (list, tuple)):
1099 # Assign list of port refs to vector port.
1100 # For now, append them... not sure if that's the right semantics
1101 # or if it should replace the current vector.
1103 self
._get
_next
().connect(ref
)
1105 # scalar assignment to plain VectorPort is implicit append
1106 self
._get
_next
().connect(other
)
1108 def clone(self
, simobj
, memo
):
1109 if memo
.has_key(self
):
1111 newRef
= copy
.copy(self
)
1113 newRef
.simobj
= simobj
1114 assert(isSimObject(newRef
.simobj
))
1115 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1118 def unproxy(self
, simobj
):
1119 [el
.unproxy(simobj
) for el
in self
.elements
]
1121 def ccConnect(self
):
1122 [el
.ccConnect() for el
in self
.elements
]
1124 # Port description object. Like a ParamDesc object, this represents a
1125 # logical port in the SimObject class, not a particular port on a
1126 # SimObject instance. The latter are represented by PortRef objects.
1128 # Port("description") or Port(default, "description")
1129 def __init__(self
, *args
):
1132 elif len(args
) == 2:
1133 self
.default
= args
[0]
1136 raise TypeError, 'wrong number of arguments'
1137 # self.name is set by SimObject class on assignment
1138 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1140 # Generate a PortRef for this port on the given SimObject with the
1142 def makeRef(self
, simobj
):
1143 return PortRef(simobj
, self
.name
)
1145 # Connect an instance of this port (on the given SimObject with
1146 # the given name) with the port described by the supplied PortRef
1147 def connect(self
, simobj
, ref
):
1148 self
.makeRef(simobj
).connect(ref
)
1150 # VectorPort description object. Like Port, but represents a vector
1151 # of connections (e.g., as on a Bus).
1152 class VectorPort(Port
):
1153 def __init__(self
, *args
):
1154 Port
.__init
__(self
, *args
)
1157 def makeRef(self
, simobj
):
1158 return VectorPortRef(simobj
, self
.name
)
1160 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1161 # proxy objects (via set_param_desc()) so that proxy error messages
1163 class PortParamDesc(object):
1164 __metaclass__
= Singleton
1169 baseEnums
= allEnums
.copy()
1170 baseParams
= allParams
.copy()
1173 global allEnums
, allParams
1175 allEnums
= baseEnums
.copy()
1176 allParams
= baseParams
.copy()
1178 __all__
= ['Param', 'VectorParam',
1179 'Enum', 'Bool', 'String', 'Float',
1180 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1181 'Int32', 'UInt32', 'Int64', 'UInt64',
1182 'Counter', 'Addr', 'Tick', 'Percent',
1183 'TcpPort', 'UdpPort', 'EthernetAddr',
1184 'MemorySize', 'MemorySize32',
1185 'Latency', 'Frequency', 'Clock',
1186 'NetworkBandwidth', 'MemoryBandwidth',
1187 'Range', 'AddrRange', 'TickRange',
1188 'MaxAddr', 'MaxTick', 'AllMemory',
1190 'NextEthernetAddr', 'NULL',
1191 'Port', 'VectorPort']