981bb0d37a9486a647546f705c833dea1f9af495
1 # Copyright (c) 2012-2013 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2004-2006 The Regents of The University of Michigan
14 # Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
15 # All rights reserved.
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 # Authors: Steve Reinhardt
45 #####################################################################
47 # Parameter description classes
49 # The _params dictionary in each class maps parameter names to either
50 # a Param or a VectorParam object. These objects contain the
51 # parameter description string, the parameter type, and the default
52 # value (if any). The convert() method on these objects is used to
53 # force whatever value is assigned to the parameter to the appropriate
56 # Note that the default values are loaded into the class's attribute
57 # space when the parameter dictionary is initialized (in
58 # MetaSimObject._new_param()); after that point they aren't used.
60 #####################################################################
73 def isSimObject(*args
, **kwargs
):
74 return SimObject
.isSimObject(*args
, **kwargs
)
76 def isSimObjectSequence(*args
, **kwargs
):
77 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
79 def isSimObjectClass(*args
, **kwargs
):
80 return SimObject
.isSimObjectClass(*args
, **kwargs
)
84 class MetaParamValue(type):
85 def __new__(mcls
, name
, bases
, dct
):
86 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
87 assert name
not in allParams
92 # Dummy base class to identify types that are legitimate for SimObject
94 class ParamValue(object):
95 __metaclass__
= MetaParamValue
98 # Generate the code needed as a prerequisite for declaring a C++
99 # object of this type. Typically generates one or more #include
100 # statements. Used when declaring parameters of this type.
102 def cxx_predecls(cls
, code
):
105 # Generate the code needed as a prerequisite for including a
106 # reference to a C++ object of this type in a SWIG .i file.
107 # Typically generates one or more %import or %include statements.
109 def swig_predecls(cls
, code
):
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
117 # allows us to blithely call unproxy() on things without checking
118 # if they're really proxies or not
119 def unproxy(self
, base
):
122 # Regular parameter description.
123 class ParamDesc(object):
124 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
125 self
.ptype_str
= ptype_str
126 # remember ptype only if it is provided
134 self
.default
= args
[0]
137 raise TypeError, 'too many arguments'
139 if kwargs
.has_key('desc'):
140 assert(not hasattr(self
, 'desc'))
141 self
.desc
= kwargs
['desc']
144 if kwargs
.has_key('default'):
145 assert(not hasattr(self
, 'default'))
146 self
.default
= kwargs
['default']
147 del kwargs
['default']
150 raise TypeError, 'extra unknown kwargs %s' % kwargs
152 if not hasattr(self
, 'desc'):
153 raise TypeError, 'desc attribute missing'
155 def __getattr__(self
, attr
):
157 ptype
= SimObject
.allClasses
[self
.ptype_str
]
158 assert isSimObjectClass(ptype
)
162 raise AttributeError, "'%s' object has no attribute '%s'" % \
163 (type(self
).__name
__, attr
)
165 def convert(self
, value
):
166 if isinstance(value
, proxy
.BaseProxy
):
167 value
.set_param_desc(self
)
169 if not hasattr(self
, 'ptype') and isNullPointer(value
):
170 # deferred evaluation of SimObject; continue to defer if
171 # we're just assigning a null pointer
173 if isinstance(value
, self
.ptype
):
175 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
177 return self
.ptype(value
)
179 def cxx_predecls(self
, code
):
180 code('#include <cstddef>')
181 self
.ptype
.cxx_predecls(code
)
183 def swig_predecls(self
, code
):
184 self
.ptype
.swig_predecls(code
)
186 def cxx_decl(self
, code
):
187 code('${{self.ptype.cxx_type}} ${{self.name}};')
189 # Vector-valued parameter description. Just like ParamDesc, except
190 # that the value is a vector (list) of the specified type instead of a
193 class VectorParamValue(list):
194 __metaclass__
= MetaParamValue
195 def __setattr__(self
, attr
, value
):
196 raise AttributeError, \
197 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
200 return ' '.join([v
.ini_str() for v
in self
])
203 return [ v
.getValue() for v
in self
]
205 def unproxy(self
, base
):
206 if len(self
) == 1 and isinstance(self
[0], proxy
.AllProxy
):
207 return self
[0].unproxy(base
)
209 return [v
.unproxy(base
) for v
in self
]
211 class SimObjectVector(VectorParamValue
):
212 # support clone operation
213 def __call__(self
, **kwargs
):
214 return SimObjectVector([v(**kwargs
) for v
in self
])
216 def clear_parent(self
, old_parent
):
218 v
.clear_parent(old_parent
)
220 def set_parent(self
, parent
, name
):
222 self
[0].set_parent(parent
, name
)
224 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
225 for i
,v
in enumerate(self
):
226 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
228 def has_parent(self
):
229 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
231 # return 'cpu0 cpu1' etc. for print_ini()
233 return ' '.join([v
._name
for v
in self
])
235 # By iterating through the constituent members of the vector here
236 # we can nicely handle iterating over all a SimObject's children
237 # without having to provide lots of special functions on
238 # SimObjectVector directly.
239 def descendants(self
):
241 for obj
in v
.descendants():
244 def get_config_as_dict(self
):
247 a
.append(v
.get_config_as_dict())
250 class VectorParamDesc(ParamDesc
):
251 # Convert assigned value to appropriate type. If the RHS is not a
252 # list or tuple, it generates a single-element list.
253 def convert(self
, value
):
254 if isinstance(value
, (list, tuple)):
255 # list: coerce each element into new list
256 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
258 # singleton: coerce to a single-element list
259 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
261 if isSimObjectSequence(tmp_list
):
262 return SimObjectVector(tmp_list
)
264 return VectorParamValue(tmp_list
)
266 def swig_module_name(self
):
267 return "%s_vector" % self
.ptype_str
269 def swig_predecls(self
, code
):
270 code('%import "${{self.swig_module_name()}}.i"')
272 def swig_decl(self
, code
):
273 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
275 self
.ptype
.cxx_predecls(code
)
278 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
279 code('%include "std_container.i"')
281 self
.ptype
.swig_predecls(code
)
283 code('%include "std_vector.i"')
286 ptype
= self
.ptype_str
287 cxx_type
= self
.ptype
.cxx_type
290 %typemap(in) std::vector< $cxx_type >::value_type {
291 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
292 if (SWIG_ConvertPtr($$input, (void **)&$$1,
293 $$descriptor($cxx_type), 0) == -1) {
299 %typemap(in) std::vector< $cxx_type >::value_type * {
300 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
301 if (SWIG_ConvertPtr($$input, (void **)&$$1,
302 $$descriptor($cxx_type *), 0) == -1) {
309 code('%template(vector_$ptype) std::vector< $cxx_type >;')
311 def cxx_predecls(self
, code
):
312 code('#include <vector>')
313 self
.ptype
.cxx_predecls(code
)
315 def cxx_decl(self
, code
):
316 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
318 class ParamFactory(object):
319 def __init__(self
, param_desc_class
, ptype_str
= None):
320 self
.param_desc_class
= param_desc_class
321 self
.ptype_str
= ptype_str
323 def __getattr__(self
, attr
):
325 attr
= self
.ptype_str
+ '.' + attr
326 return ParamFactory(self
.param_desc_class
, attr
)
328 # E.g., Param.Int(5, "number of widgets")
329 def __call__(self
, *args
, **kwargs
):
332 ptype
= allParams
[self
.ptype_str
]
334 # if name isn't defined yet, assume it's a SimObject, and
335 # try to resolve it later
337 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
339 Param
= ParamFactory(ParamDesc
)
340 VectorParam
= ParamFactory(VectorParamDesc
)
342 #####################################################################
346 # Though native Python types could be used to specify parameter types
347 # (the 'ptype' field of the Param and VectorParam classes), it's more
348 # flexible to define our own set of types. This gives us more control
349 # over how Python expressions are converted to values (via the
350 # __init__() constructor) and how these values are printed out (via
351 # the __str__() conversion method).
353 #####################################################################
355 # String-valued parameter. Just mixin the ParamValue class with the
356 # built-in str class.
357 class String(ParamValue
,str):
358 cxx_type
= 'std::string'
361 def cxx_predecls(self
, code
):
362 code('#include <string>')
365 def swig_predecls(cls
, code
):
366 code('%include "std_string.i"')
371 # superclass for "numeric" parameter values, to emulate math
372 # operations in a type-safe way. e.g., a Latency times an int returns
373 # a new Latency object.
374 class NumericParamValue(ParamValue
):
376 return str(self
.value
)
379 return float(self
.value
)
382 return long(self
.value
)
385 return int(self
.value
)
387 # hook for bounds checking
391 def __mul__(self
, other
):
392 newobj
= self
.__class
__(self
)
393 newobj
.value
*= other
399 def __div__(self
, other
):
400 newobj
= self
.__class
__(self
)
401 newobj
.value
/= other
405 def __sub__(self
, other
):
406 newobj
= self
.__class
__(self
)
407 newobj
.value
-= other
411 # Metaclass for bounds-checked integer parameters. See CheckedInt.
412 class CheckedIntType(MetaParamValue
):
413 def __init__(cls
, name
, bases
, dict):
414 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
416 # CheckedInt is an abstract base class, so we actually don't
417 # want to do any processing on it... the rest of this code is
418 # just for classes that derive from CheckedInt.
419 if name
== 'CheckedInt':
422 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
423 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
424 panic("CheckedInt subclass %s must define either\n" \
425 " 'min' and 'max' or 'size' and 'unsigned'\n",
429 cls
.max = 2 ** cls
.size
- 1
431 cls
.min = -(2 ** (cls
.size
- 1))
432 cls
.max = (2 ** (cls
.size
- 1)) - 1
434 # Abstract superclass for bounds-checked integer parameters. This
435 # class is subclassed to generate parameter classes with specific
436 # bounds. Initialization of the min and max bounds is done in the
437 # metaclass CheckedIntType.__init__.
438 class CheckedInt(NumericParamValue
):
439 __metaclass__
= CheckedIntType
442 if not self
.min <= self
.value
<= self
.max:
443 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
444 (self
.min, self
.value
, self
.max)
446 def __init__(self
, value
):
447 if isinstance(value
, str):
448 self
.value
= convert
.toInteger(value
)
449 elif isinstance(value
, (int, long, float, NumericParamValue
)):
450 self
.value
= long(value
)
452 raise TypeError, "Can't convert object of type %s to CheckedInt" \
453 % type(value
).__name
__
457 def cxx_predecls(cls
, code
):
458 # most derived types require this, so we just do it here once
459 code('#include "base/types.hh"')
462 def swig_predecls(cls
, code
):
463 # most derived types require this, so we just do it here once
464 code('%import "stdint.i"')
465 code('%import "base/types.hh"')
468 return long(self
.value
)
470 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
471 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
473 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
474 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
475 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
476 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
477 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
478 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
479 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
480 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
482 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
483 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
484 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
485 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
487 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
489 class Cycles(CheckedInt
):
495 from m5
.internal
.core
import Cycles
496 return Cycles(self
.value
)
498 class Float(ParamValue
, float):
501 def __init__(self
, value
):
502 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
503 self
.value
= float(value
)
505 raise TypeError, "Can't convert object of type %s to Float" \
506 % type(value
).__name
__
509 return float(self
.value
)
511 class MemorySize(CheckedInt
):
512 cxx_type
= 'uint64_t'
515 def __init__(self
, value
):
516 if isinstance(value
, MemorySize
):
517 self
.value
= value
.value
519 self
.value
= convert
.toMemorySize(value
)
522 class MemorySize32(CheckedInt
):
523 cxx_type
= 'uint32_t'
526 def __init__(self
, value
):
527 if isinstance(value
, MemorySize
):
528 self
.value
= value
.value
530 self
.value
= convert
.toMemorySize(value
)
533 class Addr(CheckedInt
):
537 def __init__(self
, value
):
538 if isinstance(value
, Addr
):
539 self
.value
= value
.value
542 self
.value
= convert
.toMemorySize(value
)
544 self
.value
= long(value
)
546 def __add__(self
, other
):
547 if isinstance(other
, Addr
):
548 return self
.value
+ other
.value
550 return self
.value
+ other
552 class AddrRange(ParamValue
):
553 cxx_type
= 'AddrRange'
555 def __init__(self
, *args
, **kwargs
):
556 # Disable interleaving by default
557 self
.intlvHighBit
= 0
561 def handle_kwargs(self
, kwargs
):
562 # An address range needs to have an upper limit, specified
563 # either explicitly with an end, or as an offset using the
566 self
.end
= Addr(kwargs
.pop('end'))
567 elif 'size' in kwargs
:
568 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
570 raise TypeError, "Either end or size must be specified"
572 # Now on to the optional bit
573 if 'intlvHighBit' in kwargs
:
574 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
575 if 'intlvBits' in kwargs
:
576 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
577 if 'intlvMatch' in kwargs
:
578 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
581 self
.start
= Addr(kwargs
.pop('start'))
582 handle_kwargs(self
, kwargs
)
586 self
.start
= Addr(args
[0])
587 handle_kwargs(self
, kwargs
)
588 elif isinstance(args
[0], (list, tuple)):
589 self
.start
= Addr(args
[0][0])
590 self
.end
= Addr(args
[0][1])
593 self
.end
= Addr(args
[0]) - 1
596 self
.start
= Addr(args
[0])
597 self
.end
= Addr(args
[1])
599 raise TypeError, "Too many arguments specified"
602 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
605 return '%s:%s' % (self
.start
, self
.end
)
608 # Divide the size by the size of the interleaving slice
609 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
612 def cxx_predecls(cls
, code
):
613 Addr
.cxx_predecls(code
)
614 code('#include "base/addr_range.hh"')
617 def swig_predecls(cls
, code
):
618 Addr
.swig_predecls(code
)
621 # Go from the Python class to the wrapped C++ class generated
623 from m5
.internal
.range import AddrRange
625 return AddrRange(long(self
.start
), long(self
.end
),
626 int(self
.intlvHighBit
), int(self
.intlvBits
),
627 int(self
.intlvMatch
))
629 # Boolean parameter type. Python doesn't let you subclass bool, since
630 # it doesn't want to let you create multiple instances of True and
631 # False. Thus this is a little more complicated than String.
632 class Bool(ParamValue
):
634 def __init__(self
, value
):
636 self
.value
= convert
.toBool(value
)
638 self
.value
= bool(value
)
641 return bool(self
.value
)
644 return str(self
.value
)
646 # implement truth value testing for Bool parameters so that these params
647 # evaluate correctly during the python configuration phase
648 def __nonzero__(self
):
649 return bool(self
.value
)
656 def IncEthernetAddr(addr
, val
= 1):
657 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
659 for i
in (5, 4, 3, 2, 1):
660 val
,rem
= divmod(bytes
[i
], 256)
665 assert(bytes
[0] <= 255)
666 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
668 _NextEthernetAddr
= "00:90:00:00:00:01"
669 def NextEthernetAddr():
670 global _NextEthernetAddr
672 value
= _NextEthernetAddr
673 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
676 class EthernetAddr(ParamValue
):
677 cxx_type
= 'Net::EthAddr'
680 def cxx_predecls(cls
, code
):
681 code('#include "base/inet.hh"')
684 def swig_predecls(cls
, code
):
685 code('%include "python/swig/inet.i"')
687 def __init__(self
, value
):
688 if value
== NextEthernetAddr
:
692 if not isinstance(value
, str):
693 raise TypeError, "expected an ethernet address and didn't get one"
695 bytes
= value
.split(':')
697 raise TypeError, 'invalid ethernet address %s' % value
700 if not 0 <= int(byte
, base
=16) <= 0xff:
701 raise TypeError, 'invalid ethernet address %s' % value
705 def unproxy(self
, base
):
706 if self
.value
== NextEthernetAddr
:
707 return EthernetAddr(self
.value())
711 from m5
.internal
.params
import EthAddr
712 return EthAddr(self
.value
)
717 # When initializing an IpAddress, pass in an existing IpAddress, a string of
718 # the form "a.b.c.d", or an integer representing an IP.
719 class IpAddress(ParamValue
):
720 cxx_type
= 'Net::IpAddress'
723 def cxx_predecls(cls
, code
):
724 code('#include "base/inet.hh"')
727 def swig_predecls(cls
, code
):
728 code('%include "python/swig/inet.i"')
730 def __init__(self
, value
):
731 if isinstance(value
, IpAddress
):
735 self
.ip
= convert
.toIpAddress(value
)
737 self
.ip
= long(value
)
741 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
742 return '%d.%d.%d.%d' % tuple(tup
)
744 def __eq__(self
, other
):
745 if isinstance(other
, IpAddress
):
746 return self
.ip
== other
.ip
747 elif isinstance(other
, str):
749 return self
.ip
== convert
.toIpAddress(other
)
753 return self
.ip
== other
755 def __ne__(self
, other
):
756 return not (self
== other
)
759 if self
.ip
< 0 or self
.ip
>= (1 << 32):
760 raise TypeError, "invalid ip address %#08x" % self
.ip
763 from m5
.internal
.params
import IpAddress
764 return IpAddress(self
.ip
)
766 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
767 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
768 # positional or keyword arguments.
769 class IpNetmask(IpAddress
):
770 cxx_type
= 'Net::IpNetmask'
773 def cxx_predecls(cls
, code
):
774 code('#include "base/inet.hh"')
777 def swig_predecls(cls
, code
):
778 code('%include "python/swig/inet.i"')
780 def __init__(self
, *args
, **kwargs
):
781 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
783 setattr(self
, key
, kwargs
.pop(key
))
785 setattr(self
, key
, elseVal
)
787 raise TypeError, "No value set for %s" % key
790 handle_kwarg(self
, kwargs
, 'ip')
791 handle_kwarg(self
, kwargs
, 'netmask')
795 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
796 raise TypeError, "Invalid arguments"
797 handle_kwarg(self
, kwargs
, 'ip', args
[0])
798 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
799 elif isinstance(args
[0], IpNetmask
):
801 self
.netmask
= args
[0].netmask
803 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
807 self
.netmask
= args
[1]
809 raise TypeError, "Too many arguments specified"
812 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
817 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
819 def __eq__(self
, other
):
820 if isinstance(other
, IpNetmask
):
821 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
822 elif isinstance(other
, str):
824 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
832 if self
.netmask
< 0 or self
.netmask
> 32:
833 raise TypeError, "invalid netmask %d" % netmask
836 from m5
.internal
.params
import IpNetmask
837 return IpNetmask(self
.ip
, self
.netmask
)
839 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
840 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
841 class IpWithPort(IpAddress
):
842 cxx_type
= 'Net::IpWithPort'
845 def cxx_predecls(cls
, code
):
846 code('#include "base/inet.hh"')
849 def swig_predecls(cls
, code
):
850 code('%include "python/swig/inet.i"')
852 def __init__(self
, *args
, **kwargs
):
853 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
855 setattr(self
, key
, kwargs
.pop(key
))
857 setattr(self
, key
, elseVal
)
859 raise TypeError, "No value set for %s" % key
862 handle_kwarg(self
, kwargs
, 'ip')
863 handle_kwarg(self
, kwargs
, 'port')
867 if not 'ip' in kwargs
and not 'port' in kwargs
:
868 raise TypeError, "Invalid arguments"
869 handle_kwarg(self
, kwargs
, 'ip', args
[0])
870 handle_kwarg(self
, kwargs
, 'port', args
[0])
871 elif isinstance(args
[0], IpWithPort
):
873 self
.port
= args
[0].port
875 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
881 raise TypeError, "Too many arguments specified"
884 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
889 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
891 def __eq__(self
, other
):
892 if isinstance(other
, IpWithPort
):
893 return self
.ip
== other
.ip
and self
.port
== other
.port
894 elif isinstance(other
, str):
896 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
904 if self
.port
< 0 or self
.port
> 0xffff:
905 raise TypeError, "invalid port %d" % self
.port
908 from m5
.internal
.params
import IpWithPort
909 return IpWithPort(self
.ip
, self
.port
)
911 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
912 "%a %b %d %H:%M:%S %Z %Y",
924 def parse_time(value
):
925 from time
import gmtime
, strptime
, struct_time
, time
926 from datetime
import datetime
, date
928 if isinstance(value
, struct_time
):
931 if isinstance(value
, (int, long)):
934 if isinstance(value
, (datetime
, date
)):
935 return value
.timetuple()
937 if isinstance(value
, str):
938 if value
in ('Now', 'Today'):
939 return time
.gmtime(time
.time())
941 for format
in time_formats
:
943 return strptime(value
, format
)
947 raise ValueError, "Could not parse '%s' as a time" % value
949 class Time(ParamValue
):
953 def cxx_predecls(cls
, code
):
954 code('#include <time.h>')
957 def swig_predecls(cls
, code
):
958 code('%include "python/swig/time.i"')
960 def __init__(self
, value
):
961 self
.value
= parse_time(value
)
964 from m5
.internal
.params
import tm
969 # UNIX is years since 1900
970 c_time
.tm_year
= py_time
.tm_year
- 1900;
972 # Python starts at 1, UNIX starts at 0
973 c_time
.tm_mon
= py_time
.tm_mon
- 1;
974 c_time
.tm_mday
= py_time
.tm_mday
;
975 c_time
.tm_hour
= py_time
.tm_hour
;
976 c_time
.tm_min
= py_time
.tm_min
;
977 c_time
.tm_sec
= py_time
.tm_sec
;
979 # Python has 0 as Monday, UNIX is 0 as sunday
980 c_time
.tm_wday
= py_time
.tm_wday
+ 1
981 if c_time
.tm_wday
> 6:
984 # Python starts at 1, Unix starts at 0
985 c_time
.tm_yday
= py_time
.tm_yday
- 1;
990 return time
.asctime(self
.value
)
995 def get_config_as_dict(self
):
998 # Enumerated types are a little more complex. The user specifies the
999 # type as Enum(foo) where foo is either a list or dictionary of
1000 # alternatives (typically strings, but not necessarily so). (In the
1001 # long run, the integer value of the parameter will be the list index
1002 # or the corresponding dictionary value. For now, since we only check
1003 # that the alternative is valid and then spit it into a .ini file,
1004 # there's not much point in using the dictionary.)
1006 # What Enum() must do is generate a new type encapsulating the
1007 # provided list/dictionary so that specific values of the parameter
1008 # can be instances of that type. We define two hidden internal
1009 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1010 # derive the new type from the appropriate base class on the fly.
1013 # Metaclass for Enum types
1014 class MetaEnum(MetaParamValue
):
1015 def __new__(mcls
, name
, bases
, dict):
1016 assert name
not in allEnums
1018 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1019 allEnums
[name
] = cls
1022 def __init__(cls
, name
, bases
, init_dict
):
1023 if init_dict
.has_key('map'):
1024 if not isinstance(cls
.map, dict):
1025 raise TypeError, "Enum-derived class attribute 'map' " \
1026 "must be of type dict"
1027 # build list of value strings from map
1028 cls
.vals
= cls
.map.keys()
1030 elif init_dict
.has_key('vals'):
1031 if not isinstance(cls
.vals
, list):
1032 raise TypeError, "Enum-derived class attribute 'vals' " \
1033 "must be of type list"
1034 # build string->value map from vals sequence
1036 for idx
,val
in enumerate(cls
.vals
):
1039 raise TypeError, "Enum-derived class must define "\
1040 "attribute 'map' or 'vals'"
1042 cls
.cxx_type
= 'Enums::%s' % name
1044 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1046 # Generate C++ class declaration for this enum type.
1047 # Note that we wrap the enum in a class/struct to act as a namespace,
1048 # so that the enum strings can be brief w/o worrying about collisions.
1049 def cxx_decl(cls
, code
):
1052 #ifndef __ENUM__${name}__
1053 #define __ENUM__${name}__
1059 for val
in cls
.vals
:
1060 code('$val = ${{cls.map[val]}},')
1061 code('Num_$name = ${{len(cls.vals)}}')
1065 extern const char *${name}Strings[Num_${name}];
1068 #endif // __ENUM__${name}__
1071 def cxx_def(cls
, code
):
1074 #include "enums/$name.hh"
1076 const char *${name}Strings[Num_${name}] =
1080 for val
in cls
.vals
:
1085 } // namespace Enums
1088 def swig_decl(cls
, code
):
1091 %module(package="m5.internal") enum_$name
1094 #include "enums/$name.hh"
1097 %include "enums/$name.hh"
1101 # Base class for enum types.
1102 class Enum(ParamValue
):
1103 __metaclass__
= MetaEnum
1106 def __init__(self
, value
):
1107 if value
not in self
.map:
1108 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1109 % (value
, self
.vals
)
1113 def cxx_predecls(cls
, code
):
1114 code('#include "enums/$0.hh"', cls
.__name
__)
1117 def swig_predecls(cls
, code
):
1118 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1121 return int(self
.map[self
.value
])
1126 # how big does a rounding error need to be before we warn about it?
1127 frequency_tolerance
= 0.001 # 0.1%
1129 class TickParamValue(NumericParamValue
):
1133 def cxx_predecls(cls
, code
):
1134 code('#include "base/types.hh"')
1137 def swig_predecls(cls
, code
):
1138 code('%import "stdint.i"')
1139 code('%import "base/types.hh"')
1142 return long(self
.value
)
1144 class Latency(TickParamValue
):
1145 def __init__(self
, value
):
1146 if isinstance(value
, (Latency
, Clock
)):
1147 self
.ticks
= value
.ticks
1148 self
.value
= value
.value
1149 elif isinstance(value
, Frequency
):
1150 self
.ticks
= value
.ticks
1151 self
.value
= 1.0 / value
.value
1152 elif value
.endswith('t'):
1154 self
.value
= int(value
[:-1])
1157 self
.value
= convert
.toLatency(value
)
1159 def __getattr__(self
, attr
):
1160 if attr
in ('latency', 'period'):
1162 if attr
== 'frequency':
1163 return Frequency(self
)
1164 raise AttributeError, "Latency object has no attribute '%s'" % attr
1167 if self
.ticks
or self
.value
== 0:
1170 value
= ticks
.fromSeconds(self
.value
)
1173 # convert latency to ticks
1175 return '%d' % self
.getValue()
1177 class Frequency(TickParamValue
):
1178 def __init__(self
, value
):
1179 if isinstance(value
, (Latency
, Clock
)):
1180 if value
.value
== 0:
1183 self
.value
= 1.0 / value
.value
1184 self
.ticks
= value
.ticks
1185 elif isinstance(value
, Frequency
):
1186 self
.value
= value
.value
1187 self
.ticks
= value
.ticks
1190 self
.value
= convert
.toFrequency(value
)
1192 def __getattr__(self
, attr
):
1193 if attr
== 'frequency':
1195 if attr
in ('latency', 'period'):
1196 return Latency(self
)
1197 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1199 # convert latency to ticks
1201 if self
.ticks
or self
.value
== 0:
1204 value
= ticks
.fromSeconds(1.0 / self
.value
)
1208 return '%d' % self
.getValue()
1210 # A generic frequency and/or Latency value. Value is stored as a
1211 # latency, and any manipulation using a multiplier thus scales the
1212 # clock period, i.e. a 2x multiplier doubles the clock period and thus
1213 # halves the clock frequency.
1214 class Clock(ParamValue
):
1218 def cxx_predecls(cls
, code
):
1219 code('#include "base/types.hh"')
1222 def swig_predecls(cls
, code
):
1223 code('%import "stdint.i"')
1224 code('%import "base/types.hh"')
1226 def __init__(self
, value
):
1227 if isinstance(value
, (Latency
, Clock
)):
1228 self
.ticks
= value
.ticks
1229 self
.value
= value
.value
1230 elif isinstance(value
, Frequency
):
1231 self
.ticks
= value
.ticks
1232 self
.value
= 1.0 / value
.value
1233 elif value
.endswith('t'):
1235 self
.value
= int(value
[:-1])
1238 self
.value
= convert
.anyToLatency(value
)
1240 def __getattr__(self
, attr
):
1241 if attr
== 'frequency':
1242 return Frequency(self
)
1243 if attr
in ('latency', 'period'):
1244 return Latency(self
)
1245 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1248 return self
.period
.getValue()
1251 return self
.period
.ini_str()
1253 class Voltage(float,ParamValue
):
1255 def __new__(cls
, value
):
1256 # convert to voltage
1257 val
= convert
.toVoltage(value
)
1258 return super(cls
, Voltage
).__new
__(cls
, val
)
1261 return str(self
.val
)
1268 return '%f' % self
.getValue()
1270 class NetworkBandwidth(float,ParamValue
):
1272 def __new__(cls
, value
):
1273 # convert to bits per second
1274 val
= convert
.toNetworkBandwidth(value
)
1275 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1278 return str(self
.val
)
1281 # convert to seconds per byte
1282 value
= 8.0 / float(self
)
1283 # convert to ticks per byte
1284 value
= ticks
.fromSeconds(value
)
1288 return '%f' % self
.getValue()
1290 class MemoryBandwidth(float,ParamValue
):
1292 def __new__(cls
, value
):
1293 # convert to bytes per second
1294 val
= convert
.toMemoryBandwidth(value
)
1295 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1298 return str(self
.val
)
1301 # convert to seconds per byte
1304 value
= 1.0 / float(self
)
1305 # convert to ticks per byte
1306 value
= ticks
.fromSeconds(value
)
1310 return '%f' % self
.getValue()
1313 # "Constants"... handy aliases for various values.
1316 # Special class for NULL pointers. Note the special check in
1317 # make_param_value() above that lets these be assigned where a
1318 # SimObject is required.
1319 # only one copy of a particular node
1320 class NullSimObject(object):
1321 __metaclass__
= Singleton
1326 def _instantiate(self
, parent
= None, path
= ''):
1332 def unproxy(self
, base
):
1335 def set_path(self
, parent
, name
):
1344 # The only instance you'll ever need...
1345 NULL
= NullSimObject()
1347 def isNullPointer(value
):
1348 return isinstance(value
, NullSimObject
)
1350 # Some memory range specifications use this as a default upper bound.
1353 AllMemory
= AddrRange(0, MaxAddr
)
1356 #####################################################################
1360 # Ports are used to interconnect objects in the memory system.
1362 #####################################################################
1364 # Port reference: encapsulates a reference to a particular port on a
1365 # particular SimObject.
1366 class PortRef(object):
1367 def __init__(self
, simobj
, name
, role
):
1368 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1369 self
.simobj
= simobj
1372 self
.peer
= None # not associated with another port yet
1373 self
.ccConnected
= False # C++ port connection done?
1374 self
.index
= -1 # always -1 for non-vector ports
1377 return '%s.%s' % (self
.simobj
, self
.name
)
1380 # Return the number of connected ports, i.e. 0 is we have no
1381 # peer and 1 if we do.
1382 return int(self
.peer
!= None)
1384 # for config.ini, print peer's name (not ours)
1386 return str(self
.peer
)
1389 def get_config_as_dict(self
):
1390 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1392 def __getattr__(self
, attr
):
1393 if attr
== 'peerObj':
1394 # shorthand for proxies
1395 return self
.peer
.simobj
1396 raise AttributeError, "'%s' object has no attribute '%s'" % \
1397 (self
.__class
__.__name
__, attr
)
1399 # Full connection is symmetric (both ways). Called via
1400 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1401 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1402 # e.g., "obj1.portA[3] = obj2.portB".
1403 def connect(self
, other
):
1404 if isinstance(other
, VectorPortRef
):
1405 # reference to plain VectorPort is implicit append
1406 other
= other
._get
_next
()
1407 if self
.peer
and not proxy
.isproxy(self
.peer
):
1408 fatal("Port %s is already connected to %s, cannot connect %s\n",
1409 self
, self
.peer
, other
);
1411 if proxy
.isproxy(other
):
1412 other
.set_param_desc(PortParamDesc())
1413 elif isinstance(other
, PortRef
):
1414 if other
.peer
is not self
:
1418 "assigning non-port reference '%s' to port '%s'" \
1421 def clone(self
, simobj
, memo
):
1422 if memo
.has_key(self
):
1424 newRef
= copy
.copy(self
)
1426 newRef
.simobj
= simobj
1427 assert(isSimObject(newRef
.simobj
))
1428 if self
.peer
and not proxy
.isproxy(self
.peer
):
1429 peerObj
= self
.peer
.simobj(_memo
=memo
)
1430 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1431 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1434 def unproxy(self
, simobj
):
1435 assert(simobj
is self
.simobj
)
1436 if proxy
.isproxy(self
.peer
):
1438 realPeer
= self
.peer
.unproxy(self
.simobj
)
1440 print "Error in unproxying port '%s' of %s" % \
1441 (self
.name
, self
.simobj
.path())
1443 self
.connect(realPeer
)
1445 # Call C++ to create corresponding port connection between C++ objects
1446 def ccConnect(self
):
1447 from m5
.internal
.pyobject
import connectPorts
1449 if self
.role
== 'SLAVE':
1450 # do nothing and let the master take care of it
1453 if self
.ccConnected
: # already done this
1456 if not self
.peer
: # nothing to connect to
1459 # check that we connect a master to a slave
1460 if self
.role
== peer
.role
:
1462 "cannot connect '%s' and '%s' due to identical role '%s'" \
1463 % (peer
, self
, self
.role
)
1466 # self is always the master and peer the slave
1467 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1468 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1470 print "Error connecting port %s.%s to %s.%s" % \
1471 (self
.simobj
.path(), self
.name
,
1472 peer
.simobj
.path(), peer
.name
)
1474 self
.ccConnected
= True
1475 peer
.ccConnected
= True
1477 # A reference to an individual element of a VectorPort... much like a
1478 # PortRef, but has an index.
1479 class VectorPortElementRef(PortRef
):
1480 def __init__(self
, simobj
, name
, role
, index
):
1481 PortRef
.__init
__(self
, simobj
, name
, role
)
1485 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1487 # A reference to a complete vector-valued port (not just a single element).
1488 # Can be indexed to retrieve individual VectorPortElementRef instances.
1489 class VectorPortRef(object):
1490 def __init__(self
, simobj
, name
, role
):
1491 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1492 self
.simobj
= simobj
1498 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1501 # Return the number of connected peers, corresponding the the
1502 # length of the elements.
1503 return len(self
.elements
)
1505 # for config.ini, print peer's name (not ours)
1507 return ' '.join([el
.ini_str() for el
in self
.elements
])
1510 def get_config_as_dict(self
):
1511 return {'role' : self
.role
,
1512 'peer' : [el
.ini_str() for el
in self
.elements
]}
1514 def __getitem__(self
, key
):
1515 if not isinstance(key
, int):
1516 raise TypeError, "VectorPort index must be integer"
1517 if key
>= len(self
.elements
):
1518 # need to extend list
1519 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1520 for i
in range(len(self
.elements
), key
+1)]
1521 self
.elements
.extend(ext
)
1522 return self
.elements
[key
]
1524 def _get_next(self
):
1525 return self
[len(self
.elements
)]
1527 def __setitem__(self
, key
, value
):
1528 if not isinstance(key
, int):
1529 raise TypeError, "VectorPort index must be integer"
1530 self
[key
].connect(value
)
1532 def connect(self
, other
):
1533 if isinstance(other
, (list, tuple)):
1534 # Assign list of port refs to vector port.
1535 # For now, append them... not sure if that's the right semantics
1536 # or if it should replace the current vector.
1538 self
._get
_next
().connect(ref
)
1540 # scalar assignment to plain VectorPort is implicit append
1541 self
._get
_next
().connect(other
)
1543 def clone(self
, simobj
, memo
):
1544 if memo
.has_key(self
):
1546 newRef
= copy
.copy(self
)
1548 newRef
.simobj
= simobj
1549 assert(isSimObject(newRef
.simobj
))
1550 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1553 def unproxy(self
, simobj
):
1554 [el
.unproxy(simobj
) for el
in self
.elements
]
1556 def ccConnect(self
):
1557 [el
.ccConnect() for el
in self
.elements
]
1559 # Port description object. Like a ParamDesc object, this represents a
1560 # logical port in the SimObject class, not a particular port on a
1561 # SimObject instance. The latter are represented by PortRef objects.
1563 # Generate a PortRef for this port on the given SimObject with the
1565 def makeRef(self
, simobj
):
1566 return PortRef(simobj
, self
.name
, self
.role
)
1568 # Connect an instance of this port (on the given SimObject with
1569 # the given name) with the port described by the supplied PortRef
1570 def connect(self
, simobj
, ref
):
1571 self
.makeRef(simobj
).connect(ref
)
1573 # No need for any pre-declarations at the moment as we merely rely
1574 # on an unsigned int.
1575 def cxx_predecls(self
, code
):
1578 # Declare an unsigned int with the same name as the port, that
1579 # will eventually hold the number of connected ports (and thus the
1580 # number of elements for a VectorPort).
1581 def cxx_decl(self
, code
):
1582 code('unsigned int port_${{self.name}}_connection_count;')
1584 class MasterPort(Port
):
1585 # MasterPort("description")
1586 def __init__(self
, *args
):
1589 self
.role
= 'MASTER'
1591 raise TypeError, 'wrong number of arguments'
1593 class SlavePort(Port
):
1594 # SlavePort("description")
1595 def __init__(self
, *args
):
1600 raise TypeError, 'wrong number of arguments'
1602 # VectorPort description object. Like Port, but represents a vector
1603 # of connections (e.g., as on a Bus).
1604 class VectorPort(Port
):
1605 def __init__(self
, *args
):
1608 def makeRef(self
, simobj
):
1609 return VectorPortRef(simobj
, self
.name
, self
.role
)
1611 class VectorMasterPort(VectorPort
):
1612 # VectorMasterPort("description")
1613 def __init__(self
, *args
):
1616 self
.role
= 'MASTER'
1617 VectorPort
.__init
__(self
, *args
)
1619 raise TypeError, 'wrong number of arguments'
1621 class VectorSlavePort(VectorPort
):
1622 # VectorSlavePort("description")
1623 def __init__(self
, *args
):
1627 VectorPort
.__init
__(self
, *args
)
1629 raise TypeError, 'wrong number of arguments'
1631 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1632 # proxy objects (via set_param_desc()) so that proxy error messages
1634 class PortParamDesc(object):
1635 __metaclass__
= Singleton
1640 baseEnums
= allEnums
.copy()
1641 baseParams
= allParams
.copy()
1644 global allEnums
, allParams
1646 allEnums
= baseEnums
.copy()
1647 allParams
= baseParams
.copy()
1649 __all__
= ['Param', 'VectorParam',
1650 'Enum', 'Bool', 'String', 'Float',
1651 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1652 'Int32', 'UInt32', 'Int64', 'UInt64',
1653 'Counter', 'Addr', 'Tick', 'Percent',
1654 'TcpPort', 'UdpPort', 'EthernetAddr',
1655 'IpAddress', 'IpNetmask', 'IpWithPort',
1656 'MemorySize', 'MemorySize32',
1657 'Latency', 'Frequency', 'Clock', 'Voltage',
1658 'NetworkBandwidth', 'MemoryBandwidth',
1660 'MaxAddr', 'MaxTick', 'AllMemory',
1662 'NextEthernetAddr', 'NULL',
1663 'MasterPort', 'SlavePort',
1664 'VectorMasterPort', 'VectorSlavePort']