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 #####################################################################
61 def isSimObject(*args
, **kwargs
):
62 return SimObject
.isSimObject(*args
, **kwargs
)
64 def isSimObjectSequence(*args
, **kwargs
):
65 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
67 def isSimObjectClass(*args
, **kwargs
):
68 return SimObject
.isSimObjectClass(*args
, **kwargs
)
70 # Dummy base class to identify types that are legitimate for SimObject
72 class ParamValue(object):
77 # default for printing to .ini file is regular string conversion.
78 # will be overridden in some cases
82 # allows us to blithely call unproxy() on things without checking
83 # if they're really proxies or not
84 def unproxy(self
, base
):
87 # Regular parameter description.
88 class ParamDesc(object):
89 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
90 self
.ptype_str
= ptype_str
91 # remember ptype only if it is provided
99 self
.default
= args
[0]
102 raise TypeError, 'too many arguments'
104 if kwargs
.has_key('desc'):
105 assert(not hasattr(self
, 'desc'))
106 self
.desc
= kwargs
['desc']
109 if kwargs
.has_key('default'):
110 assert(not hasattr(self
, 'default'))
111 self
.default
= kwargs
['default']
112 del kwargs
['default']
115 raise TypeError, 'extra unknown kwargs %s' % kwargs
117 if not hasattr(self
, 'desc'):
118 raise TypeError, 'desc attribute missing'
120 def __getattr__(self
, attr
):
123 ptype
= SimObject
.allClasses
[self
.ptype_str
]
124 if not isinstance(ptype
, type):
131 # "Param qualifier '%s' is not a type" % self.ptype_str
132 raise AttributeError, "'%s' object has no attribute '%s'" % \
133 (type(self
).__name
__, attr
)
135 def convert(self
, value
):
136 if isinstance(value
, proxy
.BaseProxy
):
137 value
.set_param_desc(self
)
139 if not hasattr(self
, 'ptype') and isNullPointer(value
):
140 # deferred evaluation of SimObject; continue to defer if
141 # we're just assigning a null pointer
143 if isinstance(value
, self
.ptype
):
145 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
147 return self
.ptype(value
)
149 def cxx_predecls(self
):
150 return self
.ptype
.cxx_predecls
152 def swig_predecls(self
):
153 return self
.ptype
.swig_predecls
156 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
158 # Vector-valued parameter description. Just like ParamDesc, except
159 # that the value is a vector (list) of the specified type instead of a
162 class VectorParamValue(list):
164 return ' '.join([v
.ini_str() for v
in self
])
167 return [ v
.getValue() for v
in self
]
169 def unproxy(self
, base
):
170 return [v
.unproxy(base
) for v
in self
]
172 class SimObjVector(VectorParamValue
):
177 class VectorParamDesc(ParamDesc
):
178 # Convert assigned value to appropriate type. If the RHS is not a
179 # list or tuple, it generates a single-element list.
180 def convert(self
, value
):
181 if isinstance(value
, (list, tuple)):
182 # list: coerce each element into new list
183 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
185 # singleton: coerce to a single-element list
186 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
188 if isSimObjectSequence(tmp_list
):
189 return SimObjVector(tmp_list
)
191 return VectorParamValue(tmp_list
)
193 def swig_predecls(self
):
194 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
197 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
198 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
199 (self
.ptype_str
, cxx_type
)
200 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
202 def cxx_predecls(self
):
203 return ['#include <vector>'] + self
.ptype
.cxx_predecls
206 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
208 class ParamFactory(object):
209 def __init__(self
, param_desc_class
, ptype_str
= None):
210 self
.param_desc_class
= param_desc_class
211 self
.ptype_str
= ptype_str
213 def __getattr__(self
, attr
):
215 attr
= self
.ptype_str
+ '.' + attr
216 return ParamFactory(self
.param_desc_class
, attr
)
218 # E.g., Param.Int(5, "number of widgets")
219 def __call__(self
, *args
, **kwargs
):
220 caller_frame
= inspect
.currentframe().f_back
223 ptype
= eval(self
.ptype_str
,
224 caller_frame
.f_globals
, caller_frame
.f_locals
)
225 if not isinstance(ptype
, type):
227 "Param qualifier is not a type: %s" % ptype
229 # if name isn't defined yet, assume it's a SimObject, and
230 # try to resolve it later
232 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
234 Param
= ParamFactory(ParamDesc
)
235 VectorParam
= ParamFactory(VectorParamDesc
)
237 #####################################################################
241 # Though native Python types could be used to specify parameter types
242 # (the 'ptype' field of the Param and VectorParam classes), it's more
243 # flexible to define our own set of types. This gives us more control
244 # over how Python expressions are converted to values (via the
245 # __init__() constructor) and how these values are printed out (via
246 # the __str__() conversion method).
248 #####################################################################
250 # String-valued parameter. Just mixin the ParamValue class with the
251 # built-in str class.
252 class String(ParamValue
,str):
253 cxx_type
= 'std::string'
254 cxx_predecls
= ['#include <string>']
255 swig_predecls
= ['%include "std_string.i"\n' +
256 '%apply const std::string& {std::string *};']
257 swig_predecls
= ['%include "std_string.i"' ]
262 # superclass for "numeric" parameter values, to emulate math
263 # operations in a type-safe way. e.g., a Latency times an int returns
264 # a new Latency object.
265 class NumericParamValue(ParamValue
):
267 return str(self
.value
)
270 return float(self
.value
)
273 return long(self
.value
)
276 return int(self
.value
)
278 # hook for bounds checking
282 def __mul__(self
, other
):
283 newobj
= self
.__class
__(self
)
284 newobj
.value
*= other
290 def __div__(self
, other
):
291 newobj
= self
.__class
__(self
)
292 newobj
.value
/= other
296 def __sub__(self
, other
):
297 newobj
= self
.__class
__(self
)
298 newobj
.value
-= other
302 # Metaclass for bounds-checked integer parameters. See CheckedInt.
303 class CheckedIntType(type):
304 def __init__(cls
, name
, bases
, dict):
305 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
307 # CheckedInt is an abstract base class, so we actually don't
308 # want to do any processing on it... the rest of this code is
309 # just for classes that derive from CheckedInt.
310 if name
== 'CheckedInt':
313 if not cls
.cxx_predecls
:
314 # most derived types require this, so we just do it here once
315 cls
.cxx_predecls
= ['#include "sim/host.hh"']
317 if not cls
.swig_predecls
:
318 # most derived types require this, so we just do it here once
319 cls
.swig_predecls
= ['%import "stdint.i"\n' +
320 '%import "sim/host.hh"']
322 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
323 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
324 panic("CheckedInt subclass %s must define either\n" \
325 " 'min' and 'max' or 'size' and 'unsigned'\n" \
329 cls
.max = 2 ** cls
.size
- 1
331 cls
.min = -(2 ** (cls
.size
- 1))
332 cls
.max = (2 ** (cls
.size
- 1)) - 1
334 # Abstract superclass for bounds-checked integer parameters. This
335 # class is subclassed to generate parameter classes with specific
336 # bounds. Initialization of the min and max bounds is done in the
337 # metaclass CheckedIntType.__init__.
338 class CheckedInt(NumericParamValue
):
339 __metaclass__
= CheckedIntType
342 if not self
.min <= self
.value
<= self
.max:
343 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
344 (self
.min, self
.value
, self
.max)
346 def __init__(self
, value
):
347 if isinstance(value
, str):
348 self
.value
= convert
.toInteger(value
)
349 elif isinstance(value
, (int, long, float, NumericParamValue
)):
350 self
.value
= long(value
)
352 raise TypeError, "Can't convert object of type %s to CheckedInt" \
353 % type(value
).__name
__
357 return long(self
.value
)
359 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
360 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
362 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
363 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
364 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
365 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
366 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
367 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
368 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
369 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
371 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
372 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
373 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
374 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
376 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
378 class Float(ParamValue
, float):
382 return float(self
.value
)
384 class MemorySize(CheckedInt
):
385 cxx_type
= 'uint64_t'
388 def __init__(self
, value
):
389 if isinstance(value
, MemorySize
):
390 self
.value
= value
.value
392 self
.value
= convert
.toMemorySize(value
)
395 class MemorySize32(CheckedInt
):
396 cxx_type
= 'uint32_t'
399 def __init__(self
, value
):
400 if isinstance(value
, MemorySize
):
401 self
.value
= value
.value
403 self
.value
= convert
.toMemorySize(value
)
406 class Addr(CheckedInt
):
408 cxx_predecls
= ['#include "arch/isa_traits.hh"']
411 def __init__(self
, value
):
412 if isinstance(value
, Addr
):
413 self
.value
= value
.value
416 self
.value
= convert
.toMemorySize(value
)
418 self
.value
= long(value
)
420 def __add__(self
, other
):
421 if isinstance(other
, Addr
):
422 return self
.value
+ other
.value
424 return self
.value
+ other
427 class MetaRange(type):
428 def __init__(cls
, name
, bases
, dict):
429 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
432 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
434 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
436 class Range(ParamValue
):
437 __metaclass__
= MetaRange
438 type = Int
# default; can be overridden in subclasses
439 def __init__(self
, *args
, **kwargs
):
440 def handle_kwargs(self
, kwargs
):
442 self
.second
= self
.type(kwargs
.pop('end'))
443 elif 'size' in kwargs
:
444 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
446 raise TypeError, "Either end or size must be specified"
449 self
.first
= self
.type(kwargs
.pop('start'))
450 handle_kwargs(self
, kwargs
)
454 self
.first
= self
.type(args
[0])
455 handle_kwargs(self
, kwargs
)
456 elif isinstance(args
[0], Range
):
457 self
.first
= self
.type(args
[0].first
)
458 self
.second
= self
.type(args
[0].second
)
460 self
.first
= self
.type(0)
461 self
.second
= self
.type(args
[0]) - 1
464 self
.first
= self
.type(args
[0])
465 self
.second
= self
.type(args
[1])
467 raise TypeError, "Too many arguments specified"
470 raise TypeError, "too many keywords: %s" % kwargs
.keys()
473 return '%s:%s' % (self
.first
, self
.second
)
475 class AddrRange(Range
):
477 swig_predecls
= ['%include "python/swig/range.i"']
480 from m5
.objects
.params
import AddrRange
483 value
.start
= long(self
.first
)
484 value
.end
= long(self
.second
)
487 class TickRange(Range
):
489 swig_predecls
= ['%include "python/swig/range.i"']
492 from m5
.objects
.params
import TickRange
495 value
.start
= long(self
.first
)
496 value
.end
= long(self
.second
)
499 # Boolean parameter type. Python doesn't let you subclass bool, since
500 # it doesn't want to let you create multiple instances of True and
501 # False. Thus this is a little more complicated than String.
502 class Bool(ParamValue
):
504 def __init__(self
, value
):
506 self
.value
= convert
.toBool(value
)
508 self
.value
= bool(value
)
511 return bool(self
.value
)
514 return str(self
.value
)
521 def IncEthernetAddr(addr
, val
= 1):
522 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
524 for i
in (5, 4, 3, 2, 1):
525 val
,rem
= divmod(bytes
[i
], 256)
530 assert(bytes
[0] <= 255)
531 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
533 _NextEthernetAddr
= "00:90:00:00:00:01"
534 def NextEthernetAddr():
535 global _NextEthernetAddr
537 value
= _NextEthernetAddr
538 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
541 class EthernetAddr(ParamValue
):
542 cxx_type
= 'Net::EthAddr'
543 cxx_predecls
= ['#include "base/inet.hh"']
544 swig_predecls
= ['%include "python/swig/inet.i"']
545 def __init__(self
, value
):
546 if value
== NextEthernetAddr
:
550 if not isinstance(value
, str):
551 raise TypeError, "expected an ethernet address and didn't get one"
553 bytes
= value
.split(':')
555 raise TypeError, 'invalid ethernet address %s' % value
558 if not 0 <= int(byte
) <= 256:
559 raise TypeError, 'invalid ethernet address %s' % value
563 def unproxy(self
, base
):
564 if self
.value
== NextEthernetAddr
:
565 return EthernetAddr(self
.value())
569 from m5
.objects
.params
import EthAddr
570 return EthAddr(self
.value
)
575 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
576 "%a %b %d %H:%M:%S %Z %Y",
588 def parse_time(value
):
589 from time
import gmtime
, strptime
, struct_time
, time
590 from datetime
import datetime
, date
592 if isinstance(value
, struct_time
):
595 if isinstance(value
, (int, long)):
598 if isinstance(value
, (datetime
, date
)):
599 return value
.timetuple()
601 if isinstance(value
, str):
602 if value
in ('Now', 'Today'):
603 return time
.gmtime(time
.time())
605 for format
in time_formats
:
607 return strptime(value
, format
)
611 raise ValueError, "Could not parse '%s' as a time" % value
613 class Time(ParamValue
):
615 cxx_predecls
= [ '#include <time.h>' ]
616 swig_predecls
= [ '%include "python/swig/time.i"' ]
617 def __init__(self
, value
):
618 self
.value
= parse_time(value
)
621 from m5
.objects
.params
import tm
626 # UNIX is years since 1900
627 c_time
.tm_year
= py_time
.tm_year
- 1900;
629 # Python starts at 1, UNIX starts at 0
630 c_time
.tm_mon
= py_time
.tm_mon
- 1;
631 c_time
.tm_mday
= py_time
.tm_mday
;
632 c_time
.tm_hour
= py_time
.tm_hour
;
633 c_time
.tm_min
= py_time
.tm_min
;
634 c_time
.tm_sec
= py_time
.tm_sec
;
636 # Python has 0 as Monday, UNIX is 0 as sunday
637 c_time
.tm_wday
= py_time
.tm_wday
+ 1
638 if c_time
.tm_wday
> 6:
641 # Python starts at 1, Unix starts at 0
642 c_time
.tm_yday
= py_time
.tm_yday
- 1;
647 return time
.asctime(self
.value
)
652 # Enumerated types are a little more complex. The user specifies the
653 # type as Enum(foo) where foo is either a list or dictionary of
654 # alternatives (typically strings, but not necessarily so). (In the
655 # long run, the integer value of the parameter will be the list index
656 # or the corresponding dictionary value. For now, since we only check
657 # that the alternative is valid and then spit it into a .ini file,
658 # there's not much point in using the dictionary.)
660 # What Enum() must do is generate a new type encapsulating the
661 # provided list/dictionary so that specific values of the parameter
662 # can be instances of that type. We define two hidden internal
663 # classes (_ListEnum and _DictEnum) to serve as base classes, then
664 # derive the new type from the appropriate base class on the fly.
667 # Metaclass for Enum types
668 class MetaEnum(type):
669 def __new__(mcls
, name
, bases
, dict):
670 assert name
not in allEnums
672 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
676 def __init__(cls
, name
, bases
, init_dict
):
677 if init_dict
.has_key('map'):
678 if not isinstance(cls
.map, dict):
679 raise TypeError, "Enum-derived class attribute 'map' " \
680 "must be of type dict"
681 # build list of value strings from map
682 cls
.vals
= cls
.map.keys()
684 elif init_dict
.has_key('vals'):
685 if not isinstance(cls
.vals
, list):
686 raise TypeError, "Enum-derived class attribute 'vals' " \
687 "must be of type list"
688 # build string->value map from vals sequence
690 for idx
,val
in enumerate(cls
.vals
):
693 raise TypeError, "Enum-derived class must define "\
694 "attribute 'map' or 'vals'"
696 cls
.cxx_type
= 'Enums::%s' % name
698 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
703 # Generate C++ class declaration for this enum type.
704 # Note that we wrap the enum in a class/struct to act as a namespace,
705 # so that the enum strings can be brief w/o worrying about collisions.
707 code
= "#ifndef __ENUM__%s\n" % cls
708 code
+= '#define __ENUM__%s\n' % cls
710 code
+= 'namespace Enums {\n'
711 code
+= ' enum %s {\n' % cls
713 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
714 code
+= ' Num_%s = %d,\n' % (cls
, len(cls
.vals
))
716 code
+= ' extern const char *%sStrings[Num_%s];\n' % (cls
, cls
)
723 code
= '#include "enums/%s.hh"\n' % cls
724 code
+= 'namespace Enums {\n'
725 code
+= ' const char *%sStrings[Num_%s] =\n' % (cls
, cls
)
728 code
+= ' "%s",\n' % val
733 # Base class for enum types.
734 class Enum(ParamValue
):
735 __metaclass__
= MetaEnum
738 def __init__(self
, value
):
739 if value
not in self
.map:
740 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
745 return int(self
.map[self
.value
])
750 # how big does a rounding error need to be before we warn about it?
751 frequency_tolerance
= 0.001 # 0.1%
753 class TickParamValue(NumericParamValue
):
755 cxx_predecls
= ['#include "sim/host.hh"']
756 swig_predecls
= ['%import "stdint.i"\n' +
757 '%import "sim/host.hh"']
760 return long(self
.value
)
762 class Latency(TickParamValue
):
763 def __init__(self
, value
):
764 if isinstance(value
, (Latency
, Clock
)):
765 self
.ticks
= value
.ticks
766 self
.value
= value
.value
767 elif isinstance(value
, Frequency
):
768 self
.ticks
= value
.ticks
769 self
.value
= 1.0 / value
.value
770 elif value
.endswith('t'):
772 self
.value
= int(value
[:-1])
775 self
.value
= convert
.toLatency(value
)
777 def __getattr__(self
, attr
):
778 if attr
in ('latency', 'period'):
780 if attr
== 'frequency':
781 return Frequency(self
)
782 raise AttributeError, "Latency object has no attribute '%s'" % attr
785 if self
.ticks
or self
.value
== 0:
788 value
= ticks
.fromSeconds(self
.value
)
791 # convert latency to ticks
793 return '%d' % self
.getValue()
795 class Frequency(TickParamValue
):
796 def __init__(self
, value
):
797 if isinstance(value
, (Latency
, Clock
)):
801 self
.value
= 1.0 / value
.value
802 self
.ticks
= value
.ticks
803 elif isinstance(value
, Frequency
):
804 self
.value
= value
.value
805 self
.ticks
= value
.ticks
808 self
.value
= convert
.toFrequency(value
)
810 def __getattr__(self
, attr
):
811 if attr
== 'frequency':
813 if attr
in ('latency', 'period'):
815 raise AttributeError, "Frequency object has no attribute '%s'" % attr
817 # convert latency to ticks
819 if self
.ticks
or self
.value
== 0:
822 value
= ticks
.fromSeconds(1.0 / self
.value
)
826 return '%d' % self
.getValue()
828 # A generic frequency and/or Latency value. Value is stored as a latency,
829 # but to avoid ambiguity this object does not support numeric ops (* or /).
830 # An explicit conversion to a Latency or Frequency must be made first.
831 class Clock(ParamValue
):
833 cxx_predecls
= ['#include "sim/host.hh"']
834 swig_predecls
= ['%import "stdint.i"\n' +
835 '%import "sim/host.hh"']
836 def __init__(self
, value
):
837 if isinstance(value
, (Latency
, Clock
)):
838 self
.ticks
= value
.ticks
839 self
.value
= value
.value
840 elif isinstance(value
, Frequency
):
841 self
.ticks
= value
.ticks
842 self
.value
= 1.0 / value
.value
843 elif value
.endswith('t'):
845 self
.value
= int(value
[:-1])
848 self
.value
= convert
.anyToLatency(value
)
850 def __getattr__(self
, attr
):
851 if attr
== 'frequency':
852 return Frequency(self
)
853 if attr
in ('latency', 'period'):
855 raise AttributeError, "Frequency object has no attribute '%s'" % attr
858 return self
.period
.getValue()
861 return self
.period
.ini_str()
863 class NetworkBandwidth(float,ParamValue
):
865 def __new__(cls
, value
):
866 # convert to bits per second
867 val
= convert
.toNetworkBandwidth(value
)
868 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
874 # convert to seconds per byte
875 value
= 8.0 / float(self
)
876 # convert to ticks per byte
877 value
= ticks
.fromSeconds(value
)
881 return '%f' % self
.getValue()
883 class MemoryBandwidth(float,ParamValue
):
885 def __new__(self
, value
):
886 # we want the number of ticks per byte of data
887 val
= convert
.toMemoryBandwidth(value
)
888 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
894 # convert to seconds per byte
895 value
= 1.0 / float(self
)
896 # convert to ticks per byte
897 value
= ticks
.fromSeconds(value
)
901 return '%f' % self
.getValue()
904 # "Constants"... handy aliases for various values.
907 # Special class for NULL pointers. Note the special check in
908 # make_param_value() above that lets these be assigned where a
909 # SimObject is required.
910 # only one copy of a particular node
911 class NullSimObject(object):
912 __metaclass__
= Singleton
917 def _instantiate(self
, parent
= None, path
= ''):
923 def unproxy(self
, base
):
926 def set_path(self
, parent
, name
):
935 # The only instance you'll ever need...
936 NULL
= NullSimObject()
938 def isNullPointer(value
):
939 return isinstance(value
, NullSimObject
)
941 # Some memory range specifications use this as a default upper bound.
944 AllMemory
= AddrRange(0, MaxAddr
)
947 #####################################################################
951 # Ports are used to interconnect objects in the memory system.
953 #####################################################################
955 # Port reference: encapsulates a reference to a particular port on a
956 # particular SimObject.
957 class PortRef(object):
958 def __init__(self
, simobj
, name
):
959 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
962 self
.peer
= None # not associated with another port yet
963 self
.ccConnected
= False # C++ port connection done?
964 self
.index
= -1 # always -1 for non-vector ports
967 return '%s.%s' % (self
.simobj
, self
.name
)
969 # for config.ini, print peer's name (not ours)
971 return str(self
.peer
)
973 def __getattr__(self
, attr
):
974 if attr
== 'peerObj':
975 # shorthand for proxies
976 return self
.peer
.simobj
977 raise AttributeError, "'%s' object has no attribute '%s'" % \
978 (self
.__class
__.__name
__, attr
)
980 # Full connection is symmetric (both ways). Called via
981 # SimObject.__setattr__ as a result of a port assignment, e.g.,
982 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
983 # e.g., "obj1.portA[3] = obj2.portB".
984 def connect(self
, other
):
985 if isinstance(other
, VectorPortRef
):
986 # reference to plain VectorPort is implicit append
987 other
= other
._get
_next
()
988 if self
.peer
and not proxy
.isproxy(self
.peer
):
989 print "warning: overwriting port", self
, \
990 "value", self
.peer
, "with", other
992 if proxy
.isproxy(other
):
993 other
.set_param_desc(PortParamDesc())
994 elif isinstance(other
, PortRef
):
995 if other
.peer
is not self
:
999 "assigning non-port reference '%s' to port '%s'" \
1002 def clone(self
, simobj
, memo
):
1003 if memo
.has_key(self
):
1005 newRef
= copy
.copy(self
)
1007 newRef
.simobj
= simobj
1008 assert(isSimObject(newRef
.simobj
))
1009 if self
.peer
and not proxy
.isproxy(self
.peer
):
1010 peerObj
= self
.peer
.simobj(_memo
=memo
)
1011 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1012 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1015 def unproxy(self
, simobj
):
1016 assert(simobj
is self
.simobj
)
1017 if proxy
.isproxy(self
.peer
):
1019 realPeer
= self
.peer
.unproxy(self
.simobj
)
1021 print "Error in unproxying port '%s' of %s" % \
1022 (self
.name
, self
.simobj
.path())
1024 self
.connect(realPeer
)
1026 # Call C++ to create corresponding port connection between C++ objects
1027 def ccConnect(self
):
1030 if self
.ccConnected
: # already done this
1033 internal
.sim_object
.connectPorts(self
.simobj
.getCCObject(), self
.name
,
1034 self
.index
, peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1035 self
.ccConnected
= True
1036 peer
.ccConnected
= True
1038 # A reference to an individual element of a VectorPort... much like a
1039 # PortRef, but has an index.
1040 class VectorPortElementRef(PortRef
):
1041 def __init__(self
, simobj
, name
, index
):
1042 PortRef
.__init
__(self
, simobj
, name
)
1046 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1048 # A reference to a complete vector-valued port (not just a single element).
1049 # Can be indexed to retrieve individual VectorPortElementRef instances.
1050 class VectorPortRef(object):
1051 def __init__(self
, simobj
, name
):
1052 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1053 self
.simobj
= simobj
1058 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1060 # for config.ini, print peer's name (not ours)
1062 return ' '.join([el
.ini_str() for el
in self
.elements
])
1064 def __getitem__(self
, key
):
1065 if not isinstance(key
, int):
1066 raise TypeError, "VectorPort index must be integer"
1067 if key
>= len(self
.elements
):
1068 # need to extend list
1069 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1070 for i
in range(len(self
.elements
), key
+1)]
1071 self
.elements
.extend(ext
)
1072 return self
.elements
[key
]
1074 def _get_next(self
):
1075 return self
[len(self
.elements
)]
1077 def __setitem__(self
, key
, value
):
1078 if not isinstance(key
, int):
1079 raise TypeError, "VectorPort index must be integer"
1080 self
[key
].connect(value
)
1082 def connect(self
, other
):
1083 if isinstance(other
, (list, tuple)):
1084 # Assign list of port refs to vector port.
1085 # For now, append them... not sure if that's the right semantics
1086 # or if it should replace the current vector.
1088 self
._get
_next
().connect(ref
)
1090 # scalar assignment to plain VectorPort is implicit append
1091 self
._get
_next
().connect(other
)
1093 def clone(self
, simobj
, memo
):
1094 if memo
.has_key(self
):
1096 newRef
= copy
.copy(self
)
1098 newRef
.simobj
= simobj
1099 assert(isSimObject(newRef
.simobj
))
1100 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1103 def unproxy(self
, simobj
):
1104 [el
.unproxy(simobj
) for el
in self
.elements
]
1106 def ccConnect(self
):
1107 [el
.ccConnect() for el
in self
.elements
]
1109 # Port description object. Like a ParamDesc object, this represents a
1110 # logical port in the SimObject class, not a particular port on a
1111 # SimObject instance. The latter are represented by PortRef objects.
1113 # Port("description") or Port(default, "description")
1114 def __init__(self
, *args
):
1117 elif len(args
) == 2:
1118 self
.default
= args
[0]
1121 raise TypeError, 'wrong number of arguments'
1122 # self.name is set by SimObject class on assignment
1123 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1125 # Generate a PortRef for this port on the given SimObject with the
1127 def makeRef(self
, simobj
):
1128 return PortRef(simobj
, self
.name
)
1130 # Connect an instance of this port (on the given SimObject with
1131 # the given name) with the port described by the supplied PortRef
1132 def connect(self
, simobj
, ref
):
1133 self
.makeRef(simobj
).connect(ref
)
1135 # VectorPort description object. Like Port, but represents a vector
1136 # of connections (e.g., as on a Bus).
1137 class VectorPort(Port
):
1138 def __init__(self
, *args
):
1139 Port
.__init
__(self
, *args
)
1142 def makeRef(self
, simobj
):
1143 return VectorPortRef(simobj
, self
.name
)
1145 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1146 # proxy objects (via set_param_desc()) so that proxy error messages
1148 class PortParamDesc(object):
1149 __metaclass__
= Singleton
1154 __all__
= ['Param', 'VectorParam',
1155 'Enum', 'Bool', 'String', 'Float',
1156 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1157 'Int32', 'UInt32', 'Int64', 'UInt64',
1158 'Counter', 'Addr', 'Tick', 'Percent',
1159 'TcpPort', 'UdpPort', 'EthernetAddr',
1160 'MemorySize', 'MemorySize32',
1161 'Latency', 'Frequency', 'Clock',
1162 'NetworkBandwidth', 'MemoryBandwidth',
1163 'Range', 'AddrRange', 'TickRange',
1164 'MaxAddr', 'MaxTick', 'AllMemory',
1166 'NextEthernetAddr', 'NULL',
1167 'Port', 'VectorPort']