1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Steve Reinhardt
30 #####################################################################
32 # Parameter description classes
34 # The _params dictionary in each class maps parameter names to either
35 # a Param or a VectorParam object. These objects contain the
36 # parameter description string, the parameter type, and the default
37 # value (if any). The convert() method on these objects is used to
38 # force whatever value is assigned to the parameter to the appropriate
41 # Note that the default values are loaded into the class's attribute
42 # space when the parameter dictionary is initialized (in
43 # MetaSimObject._new_param()); after that point they aren't used.
45 #####################################################################
57 def isSimObject(*args
, **kwargs
):
58 return SimObject
.isSimObject(*args
, **kwargs
)
60 def isSimObjectSequence(*args
, **kwargs
):
61 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
63 def isSimObjectClass(*args
, **kwargs
):
64 return SimObject
.isSimObjectClass(*args
, **kwargs
)
68 class MetaParamValue(type):
69 def __new__(mcls
, name
, bases
, dct
):
70 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
71 assert name
not in allParams
76 # Dummy base class to identify types that are legitimate for SimObject
78 class ParamValue(object):
79 __metaclass__
= MetaParamValue
84 # default for printing to .ini file is regular string conversion.
85 # will be overridden in some cases
89 # allows us to blithely call unproxy() on things without checking
90 # if they're really proxies or not
91 def unproxy(self
, base
):
94 # Regular parameter description.
95 class ParamDesc(object):
98 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
99 self
.ptype_str
= ptype_str
100 # remember ptype only if it is provided
108 self
.default
= args
[0]
111 raise TypeError, 'too many arguments'
113 if kwargs
.has_key('desc'):
114 assert(not hasattr(self
, 'desc'))
115 self
.desc
= kwargs
['desc']
118 if kwargs
.has_key('default'):
119 assert(not hasattr(self
, 'default'))
120 self
.default
= kwargs
['default']
121 del kwargs
['default']
124 raise TypeError, 'extra unknown kwargs %s' % kwargs
126 if not hasattr(self
, 'desc'):
127 raise TypeError, 'desc attribute missing'
129 def __getattr__(self
, attr
):
131 ptype
= SimObject
.allClasses
[self
.ptype_str
]
132 assert isSimObjectClass(ptype
)
136 raise AttributeError, "'%s' object has no attribute '%s'" % \
137 (type(self
).__name
__, attr
)
139 def convert(self
, value
):
140 if isinstance(value
, proxy
.BaseProxy
):
141 value
.set_param_desc(self
)
143 if not hasattr(self
, 'ptype') and isNullPointer(value
):
144 # deferred evaluation of SimObject; continue to defer if
145 # we're just assigning a null pointer
147 if isinstance(value
, self
.ptype
):
149 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
151 return self
.ptype(value
)
153 def cxx_predecls(self
):
154 return self
.ptype
.cxx_predecls
156 def swig_predecls(self
):
157 return self
.ptype
.swig_predecls
160 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
162 # Vector-valued parameter description. Just like ParamDesc, except
163 # that the value is a vector (list) of the specified type instead of a
166 class VectorParamValue(list):
167 __metaclass__
= MetaParamValue
168 def __setattr__(self
, attr
, value
):
169 raise AttributeError, \
170 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
173 return ' '.join([v
.ini_str() for v
in self
])
176 return [ v
.getValue() for v
in self
]
178 def unproxy(self
, base
):
179 return [v
.unproxy(base
) for v
in self
]
181 class SimObjVector(VectorParamValue
):
182 def print_ini(self
, ini_file
):
184 v
.print_ini(ini_file
)
186 class VectorParamDesc(ParamDesc
):
189 # Convert assigned value to appropriate type. If the RHS is not a
190 # list or tuple, it generates a single-element list.
191 def convert(self
, value
):
192 if isinstance(value
, (list, tuple)):
193 # list: coerce each element into new list
194 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
196 # singleton: coerce to a single-element list
197 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
199 if isSimObjectSequence(tmp_list
):
200 return SimObjVector(tmp_list
)
202 return VectorParamValue(tmp_list
)
204 def swig_predecls(self
):
205 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
208 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
209 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
210 (self
.ptype_str
, cxx_type
)
211 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
213 def cxx_predecls(self
):
214 return ['#include <vector>'] + self
.ptype
.cxx_predecls
217 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
219 class ParamFactory(object):
220 def __init__(self
, param_desc_class
, ptype_str
= None):
221 self
.param_desc_class
= param_desc_class
222 self
.ptype_str
= ptype_str
224 def __getattr__(self
, attr
):
226 attr
= self
.ptype_str
+ '.' + attr
227 return ParamFactory(self
.param_desc_class
, attr
)
229 # E.g., Param.Int(5, "number of widgets")
230 def __call__(self
, *args
, **kwargs
):
233 ptype
= allParams
[self
.ptype_str
]
235 # if name isn't defined yet, assume it's a SimObject, and
236 # try to resolve it later
238 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
240 Param
= ParamFactory(ParamDesc
)
241 VectorParam
= ParamFactory(VectorParamDesc
)
243 #####################################################################
247 # Though native Python types could be used to specify parameter types
248 # (the 'ptype' field of the Param and VectorParam classes), it's more
249 # flexible to define our own set of types. This gives us more control
250 # over how Python expressions are converted to values (via the
251 # __init__() constructor) and how these values are printed out (via
252 # the __str__() conversion method).
254 #####################################################################
256 # String-valued parameter. Just mixin the ParamValue class with the
257 # built-in str class.
258 class String(ParamValue
,str):
259 cxx_type
= 'std::string'
260 cxx_predecls
= ['#include <string>']
261 swig_predecls
= ['%include "std_string.i"\n' +
262 '%apply const std::string& {std::string *};']
263 swig_predecls
= ['%include "std_string.i"' ]
268 # superclass for "numeric" parameter values, to emulate math
269 # operations in a type-safe way. e.g., a Latency times an int returns
270 # a new Latency object.
271 class NumericParamValue(ParamValue
):
273 return str(self
.value
)
276 return float(self
.value
)
279 return long(self
.value
)
282 return int(self
.value
)
284 # hook for bounds checking
288 def __mul__(self
, other
):
289 newobj
= self
.__class
__(self
)
290 newobj
.value
*= other
296 def __div__(self
, other
):
297 newobj
= self
.__class
__(self
)
298 newobj
.value
/= other
302 def __sub__(self
, other
):
303 newobj
= self
.__class
__(self
)
304 newobj
.value
-= other
308 # Metaclass for bounds-checked integer parameters. See CheckedInt.
309 class CheckedIntType(MetaParamValue
):
310 def __init__(cls
, name
, bases
, dict):
311 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
313 # CheckedInt is an abstract base class, so we actually don't
314 # want to do any processing on it... the rest of this code is
315 # just for classes that derive from CheckedInt.
316 if name
== 'CheckedInt':
319 if not cls
.cxx_predecls
:
320 # most derived types require this, so we just do it here once
321 cls
.cxx_predecls
= ['#include "base/types.hh"']
323 if not cls
.swig_predecls
:
324 # most derived types require this, so we just do it here once
325 cls
.swig_predecls
= ['%import "stdint.i"\n' +
326 '%import "base/types.hh"']
328 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
329 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
330 panic("CheckedInt subclass %s must define either\n" \
331 " 'min' and 'max' or 'size' and 'unsigned'\n",
335 cls
.max = 2 ** cls
.size
- 1
337 cls
.min = -(2 ** (cls
.size
- 1))
338 cls
.max = (2 ** (cls
.size
- 1)) - 1
340 # Abstract superclass for bounds-checked integer parameters. This
341 # class is subclassed to generate parameter classes with specific
342 # bounds. Initialization of the min and max bounds is done in the
343 # metaclass CheckedIntType.__init__.
344 class CheckedInt(NumericParamValue
):
345 __metaclass__
= CheckedIntType
348 if not self
.min <= self
.value
<= self
.max:
349 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
350 (self
.min, self
.value
, self
.max)
352 def __init__(self
, value
):
353 if isinstance(value
, str):
354 self
.value
= convert
.toInteger(value
)
355 elif isinstance(value
, (int, long, float, NumericParamValue
)):
356 self
.value
= long(value
)
358 raise TypeError, "Can't convert object of type %s to CheckedInt" \
359 % type(value
).__name
__
363 return long(self
.value
)
365 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
366 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
368 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
369 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
370 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
371 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
372 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
373 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
374 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
375 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
377 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
378 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
379 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
380 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
382 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
384 class Float(ParamValue
, float):
387 def __init__(self
, value
):
388 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
389 self
.value
= float(value
)
391 raise TypeError, "Can't convert object of type %s to Float" \
392 % type(value
).__name
__
395 return float(self
.value
)
397 class MemorySize(CheckedInt
):
398 cxx_type
= 'uint64_t'
401 def __init__(self
, value
):
402 if isinstance(value
, MemorySize
):
403 self
.value
= value
.value
405 self
.value
= convert
.toMemorySize(value
)
408 class MemorySize32(CheckedInt
):
409 cxx_type
= 'uint32_t'
412 def __init__(self
, value
):
413 if isinstance(value
, MemorySize
):
414 self
.value
= value
.value
416 self
.value
= convert
.toMemorySize(value
)
419 class Addr(CheckedInt
):
423 def __init__(self
, value
):
424 if isinstance(value
, Addr
):
425 self
.value
= value
.value
428 self
.value
= convert
.toMemorySize(value
)
430 self
.value
= long(value
)
432 def __add__(self
, other
):
433 if isinstance(other
, Addr
):
434 return self
.value
+ other
.value
436 return self
.value
+ other
439 class MetaRange(MetaParamValue
):
440 def __init__(cls
, name
, bases
, dict):
441 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
444 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
446 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
448 class Range(ParamValue
):
449 __metaclass__
= MetaRange
450 type = Int
# default; can be overridden in subclasses
451 def __init__(self
, *args
, **kwargs
):
452 def handle_kwargs(self
, kwargs
):
454 self
.second
= self
.type(kwargs
.pop('end'))
455 elif 'size' in kwargs
:
456 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
458 raise TypeError, "Either end or size must be specified"
461 self
.first
= self
.type(kwargs
.pop('start'))
462 handle_kwargs(self
, kwargs
)
466 self
.first
= self
.type(args
[0])
467 handle_kwargs(self
, kwargs
)
468 elif isinstance(args
[0], Range
):
469 self
.first
= self
.type(args
[0].first
)
470 self
.second
= self
.type(args
[0].second
)
471 elif isinstance(args
[0], (list, tuple)):
472 self
.first
= self
.type(args
[0][0])
473 self
.second
= self
.type(args
[0][1])
475 self
.first
= self
.type(0)
476 self
.second
= self
.type(args
[0]) - 1
479 self
.first
= self
.type(args
[0])
480 self
.second
= self
.type(args
[1])
482 raise TypeError, "Too many arguments specified"
485 raise TypeError, "too many keywords: %s" % kwargs
.keys()
488 return '%s:%s' % (self
.first
, self
.second
)
490 class AddrRange(Range
):
492 swig_predecls
= ['%include "python/swig/range.i"']
495 from m5
.objects
.params
import AddrRange
498 value
.start
= long(self
.first
)
499 value
.end
= long(self
.second
)
502 class TickRange(Range
):
504 swig_predecls
= ['%include "python/swig/range.i"']
507 from m5
.objects
.params
import TickRange
510 value
.start
= long(self
.first
)
511 value
.end
= long(self
.second
)
514 # Boolean parameter type. Python doesn't let you subclass bool, since
515 # it doesn't want to let you create multiple instances of True and
516 # False. Thus this is a little more complicated than String.
517 class Bool(ParamValue
):
519 def __init__(self
, value
):
521 self
.value
= convert
.toBool(value
)
523 self
.value
= bool(value
)
526 return bool(self
.value
)
529 return str(self
.value
)
536 def IncEthernetAddr(addr
, val
= 1):
537 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
539 for i
in (5, 4, 3, 2, 1):
540 val
,rem
= divmod(bytes
[i
], 256)
545 assert(bytes
[0] <= 255)
546 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
548 _NextEthernetAddr
= "00:90:00:00:00:01"
549 def NextEthernetAddr():
550 global _NextEthernetAddr
552 value
= _NextEthernetAddr
553 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
556 class EthernetAddr(ParamValue
):
557 cxx_type
= 'Net::EthAddr'
558 cxx_predecls
= ['#include "base/inet.hh"']
559 swig_predecls
= ['%include "python/swig/inet.i"']
560 def __init__(self
, value
):
561 if value
== NextEthernetAddr
:
565 if not isinstance(value
, str):
566 raise TypeError, "expected an ethernet address and didn't get one"
568 bytes
= value
.split(':')
570 raise TypeError, 'invalid ethernet address %s' % value
573 if not 0 <= int(byte
) <= 256:
574 raise TypeError, 'invalid ethernet address %s' % value
578 def unproxy(self
, base
):
579 if self
.value
== NextEthernetAddr
:
580 return EthernetAddr(self
.value())
584 from m5
.objects
.params
import EthAddr
585 return EthAddr(self
.value
)
590 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
591 "%a %b %d %H:%M:%S %Z %Y",
603 def parse_time(value
):
604 from time
import gmtime
, strptime
, struct_time
, time
605 from datetime
import datetime
, date
607 if isinstance(value
, struct_time
):
610 if isinstance(value
, (int, long)):
613 if isinstance(value
, (datetime
, date
)):
614 return value
.timetuple()
616 if isinstance(value
, str):
617 if value
in ('Now', 'Today'):
618 return time
.gmtime(time
.time())
620 for format
in time_formats
:
622 return strptime(value
, format
)
626 raise ValueError, "Could not parse '%s' as a time" % value
628 class Time(ParamValue
):
630 cxx_predecls
= [ '#include <time.h>' ]
631 swig_predecls
= [ '%include "python/swig/time.i"' ]
632 def __init__(self
, value
):
633 self
.value
= parse_time(value
)
636 from m5
.objects
.params
import tm
641 # UNIX is years since 1900
642 c_time
.tm_year
= py_time
.tm_year
- 1900;
644 # Python starts at 1, UNIX starts at 0
645 c_time
.tm_mon
= py_time
.tm_mon
- 1;
646 c_time
.tm_mday
= py_time
.tm_mday
;
647 c_time
.tm_hour
= py_time
.tm_hour
;
648 c_time
.tm_min
= py_time
.tm_min
;
649 c_time
.tm_sec
= py_time
.tm_sec
;
651 # Python has 0 as Monday, UNIX is 0 as sunday
652 c_time
.tm_wday
= py_time
.tm_wday
+ 1
653 if c_time
.tm_wday
> 6:
656 # Python starts at 1, Unix starts at 0
657 c_time
.tm_yday
= py_time
.tm_yday
- 1;
662 return time
.asctime(self
.value
)
667 # Enumerated types are a little more complex. The user specifies the
668 # type as Enum(foo) where foo is either a list or dictionary of
669 # alternatives (typically strings, but not necessarily so). (In the
670 # long run, the integer value of the parameter will be the list index
671 # or the corresponding dictionary value. For now, since we only check
672 # that the alternative is valid and then spit it into a .ini file,
673 # there's not much point in using the dictionary.)
675 # What Enum() must do is generate a new type encapsulating the
676 # provided list/dictionary so that specific values of the parameter
677 # can be instances of that type. We define two hidden internal
678 # classes (_ListEnum and _DictEnum) to serve as base classes, then
679 # derive the new type from the appropriate base class on the fly.
682 # Metaclass for Enum types
683 class MetaEnum(MetaParamValue
):
684 def __new__(mcls
, name
, bases
, dict):
685 assert name
not in allEnums
687 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
691 def __init__(cls
, name
, bases
, init_dict
):
692 if init_dict
.has_key('map'):
693 if not isinstance(cls
.map, dict):
694 raise TypeError, "Enum-derived class attribute 'map' " \
695 "must be of type dict"
696 # build list of value strings from map
697 cls
.vals
= cls
.map.keys()
699 elif init_dict
.has_key('vals'):
700 if not isinstance(cls
.vals
, list):
701 raise TypeError, "Enum-derived class attribute 'vals' " \
702 "must be of type list"
703 # build string->value map from vals sequence
705 for idx
,val
in enumerate(cls
.vals
):
708 raise TypeError, "Enum-derived class must define "\
709 "attribute 'map' or 'vals'"
711 cls
.cxx_type
= 'Enums::%s' % name
713 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
715 # Generate C++ class declaration for this enum type.
716 # Note that we wrap the enum in a class/struct to act as a namespace,
717 # so that the enum strings can be brief w/o worrying about collisions.
720 code
= "#ifndef __ENUM__%s\n" % name
721 code
+= '#define __ENUM__%s\n' % name
723 code
+= 'namespace Enums {\n'
724 code
+= ' enum %s {\n' % name
726 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
727 code
+= ' Num_%s = %d,\n' % (name
, len(cls
.vals
))
729 code
+= ' extern const char *%sStrings[Num_%s];\n' % (name
, name
)
737 code
= '#include "enums/%s.hh"\n' % name
738 code
+= 'namespace Enums {\n'
739 code
+= ' const char *%sStrings[Num_%s] =\n' % (name
, name
)
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 "base/types.hh"']
770 swig_predecls
= ['%import "stdint.i"\n' +
771 '%import "base/types.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 "base/types.hh"']
848 swig_predecls
= ['%import "stdint.i"\n' +
849 '%import "base/types.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
1007 self
.peer
.peer
= None
1009 if proxy
.isproxy(other
):
1010 other
.set_param_desc(PortParamDesc())
1011 elif isinstance(other
, PortRef
):
1012 if other
.peer
is not self
:
1016 "assigning non-port reference '%s' to port '%s'" \
1019 def clone(self
, simobj
, memo
):
1020 if memo
.has_key(self
):
1022 newRef
= copy
.copy(self
)
1024 newRef
.simobj
= simobj
1025 assert(isSimObject(newRef
.simobj
))
1026 if self
.peer
and not proxy
.isproxy(self
.peer
):
1027 peerObj
= self
.peer
.simobj(_memo
=memo
)
1028 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1029 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1032 def unproxy(self
, simobj
):
1033 assert(simobj
is self
.simobj
)
1034 if proxy
.isproxy(self
.peer
):
1036 realPeer
= self
.peer
.unproxy(self
.simobj
)
1038 print "Error in unproxying port '%s' of %s" % \
1039 (self
.name
, self
.simobj
.path())
1041 self
.connect(realPeer
)
1043 # Call C++ to create corresponding port connection between C++ objects
1044 def ccConnect(self
):
1045 from m5
.objects
.params
import connectPorts
1047 if self
.ccConnected
: # already done this
1050 if not self
.peer
: # nothing to connect to
1052 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1053 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1054 self
.ccConnected
= True
1055 peer
.ccConnected
= True
1057 # A reference to an individual element of a VectorPort... much like a
1058 # PortRef, but has an index.
1059 class VectorPortElementRef(PortRef
):
1060 def __init__(self
, simobj
, name
, index
):
1061 PortRef
.__init
__(self
, simobj
, name
)
1065 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1067 # A reference to a complete vector-valued port (not just a single element).
1068 # Can be indexed to retrieve individual VectorPortElementRef instances.
1069 class VectorPortRef(object):
1070 def __init__(self
, simobj
, name
):
1071 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1072 self
.simobj
= simobj
1077 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1079 # for config.ini, print peer's name (not ours)
1081 return ' '.join([el
.ini_str() for el
in self
.elements
])
1083 def __getitem__(self
, key
):
1084 if not isinstance(key
, int):
1085 raise TypeError, "VectorPort index must be integer"
1086 if key
>= len(self
.elements
):
1087 # need to extend list
1088 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1089 for i
in range(len(self
.elements
), key
+1)]
1090 self
.elements
.extend(ext
)
1091 return self
.elements
[key
]
1093 def _get_next(self
):
1094 return self
[len(self
.elements
)]
1096 def __setitem__(self
, key
, value
):
1097 if not isinstance(key
, int):
1098 raise TypeError, "VectorPort index must be integer"
1099 self
[key
].connect(value
)
1101 def connect(self
, other
):
1102 if isinstance(other
, (list, tuple)):
1103 # Assign list of port refs to vector port.
1104 # For now, append them... not sure if that's the right semantics
1105 # or if it should replace the current vector.
1107 self
._get
_next
().connect(ref
)
1109 # scalar assignment to plain VectorPort is implicit append
1110 self
._get
_next
().connect(other
)
1112 def clone(self
, simobj
, memo
):
1113 if memo
.has_key(self
):
1115 newRef
= copy
.copy(self
)
1117 newRef
.simobj
= simobj
1118 assert(isSimObject(newRef
.simobj
))
1119 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1122 def unproxy(self
, simobj
):
1123 [el
.unproxy(simobj
) for el
in self
.elements
]
1125 def ccConnect(self
):
1126 [el
.ccConnect() for el
in self
.elements
]
1128 # Port description object. Like a ParamDesc object, this represents a
1129 # logical port in the SimObject class, not a particular port on a
1130 # SimObject instance. The latter are represented by PortRef objects.
1132 # Port("description") or Port(default, "description")
1133 def __init__(self
, *args
):
1136 elif len(args
) == 2:
1137 self
.default
= args
[0]
1140 raise TypeError, 'wrong number of arguments'
1141 # self.name is set by SimObject class on assignment
1142 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1144 # Generate a PortRef for this port on the given SimObject with the
1146 def makeRef(self
, simobj
):
1147 return PortRef(simobj
, self
.name
)
1149 # Connect an instance of this port (on the given SimObject with
1150 # the given name) with the port described by the supplied PortRef
1151 def connect(self
, simobj
, ref
):
1152 self
.makeRef(simobj
).connect(ref
)
1154 # VectorPort description object. Like Port, but represents a vector
1155 # of connections (e.g., as on a Bus).
1156 class VectorPort(Port
):
1157 def __init__(self
, *args
):
1158 Port
.__init
__(self
, *args
)
1161 def makeRef(self
, simobj
):
1162 return VectorPortRef(simobj
, self
.name
)
1164 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1165 # proxy objects (via set_param_desc()) so that proxy error messages
1167 class PortParamDesc(object):
1168 __metaclass__
= Singleton
1173 baseEnums
= allEnums
.copy()
1174 baseParams
= allParams
.copy()
1177 global allEnums
, allParams
1179 allEnums
= baseEnums
.copy()
1180 allParams
= baseParams
.copy()
1182 __all__
= ['Param', 'VectorParam',
1183 'Enum', 'Bool', 'String', 'Float',
1184 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1185 'Int32', 'UInt32', 'Int64', 'UInt64',
1186 'Counter', 'Addr', 'Tick', 'Percent',
1187 'TcpPort', 'UdpPort', 'EthernetAddr',
1188 'MemorySize', 'MemorySize32',
1189 'Latency', 'Frequency', 'Clock',
1190 'NetworkBandwidth', 'MemoryBandwidth',
1191 'Range', 'AddrRange', 'TickRange',
1192 'MaxAddr', 'MaxTick', 'AllMemory',
1194 'NextEthernetAddr', 'NULL',
1195 'Port', 'VectorPort']