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 add_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 @add_metaclass(MetaParamValue
)
101 class ParamValue(object):
102 cmd_line_settable
= False
104 # Generate the code needed as a prerequisite for declaring a C++
105 # object of this type. Typically generates one or more #include
106 # statements. Used when declaring parameters of this type.
108 def cxx_predecls(cls
, code
):
112 def pybind_predecls(cls
, code
):
113 cls
.cxx_predecls(code
)
115 # default for printing to .ini file is regular string conversion.
116 # will be overridden in some cases
120 # default for printing to .json file is regular string conversion.
121 # will be overridden in some cases, mostly to use native Python
122 # types where there are similar JSON types
123 def config_value(self
):
126 # Prerequisites for .ini parsing with cxx_ini_parse
128 def cxx_ini_predecls(cls
, code
):
131 # parse a .ini file entry for this param from string expression
132 # src into lvalue dest (of the param's C++ type)
134 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
135 code('// Unhandled param type: %s' % cls
.__name
__)
136 code('%s false;' % ret
)
138 # allows us to blithely call unproxy() on things without checking
139 # if they're really proxies or not
140 def unproxy(self
, base
):
143 # Produce a human readable version of the stored value
144 def pretty_print(self
, value
):
147 # Regular parameter description.
148 class ParamDesc(object):
149 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
150 self
.ptype_str
= ptype_str
151 # remember ptype only if it is provided
159 self
.default
= args
[0]
162 raise TypeError('too many arguments')
165 assert(not hasattr(self
, 'desc'))
166 self
.desc
= kwargs
['desc']
169 if 'default' in kwargs
:
170 assert(not hasattr(self
, 'default'))
171 self
.default
= kwargs
['default']
172 del kwargs
['default']
175 raise TypeError('extra unknown kwargs %s' % kwargs
)
177 if not hasattr(self
, 'desc'):
178 raise TypeError('desc attribute missing')
180 def __getattr__(self
, attr
):
182 from . import SimObject
183 ptype
= SimObject
.allClasses
[self
.ptype_str
]
184 assert isSimObjectClass(ptype
)
188 raise AttributeError("'%s' object has no attribute '%s'" % \
189 (type(self
).__name
__, attr
))
191 def example_str(self
):
192 if hasattr(self
.ptype
, "ex_str"):
193 return self
.ptype
.ex_str
195 return self
.ptype_str
197 # Is the param available to be exposed on the command line
198 def isCmdLineSettable(self
):
199 if hasattr(self
.ptype
, "cmd_line_settable"):
200 return self
.ptype
.cmd_line_settable
204 def convert(self
, value
):
205 if isinstance(value
, proxy
.BaseProxy
):
206 value
.set_param_desc(self
)
208 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
209 # deferred evaluation of SimObject; continue to defer if
210 # we're just assigning a null pointer
212 if isinstance(value
, self
.ptype
):
214 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
216 return self
.ptype(value
)
218 def pretty_print(self
, value
):
219 if isinstance(value
, proxy
.BaseProxy
):
221 if isNullPointer(value
):
223 return self
.ptype(value
).pretty_print(value
)
225 def cxx_predecls(self
, code
):
226 code('#include <cstddef>')
227 self
.ptype
.cxx_predecls(code
)
229 def pybind_predecls(self
, code
):
230 self
.ptype
.pybind_predecls(code
)
232 def cxx_decl(self
, code
):
233 code('${{self.ptype.cxx_type}} ${{self.name}};')
235 # Vector-valued parameter description. Just like ParamDesc, except
236 # that the value is a vector (list) of the specified type instead of a
239 @add_metaclass(MetaParamValue
)
240 class VectorParamValue(list):
241 def __setattr__(self
, attr
, value
):
242 raise AttributeError("Not allowed to set %s on '%s'" % \
243 (attr
, type(self
).__name
__))
245 def config_value(self
):
246 return [v
.config_value() for v
in self
]
249 return ' '.join([v
.ini_str() for v
in self
])
252 return [ v
.getValue() for v
in self
]
254 def unproxy(self
, base
):
255 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
256 # The value is a proxy (e.g. Parent.any, Parent.all or
257 # Parent.x) therefore try resolve it
258 return self
[0].unproxy(base
)
260 return [v
.unproxy(base
) for v
in self
]
262 class SimObjectVector(VectorParamValue
):
263 # support clone operation
264 def __call__(self
, **kwargs
):
265 return SimObjectVector([v(**kwargs
) for v
in self
])
267 def clear_parent(self
, old_parent
):
269 v
.clear_parent(old_parent
)
271 def set_parent(self
, parent
, name
):
273 self
[0].set_parent(parent
, name
)
275 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
276 for i
,v
in enumerate(self
):
277 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
279 def has_parent(self
):
280 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
282 # return 'cpu0 cpu1' etc. for print_ini()
284 return ' '.join([v
._name
for v
in self
])
286 # By iterating through the constituent members of the vector here
287 # we can nicely handle iterating over all a SimObject's children
288 # without having to provide lots of special functions on
289 # SimObjectVector directly.
290 def descendants(self
):
292 for obj
in v
.descendants():
295 def get_config_as_dict(self
):
298 a
.append(v
.get_config_as_dict())
301 # If we are replacing an item in the vector, make sure to set the
302 # parent reference of the new SimObject to be the same as the parent
303 # of the SimObject being replaced. Useful to have if we created
304 # a SimObjectVector of temporary objects that will be modified later in
305 # configuration scripts.
306 def __setitem__(self
, key
, value
):
308 if value
.has_parent():
309 warn("SimObject %s already has a parent" % value
.get_name() +\
310 " that is being overwritten by a SimObjectVector")
311 value
.set_parent(val
.get_parent(), val
._name
)
312 super(SimObjectVector
, self
).__setitem
__(key
, value
)
314 # Enumerate the params of each member of the SimObject vector. Creates
315 # strings that will allow indexing into the vector by the python code and
316 # allow it to be specified on the command line.
317 def enumerateParams(self
, flags_dict
= {},
320 if hasattr(self
, "_paramEnumed"):
321 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
325 # Each entry in the SimObjectVector should be an
326 # instance of a SimObject
327 flags_dict
= vals
.enumerateParams(flags_dict
,
328 cmd_line_str
+ "%d." % x
,
329 access_str
+ "[%d]." % x
)
334 class VectorParamDesc(ParamDesc
):
335 # Convert assigned value to appropriate type. If the RHS is not a
336 # list or tuple, it generates a single-element list.
337 def convert(self
, value
):
338 if isinstance(value
, (list, tuple)):
339 # list: coerce each element into new list
340 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
341 elif isinstance(value
, str):
342 # If input is a csv string
343 tmp_list
= [ ParamDesc
.convert(self
, v
) \
344 for v
in value
.strip('[').strip(']').split(',') ]
346 # singleton: coerce to a single-element list
347 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
349 if isSimObjectSequence(tmp_list
):
350 return SimObjectVector(tmp_list
)
352 return VectorParamValue(tmp_list
)
354 # Produce a human readable example string that describes
355 # how to set this vector parameter in the absence of a default
357 def example_str(self
):
358 s
= super(VectorParamDesc
, self
).example_str()
359 help_str
= "[" + s
+ "," + s
+ ", ...]"
362 # Produce a human readable representation of the value of this vector param.
363 def pretty_print(self
, value
):
364 if isinstance(value
, (list, tuple)):
365 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
366 elif isinstance(value
, str):
367 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
369 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
373 # This is a helper function for the new config system
374 def __call__(self
, value
):
375 if isinstance(value
, (list, tuple)):
376 # list: coerce each element into new list
377 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
378 elif isinstance(value
, str):
379 # If input is a csv string
380 tmp_list
= [ ParamDesc
.convert(self
, v
) \
381 for v
in value
.strip('[').strip(']').split(',') ]
383 # singleton: coerce to a single-element list
384 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
386 return VectorParamValue(tmp_list
)
388 def cxx_predecls(self
, code
):
389 code('#include <vector>')
390 self
.ptype
.cxx_predecls(code
)
392 def pybind_predecls(self
, code
):
393 code('#include <vector>')
394 self
.ptype
.pybind_predecls(code
)
396 def cxx_decl(self
, code
):
397 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
399 class ParamFactory(object):
400 def __init__(self
, param_desc_class
, ptype_str
= None):
401 self
.param_desc_class
= param_desc_class
402 self
.ptype_str
= ptype_str
404 def __getattr__(self
, attr
):
406 attr
= self
.ptype_str
+ '.' + attr
407 return ParamFactory(self
.param_desc_class
, attr
)
409 # E.g., Param.Int(5, "number of widgets")
410 def __call__(self
, *args
, **kwargs
):
413 ptype
= allParams
[self
.ptype_str
]
415 # if name isn't defined yet, assume it's a SimObject, and
416 # try to resolve it later
418 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
420 Param
= ParamFactory(ParamDesc
)
421 VectorParam
= ParamFactory(VectorParamDesc
)
423 #####################################################################
427 # Though native Python types could be used to specify parameter types
428 # (the 'ptype' field of the Param and VectorParam classes), it's more
429 # flexible to define our own set of types. This gives us more control
430 # over how Python expressions are converted to values (via the
431 # __init__() constructor) and how these values are printed out (via
432 # the __str__() conversion method).
434 #####################################################################
436 # String-valued parameter. Just mixin the ParamValue class with the
437 # built-in str class.
438 class String(ParamValue
,str):
439 cxx_type
= 'std::string'
440 cmd_line_settable
= True
443 def cxx_predecls(self
, code
):
444 code('#include <string>')
446 def __call__(self
, value
):
451 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
452 code('%s = %s;' % (dest
, src
))
453 code('%s true;' % ret
)
458 # superclass for "numeric" parameter values, to emulate math
459 # operations in a type-safe way. e.g., a Latency times an int returns
460 # a new Latency object.
461 class NumericParamValue(ParamValue
):
464 return v
.value
if isinstance(v
, NumericParamValue
) else v
467 return str(self
.value
)
470 return float(self
.value
)
473 return long(self
.value
)
476 return int(self
.value
)
478 # hook for bounds checking
482 def __mul__(self
, other
):
483 newobj
= self
.__class
__(self
)
484 newobj
.value
*= NumericParamValue
.unwrap(other
)
490 def __truediv__(self
, other
):
491 newobj
= self
.__class
__(self
)
492 newobj
.value
/= NumericParamValue
.unwrap(other
)
496 def __floordiv__(self
, other
):
497 newobj
= self
.__class
__(self
)
498 newobj
.value
//= NumericParamValue
.unwrap(other
)
503 def __add__(self
, other
):
504 newobj
= self
.__class
__(self
)
505 newobj
.value
+= NumericParamValue
.unwrap(other
)
509 def __sub__(self
, other
):
510 newobj
= self
.__class
__(self
)
511 newobj
.value
-= NumericParamValue
.unwrap(other
)
515 def __iadd__(self
, other
):
516 self
.value
+= NumericParamValue
.unwrap(other
)
520 def __isub__(self
, other
):
521 self
.value
-= NumericParamValue
.unwrap(other
)
525 def __imul__(self
, other
):
526 self
.value
*= NumericParamValue
.unwrap(other
)
530 def __itruediv__(self
, other
):
531 self
.value
/= NumericParamValue
.unwrap(other
)
535 def __ifloordiv__(self
, other
):
536 self
.value
//= NumericParamValue
.unwrap(other
)
540 def __lt__(self
, other
):
541 return self
.value
< NumericParamValue
.unwrap(other
)
543 # Python 2.7 pre __future__.division operators
544 # TODO: Remove these when after "import division from __future__"
545 __div__
= __truediv__
546 __idiv__
= __itruediv__
548 def config_value(self
):
552 def cxx_ini_predecls(cls
, code
):
553 # Assume that base/str.hh will be included anyway
554 # code('#include "base/str.hh"')
557 # The default for parsing PODs from an .ini entry is to extract from an
558 # istringstream and let overloading choose the right type according to
561 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
562 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
564 # Metaclass for bounds-checked integer parameters. See CheckedInt.
565 class CheckedIntType(MetaParamValue
):
566 def __init__(cls
, name
, bases
, dict):
567 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
569 # CheckedInt is an abstract base class, so we actually don't
570 # want to do any processing on it... the rest of this code is
571 # just for classes that derive from CheckedInt.
572 if name
== 'CheckedInt':
575 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
576 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
577 panic("CheckedInt subclass %s must define either\n" \
578 " 'min' and 'max' or 'size' and 'unsigned'\n",
582 cls
.max = 2 ** cls
.size
- 1
584 cls
.min = -(2 ** (cls
.size
- 1))
585 cls
.max = (2 ** (cls
.size
- 1)) - 1
587 # Abstract superclass for bounds-checked integer parameters. This
588 # class is subclassed to generate parameter classes with specific
589 # bounds. Initialization of the min and max bounds is done in the
590 # metaclass CheckedIntType.__init__.
591 @add_metaclass(CheckedIntType
)
592 class CheckedInt(NumericParamValue
):
593 cmd_line_settable
= True
596 if not self
.min <= self
.value
<= self
.max:
597 raise TypeError('Integer param out of bounds %d < %d < %d' % \
598 (self
.min, self
.value
, self
.max))
600 def __init__(self
, value
):
601 if isinstance(value
, str):
602 self
.value
= convert
.toInteger(value
)
603 elif isinstance(value
, (int, long, float, NumericParamValue
)):
604 self
.value
= long(value
)
606 raise TypeError("Can't convert object of type %s to CheckedInt" \
607 % type(value
).__name
__)
610 def __call__(self
, value
):
615 return int(self
.value
)
618 def cxx_predecls(cls
, code
):
619 # most derived types require this, so we just do it here once
620 code('#include "base/types.hh"')
623 return long(self
.value
)
625 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
626 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
628 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
629 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
630 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
631 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
632 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
633 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
634 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
635 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
637 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
638 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
639 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
640 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
642 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
644 class Cycles(CheckedInt
):
650 from _m5
.core
import Cycles
651 return Cycles(self
.value
)
654 def cxx_ini_predecls(cls
, code
):
655 # Assume that base/str.hh will be included anyway
656 # code('#include "base/str.hh"')
660 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
661 code('uint64_t _temp;')
662 code('bool _ret = to_number(%s, _temp);' % src
)
664 code(' %s = Cycles(_temp);' % dest
)
665 code('%s _ret;' % ret
)
667 class Float(ParamValue
, float):
669 cmd_line_settable
= True
671 def __init__(self
, value
):
672 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
673 self
.value
= float(value
)
675 raise TypeError("Can't convert object of type %s to Float" \
676 % type(value
).__name
__)
678 def __call__(self
, value
):
683 return float(self
.value
)
685 def config_value(self
):
689 def cxx_ini_predecls(cls
, code
):
690 code('#include <sstream>')
693 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
694 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
696 class MemorySize(CheckedInt
):
697 cxx_type
= 'uint64_t'
701 def __init__(self
, value
):
702 if isinstance(value
, MemorySize
):
703 self
.value
= value
.value
705 self
.value
= convert
.toMemorySize(value
)
708 class MemorySize32(CheckedInt
):
709 cxx_type
= 'uint32_t'
713 def __init__(self
, value
):
714 if isinstance(value
, MemorySize
):
715 self
.value
= value
.value
717 self
.value
= convert
.toMemorySize(value
)
720 class Addr(CheckedInt
):
724 def __init__(self
, value
):
725 if isinstance(value
, Addr
):
726 self
.value
= value
.value
729 # Often addresses are referred to with sizes. Ex: A device
730 # base address is at "512MB". Use toMemorySize() to convert
731 # these into addresses. If the address is not specified with a
732 # "size", an exception will occur and numeric translation will
734 self
.value
= convert
.toMemorySize(value
)
735 except (TypeError, ValueError):
736 # Convert number to string and use long() to do automatic
737 # base conversion (requires base=0 for auto-conversion)
738 self
.value
= long(str(value
), base
=0)
741 def __add__(self
, other
):
742 if isinstance(other
, Addr
):
743 return self
.value
+ other
.value
745 return self
.value
+ other
746 def pretty_print(self
, value
):
748 val
= convert
.toMemorySize(value
)
751 return "0x%x" % long(val
)
753 class AddrRange(ParamValue
):
754 cxx_type
= 'AddrRange'
756 def __init__(self
, *args
, **kwargs
):
757 # Disable interleaving and hashing by default
762 def handle_kwargs(self
, kwargs
):
763 # An address range needs to have an upper limit, specified
764 # either explicitly with an end, or as an offset using the
767 self
.end
= Addr(kwargs
.pop('end'))
768 elif 'size' in kwargs
:
769 self
.end
= self
.start
+ Addr(kwargs
.pop('size'))
771 raise TypeError("Either end or size must be specified")
773 # Now on to the optional bit
774 if 'intlvMatch' in kwargs
:
775 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
777 if 'masks' in kwargs
:
778 self
.masks
= [ long(x
) for x
in list(kwargs
.pop('masks')) ]
779 self
.intlvBits
= len(self
.masks
)
781 if 'intlvBits' in kwargs
:
782 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
783 self
.masks
= [0] * self
.intlvBits
784 if 'intlvHighBit' not in kwargs
:
785 raise TypeError("No interleave bits specified")
786 intlv_high_bit
= int(kwargs
.pop('intlvHighBit'))
788 if 'xorHighBit' in kwargs
:
789 xor_high_bit
= int(kwargs
.pop('xorHighBit'))
790 for i
in range(0, self
.intlvBits
):
791 bit1
= intlv_high_bit
- i
793 if xor_high_bit
!= 0:
794 bit2
= xor_high_bit
- i
796 self
.masks
[self
.intlvBits
- i
- 1] = mask
799 self
.start
= Addr(kwargs
.pop('start'))
800 handle_kwargs(self
, kwargs
)
804 self
.start
= Addr(args
[0])
805 handle_kwargs(self
, kwargs
)
806 elif isinstance(args
[0], (list, tuple)):
807 self
.start
= Addr(args
[0][0])
808 self
.end
= Addr(args
[0][1])
811 self
.end
= Addr(args
[0])
814 self
.start
= Addr(args
[0])
815 self
.end
= Addr(args
[1])
817 raise TypeError("Too many arguments specified")
820 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
823 if len(self
.masks
) == 0:
824 return '%s:%s' % (self
.start
, self
.end
)
826 return '%s:%s:%s:%s' % (self
.start
, self
.end
, self
.intlvMatch
,
827 ':'.join(str(m
) for m
in self
.masks
))
830 # Divide the size by the size of the interleaving slice
831 return (long(self
.end
) - long(self
.start
)) >> self
.intlvBits
834 def cxx_predecls(cls
, code
):
835 Addr
.cxx_predecls(code
)
836 code('#include "base/addr_range.hh"')
839 def pybind_predecls(cls
, code
):
840 Addr
.pybind_predecls(code
)
841 code('#include "base/addr_range.hh"')
844 def cxx_ini_predecls(cls
, code
):
845 code('#include <sstream>')
846 code('#include <vector>')
847 code('#include "base/types.hh"')
850 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
851 code('bool _ret = true;')
852 code('uint64_t _start, _end, _intlvMatch = 0;')
853 code('std::vector<Addr> _masks;')
855 code('std::istringstream _stream(${src});')
856 code('_stream >> _start;')
857 code('_stream.get(_sep);')
858 code('_ret = _sep == \':\';')
859 code('_stream >> _end;')
860 code('if (!_stream.fail() && !_stream.eof()) {')
861 code(' _stream.get(_sep);')
862 code(' _ret = ret && _sep == \':\';')
863 code(' _stream >> _intlvMatch;')
864 code(' while (!_stream.fail() && !_stream.eof()) {')
865 code(' _stream.get(_sep);')
866 code(' _ret = ret && _sep == \':\';')
868 code(' _stream >> mask;')
869 code(' _masks.push_back(mask);')
872 code('_ret = _ret && !_stream.fail() && _stream.eof();')
874 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
878 # Go from the Python class to the wrapped C++ class
879 from _m5
.range import AddrRange
881 return AddrRange(long(self
.start
), long(self
.end
),
882 self
.masks
, int(self
.intlvMatch
))
884 # Boolean parameter type. Python doesn't let you subclass bool, since
885 # it doesn't want to let you create multiple instances of True and
886 # False. Thus this is a little more complicated than String.
887 class Bool(ParamValue
):
889 cmd_line_settable
= True
891 def __init__(self
, value
):
893 self
.value
= convert
.toBool(value
)
895 self
.value
= bool(value
)
897 def __call__(self
, value
):
902 return bool(self
.value
)
905 return str(self
.value
)
907 # implement truth value testing for Bool parameters so that these params
908 # evaluate correctly during the python configuration phase
910 return bool(self
.value
)
912 # Python 2.7 uses __nonzero__ instead of __bool__
913 __nonzero__
= __bool__
920 def config_value(self
):
924 def cxx_ini_predecls(cls
, code
):
925 # Assume that base/str.hh will be included anyway
926 # code('#include "base/str.hh"')
930 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
931 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
933 def IncEthernetAddr(addr
, val
= 1):
934 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
936 for i
in (5, 4, 3, 2, 1):
937 val
,rem
= divmod(bytes
[i
], 256)
942 assert(bytes
[0] <= 255)
943 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
945 _NextEthernetAddr
= "00:90:00:00:00:01"
946 def NextEthernetAddr():
947 global _NextEthernetAddr
949 value
= _NextEthernetAddr
950 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
953 class EthernetAddr(ParamValue
):
954 cxx_type
= 'Net::EthAddr'
955 ex_str
= "00:90:00:00:00:01"
956 cmd_line_settable
= True
959 def cxx_predecls(cls
, code
):
960 code('#include "base/inet.hh"')
962 def __init__(self
, value
):
963 if value
== NextEthernetAddr
:
967 if not isinstance(value
, str):
968 raise TypeError("expected an ethernet address and didn't get one")
970 bytes
= value
.split(':')
972 raise TypeError('invalid ethernet address %s' % value
)
975 if not 0 <= int(byte
, base
=16) <= 0xff:
976 raise TypeError('invalid ethernet address %s' % value
)
980 def __call__(self
, value
):
984 def unproxy(self
, base
):
985 if self
.value
== NextEthernetAddr
:
986 return EthernetAddr(self
.value())
990 from _m5
.net
import EthAddr
991 return EthAddr(self
.value
)
1000 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1001 code('%s = Net::EthAddr(%s);' % (dest
, src
))
1002 code('%s true;' % ret
)
1004 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1005 # the form "a.b.c.d", or an integer representing an IP.
1006 class IpAddress(ParamValue
):
1007 cxx_type
= 'Net::IpAddress'
1008 ex_str
= "127.0.0.1"
1009 cmd_line_settable
= True
1012 def cxx_predecls(cls
, code
):
1013 code('#include "base/inet.hh"')
1015 def __init__(self
, value
):
1016 if isinstance(value
, IpAddress
):
1020 self
.ip
= convert
.toIpAddress(value
)
1022 self
.ip
= long(value
)
1025 def __call__(self
, value
):
1026 self
.__init
__(value
)
1030 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1031 return '%d.%d.%d.%d' % tuple(tup
)
1033 def __eq__(self
, other
):
1034 if isinstance(other
, IpAddress
):
1035 return self
.ip
== other
.ip
1036 elif isinstance(other
, str):
1038 return self
.ip
== convert
.toIpAddress(other
)
1042 return self
.ip
== other
1044 def __ne__(self
, other
):
1045 return not (self
== other
)
1048 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1049 raise TypeError("invalid ip address %#08x" % self
.ip
)
1052 from _m5
.net
import IpAddress
1053 return IpAddress(self
.ip
)
1055 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1056 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1057 # positional or keyword arguments.
1058 class IpNetmask(IpAddress
):
1059 cxx_type
= 'Net::IpNetmask'
1060 ex_str
= "127.0.0.0/24"
1061 cmd_line_settable
= True
1064 def cxx_predecls(cls
, code
):
1065 code('#include "base/inet.hh"')
1067 def __init__(self
, *args
, **kwargs
):
1068 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1070 setattr(self
, key
, kwargs
.pop(key
))
1072 setattr(self
, key
, elseVal
)
1074 raise TypeError("No value set for %s" % key
)
1077 handle_kwarg(self
, kwargs
, 'ip')
1078 handle_kwarg(self
, kwargs
, 'netmask')
1080 elif len(args
) == 1:
1082 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1083 raise TypeError("Invalid arguments")
1084 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1085 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1086 elif isinstance(args
[0], IpNetmask
):
1087 self
.ip
= args
[0].ip
1088 self
.netmask
= args
[0].netmask
1090 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1092 elif len(args
) == 2:
1094 self
.netmask
= args
[1]
1096 raise TypeError("Too many arguments specified")
1099 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1103 def __call__(self
, value
):
1104 self
.__init
__(value
)
1108 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1110 def __eq__(self
, other
):
1111 if isinstance(other
, IpNetmask
):
1112 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1113 elif isinstance(other
, str):
1115 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1123 if self
.netmask
< 0 or self
.netmask
> 32:
1124 raise TypeError("invalid netmask %d" % netmask
)
1127 from _m5
.net
import IpNetmask
1128 return IpNetmask(self
.ip
, self
.netmask
)
1130 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1131 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1132 class IpWithPort(IpAddress
):
1133 cxx_type
= 'Net::IpWithPort'
1134 ex_str
= "127.0.0.1:80"
1135 cmd_line_settable
= True
1138 def cxx_predecls(cls
, code
):
1139 code('#include "base/inet.hh"')
1141 def __init__(self
, *args
, **kwargs
):
1142 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1144 setattr(self
, key
, kwargs
.pop(key
))
1146 setattr(self
, key
, elseVal
)
1148 raise TypeError("No value set for %s" % key
)
1151 handle_kwarg(self
, kwargs
, 'ip')
1152 handle_kwarg(self
, kwargs
, 'port')
1154 elif len(args
) == 1:
1156 if not 'ip' in kwargs
and not 'port' in kwargs
:
1157 raise TypeError("Invalid arguments")
1158 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1159 handle_kwarg(self
, kwargs
, 'port', args
[0])
1160 elif isinstance(args
[0], IpWithPort
):
1161 self
.ip
= args
[0].ip
1162 self
.port
= args
[0].port
1164 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1166 elif len(args
) == 2:
1170 raise TypeError("Too many arguments specified")
1173 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1177 def __call__(self
, value
):
1178 self
.__init
__(value
)
1182 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1184 def __eq__(self
, other
):
1185 if isinstance(other
, IpWithPort
):
1186 return self
.ip
== other
.ip
and self
.port
== other
.port
1187 elif isinstance(other
, str):
1189 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1197 if self
.port
< 0 or self
.port
> 0xffff:
1198 raise TypeError("invalid port %d" % self
.port
)
1201 from _m5
.net
import IpWithPort
1202 return IpWithPort(self
.ip
, self
.port
)
1204 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1205 "%a %b %d %H:%M:%S %Y",
1206 "%Y/%m/%d %H:%M:%S",
1209 "%m/%d/%Y %H:%M:%S",
1212 "%m/%d/%y %H:%M:%S",
1217 def parse_time(value
):
1218 from time
import gmtime
, strptime
, struct_time
, time
1219 from datetime
import datetime
, date
1221 if isinstance(value
, struct_time
):
1224 if isinstance(value
, (int, long)):
1225 return gmtime(value
)
1227 if isinstance(value
, (datetime
, date
)):
1228 return value
.timetuple()
1230 if isinstance(value
, str):
1231 if value
in ('Now', 'Today'):
1232 return time
.gmtime(time
.time())
1234 for format
in time_formats
:
1236 return strptime(value
, format
)
1240 raise ValueError("Could not parse '%s' as a time" % value
)
1242 class Time(ParamValue
):
1246 def cxx_predecls(cls
, code
):
1247 code('#include <time.h>')
1249 def __init__(self
, value
):
1250 self
.value
= parse_time(value
)
1252 def __call__(self
, value
):
1253 self
.__init
__(value
)
1257 from _m5
.core
import tm
1260 return tm
.gmtime(calendar
.timegm(self
.value
))
1263 return time
.asctime(self
.value
)
1268 def get_config_as_dict(self
):
1273 def cxx_ini_predecls(cls
, code
):
1274 code('#include <time.h>')
1277 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1278 code('char *_parse_ret = strptime((${src}).c_str(),')
1279 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1280 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1282 # Enumerated types are a little more complex. The user specifies the
1283 # type as Enum(foo) where foo is either a list or dictionary of
1284 # alternatives (typically strings, but not necessarily so). (In the
1285 # long run, the integer value of the parameter will be the list index
1286 # or the corresponding dictionary value. For now, since we only check
1287 # that the alternative is valid and then spit it into a .ini file,
1288 # there's not much point in using the dictionary.)
1290 # What Enum() must do is generate a new type encapsulating the
1291 # provided list/dictionary so that specific values of the parameter
1292 # can be instances of that type. We define two hidden internal
1293 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1294 # derive the new type from the appropriate base class on the fly.
1297 # Metaclass for Enum types
1298 class MetaEnum(MetaParamValue
):
1299 def __new__(mcls
, name
, bases
, dict):
1301 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1302 allEnums
[name
] = cls
1305 def __init__(cls
, name
, bases
, init_dict
):
1306 if 'map' in init_dict
:
1307 if not isinstance(cls
.map, dict):
1308 raise TypeError("Enum-derived class attribute 'map' " \
1309 "must be of type dict")
1310 # build list of value strings from map
1311 cls
.vals
= list(cls
.map.keys())
1313 elif 'vals' in init_dict
:
1314 if not isinstance(cls
.vals
, list):
1315 raise TypeError("Enum-derived class attribute 'vals' " \
1316 "must be of type list")
1317 # build string->value map from vals sequence
1319 for idx
,val
in enumerate(cls
.vals
):
1322 raise TypeError("Enum-derived class must define "\
1323 "attribute 'map' or 'vals'")
1326 cls
.cxx_type
= '%s' % name
1328 cls
.cxx_type
= 'Enums::%s' % name
1330 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1332 # Generate C++ class declaration for this enum type.
1333 # Note that we wrap the enum in a class/struct to act as a namespace,
1334 # so that the enum strings can be brief w/o worrying about collisions.
1335 def cxx_decl(cls
, code
):
1336 wrapper_name
= cls
.wrapper_name
1337 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1338 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1339 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1352 $wrapper $wrapper_name {
1357 for val
in cls
.vals
:
1358 code('$val = ${{cls.map[val]}},')
1359 code('Num_$name = ${{len(cls.vals)}}')
1365 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1367 elif cls
.wrapper_is_struct
:
1368 code('static const char *${name}Strings[Num_${name}];')
1370 code('extern const char *${name}Strings[Num_${name}];')
1372 if not cls
.is_class
:
1377 code('#endif // $idem_macro')
1379 def cxx_def(cls
, code
):
1380 wrapper_name
= cls
.wrapper_name
1381 file_name
= cls
.__name
__
1382 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1384 code('#include "enums/$file_name.hh"')
1385 if cls
.wrapper_is_struct
:
1386 code('const char *${wrapper_name}::${name}Strings'
1391 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1394 code('namespace Enums {')
1396 code('const char *${name}Strings[Num_${name}] =')
1400 for val
in cls
.vals
:
1405 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1407 code('} // namespace $wrapper_name')
1410 def pybind_def(cls
, code
):
1412 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1413 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1415 code('''#include "pybind11/pybind11.h"
1416 #include "pybind11/stl.h"
1418 #include <sim/init.hh>
1420 namespace py = pybind11;
1423 module_init(py::module &m_internal)
1425 py::module m = m_internal.def_submodule("enum_${name}");
1429 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1431 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1435 for val
in cls
.vals
:
1436 code('.value("${val}", ${wrapper_name}::${val})')
1437 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1438 if not cls
.is_class
:
1439 code('.export_values()')
1446 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1449 # Base class for enum types.
1450 @add_metaclass(MetaEnum
)
1451 class Enum(ParamValue
):
1453 cmd_line_settable
= True
1455 # The name of the wrapping namespace or struct
1456 wrapper_name
= 'Enums'
1458 # If true, the enum is wrapped in a struct rather than a namespace
1459 wrapper_is_struct
= False
1463 # If not None, use this as the enum name rather than this class name
1466 def __init__(self
, value
):
1467 if value
not in self
.map:
1468 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1469 % (value
, self
.vals
))
1472 def __call__(self
, value
):
1473 self
.__init
__(value
)
1477 def cxx_predecls(cls
, code
):
1478 code('#include "enums/$0.hh"', cls
.__name
__)
1481 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1482 code('if (false) {')
1483 for elem_name
in cls
.map.keys():
1484 code('} else if (%s == "%s") {' % (src
, elem_name
))
1486 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1487 code('%s = %s::%s;' % (dest
, name
if cls
.is_class
else 'Enums',
1489 code('%s true;' % ret
)
1492 code(' %s false;' % ret
)
1496 import m5
.internal
.params
1497 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1498 return e(self
.map[self
.value
])
1503 # This param will generate a scoped c++ enum and its python bindings.
1504 @add_metaclass(MetaEnum
)
1505 class ScopedEnum(Enum
):
1507 cmd_line_settable
= True
1509 # The name of the wrapping namespace or struct
1512 # If true, the enum is wrapped in a struct rather than a namespace
1513 wrapper_is_struct
= False
1515 # If true, the generated enum is a scoped enum
1518 # If not None, use this as the enum name rather than this class name
1521 # how big does a rounding error need to be before we warn about it?
1522 frequency_tolerance
= 0.001 # 0.1%
1524 class TickParamValue(NumericParamValue
):
1527 cmd_line_settable
= True
1530 def cxx_predecls(cls
, code
):
1531 code('#include "base/types.hh"')
1533 def __call__(self
, value
):
1534 self
.__init
__(value
)
1538 return long(self
.value
)
1541 def cxx_ini_predecls(cls
, code
):
1542 code('#include <sstream>')
1544 # Ticks are expressed in seconds in JSON files and in plain
1545 # Ticks in .ini files. Switch based on a config flag
1547 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1548 code('${ret} to_number(${src}, ${dest});')
1550 class Latency(TickParamValue
):
1553 def __init__(self
, value
):
1554 if isinstance(value
, (Latency
, Clock
)):
1555 self
.ticks
= value
.ticks
1556 self
.value
= value
.value
1557 elif isinstance(value
, Frequency
):
1558 self
.ticks
= value
.ticks
1559 self
.value
= 1.0 / value
.value
1560 elif value
.endswith('t'):
1562 self
.value
= int(value
[:-1])
1565 self
.value
= convert
.toLatency(value
)
1567 def __call__(self
, value
):
1568 self
.__init
__(value
)
1571 def __getattr__(self
, attr
):
1572 if attr
in ('latency', 'period'):
1574 if attr
== 'frequency':
1575 return Frequency(self
)
1576 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1579 if self
.ticks
or self
.value
== 0:
1582 value
= ticks
.fromSeconds(self
.value
)
1585 def config_value(self
):
1586 return self
.getValue()
1588 # convert latency to ticks
1590 return '%d' % self
.getValue()
1592 class Frequency(TickParamValue
):
1595 def __init__(self
, value
):
1596 if isinstance(value
, (Latency
, Clock
)):
1597 if value
.value
== 0:
1600 self
.value
= 1.0 / value
.value
1601 self
.ticks
= value
.ticks
1602 elif isinstance(value
, Frequency
):
1603 self
.value
= value
.value
1604 self
.ticks
= value
.ticks
1607 self
.value
= convert
.toFrequency(value
)
1609 def __call__(self
, value
):
1610 self
.__init
__(value
)
1613 def __getattr__(self
, attr
):
1614 if attr
== 'frequency':
1616 if attr
in ('latency', 'period'):
1617 return Latency(self
)
1618 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1620 # convert latency to ticks
1622 if self
.ticks
or self
.value
== 0:
1625 value
= ticks
.fromSeconds(1.0 / self
.value
)
1628 def config_value(self
):
1629 return self
.getValue()
1632 return '%d' % self
.getValue()
1634 # A generic Frequency and/or Latency value. Value is stored as a
1635 # latency, just like Latency and Frequency.
1636 class Clock(TickParamValue
):
1637 def __init__(self
, value
):
1638 if isinstance(value
, (Latency
, Clock
)):
1639 self
.ticks
= value
.ticks
1640 self
.value
= value
.value
1641 elif isinstance(value
, Frequency
):
1642 self
.ticks
= value
.ticks
1643 self
.value
= 1.0 / value
.value
1644 elif value
.endswith('t'):
1646 self
.value
= int(value
[:-1])
1649 self
.value
= convert
.anyToLatency(value
)
1651 def __call__(self
, value
):
1652 self
.__init
__(value
)
1656 return "%s" % Latency(self
)
1658 def __getattr__(self
, attr
):
1659 if attr
== 'frequency':
1660 return Frequency(self
)
1661 if attr
in ('latency', 'period'):
1662 return Latency(self
)
1663 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1666 return self
.period
.getValue()
1668 def config_value(self
):
1669 return self
.period
.config_value()
1672 return self
.period
.ini_str()
1674 class Voltage(Float
):
1677 def __new__(cls
, value
):
1678 value
= convert
.toVoltage(value
)
1679 return super(cls
, Voltage
).__new
__(cls
, value
)
1681 def __init__(self
, value
):
1682 value
= convert
.toVoltage(value
)
1683 super(Voltage
, self
).__init
__(value
)
1685 class Current(Float
):
1688 def __new__(cls
, value
):
1689 value
= convert
.toCurrent(value
)
1690 return super(cls
, Current
).__new
__(cls
, value
)
1692 def __init__(self
, value
):
1693 value
= convert
.toCurrent(value
)
1694 super(Current
, self
).__init
__(value
)
1696 class Energy(Float
):
1699 def __new__(cls
, value
):
1700 value
= convert
.toEnergy(value
)
1701 return super(cls
, Energy
).__new
__(cls
, value
)
1703 def __init__(self
, value
):
1704 value
= convert
.toEnergy(value
)
1705 super(Energy
, self
).__init
__(value
)
1707 class NetworkBandwidth(float,ParamValue
):
1710 cmd_line_settable
= True
1712 def __new__(cls
, value
):
1713 # convert to bits per second
1714 val
= convert
.toNetworkBandwidth(value
)
1715 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1718 return str(self
.val
)
1720 def __call__(self
, value
):
1721 val
= convert
.toNetworkBandwidth(value
)
1726 # convert to seconds per byte
1727 value
= 8.0 / float(self
)
1728 # convert to ticks per byte
1729 value
= ticks
.fromSeconds(value
)
1733 return '%f' % self
.getValue()
1735 def config_value(self
):
1736 return '%f' % self
.getValue()
1739 def cxx_ini_predecls(cls
, code
):
1740 code('#include <sstream>')
1743 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1744 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1746 class MemoryBandwidth(float,ParamValue
):
1749 cmd_line_settable
= True
1751 def __new__(cls
, value
):
1752 # convert to bytes per second
1753 val
= convert
.toMemoryBandwidth(value
)
1754 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1756 def __call__(self
, value
):
1757 val
= convert
.toMemoryBandwidth(value
)
1762 # convert to seconds per byte
1765 value
= 1.0 / float(self
)
1766 # convert to ticks per byte
1767 value
= ticks
.fromSeconds(value
)
1771 return '%f' % self
.getValue()
1773 def config_value(self
):
1774 return '%f' % self
.getValue()
1777 def cxx_ini_predecls(cls
, code
):
1778 code('#include <sstream>')
1781 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1782 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1785 # "Constants"... handy aliases for various values.
1788 # Special class for NULL pointers. Note the special check in
1789 # make_param_value() above that lets these be assigned where a
1790 # SimObject is required.
1791 # only one copy of a particular node
1792 @add_metaclass(Singleton
)
1793 class NullSimObject(object):
1799 def _instantiate(self
, parent
= None, path
= ''):
1805 def unproxy(self
, base
):
1808 def set_path(self
, parent
, name
):
1811 def set_parent(self
, parent
, name
):
1814 def clear_parent(self
, old_parent
):
1817 def descendants(self
):
1821 def get_config_as_dict(self
):
1827 def config_value(self
):
1833 # The only instance you'll ever need...
1834 NULL
= NullSimObject()
1836 def isNullPointer(value
):
1837 return isinstance(value
, NullSimObject
)
1839 # Some memory range specifications use this as a default upper bound.
1842 AllMemory
= AddrRange(0, MaxAddr
)
1845 #####################################################################
1849 # Ports are used to interconnect objects in the memory system.
1851 #####################################################################
1853 # Port reference: encapsulates a reference to a particular port on a
1854 # particular SimObject.
1855 class PortRef(object):
1856 def __init__(self
, simobj
, name
, role
, is_source
):
1857 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1858 self
.simobj
= simobj
1861 self
.is_source
= is_source
1862 self
.peer
= None # not associated with another port yet
1863 self
.ccConnected
= False # C++ port connection done?
1864 self
.index
= -1 # always -1 for non-vector ports
1867 return '%s.%s' % (self
.simobj
, self
.name
)
1870 # Return the number of connected ports, i.e. 0 is we have no
1871 # peer and 1 if we do.
1872 return int(self
.peer
!= None)
1874 # for config.ini, print peer's name (not ours)
1876 return str(self
.peer
)
1879 def get_config_as_dict(self
):
1880 return {'role' : self
.role
, 'peer' : str(self
.peer
),
1881 'is_source' : str(self
.is_source
)}
1883 def __getattr__(self
, attr
):
1884 if attr
== 'peerObj':
1885 # shorthand for proxies
1886 return self
.peer
.simobj
1887 raise AttributeError("'%s' object has no attribute '%s'" % \
1888 (self
.__class
__.__name
__, attr
))
1890 # Full connection is symmetric (both ways). Called via
1891 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1892 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1893 # e.g., "obj1.portA[3] = obj2.portB".
1894 def connect(self
, other
):
1895 if isinstance(other
, VectorPortRef
):
1896 # reference to plain VectorPort is implicit append
1897 other
= other
._get
_next
()
1898 if self
.peer
and not proxy
.isproxy(self
.peer
):
1899 fatal("Port %s is already connected to %s, cannot connect %s\n",
1900 self
, self
.peer
, other
);
1903 if proxy
.isproxy(other
):
1904 other
.set_param_desc(PortParamDesc())
1906 elif not isinstance(other
, PortRef
):
1907 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1910 if not Port
.is_compat(self
, other
):
1911 fatal("Ports %s and %s with roles '%s' and '%s' "
1912 "are not compatible", self
, other
, self
.role
, other
.role
)
1914 if other
.peer
is not self
:
1917 # Allow a compatible port pair to be spliced between a port and its
1918 # connected peer. Useful operation for connecting instrumentation
1919 # structures into a system when it is necessary to connect the
1920 # instrumentation after the full system has been constructed.
1921 def splice(self
, new_1
, new_2
):
1922 if not self
.peer
or proxy
.isproxy(self
.peer
):
1923 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1925 if not isinstance(new_1
, PortRef
) or not isinstance(new_2
, PortRef
):
1927 "Splicing non-port references '%s','%s' to port '%s'" % \
1928 (new_1
, new_2
, self
))
1930 old_peer
= self
.peer
1932 if Port
.is_compat(old_peer
, new_1
) and Port
.is_compat(self
, new_2
):
1933 old_peer
.peer
= new_1
1934 new_1
.peer
= old_peer
1937 elif Port
.is_compat(old_peer
, new_2
) and Port
.is_compat(self
, new_1
):
1938 old_peer
.peer
= new_2
1939 new_2
.peer
= old_peer
1943 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
1944 "%s(%s) and %s(%s)", self
, self
.role
,
1945 old_peer
, old_peer
.role
, new_1
, new_1
.role
,
1948 def clone(self
, simobj
, memo
):
1951 newRef
= copy
.copy(self
)
1953 newRef
.simobj
= simobj
1954 assert(isSimObject(newRef
.simobj
))
1955 if self
.peer
and not proxy
.isproxy(self
.peer
):
1956 peerObj
= self
.peer
.simobj(_memo
=memo
)
1957 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1958 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1961 def unproxy(self
, simobj
):
1962 assert(simobj
is self
.simobj
)
1963 if proxy
.isproxy(self
.peer
):
1965 realPeer
= self
.peer
.unproxy(self
.simobj
)
1967 print("Error in unproxying port '%s' of %s" %
1968 (self
.name
, self
.simobj
.path()))
1970 self
.connect(realPeer
)
1972 # Call C++ to create corresponding port connection between C++ objects
1973 def ccConnect(self
):
1974 if self
.ccConnected
: # already done this
1978 if not self
.peer
: # nothing to connect to
1981 port
= self
.simobj
.getPort(self
.name
, self
.index
)
1982 peer_port
= peer
.simobj
.getPort(peer
.name
, peer
.index
)
1983 port
.bind(peer_port
)
1985 self
.ccConnected
= True
1987 # A reference to an individual element of a VectorPort... much like a
1988 # PortRef, but has an index.
1989 class VectorPortElementRef(PortRef
):
1990 def __init__(self
, simobj
, name
, role
, is_source
, index
):
1991 PortRef
.__init
__(self
, simobj
, name
, role
, is_source
)
1995 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1997 # A reference to a complete vector-valued port (not just a single element).
1998 # Can be indexed to retrieve individual VectorPortElementRef instances.
1999 class VectorPortRef(object):
2000 def __init__(self
, simobj
, name
, role
, is_source
):
2001 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
2002 self
.simobj
= simobj
2005 self
.is_source
= is_source
2009 return '%s.%s[:]' % (self
.simobj
, self
.name
)
2012 # Return the number of connected peers, corresponding the the
2013 # length of the elements.
2014 return len(self
.elements
)
2016 # for config.ini, print peer's name (not ours)
2018 return ' '.join([el
.ini_str() for el
in self
.elements
])
2021 def get_config_as_dict(self
):
2022 return {'role' : self
.role
,
2023 'peer' : [el
.ini_str() for el
in self
.elements
],
2024 'is_source' : str(self
.is_source
)}
2026 def __getitem__(self
, key
):
2027 if not isinstance(key
, int):
2028 raise TypeError("VectorPort index must be integer")
2029 if key
>= len(self
.elements
):
2030 # need to extend list
2031 ext
= [VectorPortElementRef(
2032 self
.simobj
, self
.name
, self
.role
, self
.is_source
, i
)
2033 for i
in range(len(self
.elements
), key
+1)]
2034 self
.elements
.extend(ext
)
2035 return self
.elements
[key
]
2037 def _get_next(self
):
2038 return self
[len(self
.elements
)]
2040 def __setitem__(self
, key
, value
):
2041 if not isinstance(key
, int):
2042 raise TypeError("VectorPort index must be integer")
2043 self
[key
].connect(value
)
2045 def connect(self
, other
):
2046 if isinstance(other
, (list, tuple)):
2047 # Assign list of port refs to vector port.
2048 # For now, append them... not sure if that's the right semantics
2049 # or if it should replace the current vector.
2051 self
._get
_next
().connect(ref
)
2053 # scalar assignment to plain VectorPort is implicit append
2054 self
._get
_next
().connect(other
)
2056 def clone(self
, simobj
, memo
):
2059 newRef
= copy
.copy(self
)
2061 newRef
.simobj
= simobj
2062 assert(isSimObject(newRef
.simobj
))
2063 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2066 def unproxy(self
, simobj
):
2067 [el
.unproxy(simobj
) for el
in self
.elements
]
2069 def ccConnect(self
):
2070 [el
.ccConnect() for el
in self
.elements
]
2072 # Port description object. Like a ParamDesc object, this represents a
2073 # logical port in the SimObject class, not a particular port on a
2074 # SimObject instance. The latter are represented by PortRef objects.
2076 # Port("role", "description")
2081 def compat(cls
, role
, peer
):
2082 cls
._compat
_dict
.setdefault(role
, set()).add(peer
)
2083 cls
._compat
_dict
.setdefault(peer
, set()).add(role
)
2086 def is_compat(cls
, one
, two
):
2087 for port
in one
, two
:
2088 if not port
.role
in Port
._compat
_dict
:
2089 fatal("Unrecognized role '%s' for port %s\n", port
.role
, port
)
2090 return one
.role
in Port
._compat
_dict
[two
.role
]
2092 def __init__(self
, role
, desc
, is_source
=False):
2095 self
.is_source
= is_source
2097 # Generate a PortRef for this port on the given SimObject with the
2099 def makeRef(self
, simobj
):
2100 return PortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2102 # Connect an instance of this port (on the given SimObject with
2103 # the given name) with the port described by the supplied PortRef
2104 def connect(self
, simobj
, ref
):
2105 self
.makeRef(simobj
).connect(ref
)
2107 # No need for any pre-declarations at the moment as we merely rely
2108 # on an unsigned int.
2109 def cxx_predecls(self
, code
):
2112 def pybind_predecls(self
, code
):
2113 cls
.cxx_predecls(self
, code
)
2115 # Declare an unsigned int with the same name as the port, that
2116 # will eventually hold the number of connected ports (and thus the
2117 # number of elements for a VectorPort).
2118 def cxx_decl(self
, code
):
2119 code('unsigned int port_${{self.name}}_connection_count;')
2121 Port
.compat('GEM5 REQUESTER', 'GEM5 RESPONDER')
2123 class RequestPort(Port
):
2124 # RequestPort("description")
2125 def __init__(self
, desc
):
2126 super(RequestPort
, self
).__init
__(
2127 'GEM5 REQUESTER', desc
, is_source
=True)
2129 class ResponsePort(Port
):
2130 # ResponsePort("description")
2131 def __init__(self
, desc
):
2132 super(ResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2134 # VectorPort description object. Like Port, but represents a vector
2135 # of connections (e.g., as on a XBar).
2136 class VectorPort(Port
):
2137 def makeRef(self
, simobj
):
2138 return VectorPortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2140 class VectorRequestPort(VectorPort
):
2141 # VectorRequestPort("description")
2142 def __init__(self
, desc
):
2143 super(VectorRequestPort
, self
).__init
__(
2144 'GEM5 REQUESTER', desc
, is_source
=True)
2146 class VectorResponsePort(VectorPort
):
2147 # VectorResponsePort("description")
2148 def __init__(self
, desc
):
2149 super(VectorResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2151 # Old names, maintained for compatibility.
2152 MasterPort
= RequestPort
2153 SlavePort
= ResponsePort
2154 VectorMasterPort
= VectorRequestPort
2155 VectorSlavePort
= VectorResponsePort
2157 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2158 # proxy objects (via set_param_desc()) so that proxy error messages
2160 @add_metaclass(Singleton
)
2161 class PortParamDesc(object):
2165 baseEnums
= allEnums
.copy()
2166 baseParams
= allParams
.copy()
2169 global allEnums
, allParams
2171 allEnums
= baseEnums
.copy()
2172 allParams
= baseParams
.copy()
2174 __all__
= ['Param', 'VectorParam',
2175 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2176 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2177 'Int32', 'UInt32', 'Int64', 'UInt64',
2178 'Counter', 'Addr', 'Tick', 'Percent',
2179 'TcpPort', 'UdpPort', 'EthernetAddr',
2180 'IpAddress', 'IpNetmask', 'IpWithPort',
2181 'MemorySize', 'MemorySize32',
2182 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2183 'NetworkBandwidth', 'MemoryBandwidth',
2185 'MaxAddr', 'MaxTick', 'AllMemory',
2187 'NextEthernetAddr', 'NULL',
2188 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2189 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2190 'VectorMasterPort', 'VectorSlavePort']