75dcf094a713d99d37e4f66ed2ff640c623a7b9a
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 #####################################################################
58 def isSimObject(*args
, **kwargs
):
59 return SimObject
.isSimObject(*args
, **kwargs
)
61 def isSimObjectSequence(*args
, **kwargs
):
62 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
64 def isSimObjectClass(*args
, **kwargs
):
65 return SimObject
.isSimObjectClass(*args
, **kwargs
)
69 class MetaParamValue(type):
70 def __new__(mcls
, name
, bases
, dct
):
71 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
72 assert name
not in allParams
77 # Dummy base class to identify types that are legitimate for SimObject
79 class ParamValue(object):
80 __metaclass__
= MetaParamValue
85 # default for printing to .ini file is regular string conversion.
86 # will be overridden in some cases
90 # allows us to blithely call unproxy() on things without checking
91 # if they're really proxies or not
92 def unproxy(self
, base
):
95 # Regular parameter description.
96 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 isSimObjectClass(ptype
)
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 SimObjectVector(VectorParamValue
):
183 # support clone operation
184 def __call__(self
, **kwargs
):
185 return SimObjectVector([v(**kwargs
) for v
in self
])
187 def clear_parent(self
, old_parent
):
189 v
.clear_parent(old_parent
)
191 def set_parent(self
, parent
, name
):
193 self
[0].set_parent(parent
, name
)
195 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
196 for i
,v
in enumerate(self
):
197 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
199 def get_parent(self
):
200 parent_set
= set(v
._parent
for v
in self
)
201 if len(parent_set
) != 1:
202 raise RuntimeError, \
203 "SimObjectVector elements have inconsistent parent value."
204 return parent_set
.pop()
206 # return 'cpu0 cpu1' etc. for print_ini()
208 return ' '.join([v
._name
for v
in self
])
210 # By iterating through the constituent members of the vector here
211 # we can nicely handle iterating over all a SimObject's children
212 # without having to provide lots of special functions on
213 # SimObjectVector directly.
214 def descendants(self
):
216 for obj
in v
.descendants():
219 class VectorParamDesc(ParamDesc
):
222 # Convert assigned value to appropriate type. If the RHS is not a
223 # list or tuple, it generates a single-element list.
224 def convert(self
, value
):
225 if isinstance(value
, (list, tuple)):
226 # list: coerce each element into new list
227 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
229 # singleton: coerce to a single-element list
230 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
232 if isSimObjectSequence(tmp_list
):
233 return SimObjectVector(tmp_list
)
235 return VectorParamValue(tmp_list
)
237 def swig_predecls(self
):
238 return ['%%include "%s_vptype.i"' % self
.ptype_str
]
241 cxx_type
= re
.sub('std::', '', self
.ptype
.cxx_type
)
242 vdecl
= 'namespace std { %%template(vector_%s) vector< %s >; }' % \
243 (self
.ptype_str
, cxx_type
)
244 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
+ [vdecl
]
246 def cxx_predecls(self
):
247 return ['#include <vector>'] + self
.ptype
.cxx_predecls
250 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
252 class ParamFactory(object):
253 def __init__(self
, param_desc_class
, ptype_str
= None):
254 self
.param_desc_class
= param_desc_class
255 self
.ptype_str
= ptype_str
257 def __getattr__(self
, attr
):
259 attr
= self
.ptype_str
+ '.' + attr
260 return ParamFactory(self
.param_desc_class
, attr
)
262 # E.g., Param.Int(5, "number of widgets")
263 def __call__(self
, *args
, **kwargs
):
266 ptype
= allParams
[self
.ptype_str
]
268 # if name isn't defined yet, assume it's a SimObject, and
269 # try to resolve it later
271 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
273 Param
= ParamFactory(ParamDesc
)
274 VectorParam
= ParamFactory(VectorParamDesc
)
276 #####################################################################
280 # Though native Python types could be used to specify parameter types
281 # (the 'ptype' field of the Param and VectorParam classes), it's more
282 # flexible to define our own set of types. This gives us more control
283 # over how Python expressions are converted to values (via the
284 # __init__() constructor) and how these values are printed out (via
285 # the __str__() conversion method).
287 #####################################################################
289 # String-valued parameter. Just mixin the ParamValue class with the
290 # built-in str class.
291 class String(ParamValue
,str):
292 cxx_type
= 'std::string'
293 cxx_predecls
= ['#include <string>']
294 swig_predecls
= ['%include "std_string.i"\n' +
295 '%apply const std::string& {std::string *};']
296 swig_predecls
= ['%include "std_string.i"' ]
301 # superclass for "numeric" parameter values, to emulate math
302 # operations in a type-safe way. e.g., a Latency times an int returns
303 # a new Latency object.
304 class NumericParamValue(ParamValue
):
306 return str(self
.value
)
309 return float(self
.value
)
312 return long(self
.value
)
315 return int(self
.value
)
317 # hook for bounds checking
321 def __mul__(self
, other
):
322 newobj
= self
.__class
__(self
)
323 newobj
.value
*= other
329 def __div__(self
, other
):
330 newobj
= self
.__class
__(self
)
331 newobj
.value
/= other
335 def __sub__(self
, other
):
336 newobj
= self
.__class
__(self
)
337 newobj
.value
-= other
341 # Metaclass for bounds-checked integer parameters. See CheckedInt.
342 class CheckedIntType(MetaParamValue
):
343 def __init__(cls
, name
, bases
, dict):
344 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
346 # CheckedInt is an abstract base class, so we actually don't
347 # want to do any processing on it... the rest of this code is
348 # just for classes that derive from CheckedInt.
349 if name
== 'CheckedInt':
352 if not cls
.cxx_predecls
:
353 # most derived types require this, so we just do it here once
354 cls
.cxx_predecls
= ['#include "base/types.hh"']
356 if not cls
.swig_predecls
:
357 # most derived types require this, so we just do it here once
358 cls
.swig_predecls
= ['%import "stdint.i"\n' +
359 '%import "base/types.hh"']
361 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
362 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
363 panic("CheckedInt subclass %s must define either\n" \
364 " 'min' and 'max' or 'size' and 'unsigned'\n",
368 cls
.max = 2 ** cls
.size
- 1
370 cls
.min = -(2 ** (cls
.size
- 1))
371 cls
.max = (2 ** (cls
.size
- 1)) - 1
373 # Abstract superclass for bounds-checked integer parameters. This
374 # class is subclassed to generate parameter classes with specific
375 # bounds. Initialization of the min and max bounds is done in the
376 # metaclass CheckedIntType.__init__.
377 class CheckedInt(NumericParamValue
):
378 __metaclass__
= CheckedIntType
381 if not self
.min <= self
.value
<= self
.max:
382 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
383 (self
.min, self
.value
, self
.max)
385 def __init__(self
, value
):
386 if isinstance(value
, str):
387 self
.value
= convert
.toInteger(value
)
388 elif isinstance(value
, (int, long, float, NumericParamValue
)):
389 self
.value
= long(value
)
391 raise TypeError, "Can't convert object of type %s to CheckedInt" \
392 % type(value
).__name
__
396 return long(self
.value
)
398 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
399 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
401 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
402 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
403 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
404 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
405 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
406 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
407 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
408 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
410 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
411 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
412 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
413 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
415 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
417 class Float(ParamValue
, float):
420 def __init__(self
, value
):
421 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
422 self
.value
= float(value
)
424 raise TypeError, "Can't convert object of type %s to Float" \
425 % type(value
).__name
__
428 return float(self
.value
)
430 class MemorySize(CheckedInt
):
431 cxx_type
= 'uint64_t'
434 def __init__(self
, value
):
435 if isinstance(value
, MemorySize
):
436 self
.value
= value
.value
438 self
.value
= convert
.toMemorySize(value
)
441 class MemorySize32(CheckedInt
):
442 cxx_type
= 'uint32_t'
445 def __init__(self
, value
):
446 if isinstance(value
, MemorySize
):
447 self
.value
= value
.value
449 self
.value
= convert
.toMemorySize(value
)
452 class Addr(CheckedInt
):
456 def __init__(self
, value
):
457 if isinstance(value
, Addr
):
458 self
.value
= value
.value
461 self
.value
= convert
.toMemorySize(value
)
463 self
.value
= long(value
)
465 def __add__(self
, other
):
466 if isinstance(other
, Addr
):
467 return self
.value
+ other
.value
469 return self
.value
+ other
472 class MetaRange(MetaParamValue
):
473 def __init__(cls
, name
, bases
, dict):
474 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
477 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
479 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
481 class Range(ParamValue
):
482 __metaclass__
= MetaRange
483 type = Int
# default; can be overridden in subclasses
484 def __init__(self
, *args
, **kwargs
):
485 def handle_kwargs(self
, kwargs
):
487 self
.second
= self
.type(kwargs
.pop('end'))
488 elif 'size' in kwargs
:
489 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
491 raise TypeError, "Either end or size must be specified"
494 self
.first
= self
.type(kwargs
.pop('start'))
495 handle_kwargs(self
, kwargs
)
499 self
.first
= self
.type(args
[0])
500 handle_kwargs(self
, kwargs
)
501 elif isinstance(args
[0], Range
):
502 self
.first
= self
.type(args
[0].first
)
503 self
.second
= self
.type(args
[0].second
)
504 elif isinstance(args
[0], (list, tuple)):
505 self
.first
= self
.type(args
[0][0])
506 self
.second
= self
.type(args
[0][1])
508 self
.first
= self
.type(0)
509 self
.second
= self
.type(args
[0]) - 1
512 self
.first
= self
.type(args
[0])
513 self
.second
= self
.type(args
[1])
515 raise TypeError, "Too many arguments specified"
518 raise TypeError, "too many keywords: %s" % kwargs
.keys()
521 return '%s:%s' % (self
.first
, self
.second
)
523 class AddrRange(Range
):
525 swig_predecls
= ['%include "python/swig/range.i"']
528 from m5
.objects
.params
import AddrRange
531 value
.start
= long(self
.first
)
532 value
.end
= long(self
.second
)
535 class TickRange(Range
):
537 swig_predecls
= ['%include "python/swig/range.i"']
540 from m5
.objects
.params
import TickRange
543 value
.start
= long(self
.first
)
544 value
.end
= long(self
.second
)
547 # Boolean parameter type. Python doesn't let you subclass bool, since
548 # it doesn't want to let you create multiple instances of True and
549 # False. Thus this is a little more complicated than String.
550 class Bool(ParamValue
):
552 def __init__(self
, value
):
554 self
.value
= convert
.toBool(value
)
556 self
.value
= bool(value
)
559 return bool(self
.value
)
562 return str(self
.value
)
569 def IncEthernetAddr(addr
, val
= 1):
570 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
572 for i
in (5, 4, 3, 2, 1):
573 val
,rem
= divmod(bytes
[i
], 256)
578 assert(bytes
[0] <= 255)
579 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
581 _NextEthernetAddr
= "00:90:00:00:00:01"
582 def NextEthernetAddr():
583 global _NextEthernetAddr
585 value
= _NextEthernetAddr
586 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
589 class EthernetAddr(ParamValue
):
590 cxx_type
= 'Net::EthAddr'
591 cxx_predecls
= ['#include "base/inet.hh"']
592 swig_predecls
= ['%include "python/swig/inet.i"']
593 def __init__(self
, value
):
594 if value
== NextEthernetAddr
:
598 if not isinstance(value
, str):
599 raise TypeError, "expected an ethernet address and didn't get one"
601 bytes
= value
.split(':')
603 raise TypeError, 'invalid ethernet address %s' % value
606 if not 0 <= int(byte
) <= 256:
607 raise TypeError, 'invalid ethernet address %s' % value
611 def unproxy(self
, base
):
612 if self
.value
== NextEthernetAddr
:
613 return EthernetAddr(self
.value())
617 from m5
.objects
.params
import EthAddr
618 return EthAddr(self
.value
)
623 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
624 "%a %b %d %H:%M:%S %Z %Y",
636 def parse_time(value
):
637 from time
import gmtime
, strptime
, struct_time
, time
638 from datetime
import datetime
, date
640 if isinstance(value
, struct_time
):
643 if isinstance(value
, (int, long)):
646 if isinstance(value
, (datetime
, date
)):
647 return value
.timetuple()
649 if isinstance(value
, str):
650 if value
in ('Now', 'Today'):
651 return time
.gmtime(time
.time())
653 for format
in time_formats
:
655 return strptime(value
, format
)
659 raise ValueError, "Could not parse '%s' as a time" % value
661 class Time(ParamValue
):
663 cxx_predecls
= [ '#include <time.h>' ]
664 swig_predecls
= [ '%include "python/swig/time.i"' ]
665 def __init__(self
, value
):
666 self
.value
= parse_time(value
)
669 from m5
.objects
.params
import tm
674 # UNIX is years since 1900
675 c_time
.tm_year
= py_time
.tm_year
- 1900;
677 # Python starts at 1, UNIX starts at 0
678 c_time
.tm_mon
= py_time
.tm_mon
- 1;
679 c_time
.tm_mday
= py_time
.tm_mday
;
680 c_time
.tm_hour
= py_time
.tm_hour
;
681 c_time
.tm_min
= py_time
.tm_min
;
682 c_time
.tm_sec
= py_time
.tm_sec
;
684 # Python has 0 as Monday, UNIX is 0 as sunday
685 c_time
.tm_wday
= py_time
.tm_wday
+ 1
686 if c_time
.tm_wday
> 6:
689 # Python starts at 1, Unix starts at 0
690 c_time
.tm_yday
= py_time
.tm_yday
- 1;
695 return time
.asctime(self
.value
)
700 # Enumerated types are a little more complex. The user specifies the
701 # type as Enum(foo) where foo is either a list or dictionary of
702 # alternatives (typically strings, but not necessarily so). (In the
703 # long run, the integer value of the parameter will be the list index
704 # or the corresponding dictionary value. For now, since we only check
705 # that the alternative is valid and then spit it into a .ini file,
706 # there's not much point in using the dictionary.)
708 # What Enum() must do is generate a new type encapsulating the
709 # provided list/dictionary so that specific values of the parameter
710 # can be instances of that type. We define two hidden internal
711 # classes (_ListEnum and _DictEnum) to serve as base classes, then
712 # derive the new type from the appropriate base class on the fly.
715 # Metaclass for Enum types
716 class MetaEnum(MetaParamValue
):
717 def __new__(mcls
, name
, bases
, dict):
718 assert name
not in allEnums
720 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
724 def __init__(cls
, name
, bases
, init_dict
):
725 if init_dict
.has_key('map'):
726 if not isinstance(cls
.map, dict):
727 raise TypeError, "Enum-derived class attribute 'map' " \
728 "must be of type dict"
729 # build list of value strings from map
730 cls
.vals
= cls
.map.keys()
732 elif init_dict
.has_key('vals'):
733 if not isinstance(cls
.vals
, list):
734 raise TypeError, "Enum-derived class attribute 'vals' " \
735 "must be of type list"
736 # build string->value map from vals sequence
738 for idx
,val
in enumerate(cls
.vals
):
741 raise TypeError, "Enum-derived class must define "\
742 "attribute 'map' or 'vals'"
744 cls
.cxx_type
= 'Enums::%s' % name
746 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
748 # Generate C++ class declaration for this enum type.
749 # Note that we wrap the enum in a class/struct to act as a namespace,
750 # so that the enum strings can be brief w/o worrying about collisions.
753 code
= "#ifndef __ENUM__%s\n" % name
754 code
+= '#define __ENUM__%s\n' % name
756 code
+= 'namespace Enums {\n'
757 code
+= ' enum %s {\n' % name
759 code
+= ' %s = %d,\n' % (val
, cls
.map[val
])
760 code
+= ' Num_%s = %d,\n' % (name
, len(cls
.vals
))
762 code
+= ' extern const char *%sStrings[Num_%s];\n' % (name
, name
)
770 code
= '#include "enums/%s.hh"\n' % name
771 code
+= 'namespace Enums {\n'
772 code
+= ' const char *%sStrings[Num_%s] =\n' % (name
, name
)
775 code
+= ' "%s",\n' % val
780 # Base class for enum types.
781 class Enum(ParamValue
):
782 __metaclass__
= MetaEnum
785 def __init__(self
, value
):
786 if value
not in self
.map:
787 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
792 return int(self
.map[self
.value
])
797 # how big does a rounding error need to be before we warn about it?
798 frequency_tolerance
= 0.001 # 0.1%
800 class TickParamValue(NumericParamValue
):
802 cxx_predecls
= ['#include "base/types.hh"']
803 swig_predecls
= ['%import "stdint.i"\n' +
804 '%import "base/types.hh"']
807 return long(self
.value
)
809 class Latency(TickParamValue
):
810 def __init__(self
, value
):
811 if isinstance(value
, (Latency
, Clock
)):
812 self
.ticks
= value
.ticks
813 self
.value
= value
.value
814 elif isinstance(value
, Frequency
):
815 self
.ticks
= value
.ticks
816 self
.value
= 1.0 / value
.value
817 elif value
.endswith('t'):
819 self
.value
= int(value
[:-1])
822 self
.value
= convert
.toLatency(value
)
824 def __getattr__(self
, attr
):
825 if attr
in ('latency', 'period'):
827 if attr
== 'frequency':
828 return Frequency(self
)
829 raise AttributeError, "Latency object has no attribute '%s'" % attr
832 if self
.ticks
or self
.value
== 0:
835 value
= ticks
.fromSeconds(self
.value
)
838 # convert latency to ticks
840 return '%d' % self
.getValue()
842 class Frequency(TickParamValue
):
843 def __init__(self
, value
):
844 if isinstance(value
, (Latency
, Clock
)):
848 self
.value
= 1.0 / value
.value
849 self
.ticks
= value
.ticks
850 elif isinstance(value
, Frequency
):
851 self
.value
= value
.value
852 self
.ticks
= value
.ticks
855 self
.value
= convert
.toFrequency(value
)
857 def __getattr__(self
, attr
):
858 if attr
== 'frequency':
860 if attr
in ('latency', 'period'):
862 raise AttributeError, "Frequency object has no attribute '%s'" % attr
864 # convert latency to ticks
866 if self
.ticks
or self
.value
== 0:
869 value
= ticks
.fromSeconds(1.0 / self
.value
)
873 return '%d' % self
.getValue()
875 # A generic frequency and/or Latency value. Value is stored as a latency,
876 # but to avoid ambiguity this object does not support numeric ops (* or /).
877 # An explicit conversion to a Latency or Frequency must be made first.
878 class Clock(ParamValue
):
880 cxx_predecls
= ['#include "base/types.hh"']
881 swig_predecls
= ['%import "stdint.i"\n' +
882 '%import "base/types.hh"']
883 def __init__(self
, value
):
884 if isinstance(value
, (Latency
, Clock
)):
885 self
.ticks
= value
.ticks
886 self
.value
= value
.value
887 elif isinstance(value
, Frequency
):
888 self
.ticks
= value
.ticks
889 self
.value
= 1.0 / value
.value
890 elif value
.endswith('t'):
892 self
.value
= int(value
[:-1])
895 self
.value
= convert
.anyToLatency(value
)
897 def __getattr__(self
, attr
):
898 if attr
== 'frequency':
899 return Frequency(self
)
900 if attr
in ('latency', 'period'):
902 raise AttributeError, "Frequency object has no attribute '%s'" % attr
905 return self
.period
.getValue()
908 return self
.period
.ini_str()
910 class NetworkBandwidth(float,ParamValue
):
912 def __new__(cls
, value
):
913 # convert to bits per second
914 val
= convert
.toNetworkBandwidth(value
)
915 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
921 # convert to seconds per byte
922 value
= 8.0 / float(self
)
923 # convert to ticks per byte
924 value
= ticks
.fromSeconds(value
)
928 return '%f' % self
.getValue()
930 class MemoryBandwidth(float,ParamValue
):
932 def __new__(cls
, value
):
933 # we want the number of ticks per byte of data
934 val
= convert
.toMemoryBandwidth(value
)
935 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
941 # convert to seconds per byte
944 value
= 1.0 / float(self
)
945 # convert to ticks per byte
946 value
= ticks
.fromSeconds(value
)
950 return '%f' % self
.getValue()
953 # "Constants"... handy aliases for various values.
956 # Special class for NULL pointers. Note the special check in
957 # make_param_value() above that lets these be assigned where a
958 # SimObject is required.
959 # only one copy of a particular node
960 class NullSimObject(object):
961 __metaclass__
= Singleton
966 def _instantiate(self
, parent
= None, path
= ''):
972 def unproxy(self
, base
):
975 def set_path(self
, parent
, name
):
984 # The only instance you'll ever need...
985 NULL
= NullSimObject()
987 def isNullPointer(value
):
988 return isinstance(value
, NullSimObject
)
990 # Some memory range specifications use this as a default upper bound.
993 AllMemory
= AddrRange(0, MaxAddr
)
996 #####################################################################
1000 # Ports are used to interconnect objects in the memory system.
1002 #####################################################################
1004 # Port reference: encapsulates a reference to a particular port on a
1005 # particular SimObject.
1006 class PortRef(object):
1007 def __init__(self
, simobj
, name
):
1008 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1009 self
.simobj
= simobj
1011 self
.peer
= None # not associated with another port yet
1012 self
.ccConnected
= False # C++ port connection done?
1013 self
.index
= -1 # always -1 for non-vector ports
1016 return '%s.%s' % (self
.simobj
, self
.name
)
1018 # for config.ini, print peer's name (not ours)
1020 return str(self
.peer
)
1022 def __getattr__(self
, attr
):
1023 if attr
== 'peerObj':
1024 # shorthand for proxies
1025 return self
.peer
.simobj
1026 raise AttributeError, "'%s' object has no attribute '%s'" % \
1027 (self
.__class
__.__name
__, attr
)
1029 # Full connection is symmetric (both ways). Called via
1030 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1031 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1032 # e.g., "obj1.portA[3] = obj2.portB".
1033 def connect(self
, other
):
1034 if isinstance(other
, VectorPortRef
):
1035 # reference to plain VectorPort is implicit append
1036 other
= other
._get
_next
()
1037 if self
.peer
and not proxy
.isproxy(self
.peer
):
1038 print "warning: overwriting port", self
, \
1039 "value", self
.peer
, "with", other
1040 self
.peer
.peer
= None
1042 if proxy
.isproxy(other
):
1043 other
.set_param_desc(PortParamDesc())
1044 elif isinstance(other
, PortRef
):
1045 if other
.peer
is not self
:
1049 "assigning non-port reference '%s' to port '%s'" \
1052 def clone(self
, simobj
, memo
):
1053 if memo
.has_key(self
):
1055 newRef
= copy
.copy(self
)
1057 newRef
.simobj
= simobj
1058 assert(isSimObject(newRef
.simobj
))
1059 if self
.peer
and not proxy
.isproxy(self
.peer
):
1060 peerObj
= self
.peer
.simobj(_memo
=memo
)
1061 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1062 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1065 def unproxy(self
, simobj
):
1066 assert(simobj
is self
.simobj
)
1067 if proxy
.isproxy(self
.peer
):
1069 realPeer
= self
.peer
.unproxy(self
.simobj
)
1071 print "Error in unproxying port '%s' of %s" % \
1072 (self
.name
, self
.simobj
.path())
1074 self
.connect(realPeer
)
1076 # Call C++ to create corresponding port connection between C++ objects
1077 def ccConnect(self
):
1078 from m5
.objects
.params
import connectPorts
1080 if self
.ccConnected
: # already done this
1083 if not self
.peer
: # nothing to connect to
1086 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1087 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1089 print "Error connecting port %s.%s to %s.%s" % \
1090 (self
.simobj
.path(), self
.name
,
1091 peer
.simobj
.path(), peer
.name
)
1093 self
.ccConnected
= True
1094 peer
.ccConnected
= True
1096 # A reference to an individual element of a VectorPort... much like a
1097 # PortRef, but has an index.
1098 class VectorPortElementRef(PortRef
):
1099 def __init__(self
, simobj
, name
, index
):
1100 PortRef
.__init
__(self
, simobj
, name
)
1104 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1106 # A reference to a complete vector-valued port (not just a single element).
1107 # Can be indexed to retrieve individual VectorPortElementRef instances.
1108 class VectorPortRef(object):
1109 def __init__(self
, simobj
, name
):
1110 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1111 self
.simobj
= simobj
1116 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1118 # for config.ini, print peer's name (not ours)
1120 return ' '.join([el
.ini_str() for el
in self
.elements
])
1122 def __getitem__(self
, key
):
1123 if not isinstance(key
, int):
1124 raise TypeError, "VectorPort index must be integer"
1125 if key
>= len(self
.elements
):
1126 # need to extend list
1127 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1128 for i
in range(len(self
.elements
), key
+1)]
1129 self
.elements
.extend(ext
)
1130 return self
.elements
[key
]
1132 def _get_next(self
):
1133 return self
[len(self
.elements
)]
1135 def __setitem__(self
, key
, value
):
1136 if not isinstance(key
, int):
1137 raise TypeError, "VectorPort index must be integer"
1138 self
[key
].connect(value
)
1140 def connect(self
, other
):
1141 if isinstance(other
, (list, tuple)):
1142 # Assign list of port refs to vector port.
1143 # For now, append them... not sure if that's the right semantics
1144 # or if it should replace the current vector.
1146 self
._get
_next
().connect(ref
)
1148 # scalar assignment to plain VectorPort is implicit append
1149 self
._get
_next
().connect(other
)
1151 def clone(self
, simobj
, memo
):
1152 if memo
.has_key(self
):
1154 newRef
= copy
.copy(self
)
1156 newRef
.simobj
= simobj
1157 assert(isSimObject(newRef
.simobj
))
1158 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1161 def unproxy(self
, simobj
):
1162 [el
.unproxy(simobj
) for el
in self
.elements
]
1164 def ccConnect(self
):
1165 [el
.ccConnect() for el
in self
.elements
]
1167 # Port description object. Like a ParamDesc object, this represents a
1168 # logical port in the SimObject class, not a particular port on a
1169 # SimObject instance. The latter are represented by PortRef objects.
1171 # Port("description") or Port(default, "description")
1172 def __init__(self
, *args
):
1175 elif len(args
) == 2:
1176 self
.default
= args
[0]
1179 raise TypeError, 'wrong number of arguments'
1180 # self.name is set by SimObject class on assignment
1181 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1183 # Generate a PortRef for this port on the given SimObject with the
1185 def makeRef(self
, simobj
):
1186 return PortRef(simobj
, self
.name
)
1188 # Connect an instance of this port (on the given SimObject with
1189 # the given name) with the port described by the supplied PortRef
1190 def connect(self
, simobj
, ref
):
1191 self
.makeRef(simobj
).connect(ref
)
1193 # VectorPort description object. Like Port, but represents a vector
1194 # of connections (e.g., as on a Bus).
1195 class VectorPort(Port
):
1196 def __init__(self
, *args
):
1197 Port
.__init
__(self
, *args
)
1200 def makeRef(self
, simobj
):
1201 return VectorPortRef(simobj
, self
.name
)
1203 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1204 # proxy objects (via set_param_desc()) so that proxy error messages
1206 class PortParamDesc(object):
1207 __metaclass__
= Singleton
1212 baseEnums
= allEnums
.copy()
1213 baseParams
= allParams
.copy()
1216 global allEnums
, allParams
1218 allEnums
= baseEnums
.copy()
1219 allParams
= baseParams
.copy()
1221 __all__
= ['Param', 'VectorParam',
1222 'Enum', 'Bool', 'String', 'Float',
1223 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1224 'Int32', 'UInt32', 'Int64', 'UInt64',
1225 'Counter', 'Addr', 'Tick', 'Percent',
1226 'TcpPort', 'UdpPort', 'EthernetAddr',
1227 'MemorySize', 'MemorySize32',
1228 'Latency', 'Frequency', 'Clock',
1229 'NetworkBandwidth', 'MemoryBandwidth',
1230 'Range', 'AddrRange', 'TickRange',
1231 'MaxAddr', 'MaxTick', 'AllMemory',
1233 'NextEthernetAddr', 'NULL',
1234 'Port', 'VectorPort']