46c3d028c5447fdaeb53f5ff0f335834a3eeccd8
1 # Copyright (c) 2012 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
= 'Range<Addr>'
555 def __init__(self
, *args
, **kwargs
):
556 def handle_kwargs(self
, kwargs
):
558 self
.end
= Addr(kwargs
.pop('end'))
559 elif 'size' in kwargs
:
560 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
562 raise TypeError, "Either end or size must be specified"
565 self
.start
= Addr(kwargs
.pop('start'))
566 handle_kwargs(self
, kwargs
)
570 self
.start
= Addr(args
[0])
571 handle_kwargs(self
, kwargs
)
572 elif isinstance(args
[0], (list, tuple)):
573 self
.start
= Addr(args
[0][0])
574 self
.end
= Addr(args
[0][1])
577 self
.end
= Addr(args
[0]) - 1
580 self
.start
= Addr(args
[0])
581 self
.end
= Addr(args
[1])
583 raise TypeError, "Too many arguments specified"
586 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
589 return '%s:%s' % (self
.start
, self
.end
)
592 return long(self
.end
) - long(self
.start
) + 1
595 def cxx_predecls(cls
, code
):
596 Addr
.cxx_predecls(code
)
597 code('#include "base/range.hh"')
600 def swig_predecls(cls
, code
):
601 Addr
.swig_predecls(code
)
602 code('%import "python/swig/range.i"')
605 from m5
.internal
.range import AddrRange
608 value
.start
= long(self
.start
)
609 value
.end
= long(self
.end
)
612 # Boolean parameter type. Python doesn't let you subclass bool, since
613 # it doesn't want to let you create multiple instances of True and
614 # False. Thus this is a little more complicated than String.
615 class Bool(ParamValue
):
617 def __init__(self
, value
):
619 self
.value
= convert
.toBool(value
)
621 self
.value
= bool(value
)
624 return bool(self
.value
)
627 return str(self
.value
)
629 # implement truth value testing for Bool parameters so that these params
630 # evaluate correctly during the python configuration phase
631 def __nonzero__(self
):
632 return bool(self
.value
)
639 def IncEthernetAddr(addr
, val
= 1):
640 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
642 for i
in (5, 4, 3, 2, 1):
643 val
,rem
= divmod(bytes
[i
], 256)
648 assert(bytes
[0] <= 255)
649 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
651 _NextEthernetAddr
= "00:90:00:00:00:01"
652 def NextEthernetAddr():
653 global _NextEthernetAddr
655 value
= _NextEthernetAddr
656 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
659 class EthernetAddr(ParamValue
):
660 cxx_type
= 'Net::EthAddr'
663 def cxx_predecls(cls
, code
):
664 code('#include "base/inet.hh"')
667 def swig_predecls(cls
, code
):
668 code('%include "python/swig/inet.i"')
670 def __init__(self
, value
):
671 if value
== NextEthernetAddr
:
675 if not isinstance(value
, str):
676 raise TypeError, "expected an ethernet address and didn't get one"
678 bytes
= value
.split(':')
680 raise TypeError, 'invalid ethernet address %s' % value
683 if not 0 <= int(byte
) <= 0xff:
684 raise TypeError, 'invalid ethernet address %s' % value
688 def unproxy(self
, base
):
689 if self
.value
== NextEthernetAddr
:
690 return EthernetAddr(self
.value())
694 from m5
.internal
.params
import EthAddr
695 return EthAddr(self
.value
)
700 # When initializing an IpAddress, pass in an existing IpAddress, a string of
701 # the form "a.b.c.d", or an integer representing an IP.
702 class IpAddress(ParamValue
):
703 cxx_type
= 'Net::IpAddress'
706 def cxx_predecls(cls
, code
):
707 code('#include "base/inet.hh"')
710 def swig_predecls(cls
, code
):
711 code('%include "python/swig/inet.i"')
713 def __init__(self
, value
):
714 if isinstance(value
, IpAddress
):
718 self
.ip
= convert
.toIpAddress(value
)
720 self
.ip
= long(value
)
724 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
725 return '%d.%d.%d.%d' % tuple(tup
)
727 def __eq__(self
, other
):
728 if isinstance(other
, IpAddress
):
729 return self
.ip
== other
.ip
730 elif isinstance(other
, str):
732 return self
.ip
== convert
.toIpAddress(other
)
736 return self
.ip
== other
738 def __ne__(self
, other
):
739 return not (self
== other
)
742 if self
.ip
< 0 or self
.ip
>= (1 << 32):
743 raise TypeError, "invalid ip address %#08x" % self
.ip
746 from m5
.internal
.params
import IpAddress
747 return IpAddress(self
.ip
)
749 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
750 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
751 # positional or keyword arguments.
752 class IpNetmask(IpAddress
):
753 cxx_type
= 'Net::IpNetmask'
756 def cxx_predecls(cls
, code
):
757 code('#include "base/inet.hh"')
760 def swig_predecls(cls
, code
):
761 code('%include "python/swig/inet.i"')
763 def __init__(self
, *args
, **kwargs
):
764 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
766 setattr(self
, key
, kwargs
.pop(key
))
768 setattr(self
, key
, elseVal
)
770 raise TypeError, "No value set for %s" % key
773 handle_kwarg(self
, kwargs
, 'ip')
774 handle_kwarg(self
, kwargs
, 'netmask')
778 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
779 raise TypeError, "Invalid arguments"
780 handle_kwarg(self
, kwargs
, 'ip', args
[0])
781 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
782 elif isinstance(args
[0], IpNetmask
):
784 self
.netmask
= args
[0].netmask
786 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
790 self
.netmask
= args
[1]
792 raise TypeError, "Too many arguments specified"
795 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
800 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
802 def __eq__(self
, other
):
803 if isinstance(other
, IpNetmask
):
804 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
805 elif isinstance(other
, str):
807 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
815 if self
.netmask
< 0 or self
.netmask
> 32:
816 raise TypeError, "invalid netmask %d" % netmask
819 from m5
.internal
.params
import IpNetmask
820 return IpNetmask(self
.ip
, self
.netmask
)
822 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
823 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
824 class IpWithPort(IpAddress
):
825 cxx_type
= 'Net::IpWithPort'
828 def cxx_predecls(cls
, code
):
829 code('#include "base/inet.hh"')
832 def swig_predecls(cls
, code
):
833 code('%include "python/swig/inet.i"')
835 def __init__(self
, *args
, **kwargs
):
836 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
838 setattr(self
, key
, kwargs
.pop(key
))
840 setattr(self
, key
, elseVal
)
842 raise TypeError, "No value set for %s" % key
845 handle_kwarg(self
, kwargs
, 'ip')
846 handle_kwarg(self
, kwargs
, 'port')
850 if not 'ip' in kwargs
and not 'port' in kwargs
:
851 raise TypeError, "Invalid arguments"
852 handle_kwarg(self
, kwargs
, 'ip', args
[0])
853 handle_kwarg(self
, kwargs
, 'port', args
[0])
854 elif isinstance(args
[0], IpWithPort
):
856 self
.port
= args
[0].port
858 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
864 raise TypeError, "Too many arguments specified"
867 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
872 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
874 def __eq__(self
, other
):
875 if isinstance(other
, IpWithPort
):
876 return self
.ip
== other
.ip
and self
.port
== other
.port
877 elif isinstance(other
, str):
879 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
887 if self
.port
< 0 or self
.port
> 0xffff:
888 raise TypeError, "invalid port %d" % self
.port
891 from m5
.internal
.params
import IpWithPort
892 return IpWithPort(self
.ip
, self
.port
)
894 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
895 "%a %b %d %H:%M:%S %Z %Y",
907 def parse_time(value
):
908 from time
import gmtime
, strptime
, struct_time
, time
909 from datetime
import datetime
, date
911 if isinstance(value
, struct_time
):
914 if isinstance(value
, (int, long)):
917 if isinstance(value
, (datetime
, date
)):
918 return value
.timetuple()
920 if isinstance(value
, str):
921 if value
in ('Now', 'Today'):
922 return time
.gmtime(time
.time())
924 for format
in time_formats
:
926 return strptime(value
, format
)
930 raise ValueError, "Could not parse '%s' as a time" % value
932 class Time(ParamValue
):
936 def cxx_predecls(cls
, code
):
937 code('#include <time.h>')
940 def swig_predecls(cls
, code
):
941 code('%include "python/swig/time.i"')
943 def __init__(self
, value
):
944 self
.value
= parse_time(value
)
947 from m5
.internal
.params
import tm
952 # UNIX is years since 1900
953 c_time
.tm_year
= py_time
.tm_year
- 1900;
955 # Python starts at 1, UNIX starts at 0
956 c_time
.tm_mon
= py_time
.tm_mon
- 1;
957 c_time
.tm_mday
= py_time
.tm_mday
;
958 c_time
.tm_hour
= py_time
.tm_hour
;
959 c_time
.tm_min
= py_time
.tm_min
;
960 c_time
.tm_sec
= py_time
.tm_sec
;
962 # Python has 0 as Monday, UNIX is 0 as sunday
963 c_time
.tm_wday
= py_time
.tm_wday
+ 1
964 if c_time
.tm_wday
> 6:
967 # Python starts at 1, Unix starts at 0
968 c_time
.tm_yday
= py_time
.tm_yday
- 1;
973 return time
.asctime(self
.value
)
978 def get_config_as_dict(self
):
981 # Enumerated types are a little more complex. The user specifies the
982 # type as Enum(foo) where foo is either a list or dictionary of
983 # alternatives (typically strings, but not necessarily so). (In the
984 # long run, the integer value of the parameter will be the list index
985 # or the corresponding dictionary value. For now, since we only check
986 # that the alternative is valid and then spit it into a .ini file,
987 # there's not much point in using the dictionary.)
989 # What Enum() must do is generate a new type encapsulating the
990 # provided list/dictionary so that specific values of the parameter
991 # can be instances of that type. We define two hidden internal
992 # classes (_ListEnum and _DictEnum) to serve as base classes, then
993 # derive the new type from the appropriate base class on the fly.
996 # Metaclass for Enum types
997 class MetaEnum(MetaParamValue
):
998 def __new__(mcls
, name
, bases
, dict):
999 assert name
not in allEnums
1001 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1002 allEnums
[name
] = cls
1005 def __init__(cls
, name
, bases
, init_dict
):
1006 if init_dict
.has_key('map'):
1007 if not isinstance(cls
.map, dict):
1008 raise TypeError, "Enum-derived class attribute 'map' " \
1009 "must be of type dict"
1010 # build list of value strings from map
1011 cls
.vals
= cls
.map.keys()
1013 elif init_dict
.has_key('vals'):
1014 if not isinstance(cls
.vals
, list):
1015 raise TypeError, "Enum-derived class attribute 'vals' " \
1016 "must be of type list"
1017 # build string->value map from vals sequence
1019 for idx
,val
in enumerate(cls
.vals
):
1022 raise TypeError, "Enum-derived class must define "\
1023 "attribute 'map' or 'vals'"
1025 cls
.cxx_type
= 'Enums::%s' % name
1027 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1029 # Generate C++ class declaration for this enum type.
1030 # Note that we wrap the enum in a class/struct to act as a namespace,
1031 # so that the enum strings can be brief w/o worrying about collisions.
1032 def cxx_decl(cls
, code
):
1035 #ifndef __ENUM__${name}__
1036 #define __ENUM__${name}__
1042 for val
in cls
.vals
:
1043 code('$val = ${{cls.map[val]}},')
1044 code('Num_$name = ${{len(cls.vals)}}')
1048 extern const char *${name}Strings[Num_${name}];
1051 #endif // __ENUM__${name}__
1054 def cxx_def(cls
, code
):
1057 #include "enums/$name.hh"
1059 const char *${name}Strings[Num_${name}] =
1063 for val
in cls
.vals
:
1068 } // namespace Enums
1071 def swig_decl(cls
, code
):
1074 %module(package="m5.internal") enum_$name
1077 #include "enums/$name.hh"
1080 %include "enums/$name.hh"
1084 # Base class for enum types.
1085 class Enum(ParamValue
):
1086 __metaclass__
= MetaEnum
1089 def __init__(self
, value
):
1090 if value
not in self
.map:
1091 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1092 % (value
, self
.vals
)
1096 def cxx_predecls(cls
, code
):
1097 code('#include "enums/$0.hh"', cls
.__name
__)
1100 def swig_predecls(cls
, code
):
1101 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1104 return int(self
.map[self
.value
])
1109 # how big does a rounding error need to be before we warn about it?
1110 frequency_tolerance
= 0.001 # 0.1%
1112 class TickParamValue(NumericParamValue
):
1116 def cxx_predecls(cls
, code
):
1117 code('#include "base/types.hh"')
1120 def swig_predecls(cls
, code
):
1121 code('%import "stdint.i"')
1122 code('%import "base/types.hh"')
1125 return long(self
.value
)
1127 class Latency(TickParamValue
):
1128 def __init__(self
, value
):
1129 if isinstance(value
, (Latency
, Clock
)):
1130 self
.ticks
= value
.ticks
1131 self
.value
= value
.value
1132 elif isinstance(value
, Frequency
):
1133 self
.ticks
= value
.ticks
1134 self
.value
= 1.0 / value
.value
1135 elif value
.endswith('t'):
1137 self
.value
= int(value
[:-1])
1140 self
.value
= convert
.toLatency(value
)
1142 def __getattr__(self
, attr
):
1143 if attr
in ('latency', 'period'):
1145 if attr
== 'frequency':
1146 return Frequency(self
)
1147 raise AttributeError, "Latency object has no attribute '%s'" % attr
1150 if self
.ticks
or self
.value
== 0:
1153 value
= ticks
.fromSeconds(self
.value
)
1156 # convert latency to ticks
1158 return '%d' % self
.getValue()
1160 class Frequency(TickParamValue
):
1161 def __init__(self
, value
):
1162 if isinstance(value
, (Latency
, Clock
)):
1163 if value
.value
== 0:
1166 self
.value
= 1.0 / value
.value
1167 self
.ticks
= value
.ticks
1168 elif isinstance(value
, Frequency
):
1169 self
.value
= value
.value
1170 self
.ticks
= value
.ticks
1173 self
.value
= convert
.toFrequency(value
)
1175 def __getattr__(self
, attr
):
1176 if attr
== 'frequency':
1178 if attr
in ('latency', 'period'):
1179 return Latency(self
)
1180 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1182 # convert latency to ticks
1184 if self
.ticks
or self
.value
== 0:
1187 value
= ticks
.fromSeconds(1.0 / self
.value
)
1191 return '%d' % self
.getValue()
1193 # A generic frequency and/or Latency value. Value is stored as a latency,
1194 # but to avoid ambiguity this object does not support numeric ops (* or /).
1195 # An explicit conversion to a Latency or Frequency must be made first.
1196 class Clock(ParamValue
):
1200 def cxx_predecls(cls
, code
):
1201 code('#include "base/types.hh"')
1204 def swig_predecls(cls
, code
):
1205 code('%import "stdint.i"')
1206 code('%import "base/types.hh"')
1208 def __init__(self
, value
):
1209 if isinstance(value
, (Latency
, Clock
)):
1210 self
.ticks
= value
.ticks
1211 self
.value
= value
.value
1212 elif isinstance(value
, Frequency
):
1213 self
.ticks
= value
.ticks
1214 self
.value
= 1.0 / value
.value
1215 elif value
.endswith('t'):
1217 self
.value
= int(value
[:-1])
1220 self
.value
= convert
.anyToLatency(value
)
1222 def __getattr__(self
, attr
):
1223 if attr
== 'frequency':
1224 return Frequency(self
)
1225 if attr
in ('latency', 'period'):
1226 return Latency(self
)
1227 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1230 return self
.period
.getValue()
1233 return self
.period
.ini_str()
1235 class NetworkBandwidth(float,ParamValue
):
1237 def __new__(cls
, value
):
1238 # convert to bits per second
1239 val
= convert
.toNetworkBandwidth(value
)
1240 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1243 return str(self
.val
)
1246 # convert to seconds per byte
1247 value
= 8.0 / float(self
)
1248 # convert to ticks per byte
1249 value
= ticks
.fromSeconds(value
)
1253 return '%f' % self
.getValue()
1255 class MemoryBandwidth(float,ParamValue
):
1257 def __new__(cls
, value
):
1258 # convert to bytes per second
1259 val
= convert
.toMemoryBandwidth(value
)
1260 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1263 return str(self
.val
)
1266 # convert to seconds per byte
1269 value
= 1.0 / float(self
)
1270 # convert to ticks per byte
1271 value
= ticks
.fromSeconds(value
)
1275 return '%f' % self
.getValue()
1278 # "Constants"... handy aliases for various values.
1281 # Special class for NULL pointers. Note the special check in
1282 # make_param_value() above that lets these be assigned where a
1283 # SimObject is required.
1284 # only one copy of a particular node
1285 class NullSimObject(object):
1286 __metaclass__
= Singleton
1291 def _instantiate(self
, parent
= None, path
= ''):
1297 def unproxy(self
, base
):
1300 def set_path(self
, parent
, name
):
1309 # The only instance you'll ever need...
1310 NULL
= NullSimObject()
1312 def isNullPointer(value
):
1313 return isinstance(value
, NullSimObject
)
1315 # Some memory range specifications use this as a default upper bound.
1318 AllMemory
= AddrRange(0, MaxAddr
)
1321 #####################################################################
1325 # Ports are used to interconnect objects in the memory system.
1327 #####################################################################
1329 # Port reference: encapsulates a reference to a particular port on a
1330 # particular SimObject.
1331 class PortRef(object):
1332 def __init__(self
, simobj
, name
, role
):
1333 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1334 self
.simobj
= simobj
1337 self
.peer
= None # not associated with another port yet
1338 self
.ccConnected
= False # C++ port connection done?
1339 self
.index
= -1 # always -1 for non-vector ports
1342 return '%s.%s' % (self
.simobj
, self
.name
)
1345 # Return the number of connected ports, i.e. 0 is we have no
1346 # peer and 1 if we do.
1347 return int(self
.peer
!= None)
1349 # for config.ini, print peer's name (not ours)
1351 return str(self
.peer
)
1354 def get_config_as_dict(self
):
1355 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1357 def __getattr__(self
, attr
):
1358 if attr
== 'peerObj':
1359 # shorthand for proxies
1360 return self
.peer
.simobj
1361 raise AttributeError, "'%s' object has no attribute '%s'" % \
1362 (self
.__class
__.__name
__, attr
)
1364 # Full connection is symmetric (both ways). Called via
1365 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1366 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1367 # e.g., "obj1.portA[3] = obj2.portB".
1368 def connect(self
, other
):
1369 if isinstance(other
, VectorPortRef
):
1370 # reference to plain VectorPort is implicit append
1371 other
= other
._get
_next
()
1372 if self
.peer
and not proxy
.isproxy(self
.peer
):
1373 fatal("Port %s is already connected to %s, cannot connect %s\n",
1374 self
, self
.peer
, other
);
1376 if proxy
.isproxy(other
):
1377 other
.set_param_desc(PortParamDesc())
1378 elif isinstance(other
, PortRef
):
1379 if other
.peer
is not self
:
1383 "assigning non-port reference '%s' to port '%s'" \
1386 def clone(self
, simobj
, memo
):
1387 if memo
.has_key(self
):
1389 newRef
= copy
.copy(self
)
1391 newRef
.simobj
= simobj
1392 assert(isSimObject(newRef
.simobj
))
1393 if self
.peer
and not proxy
.isproxy(self
.peer
):
1394 peerObj
= self
.peer
.simobj(_memo
=memo
)
1395 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1396 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1399 def unproxy(self
, simobj
):
1400 assert(simobj
is self
.simobj
)
1401 if proxy
.isproxy(self
.peer
):
1403 realPeer
= self
.peer
.unproxy(self
.simobj
)
1405 print "Error in unproxying port '%s' of %s" % \
1406 (self
.name
, self
.simobj
.path())
1408 self
.connect(realPeer
)
1410 # Call C++ to create corresponding port connection between C++ objects
1411 def ccConnect(self
):
1412 from m5
.internal
.pyobject
import connectPorts
1414 if self
.role
== 'SLAVE':
1415 # do nothing and let the master take care of it
1418 if self
.ccConnected
: # already done this
1421 if not self
.peer
: # nothing to connect to
1424 # check that we connect a master to a slave
1425 if self
.role
== peer
.role
:
1427 "cannot connect '%s' and '%s' due to identical role '%s'" \
1428 % (peer
, self
, self
.role
)
1431 # self is always the master and peer the slave
1432 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1433 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1435 print "Error connecting port %s.%s to %s.%s" % \
1436 (self
.simobj
.path(), self
.name
,
1437 peer
.simobj
.path(), peer
.name
)
1439 self
.ccConnected
= True
1440 peer
.ccConnected
= True
1442 # A reference to an individual element of a VectorPort... much like a
1443 # PortRef, but has an index.
1444 class VectorPortElementRef(PortRef
):
1445 def __init__(self
, simobj
, name
, role
, index
):
1446 PortRef
.__init
__(self
, simobj
, name
, role
)
1450 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1452 # A reference to a complete vector-valued port (not just a single element).
1453 # Can be indexed to retrieve individual VectorPortElementRef instances.
1454 class VectorPortRef(object):
1455 def __init__(self
, simobj
, name
, role
):
1456 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1457 self
.simobj
= simobj
1463 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1466 # Return the number of connected peers, corresponding the the
1467 # length of the elements.
1468 return len(self
.elements
)
1470 # for config.ini, print peer's name (not ours)
1472 return ' '.join([el
.ini_str() for el
in self
.elements
])
1475 def get_config_as_dict(self
):
1476 return {'role' : self
.role
,
1477 'peer' : [el
.ini_str() for el
in self
.elements
]}
1479 def __getitem__(self
, key
):
1480 if not isinstance(key
, int):
1481 raise TypeError, "VectorPort index must be integer"
1482 if key
>= len(self
.elements
):
1483 # need to extend list
1484 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1485 for i
in range(len(self
.elements
), key
+1)]
1486 self
.elements
.extend(ext
)
1487 return self
.elements
[key
]
1489 def _get_next(self
):
1490 return self
[len(self
.elements
)]
1492 def __setitem__(self
, key
, value
):
1493 if not isinstance(key
, int):
1494 raise TypeError, "VectorPort index must be integer"
1495 self
[key
].connect(value
)
1497 def connect(self
, other
):
1498 if isinstance(other
, (list, tuple)):
1499 # Assign list of port refs to vector port.
1500 # For now, append them... not sure if that's the right semantics
1501 # or if it should replace the current vector.
1503 self
._get
_next
().connect(ref
)
1505 # scalar assignment to plain VectorPort is implicit append
1506 self
._get
_next
().connect(other
)
1508 def clone(self
, simobj
, memo
):
1509 if memo
.has_key(self
):
1511 newRef
= copy
.copy(self
)
1513 newRef
.simobj
= simobj
1514 assert(isSimObject(newRef
.simobj
))
1515 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1518 def unproxy(self
, simobj
):
1519 [el
.unproxy(simobj
) for el
in self
.elements
]
1521 def ccConnect(self
):
1522 [el
.ccConnect() for el
in self
.elements
]
1524 # Port description object. Like a ParamDesc object, this represents a
1525 # logical port in the SimObject class, not a particular port on a
1526 # SimObject instance. The latter are represented by PortRef objects.
1528 # Generate a PortRef for this port on the given SimObject with the
1530 def makeRef(self
, simobj
):
1531 return PortRef(simobj
, self
.name
, self
.role
)
1533 # Connect an instance of this port (on the given SimObject with
1534 # the given name) with the port described by the supplied PortRef
1535 def connect(self
, simobj
, ref
):
1536 self
.makeRef(simobj
).connect(ref
)
1538 # No need for any pre-declarations at the moment as we merely rely
1539 # on an unsigned int.
1540 def cxx_predecls(self
, code
):
1543 # Declare an unsigned int with the same name as the port, that
1544 # will eventually hold the number of connected ports (and thus the
1545 # number of elements for a VectorPort).
1546 def cxx_decl(self
, code
):
1547 code('unsigned int port_${{self.name}}_connection_count;')
1549 class MasterPort(Port
):
1550 # MasterPort("description")
1551 def __init__(self
, *args
):
1554 self
.role
= 'MASTER'
1556 raise TypeError, 'wrong number of arguments'
1558 class SlavePort(Port
):
1559 # SlavePort("description")
1560 def __init__(self
, *args
):
1565 raise TypeError, 'wrong number of arguments'
1567 # VectorPort description object. Like Port, but represents a vector
1568 # of connections (e.g., as on a Bus).
1569 class VectorPort(Port
):
1570 def __init__(self
, *args
):
1573 def makeRef(self
, simobj
):
1574 return VectorPortRef(simobj
, self
.name
, self
.role
)
1576 class VectorMasterPort(VectorPort
):
1577 # VectorMasterPort("description")
1578 def __init__(self
, *args
):
1581 self
.role
= 'MASTER'
1582 VectorPort
.__init
__(self
, *args
)
1584 raise TypeError, 'wrong number of arguments'
1586 class VectorSlavePort(VectorPort
):
1587 # VectorSlavePort("description")
1588 def __init__(self
, *args
):
1592 VectorPort
.__init
__(self
, *args
)
1594 raise TypeError, 'wrong number of arguments'
1596 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1597 # proxy objects (via set_param_desc()) so that proxy error messages
1599 class PortParamDesc(object):
1600 __metaclass__
= Singleton
1605 baseEnums
= allEnums
.copy()
1606 baseParams
= allParams
.copy()
1609 global allEnums
, allParams
1611 allEnums
= baseEnums
.copy()
1612 allParams
= baseParams
.copy()
1614 __all__
= ['Param', 'VectorParam',
1615 'Enum', 'Bool', 'String', 'Float',
1616 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1617 'Int32', 'UInt32', 'Int64', 'UInt64',
1618 'Counter', 'Addr', 'Tick', 'Percent',
1619 'TcpPort', 'UdpPort', 'EthernetAddr',
1620 'IpAddress', 'IpNetmask', 'IpWithPort',
1621 'MemorySize', 'MemorySize32',
1622 'Latency', 'Frequency', 'Clock',
1623 'NetworkBandwidth', 'MemoryBandwidth',
1625 'MaxAddr', 'MaxTick', 'AllMemory',
1627 'NextEthernetAddr', 'NULL',
1628 'MasterPort', 'SlavePort',
1629 'VectorMasterPort', 'VectorSlavePort']