38e320b5302dcd16aa39bd35659351c2149ffccc
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
86 # default for printing to .ini file is regular string conversion.
87 # will be overridden in some cases
91 # allows us to blithely call unproxy() on things without checking
92 # if they're really proxies or not
93 def unproxy(self
, base
):
96 # Regular parameter description.
97 class ParamDesc(object):
100 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
101 self
.ptype_str
= ptype_str
102 # remember ptype only if it is provided
110 self
.default
= args
[0]
113 raise TypeError, 'too many arguments'
115 if kwargs
.has_key('desc'):
116 assert(not hasattr(self
, 'desc'))
117 self
.desc
= kwargs
['desc']
120 if kwargs
.has_key('default'):
121 assert(not hasattr(self
, 'default'))
122 self
.default
= kwargs
['default']
123 del kwargs
['default']
126 raise TypeError, 'extra unknown kwargs %s' % kwargs
128 if not hasattr(self
, 'desc'):
129 raise TypeError, 'desc attribute missing'
131 def __getattr__(self
, attr
):
133 ptype
= SimObject
.allClasses
[self
.ptype_str
]
134 assert isSimObjectClass(ptype
)
138 raise AttributeError, "'%s' object has no attribute '%s'" % \
139 (type(self
).__name
__, attr
)
141 def convert(self
, value
):
142 if isinstance(value
, proxy
.BaseProxy
):
143 value
.set_param_desc(self
)
145 if not hasattr(self
, 'ptype') and isNullPointer(value
):
146 # deferred evaluation of SimObject; continue to defer if
147 # we're just assigning a null pointer
149 if isinstance(value
, self
.ptype
):
151 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
153 return self
.ptype(value
)
155 def cxx_predecls(self
):
156 return self
.ptype
.cxx_predecls
158 def swig_predecls(self
):
159 return self
.ptype
.swig_predecls
162 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
164 # Vector-valued parameter description. Just like ParamDesc, except
165 # that the value is a vector (list) of the specified type instead of a
168 class VectorParamValue(list):
169 __metaclass__
= MetaParamValue
170 def __setattr__(self
, attr
, value
):
171 raise AttributeError, \
172 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
175 return ' '.join([v
.ini_str() for v
in self
])
178 return [ v
.getValue() for v
in self
]
180 def unproxy(self
, base
):
181 return [v
.unproxy(base
) for v
in self
]
183 class SimObjectVector(VectorParamValue
):
184 # support clone operation
185 def __call__(self
, **kwargs
):
186 return SimObjectVector([v(**kwargs
) for v
in self
])
188 def clear_parent(self
, old_parent
):
190 v
.clear_parent(old_parent
)
192 def set_parent(self
, parent
, name
):
194 self
[0].set_parent(parent
, name
)
196 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
197 for i
,v
in enumerate(self
):
198 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
200 def get_parent(self
):
201 parent_set
= set(v
._parent
for v
in self
)
202 if len(parent_set
) != 1:
203 raise RuntimeError, \
204 "SimObjectVector elements have inconsistent parent value."
205 return parent_set
.pop()
207 # return 'cpu0 cpu1' etc. for print_ini()
209 return ' '.join([v
._name
for v
in self
])
211 # By iterating through the constituent members of the vector here
212 # we can nicely handle iterating over all a SimObject's children
213 # without having to provide lots of special functions on
214 # SimObjectVector directly.
215 def descendants(self
):
217 for obj
in v
.descendants():
220 class VectorParamDesc(ParamDesc
):
223 # Convert assigned value to appropriate type. If the RHS is not a
224 # list or tuple, it generates a single-element list.
225 def convert(self
, value
):
226 if isinstance(value
, (list, tuple)):
227 # list: coerce each element into new list
228 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
230 # singleton: coerce to a single-element list
231 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
233 if isSimObjectSequence(tmp_list
):
234 return SimObjectVector(tmp_list
)
236 return VectorParamValue(tmp_list
)
238 def swig_predecls(self
):
239 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
242 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
243 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
244 (self
.ptype_str
, cxx_type
)
245 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
247 def cxx_predecls(self
):
248 return ['#include <vector>'] + self
.ptype
.cxx_predecls
251 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
253 class ParamFactory(object):
254 def __init__(self
, param_desc_class
, ptype_str
= None):
255 self
.param_desc_class
= param_desc_class
256 self
.ptype_str
= ptype_str
258 def __getattr__(self
, attr
):
260 attr
= self
.ptype_str
+ '.' + attr
261 return ParamFactory(self
.param_desc_class
, attr
)
263 # E.g., Param.Int(5, "number of widgets")
264 def __call__(self
, *args
, **kwargs
):
267 ptype
= allParams
[self
.ptype_str
]
269 # if name isn't defined yet, assume it's a SimObject, and
270 # try to resolve it later
272 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
274 Param
= ParamFactory(ParamDesc
)
275 VectorParam
= ParamFactory(VectorParamDesc
)
277 #####################################################################
281 # Though native Python types could be used to specify parameter types
282 # (the 'ptype' field of the Param and VectorParam classes), it's more
283 # flexible to define our own set of types. This gives us more control
284 # over how Python expressions are converted to values (via the
285 # __init__() constructor) and how these values are printed out (via
286 # the __str__() conversion method).
288 #####################################################################
290 # String-valued parameter. Just mixin the ParamValue class with the
291 # built-in str class.
292 class String(ParamValue
,str):
293 cxx_type
= 'std::string'
294 cxx_predecls
= ['#include <string>']
295 swig_predecls
= ['%include "std_string.i"\n' +
296 '%apply const std::string& {std::string *};']
297 swig_predecls
= ['%include "std_string.i"' ]
302 # superclass for "numeric" parameter values, to emulate math
303 # operations in a type-safe way. e.g., a Latency times an int returns
304 # a new Latency object.
305 class NumericParamValue(ParamValue
):
307 return str(self
.value
)
310 return float(self
.value
)
313 return long(self
.value
)
316 return int(self
.value
)
318 # hook for bounds checking
322 def __mul__(self
, other
):
323 newobj
= self
.__class
__(self
)
324 newobj
.value
*= other
330 def __div__(self
, other
):
331 newobj
= self
.__class
__(self
)
332 newobj
.value
/= other
336 def __sub__(self
, other
):
337 newobj
= self
.__class
__(self
)
338 newobj
.value
-= other
342 # Metaclass for bounds-checked integer parameters. See CheckedInt.
343 class CheckedIntType(MetaParamValue
):
344 def __init__(cls
, name
, bases
, dict):
345 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
347 # CheckedInt is an abstract base class, so we actually don't
348 # want to do any processing on it... the rest of this code is
349 # just for classes that derive from CheckedInt.
350 if name
== 'CheckedInt':
353 if not cls
.cxx_predecls
:
354 # most derived types require this, so we just do it here once
355 cls
.cxx_predecls
= ['#include "base/types.hh"']
357 if not cls
.swig_predecls
:
358 # most derived types require this, so we just do it here once
359 cls
.swig_predecls
= ['%import "stdint.i"\n' +
360 '%import "base/types.hh"']
362 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
363 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
364 panic("CheckedInt subclass %s must define either\n" \
365 " 'min' and 'max' or 'size' and 'unsigned'\n",
369 cls
.max = 2 ** cls
.size
- 1
371 cls
.min = -(2 ** (cls
.size
- 1))
372 cls
.max = (2 ** (cls
.size
- 1)) - 1
374 # Abstract superclass for bounds-checked integer parameters. This
375 # class is subclassed to generate parameter classes with specific
376 # bounds. Initialization of the min and max bounds is done in the
377 # metaclass CheckedIntType.__init__.
378 class CheckedInt(NumericParamValue
):
379 __metaclass__
= CheckedIntType
382 if not self
.min <= self
.value
<= self
.max:
383 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
384 (self
.min, self
.value
, self
.max)
386 def __init__(self
, value
):
387 if isinstance(value
, str):
388 self
.value
= convert
.toInteger(value
)
389 elif isinstance(value
, (int, long, float, NumericParamValue
)):
390 self
.value
= long(value
)
392 raise TypeError, "Can't convert object of type %s to CheckedInt" \
393 % type(value
).__name
__
397 return long(self
.value
)
399 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
400 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
402 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
403 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
404 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
405 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
406 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
407 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
408 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
409 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
411 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
412 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
413 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
414 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
416 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
418 class Float(ParamValue
, float):
421 def __init__(self
, value
):
422 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
423 self
.value
= float(value
)
425 raise TypeError, "Can't convert object of type %s to Float" \
426 % type(value
).__name
__
429 return float(self
.value
)
431 class MemorySize(CheckedInt
):
432 cxx_type
= 'uint64_t'
435 def __init__(self
, value
):
436 if isinstance(value
, MemorySize
):
437 self
.value
= value
.value
439 self
.value
= convert
.toMemorySize(value
)
442 class MemorySize32(CheckedInt
):
443 cxx_type
= 'uint32_t'
446 def __init__(self
, value
):
447 if isinstance(value
, MemorySize
):
448 self
.value
= value
.value
450 self
.value
= convert
.toMemorySize(value
)
453 class Addr(CheckedInt
):
457 def __init__(self
, value
):
458 if isinstance(value
, Addr
):
459 self
.value
= value
.value
462 self
.value
= convert
.toMemorySize(value
)
464 self
.value
= long(value
)
466 def __add__(self
, other
):
467 if isinstance(other
, Addr
):
468 return self
.value
+ other
.value
470 return self
.value
+ other
473 class MetaRange(MetaParamValue
):
474 def __init__(cls
, name
, bases
, dict):
475 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
478 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
480 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
482 class Range(ParamValue
):
483 __metaclass__
= MetaRange
484 type = Int
# default; can be overridden in subclasses
485 def __init__(self
, *args
, **kwargs
):
486 def handle_kwargs(self
, kwargs
):
488 self
.second
= self
.type(kwargs
.pop('end'))
489 elif 'size' in kwargs
:
490 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
492 raise TypeError, "Either end or size must be specified"
495 self
.first
= self
.type(kwargs
.pop('start'))
496 handle_kwargs(self
, kwargs
)
500 self
.first
= self
.type(args
[0])
501 handle_kwargs(self
, kwargs
)
502 elif isinstance(args
[0], Range
):
503 self
.first
= self
.type(args
[0].first
)
504 self
.second
= self
.type(args
[0].second
)
505 elif isinstance(args
[0], (list, tuple)):
506 self
.first
= self
.type(args
[0][0])
507 self
.second
= self
.type(args
[0][1])
509 self
.first
= self
.type(0)
510 self
.second
= self
.type(args
[0]) - 1
513 self
.first
= self
.type(args
[0])
514 self
.second
= self
.type(args
[1])
516 raise TypeError, "Too many arguments specified"
519 raise TypeError, "too many keywords: %s" % kwargs
.keys()
522 return '%s:%s' % (self
.first
, self
.second
)
524 class AddrRange(Range
):
526 swig_predecls
= ['%include "python/swig/range.i"']
529 from m5
.objects
.params
import AddrRange
532 value
.start
= long(self
.first
)
533 value
.end
= long(self
.second
)
536 class TickRange(Range
):
538 swig_predecls
= ['%include "python/swig/range.i"']
541 from m5
.objects
.params
import TickRange
544 value
.start
= long(self
.first
)
545 value
.end
= long(self
.second
)
548 # Boolean parameter type. Python doesn't let you subclass bool, since
549 # it doesn't want to let you create multiple instances of True and
550 # False. Thus this is a little more complicated than String.
551 class Bool(ParamValue
):
553 def __init__(self
, value
):
555 self
.value
= convert
.toBool(value
)
557 self
.value
= bool(value
)
560 return bool(self
.value
)
563 return str(self
.value
)
570 def IncEthernetAddr(addr
, val
= 1):
571 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
573 for i
in (5, 4, 3, 2, 1):
574 val
,rem
= divmod(bytes
[i
], 256)
579 assert(bytes
[0] <= 255)
580 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
582 _NextEthernetAddr
= "00:90:00:00:00:01"
583 def NextEthernetAddr():
584 global _NextEthernetAddr
586 value
= _NextEthernetAddr
587 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
590 class EthernetAddr(ParamValue
):
591 cxx_type
= 'Net::EthAddr'
592 cxx_predecls
= ['#include "base/inet.hh"']
593 swig_predecls
= ['%include "python/swig/inet.i"']
594 def __init__(self
, value
):
595 if value
== NextEthernetAddr
:
599 if not isinstance(value
, str):
600 raise TypeError, "expected an ethernet address and didn't get one"
602 bytes
= value
.split(':')
604 raise TypeError, 'invalid ethernet address %s' % value
607 if not 0 <= int(byte
) <= 256:
608 raise TypeError, 'invalid ethernet address %s' % value
612 def unproxy(self
, base
):
613 if self
.value
== NextEthernetAddr
:
614 return EthernetAddr(self
.value())
618 from m5
.objects
.params
import EthAddr
619 return EthAddr(self
.value
)
624 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
625 "%a %b %d %H:%M:%S %Z %Y",
637 def parse_time(value
):
638 from time
import gmtime
, strptime
, struct_time
, time
639 from datetime
import datetime
, date
641 if isinstance(value
, struct_time
):
644 if isinstance(value
, (int, long)):
647 if isinstance(value
, (datetime
, date
)):
648 return value
.timetuple()
650 if isinstance(value
, str):
651 if value
in ('Now', 'Today'):
652 return time
.gmtime(time
.time())
654 for format
in time_formats
:
656 return strptime(value
, format
)
660 raise ValueError, "Could not parse '%s' as a time" % value
662 class Time(ParamValue
):
664 cxx_predecls
= [ '#include <time.h>' ]
665 swig_predecls
= [ '%include "python/swig/time.i"' ]
666 def __init__(self
, value
):
667 self
.value
= parse_time(value
)
670 from m5
.objects
.params
import tm
675 # UNIX is years since 1900
676 c_time
.tm_year
= py_time
.tm_year
- 1900;
678 # Python starts at 1, UNIX starts at 0
679 c_time
.tm_mon
= py_time
.tm_mon
- 1;
680 c_time
.tm_mday
= py_time
.tm_mday
;
681 c_time
.tm_hour
= py_time
.tm_hour
;
682 c_time
.tm_min
= py_time
.tm_min
;
683 c_time
.tm_sec
= py_time
.tm_sec
;
685 # Python has 0 as Monday, UNIX is 0 as sunday
686 c_time
.tm_wday
= py_time
.tm_wday
+ 1
687 if c_time
.tm_wday
> 6:
690 # Python starts at 1, Unix starts at 0
691 c_time
.tm_yday
= py_time
.tm_yday
- 1;
696 return time
.asctime(self
.value
)
701 # Enumerated types are a little more complex. The user specifies the
702 # type as Enum(foo) where foo is either a list or dictionary of
703 # alternatives (typically strings, but not necessarily so). (In the
704 # long run, the integer value of the parameter will be the list index
705 # or the corresponding dictionary value. For now, since we only check
706 # that the alternative is valid and then spit it into a .ini file,
707 # there's not much point in using the dictionary.)
709 # What Enum() must do is generate a new type encapsulating the
710 # provided list/dictionary so that specific values of the parameter
711 # can be instances of that type. We define two hidden internal
712 # classes (_ListEnum and _DictEnum) to serve as base classes, then
713 # derive the new type from the appropriate base class on the fly.
716 # Metaclass for Enum types
717 class MetaEnum(MetaParamValue
):
718 def __new__(mcls
, name
, bases
, dict):
719 assert name
not in allEnums
721 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
725 def __init__(cls
, name
, bases
, init_dict
):
726 if init_dict
.has_key('map'):
727 if not isinstance(cls
.map, dict):
728 raise TypeError, "Enum-derived class attribute 'map' " \
729 "must be of type dict"
730 # build list of value strings from map
731 cls
.vals
= cls
.map.keys()
733 elif init_dict
.has_key('vals'):
734 if not isinstance(cls
.vals
, list):
735 raise TypeError, "Enum-derived class attribute 'vals' " \
736 "must be of type list"
737 # build string->value map from vals sequence
739 for idx
,val
in enumerate(cls
.vals
):
742 raise TypeError, "Enum-derived class must define "\
743 "attribute 'map' or 'vals'"
745 cls
.cxx_type
= 'Enums::%s' % name
747 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
749 # Generate C++ class declaration for this enum type.
750 # Note that we wrap the enum in a class/struct to act as a namespace,
751 # so that the enum strings can be brief w/o worrying about collisions.
754 code
= "#ifndef __ENUM__%s\n" % name
755 code
+= '#define __ENUM__%s\n' % name
757 code
+= 'namespace Enums {\n'
758 code
+= ' enum %s {\n' % name
760 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
761 code
+= ' Num_%s = %d,\n' % (name
, len(cls
.vals
))
763 code
+= ' extern const char *%sStrings[Num_%s];\n' % (name
, name
)
771 code
= '#include "enums/%s.hh"\n' % name
772 code
+= 'namespace Enums {\n'
773 code
+= ' const char *%sStrings[Num_%s] =\n' % (name
, name
)
776 code
+= ' "%s",\n' % val
781 # Base class for enum types.
782 class Enum(ParamValue
):
783 __metaclass__
= MetaEnum
786 def __init__(self
, value
):
787 if value
not in self
.map:
788 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
793 return int(self
.map[self
.value
])
798 # how big does a rounding error need to be before we warn about it?
799 frequency_tolerance
= 0.001 # 0.1%
801 class TickParamValue(NumericParamValue
):
803 cxx_predecls
= ['#include "base/types.hh"']
804 swig_predecls
= ['%import "stdint.i"\n' +
805 '%import "base/types.hh"']
808 return long(self
.value
)
810 class Latency(TickParamValue
):
811 def __init__(self
, value
):
812 if isinstance(value
, (Latency
, Clock
)):
813 self
.ticks
= value
.ticks
814 self
.value
= value
.value
815 elif isinstance(value
, Frequency
):
816 self
.ticks
= value
.ticks
817 self
.value
= 1.0 / value
.value
818 elif value
.endswith('t'):
820 self
.value
= int(value
[:-1])
823 self
.value
= convert
.toLatency(value
)
825 def __getattr__(self
, attr
):
826 if attr
in ('latency', 'period'):
828 if attr
== 'frequency':
829 return Frequency(self
)
830 raise AttributeError, "Latency object has no attribute '%s'" % attr
833 if self
.ticks
or self
.value
== 0:
836 value
= ticks
.fromSeconds(self
.value
)
839 # convert latency to ticks
841 return '%d' % self
.getValue()
843 class Frequency(TickParamValue
):
844 def __init__(self
, value
):
845 if isinstance(value
, (Latency
, Clock
)):
849 self
.value
= 1.0 / value
.value
850 self
.ticks
= value
.ticks
851 elif isinstance(value
, Frequency
):
852 self
.value
= value
.value
853 self
.ticks
= value
.ticks
856 self
.value
= convert
.toFrequency(value
)
858 def __getattr__(self
, attr
):
859 if attr
== 'frequency':
861 if attr
in ('latency', 'period'):
863 raise AttributeError, "Frequency object has no attribute '%s'" % attr
865 # convert latency to ticks
867 if self
.ticks
or self
.value
== 0:
870 value
= ticks
.fromSeconds(1.0 / self
.value
)
874 return '%d' % self
.getValue()
876 # A generic frequency and/or Latency value. Value is stored as a latency,
877 # but to avoid ambiguity this object does not support numeric ops (* or /).
878 # An explicit conversion to a Latency or Frequency must be made first.
879 class Clock(ParamValue
):
881 cxx_predecls
= ['#include "base/types.hh"']
882 swig_predecls
= ['%import "stdint.i"\n' +
883 '%import "base/types.hh"']
884 def __init__(self
, value
):
885 if isinstance(value
, (Latency
, Clock
)):
886 self
.ticks
= value
.ticks
887 self
.value
= value
.value
888 elif isinstance(value
, Frequency
):
889 self
.ticks
= value
.ticks
890 self
.value
= 1.0 / value
.value
891 elif value
.endswith('t'):
893 self
.value
= int(value
[:-1])
896 self
.value
= convert
.anyToLatency(value
)
898 def __getattr__(self
, attr
):
899 if attr
== 'frequency':
900 return Frequency(self
)
901 if attr
in ('latency', 'period'):
903 raise AttributeError, "Frequency object has no attribute '%s'" % attr
906 return self
.period
.getValue()
909 return self
.period
.ini_str()
911 class NetworkBandwidth(float,ParamValue
):
913 def __new__(cls
, value
):
914 # convert to bits per second
915 val
= convert
.toNetworkBandwidth(value
)
916 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
922 # convert to seconds per byte
923 value
= 8.0 / float(self
)
924 # convert to ticks per byte
925 value
= ticks
.fromSeconds(value
)
929 return '%f' % self
.getValue()
931 class MemoryBandwidth(float,ParamValue
):
933 def __new__(cls
, value
):
934 # we want the number of ticks per byte of data
935 val
= convert
.toMemoryBandwidth(value
)
936 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
942 # convert to seconds per byte
945 value
= 1.0 / float(self
)
946 # convert to ticks per byte
947 value
= ticks
.fromSeconds(value
)
951 return '%f' % self
.getValue()
954 # "Constants"... handy aliases for various values.
957 # Special class for NULL pointers. Note the special check in
958 # make_param_value() above that lets these be assigned where a
959 # SimObject is required.
960 # only one copy of a particular node
961 class NullSimObject(object):
962 __metaclass__
= Singleton
967 def _instantiate(self
, parent
= None, path
= ''):
973 def unproxy(self
, base
):
976 def set_path(self
, parent
, name
):
985 # The only instance you'll ever need...
986 NULL
= NullSimObject()
988 def isNullPointer(value
):
989 return isinstance(value
, NullSimObject
)
991 # Some memory range specifications use this as a default upper bound.
994 AllMemory
= AddrRange(0, MaxAddr
)
997 #####################################################################
1001 # Ports are used to interconnect objects in the memory system.
1003 #####################################################################
1005 # Port reference: encapsulates a reference to a particular port on a
1006 # particular SimObject.
1007 class PortRef(object):
1008 def __init__(self
, simobj
, name
):
1009 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1010 self
.simobj
= simobj
1012 self
.peer
= None # not associated with another port yet
1013 self
.ccConnected
= False # C++ port connection done?
1014 self
.index
= -1 # always -1 for non-vector ports
1017 return '%s.%s' % (self
.simobj
, self
.name
)
1019 # for config.ini, print peer's name (not ours)
1021 return str(self
.peer
)
1023 def __getattr__(self
, attr
):
1024 if attr
== 'peerObj':
1025 # shorthand for proxies
1026 return self
.peer
.simobj
1027 raise AttributeError, "'%s' object has no attribute '%s'" % \
1028 (self
.__class
__.__name
__, attr
)
1030 # Full connection is symmetric (both ways). Called via
1031 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1032 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1033 # e.g., "obj1.portA[3] = obj2.portB".
1034 def connect(self
, other
):
1035 if isinstance(other
, VectorPortRef
):
1036 # reference to plain VectorPort is implicit append
1037 other
= other
._get
_next
()
1038 if self
.peer
and not proxy
.isproxy(self
.peer
):
1039 print "warning: overwriting port", self
, \
1040 "value", self
.peer
, "with", other
1041 self
.peer
.peer
= None
1043 if proxy
.isproxy(other
):
1044 other
.set_param_desc(PortParamDesc())
1045 elif isinstance(other
, PortRef
):
1046 if other
.peer
is not self
:
1050 "assigning non-port reference '%s' to port '%s'" \
1053 def clone(self
, simobj
, memo
):
1054 if memo
.has_key(self
):
1056 newRef
= copy
.copy(self
)
1058 newRef
.simobj
= simobj
1059 assert(isSimObject(newRef
.simobj
))
1060 if self
.peer
and not proxy
.isproxy(self
.peer
):
1061 peerObj
= self
.peer
.simobj(_memo
=memo
)
1062 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1063 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1066 def unproxy(self
, simobj
):
1067 assert(simobj
is self
.simobj
)
1068 if proxy
.isproxy(self
.peer
):
1070 realPeer
= self
.peer
.unproxy(self
.simobj
)
1072 print "Error in unproxying port '%s' of %s" % \
1073 (self
.name
, self
.simobj
.path())
1075 self
.connect(realPeer
)
1077 # Call C++ to create corresponding port connection between C++ objects
1078 def ccConnect(self
):
1079 from m5
.objects
.params
import connectPorts
1081 if self
.ccConnected
: # already done this
1084 if not self
.peer
: # nothing to connect to
1087 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1088 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1090 print "Error connecting port %s.%s to %s.%s" % \
1091 (self
.simobj
.path(), self
.name
,
1092 peer
.simobj
.path(), peer
.name
)
1094 self
.ccConnected
= True
1095 peer
.ccConnected
= True
1097 # A reference to an individual element of a VectorPort... much like a
1098 # PortRef, but has an index.
1099 class VectorPortElementRef(PortRef
):
1100 def __init__(self
, simobj
, name
, index
):
1101 PortRef
.__init
__(self
, simobj
, name
)
1105 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1107 # A reference to a complete vector-valued port (not just a single element).
1108 # Can be indexed to retrieve individual VectorPortElementRef instances.
1109 class VectorPortRef(object):
1110 def __init__(self
, simobj
, name
):
1111 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1112 self
.simobj
= simobj
1117 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1119 # for config.ini, print peer's name (not ours)
1121 return ' '.join([el
.ini_str() for el
in self
.elements
])
1123 def __getitem__(self
, key
):
1124 if not isinstance(key
, int):
1125 raise TypeError, "VectorPort index must be integer"
1126 if key
>= len(self
.elements
):
1127 # need to extend list
1128 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1129 for i
in range(len(self
.elements
), key
+1)]
1130 self
.elements
.extend(ext
)
1131 return self
.elements
[key
]
1133 def _get_next(self
):
1134 return self
[len(self
.elements
)]
1136 def __setitem__(self
, key
, value
):
1137 if not isinstance(key
, int):
1138 raise TypeError, "VectorPort index must be integer"
1139 self
[key
].connect(value
)
1141 def connect(self
, other
):
1142 if isinstance(other
, (list, tuple)):
1143 # Assign list of port refs to vector port.
1144 # For now, append them... not sure if that's the right semantics
1145 # or if it should replace the current vector.
1147 self
._get
_next
().connect(ref
)
1149 # scalar assignment to plain VectorPort is implicit append
1150 self
._get
_next
().connect(other
)
1152 def clone(self
, simobj
, memo
):
1153 if memo
.has_key(self
):
1155 newRef
= copy
.copy(self
)
1157 newRef
.simobj
= simobj
1158 assert(isSimObject(newRef
.simobj
))
1159 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1162 def unproxy(self
, simobj
):
1163 [el
.unproxy(simobj
) for el
in self
.elements
]
1165 def ccConnect(self
):
1166 [el
.ccConnect() for el
in self
.elements
]
1168 # Port description object. Like a ParamDesc object, this represents a
1169 # logical port in the SimObject class, not a particular port on a
1170 # SimObject instance. The latter are represented by PortRef objects.
1172 # Port("description") or Port(default, "description")
1173 def __init__(self
, *args
):
1176 elif len(args
) == 2:
1177 self
.default
= args
[0]
1180 raise TypeError, 'wrong number of arguments'
1181 # self.name is set by SimObject class on assignment
1182 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1184 # Generate a PortRef for this port on the given SimObject with the
1186 def makeRef(self
, simobj
):
1187 return PortRef(simobj
, self
.name
)
1189 # Connect an instance of this port (on the given SimObject with
1190 # the given name) with the port described by the supplied PortRef
1191 def connect(self
, simobj
, ref
):
1192 self
.makeRef(simobj
).connect(ref
)
1194 # VectorPort description object. Like Port, but represents a vector
1195 # of connections (e.g., as on a Bus).
1196 class VectorPort(Port
):
1197 def __init__(self
, *args
):
1198 Port
.__init
__(self
, *args
)
1201 def makeRef(self
, simobj
):
1202 return VectorPortRef(simobj
, self
.name
)
1204 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1205 # proxy objects (via set_param_desc()) so that proxy error messages
1207 class PortParamDesc(object):
1208 __metaclass__
= Singleton
1213 baseEnums
= allEnums
.copy()
1214 baseParams
= allParams
.copy()
1217 global allEnums
, allParams
1219 allEnums
= baseEnums
.copy()
1220 allParams
= baseParams
.copy()
1222 __all__
= ['Param', 'VectorParam',
1223 'Enum', 'Bool', 'String', 'Float',
1224 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1225 'Int32', 'UInt32', 'Int64', 'UInt64',
1226 'Counter', 'Addr', 'Tick', 'Percent',
1227 'TcpPort', 'UdpPort', 'EthernetAddr',
1228 'MemorySize', 'MemorySize32',
1229 'Latency', 'Frequency', 'Clock',
1230 'NetworkBandwidth', 'MemoryBandwidth',
1231 'Range', 'AddrRange', 'TickRange',
1232 'MaxAddr', 'MaxTick', 'AllMemory',
1234 'NextEthernetAddr', 'NULL',
1235 'Port', 'VectorPort']