1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
2 # Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # Authors: Steve Reinhardt
32 #####################################################################
34 # Parameter description classes
36 # The _params dictionary in each class maps parameter names to either
37 # a Param or a VectorParam object. These objects contain the
38 # parameter description string, the parameter type, and the default
39 # value (if any). The convert() method on these objects is used to
40 # force whatever value is assigned to the parameter to the appropriate
43 # Note that the default values are loaded into the class's attribute
44 # space when the parameter dictionary is initialized (in
45 # MetaSimObject._new_param()); after that point they aren't used.
47 #####################################################################
60 def isSimObject(*args
, **kwargs
):
61 return SimObject
.isSimObject(*args
, **kwargs
)
63 def isSimObjectSequence(*args
, **kwargs
):
64 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
66 def isSimObjectClass(*args
, **kwargs
):
67 return SimObject
.isSimObjectClass(*args
, **kwargs
)
71 class MetaParamValue(type):
72 def __new__(mcls
, name
, bases
, dct
):
73 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
74 assert name
not in allParams
79 # Dummy base class to identify types that are legitimate for SimObject
81 class ParamValue(object):
82 __metaclass__
= MetaParamValue
85 # Generate the code needed as a prerequisite for declaring a C++
86 # object of this type. Typically generates one or more #include
87 # statements. Used when declaring parameters of this type.
89 def cxx_predecls(cls
, code
):
92 # Generate the code needed as a prerequisite for including a
93 # reference to a C++ object of this type in a SWIG .i file.
94 # Typically generates one or more %import or %include statements.
96 def swig_predecls(cls
, code
):
99 # default for printing to .ini file is regular string conversion.
100 # will be overridden in some cases
104 # allows us to blithely call unproxy() on things without checking
105 # if they're really proxies or not
106 def unproxy(self
, base
):
109 # Regular parameter description.
110 class ParamDesc(object):
111 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
112 self
.ptype_str
= ptype_str
113 # remember ptype only if it is provided
121 self
.default
= args
[0]
124 raise TypeError, 'too many arguments'
126 if kwargs
.has_key('desc'):
127 assert(not hasattr(self
, 'desc'))
128 self
.desc
= kwargs
['desc']
131 if kwargs
.has_key('default'):
132 assert(not hasattr(self
, 'default'))
133 self
.default
= kwargs
['default']
134 del kwargs
['default']
137 raise TypeError, 'extra unknown kwargs %s' % kwargs
139 if not hasattr(self
, 'desc'):
140 raise TypeError, 'desc attribute missing'
142 def __getattr__(self
, attr
):
144 ptype
= SimObject
.allClasses
[self
.ptype_str
]
145 assert isSimObjectClass(ptype
)
149 raise AttributeError, "'%s' object has no attribute '%s'" % \
150 (type(self
).__name
__, attr
)
152 def convert(self
, value
):
153 if isinstance(value
, proxy
.BaseProxy
):
154 value
.set_param_desc(self
)
156 if not hasattr(self
, 'ptype') and isNullPointer(value
):
157 # deferred evaluation of SimObject; continue to defer if
158 # we're just assigning a null pointer
160 if isinstance(value
, self
.ptype
):
162 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
164 return self
.ptype(value
)
166 def cxx_predecls(self
, code
):
167 code('#include <cstddef>')
168 self
.ptype
.cxx_predecls(code
)
170 def swig_predecls(self
, code
):
171 self
.ptype
.swig_predecls(code
)
173 def cxx_decl(self
, code
):
174 code('${{self.ptype.cxx_type}} ${{self.name}};')
176 # Vector-valued parameter description. Just like ParamDesc, except
177 # that the value is a vector (list) of the specified type instead of a
180 class VectorParamValue(list):
181 __metaclass__
= MetaParamValue
182 def __setattr__(self
, attr
, value
):
183 raise AttributeError, \
184 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
187 return ' '.join([v
.ini_str() for v
in self
])
190 return [ v
.getValue() for v
in self
]
192 def unproxy(self
, base
):
193 if len(self
) == 1 and isinstance(self
[0], proxy
.AllProxy
):
194 return self
[0].unproxy(base
)
196 return [v
.unproxy(base
) for v
in self
]
198 class SimObjectVector(VectorParamValue
):
199 # support clone operation
200 def __call__(self
, **kwargs
):
201 return SimObjectVector([v(**kwargs
) for v
in self
])
203 def clear_parent(self
, old_parent
):
205 v
.clear_parent(old_parent
)
207 def set_parent(self
, parent
, name
):
209 self
[0].set_parent(parent
, name
)
211 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
212 for i
,v
in enumerate(self
):
213 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
215 def has_parent(self
):
216 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
218 # return 'cpu0 cpu1' etc. for print_ini()
220 return ' '.join([v
._name
for v
in self
])
222 # By iterating through the constituent members of the vector here
223 # we can nicely handle iterating over all a SimObject's children
224 # without having to provide lots of special functions on
225 # SimObjectVector directly.
226 def descendants(self
):
228 for obj
in v
.descendants():
231 def get_config_as_dict(self
):
234 a
.append(v
.get_config_as_dict())
237 class VectorParamDesc(ParamDesc
):
238 # Convert assigned value to appropriate type. If the RHS is not a
239 # list or tuple, it generates a single-element list.
240 def convert(self
, value
):
241 if isinstance(value
, (list, tuple)):
242 # list: coerce each element into new list
243 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
245 # singleton: coerce to a single-element list
246 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
248 if isSimObjectSequence(tmp_list
):
249 return SimObjectVector(tmp_list
)
251 return VectorParamValue(tmp_list
)
253 def swig_module_name(self
):
254 return "%s_vector" % self
.ptype_str
256 def swig_predecls(self
, code
):
257 code('%import "${{self.swig_module_name()}}.i"')
259 def swig_decl(self
, code
):
260 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
262 self
.ptype
.cxx_predecls(code
)
265 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
266 code('%include "std_container.i"')
268 self
.ptype
.swig_predecls(code
)
270 code('%include "std_vector.i"')
273 ptype
= self
.ptype_str
274 cxx_type
= self
.ptype
.cxx_type
277 %typemap(in) std::vector< $cxx_type >::value_type {
278 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
279 if (SWIG_ConvertPtr($$input, (void **)&$$1,
280 $$descriptor($cxx_type), 0) == -1) {
286 %typemap(in) std::vector< $cxx_type >::value_type * {
287 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
288 if (SWIG_ConvertPtr($$input, (void **)&$$1,
289 $$descriptor($cxx_type *), 0) == -1) {
296 code('%template(vector_$ptype) std::vector< $cxx_type >;')
298 def cxx_predecls(self
, code
):
299 code('#include <vector>')
300 self
.ptype
.cxx_predecls(code
)
302 def cxx_decl(self
, code
):
303 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
305 class ParamFactory(object):
306 def __init__(self
, param_desc_class
, ptype_str
= None):
307 self
.param_desc_class
= param_desc_class
308 self
.ptype_str
= ptype_str
310 def __getattr__(self
, attr
):
312 attr
= self
.ptype_str
+ '.' + attr
313 return ParamFactory(self
.param_desc_class
, attr
)
315 # E.g., Param.Int(5, "number of widgets")
316 def __call__(self
, *args
, **kwargs
):
319 ptype
= allParams
[self
.ptype_str
]
321 # if name isn't defined yet, assume it's a SimObject, and
322 # try to resolve it later
324 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
326 Param
= ParamFactory(ParamDesc
)
327 VectorParam
= ParamFactory(VectorParamDesc
)
329 #####################################################################
333 # Though native Python types could be used to specify parameter types
334 # (the 'ptype' field of the Param and VectorParam classes), it's more
335 # flexible to define our own set of types. This gives us more control
336 # over how Python expressions are converted to values (via the
337 # __init__() constructor) and how these values are printed out (via
338 # the __str__() conversion method).
340 #####################################################################
342 # String-valued parameter. Just mixin the ParamValue class with the
343 # built-in str class.
344 class String(ParamValue
,str):
345 cxx_type
= 'std::string'
348 def cxx_predecls(self
, code
):
349 code('#include <string>')
352 def swig_predecls(cls
, code
):
353 code('%include "std_string.i"')
358 # superclass for "numeric" parameter values, to emulate math
359 # operations in a type-safe way. e.g., a Latency times an int returns
360 # a new Latency object.
361 class NumericParamValue(ParamValue
):
363 return str(self
.value
)
366 return float(self
.value
)
369 return long(self
.value
)
372 return int(self
.value
)
374 # hook for bounds checking
378 def __mul__(self
, other
):
379 newobj
= self
.__class
__(self
)
380 newobj
.value
*= other
386 def __div__(self
, other
):
387 newobj
= self
.__class
__(self
)
388 newobj
.value
/= other
392 def __sub__(self
, other
):
393 newobj
= self
.__class
__(self
)
394 newobj
.value
-= other
398 # Metaclass for bounds-checked integer parameters. See CheckedInt.
399 class CheckedIntType(MetaParamValue
):
400 def __init__(cls
, name
, bases
, dict):
401 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
403 # CheckedInt is an abstract base class, so we actually don't
404 # want to do any processing on it... the rest of this code is
405 # just for classes that derive from CheckedInt.
406 if name
== 'CheckedInt':
409 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
410 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
411 panic("CheckedInt subclass %s must define either\n" \
412 " 'min' and 'max' or 'size' and 'unsigned'\n",
416 cls
.max = 2 ** cls
.size
- 1
418 cls
.min = -(2 ** (cls
.size
- 1))
419 cls
.max = (2 ** (cls
.size
- 1)) - 1
421 # Abstract superclass for bounds-checked integer parameters. This
422 # class is subclassed to generate parameter classes with specific
423 # bounds. Initialization of the min and max bounds is done in the
424 # metaclass CheckedIntType.__init__.
425 class CheckedInt(NumericParamValue
):
426 __metaclass__
= CheckedIntType
429 if not self
.min <= self
.value
<= self
.max:
430 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
431 (self
.min, self
.value
, self
.max)
433 def __init__(self
, value
):
434 if isinstance(value
, str):
435 self
.value
= convert
.toInteger(value
)
436 elif isinstance(value
, (int, long, float, NumericParamValue
)):
437 self
.value
= long(value
)
439 raise TypeError, "Can't convert object of type %s to CheckedInt" \
440 % type(value
).__name
__
444 def cxx_predecls(cls
, code
):
445 # most derived types require this, so we just do it here once
446 code('#include "base/types.hh"')
449 def swig_predecls(cls
, code
):
450 # most derived types require this, so we just do it here once
451 code('%import "stdint.i"')
452 code('%import "base/types.hh"')
455 return long(self
.value
)
457 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
458 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
460 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
461 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
462 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
463 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
464 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
465 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
466 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
467 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
469 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
470 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
471 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
472 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
474 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
476 class Float(ParamValue
, float):
479 def __init__(self
, value
):
480 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
481 self
.value
= float(value
)
483 raise TypeError, "Can't convert object of type %s to Float" \
484 % type(value
).__name
__
487 return float(self
.value
)
489 class MemorySize(CheckedInt
):
490 cxx_type
= 'uint64_t'
493 def __init__(self
, value
):
494 if isinstance(value
, MemorySize
):
495 self
.value
= value
.value
497 self
.value
= convert
.toMemorySize(value
)
500 class MemorySize32(CheckedInt
):
501 cxx_type
= 'uint32_t'
504 def __init__(self
, value
):
505 if isinstance(value
, MemorySize
):
506 self
.value
= value
.value
508 self
.value
= convert
.toMemorySize(value
)
511 class Addr(CheckedInt
):
515 def __init__(self
, value
):
516 if isinstance(value
, Addr
):
517 self
.value
= value
.value
520 self
.value
= convert
.toMemorySize(value
)
522 self
.value
= long(value
)
524 def __add__(self
, other
):
525 if isinstance(other
, Addr
):
526 return self
.value
+ other
.value
528 return self
.value
+ other
531 class MetaRange(MetaParamValue
):
532 def __init__(cls
, name
, bases
, dict):
533 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
536 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
538 class Range(ParamValue
):
539 __metaclass__
= MetaRange
540 type = Int
# default; can be overridden in subclasses
541 def __init__(self
, *args
, **kwargs
):
542 def handle_kwargs(self
, kwargs
):
544 self
.second
= self
.type(kwargs
.pop('end'))
545 elif 'size' in kwargs
:
546 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
548 raise TypeError, "Either end or size must be specified"
551 self
.first
= self
.type(kwargs
.pop('start'))
552 handle_kwargs(self
, kwargs
)
556 self
.first
= self
.type(args
[0])
557 handle_kwargs(self
, kwargs
)
558 elif isinstance(args
[0], Range
):
559 self
.first
= self
.type(args
[0].first
)
560 self
.second
= self
.type(args
[0].second
)
561 elif isinstance(args
[0], (list, tuple)):
562 self
.first
= self
.type(args
[0][0])
563 self
.second
= self
.type(args
[0][1])
565 self
.first
= self
.type(0)
566 self
.second
= self
.type(args
[0]) - 1
569 self
.first
= self
.type(args
[0])
570 self
.second
= self
.type(args
[1])
572 raise TypeError, "Too many arguments specified"
575 raise TypeError, "too many keywords: %s" % kwargs
.keys()
578 return '%s:%s' % (self
.first
, self
.second
)
581 def cxx_predecls(cls
, code
):
582 cls
.type.cxx_predecls(code
)
583 code('#include "base/range.hh"')
586 def swig_predecls(cls
, code
):
587 cls
.type.swig_predecls(code
)
588 code('%import "python/swig/range.i"')
590 class AddrRange(Range
):
594 from m5
.internal
.range import AddrRange
597 value
.start
= long(self
.first
)
598 value
.end
= long(self
.second
)
601 class TickRange(Range
):
605 from m5
.internal
.range import TickRange
608 value
.start
= long(self
.first
)
609 value
.end
= long(self
.second
)
612 # Boolean parameter type. Python doesn't let you subclass bool, since
613 # it doesn't want to let you create multiple instances of True and
614 # False. Thus this is a little more complicated than String.
615 class Bool(ParamValue
):
617 def __init__(self
, value
):
619 self
.value
= convert
.toBool(value
)
621 self
.value
= bool(value
)
624 return bool(self
.value
)
627 return str(self
.value
)
634 def IncEthernetAddr(addr
, val
= 1):
635 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
637 for i
in (5, 4, 3, 2, 1):
638 val
,rem
= divmod(bytes
[i
], 256)
643 assert(bytes
[0] <= 255)
644 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
646 _NextEthernetAddr
= "00:90:00:00:00:01"
647 def NextEthernetAddr():
648 global _NextEthernetAddr
650 value
= _NextEthernetAddr
651 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
654 class EthernetAddr(ParamValue
):
655 cxx_type
= 'Net::EthAddr'
658 def cxx_predecls(cls
, code
):
659 code('#include "base/inet.hh"')
662 def swig_predecls(cls
, code
):
663 code('%include "python/swig/inet.i"')
665 def __init__(self
, value
):
666 if value
== NextEthernetAddr
:
670 if not isinstance(value
, str):
671 raise TypeError, "expected an ethernet address and didn't get one"
673 bytes
= value
.split(':')
675 raise TypeError, 'invalid ethernet address %s' % value
678 if not 0 <= int(byte
) <= 0xff:
679 raise TypeError, 'invalid ethernet address %s' % value
683 def unproxy(self
, base
):
684 if self
.value
== NextEthernetAddr
:
685 return EthernetAddr(self
.value())
689 from m5
.internal
.params
import EthAddr
690 return EthAddr(self
.value
)
695 # When initializing an IpAddress, pass in an existing IpAddress, a string of
696 # the form "a.b.c.d", or an integer representing an IP.
697 class IpAddress(ParamValue
):
698 cxx_type
= 'Net::IpAddress'
701 def cxx_predecls(cls
, code
):
702 code('#include "base/inet.hh"')
705 def swig_predecls(cls
, code
):
706 code('%include "python/swig/inet.i"')
708 def __init__(self
, value
):
709 if isinstance(value
, IpAddress
):
713 self
.ip
= convert
.toIpAddress(value
)
715 self
.ip
= long(value
)
719 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
720 return '%d.%d.%d.%d' % tuple(tup
)
722 def __eq__(self
, other
):
723 if isinstance(other
, IpAddress
):
724 return self
.ip
== other
.ip
725 elif isinstance(other
, str):
727 return self
.ip
== convert
.toIpAddress(other
)
731 return self
.ip
== other
733 def __ne__(self
, other
):
734 return not (self
== other
)
737 if self
.ip
< 0 or self
.ip
>= (1 << 32):
738 raise TypeError, "invalid ip address %#08x" % self
.ip
741 from m5
.internal
.params
import IpAddress
742 return IpAddress(self
.ip
)
744 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
745 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
746 # positional or keyword arguments.
747 class IpNetmask(IpAddress
):
748 cxx_type
= 'Net::IpNetmask'
751 def cxx_predecls(cls
, code
):
752 code('#include "base/inet.hh"')
755 def swig_predecls(cls
, code
):
756 code('%include "python/swig/inet.i"')
758 def __init__(self
, *args
, **kwargs
):
759 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
761 setattr(self
, key
, kwargs
.pop(key
))
763 setattr(self
, key
, elseVal
)
765 raise TypeError, "No value set for %s" % key
768 handle_kwarg(self
, kwargs
, 'ip')
769 handle_kwarg(self
, kwargs
, 'netmask')
773 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
774 raise TypeError, "Invalid arguments"
775 handle_kwarg(self
, kwargs
, 'ip', args
[0])
776 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
777 elif isinstance(args
[0], IpNetmask
):
779 self
.netmask
= args
[0].netmask
781 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
785 self
.netmask
= args
[1]
787 raise TypeError, "Too many arguments specified"
790 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
795 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
797 def __eq__(self
, other
):
798 if isinstance(other
, IpNetmask
):
799 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
800 elif isinstance(other
, str):
802 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
810 if self
.netmask
< 0 or self
.netmask
> 32:
811 raise TypeError, "invalid netmask %d" % netmask
814 from m5
.internal
.params
import IpNetmask
815 return IpNetmask(self
.ip
, self
.netmask
)
817 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
818 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
819 class IpWithPort(IpAddress
):
820 cxx_type
= 'Net::IpWithPort'
823 def cxx_predecls(cls
, code
):
824 code('#include "base/inet.hh"')
827 def swig_predecls(cls
, code
):
828 code('%include "python/swig/inet.i"')
830 def __init__(self
, *args
, **kwargs
):
831 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
833 setattr(self
, key
, kwargs
.pop(key
))
835 setattr(self
, key
, elseVal
)
837 raise TypeError, "No value set for %s" % key
840 handle_kwarg(self
, kwargs
, 'ip')
841 handle_kwarg(self
, kwargs
, 'port')
845 if not 'ip' in kwargs
and not 'port' in kwargs
:
846 raise TypeError, "Invalid arguments"
847 handle_kwarg(self
, kwargs
, 'ip', args
[0])
848 handle_kwarg(self
, kwargs
, 'port', args
[0])
849 elif isinstance(args
[0], IpWithPort
):
851 self
.port
= args
[0].port
853 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
859 raise TypeError, "Too many arguments specified"
862 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
867 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
869 def __eq__(self
, other
):
870 if isinstance(other
, IpWithPort
):
871 return self
.ip
== other
.ip
and self
.port
== other
.port
872 elif isinstance(other
, str):
874 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
882 if self
.port
< 0 or self
.port
> 0xffff:
883 raise TypeError, "invalid port %d" % self
.port
886 from m5
.internal
.params
import IpWithPort
887 return IpWithPort(self
.ip
, self
.port
)
889 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
890 "%a %b %d %H:%M:%S %Z %Y",
902 def parse_time(value
):
903 from time
import gmtime
, strptime
, struct_time
, time
904 from datetime
import datetime
, date
906 if isinstance(value
, struct_time
):
909 if isinstance(value
, (int, long)):
912 if isinstance(value
, (datetime
, date
)):
913 return value
.timetuple()
915 if isinstance(value
, str):
916 if value
in ('Now', 'Today'):
917 return time
.gmtime(time
.time())
919 for format
in time_formats
:
921 return strptime(value
, format
)
925 raise ValueError, "Could not parse '%s' as a time" % value
927 class Time(ParamValue
):
931 def cxx_predecls(cls
, code
):
932 code('#include <time.h>')
935 def swig_predecls(cls
, code
):
936 code('%include "python/swig/time.i"')
938 def __init__(self
, value
):
939 self
.value
= parse_time(value
)
942 from m5
.internal
.params
import tm
947 # UNIX is years since 1900
948 c_time
.tm_year
= py_time
.tm_year
- 1900;
950 # Python starts at 1, UNIX starts at 0
951 c_time
.tm_mon
= py_time
.tm_mon
- 1;
952 c_time
.tm_mday
= py_time
.tm_mday
;
953 c_time
.tm_hour
= py_time
.tm_hour
;
954 c_time
.tm_min
= py_time
.tm_min
;
955 c_time
.tm_sec
= py_time
.tm_sec
;
957 # Python has 0 as Monday, UNIX is 0 as sunday
958 c_time
.tm_wday
= py_time
.tm_wday
+ 1
959 if c_time
.tm_wday
> 6:
962 # Python starts at 1, Unix starts at 0
963 c_time
.tm_yday
= py_time
.tm_yday
- 1;
968 return time
.asctime(self
.value
)
973 def get_config_as_dict(self
):
976 # Enumerated types are a little more complex. The user specifies the
977 # type as Enum(foo) where foo is either a list or dictionary of
978 # alternatives (typically strings, but not necessarily so). (In the
979 # long run, the integer value of the parameter will be the list index
980 # or the corresponding dictionary value. For now, since we only check
981 # that the alternative is valid and then spit it into a .ini file,
982 # there's not much point in using the dictionary.)
984 # What Enum() must do is generate a new type encapsulating the
985 # provided list/dictionary so that specific values of the parameter
986 # can be instances of that type. We define two hidden internal
987 # classes (_ListEnum and _DictEnum) to serve as base classes, then
988 # derive the new type from the appropriate base class on the fly.
991 # Metaclass for Enum types
992 class MetaEnum(MetaParamValue
):
993 def __new__(mcls
, name
, bases
, dict):
994 assert name
not in allEnums
996 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1000 def __init__(cls
, name
, bases
, init_dict
):
1001 if init_dict
.has_key('map'):
1002 if not isinstance(cls
.map, dict):
1003 raise TypeError, "Enum-derived class attribute 'map' " \
1004 "must be of type dict"
1005 # build list of value strings from map
1006 cls
.vals
= cls
.map.keys()
1008 elif init_dict
.has_key('vals'):
1009 if not isinstance(cls
.vals
, list):
1010 raise TypeError, "Enum-derived class attribute 'vals' " \
1011 "must be of type list"
1012 # build string->value map from vals sequence
1014 for idx
,val
in enumerate(cls
.vals
):
1017 raise TypeError, "Enum-derived class must define "\
1018 "attribute 'map' or 'vals'"
1020 cls
.cxx_type
= 'Enums::%s' % name
1022 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1024 # Generate C++ class declaration for this enum type.
1025 # Note that we wrap the enum in a class/struct to act as a namespace,
1026 # so that the enum strings can be brief w/o worrying about collisions.
1027 def cxx_decl(cls
, code
):
1030 #ifndef __ENUM__${name}__
1031 #define __ENUM__${name}__
1037 for val
in cls
.vals
:
1038 code('$val = ${{cls.map[val]}},')
1039 code('Num_$name = ${{len(cls.vals)}},')
1043 extern const char *${name}Strings[Num_${name}];
1046 #endif // __ENUM__${name}__
1049 def cxx_def(cls
, code
):
1052 #include "enums/$name.hh"
1054 const char *${name}Strings[Num_${name}] =
1058 for val
in cls
.vals
:
1063 } // namespace Enums
1066 def swig_decl(cls
, code
):
1069 %module(package="m5.internal") enum_$name
1072 #include "enums/$name.hh"
1075 %include "enums/$name.hh"
1079 # Base class for enum types.
1080 class Enum(ParamValue
):
1081 __metaclass__
= MetaEnum
1084 def __init__(self
, value
):
1085 if value
not in self
.map:
1086 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1087 % (value
, self
.vals
)
1091 def cxx_predecls(cls
, code
):
1092 code('#include "enums/$0.hh"', cls
.__name
__)
1095 def swig_predecls(cls
, code
):
1096 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1099 return int(self
.map[self
.value
])
1104 # how big does a rounding error need to be before we warn about it?
1105 frequency_tolerance
= 0.001 # 0.1%
1107 class TickParamValue(NumericParamValue
):
1111 def cxx_predecls(cls
, code
):
1112 code('#include "base/types.hh"')
1115 def swig_predecls(cls
, code
):
1116 code('%import "stdint.i"')
1117 code('%import "base/types.hh"')
1120 return long(self
.value
)
1122 class Latency(TickParamValue
):
1123 def __init__(self
, value
):
1124 if isinstance(value
, (Latency
, Clock
)):
1125 self
.ticks
= value
.ticks
1126 self
.value
= value
.value
1127 elif isinstance(value
, Frequency
):
1128 self
.ticks
= value
.ticks
1129 self
.value
= 1.0 / value
.value
1130 elif value
.endswith('t'):
1132 self
.value
= int(value
[:-1])
1135 self
.value
= convert
.toLatency(value
)
1137 def __getattr__(self
, attr
):
1138 if attr
in ('latency', 'period'):
1140 if attr
== 'frequency':
1141 return Frequency(self
)
1142 raise AttributeError, "Latency object has no attribute '%s'" % attr
1145 if self
.ticks
or self
.value
== 0:
1148 value
= ticks
.fromSeconds(self
.value
)
1151 # convert latency to ticks
1153 return '%d' % self
.getValue()
1155 class Frequency(TickParamValue
):
1156 def __init__(self
, value
):
1157 if isinstance(value
, (Latency
, Clock
)):
1158 if value
.value
== 0:
1161 self
.value
= 1.0 / value
.value
1162 self
.ticks
= value
.ticks
1163 elif isinstance(value
, Frequency
):
1164 self
.value
= value
.value
1165 self
.ticks
= value
.ticks
1168 self
.value
= convert
.toFrequency(value
)
1170 def __getattr__(self
, attr
):
1171 if attr
== 'frequency':
1173 if attr
in ('latency', 'period'):
1174 return Latency(self
)
1175 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1177 # convert latency to ticks
1179 if self
.ticks
or self
.value
== 0:
1182 value
= ticks
.fromSeconds(1.0 / self
.value
)
1186 return '%d' % self
.getValue()
1188 # A generic frequency and/or Latency value. Value is stored as a latency,
1189 # but to avoid ambiguity this object does not support numeric ops (* or /).
1190 # An explicit conversion to a Latency or Frequency must be made first.
1191 class Clock(ParamValue
):
1195 def cxx_predecls(cls
, code
):
1196 code('#include "base/types.hh"')
1199 def swig_predecls(cls
, code
):
1200 code('%import "stdint.i"')
1201 code('%import "base/types.hh"')
1203 def __init__(self
, value
):
1204 if isinstance(value
, (Latency
, Clock
)):
1205 self
.ticks
= value
.ticks
1206 self
.value
= value
.value
1207 elif isinstance(value
, Frequency
):
1208 self
.ticks
= value
.ticks
1209 self
.value
= 1.0 / value
.value
1210 elif value
.endswith('t'):
1212 self
.value
= int(value
[:-1])
1215 self
.value
= convert
.anyToLatency(value
)
1217 def __getattr__(self
, attr
):
1218 if attr
== 'frequency':
1219 return Frequency(self
)
1220 if attr
in ('latency', 'period'):
1221 return Latency(self
)
1222 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1225 return self
.period
.getValue()
1228 return self
.period
.ini_str()
1230 class NetworkBandwidth(float,ParamValue
):
1232 def __new__(cls
, value
):
1233 # convert to bits per second
1234 val
= convert
.toNetworkBandwidth(value
)
1235 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1238 return str(self
.val
)
1241 # convert to seconds per byte
1242 value
= 8.0 / float(self
)
1243 # convert to ticks per byte
1244 value
= ticks
.fromSeconds(value
)
1248 return '%f' % self
.getValue()
1250 class MemoryBandwidth(float,ParamValue
):
1252 def __new__(cls
, value
):
1253 # convert to bytes per second
1254 val
= convert
.toMemoryBandwidth(value
)
1255 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1258 return str(self
.val
)
1261 # convert to seconds per byte
1264 value
= 1.0 / float(self
)
1265 # convert to ticks per byte
1266 value
= ticks
.fromSeconds(value
)
1270 return '%f' % self
.getValue()
1273 # "Constants"... handy aliases for various values.
1276 # Special class for NULL pointers. Note the special check in
1277 # make_param_value() above that lets these be assigned where a
1278 # SimObject is required.
1279 # only one copy of a particular node
1280 class NullSimObject(object):
1281 __metaclass__
= Singleton
1286 def _instantiate(self
, parent
= None, path
= ''):
1292 def unproxy(self
, base
):
1295 def set_path(self
, parent
, name
):
1304 # The only instance you'll ever need...
1305 NULL
= NullSimObject()
1307 def isNullPointer(value
):
1308 return isinstance(value
, NullSimObject
)
1310 # Some memory range specifications use this as a default upper bound.
1313 AllMemory
= AddrRange(0, MaxAddr
)
1316 #####################################################################
1320 # Ports are used to interconnect objects in the memory system.
1322 #####################################################################
1324 # Port reference: encapsulates a reference to a particular port on a
1325 # particular SimObject.
1326 class PortRef(object):
1327 def __init__(self
, simobj
, name
):
1328 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1329 self
.simobj
= simobj
1331 self
.peer
= None # not associated with another port yet
1332 self
.ccConnected
= False # C++ port connection done?
1333 self
.index
= -1 # always -1 for non-vector ports
1336 return '%s.%s' % (self
.simobj
, self
.name
)
1338 # for config.ini, print peer's name (not ours)
1340 return str(self
.peer
)
1342 def __getattr__(self
, attr
):
1343 if attr
== 'peerObj':
1344 # shorthand for proxies
1345 return self
.peer
.simobj
1346 raise AttributeError, "'%s' object has no attribute '%s'" % \
1347 (self
.__class
__.__name
__, attr
)
1349 # Full connection is symmetric (both ways). Called via
1350 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1351 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1352 # e.g., "obj1.portA[3] = obj2.portB".
1353 def connect(self
, other
):
1354 if isinstance(other
, VectorPortRef
):
1355 # reference to plain VectorPort is implicit append
1356 other
= other
._get
_next
()
1357 if self
.peer
and not proxy
.isproxy(self
.peer
):
1358 print "warning: overwriting port", self
, \
1359 "value", self
.peer
, "with", other
1360 self
.peer
.peer
= None
1362 if proxy
.isproxy(other
):
1363 other
.set_param_desc(PortParamDesc())
1364 elif isinstance(other
, PortRef
):
1365 if other
.peer
is not self
:
1369 "assigning non-port reference '%s' to port '%s'" \
1372 def clone(self
, simobj
, memo
):
1373 if memo
.has_key(self
):
1375 newRef
= copy
.copy(self
)
1377 newRef
.simobj
= simobj
1378 assert(isSimObject(newRef
.simobj
))
1379 if self
.peer
and not proxy
.isproxy(self
.peer
):
1380 peerObj
= self
.peer
.simobj(_memo
=memo
)
1381 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1382 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1385 def unproxy(self
, simobj
):
1386 assert(simobj
is self
.simobj
)
1387 if proxy
.isproxy(self
.peer
):
1389 realPeer
= self
.peer
.unproxy(self
.simobj
)
1391 print "Error in unproxying port '%s' of %s" % \
1392 (self
.name
, self
.simobj
.path())
1394 self
.connect(realPeer
)
1396 # Call C++ to create corresponding port connection between C++ objects
1397 def ccConnect(self
):
1398 from m5
.internal
.pyobject
import connectPorts
1400 if self
.ccConnected
: # already done this
1403 if not self
.peer
: # nothing to connect to
1406 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1407 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1409 print "Error connecting port %s.%s to %s.%s" % \
1410 (self
.simobj
.path(), self
.name
,
1411 peer
.simobj
.path(), peer
.name
)
1413 self
.ccConnected
= True
1414 peer
.ccConnected
= True
1416 # A reference to an individual element of a VectorPort... much like a
1417 # PortRef, but has an index.
1418 class VectorPortElementRef(PortRef
):
1419 def __init__(self
, simobj
, name
, index
):
1420 PortRef
.__init
__(self
, simobj
, name
)
1424 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1426 # A reference to a complete vector-valued port (not just a single element).
1427 # Can be indexed to retrieve individual VectorPortElementRef instances.
1428 class VectorPortRef(object):
1429 def __init__(self
, simobj
, name
):
1430 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1431 self
.simobj
= simobj
1436 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1438 # for config.ini, print peer's name (not ours)
1440 return ' '.join([el
.ini_str() for el
in self
.elements
])
1442 def __getitem__(self
, key
):
1443 if not isinstance(key
, int):
1444 raise TypeError, "VectorPort index must be integer"
1445 if key
>= len(self
.elements
):
1446 # need to extend list
1447 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1448 for i
in range(len(self
.elements
), key
+1)]
1449 self
.elements
.extend(ext
)
1450 return self
.elements
[key
]
1452 def _get_next(self
):
1453 return self
[len(self
.elements
)]
1455 def __setitem__(self
, key
, value
):
1456 if not isinstance(key
, int):
1457 raise TypeError, "VectorPort index must be integer"
1458 self
[key
].connect(value
)
1460 def connect(self
, other
):
1461 if isinstance(other
, (list, tuple)):
1462 # Assign list of port refs to vector port.
1463 # For now, append them... not sure if that's the right semantics
1464 # or if it should replace the current vector.
1466 self
._get
_next
().connect(ref
)
1468 # scalar assignment to plain VectorPort is implicit append
1469 self
._get
_next
().connect(other
)
1471 def clone(self
, simobj
, memo
):
1472 if memo
.has_key(self
):
1474 newRef
= copy
.copy(self
)
1476 newRef
.simobj
= simobj
1477 assert(isSimObject(newRef
.simobj
))
1478 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1481 def unproxy(self
, simobj
):
1482 [el
.unproxy(simobj
) for el
in self
.elements
]
1484 def ccConnect(self
):
1485 [el
.ccConnect() for el
in self
.elements
]
1487 # Port description object. Like a ParamDesc object, this represents a
1488 # logical port in the SimObject class, not a particular port on a
1489 # SimObject instance. The latter are represented by PortRef objects.
1491 # Port("description")
1492 def __init__(self
, *args
):
1496 raise TypeError, 'wrong number of arguments'
1497 # self.name is set by SimObject class on assignment
1498 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1500 # Generate a PortRef for this port on the given SimObject with the
1502 def makeRef(self
, simobj
):
1503 return PortRef(simobj
, self
.name
)
1505 # Connect an instance of this port (on the given SimObject with
1506 # the given name) with the port described by the supplied PortRef
1507 def connect(self
, simobj
, ref
):
1508 self
.makeRef(simobj
).connect(ref
)
1510 # VectorPort description object. Like Port, but represents a vector
1511 # of connections (e.g., as on a Bus).
1512 class VectorPort(Port
):
1513 def __init__(self
, *args
):
1514 Port
.__init
__(self
, *args
)
1517 def makeRef(self
, simobj
):
1518 return VectorPortRef(simobj
, self
.name
)
1520 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1521 # proxy objects (via set_param_desc()) so that proxy error messages
1523 class PortParamDesc(object):
1524 __metaclass__
= Singleton
1529 baseEnums
= allEnums
.copy()
1530 baseParams
= allParams
.copy()
1533 global allEnums
, allParams
1535 allEnums
= baseEnums
.copy()
1536 allParams
= baseParams
.copy()
1538 __all__
= ['Param', 'VectorParam',
1539 'Enum', 'Bool', 'String', 'Float',
1540 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1541 'Int32', 'UInt32', 'Int64', 'UInt64',
1542 'Counter', 'Addr', 'Tick', 'Percent',
1543 'TcpPort', 'UdpPort', 'EthernetAddr',
1544 'IpAddress', 'IpNetmask', 'IpWithPort',
1545 'MemorySize', 'MemorySize32',
1546 'Latency', 'Frequency', 'Clock',
1547 'NetworkBandwidth', 'MemoryBandwidth',
1548 'Range', 'AddrRange', 'TickRange',
1549 'MaxAddr', 'MaxTick', 'AllMemory',
1551 'NextEthernetAddr', 'NULL',
1552 'Port', 'VectorPort']