1 # Copyright (c) 2012-2014, 2017-2019 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 #####################################################################
42 # Parameter description classes
44 # The _params dictionary in each class maps parameter names to either
45 # a Param or a VectorParam object. These objects contain the
46 # parameter description string, the parameter type, and the default
47 # value (if any). The convert() method on these objects is used to
48 # force whatever value is assigned to the parameter to the appropriate
51 # Note that the default values are loaded into the class's attribute
52 # space when the parameter dictionary is initialized (in
53 # MetaSimObject._new_param()); after that point they aren't used.
55 #####################################################################
57 from __future__
import print_function
58 from six
import with_metaclass
74 def isSimObject(*args
, **kwargs
):
75 from . import SimObject
76 return SimObject
.isSimObject(*args
, **kwargs
)
78 def isSimObjectSequence(*args
, **kwargs
):
79 from . import SimObject
80 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
82 def isSimObjectClass(*args
, **kwargs
):
83 from . import SimObject
84 return SimObject
.isSimObjectClass(*args
, **kwargs
)
88 class MetaParamValue(type):
89 def __new__(mcls
, name
, bases
, dct
):
90 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
92 warn("%s already exists in allParams. This may be caused by the " \
93 "Python 2.7 compatibility layer." % (name
, ))
98 # Dummy base class to identify types that are legitimate for SimObject
100 class ParamValue(with_metaclass(MetaParamValue
, object)):
101 cmd_line_settable
= False
103 # Generate the code needed as a prerequisite for declaring a C++
104 # object of this type. Typically generates one or more #include
105 # statements. Used when declaring parameters of this type.
107 def cxx_predecls(cls
, code
):
111 def pybind_predecls(cls
, code
):
112 cls
.cxx_predecls(code
)
114 # default for printing to .ini file is regular string conversion.
115 # will be overridden in some cases
119 # default for printing to .json file is regular string conversion.
120 # will be overridden in some cases, mostly to use native Python
121 # types where there are similar JSON types
122 def config_value(self
):
125 # Prerequisites for .ini parsing with cxx_ini_parse
127 def cxx_ini_predecls(cls
, code
):
130 # parse a .ini file entry for this param from string expression
131 # src into lvalue dest (of the param's C++ type)
133 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
134 code('// Unhandled param type: %s' % cls
.__name
__)
135 code('%s false;' % ret
)
137 # allows us to blithely call unproxy() on things without checking
138 # if they're really proxies or not
139 def unproxy(self
, base
):
142 # Produce a human readable version of the stored value
143 def pretty_print(self
, value
):
146 # Regular parameter description.
147 class ParamDesc(object):
148 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
149 self
.ptype_str
= ptype_str
150 # remember ptype only if it is provided
158 self
.default
= args
[0]
161 raise TypeError('too many arguments')
164 assert(not hasattr(self
, 'desc'))
165 self
.desc
= kwargs
['desc']
168 if 'default' in kwargs
:
169 assert(not hasattr(self
, 'default'))
170 self
.default
= kwargs
['default']
171 del kwargs
['default']
174 raise TypeError('extra unknown kwargs %s' % kwargs
)
176 if not hasattr(self
, 'desc'):
177 raise TypeError('desc attribute missing')
179 def __getattr__(self
, attr
):
181 from . import SimObject
182 ptype
= SimObject
.allClasses
[self
.ptype_str
]
183 assert isSimObjectClass(ptype
)
187 raise AttributeError("'%s' object has no attribute '%s'" % \
188 (type(self
).__name
__, attr
))
190 def example_str(self
):
191 if hasattr(self
.ptype
, "ex_str"):
192 return self
.ptype
.ex_str
194 return self
.ptype_str
196 # Is the param available to be exposed on the command line
197 def isCmdLineSettable(self
):
198 if hasattr(self
.ptype
, "cmd_line_settable"):
199 return self
.ptype
.cmd_line_settable
203 def convert(self
, value
):
204 if isinstance(value
, proxy
.BaseProxy
):
205 value
.set_param_desc(self
)
207 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
208 # deferred evaluation of SimObject; continue to defer if
209 # we're just assigning a null pointer
211 if isinstance(value
, self
.ptype
):
213 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
215 return self
.ptype(value
)
217 def pretty_print(self
, value
):
218 if isinstance(value
, proxy
.BaseProxy
):
220 if isNullPointer(value
):
222 return self
.ptype(value
).pretty_print(value
)
224 def cxx_predecls(self
, code
):
225 code('#include <cstddef>')
226 self
.ptype
.cxx_predecls(code
)
228 def pybind_predecls(self
, code
):
229 self
.ptype
.pybind_predecls(code
)
231 def cxx_decl(self
, code
):
232 code('${{self.ptype.cxx_type}} ${{self.name}};')
234 # Vector-valued parameter description. Just like ParamDesc, except
235 # that the value is a vector (list) of the specified type instead of a
238 class VectorParamValue(with_metaclass(MetaParamValue
, list)):
239 def __setattr__(self
, attr
, value
):
240 raise AttributeError("Not allowed to set %s on '%s'" % \
241 (attr
, type(self
).__name
__))
243 def config_value(self
):
244 return [v
.config_value() for v
in self
]
247 return ' '.join([v
.ini_str() for v
in self
])
250 return [ v
.getValue() for v
in self
]
252 def unproxy(self
, base
):
253 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
254 # The value is a proxy (e.g. Parent.any, Parent.all or
255 # Parent.x) therefore try resolve it
256 return self
[0].unproxy(base
)
258 return [v
.unproxy(base
) for v
in self
]
260 class SimObjectVector(VectorParamValue
):
261 # support clone operation
262 def __call__(self
, **kwargs
):
263 return SimObjectVector([v(**kwargs
) for v
in self
])
265 def clear_parent(self
, old_parent
):
267 v
.clear_parent(old_parent
)
269 def set_parent(self
, parent
, name
):
271 self
[0].set_parent(parent
, name
)
273 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
274 for i
,v
in enumerate(self
):
275 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
277 def has_parent(self
):
278 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
280 # return 'cpu0 cpu1' etc. for print_ini()
282 return ' '.join([v
._name
for v
in self
])
284 # By iterating through the constituent members of the vector here
285 # we can nicely handle iterating over all a SimObject's children
286 # without having to provide lots of special functions on
287 # SimObjectVector directly.
288 def descendants(self
):
290 for obj
in v
.descendants():
293 def get_config_as_dict(self
):
296 a
.append(v
.get_config_as_dict())
299 # If we are replacing an item in the vector, make sure to set the
300 # parent reference of the new SimObject to be the same as the parent
301 # of the SimObject being replaced. Useful to have if we created
302 # a SimObjectVector of temporary objects that will be modified later in
303 # configuration scripts.
304 def __setitem__(self
, key
, value
):
306 if value
.has_parent():
307 warn("SimObject %s already has a parent" % value
.get_name() +\
308 " that is being overwritten by a SimObjectVector")
309 value
.set_parent(val
.get_parent(), val
._name
)
310 super(SimObjectVector
, self
).__setitem
__(key
, value
)
312 # Enumerate the params of each member of the SimObject vector. Creates
313 # strings that will allow indexing into the vector by the python code and
314 # allow it to be specified on the command line.
315 def enumerateParams(self
, flags_dict
= {},
318 if hasattr(self
, "_paramEnumed"):
319 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
323 # Each entry in the SimObjectVector should be an
324 # instance of a SimObject
325 flags_dict
= vals
.enumerateParams(flags_dict
,
326 cmd_line_str
+ "%d." % x
,
327 access_str
+ "[%d]." % x
)
332 class VectorParamDesc(ParamDesc
):
333 # Convert assigned value to appropriate type. If the RHS is not a
334 # list or tuple, it generates a single-element list.
335 def convert(self
, value
):
336 if isinstance(value
, (list, tuple)):
337 # list: coerce each element into new list
338 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
339 elif isinstance(value
, str):
340 # If input is a csv string
341 tmp_list
= [ ParamDesc
.convert(self
, v
) \
342 for v
in value
.strip('[').strip(']').split(',') ]
344 # singleton: coerce to a single-element list
345 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
347 if isSimObjectSequence(tmp_list
):
348 return SimObjectVector(tmp_list
)
350 return VectorParamValue(tmp_list
)
352 # Produce a human readable example string that describes
353 # how to set this vector parameter in the absence of a default
355 def example_str(self
):
356 s
= super(VectorParamDesc
, self
).example_str()
357 help_str
= "[" + s
+ "," + s
+ ", ...]"
360 # Produce a human readable representation of the value of this vector param.
361 def pretty_print(self
, value
):
362 if isinstance(value
, (list, tuple)):
363 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
364 elif isinstance(value
, str):
365 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
367 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
371 # This is a helper function for the new config system
372 def __call__(self
, value
):
373 if isinstance(value
, (list, tuple)):
374 # list: coerce each element into new list
375 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
376 elif isinstance(value
, str):
377 # If input is a csv string
378 tmp_list
= [ ParamDesc
.convert(self
, v
) \
379 for v
in value
.strip('[').strip(']').split(',') ]
381 # singleton: coerce to a single-element list
382 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
384 return VectorParamValue(tmp_list
)
386 def cxx_predecls(self
, code
):
387 code('#include <vector>')
388 self
.ptype
.cxx_predecls(code
)
390 def pybind_predecls(self
, code
):
391 code('#include <vector>')
392 self
.ptype
.pybind_predecls(code
)
394 def cxx_decl(self
, code
):
395 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
397 class ParamFactory(object):
398 def __init__(self
, param_desc_class
, ptype_str
= None):
399 self
.param_desc_class
= param_desc_class
400 self
.ptype_str
= ptype_str
402 def __getattr__(self
, attr
):
404 attr
= self
.ptype_str
+ '.' + attr
405 return ParamFactory(self
.param_desc_class
, attr
)
407 # E.g., Param.Int(5, "number of widgets")
408 def __call__(self
, *args
, **kwargs
):
411 ptype
= allParams
[self
.ptype_str
]
413 # if name isn't defined yet, assume it's a SimObject, and
414 # try to resolve it later
416 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
418 Param
= ParamFactory(ParamDesc
)
419 VectorParam
= ParamFactory(VectorParamDesc
)
421 #####################################################################
425 # Though native Python types could be used to specify parameter types
426 # (the 'ptype' field of the Param and VectorParam classes), it's more
427 # flexible to define our own set of types. This gives us more control
428 # over how Python expressions are converted to values (via the
429 # __init__() constructor) and how these values are printed out (via
430 # the __str__() conversion method).
432 #####################################################################
434 # String-valued parameter. Just mixin the ParamValue class with the
435 # built-in str class.
436 class String(ParamValue
,str):
437 cxx_type
= 'std::string'
438 cmd_line_settable
= True
441 def cxx_predecls(self
, code
):
442 code('#include <string>')
444 def __call__(self
, value
):
449 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
450 code('%s = %s;' % (dest
, src
))
451 code('%s true;' % ret
)
456 # superclass for "numeric" parameter values, to emulate math
457 # operations in a type-safe way. e.g., a Latency times an int returns
458 # a new Latency object.
459 class NumericParamValue(ParamValue
):
462 return v
.value
if isinstance(v
, NumericParamValue
) else v
465 return str(self
.value
)
468 return float(self
.value
)
471 return long(self
.value
)
474 return int(self
.value
)
476 # hook for bounds checking
480 def __mul__(self
, other
):
481 newobj
= self
.__class
__(self
)
482 newobj
.value
*= NumericParamValue
.unwrap(other
)
488 def __truediv__(self
, other
):
489 newobj
= self
.__class
__(self
)
490 newobj
.value
/= NumericParamValue
.unwrap(other
)
494 def __floordiv__(self
, other
):
495 newobj
= self
.__class
__(self
)
496 newobj
.value
//= NumericParamValue
.unwrap(other
)
501 def __add__(self
, other
):
502 newobj
= self
.__class
__(self
)
503 newobj
.value
+= NumericParamValue
.unwrap(other
)
507 def __sub__(self
, other
):
508 newobj
= self
.__class
__(self
)
509 newobj
.value
-= NumericParamValue
.unwrap(other
)
513 def __iadd__(self
, other
):
514 self
.value
+= NumericParamValue
.unwrap(other
)
518 def __isub__(self
, other
):
519 self
.value
-= NumericParamValue
.unwrap(other
)
523 def __imul__(self
, other
):
524 self
.value
*= NumericParamValue
.unwrap(other
)
528 def __itruediv__(self
, other
):
529 self
.value
/= NumericParamValue
.unwrap(other
)
533 def __ifloordiv__(self
, other
):
534 self
.value
//= NumericParamValue
.unwrap(other
)
538 def __lt__(self
, other
):
539 return self
.value
< NumericParamValue
.unwrap(other
)
541 # Python 2.7 pre __future__.division operators
542 # TODO: Remove these when after "import division from __future__"
543 __div__
= __truediv__
544 __idiv__
= __itruediv__
546 def config_value(self
):
550 def cxx_ini_predecls(cls
, code
):
551 # Assume that base/str.hh will be included anyway
552 # code('#include "base/str.hh"')
555 # The default for parsing PODs from an .ini entry is to extract from an
556 # istringstream and let overloading choose the right type according to
559 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
560 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
562 # Metaclass for bounds-checked integer parameters. See CheckedInt.
563 class CheckedIntType(MetaParamValue
):
564 def __init__(cls
, name
, bases
, dict):
565 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
567 # CheckedInt is an abstract base class, so we actually don't
568 # want to do any processing on it... the rest of this code is
569 # just for classes that derive from CheckedInt.
570 if name
== 'CheckedInt':
573 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
574 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
575 panic("CheckedInt subclass %s must define either\n" \
576 " 'min' and 'max' or 'size' and 'unsigned'\n",
580 cls
.max = 2 ** cls
.size
- 1
582 cls
.min = -(2 ** (cls
.size
- 1))
583 cls
.max = (2 ** (cls
.size
- 1)) - 1
585 # Abstract superclass for bounds-checked integer parameters. This
586 # class is subclassed to generate parameter classes with specific
587 # bounds. Initialization of the min and max bounds is done in the
588 # metaclass CheckedIntType.__init__.
589 class CheckedInt(with_metaclass(CheckedIntType
, NumericParamValue
)):
590 cmd_line_settable
= True
593 if not self
.min <= self
.value
<= self
.max:
594 raise TypeError('Integer param out of bounds %d < %d < %d' % \
595 (self
.min, self
.value
, self
.max))
597 def __init__(self
, value
):
598 if isinstance(value
, str):
599 self
.value
= convert
.toInteger(value
)
600 elif isinstance(value
, (int, long, float, NumericParamValue
)):
601 self
.value
= long(value
)
603 raise TypeError("Can't convert object of type %s to CheckedInt" \
604 % type(value
).__name
__)
607 def __call__(self
, value
):
612 return int(self
.value
)
615 def cxx_predecls(cls
, code
):
616 # most derived types require this, so we just do it here once
617 code('#include "base/types.hh"')
620 return long(self
.value
)
622 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
623 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
625 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
626 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
627 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
628 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
629 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
630 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
631 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
632 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
634 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
635 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
636 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
637 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
639 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
641 class Cycles(CheckedInt
):
647 from _m5
.core
import Cycles
648 return Cycles(self
.value
)
651 def cxx_ini_predecls(cls
, code
):
652 # Assume that base/str.hh will be included anyway
653 # code('#include "base/str.hh"')
657 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
658 code('uint64_t _temp;')
659 code('bool _ret = to_number(%s, _temp);' % src
)
661 code(' %s = Cycles(_temp);' % dest
)
662 code('%s _ret;' % ret
)
664 class Float(ParamValue
, float):
666 cmd_line_settable
= True
668 def __init__(self
, value
):
669 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
670 self
.value
= float(value
)
672 raise TypeError("Can't convert object of type %s to Float" \
673 % type(value
).__name
__)
675 def __call__(self
, value
):
680 return float(self
.value
)
682 def config_value(self
):
686 def cxx_ini_predecls(cls
, code
):
687 code('#include <sstream>')
690 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
691 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
693 class MemorySize(CheckedInt
):
694 cxx_type
= 'uint64_t'
698 def __init__(self
, value
):
699 if isinstance(value
, MemorySize
):
700 self
.value
= value
.value
702 self
.value
= convert
.toMemorySize(value
)
705 class MemorySize32(CheckedInt
):
706 cxx_type
= 'uint32_t'
710 def __init__(self
, value
):
711 if isinstance(value
, MemorySize
):
712 self
.value
= value
.value
714 self
.value
= convert
.toMemorySize(value
)
717 class Addr(CheckedInt
):
721 def __init__(self
, value
):
722 if isinstance(value
, Addr
):
723 self
.value
= value
.value
726 # Often addresses are referred to with sizes. Ex: A device
727 # base address is at "512MB". Use toMemorySize() to convert
728 # these into addresses. If the address is not specified with a
729 # "size", an exception will occur and numeric translation will
731 self
.value
= convert
.toMemorySize(value
)
732 except (TypeError, ValueError):
733 # Convert number to string and use long() to do automatic
734 # base conversion (requires base=0 for auto-conversion)
735 self
.value
= long(str(value
), base
=0)
738 def __add__(self
, other
):
739 if isinstance(other
, Addr
):
740 return self
.value
+ other
.value
742 return self
.value
+ other
743 def pretty_print(self
, value
):
745 val
= convert
.toMemorySize(value
)
748 return "0x%x" % long(val
)
750 class AddrRange(ParamValue
):
751 cxx_type
= 'AddrRange'
753 def __init__(self
, *args
, **kwargs
):
754 # Disable interleaving and hashing by default
759 def handle_kwargs(self
, kwargs
):
760 # An address range needs to have an upper limit, specified
761 # either explicitly with an end, or as an offset using the
764 self
.end
= Addr(kwargs
.pop('end'))
765 elif 'size' in kwargs
:
766 self
.end
= self
.start
+ Addr(kwargs
.pop('size'))
768 raise TypeError("Either end or size must be specified")
770 # Now on to the optional bit
771 if 'intlvMatch' in kwargs
:
772 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
774 if 'masks' in kwargs
:
775 self
.masks
= [ long(x
) for x
in list(kwargs
.pop('masks')) ]
776 self
.intlvBits
= len(self
.masks
)
778 if 'intlvBits' in kwargs
:
779 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
780 self
.masks
= [0] * self
.intlvBits
781 if 'intlvHighBit' not in kwargs
:
782 raise TypeError("No interleave bits specified")
783 intlv_high_bit
= int(kwargs
.pop('intlvHighBit'))
785 if 'xorHighBit' in kwargs
:
786 xor_high_bit
= int(kwargs
.pop('xorHighBit'))
787 for i
in range(0, self
.intlvBits
):
788 bit1
= intlv_high_bit
- i
790 if xor_high_bit
!= 0:
791 bit2
= xor_high_bit
- i
793 self
.masks
[self
.intlvBits
- i
- 1] = mask
796 self
.start
= Addr(kwargs
.pop('start'))
797 handle_kwargs(self
, kwargs
)
801 self
.start
= Addr(args
[0])
802 handle_kwargs(self
, kwargs
)
803 elif isinstance(args
[0], (list, tuple)):
804 self
.start
= Addr(args
[0][0])
805 self
.end
= Addr(args
[0][1])
808 self
.end
= Addr(args
[0])
811 self
.start
= Addr(args
[0])
812 self
.end
= Addr(args
[1])
814 raise TypeError("Too many arguments specified")
817 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
820 if len(self
.masks
) == 0:
821 return '%s:%s' % (self
.start
, self
.end
)
823 return '%s:%s:%s:%s' % (self
.start
, self
.end
, self
.intlvMatch
,
824 ':'.join(str(m
) for m
in self
.masks
))
827 # Divide the size by the size of the interleaving slice
828 return (long(self
.end
) - long(self
.start
)) >> self
.intlvBits
831 def cxx_predecls(cls
, code
):
832 Addr
.cxx_predecls(code
)
833 code('#include "base/addr_range.hh"')
836 def pybind_predecls(cls
, code
):
837 Addr
.pybind_predecls(code
)
838 code('#include "base/addr_range.hh"')
841 def cxx_ini_predecls(cls
, code
):
842 code('#include <sstream>')
843 code('#include <vector>')
844 code('#include "base/types.hh"')
847 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
848 code('bool _ret = true;')
849 code('uint64_t _start, _end, _intlvMatch = 0;')
850 code('std::vector<Addr> _masks;')
852 code('std::istringstream _stream(${src});')
853 code('_stream >> _start;')
854 code('_stream.get(_sep);')
855 code('_ret = _sep == \':\';')
856 code('_stream >> _end;')
857 code('if (!_stream.fail() && !_stream.eof()) {')
858 code(' _stream.get(_sep);')
859 code(' _ret = ret && _sep == \':\';')
860 code(' _stream >> _intlvMatch;')
861 code(' while (!_stream.fail() && !_stream.eof()) {')
862 code(' _stream.get(_sep);')
863 code(' _ret = ret && _sep == \':\';')
865 code(' _stream >> mask;')
866 code(' _masks.push_back(mask);')
869 code('_ret = _ret && !_stream.fail() && _stream.eof();')
871 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
875 # Go from the Python class to the wrapped C++ class
876 from _m5
.range import AddrRange
878 return AddrRange(long(self
.start
), long(self
.end
),
879 self
.masks
, int(self
.intlvMatch
))
881 # Boolean parameter type. Python doesn't let you subclass bool, since
882 # it doesn't want to let you create multiple instances of True and
883 # False. Thus this is a little more complicated than String.
884 class Bool(ParamValue
):
886 cmd_line_settable
= True
888 def __init__(self
, value
):
890 self
.value
= convert
.toBool(value
)
892 self
.value
= bool(value
)
894 def __call__(self
, value
):
899 return bool(self
.value
)
902 return str(self
.value
)
904 # implement truth value testing for Bool parameters so that these params
905 # evaluate correctly during the python configuration phase
907 return bool(self
.value
)
909 # Python 2.7 uses __nonzero__ instead of __bool__
910 __nonzero__
= __bool__
917 def config_value(self
):
921 def cxx_ini_predecls(cls
, code
):
922 # Assume that base/str.hh will be included anyway
923 # code('#include "base/str.hh"')
927 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
928 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
930 def IncEthernetAddr(addr
, val
= 1):
931 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
933 for i
in (5, 4, 3, 2, 1):
934 val
,rem
= divmod(bytes
[i
], 256)
939 assert(bytes
[0] <= 255)
940 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
942 _NextEthernetAddr
= "00:90:00:00:00:01"
943 def NextEthernetAddr():
944 global _NextEthernetAddr
946 value
= _NextEthernetAddr
947 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
950 class EthernetAddr(ParamValue
):
951 cxx_type
= 'Net::EthAddr'
952 ex_str
= "00:90:00:00:00:01"
953 cmd_line_settable
= True
956 def cxx_predecls(cls
, code
):
957 code('#include "base/inet.hh"')
959 def __init__(self
, value
):
960 if value
== NextEthernetAddr
:
964 if not isinstance(value
, str):
965 raise TypeError("expected an ethernet address and didn't get one")
967 bytes
= value
.split(':')
969 raise TypeError('invalid ethernet address %s' % value
)
972 if not 0 <= int(byte
, base
=16) <= 0xff:
973 raise TypeError('invalid ethernet address %s' % value
)
977 def __call__(self
, value
):
981 def unproxy(self
, base
):
982 if self
.value
== NextEthernetAddr
:
983 return EthernetAddr(self
.value())
987 from _m5
.net
import EthAddr
988 return EthAddr(self
.value
)
997 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
998 code('%s = Net::EthAddr(%s);' % (dest
, src
))
999 code('%s true;' % ret
)
1001 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1002 # the form "a.b.c.d", or an integer representing an IP.
1003 class IpAddress(ParamValue
):
1004 cxx_type
= 'Net::IpAddress'
1005 ex_str
= "127.0.0.1"
1006 cmd_line_settable
= True
1009 def cxx_predecls(cls
, code
):
1010 code('#include "base/inet.hh"')
1012 def __init__(self
, value
):
1013 if isinstance(value
, IpAddress
):
1017 self
.ip
= convert
.toIpAddress(value
)
1019 self
.ip
= long(value
)
1022 def __call__(self
, value
):
1023 self
.__init
__(value
)
1027 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1028 return '%d.%d.%d.%d' % tuple(tup
)
1030 def __eq__(self
, other
):
1031 if isinstance(other
, IpAddress
):
1032 return self
.ip
== other
.ip
1033 elif isinstance(other
, str):
1035 return self
.ip
== convert
.toIpAddress(other
)
1039 return self
.ip
== other
1041 def __ne__(self
, other
):
1042 return not (self
== other
)
1045 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1046 raise TypeError("invalid ip address %#08x" % self
.ip
)
1049 from _m5
.net
import IpAddress
1050 return IpAddress(self
.ip
)
1052 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1053 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1054 # positional or keyword arguments.
1055 class IpNetmask(IpAddress
):
1056 cxx_type
= 'Net::IpNetmask'
1057 ex_str
= "127.0.0.0/24"
1058 cmd_line_settable
= True
1061 def cxx_predecls(cls
, code
):
1062 code('#include "base/inet.hh"')
1064 def __init__(self
, *args
, **kwargs
):
1065 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1067 setattr(self
, key
, kwargs
.pop(key
))
1069 setattr(self
, key
, elseVal
)
1071 raise TypeError("No value set for %s" % key
)
1074 handle_kwarg(self
, kwargs
, 'ip')
1075 handle_kwarg(self
, kwargs
, 'netmask')
1077 elif len(args
) == 1:
1079 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1080 raise TypeError("Invalid arguments")
1081 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1082 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1083 elif isinstance(args
[0], IpNetmask
):
1084 self
.ip
= args
[0].ip
1085 self
.netmask
= args
[0].netmask
1087 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1089 elif len(args
) == 2:
1091 self
.netmask
= args
[1]
1093 raise TypeError("Too many arguments specified")
1096 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1100 def __call__(self
, value
):
1101 self
.__init
__(value
)
1105 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1107 def __eq__(self
, other
):
1108 if isinstance(other
, IpNetmask
):
1109 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1110 elif isinstance(other
, str):
1112 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1120 if self
.netmask
< 0 or self
.netmask
> 32:
1121 raise TypeError("invalid netmask %d" % netmask
)
1124 from _m5
.net
import IpNetmask
1125 return IpNetmask(self
.ip
, self
.netmask
)
1127 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1128 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1129 class IpWithPort(IpAddress
):
1130 cxx_type
= 'Net::IpWithPort'
1131 ex_str
= "127.0.0.1:80"
1132 cmd_line_settable
= True
1135 def cxx_predecls(cls
, code
):
1136 code('#include "base/inet.hh"')
1138 def __init__(self
, *args
, **kwargs
):
1139 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1141 setattr(self
, key
, kwargs
.pop(key
))
1143 setattr(self
, key
, elseVal
)
1145 raise TypeError("No value set for %s" % key
)
1148 handle_kwarg(self
, kwargs
, 'ip')
1149 handle_kwarg(self
, kwargs
, 'port')
1151 elif len(args
) == 1:
1153 if not 'ip' in kwargs
and not 'port' in kwargs
:
1154 raise TypeError("Invalid arguments")
1155 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1156 handle_kwarg(self
, kwargs
, 'port', args
[0])
1157 elif isinstance(args
[0], IpWithPort
):
1158 self
.ip
= args
[0].ip
1159 self
.port
= args
[0].port
1161 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1163 elif len(args
) == 2:
1167 raise TypeError("Too many arguments specified")
1170 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1174 def __call__(self
, value
):
1175 self
.__init
__(value
)
1179 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1181 def __eq__(self
, other
):
1182 if isinstance(other
, IpWithPort
):
1183 return self
.ip
== other
.ip
and self
.port
== other
.port
1184 elif isinstance(other
, str):
1186 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1194 if self
.port
< 0 or self
.port
> 0xffff:
1195 raise TypeError("invalid port %d" % self
.port
)
1198 from _m5
.net
import IpWithPort
1199 return IpWithPort(self
.ip
, self
.port
)
1201 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1202 "%a %b %d %H:%M:%S %Y",
1203 "%Y/%m/%d %H:%M:%S",
1206 "%m/%d/%Y %H:%M:%S",
1209 "%m/%d/%y %H:%M:%S",
1214 def parse_time(value
):
1215 from time
import gmtime
, strptime
, struct_time
, time
1216 from datetime
import datetime
, date
1218 if isinstance(value
, struct_time
):
1221 if isinstance(value
, (int, long)):
1222 return gmtime(value
)
1224 if isinstance(value
, (datetime
, date
)):
1225 return value
.timetuple()
1227 if isinstance(value
, str):
1228 if value
in ('Now', 'Today'):
1229 return time
.gmtime(time
.time())
1231 for format
in time_formats
:
1233 return strptime(value
, format
)
1237 raise ValueError("Could not parse '%s' as a time" % value
)
1239 class Time(ParamValue
):
1243 def cxx_predecls(cls
, code
):
1244 code('#include <time.h>')
1246 def __init__(self
, value
):
1247 self
.value
= parse_time(value
)
1249 def __call__(self
, value
):
1250 self
.__init
__(value
)
1254 from _m5
.core
import tm
1257 return tm
.gmtime(calendar
.timegm(self
.value
))
1260 return time
.asctime(self
.value
)
1265 def get_config_as_dict(self
):
1270 def cxx_ini_predecls(cls
, code
):
1271 code('#include <time.h>')
1274 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1275 code('char *_parse_ret = strptime((${src}).c_str(),')
1276 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1277 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1279 # Enumerated types are a little more complex. The user specifies the
1280 # type as Enum(foo) where foo is either a list or dictionary of
1281 # alternatives (typically strings, but not necessarily so). (In the
1282 # long run, the integer value of the parameter will be the list index
1283 # or the corresponding dictionary value. For now, since we only check
1284 # that the alternative is valid and then spit it into a .ini file,
1285 # there's not much point in using the dictionary.)
1287 # What Enum() must do is generate a new type encapsulating the
1288 # provided list/dictionary so that specific values of the parameter
1289 # can be instances of that type. We define two hidden internal
1290 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1291 # derive the new type from the appropriate base class on the fly.
1294 # Metaclass for Enum types
1295 class MetaEnum(MetaParamValue
):
1296 def __new__(mcls
, name
, bases
, dict):
1298 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1299 allEnums
[name
] = cls
1302 def __init__(cls
, name
, bases
, init_dict
):
1303 if 'map' in init_dict
:
1304 if not isinstance(cls
.map, dict):
1305 raise TypeError("Enum-derived class attribute 'map' " \
1306 "must be of type dict")
1307 # build list of value strings from map
1308 cls
.vals
= list(cls
.map.keys())
1310 elif 'vals' in init_dict
:
1311 if not isinstance(cls
.vals
, list):
1312 raise TypeError("Enum-derived class attribute 'vals' " \
1313 "must be of type list")
1314 # build string->value map from vals sequence
1316 for idx
,val
in enumerate(cls
.vals
):
1319 raise TypeError("Enum-derived class must define "\
1320 "attribute 'map' or 'vals'")
1323 cls
.cxx_type
= '%s' % name
1325 cls
.cxx_type
= 'Enums::%s' % name
1327 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1329 # Generate C++ class declaration for this enum type.
1330 # Note that we wrap the enum in a class/struct to act as a namespace,
1331 # so that the enum strings can be brief w/o worrying about collisions.
1332 def cxx_decl(cls
, code
):
1333 wrapper_name
= cls
.wrapper_name
1334 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1335 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1336 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1349 $wrapper $wrapper_name {
1354 for val
in cls
.vals
:
1355 code('$val = ${{cls.map[val]}},')
1356 code('Num_$name = ${{len(cls.vals)}}')
1362 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1364 elif cls
.wrapper_is_struct
:
1365 code('static const char *${name}Strings[Num_${name}];')
1367 code('extern const char *${name}Strings[Num_${name}];')
1369 if not cls
.is_class
:
1374 code('#endif // $idem_macro')
1376 def cxx_def(cls
, code
):
1377 wrapper_name
= cls
.wrapper_name
1378 file_name
= cls
.__name
__
1379 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1381 code('#include "enums/$file_name.hh"')
1382 if cls
.wrapper_is_struct
:
1383 code('const char *${wrapper_name}::${name}Strings'
1388 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1391 code('namespace Enums {')
1393 code('const char *${name}Strings[Num_${name}] =')
1397 for val
in cls
.vals
:
1402 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1404 code('} // namespace $wrapper_name')
1407 def pybind_def(cls
, code
):
1409 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1410 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1412 code('''#include "pybind11/pybind11.h"
1413 #include "pybind11/stl.h"
1415 #include <sim/init.hh>
1417 namespace py = pybind11;
1420 module_init(py::module &m_internal)
1422 py::module m = m_internal.def_submodule("enum_${name}");
1426 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1428 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1432 for val
in cls
.vals
:
1433 code('.value("${val}", ${wrapper_name}::${val})')
1434 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1435 if not cls
.is_class
:
1436 code('.export_values()')
1443 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1446 # Base class for enum types.
1447 class Enum(with_metaclass(MetaEnum
, ParamValue
)):
1449 cmd_line_settable
= True
1451 # The name of the wrapping namespace or struct
1452 wrapper_name
= 'Enums'
1454 # If true, the enum is wrapped in a struct rather than a namespace
1455 wrapper_is_struct
= False
1459 # If not None, use this as the enum name rather than this class name
1462 def __init__(self
, value
):
1463 if value
not in self
.map:
1464 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1465 % (value
, self
.vals
))
1468 def __call__(self
, value
):
1469 self
.__init
__(value
)
1473 def cxx_predecls(cls
, code
):
1474 code('#include "enums/$0.hh"', cls
.__name
__)
1477 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1478 code('if (false) {')
1479 for elem_name
in cls
.map.keys():
1480 code('} else if (%s == "%s") {' % (src
, elem_name
))
1482 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1483 code('%s = %s::%s;' % (dest
, name
if cls
.is_class
else 'Enums',
1485 code('%s true;' % ret
)
1488 code(' %s false;' % ret
)
1492 import m5
.internal
.params
1493 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1494 return e(self
.map[self
.value
])
1499 # This param will generate a scoped c++ enum and its python bindings.
1500 class ScopedEnum(Enum
):
1502 cmd_line_settable
= True
1504 # The name of the wrapping namespace or struct
1507 # If true, the enum is wrapped in a struct rather than a namespace
1508 wrapper_is_struct
= False
1510 # If true, the generated enum is a scoped enum
1513 # If not None, use this as the enum name rather than this class name
1516 class ByteOrder(ScopedEnum
):
1517 """Enum representing component's byte order (endianness)"""
1524 # how big does a rounding error need to be before we warn about it?
1525 frequency_tolerance
= 0.001 # 0.1%
1527 class TickParamValue(NumericParamValue
):
1530 cmd_line_settable
= True
1533 def cxx_predecls(cls
, code
):
1534 code('#include "base/types.hh"')
1536 def __call__(self
, value
):
1537 self
.__init
__(value
)
1541 return long(self
.value
)
1544 def cxx_ini_predecls(cls
, code
):
1545 code('#include <sstream>')
1547 # Ticks are expressed in seconds in JSON files and in plain
1548 # Ticks in .ini files. Switch based on a config flag
1550 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1551 code('${ret} to_number(${src}, ${dest});')
1553 class Latency(TickParamValue
):
1556 def __init__(self
, value
):
1557 if isinstance(value
, (Latency
, Clock
)):
1558 self
.ticks
= value
.ticks
1559 self
.value
= value
.value
1560 elif isinstance(value
, Frequency
):
1561 self
.ticks
= value
.ticks
1562 self
.value
= 1.0 / value
.value
1563 elif value
.endswith('t'):
1565 self
.value
= int(value
[:-1])
1568 self
.value
= convert
.toLatency(value
)
1570 def __call__(self
, value
):
1571 self
.__init
__(value
)
1574 def __getattr__(self
, attr
):
1575 if attr
in ('latency', 'period'):
1577 if attr
== 'frequency':
1578 return Frequency(self
)
1579 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1582 if self
.ticks
or self
.value
== 0:
1585 value
= ticks
.fromSeconds(self
.value
)
1588 def config_value(self
):
1589 return self
.getValue()
1591 # convert latency to ticks
1593 return '%d' % self
.getValue()
1595 class Frequency(TickParamValue
):
1598 def __init__(self
, value
):
1599 if isinstance(value
, (Latency
, Clock
)):
1600 if value
.value
== 0:
1603 self
.value
= 1.0 / value
.value
1604 self
.ticks
= value
.ticks
1605 elif isinstance(value
, Frequency
):
1606 self
.value
= value
.value
1607 self
.ticks
= value
.ticks
1610 self
.value
= convert
.toFrequency(value
)
1612 def __call__(self
, value
):
1613 self
.__init
__(value
)
1616 def __getattr__(self
, attr
):
1617 if attr
== 'frequency':
1619 if attr
in ('latency', 'period'):
1620 return Latency(self
)
1621 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1623 # convert latency to ticks
1625 if self
.ticks
or self
.value
== 0:
1628 value
= ticks
.fromSeconds(1.0 / self
.value
)
1631 def config_value(self
):
1632 return self
.getValue()
1635 return '%d' % self
.getValue()
1637 # A generic Frequency and/or Latency value. Value is stored as a
1638 # latency, just like Latency and Frequency.
1639 class Clock(TickParamValue
):
1640 def __init__(self
, value
):
1641 if isinstance(value
, (Latency
, Clock
)):
1642 self
.ticks
= value
.ticks
1643 self
.value
= value
.value
1644 elif isinstance(value
, Frequency
):
1645 self
.ticks
= value
.ticks
1646 self
.value
= 1.0 / value
.value
1647 elif value
.endswith('t'):
1649 self
.value
= int(value
[:-1])
1652 self
.value
= convert
.anyToLatency(value
)
1654 def __call__(self
, value
):
1655 self
.__init
__(value
)
1659 return "%s" % Latency(self
)
1661 def __getattr__(self
, attr
):
1662 if attr
== 'frequency':
1663 return Frequency(self
)
1664 if attr
in ('latency', 'period'):
1665 return Latency(self
)
1666 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1669 return self
.period
.getValue()
1671 def config_value(self
):
1672 return self
.period
.config_value()
1675 return self
.period
.ini_str()
1677 class Voltage(Float
):
1680 def __new__(cls
, value
):
1681 value
= convert
.toVoltage(value
)
1682 return super(cls
, Voltage
).__new
__(cls
, value
)
1684 def __init__(self
, value
):
1685 value
= convert
.toVoltage(value
)
1686 super(Voltage
, self
).__init
__(value
)
1688 class Current(Float
):
1691 def __new__(cls
, value
):
1692 value
= convert
.toCurrent(value
)
1693 return super(cls
, Current
).__new
__(cls
, value
)
1695 def __init__(self
, value
):
1696 value
= convert
.toCurrent(value
)
1697 super(Current
, self
).__init
__(value
)
1699 class Energy(Float
):
1702 def __new__(cls
, value
):
1703 value
= convert
.toEnergy(value
)
1704 return super(cls
, Energy
).__new
__(cls
, value
)
1706 def __init__(self
, value
):
1707 value
= convert
.toEnergy(value
)
1708 super(Energy
, self
).__init
__(value
)
1710 class NetworkBandwidth(float,ParamValue
):
1713 cmd_line_settable
= True
1715 def __new__(cls
, value
):
1716 # convert to bits per second
1717 val
= convert
.toNetworkBandwidth(value
)
1718 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1721 return str(self
.val
)
1723 def __call__(self
, value
):
1724 val
= convert
.toNetworkBandwidth(value
)
1729 # convert to seconds per byte
1730 value
= 8.0 / float(self
)
1731 # convert to ticks per byte
1732 value
= ticks
.fromSeconds(value
)
1736 return '%f' % self
.getValue()
1738 def config_value(self
):
1739 return '%f' % self
.getValue()
1742 def cxx_ini_predecls(cls
, code
):
1743 code('#include <sstream>')
1746 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1747 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1749 class MemoryBandwidth(float,ParamValue
):
1752 cmd_line_settable
= True
1754 def __new__(cls
, value
):
1755 # convert to bytes per second
1756 val
= convert
.toMemoryBandwidth(value
)
1757 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1759 def __call__(self
, value
):
1760 val
= convert
.toMemoryBandwidth(value
)
1765 # convert to seconds per byte
1768 value
= 1.0 / float(self
)
1769 # convert to ticks per byte
1770 value
= ticks
.fromSeconds(value
)
1774 return '%f' % self
.getValue()
1776 def config_value(self
):
1777 return '%f' % self
.getValue()
1780 def cxx_ini_predecls(cls
, code
):
1781 code('#include <sstream>')
1784 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1785 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1788 # "Constants"... handy aliases for various values.
1791 # Special class for NULL pointers. Note the special check in
1792 # make_param_value() above that lets these be assigned where a
1793 # SimObject is required.
1794 # only one copy of a particular node
1795 class NullSimObject(with_metaclass(Singleton
, object)):
1801 def _instantiate(self
, parent
= None, path
= ''):
1807 def unproxy(self
, base
):
1810 def set_path(self
, parent
, name
):
1813 def set_parent(self
, parent
, name
):
1816 def clear_parent(self
, old_parent
):
1819 def descendants(self
):
1823 def get_config_as_dict(self
):
1829 def config_value(self
):
1835 # The only instance you'll ever need...
1836 NULL
= NullSimObject()
1838 def isNullPointer(value
):
1839 return isinstance(value
, NullSimObject
)
1841 # Some memory range specifications use this as a default upper bound.
1844 AllMemory
= AddrRange(0, MaxAddr
)
1847 #####################################################################
1851 # Ports are used to interconnect objects in the memory system.
1853 #####################################################################
1855 # Port reference: encapsulates a reference to a particular port on a
1856 # particular SimObject.
1857 class PortRef(object):
1858 def __init__(self
, simobj
, name
, role
, is_source
):
1859 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1860 self
.simobj
= simobj
1863 self
.is_source
= is_source
1864 self
.peer
= None # not associated with another port yet
1865 self
.ccConnected
= False # C++ port connection done?
1866 self
.index
= -1 # always -1 for non-vector ports
1869 return '%s.%s' % (self
.simobj
, self
.name
)
1872 # Return the number of connected ports, i.e. 0 is we have no
1873 # peer and 1 if we do.
1874 return int(self
.peer
!= None)
1876 # for config.ini, print peer's name (not ours)
1878 return str(self
.peer
)
1881 def get_config_as_dict(self
):
1882 return {'role' : self
.role
, 'peer' : str(self
.peer
),
1883 'is_source' : str(self
.is_source
)}
1885 def __getattr__(self
, attr
):
1886 if attr
== 'peerObj':
1887 # shorthand for proxies
1888 return self
.peer
.simobj
1889 raise AttributeError("'%s' object has no attribute '%s'" % \
1890 (self
.__class
__.__name
__, attr
))
1892 # Full connection is symmetric (both ways). Called via
1893 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1894 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1895 # e.g., "obj1.portA[3] = obj2.portB".
1896 def connect(self
, other
):
1897 if isinstance(other
, VectorPortRef
):
1898 # reference to plain VectorPort is implicit append
1899 other
= other
._get
_next
()
1900 if self
.peer
and not proxy
.isproxy(self
.peer
):
1901 fatal("Port %s is already connected to %s, cannot connect %s\n",
1902 self
, self
.peer
, other
);
1905 if proxy
.isproxy(other
):
1906 other
.set_param_desc(PortParamDesc())
1908 elif not isinstance(other
, PortRef
):
1909 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1912 if not Port
.is_compat(self
, other
):
1913 fatal("Ports %s and %s with roles '%s' and '%s' "
1914 "are not compatible", self
, other
, self
.role
, other
.role
)
1916 if other
.peer
is not self
:
1919 # Allow a compatible port pair to be spliced between a port and its
1920 # connected peer. Useful operation for connecting instrumentation
1921 # structures into a system when it is necessary to connect the
1922 # instrumentation after the full system has been constructed.
1923 def splice(self
, new_1
, new_2
):
1924 if not self
.peer
or proxy
.isproxy(self
.peer
):
1925 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1927 if not isinstance(new_1
, PortRef
) or not isinstance(new_2
, PortRef
):
1929 "Splicing non-port references '%s','%s' to port '%s'" % \
1930 (new_1
, new_2
, self
))
1932 old_peer
= self
.peer
1934 if Port
.is_compat(old_peer
, new_1
) and Port
.is_compat(self
, new_2
):
1935 old_peer
.peer
= new_1
1936 new_1
.peer
= old_peer
1939 elif Port
.is_compat(old_peer
, new_2
) and Port
.is_compat(self
, new_1
):
1940 old_peer
.peer
= new_2
1941 new_2
.peer
= old_peer
1945 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
1946 "%s(%s) and %s(%s)", self
, self
.role
,
1947 old_peer
, old_peer
.role
, new_1
, new_1
.role
,
1950 def clone(self
, simobj
, memo
):
1953 newRef
= copy
.copy(self
)
1955 newRef
.simobj
= simobj
1956 assert(isSimObject(newRef
.simobj
))
1957 if self
.peer
and not proxy
.isproxy(self
.peer
):
1958 peerObj
= self
.peer
.simobj(_memo
=memo
)
1959 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1960 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1963 def unproxy(self
, simobj
):
1964 assert(simobj
is self
.simobj
)
1965 if proxy
.isproxy(self
.peer
):
1967 realPeer
= self
.peer
.unproxy(self
.simobj
)
1969 print("Error in unproxying port '%s' of %s" %
1970 (self
.name
, self
.simobj
.path()))
1972 self
.connect(realPeer
)
1974 # Call C++ to create corresponding port connection between C++ objects
1975 def ccConnect(self
):
1976 if self
.ccConnected
: # already done this
1980 if not self
.peer
: # nothing to connect to
1983 port
= self
.simobj
.getPort(self
.name
, self
.index
)
1984 peer_port
= peer
.simobj
.getPort(peer
.name
, peer
.index
)
1985 port
.bind(peer_port
)
1987 self
.ccConnected
= True
1989 # A reference to an individual element of a VectorPort... much like a
1990 # PortRef, but has an index.
1991 class VectorPortElementRef(PortRef
):
1992 def __init__(self
, simobj
, name
, role
, is_source
, index
):
1993 PortRef
.__init
__(self
, simobj
, name
, role
, is_source
)
1997 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1999 # A reference to a complete vector-valued port (not just a single element).
2000 # Can be indexed to retrieve individual VectorPortElementRef instances.
2001 class VectorPortRef(object):
2002 def __init__(self
, simobj
, name
, role
, is_source
):
2003 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
2004 self
.simobj
= simobj
2007 self
.is_source
= is_source
2011 return '%s.%s[:]' % (self
.simobj
, self
.name
)
2014 # Return the number of connected peers, corresponding the the
2015 # length of the elements.
2016 return len(self
.elements
)
2018 # for config.ini, print peer's name (not ours)
2020 return ' '.join([el
.ini_str() for el
in self
.elements
])
2023 def get_config_as_dict(self
):
2024 return {'role' : self
.role
,
2025 'peer' : [el
.ini_str() for el
in self
.elements
],
2026 'is_source' : str(self
.is_source
)}
2028 def __getitem__(self
, key
):
2029 if not isinstance(key
, int):
2030 raise TypeError("VectorPort index must be integer")
2031 if key
>= len(self
.elements
):
2032 # need to extend list
2033 ext
= [VectorPortElementRef(
2034 self
.simobj
, self
.name
, self
.role
, self
.is_source
, i
)
2035 for i
in range(len(self
.elements
), key
+1)]
2036 self
.elements
.extend(ext
)
2037 return self
.elements
[key
]
2039 def _get_next(self
):
2040 return self
[len(self
.elements
)]
2042 def __setitem__(self
, key
, value
):
2043 if not isinstance(key
, int):
2044 raise TypeError("VectorPort index must be integer")
2045 self
[key
].connect(value
)
2047 def connect(self
, other
):
2048 if isinstance(other
, (list, tuple)):
2049 # Assign list of port refs to vector port.
2050 # For now, append them... not sure if that's the right semantics
2051 # or if it should replace the current vector.
2053 self
._get
_next
().connect(ref
)
2055 # scalar assignment to plain VectorPort is implicit append
2056 self
._get
_next
().connect(other
)
2058 def clone(self
, simobj
, memo
):
2061 newRef
= copy
.copy(self
)
2063 newRef
.simobj
= simobj
2064 assert(isSimObject(newRef
.simobj
))
2065 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2068 def unproxy(self
, simobj
):
2069 [el
.unproxy(simobj
) for el
in self
.elements
]
2071 def ccConnect(self
):
2072 [el
.ccConnect() for el
in self
.elements
]
2074 # Port description object. Like a ParamDesc object, this represents a
2075 # logical port in the SimObject class, not a particular port on a
2076 # SimObject instance. The latter are represented by PortRef objects.
2078 # Port("role", "description")
2083 def compat(cls
, role
, peer
):
2084 cls
._compat
_dict
.setdefault(role
, set()).add(peer
)
2085 cls
._compat
_dict
.setdefault(peer
, set()).add(role
)
2088 def is_compat(cls
, one
, two
):
2089 for port
in one
, two
:
2090 if not port
.role
in Port
._compat
_dict
:
2091 fatal("Unrecognized role '%s' for port %s\n", port
.role
, port
)
2092 return one
.role
in Port
._compat
_dict
[two
.role
]
2094 def __init__(self
, role
, desc
, is_source
=False):
2097 self
.is_source
= is_source
2099 # Generate a PortRef for this port on the given SimObject with the
2101 def makeRef(self
, simobj
):
2102 return PortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2104 # Connect an instance of this port (on the given SimObject with
2105 # the given name) with the port described by the supplied PortRef
2106 def connect(self
, simobj
, ref
):
2107 self
.makeRef(simobj
).connect(ref
)
2109 # No need for any pre-declarations at the moment as we merely rely
2110 # on an unsigned int.
2111 def cxx_predecls(self
, code
):
2114 def pybind_predecls(self
, code
):
2115 cls
.cxx_predecls(self
, code
)
2117 # Declare an unsigned int with the same name as the port, that
2118 # will eventually hold the number of connected ports (and thus the
2119 # number of elements for a VectorPort).
2120 def cxx_decl(self
, code
):
2121 code('unsigned int port_${{self.name}}_connection_count;')
2123 Port
.compat('GEM5 REQUESTOR', 'GEM5 RESPONDER')
2125 class RequestPort(Port
):
2126 # RequestPort("description")
2127 def __init__(self
, desc
):
2128 super(RequestPort
, self
).__init
__(
2129 'GEM5 REQUESTOR', desc
, is_source
=True)
2131 class ResponsePort(Port
):
2132 # ResponsePort("description")
2133 def __init__(self
, desc
):
2134 super(ResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2136 # VectorPort description object. Like Port, but represents a vector
2137 # of connections (e.g., as on a XBar).
2138 class VectorPort(Port
):
2139 def makeRef(self
, simobj
):
2140 return VectorPortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2142 class VectorRequestPort(VectorPort
):
2143 # VectorRequestPort("description")
2144 def __init__(self
, desc
):
2145 super(VectorRequestPort
, self
).__init
__(
2146 'GEM5 REQUESTOR', desc
, is_source
=True)
2148 class VectorResponsePort(VectorPort
):
2149 # VectorResponsePort("description")
2150 def __init__(self
, desc
):
2151 super(VectorResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2153 # Old names, maintained for compatibility.
2154 MasterPort
= RequestPort
2155 SlavePort
= ResponsePort
2156 VectorMasterPort
= VectorRequestPort
2157 VectorSlavePort
= VectorResponsePort
2159 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2160 # proxy objects (via set_param_desc()) so that proxy error messages
2162 class PortParamDesc(with_metaclass(Singleton
, object)):
2166 class DeprecatedParam(object):
2167 """A special type for deprecated parameter variable names.
2169 There are times when we need to change the name of parameter, but this
2170 breaks the external-facing python API used in configuration files. Using
2171 this "type" for a parameter will warn users that they are using the old
2172 name, but allow for backwards compatibility.
2175 In the following example, the `time` parameter is changed to `delay`.
2178 class SomeDevice(SimObject):
2179 delay = Param.Latency('1ns', 'The time to wait before something')
2180 time = DeprecatedParam(delay, '`time` is now called `delay`')
2184 def __init__(self
, new_param
, message
=''):
2185 """new_param: the new parameter variable that users should be using
2186 instead of this parameter variable.
2187 message: an optional message to print when warning the user
2189 self
.message
= message
2190 self
.newParam
= new_param
2191 # Note: We won't know the string variable names until later in the
2192 # SimObject initialization process. Note: we expect that the setters
2193 # will be called when the SimObject type (class) is initialized so
2194 # these variables should be filled in before the instance of the
2195 # SimObject with this parameter is constructed
2201 assert(self
._oldName
!= '') # should already be set
2202 return self
._oldName
2205 def oldName(self
, name
):
2206 assert(self
._oldName
== '') # Cannot "re-set" this value
2207 self
._oldName
= name
2211 assert(self
._newName
!= '') # should already be set
2212 return self
._newName
2215 def newName(self
, name
):
2216 assert(self
._newName
== '') # Cannot "re-set" this value
2217 self
._newName
= name
2219 def printWarning(self
, instance_name
, simobj_name
):
2220 """Issue a warning that this variable name should not be used.
2222 instance_name: str, the name of the instance used in python
2223 simobj_name: str, the name of the SimObject type
2225 if not self
.message
:
2226 self
.message
= "See {} for more information".format(simobj_name
)
2227 warn('{}.{} is deprecated. {}'.format(
2228 instance_name
, self
._oldName
, self
.message
))
2230 baseEnums
= allEnums
.copy()
2231 baseParams
= allParams
.copy()
2234 global allEnums
, allParams
2236 allEnums
= baseEnums
.copy()
2237 allParams
= baseParams
.copy()
2239 __all__
= ['Param', 'VectorParam',
2240 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2241 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2242 'Int32', 'UInt32', 'Int64', 'UInt64',
2243 'Counter', 'Addr', 'Tick', 'Percent',
2244 'TcpPort', 'UdpPort', 'EthernetAddr',
2245 'IpAddress', 'IpNetmask', 'IpWithPort',
2246 'MemorySize', 'MemorySize32',
2247 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2248 'NetworkBandwidth', 'MemoryBandwidth',
2250 'MaxAddr', 'MaxTick', 'AllMemory',
2252 'NextEthernetAddr', 'NULL',
2253 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2254 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2255 'VectorMasterPort', 'VectorSlavePort',