ee3678dc9b7c8b31b0a38ab529941c162fb3f6f9
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 self
.ptype
.swig_predecls(code
)
261 code('%include "std_vector.i"')
264 ptype
= self
.ptype_str
265 cxx_type
= self
.ptype
.cxx_type
268 %typemap(in) std::vector< $cxx_type >::value_type {
269 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
270 if (SWIG_ConvertPtr($$input, (void **)&$$1,
271 $$descriptor($cxx_type), 0) == -1) {
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) {
287 code('%template(vector_$ptype) std::vector< $cxx_type >;')
289 def cxx_predecls(self
, code
):
290 code('#include <vector>')
291 self
.ptype
.cxx_predecls(code
)
293 def cxx_decl(self
, code
):
294 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
296 class ParamFactory(object):
297 def __init__(self
, param_desc_class
, ptype_str
= None):
298 self
.param_desc_class
= param_desc_class
299 self
.ptype_str
= ptype_str
301 def __getattr__(self
, attr
):
303 attr
= self
.ptype_str
+ '.' + attr
304 return ParamFactory(self
.param_desc_class
, attr
)
306 # E.g., Param.Int(5, "number of widgets")
307 def __call__(self
, *args
, **kwargs
):
310 ptype
= allParams
[self
.ptype_str
]
312 # if name isn't defined yet, assume it's a SimObject, and
313 # try to resolve it later
315 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
317 Param
= ParamFactory(ParamDesc
)
318 VectorParam
= ParamFactory(VectorParamDesc
)
320 #####################################################################
324 # Though native Python types could be used to specify parameter types
325 # (the 'ptype' field of the Param and VectorParam classes), it's more
326 # flexible to define our own set of types. This gives us more control
327 # over how Python expressions are converted to values (via the
328 # __init__() constructor) and how these values are printed out (via
329 # the __str__() conversion method).
331 #####################################################################
333 # String-valued parameter. Just mixin the ParamValue class with the
334 # built-in str class.
335 class String(ParamValue
,str):
336 cxx_type
= 'std::string'
339 def cxx_predecls(self
, code
):
340 code('#include <string>')
343 def swig_predecls(cls
, code
):
344 code('%include "std_string.i"')
349 # superclass for "numeric" parameter values, to emulate math
350 # operations in a type-safe way. e.g., a Latency times an int returns
351 # a new Latency object.
352 class NumericParamValue(ParamValue
):
354 return str(self
.value
)
357 return float(self
.value
)
360 return long(self
.value
)
363 return int(self
.value
)
365 # hook for bounds checking
369 def __mul__(self
, other
):
370 newobj
= self
.__class
__(self
)
371 newobj
.value
*= other
377 def __div__(self
, other
):
378 newobj
= self
.__class
__(self
)
379 newobj
.value
/= other
383 def __sub__(self
, other
):
384 newobj
= self
.__class
__(self
)
385 newobj
.value
-= other
389 # Metaclass for bounds-checked integer parameters. See CheckedInt.
390 class CheckedIntType(MetaParamValue
):
391 def __init__(cls
, name
, bases
, dict):
392 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
394 # CheckedInt is an abstract base class, so we actually don't
395 # want to do any processing on it... the rest of this code is
396 # just for classes that derive from CheckedInt.
397 if name
== 'CheckedInt':
400 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
401 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
402 panic("CheckedInt subclass %s must define either\n" \
403 " 'min' and 'max' or 'size' and 'unsigned'\n",
407 cls
.max = 2 ** cls
.size
- 1
409 cls
.min = -(2 ** (cls
.size
- 1))
410 cls
.max = (2 ** (cls
.size
- 1)) - 1
412 # Abstract superclass for bounds-checked integer parameters. This
413 # class is subclassed to generate parameter classes with specific
414 # bounds. Initialization of the min and max bounds is done in the
415 # metaclass CheckedIntType.__init__.
416 class CheckedInt(NumericParamValue
):
417 __metaclass__
= CheckedIntType
420 if not self
.min <= self
.value
<= self
.max:
421 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
422 (self
.min, self
.value
, self
.max)
424 def __init__(self
, value
):
425 if isinstance(value
, str):
426 self
.value
= convert
.toInteger(value
)
427 elif isinstance(value
, (int, long, float, NumericParamValue
)):
428 self
.value
= long(value
)
430 raise TypeError, "Can't convert object of type %s to CheckedInt" \
431 % type(value
).__name
__
435 def cxx_predecls(cls
, code
):
436 # most derived types require this, so we just do it here once
437 code('#include "base/types.hh"')
440 def swig_predecls(cls
, code
):
441 # most derived types require this, so we just do it here once
442 code('%import "stdint.i"')
443 code('%import "base/types.hh"')
446 return long(self
.value
)
448 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
449 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
451 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
452 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
453 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
454 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
455 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
456 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
457 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
458 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
460 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
461 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
462 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
463 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
465 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
467 class Float(ParamValue
, float):
470 def __init__(self
, value
):
471 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
472 self
.value
= float(value
)
474 raise TypeError, "Can't convert object of type %s to Float" \
475 % type(value
).__name
__
478 return float(self
.value
)
480 class MemorySize(CheckedInt
):
481 cxx_type
= 'uint64_t'
484 def __init__(self
, value
):
485 if isinstance(value
, MemorySize
):
486 self
.value
= value
.value
488 self
.value
= convert
.toMemorySize(value
)
491 class MemorySize32(CheckedInt
):
492 cxx_type
= 'uint32_t'
495 def __init__(self
, value
):
496 if isinstance(value
, MemorySize
):
497 self
.value
= value
.value
499 self
.value
= convert
.toMemorySize(value
)
502 class Addr(CheckedInt
):
506 def __init__(self
, value
):
507 if isinstance(value
, Addr
):
508 self
.value
= value
.value
511 self
.value
= convert
.toMemorySize(value
)
513 self
.value
= long(value
)
515 def __add__(self
, other
):
516 if isinstance(other
, Addr
):
517 return self
.value
+ other
.value
519 return self
.value
+ other
522 class MetaRange(MetaParamValue
):
523 def __init__(cls
, name
, bases
, dict):
524 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
527 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
529 class Range(ParamValue
):
530 __metaclass__
= MetaRange
531 type = Int
# default; can be overridden in subclasses
532 def __init__(self
, *args
, **kwargs
):
533 def handle_kwargs(self
, kwargs
):
535 self
.second
= self
.type(kwargs
.pop('end'))
536 elif 'size' in kwargs
:
537 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
539 raise TypeError, "Either end or size must be specified"
542 self
.first
= self
.type(kwargs
.pop('start'))
543 handle_kwargs(self
, kwargs
)
547 self
.first
= self
.type(args
[0])
548 handle_kwargs(self
, kwargs
)
549 elif isinstance(args
[0], Range
):
550 self
.first
= self
.type(args
[0].first
)
551 self
.second
= self
.type(args
[0].second
)
552 elif isinstance(args
[0], (list, tuple)):
553 self
.first
= self
.type(args
[0][0])
554 self
.second
= self
.type(args
[0][1])
556 self
.first
= self
.type(0)
557 self
.second
= self
.type(args
[0]) - 1
560 self
.first
= self
.type(args
[0])
561 self
.second
= self
.type(args
[1])
563 raise TypeError, "Too many arguments specified"
566 raise TypeError, "too many keywords: %s" % kwargs
.keys()
569 return '%s:%s' % (self
.first
, self
.second
)
572 def cxx_predecls(cls
, code
):
573 cls
.type.cxx_predecls(code
)
574 code('#include "base/range.hh"')
577 def swig_predecls(cls
, code
):
578 cls
.type.swig_predecls(code
)
579 code('%import "python/swig/range.i"')
581 class AddrRange(Range
):
585 from m5
.internal
.range import AddrRange
588 value
.start
= long(self
.first
)
589 value
.end
= long(self
.second
)
592 class TickRange(Range
):
596 from m5
.internal
.range import TickRange
599 value
.start
= long(self
.first
)
600 value
.end
= long(self
.second
)
603 # Boolean parameter type. Python doesn't let you subclass bool, since
604 # it doesn't want to let you create multiple instances of True and
605 # False. Thus this is a little more complicated than String.
606 class Bool(ParamValue
):
608 def __init__(self
, value
):
610 self
.value
= convert
.toBool(value
)
612 self
.value
= bool(value
)
615 return bool(self
.value
)
618 return str(self
.value
)
625 def IncEthernetAddr(addr
, val
= 1):
626 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
628 for i
in (5, 4, 3, 2, 1):
629 val
,rem
= divmod(bytes
[i
], 256)
634 assert(bytes
[0] <= 255)
635 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
637 _NextEthernetAddr
= "00:90:00:00:00:01"
638 def NextEthernetAddr():
639 global _NextEthernetAddr
641 value
= _NextEthernetAddr
642 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
645 class EthernetAddr(ParamValue
):
646 cxx_type
= 'Net::EthAddr'
649 def cxx_predecls(cls
, code
):
650 code('#include "base/inet.hh"')
653 def swig_predecls(cls
, code
):
654 code('%include "python/swig/inet.i"')
656 def __init__(self
, value
):
657 if value
== NextEthernetAddr
:
661 if not isinstance(value
, str):
662 raise TypeError, "expected an ethernet address and didn't get one"
664 bytes
= value
.split(':')
666 raise TypeError, 'invalid ethernet address %s' % value
669 if not 0 <= int(byte
) <= 0xff:
670 raise TypeError, 'invalid ethernet address %s' % value
674 def unproxy(self
, base
):
675 if self
.value
== NextEthernetAddr
:
676 return EthernetAddr(self
.value())
680 from m5
.internal
.params
import EthAddr
681 return EthAddr(self
.value
)
686 # When initializing an IpAddress, pass in an existing IpAddress, a string of
687 # the form "a.b.c.d", or an integer representing an IP.
688 class IpAddress(ParamValue
):
689 cxx_type
= 'Net::IpAddress'
692 def cxx_predecls(cls
, code
):
693 code('#include "base/inet.hh"')
696 def swig_predecls(cls
, code
):
697 code('%include "python/swig/inet.i"')
699 def __init__(self
, value
):
700 if isinstance(value
, IpAddress
):
704 self
.ip
= convert
.toIpAddress(value
)
706 self
.ip
= long(value
)
710 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
711 return '%d.%d.%d.%d' % tuple(tup
)
713 def __eq__(self
, other
):
714 if isinstance(other
, IpAddress
):
715 return self
.ip
== other
.ip
716 elif isinstance(other
, str):
718 return self
.ip
== convert
.toIpAddress(other
)
722 return self
.ip
== other
724 def __ne__(self
, other
):
725 return not (self
== other
)
728 if self
.ip
< 0 or self
.ip
>= (1 << 32):
729 raise TypeError, "invalid ip address %#08x" % self
.ip
732 from m5
.internal
.params
import IpAddress
733 return IpAddress(self
.ip
)
735 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
736 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
737 # positional or keyword arguments.
738 class IpNetmask(IpAddress
):
739 cxx_type
= 'Net::IpNetmask'
742 def cxx_predecls(cls
, code
):
743 code('#include "base/inet.hh"')
746 def swig_predecls(cls
, code
):
747 code('%include "python/swig/inet.i"')
749 def __init__(self
, *args
, **kwargs
):
750 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
752 setattr(self
, key
, kwargs
.pop(key
))
754 setattr(self
, key
, elseVal
)
756 raise TypeError, "No value set for %s" % key
759 handle_kwarg(self
, kwargs
, 'ip')
760 handle_kwarg(self
, kwargs
, 'netmask')
764 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
765 raise TypeError, "Invalid arguments"
766 handle_kwarg(self
, kwargs
, 'ip', args
[0])
767 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
768 elif isinstance(args
[0], IpNetmask
):
770 self
.netmask
= args
[0].netmask
772 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
776 self
.netmask
= args
[1]
778 raise TypeError, "Too many arguments specified"
781 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
786 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
788 def __eq__(self
, other
):
789 if isinstance(other
, IpNetmask
):
790 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
791 elif isinstance(other
, str):
793 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
801 if self
.netmask
< 0 or self
.netmask
> 32:
802 raise TypeError, "invalid netmask %d" % netmask
805 from m5
.internal
.params
import IpNetmask
806 return IpNetmask(self
.ip
, self
.netmask
)
808 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
809 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
810 class IpWithPort(IpAddress
):
811 cxx_type
= 'Net::IpWithPort'
814 def cxx_predecls(cls
, code
):
815 code('#include "base/inet.hh"')
818 def swig_predecls(cls
, code
):
819 code('%include "python/swig/inet.i"')
821 def __init__(self
, *args
, **kwargs
):
822 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
824 setattr(self
, key
, kwargs
.pop(key
))
826 setattr(self
, key
, elseVal
)
828 raise TypeError, "No value set for %s" % key
831 handle_kwarg(self
, kwargs
, 'ip')
832 handle_kwarg(self
, kwargs
, 'port')
836 if not 'ip' in kwargs
and not 'port' in kwargs
:
837 raise TypeError, "Invalid arguments"
838 handle_kwarg(self
, kwargs
, 'ip', args
[0])
839 handle_kwarg(self
, kwargs
, 'port', args
[0])
840 elif isinstance(args
[0], IpWithPort
):
842 self
.port
= args
[0].port
844 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
850 raise TypeError, "Too many arguments specified"
853 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
858 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
860 def __eq__(self
, other
):
861 if isinstance(other
, IpWithPort
):
862 return self
.ip
== other
.ip
and self
.port
== other
.port
863 elif isinstance(other
, str):
865 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
873 if self
.port
< 0 or self
.port
> 0xffff:
874 raise TypeError, "invalid port %d" % self
.port
877 from m5
.internal
.params
import IpWithPort
878 return IpWithPort(self
.ip
, self
.port
)
880 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
881 "%a %b %d %H:%M:%S %Z %Y",
893 def parse_time(value
):
894 from time
import gmtime
, strptime
, struct_time
, time
895 from datetime
import datetime
, date
897 if isinstance(value
, struct_time
):
900 if isinstance(value
, (int, long)):
903 if isinstance(value
, (datetime
, date
)):
904 return value
.timetuple()
906 if isinstance(value
, str):
907 if value
in ('Now', 'Today'):
908 return time
.gmtime(time
.time())
910 for format
in time_formats
:
912 return strptime(value
, format
)
916 raise ValueError, "Could not parse '%s' as a time" % value
918 class Time(ParamValue
):
922 def cxx_predecls(cls
, code
):
923 code('#include <time.h>')
926 def swig_predecls(cls
, code
):
927 code('%include "python/swig/time.i"')
929 def __init__(self
, value
):
930 self
.value
= parse_time(value
)
933 from m5
.internal
.params
import tm
938 # UNIX is years since 1900
939 c_time
.tm_year
= py_time
.tm_year
- 1900;
941 # Python starts at 1, UNIX starts at 0
942 c_time
.tm_mon
= py_time
.tm_mon
- 1;
943 c_time
.tm_mday
= py_time
.tm_mday
;
944 c_time
.tm_hour
= py_time
.tm_hour
;
945 c_time
.tm_min
= py_time
.tm_min
;
946 c_time
.tm_sec
= py_time
.tm_sec
;
948 # Python has 0 as Monday, UNIX is 0 as sunday
949 c_time
.tm_wday
= py_time
.tm_wday
+ 1
950 if c_time
.tm_wday
> 6:
953 # Python starts at 1, Unix starts at 0
954 c_time
.tm_yday
= py_time
.tm_yday
- 1;
959 return time
.asctime(self
.value
)
964 # Enumerated types are a little more complex. The user specifies the
965 # type as Enum(foo) where foo is either a list or dictionary of
966 # alternatives (typically strings, but not necessarily so). (In the
967 # long run, the integer value of the parameter will be the list index
968 # or the corresponding dictionary value. For now, since we only check
969 # that the alternative is valid and then spit it into a .ini file,
970 # there's not much point in using the dictionary.)
972 # What Enum() must do is generate a new type encapsulating the
973 # provided list/dictionary so that specific values of the parameter
974 # can be instances of that type. We define two hidden internal
975 # classes (_ListEnum and _DictEnum) to serve as base classes, then
976 # derive the new type from the appropriate base class on the fly.
979 # Metaclass for Enum types
980 class MetaEnum(MetaParamValue
):
981 def __new__(mcls
, name
, bases
, dict):
982 assert name
not in allEnums
984 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
988 def __init__(cls
, name
, bases
, init_dict
):
989 if init_dict
.has_key('map'):
990 if not isinstance(cls
.map, dict):
991 raise TypeError, "Enum-derived class attribute 'map' " \
992 "must be of type dict"
993 # build list of value strings from map
994 cls
.vals
= cls
.map.keys()
996 elif init_dict
.has_key('vals'):
997 if not isinstance(cls
.vals
, list):
998 raise TypeError, "Enum-derived class attribute 'vals' " \
999 "must be of type list"
1000 # build string->value map from vals sequence
1002 for idx
,val
in enumerate(cls
.vals
):
1005 raise TypeError, "Enum-derived class must define "\
1006 "attribute 'map' or 'vals'"
1008 cls
.cxx_type
= 'Enums::%s' % name
1010 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1012 # Generate C++ class declaration for this enum type.
1013 # Note that we wrap the enum in a class/struct to act as a namespace,
1014 # so that the enum strings can be brief w/o worrying about collisions.
1015 def cxx_decl(cls
, code
):
1018 #ifndef __ENUM__${name}__
1019 #define __ENUM__${name}__
1025 for val
in cls
.vals
:
1026 code('$val = ${{cls.map[val]}},')
1027 code('Num_$name = ${{len(cls.vals)}},')
1031 extern const char *${name}Strings[Num_${name}];
1034 #endif // __ENUM__${name}__
1037 def cxx_def(cls
, code
):
1040 #include "enums/$name.hh"
1042 const char *${name}Strings[Num_${name}] =
1046 for val
in cls
.vals
:
1051 } // namespace Enums
1054 def swig_decl(cls
, code
):
1057 %module(package="m5.internal") enum_$name
1060 #include "enums/$name.hh"
1063 %include "enums/$name.hh"
1067 # Base class for enum types.
1068 class Enum(ParamValue
):
1069 __metaclass__
= MetaEnum
1072 def __init__(self
, value
):
1073 if value
not in self
.map:
1074 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1075 % (value
, self
.vals
)
1079 def cxx_predecls(cls
, code
):
1080 code('#include "enums/$0.hh"', cls
.__name
__)
1083 def swig_predecls(cls
, code
):
1084 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1087 return int(self
.map[self
.value
])
1092 # how big does a rounding error need to be before we warn about it?
1093 frequency_tolerance
= 0.001 # 0.1%
1095 class TickParamValue(NumericParamValue
):
1099 def cxx_predecls(cls
, code
):
1100 code('#include "base/types.hh"')
1103 def swig_predecls(cls
, code
):
1104 code('%import "stdint.i"')
1105 code('%import "base/types.hh"')
1108 return long(self
.value
)
1110 class Latency(TickParamValue
):
1111 def __init__(self
, value
):
1112 if isinstance(value
, (Latency
, Clock
)):
1113 self
.ticks
= value
.ticks
1114 self
.value
= value
.value
1115 elif isinstance(value
, Frequency
):
1116 self
.ticks
= value
.ticks
1117 self
.value
= 1.0 / value
.value
1118 elif value
.endswith('t'):
1120 self
.value
= int(value
[:-1])
1123 self
.value
= convert
.toLatency(value
)
1125 def __getattr__(self
, attr
):
1126 if attr
in ('latency', 'period'):
1128 if attr
== 'frequency':
1129 return Frequency(self
)
1130 raise AttributeError, "Latency object has no attribute '%s'" % attr
1133 if self
.ticks
or self
.value
== 0:
1136 value
= ticks
.fromSeconds(self
.value
)
1139 # convert latency to ticks
1141 return '%d' % self
.getValue()
1143 class Frequency(TickParamValue
):
1144 def __init__(self
, value
):
1145 if isinstance(value
, (Latency
, Clock
)):
1146 if value
.value
== 0:
1149 self
.value
= 1.0 / value
.value
1150 self
.ticks
= value
.ticks
1151 elif isinstance(value
, Frequency
):
1152 self
.value
= value
.value
1153 self
.ticks
= value
.ticks
1156 self
.value
= convert
.toFrequency(value
)
1158 def __getattr__(self
, attr
):
1159 if attr
== 'frequency':
1161 if attr
in ('latency', 'period'):
1162 return Latency(self
)
1163 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1165 # convert latency to ticks
1167 if self
.ticks
or self
.value
== 0:
1170 value
= ticks
.fromSeconds(1.0 / self
.value
)
1174 return '%d' % self
.getValue()
1176 # A generic frequency and/or Latency value. Value is stored as a latency,
1177 # but to avoid ambiguity this object does not support numeric ops (* or /).
1178 # An explicit conversion to a Latency or Frequency must be made first.
1179 class Clock(ParamValue
):
1183 def cxx_predecls(cls
, code
):
1184 code('#include "base/types.hh"')
1187 def swig_predecls(cls
, code
):
1188 code('%import "stdint.i"')
1189 code('%import "base/types.hh"')
1191 def __init__(self
, value
):
1192 if isinstance(value
, (Latency
, Clock
)):
1193 self
.ticks
= value
.ticks
1194 self
.value
= value
.value
1195 elif isinstance(value
, Frequency
):
1196 self
.ticks
= value
.ticks
1197 self
.value
= 1.0 / value
.value
1198 elif value
.endswith('t'):
1200 self
.value
= int(value
[:-1])
1203 self
.value
= convert
.anyToLatency(value
)
1205 def __getattr__(self
, attr
):
1206 if attr
== 'frequency':
1207 return Frequency(self
)
1208 if attr
in ('latency', 'period'):
1209 return Latency(self
)
1210 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1213 return self
.period
.getValue()
1216 return self
.period
.ini_str()
1218 class NetworkBandwidth(float,ParamValue
):
1220 def __new__(cls
, value
):
1221 # convert to bits per second
1222 val
= convert
.toNetworkBandwidth(value
)
1223 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1226 return str(self
.val
)
1229 # convert to seconds per byte
1230 value
= 8.0 / float(self
)
1231 # convert to ticks per byte
1232 value
= ticks
.fromSeconds(value
)
1236 return '%f' % self
.getValue()
1238 class MemoryBandwidth(float,ParamValue
):
1240 def __new__(cls
, value
):
1241 # convert to bytes per second
1242 val
= convert
.toMemoryBandwidth(value
)
1243 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1246 return str(self
.val
)
1249 # convert to seconds per byte
1252 value
= 1.0 / float(self
)
1253 # convert to ticks per byte
1254 value
= ticks
.fromSeconds(value
)
1258 return '%f' % self
.getValue()
1261 # "Constants"... handy aliases for various values.
1264 # Special class for NULL pointers. Note the special check in
1265 # make_param_value() above that lets these be assigned where a
1266 # SimObject is required.
1267 # only one copy of a particular node
1268 class NullSimObject(object):
1269 __metaclass__
= Singleton
1274 def _instantiate(self
, parent
= None, path
= ''):
1280 def unproxy(self
, base
):
1283 def set_path(self
, parent
, name
):
1292 # The only instance you'll ever need...
1293 NULL
= NullSimObject()
1295 def isNullPointer(value
):
1296 return isinstance(value
, NullSimObject
)
1298 # Some memory range specifications use this as a default upper bound.
1301 AllMemory
= AddrRange(0, MaxAddr
)
1304 #####################################################################
1308 # Ports are used to interconnect objects in the memory system.
1310 #####################################################################
1312 # Port reference: encapsulates a reference to a particular port on a
1313 # particular SimObject.
1314 class PortRef(object):
1315 def __init__(self
, simobj
, name
):
1316 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1317 self
.simobj
= simobj
1319 self
.peer
= None # not associated with another port yet
1320 self
.ccConnected
= False # C++ port connection done?
1321 self
.index
= -1 # always -1 for non-vector ports
1324 return '%s.%s' % (self
.simobj
, self
.name
)
1326 # for config.ini, print peer's name (not ours)
1328 return str(self
.peer
)
1330 def __getattr__(self
, attr
):
1331 if attr
== 'peerObj':
1332 # shorthand for proxies
1333 return self
.peer
.simobj
1334 raise AttributeError, "'%s' object has no attribute '%s'" % \
1335 (self
.__class
__.__name
__, attr
)
1337 # Full connection is symmetric (both ways). Called via
1338 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1339 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1340 # e.g., "obj1.portA[3] = obj2.portB".
1341 def connect(self
, other
):
1342 if isinstance(other
, VectorPortRef
):
1343 # reference to plain VectorPort is implicit append
1344 other
= other
._get
_next
()
1345 if self
.peer
and not proxy
.isproxy(self
.peer
):
1346 print "warning: overwriting port", self
, \
1347 "value", self
.peer
, "with", other
1348 self
.peer
.peer
= None
1350 if proxy
.isproxy(other
):
1351 other
.set_param_desc(PortParamDesc())
1352 elif isinstance(other
, PortRef
):
1353 if other
.peer
is not self
:
1357 "assigning non-port reference '%s' to port '%s'" \
1360 def clone(self
, simobj
, memo
):
1361 if memo
.has_key(self
):
1363 newRef
= copy
.copy(self
)
1365 newRef
.simobj
= simobj
1366 assert(isSimObject(newRef
.simobj
))
1367 if self
.peer
and not proxy
.isproxy(self
.peer
):
1368 peerObj
= self
.peer
.simobj(_memo
=memo
)
1369 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1370 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1373 def unproxy(self
, simobj
):
1374 assert(simobj
is self
.simobj
)
1375 if proxy
.isproxy(self
.peer
):
1377 realPeer
= self
.peer
.unproxy(self
.simobj
)
1379 print "Error in unproxying port '%s' of %s" % \
1380 (self
.name
, self
.simobj
.path())
1382 self
.connect(realPeer
)
1384 # Call C++ to create corresponding port connection between C++ objects
1385 def ccConnect(self
):
1386 from m5
.internal
.pyobject
import connectPorts
1388 if self
.ccConnected
: # already done this
1391 if not self
.peer
: # nothing to connect to
1394 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1395 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1397 print "Error connecting port %s.%s to %s.%s" % \
1398 (self
.simobj
.path(), self
.name
,
1399 peer
.simobj
.path(), peer
.name
)
1401 self
.ccConnected
= True
1402 peer
.ccConnected
= True
1404 # A reference to an individual element of a VectorPort... much like a
1405 # PortRef, but has an index.
1406 class VectorPortElementRef(PortRef
):
1407 def __init__(self
, simobj
, name
, index
):
1408 PortRef
.__init
__(self
, simobj
, name
)
1412 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1414 # A reference to a complete vector-valued port (not just a single element).
1415 # Can be indexed to retrieve individual VectorPortElementRef instances.
1416 class VectorPortRef(object):
1417 def __init__(self
, simobj
, name
):
1418 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1419 self
.simobj
= simobj
1424 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1426 # for config.ini, print peer's name (not ours)
1428 return ' '.join([el
.ini_str() for el
in self
.elements
])
1430 def __getitem__(self
, key
):
1431 if not isinstance(key
, int):
1432 raise TypeError, "VectorPort index must be integer"
1433 if key
>= len(self
.elements
):
1434 # need to extend list
1435 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1436 for i
in range(len(self
.elements
), key
+1)]
1437 self
.elements
.extend(ext
)
1438 return self
.elements
[key
]
1440 def _get_next(self
):
1441 return self
[len(self
.elements
)]
1443 def __setitem__(self
, key
, value
):
1444 if not isinstance(key
, int):
1445 raise TypeError, "VectorPort index must be integer"
1446 self
[key
].connect(value
)
1448 def connect(self
, other
):
1449 if isinstance(other
, (list, tuple)):
1450 # Assign list of port refs to vector port.
1451 # For now, append them... not sure if that's the right semantics
1452 # or if it should replace the current vector.
1454 self
._get
_next
().connect(ref
)
1456 # scalar assignment to plain VectorPort is implicit append
1457 self
._get
_next
().connect(other
)
1459 def clone(self
, simobj
, memo
):
1460 if memo
.has_key(self
):
1462 newRef
= copy
.copy(self
)
1464 newRef
.simobj
= simobj
1465 assert(isSimObject(newRef
.simobj
))
1466 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1469 def unproxy(self
, simobj
):
1470 [el
.unproxy(simobj
) for el
in self
.elements
]
1472 def ccConnect(self
):
1473 [el
.ccConnect() for el
in self
.elements
]
1475 # Port description object. Like a ParamDesc object, this represents a
1476 # logical port in the SimObject class, not a particular port on a
1477 # SimObject instance. The latter are represented by PortRef objects.
1479 # Port("description") or Port(default, "description")
1480 def __init__(self
, *args
):
1483 elif len(args
) == 2:
1484 self
.default
= args
[0]
1487 raise TypeError, 'wrong number of arguments'
1488 # self.name is set by SimObject class on assignment
1489 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1491 # Generate a PortRef for this port on the given SimObject with the
1493 def makeRef(self
, simobj
):
1494 return PortRef(simobj
, self
.name
)
1496 # Connect an instance of this port (on the given SimObject with
1497 # the given name) with the port described by the supplied PortRef
1498 def connect(self
, simobj
, ref
):
1499 self
.makeRef(simobj
).connect(ref
)
1501 # VectorPort description object. Like Port, but represents a vector
1502 # of connections (e.g., as on a Bus).
1503 class VectorPort(Port
):
1504 def __init__(self
, *args
):
1505 Port
.__init
__(self
, *args
)
1508 def makeRef(self
, simobj
):
1509 return VectorPortRef(simobj
, self
.name
)
1511 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1512 # proxy objects (via set_param_desc()) so that proxy error messages
1514 class PortParamDesc(object):
1515 __metaclass__
= Singleton
1520 baseEnums
= allEnums
.copy()
1521 baseParams
= allParams
.copy()
1524 global allEnums
, allParams
1526 allEnums
= baseEnums
.copy()
1527 allParams
= baseParams
.copy()
1529 __all__
= ['Param', 'VectorParam',
1530 'Enum', 'Bool', 'String', 'Float',
1531 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1532 'Int32', 'UInt32', 'Int64', 'UInt64',
1533 'Counter', 'Addr', 'Tick', 'Percent',
1534 'TcpPort', 'UdpPort', 'EthernetAddr',
1535 'IpAddress', 'IpNetmask', 'IpWithPort',
1536 'MemorySize', 'MemorySize32',
1537 'Latency', 'Frequency', 'Clock',
1538 'NetworkBandwidth', 'MemoryBandwidth',
1539 'Range', 'AddrRange', 'TickRange',
1540 'MaxAddr', 'MaxTick', 'AllMemory',
1542 'NextEthernetAddr', 'NULL',
1543 'Port', 'VectorPort']