03917d08525072102cb9286e81ed57f1de4568e8
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 class VectorParamDesc(ParamDesc
):
232 # Convert assigned value to appropriate type. If the RHS is not a
233 # list or tuple, it generates a single-element list.
234 def convert(self
, value
):
235 if isinstance(value
, (list, tuple)):
236 # list: coerce each element into new list
237 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
239 # singleton: coerce to a single-element list
240 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
242 if isSimObjectSequence(tmp_list
):
243 return SimObjectVector(tmp_list
)
245 return VectorParamValue(tmp_list
)
247 def swig_module_name(self
):
248 return "%s_vector" % self
.ptype_str
250 def swig_predecls(self
, code
):
251 code('%import "${{self.swig_module_name()}}.i"')
253 def swig_decl(self
, code
):
254 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
256 self
.ptype
.cxx_predecls(code
)
259 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
260 code('%include "std_container.i"')
262 self
.ptype
.swig_predecls(code
)
264 code('%include "std_vector.i"')
267 ptype
= self
.ptype_str
268 cxx_type
= self
.ptype
.cxx_type
271 %typemap(in) std::vector< $cxx_type >::value_type {
272 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
273 if (SWIG_ConvertPtr($$input, (void **)&$$1,
274 $$descriptor($cxx_type), 0) == -1) {
280 %typemap(in) std::vector< $cxx_type >::value_type * {
281 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
282 if (SWIG_ConvertPtr($$input, (void **)&$$1,
283 $$descriptor($cxx_type *), 0) == -1) {
290 code('%template(vector_$ptype) std::vector< $cxx_type >;')
292 def cxx_predecls(self
, code
):
293 code('#include <vector>')
294 self
.ptype
.cxx_predecls(code
)
296 def cxx_decl(self
, code
):
297 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
299 class ParamFactory(object):
300 def __init__(self
, param_desc_class
, ptype_str
= None):
301 self
.param_desc_class
= param_desc_class
302 self
.ptype_str
= ptype_str
304 def __getattr__(self
, attr
):
306 attr
= self
.ptype_str
+ '.' + attr
307 return ParamFactory(self
.param_desc_class
, attr
)
309 # E.g., Param.Int(5, "number of widgets")
310 def __call__(self
, *args
, **kwargs
):
313 ptype
= allParams
[self
.ptype_str
]
315 # if name isn't defined yet, assume it's a SimObject, and
316 # try to resolve it later
318 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
320 Param
= ParamFactory(ParamDesc
)
321 VectorParam
= ParamFactory(VectorParamDesc
)
323 #####################################################################
327 # Though native Python types could be used to specify parameter types
328 # (the 'ptype' field of the Param and VectorParam classes), it's more
329 # flexible to define our own set of types. This gives us more control
330 # over how Python expressions are converted to values (via the
331 # __init__() constructor) and how these values are printed out (via
332 # the __str__() conversion method).
334 #####################################################################
336 # String-valued parameter. Just mixin the ParamValue class with the
337 # built-in str class.
338 class String(ParamValue
,str):
339 cxx_type
= 'std::string'
342 def cxx_predecls(self
, code
):
343 code('#include <string>')
346 def swig_predecls(cls
, code
):
347 code('%include "std_string.i"')
352 # superclass for "numeric" parameter values, to emulate math
353 # operations in a type-safe way. e.g., a Latency times an int returns
354 # a new Latency object.
355 class NumericParamValue(ParamValue
):
357 return str(self
.value
)
360 return float(self
.value
)
363 return long(self
.value
)
366 return int(self
.value
)
368 # hook for bounds checking
372 def __mul__(self
, other
):
373 newobj
= self
.__class
__(self
)
374 newobj
.value
*= other
380 def __div__(self
, other
):
381 newobj
= self
.__class
__(self
)
382 newobj
.value
/= other
386 def __sub__(self
, other
):
387 newobj
= self
.__class
__(self
)
388 newobj
.value
-= other
392 # Metaclass for bounds-checked integer parameters. See CheckedInt.
393 class CheckedIntType(MetaParamValue
):
394 def __init__(cls
, name
, bases
, dict):
395 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
397 # CheckedInt is an abstract base class, so we actually don't
398 # want to do any processing on it... the rest of this code is
399 # just for classes that derive from CheckedInt.
400 if name
== 'CheckedInt':
403 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
404 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
405 panic("CheckedInt subclass %s must define either\n" \
406 " 'min' and 'max' or 'size' and 'unsigned'\n",
410 cls
.max = 2 ** cls
.size
- 1
412 cls
.min = -(2 ** (cls
.size
- 1))
413 cls
.max = (2 ** (cls
.size
- 1)) - 1
415 # Abstract superclass for bounds-checked integer parameters. This
416 # class is subclassed to generate parameter classes with specific
417 # bounds. Initialization of the min and max bounds is done in the
418 # metaclass CheckedIntType.__init__.
419 class CheckedInt(NumericParamValue
):
420 __metaclass__
= CheckedIntType
423 if not self
.min <= self
.value
<= self
.max:
424 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
425 (self
.min, self
.value
, self
.max)
427 def __init__(self
, value
):
428 if isinstance(value
, str):
429 self
.value
= convert
.toInteger(value
)
430 elif isinstance(value
, (int, long, float, NumericParamValue
)):
431 self
.value
= long(value
)
433 raise TypeError, "Can't convert object of type %s to CheckedInt" \
434 % type(value
).__name
__
438 def cxx_predecls(cls
, code
):
439 # most derived types require this, so we just do it here once
440 code('#include "base/types.hh"')
443 def swig_predecls(cls
, code
):
444 # most derived types require this, so we just do it here once
445 code('%import "stdint.i"')
446 code('%import "base/types.hh"')
449 return long(self
.value
)
451 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
452 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
454 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
455 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
456 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
457 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
458 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
459 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
460 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
461 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
463 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
464 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
465 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
466 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
468 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
470 class Float(ParamValue
, float):
473 def __init__(self
, value
):
474 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
475 self
.value
= float(value
)
477 raise TypeError, "Can't convert object of type %s to Float" \
478 % type(value
).__name
__
481 return float(self
.value
)
483 class MemorySize(CheckedInt
):
484 cxx_type
= 'uint64_t'
487 def __init__(self
, value
):
488 if isinstance(value
, MemorySize
):
489 self
.value
= value
.value
491 self
.value
= convert
.toMemorySize(value
)
494 class MemorySize32(CheckedInt
):
495 cxx_type
= 'uint32_t'
498 def __init__(self
, value
):
499 if isinstance(value
, MemorySize
):
500 self
.value
= value
.value
502 self
.value
= convert
.toMemorySize(value
)
505 class Addr(CheckedInt
):
509 def __init__(self
, value
):
510 if isinstance(value
, Addr
):
511 self
.value
= value
.value
514 self
.value
= convert
.toMemorySize(value
)
516 self
.value
= long(value
)
518 def __add__(self
, other
):
519 if isinstance(other
, Addr
):
520 return self
.value
+ other
.value
522 return self
.value
+ other
525 class MetaRange(MetaParamValue
):
526 def __init__(cls
, name
, bases
, dict):
527 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
530 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
532 class Range(ParamValue
):
533 __metaclass__
= MetaRange
534 type = Int
# default; can be overridden in subclasses
535 def __init__(self
, *args
, **kwargs
):
536 def handle_kwargs(self
, kwargs
):
538 self
.second
= self
.type(kwargs
.pop('end'))
539 elif 'size' in kwargs
:
540 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
542 raise TypeError, "Either end or size must be specified"
545 self
.first
= self
.type(kwargs
.pop('start'))
546 handle_kwargs(self
, kwargs
)
550 self
.first
= self
.type(args
[0])
551 handle_kwargs(self
, kwargs
)
552 elif isinstance(args
[0], Range
):
553 self
.first
= self
.type(args
[0].first
)
554 self
.second
= self
.type(args
[0].second
)
555 elif isinstance(args
[0], (list, tuple)):
556 self
.first
= self
.type(args
[0][0])
557 self
.second
= self
.type(args
[0][1])
559 self
.first
= self
.type(0)
560 self
.second
= self
.type(args
[0]) - 1
563 self
.first
= self
.type(args
[0])
564 self
.second
= self
.type(args
[1])
566 raise TypeError, "Too many arguments specified"
569 raise TypeError, "too many keywords: %s" % kwargs
.keys()
572 return '%s:%s' % (self
.first
, self
.second
)
575 def cxx_predecls(cls
, code
):
576 cls
.type.cxx_predecls(code
)
577 code('#include "base/range.hh"')
580 def swig_predecls(cls
, code
):
581 cls
.type.swig_predecls(code
)
582 code('%import "python/swig/range.i"')
584 class AddrRange(Range
):
588 from m5
.internal
.range import AddrRange
591 value
.start
= long(self
.first
)
592 value
.end
= long(self
.second
)
595 class TickRange(Range
):
599 from m5
.internal
.range import TickRange
602 value
.start
= long(self
.first
)
603 value
.end
= long(self
.second
)
606 # Boolean parameter type. Python doesn't let you subclass bool, since
607 # it doesn't want to let you create multiple instances of True and
608 # False. Thus this is a little more complicated than String.
609 class Bool(ParamValue
):
611 def __init__(self
, value
):
613 self
.value
= convert
.toBool(value
)
615 self
.value
= bool(value
)
618 return bool(self
.value
)
621 return str(self
.value
)
628 def IncEthernetAddr(addr
, val
= 1):
629 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
631 for i
in (5, 4, 3, 2, 1):
632 val
,rem
= divmod(bytes
[i
], 256)
637 assert(bytes
[0] <= 255)
638 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
640 _NextEthernetAddr
= "00:90:00:00:00:01"
641 def NextEthernetAddr():
642 global _NextEthernetAddr
644 value
= _NextEthernetAddr
645 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
648 class EthernetAddr(ParamValue
):
649 cxx_type
= 'Net::EthAddr'
652 def cxx_predecls(cls
, code
):
653 code('#include "base/inet.hh"')
656 def swig_predecls(cls
, code
):
657 code('%include "python/swig/inet.i"')
659 def __init__(self
, value
):
660 if value
== NextEthernetAddr
:
664 if not isinstance(value
, str):
665 raise TypeError, "expected an ethernet address and didn't get one"
667 bytes
= value
.split(':')
669 raise TypeError, 'invalid ethernet address %s' % value
672 if not 0 <= int(byte
) <= 0xff:
673 raise TypeError, 'invalid ethernet address %s' % value
677 def unproxy(self
, base
):
678 if self
.value
== NextEthernetAddr
:
679 return EthernetAddr(self
.value())
683 from m5
.internal
.params
import EthAddr
684 return EthAddr(self
.value
)
689 # When initializing an IpAddress, pass in an existing IpAddress, a string of
690 # the form "a.b.c.d", or an integer representing an IP.
691 class IpAddress(ParamValue
):
692 cxx_type
= 'Net::IpAddress'
695 def cxx_predecls(cls
, code
):
696 code('#include "base/inet.hh"')
699 def swig_predecls(cls
, code
):
700 code('%include "python/swig/inet.i"')
702 def __init__(self
, value
):
703 if isinstance(value
, IpAddress
):
707 self
.ip
= convert
.toIpAddress(value
)
709 self
.ip
= long(value
)
713 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
714 return '%d.%d.%d.%d' % tuple(tup
)
716 def __eq__(self
, other
):
717 if isinstance(other
, IpAddress
):
718 return self
.ip
== other
.ip
719 elif isinstance(other
, str):
721 return self
.ip
== convert
.toIpAddress(other
)
725 return self
.ip
== other
727 def __ne__(self
, other
):
728 return not (self
== other
)
731 if self
.ip
< 0 or self
.ip
>= (1 << 32):
732 raise TypeError, "invalid ip address %#08x" % self
.ip
735 from m5
.internal
.params
import IpAddress
736 return IpAddress(self
.ip
)
738 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
739 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
740 # positional or keyword arguments.
741 class IpNetmask(IpAddress
):
742 cxx_type
= 'Net::IpNetmask'
745 def cxx_predecls(cls
, code
):
746 code('#include "base/inet.hh"')
749 def swig_predecls(cls
, code
):
750 code('%include "python/swig/inet.i"')
752 def __init__(self
, *args
, **kwargs
):
753 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
755 setattr(self
, key
, kwargs
.pop(key
))
757 setattr(self
, key
, elseVal
)
759 raise TypeError, "No value set for %s" % key
762 handle_kwarg(self
, kwargs
, 'ip')
763 handle_kwarg(self
, kwargs
, 'netmask')
767 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
768 raise TypeError, "Invalid arguments"
769 handle_kwarg(self
, kwargs
, 'ip', args
[0])
770 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
771 elif isinstance(args
[0], IpNetmask
):
773 self
.netmask
= args
[0].netmask
775 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
779 self
.netmask
= args
[1]
781 raise TypeError, "Too many arguments specified"
784 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
789 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
791 def __eq__(self
, other
):
792 if isinstance(other
, IpNetmask
):
793 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
794 elif isinstance(other
, str):
796 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
804 if self
.netmask
< 0 or self
.netmask
> 32:
805 raise TypeError, "invalid netmask %d" % netmask
808 from m5
.internal
.params
import IpNetmask
809 return IpNetmask(self
.ip
, self
.netmask
)
811 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
812 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
813 class IpWithPort(IpAddress
):
814 cxx_type
= 'Net::IpWithPort'
817 def cxx_predecls(cls
, code
):
818 code('#include "base/inet.hh"')
821 def swig_predecls(cls
, code
):
822 code('%include "python/swig/inet.i"')
824 def __init__(self
, *args
, **kwargs
):
825 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
827 setattr(self
, key
, kwargs
.pop(key
))
829 setattr(self
, key
, elseVal
)
831 raise TypeError, "No value set for %s" % key
834 handle_kwarg(self
, kwargs
, 'ip')
835 handle_kwarg(self
, kwargs
, 'port')
839 if not 'ip' in kwargs
and not 'port' in kwargs
:
840 raise TypeError, "Invalid arguments"
841 handle_kwarg(self
, kwargs
, 'ip', args
[0])
842 handle_kwarg(self
, kwargs
, 'port', args
[0])
843 elif isinstance(args
[0], IpWithPort
):
845 self
.port
= args
[0].port
847 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
853 raise TypeError, "Too many arguments specified"
856 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
861 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
863 def __eq__(self
, other
):
864 if isinstance(other
, IpWithPort
):
865 return self
.ip
== other
.ip
and self
.port
== other
.port
866 elif isinstance(other
, str):
868 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
876 if self
.port
< 0 or self
.port
> 0xffff:
877 raise TypeError, "invalid port %d" % self
.port
880 from m5
.internal
.params
import IpWithPort
881 return IpWithPort(self
.ip
, self
.port
)
883 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
884 "%a %b %d %H:%M:%S %Z %Y",
896 def parse_time(value
):
897 from time
import gmtime
, strptime
, struct_time
, time
898 from datetime
import datetime
, date
900 if isinstance(value
, struct_time
):
903 if isinstance(value
, (int, long)):
906 if isinstance(value
, (datetime
, date
)):
907 return value
.timetuple()
909 if isinstance(value
, str):
910 if value
in ('Now', 'Today'):
911 return time
.gmtime(time
.time())
913 for format
in time_formats
:
915 return strptime(value
, format
)
919 raise ValueError, "Could not parse '%s' as a time" % value
921 class Time(ParamValue
):
925 def cxx_predecls(cls
, code
):
926 code('#include <time.h>')
929 def swig_predecls(cls
, code
):
930 code('%include "python/swig/time.i"')
932 def __init__(self
, value
):
933 self
.value
= parse_time(value
)
936 from m5
.internal
.params
import tm
941 # UNIX is years since 1900
942 c_time
.tm_year
= py_time
.tm_year
- 1900;
944 # Python starts at 1, UNIX starts at 0
945 c_time
.tm_mon
= py_time
.tm_mon
- 1;
946 c_time
.tm_mday
= py_time
.tm_mday
;
947 c_time
.tm_hour
= py_time
.tm_hour
;
948 c_time
.tm_min
= py_time
.tm_min
;
949 c_time
.tm_sec
= py_time
.tm_sec
;
951 # Python has 0 as Monday, UNIX is 0 as sunday
952 c_time
.tm_wday
= py_time
.tm_wday
+ 1
953 if c_time
.tm_wday
> 6:
956 # Python starts at 1, Unix starts at 0
957 c_time
.tm_yday
= py_time
.tm_yday
- 1;
962 return time
.asctime(self
.value
)
967 # Enumerated types are a little more complex. The user specifies the
968 # type as Enum(foo) where foo is either a list or dictionary of
969 # alternatives (typically strings, but not necessarily so). (In the
970 # long run, the integer value of the parameter will be the list index
971 # or the corresponding dictionary value. For now, since we only check
972 # that the alternative is valid and then spit it into a .ini file,
973 # there's not much point in using the dictionary.)
975 # What Enum() must do is generate a new type encapsulating the
976 # provided list/dictionary so that specific values of the parameter
977 # can be instances of that type. We define two hidden internal
978 # classes (_ListEnum and _DictEnum) to serve as base classes, then
979 # derive the new type from the appropriate base class on the fly.
982 # Metaclass for Enum types
983 class MetaEnum(MetaParamValue
):
984 def __new__(mcls
, name
, bases
, dict):
985 assert name
not in allEnums
987 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
991 def __init__(cls
, name
, bases
, init_dict
):
992 if init_dict
.has_key('map'):
993 if not isinstance(cls
.map, dict):
994 raise TypeError, "Enum-derived class attribute 'map' " \
995 "must be of type dict"
996 # build list of value strings from map
997 cls
.vals
= cls
.map.keys()
999 elif init_dict
.has_key('vals'):
1000 if not isinstance(cls
.vals
, list):
1001 raise TypeError, "Enum-derived class attribute 'vals' " \
1002 "must be of type list"
1003 # build string->value map from vals sequence
1005 for idx
,val
in enumerate(cls
.vals
):
1008 raise TypeError, "Enum-derived class must define "\
1009 "attribute 'map' or 'vals'"
1011 cls
.cxx_type
= 'Enums::%s' % name
1013 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1015 # Generate C++ class declaration for this enum type.
1016 # Note that we wrap the enum in a class/struct to act as a namespace,
1017 # so that the enum strings can be brief w/o worrying about collisions.
1018 def cxx_decl(cls
, code
):
1021 #ifndef __ENUM__${name}__
1022 #define __ENUM__${name}__
1028 for val
in cls
.vals
:
1029 code('$val = ${{cls.map[val]}},')
1030 code('Num_$name = ${{len(cls.vals)}},')
1034 extern const char *${name}Strings[Num_${name}];
1037 #endif // __ENUM__${name}__
1040 def cxx_def(cls
, code
):
1043 #include "enums/$name.hh"
1045 const char *${name}Strings[Num_${name}] =
1049 for val
in cls
.vals
:
1054 } // namespace Enums
1057 def swig_decl(cls
, code
):
1060 %module(package="m5.internal") enum_$name
1063 #include "enums/$name.hh"
1066 %include "enums/$name.hh"
1070 # Base class for enum types.
1071 class Enum(ParamValue
):
1072 __metaclass__
= MetaEnum
1075 def __init__(self
, value
):
1076 if value
not in self
.map:
1077 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1078 % (value
, self
.vals
)
1082 def cxx_predecls(cls
, code
):
1083 code('#include "enums/$0.hh"', cls
.__name
__)
1086 def swig_predecls(cls
, code
):
1087 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1090 return int(self
.map[self
.value
])
1095 # how big does a rounding error need to be before we warn about it?
1096 frequency_tolerance
= 0.001 # 0.1%
1098 class TickParamValue(NumericParamValue
):
1102 def cxx_predecls(cls
, code
):
1103 code('#include "base/types.hh"')
1106 def swig_predecls(cls
, code
):
1107 code('%import "stdint.i"')
1108 code('%import "base/types.hh"')
1111 return long(self
.value
)
1113 class Latency(TickParamValue
):
1114 def __init__(self
, value
):
1115 if isinstance(value
, (Latency
, Clock
)):
1116 self
.ticks
= value
.ticks
1117 self
.value
= value
.value
1118 elif isinstance(value
, Frequency
):
1119 self
.ticks
= value
.ticks
1120 self
.value
= 1.0 / value
.value
1121 elif value
.endswith('t'):
1123 self
.value
= int(value
[:-1])
1126 self
.value
= convert
.toLatency(value
)
1128 def __getattr__(self
, attr
):
1129 if attr
in ('latency', 'period'):
1131 if attr
== 'frequency':
1132 return Frequency(self
)
1133 raise AttributeError, "Latency object has no attribute '%s'" % attr
1136 if self
.ticks
or self
.value
== 0:
1139 value
= ticks
.fromSeconds(self
.value
)
1142 # convert latency to ticks
1144 return '%d' % self
.getValue()
1146 class Frequency(TickParamValue
):
1147 def __init__(self
, value
):
1148 if isinstance(value
, (Latency
, Clock
)):
1149 if value
.value
== 0:
1152 self
.value
= 1.0 / value
.value
1153 self
.ticks
= value
.ticks
1154 elif isinstance(value
, Frequency
):
1155 self
.value
= value
.value
1156 self
.ticks
= value
.ticks
1159 self
.value
= convert
.toFrequency(value
)
1161 def __getattr__(self
, attr
):
1162 if attr
== 'frequency':
1164 if attr
in ('latency', 'period'):
1165 return Latency(self
)
1166 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1168 # convert latency to ticks
1170 if self
.ticks
or self
.value
== 0:
1173 value
= ticks
.fromSeconds(1.0 / self
.value
)
1177 return '%d' % self
.getValue()
1179 # A generic frequency and/or Latency value. Value is stored as a latency,
1180 # but to avoid ambiguity this object does not support numeric ops (* or /).
1181 # An explicit conversion to a Latency or Frequency must be made first.
1182 class Clock(ParamValue
):
1186 def cxx_predecls(cls
, code
):
1187 code('#include "base/types.hh"')
1190 def swig_predecls(cls
, code
):
1191 code('%import "stdint.i"')
1192 code('%import "base/types.hh"')
1194 def __init__(self
, value
):
1195 if isinstance(value
, (Latency
, Clock
)):
1196 self
.ticks
= value
.ticks
1197 self
.value
= value
.value
1198 elif isinstance(value
, Frequency
):
1199 self
.ticks
= value
.ticks
1200 self
.value
= 1.0 / value
.value
1201 elif value
.endswith('t'):
1203 self
.value
= int(value
[:-1])
1206 self
.value
= convert
.anyToLatency(value
)
1208 def __getattr__(self
, attr
):
1209 if attr
== 'frequency':
1210 return Frequency(self
)
1211 if attr
in ('latency', 'period'):
1212 return Latency(self
)
1213 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1216 return self
.period
.getValue()
1219 return self
.period
.ini_str()
1221 class NetworkBandwidth(float,ParamValue
):
1223 def __new__(cls
, value
):
1224 # convert to bits per second
1225 val
= convert
.toNetworkBandwidth(value
)
1226 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1229 return str(self
.val
)
1232 # convert to seconds per byte
1233 value
= 8.0 / float(self
)
1234 # convert to ticks per byte
1235 value
= ticks
.fromSeconds(value
)
1239 return '%f' % self
.getValue()
1241 class MemoryBandwidth(float,ParamValue
):
1243 def __new__(cls
, value
):
1244 # convert to bytes per second
1245 val
= convert
.toMemoryBandwidth(value
)
1246 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1249 return str(self
.val
)
1252 # convert to seconds per byte
1255 value
= 1.0 / float(self
)
1256 # convert to ticks per byte
1257 value
= ticks
.fromSeconds(value
)
1261 return '%f' % self
.getValue()
1264 # "Constants"... handy aliases for various values.
1267 # Special class for NULL pointers. Note the special check in
1268 # make_param_value() above that lets these be assigned where a
1269 # SimObject is required.
1270 # only one copy of a particular node
1271 class NullSimObject(object):
1272 __metaclass__
= Singleton
1277 def _instantiate(self
, parent
= None, path
= ''):
1283 def unproxy(self
, base
):
1286 def set_path(self
, parent
, name
):
1295 # The only instance you'll ever need...
1296 NULL
= NullSimObject()
1298 def isNullPointer(value
):
1299 return isinstance(value
, NullSimObject
)
1301 # Some memory range specifications use this as a default upper bound.
1304 AllMemory
= AddrRange(0, MaxAddr
)
1307 #####################################################################
1311 # Ports are used to interconnect objects in the memory system.
1313 #####################################################################
1315 # Port reference: encapsulates a reference to a particular port on a
1316 # particular SimObject.
1317 class PortRef(object):
1318 def __init__(self
, simobj
, name
):
1319 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1320 self
.simobj
= simobj
1322 self
.peer
= None # not associated with another port yet
1323 self
.ccConnected
= False # C++ port connection done?
1324 self
.index
= -1 # always -1 for non-vector ports
1327 return '%s.%s' % (self
.simobj
, self
.name
)
1329 # for config.ini, print peer's name (not ours)
1331 return str(self
.peer
)
1333 def __getattr__(self
, attr
):
1334 if attr
== 'peerObj':
1335 # shorthand for proxies
1336 return self
.peer
.simobj
1337 raise AttributeError, "'%s' object has no attribute '%s'" % \
1338 (self
.__class
__.__name
__, attr
)
1340 # Full connection is symmetric (both ways). Called via
1341 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1342 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1343 # e.g., "obj1.portA[3] = obj2.portB".
1344 def connect(self
, other
):
1345 if isinstance(other
, VectorPortRef
):
1346 # reference to plain VectorPort is implicit append
1347 other
= other
._get
_next
()
1348 if self
.peer
and not proxy
.isproxy(self
.peer
):
1349 print "warning: overwriting port", self
, \
1350 "value", self
.peer
, "with", other
1351 self
.peer
.peer
= None
1353 if proxy
.isproxy(other
):
1354 other
.set_param_desc(PortParamDesc())
1355 elif isinstance(other
, PortRef
):
1356 if other
.peer
is not self
:
1360 "assigning non-port reference '%s' to port '%s'" \
1363 def clone(self
, simobj
, memo
):
1364 if memo
.has_key(self
):
1366 newRef
= copy
.copy(self
)
1368 newRef
.simobj
= simobj
1369 assert(isSimObject(newRef
.simobj
))
1370 if self
.peer
and not proxy
.isproxy(self
.peer
):
1371 peerObj
= self
.peer
.simobj(_memo
=memo
)
1372 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1373 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1376 def unproxy(self
, simobj
):
1377 assert(simobj
is self
.simobj
)
1378 if proxy
.isproxy(self
.peer
):
1380 realPeer
= self
.peer
.unproxy(self
.simobj
)
1382 print "Error in unproxying port '%s' of %s" % \
1383 (self
.name
, self
.simobj
.path())
1385 self
.connect(realPeer
)
1387 # Call C++ to create corresponding port connection between C++ objects
1388 def ccConnect(self
):
1389 from m5
.internal
.pyobject
import connectPorts
1391 if self
.ccConnected
: # already done this
1394 if not self
.peer
: # nothing to connect to
1397 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1398 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1400 print "Error connecting port %s.%s to %s.%s" % \
1401 (self
.simobj
.path(), self
.name
,
1402 peer
.simobj
.path(), peer
.name
)
1404 self
.ccConnected
= True
1405 peer
.ccConnected
= True
1407 # A reference to an individual element of a VectorPort... much like a
1408 # PortRef, but has an index.
1409 class VectorPortElementRef(PortRef
):
1410 def __init__(self
, simobj
, name
, index
):
1411 PortRef
.__init
__(self
, simobj
, name
)
1415 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1417 # A reference to a complete vector-valued port (not just a single element).
1418 # Can be indexed to retrieve individual VectorPortElementRef instances.
1419 class VectorPortRef(object):
1420 def __init__(self
, simobj
, name
):
1421 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1422 self
.simobj
= simobj
1427 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1429 # for config.ini, print peer's name (not ours)
1431 return ' '.join([el
.ini_str() for el
in self
.elements
])
1433 def __getitem__(self
, key
):
1434 if not isinstance(key
, int):
1435 raise TypeError, "VectorPort index must be integer"
1436 if key
>= len(self
.elements
):
1437 # need to extend list
1438 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1439 for i
in range(len(self
.elements
), key
+1)]
1440 self
.elements
.extend(ext
)
1441 return self
.elements
[key
]
1443 def _get_next(self
):
1444 return self
[len(self
.elements
)]
1446 def __setitem__(self
, key
, value
):
1447 if not isinstance(key
, int):
1448 raise TypeError, "VectorPort index must be integer"
1449 self
[key
].connect(value
)
1451 def connect(self
, other
):
1452 if isinstance(other
, (list, tuple)):
1453 # Assign list of port refs to vector port.
1454 # For now, append them... not sure if that's the right semantics
1455 # or if it should replace the current vector.
1457 self
._get
_next
().connect(ref
)
1459 # scalar assignment to plain VectorPort is implicit append
1460 self
._get
_next
().connect(other
)
1462 def clone(self
, simobj
, memo
):
1463 if memo
.has_key(self
):
1465 newRef
= copy
.copy(self
)
1467 newRef
.simobj
= simobj
1468 assert(isSimObject(newRef
.simobj
))
1469 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1472 def unproxy(self
, simobj
):
1473 [el
.unproxy(simobj
) for el
in self
.elements
]
1475 def ccConnect(self
):
1476 [el
.ccConnect() for el
in self
.elements
]
1478 # Port description object. Like a ParamDesc object, this represents a
1479 # logical port in the SimObject class, not a particular port on a
1480 # SimObject instance. The latter are represented by PortRef objects.
1482 # Port("description") or Port(default, "description")
1483 def __init__(self
, *args
):
1486 elif len(args
) == 2:
1487 self
.default
= args
[0]
1490 raise TypeError, 'wrong number of arguments'
1491 # self.name is set by SimObject class on assignment
1492 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1494 # Generate a PortRef for this port on the given SimObject with the
1496 def makeRef(self
, simobj
):
1497 return PortRef(simobj
, self
.name
)
1499 # Connect an instance of this port (on the given SimObject with
1500 # the given name) with the port described by the supplied PortRef
1501 def connect(self
, simobj
, ref
):
1502 self
.makeRef(simobj
).connect(ref
)
1504 # VectorPort description object. Like Port, but represents a vector
1505 # of connections (e.g., as on a Bus).
1506 class VectorPort(Port
):
1507 def __init__(self
, *args
):
1508 Port
.__init
__(self
, *args
)
1511 def makeRef(self
, simobj
):
1512 return VectorPortRef(simobj
, self
.name
)
1514 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1515 # proxy objects (via set_param_desc()) so that proxy error messages
1517 class PortParamDesc(object):
1518 __metaclass__
= Singleton
1523 baseEnums
= allEnums
.copy()
1524 baseParams
= allParams
.copy()
1527 global allEnums
, allParams
1529 allEnums
= baseEnums
.copy()
1530 allParams
= baseParams
.copy()
1532 __all__
= ['Param', 'VectorParam',
1533 'Enum', 'Bool', 'String', 'Float',
1534 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1535 'Int32', 'UInt32', 'Int64', 'UInt64',
1536 'Counter', 'Addr', 'Tick', 'Percent',
1537 'TcpPort', 'UdpPort', 'EthernetAddr',
1538 'IpAddress', 'IpNetmask', 'IpWithPort',
1539 'MemorySize', 'MemorySize32',
1540 'Latency', 'Frequency', 'Clock',
1541 'NetworkBandwidth', 'MemoryBandwidth',
1542 'Range', 'AddrRange', 'TickRange',
1543 'MaxAddr', 'MaxTick', 'AllMemory',
1545 'NextEthernetAddr', 'NULL',
1546 'Port', 'VectorPort']