1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Steve Reinhardt
30 #####################################################################
32 # Parameter description classes
34 # The _params dictionary in each class maps parameter names to either
35 # a Param or a VectorParam object. These objects contain the
36 # parameter description string, the parameter type, and the default
37 # value (if any). The convert() method on these objects is used to
38 # force whatever value is assigned to the parameter to the appropriate
41 # Note that the default values are loaded into the class's attribute
42 # space when the parameter dictionary is initialized (in
43 # MetaSimObject._new_param()); after that point they aren't used.
45 #####################################################################
60 def isSimObject(*args
, **kwargs
):
61 return SimObject
.isSimObject(*args
, **kwargs
)
63 def isSimObjectSequence(*args
, **kwargs
):
64 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
66 def isSimObjectClass(*args
, **kwargs
):
67 return SimObject
.isSimObjectClass(*args
, **kwargs
)
71 class MetaParamValue(type):
72 def __new__(mcls
, name
, bases
, dct
):
73 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
74 assert name
not in allParams
79 # Dummy base class to identify types that are legitimate for SimObject
81 class ParamValue(object):
82 __metaclass__
= MetaParamValue
87 # default for printing to .ini file is regular string conversion.
88 # will be overridden in some cases
92 # allows us to blithely call unproxy() on things without checking
93 # if they're really proxies or not
94 def unproxy(self
, base
):
97 # Regular parameter description.
98 class ParamDesc(object):
99 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
100 self
.ptype_str
= ptype_str
101 # remember ptype only if it is provided
109 self
.default
= args
[0]
112 raise TypeError, 'too many arguments'
114 if kwargs
.has_key('desc'):
115 assert(not hasattr(self
, 'desc'))
116 self
.desc
= kwargs
['desc']
119 if kwargs
.has_key('default'):
120 assert(not hasattr(self
, 'default'))
121 self
.default
= kwargs
['default']
122 del kwargs
['default']
125 raise TypeError, 'extra unknown kwargs %s' % kwargs
127 if not hasattr(self
, 'desc'):
128 raise TypeError, 'desc attribute missing'
130 def __getattr__(self
, attr
):
132 ptype
= SimObject
.allClasses
[self
.ptype_str
]
133 assert issubclass(ptype
, SimObject
.SimObject
)
137 raise AttributeError, "'%s' object has no attribute '%s'" % \
138 (type(self
).__name
__, attr
)
140 def convert(self
, value
):
141 if isinstance(value
, proxy
.BaseProxy
):
142 value
.set_param_desc(self
)
144 if not hasattr(self
, 'ptype') and isNullPointer(value
):
145 # deferred evaluation of SimObject; continue to defer if
146 # we're just assigning a null pointer
148 if isinstance(value
, self
.ptype
):
150 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
152 return self
.ptype(value
)
154 def cxx_predecls(self
):
155 return self
.ptype
.cxx_predecls
157 def swig_predecls(self
):
158 return self
.ptype
.swig_predecls
161 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
163 # Vector-valued parameter description. Just like ParamDesc, except
164 # that the value is a vector (list) of the specified type instead of a
167 class VectorParamValue(list):
168 __metaclass__
= MetaParamValue
169 def __setattr__(self
, attr
, value
):
170 raise AttributeError, \
171 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
174 return ' '.join([v
.ini_str() for v
in self
])
177 return [ v
.getValue() for v
in self
]
179 def unproxy(self
, base
):
180 return [v
.unproxy(base
) for v
in self
]
182 class SimObjVector(VectorParamValue
):
183 def print_ini(self
, ini_file
):
185 v
.print_ini(ini_file
)
187 class VectorParamDesc(ParamDesc
):
188 # Convert assigned value to appropriate type. If the RHS is not a
189 # list or tuple, it generates a single-element list.
190 def convert(self
, value
):
191 if isinstance(value
, (list, tuple)):
192 # list: coerce each element into new list
193 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
195 # singleton: coerce to a single-element list
196 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
198 if isSimObjectSequence(tmp_list
):
199 return SimObjVector(tmp_list
)
201 return VectorParamValue(tmp_list
)
203 def swig_predecls(self
):
204 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
207 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
208 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
209 (self
.ptype_str
, cxx_type
)
210 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
212 def cxx_predecls(self
):
213 return ['#include <vector>'] + self
.ptype
.cxx_predecls
216 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
218 class ParamFactory(object):
219 def __init__(self
, param_desc_class
, ptype_str
= None):
220 self
.param_desc_class
= param_desc_class
221 self
.ptype_str
= ptype_str
223 def __getattr__(self
, attr
):
225 attr
= self
.ptype_str
+ '.' + attr
226 return ParamFactory(self
.param_desc_class
, attr
)
228 # E.g., Param.Int(5, "number of widgets")
229 def __call__(self
, *args
, **kwargs
):
232 ptype
= allParams
[self
.ptype_str
]
234 # if name isn't defined yet, assume it's a SimObject, and
235 # try to resolve it later
237 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
239 Param
= ParamFactory(ParamDesc
)
240 VectorParam
= ParamFactory(VectorParamDesc
)
242 #####################################################################
246 # Though native Python types could be used to specify parameter types
247 # (the 'ptype' field of the Param and VectorParam classes), it's more
248 # flexible to define our own set of types. This gives us more control
249 # over how Python expressions are converted to values (via the
250 # __init__() constructor) and how these values are printed out (via
251 # the __str__() conversion method).
253 #####################################################################
255 # String-valued parameter. Just mixin the ParamValue class with the
256 # built-in str class.
257 class String(ParamValue
,str):
258 cxx_type
= 'std::string'
259 cxx_predecls
= ['#include <string>']
260 swig_predecls
= ['%include "std_string.i"\n' +
261 '%apply const std::string& {std::string *};']
262 swig_predecls
= ['%include "std_string.i"' ]
267 # superclass for "numeric" parameter values, to emulate math
268 # operations in a type-safe way. e.g., a Latency times an int returns
269 # a new Latency object.
270 class NumericParamValue(ParamValue
):
272 return str(self
.value
)
275 return float(self
.value
)
278 return long(self
.value
)
281 return int(self
.value
)
283 # hook for bounds checking
287 def __mul__(self
, other
):
288 newobj
= self
.__class
__(self
)
289 newobj
.value
*= other
295 def __div__(self
, other
):
296 newobj
= self
.__class
__(self
)
297 newobj
.value
/= other
301 def __sub__(self
, other
):
302 newobj
= self
.__class
__(self
)
303 newobj
.value
-= other
307 # Metaclass for bounds-checked integer parameters. See CheckedInt.
308 class CheckedIntType(MetaParamValue
):
309 def __init__(cls
, name
, bases
, dict):
310 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
312 # CheckedInt is an abstract base class, so we actually don't
313 # want to do any processing on it... the rest of this code is
314 # just for classes that derive from CheckedInt.
315 if name
== 'CheckedInt':
318 if not cls
.cxx_predecls
:
319 # most derived types require this, so we just do it here once
320 cls
.cxx_predecls
= ['#include "sim/host.hh"']
322 if not cls
.swig_predecls
:
323 # most derived types require this, so we just do it here once
324 cls
.swig_predecls
= ['%import "stdint.i"\n' +
325 '%import "sim/host.hh"']
327 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
328 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
329 panic("CheckedInt subclass %s must define either\n" \
330 " 'min' and 'max' or 'size' and 'unsigned'\n" \
334 cls
.max = 2 ** cls
.size
- 1
336 cls
.min = -(2 ** (cls
.size
- 1))
337 cls
.max = (2 ** (cls
.size
- 1)) - 1
339 # Abstract superclass for bounds-checked integer parameters. This
340 # class is subclassed to generate parameter classes with specific
341 # bounds. Initialization of the min and max bounds is done in the
342 # metaclass CheckedIntType.__init__.
343 class CheckedInt(NumericParamValue
):
344 __metaclass__
= CheckedIntType
347 if not self
.min <= self
.value
<= self
.max:
348 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
349 (self
.min, self
.value
, self
.max)
351 def __init__(self
, value
):
352 if isinstance(value
, str):
353 self
.value
= convert
.toInteger(value
)
354 elif isinstance(value
, (int, long, float, NumericParamValue
)):
355 self
.value
= long(value
)
357 raise TypeError, "Can't convert object of type %s to CheckedInt" \
358 % type(value
).__name
__
362 return long(self
.value
)
364 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
365 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
367 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
368 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
369 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
370 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
371 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
372 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
373 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
374 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
376 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
377 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
378 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
379 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
381 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
383 class Float(ParamValue
, float):
386 def __init__(self
, value
):
387 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
388 self
.value
= float(value
)
390 raise TypeError, "Can't convert object of type %s to Float" \
391 % type(value
).__name
__
394 return float(self
.value
)
396 class MemorySize(CheckedInt
):
397 cxx_type
= 'uint64_t'
400 def __init__(self
, value
):
401 if isinstance(value
, MemorySize
):
402 self
.value
= value
.value
404 self
.value
= convert
.toMemorySize(value
)
407 class MemorySize32(CheckedInt
):
408 cxx_type
= 'uint32_t'
411 def __init__(self
, value
):
412 if isinstance(value
, MemorySize
):
413 self
.value
= value
.value
415 self
.value
= convert
.toMemorySize(value
)
418 class Addr(CheckedInt
):
422 def __init__(self
, value
):
423 if isinstance(value
, Addr
):
424 self
.value
= value
.value
427 self
.value
= convert
.toMemorySize(value
)
429 self
.value
= long(value
)
431 def __add__(self
, other
):
432 if isinstance(other
, Addr
):
433 return self
.value
+ other
.value
435 return self
.value
+ other
438 class MetaRange(MetaParamValue
):
439 def __init__(cls
, name
, bases
, dict):
440 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
443 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
445 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
447 class Range(ParamValue
):
448 __metaclass__
= MetaRange
449 type = Int
# default; can be overridden in subclasses
450 def __init__(self
, *args
, **kwargs
):
451 def handle_kwargs(self
, kwargs
):
453 self
.second
= self
.type(kwargs
.pop('end'))
454 elif 'size' in kwargs
:
455 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
457 raise TypeError, "Either end or size must be specified"
460 self
.first
= self
.type(kwargs
.pop('start'))
461 handle_kwargs(self
, kwargs
)
465 self
.first
= self
.type(args
[0])
466 handle_kwargs(self
, kwargs
)
467 elif isinstance(args
[0], Range
):
468 self
.first
= self
.type(args
[0].first
)
469 self
.second
= self
.type(args
[0].second
)
470 elif isinstance(args
[0], (list, tuple)):
471 self
.first
= self
.type(args
[0][0])
472 self
.second
= self
.type(args
[0][1])
474 self
.first
= self
.type(0)
475 self
.second
= self
.type(args
[0]) - 1
478 self
.first
= self
.type(args
[0])
479 self
.second
= self
.type(args
[1])
481 raise TypeError, "Too many arguments specified"
484 raise TypeError, "too many keywords: %s" % kwargs
.keys()
487 return '%s:%s' % (self
.first
, self
.second
)
489 class AddrRange(Range
):
491 swig_predecls
= ['%include "python/swig/range.i"']
494 from m5
.objects
.params
import AddrRange
497 value
.start
= long(self
.first
)
498 value
.end
= long(self
.second
)
501 class TickRange(Range
):
503 swig_predecls
= ['%include "python/swig/range.i"']
506 from m5
.objects
.params
import TickRange
509 value
.start
= long(self
.first
)
510 value
.end
= long(self
.second
)
513 # Boolean parameter type. Python doesn't let you subclass bool, since
514 # it doesn't want to let you create multiple instances of True and
515 # False. Thus this is a little more complicated than String.
516 class Bool(ParamValue
):
518 def __init__(self
, value
):
520 self
.value
= convert
.toBool(value
)
522 self
.value
= bool(value
)
525 return bool(self
.value
)
528 return str(self
.value
)
535 def IncEthernetAddr(addr
, val
= 1):
536 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
538 for i
in (5, 4, 3, 2, 1):
539 val
,rem
= divmod(bytes
[i
], 256)
544 assert(bytes
[0] <= 255)
545 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
547 _NextEthernetAddr
= "00:90:00:00:00:01"
548 def NextEthernetAddr():
549 global _NextEthernetAddr
551 value
= _NextEthernetAddr
552 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
555 class EthernetAddr(ParamValue
):
556 cxx_type
= 'Net::EthAddr'
557 cxx_predecls
= ['#include "base/inet.hh"']
558 swig_predecls
= ['%include "python/swig/inet.i"']
559 def __init__(self
, value
):
560 if value
== NextEthernetAddr
:
564 if not isinstance(value
, str):
565 raise TypeError, "expected an ethernet address and didn't get one"
567 bytes
= value
.split(':')
569 raise TypeError, 'invalid ethernet address %s' % value
572 if not 0 <= int(byte
) <= 256:
573 raise TypeError, 'invalid ethernet address %s' % value
577 def unproxy(self
, base
):
578 if self
.value
== NextEthernetAddr
:
579 return EthernetAddr(self
.value())
583 from m5
.objects
.params
import EthAddr
584 return EthAddr(self
.value
)
589 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
590 "%a %b %d %H:%M:%S %Z %Y",
602 def parse_time(value
):
603 from time
import gmtime
, strptime
, struct_time
, time
604 from datetime
import datetime
, date
606 if isinstance(value
, struct_time
):
609 if isinstance(value
, (int, long)):
612 if isinstance(value
, (datetime
, date
)):
613 return value
.timetuple()
615 if isinstance(value
, str):
616 if value
in ('Now', 'Today'):
617 return time
.gmtime(time
.time())
619 for format
in time_formats
:
621 return strptime(value
, format
)
625 raise ValueError, "Could not parse '%s' as a time" % value
627 class Time(ParamValue
):
629 cxx_predecls
= [ '#include <time.h>' ]
630 swig_predecls
= [ '%include "python/swig/time.i"' ]
631 def __init__(self
, value
):
632 self
.value
= parse_time(value
)
635 from m5
.objects
.params
import tm
640 # UNIX is years since 1900
641 c_time
.tm_year
= py_time
.tm_year
- 1900;
643 # Python starts at 1, UNIX starts at 0
644 c_time
.tm_mon
= py_time
.tm_mon
- 1;
645 c_time
.tm_mday
= py_time
.tm_mday
;
646 c_time
.tm_hour
= py_time
.tm_hour
;
647 c_time
.tm_min
= py_time
.tm_min
;
648 c_time
.tm_sec
= py_time
.tm_sec
;
650 # Python has 0 as Monday, UNIX is 0 as sunday
651 c_time
.tm_wday
= py_time
.tm_wday
+ 1
652 if c_time
.tm_wday
> 6:
655 # Python starts at 1, Unix starts at 0
656 c_time
.tm_yday
= py_time
.tm_yday
- 1;
661 return time
.asctime(self
.value
)
666 # Enumerated types are a little more complex. The user specifies the
667 # type as Enum(foo) where foo is either a list or dictionary of
668 # alternatives (typically strings, but not necessarily so). (In the
669 # long run, the integer value of the parameter will be the list index
670 # or the corresponding dictionary value. For now, since we only check
671 # that the alternative is valid and then spit it into a .ini file,
672 # there's not much point in using the dictionary.)
674 # What Enum() must do is generate a new type encapsulating the
675 # provided list/dictionary so that specific values of the parameter
676 # can be instances of that type. We define two hidden internal
677 # classes (_ListEnum and _DictEnum) to serve as base classes, then
678 # derive the new type from the appropriate base class on the fly.
681 # Metaclass for Enum types
682 class MetaEnum(MetaParamValue
):
683 def __new__(mcls
, name
, bases
, dict):
684 assert name
not in allEnums
686 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
690 def __init__(cls
, name
, bases
, init_dict
):
691 if init_dict
.has_key('map'):
692 if not isinstance(cls
.map, dict):
693 raise TypeError, "Enum-derived class attribute 'map' " \
694 "must be of type dict"
695 # build list of value strings from map
696 cls
.vals
= cls
.map.keys()
698 elif init_dict
.has_key('vals'):
699 if not isinstance(cls
.vals
, list):
700 raise TypeError, "Enum-derived class attribute 'vals' " \
701 "must be of type list"
702 # build string->value map from vals sequence
704 for idx
,val
in enumerate(cls
.vals
):
707 raise TypeError, "Enum-derived class must define "\
708 "attribute 'map' or 'vals'"
710 cls
.cxx_type
= 'Enums::%s' % name
712 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
717 # Generate C++ class declaration for this enum type.
718 # Note that we wrap the enum in a class/struct to act as a namespace,
719 # so that the enum strings can be brief w/o worrying about collisions.
721 code
= "#ifndef __ENUM__%s\n" % cls
722 code
+= '#define __ENUM__%s\n' % cls
724 code
+= 'namespace Enums {\n'
725 code
+= ' enum %s {\n' % cls
727 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
728 code
+= ' Num_%s = %d,\n' % (cls
, len(cls
.vals
))
730 code
+= ' extern const char *%sStrings[Num_%s];\n' % (cls
, cls
)
737 code
= '#include "enums/%s.hh"\n' % cls
738 code
+= 'namespace Enums {\n'
739 code
+= ' const char *%sStrings[Num_%s] =\n' % (cls
, cls
)
742 code
+= ' "%s",\n' % val
747 # Base class for enum types.
748 class Enum(ParamValue
):
749 __metaclass__
= MetaEnum
752 def __init__(self
, value
):
753 if value
not in self
.map:
754 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
759 return int(self
.map[self
.value
])
764 # how big does a rounding error need to be before we warn about it?
765 frequency_tolerance
= 0.001 # 0.1%
767 class TickParamValue(NumericParamValue
):
769 cxx_predecls
= ['#include "sim/host.hh"']
770 swig_predecls
= ['%import "stdint.i"\n' +
771 '%import "sim/host.hh"']
774 return long(self
.value
)
776 class Latency(TickParamValue
):
777 def __init__(self
, value
):
778 if isinstance(value
, (Latency
, Clock
)):
779 self
.ticks
= value
.ticks
780 self
.value
= value
.value
781 elif isinstance(value
, Frequency
):
782 self
.ticks
= value
.ticks
783 self
.value
= 1.0 / value
.value
784 elif value
.endswith('t'):
786 self
.value
= int(value
[:-1])
789 self
.value
= convert
.toLatency(value
)
791 def __getattr__(self
, attr
):
792 if attr
in ('latency', 'period'):
794 if attr
== 'frequency':
795 return Frequency(self
)
796 raise AttributeError, "Latency object has no attribute '%s'" % attr
799 if self
.ticks
or self
.value
== 0:
802 value
= ticks
.fromSeconds(self
.value
)
805 # convert latency to ticks
807 return '%d' % self
.getValue()
809 class Frequency(TickParamValue
):
810 def __init__(self
, value
):
811 if isinstance(value
, (Latency
, Clock
)):
815 self
.value
= 1.0 / value
.value
816 self
.ticks
= value
.ticks
817 elif isinstance(value
, Frequency
):
818 self
.value
= value
.value
819 self
.ticks
= value
.ticks
822 self
.value
= convert
.toFrequency(value
)
824 def __getattr__(self
, attr
):
825 if attr
== 'frequency':
827 if attr
in ('latency', 'period'):
829 raise AttributeError, "Frequency object has no attribute '%s'" % attr
831 # convert latency to ticks
833 if self
.ticks
or self
.value
== 0:
836 value
= ticks
.fromSeconds(1.0 / self
.value
)
840 return '%d' % self
.getValue()
842 # A generic frequency and/or Latency value. Value is stored as a latency,
843 # but to avoid ambiguity this object does not support numeric ops (* or /).
844 # An explicit conversion to a Latency or Frequency must be made first.
845 class Clock(ParamValue
):
847 cxx_predecls
= ['#include "sim/host.hh"']
848 swig_predecls
= ['%import "stdint.i"\n' +
849 '%import "sim/host.hh"']
850 def __init__(self
, value
):
851 if isinstance(value
, (Latency
, Clock
)):
852 self
.ticks
= value
.ticks
853 self
.value
= value
.value
854 elif isinstance(value
, Frequency
):
855 self
.ticks
= value
.ticks
856 self
.value
= 1.0 / value
.value
857 elif value
.endswith('t'):
859 self
.value
= int(value
[:-1])
862 self
.value
= convert
.anyToLatency(value
)
864 def __getattr__(self
, attr
):
865 if attr
== 'frequency':
866 return Frequency(self
)
867 if attr
in ('latency', 'period'):
869 raise AttributeError, "Frequency object has no attribute '%s'" % attr
872 return self
.period
.getValue()
875 return self
.period
.ini_str()
877 class NetworkBandwidth(float,ParamValue
):
879 def __new__(cls
, value
):
880 # convert to bits per second
881 val
= convert
.toNetworkBandwidth(value
)
882 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
888 # convert to seconds per byte
889 value
= 8.0 / float(self
)
890 # convert to ticks per byte
891 value
= ticks
.fromSeconds(value
)
895 return '%f' % self
.getValue()
897 class MemoryBandwidth(float,ParamValue
):
899 def __new__(cls
, value
):
900 # we want the number of ticks per byte of data
901 val
= convert
.toMemoryBandwidth(value
)
902 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
908 # convert to seconds per byte
911 value
= 1.0 / float(self
)
912 # convert to ticks per byte
913 value
= ticks
.fromSeconds(value
)
917 return '%f' % self
.getValue()
920 # "Constants"... handy aliases for various values.
923 # Special class for NULL pointers. Note the special check in
924 # make_param_value() above that lets these be assigned where a
925 # SimObject is required.
926 # only one copy of a particular node
927 class NullSimObject(object):
928 __metaclass__
= Singleton
933 def _instantiate(self
, parent
= None, path
= ''):
939 def unproxy(self
, base
):
942 def set_path(self
, parent
, name
):
951 # The only instance you'll ever need...
952 NULL
= NullSimObject()
954 def isNullPointer(value
):
955 return isinstance(value
, NullSimObject
)
957 # Some memory range specifications use this as a default upper bound.
960 AllMemory
= AddrRange(0, MaxAddr
)
963 #####################################################################
967 # Ports are used to interconnect objects in the memory system.
969 #####################################################################
971 # Port reference: encapsulates a reference to a particular port on a
972 # particular SimObject.
973 class PortRef(object):
974 def __init__(self
, simobj
, name
):
975 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
978 self
.peer
= None # not associated with another port yet
979 self
.ccConnected
= False # C++ port connection done?
980 self
.index
= -1 # always -1 for non-vector ports
983 return '%s.%s' % (self
.simobj
, self
.name
)
985 # for config.ini, print peer's name (not ours)
987 return str(self
.peer
)
989 def __getattr__(self
, attr
):
990 if attr
== 'peerObj':
991 # shorthand for proxies
992 return self
.peer
.simobj
993 raise AttributeError, "'%s' object has no attribute '%s'" % \
994 (self
.__class
__.__name
__, attr
)
996 # Full connection is symmetric (both ways). Called via
997 # SimObject.__setattr__ as a result of a port assignment, e.g.,
998 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
999 # e.g., "obj1.portA[3] = obj2.portB".
1000 def connect(self
, other
):
1001 if isinstance(other
, VectorPortRef
):
1002 # reference to plain VectorPort is implicit append
1003 other
= other
._get
_next
()
1004 if self
.peer
and not proxy
.isproxy(self
.peer
):
1005 print "warning: overwriting port", self
, \
1006 "value", self
.peer
, "with", other
1008 if proxy
.isproxy(other
):
1009 other
.set_param_desc(PortParamDesc())
1010 elif isinstance(other
, PortRef
):
1011 if other
.peer
is not self
:
1015 "assigning non-port reference '%s' to port '%s'" \
1018 def clone(self
, simobj
, memo
):
1019 if memo
.has_key(self
):
1021 newRef
= copy
.copy(self
)
1023 newRef
.simobj
= simobj
1024 assert(isSimObject(newRef
.simobj
))
1025 if self
.peer
and not proxy
.isproxy(self
.peer
):
1026 peerObj
= self
.peer
.simobj(_memo
=memo
)
1027 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1028 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1031 def unproxy(self
, simobj
):
1032 assert(simobj
is self
.simobj
)
1033 if proxy
.isproxy(self
.peer
):
1035 realPeer
= self
.peer
.unproxy(self
.simobj
)
1037 print "Error in unproxying port '%s' of %s" % \
1038 (self
.name
, self
.simobj
.path())
1040 self
.connect(realPeer
)
1042 # Call C++ to create corresponding port connection between C++ objects
1043 def ccConnect(self
):
1044 from m5
.objects
.params
import connectPorts
1046 if self
.ccConnected
: # already done this
1049 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1050 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1051 self
.ccConnected
= True
1052 peer
.ccConnected
= True
1054 # A reference to an individual element of a VectorPort... much like a
1055 # PortRef, but has an index.
1056 class VectorPortElementRef(PortRef
):
1057 def __init__(self
, simobj
, name
, index
):
1058 PortRef
.__init
__(self
, simobj
, name
)
1062 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1064 # A reference to a complete vector-valued port (not just a single element).
1065 # Can be indexed to retrieve individual VectorPortElementRef instances.
1066 class VectorPortRef(object):
1067 def __init__(self
, simobj
, name
):
1068 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1069 self
.simobj
= simobj
1074 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1076 # for config.ini, print peer's name (not ours)
1078 return ' '.join([el
.ini_str() for el
in self
.elements
])
1080 def __getitem__(self
, key
):
1081 if not isinstance(key
, int):
1082 raise TypeError, "VectorPort index must be integer"
1083 if key
>= len(self
.elements
):
1084 # need to extend list
1085 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1086 for i
in range(len(self
.elements
), key
+1)]
1087 self
.elements
.extend(ext
)
1088 return self
.elements
[key
]
1090 def _get_next(self
):
1091 return self
[len(self
.elements
)]
1093 def __setitem__(self
, key
, value
):
1094 if not isinstance(key
, int):
1095 raise TypeError, "VectorPort index must be integer"
1096 self
[key
].connect(value
)
1098 def connect(self
, other
):
1099 if isinstance(other
, (list, tuple)):
1100 # Assign list of port refs to vector port.
1101 # For now, append them... not sure if that's the right semantics
1102 # or if it should replace the current vector.
1104 self
._get
_next
().connect(ref
)
1106 # scalar assignment to plain VectorPort is implicit append
1107 self
._get
_next
().connect(other
)
1109 def clone(self
, simobj
, memo
):
1110 if memo
.has_key(self
):
1112 newRef
= copy
.copy(self
)
1114 newRef
.simobj
= simobj
1115 assert(isSimObject(newRef
.simobj
))
1116 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1119 def unproxy(self
, simobj
):
1120 [el
.unproxy(simobj
) for el
in self
.elements
]
1122 def ccConnect(self
):
1123 [el
.ccConnect() for el
in self
.elements
]
1125 # Port description object. Like a ParamDesc object, this represents a
1126 # logical port in the SimObject class, not a particular port on a
1127 # SimObject instance. The latter are represented by PortRef objects.
1129 # Port("description") or Port(default, "description")
1130 def __init__(self
, *args
):
1133 elif len(args
) == 2:
1134 self
.default
= args
[0]
1137 raise TypeError, 'wrong number of arguments'
1138 # self.name is set by SimObject class on assignment
1139 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1141 # Generate a PortRef for this port on the given SimObject with the
1143 def makeRef(self
, simobj
):
1144 return PortRef(simobj
, self
.name
)
1146 # Connect an instance of this port (on the given SimObject with
1147 # the given name) with the port described by the supplied PortRef
1148 def connect(self
, simobj
, ref
):
1149 self
.makeRef(simobj
).connect(ref
)
1151 # VectorPort description object. Like Port, but represents a vector
1152 # of connections (e.g., as on a Bus).
1153 class VectorPort(Port
):
1154 def __init__(self
, *args
):
1155 Port
.__init
__(self
, *args
)
1158 def makeRef(self
, simobj
):
1159 return VectorPortRef(simobj
, self
.name
)
1161 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1162 # proxy objects (via set_param_desc()) so that proxy error messages
1164 class PortParamDesc(object):
1165 __metaclass__
= Singleton
1170 __all__
= ['Param', 'VectorParam',
1171 'Enum', 'Bool', 'String', 'Float',
1172 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1173 'Int32', 'UInt32', 'Int64', 'UInt64',
1174 'Counter', 'Addr', 'Tick', 'Percent',
1175 'TcpPort', 'UdpPort', 'EthernetAddr',
1176 'MemorySize', 'MemorySize32',
1177 'Latency', 'Frequency', 'Clock',
1178 'NetworkBandwidth', 'MemoryBandwidth',
1179 'Range', 'AddrRange', 'TickRange',
1180 'MaxAddr', 'MaxTick', 'AllMemory',
1182 'NextEthernetAddr', 'NULL',
1183 'Port', 'VectorPort']