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 # Authors: Steve Reinhardt
45 #####################################################################
47 # Parameter description classes
49 # The _params dictionary in each class maps parameter names to either
50 # a Param or a VectorParam object. These objects contain the
51 # parameter description string, the parameter type, and the default
52 # value (if any). The convert() method on these objects is used to
53 # force whatever value is assigned to the parameter to the appropriate
56 # Note that the default values are loaded into the class's attribute
57 # space when the parameter dictionary is initialized (in
58 # MetaSimObject._new_param()); after that point they aren't used.
60 #####################################################################
62 from __future__
import print_function
78 def isSimObject(*args
, **kwargs
):
79 from . import SimObject
80 return SimObject
.isSimObject(*args
, **kwargs
)
82 def isSimObjectSequence(*args
, **kwargs
):
83 from . import SimObject
84 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
86 def isSimObjectClass(*args
, **kwargs
):
87 from . import SimObject
88 return SimObject
.isSimObjectClass(*args
, **kwargs
)
92 class MetaParamValue(type):
93 def __new__(mcls
, name
, bases
, dct
):
94 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
95 assert name
not in allParams
100 # Dummy base class to identify types that are legitimate for SimObject
102 class ParamValue(object):
103 __metaclass__
= MetaParamValue
104 cmd_line_settable
= False
106 # Generate the code needed as a prerequisite for declaring a C++
107 # object of this type. Typically generates one or more #include
108 # statements. Used when declaring parameters of this type.
110 def cxx_predecls(cls
, code
):
114 def pybind_predecls(cls
, code
):
115 cls
.cxx_predecls(code
)
117 # default for printing to .ini file is regular string conversion.
118 # will be overridden in some cases
122 # default for printing to .json file is regular string conversion.
123 # will be overridden in some cases, mostly to use native Python
124 # types where there are similar JSON types
125 def config_value(self
):
128 # Prerequisites for .ini parsing with cxx_ini_parse
130 def cxx_ini_predecls(cls
, code
):
133 # parse a .ini file entry for this param from string expression
134 # src into lvalue dest (of the param's C++ type)
136 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
137 code('// Unhandled param type: %s' % cls
.__name
__)
138 code('%s false;' % ret
)
140 # allows us to blithely call unproxy() on things without checking
141 # if they're really proxies or not
142 def unproxy(self
, base
):
145 # Produce a human readable version of the stored value
146 def pretty_print(self
, value
):
149 # Regular parameter description.
150 class ParamDesc(object):
151 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
152 self
.ptype_str
= ptype_str
153 # remember ptype only if it is provided
161 self
.default
= args
[0]
164 raise TypeError('too many arguments')
167 assert(not hasattr(self
, 'desc'))
168 self
.desc
= kwargs
['desc']
171 if 'default' in kwargs
:
172 assert(not hasattr(self
, 'default'))
173 self
.default
= kwargs
['default']
174 del kwargs
['default']
177 raise TypeError('extra unknown kwargs %s' % kwargs
)
179 if not hasattr(self
, 'desc'):
180 raise TypeError('desc attribute missing')
182 def __getattr__(self
, attr
):
184 from . import SimObject
185 ptype
= SimObject
.allClasses
[self
.ptype_str
]
186 assert isSimObjectClass(ptype
)
190 raise AttributeError("'%s' object has no attribute '%s'" % \
191 (type(self
).__name
__, attr
))
193 def example_str(self
):
194 if hasattr(self
.ptype
, "ex_str"):
195 return self
.ptype
.ex_str
197 return self
.ptype_str
199 # Is the param available to be exposed on the command line
200 def isCmdLineSettable(self
):
201 if hasattr(self
.ptype
, "cmd_line_settable"):
202 return self
.ptype
.cmd_line_settable
206 def convert(self
, value
):
207 if isinstance(value
, proxy
.BaseProxy
):
208 value
.set_param_desc(self
)
210 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
211 # deferred evaluation of SimObject; continue to defer if
212 # we're just assigning a null pointer
214 if isinstance(value
, self
.ptype
):
216 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
218 return self
.ptype(value
)
220 def pretty_print(self
, value
):
221 if isinstance(value
, proxy
.BaseProxy
):
223 if isNullPointer(value
):
225 return self
.ptype(value
).pretty_print(value
)
227 def cxx_predecls(self
, code
):
228 code('#include <cstddef>')
229 self
.ptype
.cxx_predecls(code
)
231 def pybind_predecls(self
, code
):
232 self
.ptype
.pybind_predecls(code
)
234 def cxx_decl(self
, code
):
235 code('${{self.ptype.cxx_type}} ${{self.name}};')
237 # Vector-valued parameter description. Just like ParamDesc, except
238 # that the value is a vector (list) of the specified type instead of a
241 class VectorParamValue(list):
242 __metaclass__
= MetaParamValue
243 def __setattr__(self
, attr
, value
):
244 raise AttributeError("Not allowed to set %s on '%s'" % \
245 (attr
, type(self
).__name
__))
247 def config_value(self
):
248 return [v
.config_value() for v
in self
]
251 return ' '.join([v
.ini_str() for v
in self
])
254 return [ v
.getValue() for v
in self
]
256 def unproxy(self
, base
):
257 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
258 # The value is a proxy (e.g. Parent.any, Parent.all or
259 # Parent.x) therefore try resolve it
260 return self
[0].unproxy(base
)
262 return [v
.unproxy(base
) for v
in self
]
264 class SimObjectVector(VectorParamValue
):
265 # support clone operation
266 def __call__(self
, **kwargs
):
267 return SimObjectVector([v(**kwargs
) for v
in self
])
269 def clear_parent(self
, old_parent
):
271 v
.clear_parent(old_parent
)
273 def set_parent(self
, parent
, name
):
275 self
[0].set_parent(parent
, name
)
277 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
278 for i
,v
in enumerate(self
):
279 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
281 def has_parent(self
):
282 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
284 # return 'cpu0 cpu1' etc. for print_ini()
286 return ' '.join([v
._name
for v
in self
])
288 # By iterating through the constituent members of the vector here
289 # we can nicely handle iterating over all a SimObject's children
290 # without having to provide lots of special functions on
291 # SimObjectVector directly.
292 def descendants(self
):
294 for obj
in v
.descendants():
297 def get_config_as_dict(self
):
300 a
.append(v
.get_config_as_dict())
303 # If we are replacing an item in the vector, make sure to set the
304 # parent reference of the new SimObject to be the same as the parent
305 # of the SimObject being replaced. Useful to have if we created
306 # a SimObjectVector of temporary objects that will be modified later in
307 # configuration scripts.
308 def __setitem__(self
, key
, value
):
310 if value
.has_parent():
311 warn("SimObject %s already has a parent" % value
.get_name() +\
312 " that is being overwritten by a SimObjectVector")
313 value
.set_parent(val
.get_parent(), val
._name
)
314 super(SimObjectVector
, self
).__setitem
__(key
, value
)
316 # Enumerate the params of each member of the SimObject vector. Creates
317 # strings that will allow indexing into the vector by the python code and
318 # allow it to be specified on the command line.
319 def enumerateParams(self
, flags_dict
= {},
322 if hasattr(self
, "_paramEnumed"):
323 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
327 # Each entry in the SimObjectVector should be an
328 # instance of a SimObject
329 flags_dict
= vals
.enumerateParams(flags_dict
,
330 cmd_line_str
+ "%d." % x
,
331 access_str
+ "[%d]." % x
)
336 class VectorParamDesc(ParamDesc
):
337 # Convert assigned value to appropriate type. If the RHS is not a
338 # list or tuple, it generates a single-element list.
339 def convert(self
, value
):
340 if isinstance(value
, (list, tuple)):
341 # list: coerce each element into new list
342 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
343 elif isinstance(value
, str):
344 # If input is a csv string
345 tmp_list
= [ ParamDesc
.convert(self
, v
) \
346 for v
in value
.strip('[').strip(']').split(',') ]
348 # singleton: coerce to a single-element list
349 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
351 if isSimObjectSequence(tmp_list
):
352 return SimObjectVector(tmp_list
)
354 return VectorParamValue(tmp_list
)
356 # Produce a human readable example string that describes
357 # how to set this vector parameter in the absence of a default
359 def example_str(self
):
360 s
= super(VectorParamDesc
, self
).example_str()
361 help_str
= "[" + s
+ "," + s
+ ", ...]"
364 # Produce a human readable representation of the value of this vector param.
365 def pretty_print(self
, value
):
366 if isinstance(value
, (list, tuple)):
367 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
368 elif isinstance(value
, str):
369 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
371 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
375 # This is a helper function for the new config system
376 def __call__(self
, value
):
377 if isinstance(value
, (list, tuple)):
378 # list: coerce each element into new list
379 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
380 elif isinstance(value
, str):
381 # If input is a csv string
382 tmp_list
= [ ParamDesc
.convert(self
, v
) \
383 for v
in value
.strip('[').strip(']').split(',') ]
385 # singleton: coerce to a single-element list
386 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
388 return VectorParamValue(tmp_list
)
390 def cxx_predecls(self
, code
):
391 code('#include <vector>')
392 self
.ptype
.cxx_predecls(code
)
394 def pybind_predecls(self
, code
):
395 code('#include <vector>')
396 self
.ptype
.pybind_predecls(code
)
398 def cxx_decl(self
, code
):
399 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
401 class ParamFactory(object):
402 def __init__(self
, param_desc_class
, ptype_str
= None):
403 self
.param_desc_class
= param_desc_class
404 self
.ptype_str
= ptype_str
406 def __getattr__(self
, attr
):
408 attr
= self
.ptype_str
+ '.' + attr
409 return ParamFactory(self
.param_desc_class
, attr
)
411 # E.g., Param.Int(5, "number of widgets")
412 def __call__(self
, *args
, **kwargs
):
415 ptype
= allParams
[self
.ptype_str
]
417 # if name isn't defined yet, assume it's a SimObject, and
418 # try to resolve it later
420 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
422 Param
= ParamFactory(ParamDesc
)
423 VectorParam
= ParamFactory(VectorParamDesc
)
425 #####################################################################
429 # Though native Python types could be used to specify parameter types
430 # (the 'ptype' field of the Param and VectorParam classes), it's more
431 # flexible to define our own set of types. This gives us more control
432 # over how Python expressions are converted to values (via the
433 # __init__() constructor) and how these values are printed out (via
434 # the __str__() conversion method).
436 #####################################################################
438 # String-valued parameter. Just mixin the ParamValue class with the
439 # built-in str class.
440 class String(ParamValue
,str):
441 cxx_type
= 'std::string'
442 cmd_line_settable
= True
445 def cxx_predecls(self
, code
):
446 code('#include <string>')
448 def __call__(self
, value
):
453 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
454 code('%s = %s;' % (dest
, src
))
455 code('%s true;' % ret
)
460 # superclass for "numeric" parameter values, to emulate math
461 # operations in a type-safe way. e.g., a Latency times an int returns
462 # a new Latency object.
463 class NumericParamValue(ParamValue
):
466 return v
.value
if isinstance(v
, NumericParamValue
) else v
469 return str(self
.value
)
472 return float(self
.value
)
475 return long(self
.value
)
478 return int(self
.value
)
480 # hook for bounds checking
484 def __mul__(self
, other
):
485 newobj
= self
.__class
__(self
)
486 newobj
.value
*= NumericParamValue
.unwrap(other
)
492 def __truediv__(self
, other
):
493 newobj
= self
.__class
__(self
)
494 newobj
.value
/= NumericParamValue
.unwrap(other
)
498 def __floordiv__(self
, other
):
499 newobj
= self
.__class
__(self
)
500 newobj
.value
//= NumericParamValue
.unwrap(other
)
505 def __add__(self
, other
):
506 newobj
= self
.__class
__(self
)
507 newobj
.value
+= NumericParamValue
.unwrap(other
)
511 def __sub__(self
, other
):
512 newobj
= self
.__class
__(self
)
513 newobj
.value
-= NumericParamValue
.unwrap(other
)
517 def __iadd__(self
, other
):
518 self
.value
+= NumericParamValue
.unwrap(other
)
522 def __isub__(self
, other
):
523 self
.value
-= NumericParamValue
.unwrap(other
)
527 def __imul__(self
, other
):
528 self
.value
*= NumericParamValue
.unwrap(other
)
532 def __itruediv__(self
, other
):
533 self
.value
/= NumericParamValue
.unwrap(other
)
537 def __ifloordiv__(self
, other
):
538 self
.value
//= NumericParamValue
.unwrap(other
)
542 def __lt__(self
, other
):
543 return self
.value
< NumericParamValue
.unwrap(other
)
545 # Python 2.7 pre __future__.division operators
546 # TODO: Remove these when after "import division from __future__"
547 __div__
= __truediv__
548 __idiv__
= __itruediv__
550 def config_value(self
):
554 def cxx_ini_predecls(cls
, code
):
555 # Assume that base/str.hh will be included anyway
556 # code('#include "base/str.hh"')
559 # The default for parsing PODs from an .ini entry is to extract from an
560 # istringstream and let overloading choose the right type according to
563 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
564 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
566 # Metaclass for bounds-checked integer parameters. See CheckedInt.
567 class CheckedIntType(MetaParamValue
):
568 def __init__(cls
, name
, bases
, dict):
569 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
571 # CheckedInt is an abstract base class, so we actually don't
572 # want to do any processing on it... the rest of this code is
573 # just for classes that derive from CheckedInt.
574 if name
== 'CheckedInt':
577 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
578 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
579 panic("CheckedInt subclass %s must define either\n" \
580 " 'min' and 'max' or 'size' and 'unsigned'\n",
584 cls
.max = 2 ** cls
.size
- 1
586 cls
.min = -(2 ** (cls
.size
- 1))
587 cls
.max = (2 ** (cls
.size
- 1)) - 1
589 # Abstract superclass for bounds-checked integer parameters. This
590 # class is subclassed to generate parameter classes with specific
591 # bounds. Initialization of the min and max bounds is done in the
592 # metaclass CheckedIntType.__init__.
593 class CheckedInt(NumericParamValue
):
594 __metaclass__
= CheckedIntType
595 cmd_line_settable
= True
598 if not self
.min <= self
.value
<= self
.max:
599 raise TypeError('Integer param out of bounds %d < %d < %d' % \
600 (self
.min, self
.value
, self
.max))
602 def __init__(self
, value
):
603 if isinstance(value
, str):
604 self
.value
= convert
.toInteger(value
)
605 elif isinstance(value
, (int, long, float, NumericParamValue
)):
606 self
.value
= long(value
)
608 raise TypeError("Can't convert object of type %s to CheckedInt" \
609 % type(value
).__name
__)
612 def __call__(self
, value
):
617 return int(self
.value
)
620 def cxx_predecls(cls
, code
):
621 # most derived types require this, so we just do it here once
622 code('#include "base/types.hh"')
625 return long(self
.value
)
627 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
628 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
630 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
631 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
632 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
633 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
634 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
635 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
636 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
637 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
639 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
640 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
641 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
642 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
644 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
646 class Cycles(CheckedInt
):
652 from _m5
.core
import Cycles
653 return Cycles(self
.value
)
656 def cxx_ini_predecls(cls
, code
):
657 # Assume that base/str.hh will be included anyway
658 # code('#include "base/str.hh"')
662 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
663 code('uint64_t _temp;')
664 code('bool _ret = to_number(%s, _temp);' % src
)
666 code(' %s = Cycles(_temp);' % dest
)
667 code('%s _ret;' % ret
)
669 class Float(ParamValue
, float):
671 cmd_line_settable
= True
673 def __init__(self
, value
):
674 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
675 self
.value
= float(value
)
677 raise TypeError("Can't convert object of type %s to Float" \
678 % type(value
).__name
__)
680 def __call__(self
, value
):
685 return float(self
.value
)
687 def config_value(self
):
691 def cxx_ini_predecls(cls
, code
):
692 code('#include <sstream>')
695 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
696 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
698 class MemorySize(CheckedInt
):
699 cxx_type
= 'uint64_t'
703 def __init__(self
, value
):
704 if isinstance(value
, MemorySize
):
705 self
.value
= value
.value
707 self
.value
= convert
.toMemorySize(value
)
710 class MemorySize32(CheckedInt
):
711 cxx_type
= 'uint32_t'
715 def __init__(self
, value
):
716 if isinstance(value
, MemorySize
):
717 self
.value
= value
.value
719 self
.value
= convert
.toMemorySize(value
)
722 class Addr(CheckedInt
):
726 def __init__(self
, value
):
727 if isinstance(value
, Addr
):
728 self
.value
= value
.value
731 # Often addresses are referred to with sizes. Ex: A device
732 # base address is at "512MB". Use toMemorySize() to convert
733 # these into addresses. If the address is not specified with a
734 # "size", an exception will occur and numeric translation will
736 self
.value
= convert
.toMemorySize(value
)
737 except (TypeError, ValueError):
738 # Convert number to string and use long() to do automatic
739 # base conversion (requires base=0 for auto-conversion)
740 self
.value
= long(str(value
), base
=0)
743 def __add__(self
, other
):
744 if isinstance(other
, Addr
):
745 return self
.value
+ other
.value
747 return self
.value
+ other
748 def pretty_print(self
, value
):
750 val
= convert
.toMemorySize(value
)
753 return "0x%x" % long(val
)
755 class AddrRange(ParamValue
):
756 cxx_type
= 'AddrRange'
758 def __init__(self
, *args
, **kwargs
):
759 # Disable interleaving and hashing by default
760 self
.intlvHighBit
= 0
766 def handle_kwargs(self
, kwargs
):
767 # An address range needs to have an upper limit, specified
768 # either explicitly with an end, or as an offset using the
771 self
.end
= Addr(kwargs
.pop('end'))
772 elif 'size' in kwargs
:
773 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
775 raise TypeError("Either end or size must be specified")
777 # Now on to the optional bit
778 if 'intlvMatch' in kwargs
:
779 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
781 if 'masks' in kwargs
:
782 self
.masks
= [ long(x
) for x
in list(kwargs
.pop('masks')) ]
783 self
.intlvBits
= len(self
.masks
)
785 if 'intlvHighBit' in kwargs
:
786 intlv_high_bit
= int(kwargs
.pop('intlvHighBit'))
787 if 'xorHighBit' in kwargs
:
788 xor_high_bit
= int(kwargs
.pop('xorHighBit'))
789 if 'intlvBits' in kwargs
:
790 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
791 self
.masks
= [0] * self
.intlvBits
792 for i
in range(0, self
.intlvBits
):
793 bit1
= intlv_high_bit
- i
795 if xor_high_bit
!= 0:
796 bit2
= xor_high_bit
- i
798 self
.masks
[self
.intlvBits
- i
- 1] = mask
801 self
.start
= Addr(kwargs
.pop('start'))
802 handle_kwargs(self
, kwargs
)
806 self
.start
= Addr(args
[0])
807 handle_kwargs(self
, kwargs
)
808 elif isinstance(args
[0], (list, tuple)):
809 self
.start
= Addr(args
[0][0])
810 self
.end
= Addr(args
[0][1])
813 self
.end
= Addr(args
[0]) - 1
816 self
.start
= Addr(args
[0])
817 self
.end
= Addr(args
[1])
819 raise TypeError("Too many arguments specified")
822 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
825 if len(self
.masks
) == 0:
826 return '%s:%s' % (self
.start
, self
.end
)
828 return '%s:%s:%s:%s' % (self
.start
, self
.end
, self
.intlvMatch
,
829 ':'.join(str(m
) for m
in self
.masks
))
832 # Divide the size by the size of the interleaving slice
833 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
836 def cxx_predecls(cls
, code
):
837 Addr
.cxx_predecls(code
)
838 code('#include "base/addr_range.hh"')
841 def pybind_predecls(cls
, code
):
842 Addr
.pybind_predecls(code
)
843 code('#include "base/addr_range.hh"')
846 def cxx_ini_predecls(cls
, code
):
847 code('#include <sstream>')
848 code('#include <vector>')
849 code('#include "base/types.hh"')
852 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
853 code('bool _ret = true;')
854 code('uint64_t _start, _end, _intlvMatch = 0;')
855 code('std::vector<Addr> _masks;')
857 code('std::istringstream _stream(${src});')
858 code('_stream >> _start;')
859 code('_stream.get(_sep);')
860 code('_ret = _sep == \':\';')
861 code('_stream >> _end;')
862 code('if (!_stream.fail() && !_stream.eof()) {')
863 code(' _stream.get(_sep);')
864 code(' _ret = ret && _sep == \':\';')
865 code(' _stream >> _intlvMatch;')
866 code(' while (!_stream.fail() && !_stream.eof()) {')
867 code(' _stream.get(_sep);')
868 code(' _ret = ret && _sep == \':\';')
870 code(' _stream >> mask;')
871 code(' _masks.push_back(mask);')
874 code('_ret = _ret && !_stream.fail() && _stream.eof();')
876 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
880 # Go from the Python class to the wrapped C++ class
881 from _m5
.range import AddrRange
883 return AddrRange(long(self
.start
), long(self
.end
),
884 self
.masks
, int(self
.intlvMatch
))
886 # Boolean parameter type. Python doesn't let you subclass bool, since
887 # it doesn't want to let you create multiple instances of True and
888 # False. Thus this is a little more complicated than String.
889 class Bool(ParamValue
):
891 cmd_line_settable
= True
893 def __init__(self
, value
):
895 self
.value
= convert
.toBool(value
)
897 self
.value
= bool(value
)
899 def __call__(self
, value
):
904 return bool(self
.value
)
907 return str(self
.value
)
909 # implement truth value testing for Bool parameters so that these params
910 # evaluate correctly during the python configuration phase
912 return bool(self
.value
)
914 # Python 2.7 uses __nonzero__ instead of __bool__
915 __nonzero__
= __bool__
922 def config_value(self
):
926 def cxx_ini_predecls(cls
, code
):
927 # Assume that base/str.hh will be included anyway
928 # code('#include "base/str.hh"')
932 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
933 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
935 def IncEthernetAddr(addr
, val
= 1):
936 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
938 for i
in (5, 4, 3, 2, 1):
939 val
,rem
= divmod(bytes
[i
], 256)
944 assert(bytes
[0] <= 255)
945 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
947 _NextEthernetAddr
= "00:90:00:00:00:01"
948 def NextEthernetAddr():
949 global _NextEthernetAddr
951 value
= _NextEthernetAddr
952 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
955 class EthernetAddr(ParamValue
):
956 cxx_type
= 'Net::EthAddr'
957 ex_str
= "00:90:00:00:00:01"
958 cmd_line_settable
= True
961 def cxx_predecls(cls
, code
):
962 code('#include "base/inet.hh"')
964 def __init__(self
, value
):
965 if value
== NextEthernetAddr
:
969 if not isinstance(value
, str):
970 raise TypeError("expected an ethernet address and didn't get one")
972 bytes
= value
.split(':')
974 raise TypeError('invalid ethernet address %s' % value
)
977 if not 0 <= int(byte
, base
=16) <= 0xff:
978 raise TypeError('invalid ethernet address %s' % value
)
982 def __call__(self
, value
):
986 def unproxy(self
, base
):
987 if self
.value
== NextEthernetAddr
:
988 return EthernetAddr(self
.value())
992 from _m5
.net
import EthAddr
993 return EthAddr(self
.value
)
1002 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1003 code('%s = Net::EthAddr(%s);' % (dest
, src
))
1004 code('%s true;' % ret
)
1006 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1007 # the form "a.b.c.d", or an integer representing an IP.
1008 class IpAddress(ParamValue
):
1009 cxx_type
= 'Net::IpAddress'
1010 ex_str
= "127.0.0.1"
1011 cmd_line_settable
= True
1014 def cxx_predecls(cls
, code
):
1015 code('#include "base/inet.hh"')
1017 def __init__(self
, value
):
1018 if isinstance(value
, IpAddress
):
1022 self
.ip
= convert
.toIpAddress(value
)
1024 self
.ip
= long(value
)
1027 def __call__(self
, value
):
1028 self
.__init
__(value
)
1032 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1033 return '%d.%d.%d.%d' % tuple(tup
)
1035 def __eq__(self
, other
):
1036 if isinstance(other
, IpAddress
):
1037 return self
.ip
== other
.ip
1038 elif isinstance(other
, str):
1040 return self
.ip
== convert
.toIpAddress(other
)
1044 return self
.ip
== other
1046 def __ne__(self
, other
):
1047 return not (self
== other
)
1050 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1051 raise TypeError("invalid ip address %#08x" % self
.ip
)
1054 from _m5
.net
import IpAddress
1055 return IpAddress(self
.ip
)
1057 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1058 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1059 # positional or keyword arguments.
1060 class IpNetmask(IpAddress
):
1061 cxx_type
= 'Net::IpNetmask'
1062 ex_str
= "127.0.0.0/24"
1063 cmd_line_settable
= True
1066 def cxx_predecls(cls
, code
):
1067 code('#include "base/inet.hh"')
1069 def __init__(self
, *args
, **kwargs
):
1070 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1072 setattr(self
, key
, kwargs
.pop(key
))
1074 setattr(self
, key
, elseVal
)
1076 raise TypeError("No value set for %s" % key
)
1079 handle_kwarg(self
, kwargs
, 'ip')
1080 handle_kwarg(self
, kwargs
, 'netmask')
1082 elif len(args
) == 1:
1084 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1085 raise TypeError("Invalid arguments")
1086 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1087 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1088 elif isinstance(args
[0], IpNetmask
):
1089 self
.ip
= args
[0].ip
1090 self
.netmask
= args
[0].netmask
1092 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1094 elif len(args
) == 2:
1096 self
.netmask
= args
[1]
1098 raise TypeError("Too many arguments specified")
1101 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1105 def __call__(self
, value
):
1106 self
.__init
__(value
)
1110 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1112 def __eq__(self
, other
):
1113 if isinstance(other
, IpNetmask
):
1114 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1115 elif isinstance(other
, str):
1117 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1125 if self
.netmask
< 0 or self
.netmask
> 32:
1126 raise TypeError("invalid netmask %d" % netmask
)
1129 from _m5
.net
import IpNetmask
1130 return IpNetmask(self
.ip
, self
.netmask
)
1132 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1133 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1134 class IpWithPort(IpAddress
):
1135 cxx_type
= 'Net::IpWithPort'
1136 ex_str
= "127.0.0.1:80"
1137 cmd_line_settable
= True
1140 def cxx_predecls(cls
, code
):
1141 code('#include "base/inet.hh"')
1143 def __init__(self
, *args
, **kwargs
):
1144 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1146 setattr(self
, key
, kwargs
.pop(key
))
1148 setattr(self
, key
, elseVal
)
1150 raise TypeError("No value set for %s" % key
)
1153 handle_kwarg(self
, kwargs
, 'ip')
1154 handle_kwarg(self
, kwargs
, 'port')
1156 elif len(args
) == 1:
1158 if not 'ip' in kwargs
and not 'port' in kwargs
:
1159 raise TypeError("Invalid arguments")
1160 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1161 handle_kwarg(self
, kwargs
, 'port', args
[0])
1162 elif isinstance(args
[0], IpWithPort
):
1163 self
.ip
= args
[0].ip
1164 self
.port
= args
[0].port
1166 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1168 elif len(args
) == 2:
1172 raise TypeError("Too many arguments specified")
1175 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1179 def __call__(self
, value
):
1180 self
.__init
__(value
)
1184 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1186 def __eq__(self
, other
):
1187 if isinstance(other
, IpWithPort
):
1188 return self
.ip
== other
.ip
and self
.port
== other
.port
1189 elif isinstance(other
, str):
1191 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1199 if self
.port
< 0 or self
.port
> 0xffff:
1200 raise TypeError("invalid port %d" % self
.port
)
1203 from _m5
.net
import IpWithPort
1204 return IpWithPort(self
.ip
, self
.port
)
1206 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1207 "%a %b %d %H:%M:%S %Y",
1208 "%Y/%m/%d %H:%M:%S",
1211 "%m/%d/%Y %H:%M:%S",
1214 "%m/%d/%y %H:%M:%S",
1219 def parse_time(value
):
1220 from time
import gmtime
, strptime
, struct_time
, time
1221 from datetime
import datetime
, date
1223 if isinstance(value
, struct_time
):
1226 if isinstance(value
, (int, long)):
1227 return gmtime(value
)
1229 if isinstance(value
, (datetime
, date
)):
1230 return value
.timetuple()
1232 if isinstance(value
, str):
1233 if value
in ('Now', 'Today'):
1234 return time
.gmtime(time
.time())
1236 for format
in time_formats
:
1238 return strptime(value
, format
)
1242 raise ValueError("Could not parse '%s' as a time" % value
)
1244 class Time(ParamValue
):
1248 def cxx_predecls(cls
, code
):
1249 code('#include <time.h>')
1251 def __init__(self
, value
):
1252 self
.value
= parse_time(value
)
1254 def __call__(self
, value
):
1255 self
.__init
__(value
)
1259 from _m5
.core
import tm
1262 return tm
.gmtime(calendar
.timegm(self
.value
))
1265 return time
.asctime(self
.value
)
1270 def get_config_as_dict(self
):
1275 def cxx_ini_predecls(cls
, code
):
1276 code('#include <time.h>')
1279 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1280 code('char *_parse_ret = strptime((${src}).c_str(),')
1281 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1282 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1284 # Enumerated types are a little more complex. The user specifies the
1285 # type as Enum(foo) where foo is either a list or dictionary of
1286 # alternatives (typically strings, but not necessarily so). (In the
1287 # long run, the integer value of the parameter will be the list index
1288 # or the corresponding dictionary value. For now, since we only check
1289 # that the alternative is valid and then spit it into a .ini file,
1290 # there's not much point in using the dictionary.)
1292 # What Enum() must do is generate a new type encapsulating the
1293 # provided list/dictionary so that specific values of the parameter
1294 # can be instances of that type. We define two hidden internal
1295 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1296 # derive the new type from the appropriate base class on the fly.
1299 # Metaclass for Enum types
1300 class MetaEnum(MetaParamValue
):
1301 def __new__(mcls
, name
, bases
, dict):
1302 assert name
not in allEnums
1304 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1305 allEnums
[name
] = cls
1308 def __init__(cls
, name
, bases
, init_dict
):
1309 if 'map' in init_dict
:
1310 if not isinstance(cls
.map, dict):
1311 raise TypeError("Enum-derived class attribute 'map' " \
1312 "must be of type dict")
1313 # build list of value strings from map
1314 cls
.vals
= list(cls
.map.keys())
1316 elif 'vals' in init_dict
:
1317 if not isinstance(cls
.vals
, list):
1318 raise TypeError("Enum-derived class attribute 'vals' " \
1319 "must be of type list")
1320 # build string->value map from vals sequence
1322 for idx
,val
in enumerate(cls
.vals
):
1325 raise TypeError("Enum-derived class must define "\
1326 "attribute 'map' or 'vals'")
1329 cls
.cxx_type
= '%s' % name
1331 cls
.cxx_type
= 'Enums::%s' % name
1333 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1335 # Generate C++ class declaration for this enum type.
1336 # Note that we wrap the enum in a class/struct to act as a namespace,
1337 # so that the enum strings can be brief w/o worrying about collisions.
1338 def cxx_decl(cls
, code
):
1339 wrapper_name
= cls
.wrapper_name
1340 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1341 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1342 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1355 $wrapper $wrapper_name {
1360 for val
in cls
.vals
:
1361 code('$val = ${{cls.map[val]}},')
1362 code('Num_$name = ${{len(cls.vals)}}')
1368 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1370 elif cls
.wrapper_is_struct
:
1371 code('static const char *${name}Strings[Num_${name}];')
1373 code('extern const char *${name}Strings[Num_${name}];')
1375 if not cls
.is_class
:
1380 code('#endif // $idem_macro')
1382 def cxx_def(cls
, code
):
1383 wrapper_name
= cls
.wrapper_name
1384 file_name
= cls
.__name
__
1385 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1387 code('#include "enums/$file_name.hh"')
1388 if cls
.wrapper_is_struct
:
1389 code('const char *${wrapper_name}::${name}Strings'
1394 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1397 code('namespace Enums {')
1399 code('const char *${name}Strings[Num_${name}] =')
1403 for val
in cls
.vals
:
1408 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1410 code('} // namespace $wrapper_name')
1413 def pybind_def(cls
, code
):
1415 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1416 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1418 code('''#include "pybind11/pybind11.h"
1419 #include "pybind11/stl.h"
1421 #include <sim/init.hh>
1423 namespace py = pybind11;
1426 module_init(py::module &m_internal)
1428 py::module m = m_internal.def_submodule("enum_${name}");
1432 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1434 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1438 for val
in cls
.vals
:
1439 code('.value("${val}", ${wrapper_name}::${val})')
1440 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1441 code('.export_values()')
1448 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1451 # Base class for enum types.
1452 class Enum(ParamValue
):
1453 __metaclass__
= MetaEnum
1455 cmd_line_settable
= True
1457 # The name of the wrapping namespace or struct
1458 wrapper_name
= 'Enums'
1460 # If true, the enum is wrapped in a struct rather than a namespace
1461 wrapper_is_struct
= False
1465 # If not None, use this as the enum name rather than this class name
1468 def __init__(self
, value
):
1469 if value
not in self
.map:
1470 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1471 % (value
, self
.vals
))
1474 def __call__(self
, value
):
1475 self
.__init
__(value
)
1479 def cxx_predecls(cls
, code
):
1480 code('#include "enums/$0.hh"', cls
.__name
__)
1483 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1484 code('if (false) {')
1485 for elem_name
in cls
.map.keys():
1486 code('} else if (%s == "%s") {' % (src
, elem_name
))
1488 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1489 code('%s = %s::%s;' % (dest
, name
if cls
.is_class
else 'Enums',
1491 code('%s true;' % ret
)
1494 code(' %s false;' % ret
)
1498 import m5
.internal
.params
1499 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1500 return e(self
.map[self
.value
])
1505 # This param will generate a scoped c++ enum and its python bindings.
1506 class ScopedEnum(Enum
):
1507 __metaclass__
= MetaEnum
1509 cmd_line_settable
= True
1511 # The name of the wrapping namespace or struct
1514 # If true, the enum is wrapped in a struct rather than a namespace
1515 wrapper_is_struct
= False
1517 # If true, the generated enum is a scoped enum
1520 # If not None, use this as the enum name rather than this class name
1523 # how big does a rounding error need to be before we warn about it?
1524 frequency_tolerance
= 0.001 # 0.1%
1526 class TickParamValue(NumericParamValue
):
1529 cmd_line_settable
= True
1532 def cxx_predecls(cls
, code
):
1533 code('#include "base/types.hh"')
1535 def __call__(self
, value
):
1536 self
.__init
__(value
)
1540 return long(self
.value
)
1543 def cxx_ini_predecls(cls
, code
):
1544 code('#include <sstream>')
1546 # Ticks are expressed in seconds in JSON files and in plain
1547 # Ticks in .ini files. Switch based on a config flag
1549 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1550 code('${ret} to_number(${src}, ${dest});')
1552 class Latency(TickParamValue
):
1555 def __init__(self
, value
):
1556 if isinstance(value
, (Latency
, Clock
)):
1557 self
.ticks
= value
.ticks
1558 self
.value
= value
.value
1559 elif isinstance(value
, Frequency
):
1560 self
.ticks
= value
.ticks
1561 self
.value
= 1.0 / value
.value
1562 elif value
.endswith('t'):
1564 self
.value
= int(value
[:-1])
1567 self
.value
= convert
.toLatency(value
)
1569 def __call__(self
, value
):
1570 self
.__init
__(value
)
1573 def __getattr__(self
, attr
):
1574 if attr
in ('latency', 'period'):
1576 if attr
== 'frequency':
1577 return Frequency(self
)
1578 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1581 if self
.ticks
or self
.value
== 0:
1584 value
= ticks
.fromSeconds(self
.value
)
1587 def config_value(self
):
1588 return self
.getValue()
1590 # convert latency to ticks
1592 return '%d' % self
.getValue()
1594 class Frequency(TickParamValue
):
1597 def __init__(self
, value
):
1598 if isinstance(value
, (Latency
, Clock
)):
1599 if value
.value
== 0:
1602 self
.value
= 1.0 / value
.value
1603 self
.ticks
= value
.ticks
1604 elif isinstance(value
, Frequency
):
1605 self
.value
= value
.value
1606 self
.ticks
= value
.ticks
1609 self
.value
= convert
.toFrequency(value
)
1611 def __call__(self
, value
):
1612 self
.__init
__(value
)
1615 def __getattr__(self
, attr
):
1616 if attr
== 'frequency':
1618 if attr
in ('latency', 'period'):
1619 return Latency(self
)
1620 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1622 # convert latency to ticks
1624 if self
.ticks
or self
.value
== 0:
1627 value
= ticks
.fromSeconds(1.0 / self
.value
)
1630 def config_value(self
):
1631 return self
.getValue()
1634 return '%d' % self
.getValue()
1636 # A generic Frequency and/or Latency value. Value is stored as a
1637 # latency, just like Latency and Frequency.
1638 class Clock(TickParamValue
):
1639 def __init__(self
, value
):
1640 if isinstance(value
, (Latency
, Clock
)):
1641 self
.ticks
= value
.ticks
1642 self
.value
= value
.value
1643 elif isinstance(value
, Frequency
):
1644 self
.ticks
= value
.ticks
1645 self
.value
= 1.0 / value
.value
1646 elif value
.endswith('t'):
1648 self
.value
= int(value
[:-1])
1651 self
.value
= convert
.anyToLatency(value
)
1653 def __call__(self
, value
):
1654 self
.__init
__(value
)
1658 return "%s" % Latency(self
)
1660 def __getattr__(self
, attr
):
1661 if attr
== 'frequency':
1662 return Frequency(self
)
1663 if attr
in ('latency', 'period'):
1664 return Latency(self
)
1665 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1668 return self
.period
.getValue()
1670 def config_value(self
):
1671 return self
.period
.config_value()
1674 return self
.period
.ini_str()
1676 class Voltage(Float
):
1679 def __new__(cls
, value
):
1680 value
= convert
.toVoltage(value
)
1681 return super(cls
, Voltage
).__new
__(cls
, value
)
1683 def __init__(self
, value
):
1684 value
= convert
.toVoltage(value
)
1685 super(Voltage
, self
).__init
__(value
)
1687 class Current(Float
):
1690 def __new__(cls
, value
):
1691 value
= convert
.toCurrent(value
)
1692 return super(cls
, Current
).__new
__(cls
, value
)
1694 def __init__(self
, value
):
1695 value
= convert
.toCurrent(value
)
1696 super(Current
, self
).__init
__(value
)
1698 class Energy(Float
):
1701 def __new__(cls
, value
):
1702 value
= convert
.toEnergy(value
)
1703 return super(cls
, Energy
).__new
__(cls
, value
)
1705 def __init__(self
, value
):
1706 value
= convert
.toEnergy(value
)
1707 super(Energy
, self
).__init
__(value
)
1709 class NetworkBandwidth(float,ParamValue
):
1712 cmd_line_settable
= True
1714 def __new__(cls
, value
):
1715 # convert to bits per second
1716 val
= convert
.toNetworkBandwidth(value
)
1717 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1720 return str(self
.val
)
1722 def __call__(self
, value
):
1723 val
= convert
.toNetworkBandwidth(value
)
1728 # convert to seconds per byte
1729 value
= 8.0 / float(self
)
1730 # convert to ticks per byte
1731 value
= ticks
.fromSeconds(value
)
1735 return '%f' % self
.getValue()
1737 def config_value(self
):
1738 return '%f' % self
.getValue()
1741 def cxx_ini_predecls(cls
, code
):
1742 code('#include <sstream>')
1745 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1746 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1748 class MemoryBandwidth(float,ParamValue
):
1751 cmd_line_settable
= True
1753 def __new__(cls
, value
):
1754 # convert to bytes per second
1755 val
= convert
.toMemoryBandwidth(value
)
1756 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1758 def __call__(self
, value
):
1759 val
= convert
.toMemoryBandwidth(value
)
1764 # convert to seconds per byte
1767 value
= 1.0 / float(self
)
1768 # convert to ticks per byte
1769 value
= ticks
.fromSeconds(value
)
1773 return '%f' % self
.getValue()
1775 def config_value(self
):
1776 return '%f' % self
.getValue()
1779 def cxx_ini_predecls(cls
, code
):
1780 code('#include <sstream>')
1783 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1784 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1787 # "Constants"... handy aliases for various values.
1790 # Special class for NULL pointers. Note the special check in
1791 # make_param_value() above that lets these be assigned where a
1792 # SimObject is required.
1793 # only one copy of a particular node
1794 class NullSimObject(object):
1795 __metaclass__
= Singleton
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 REQUESTER', 'GEM5 RESPONDER')
2125 class RequestPort(Port
):
2126 # RequestPort("description")
2127 def __init__(self
, desc
):
2128 super(RequestPort
, self
).__init
__(
2129 'GEM5 REQUESTER', 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 REQUESTER', 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(object):
2163 __metaclass__
= Singleton
2168 baseEnums
= allEnums
.copy()
2169 baseParams
= allParams
.copy()
2172 global allEnums
, allParams
2174 allEnums
= baseEnums
.copy()
2175 allParams
= baseParams
.copy()
2177 __all__
= ['Param', 'VectorParam',
2178 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2179 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2180 'Int32', 'UInt32', 'Int64', 'UInt64',
2181 'Counter', 'Addr', 'Tick', 'Percent',
2182 'TcpPort', 'UdpPort', 'EthernetAddr',
2183 'IpAddress', 'IpNetmask', 'IpWithPort',
2184 'MemorySize', 'MemorySize32',
2185 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2186 'NetworkBandwidth', 'MemoryBandwidth',
2188 'MaxAddr', 'MaxTick', 'AllMemory',
2190 'NextEthernetAddr', 'NULL',
2191 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2192 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2193 'VectorMasterPort', 'VectorSlavePort']