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
73 def isSimObject(*args
, **kwargs
):
74 from . import SimObject
75 return SimObject
.isSimObject(*args
, **kwargs
)
77 def isSimObjectSequence(*args
, **kwargs
):
78 from . import SimObject
79 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
81 def isSimObjectClass(*args
, **kwargs
):
82 from . import SimObject
83 return SimObject
.isSimObjectClass(*args
, **kwargs
)
87 class MetaParamValue(type):
88 def __new__(mcls
, name
, bases
, dct
):
89 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
90 assert name
not in allParams
95 # Dummy base class to identify types that are legitimate for SimObject
97 class ParamValue(object):
98 __metaclass__
= MetaParamValue
99 cmd_line_settable
= False
101 # Generate the code needed as a prerequisite for declaring a C++
102 # object of this type. Typically generates one or more #include
103 # statements. Used when declaring parameters of this type.
105 def cxx_predecls(cls
, code
):
109 def pybind_predecls(cls
, code
):
110 cls
.cxx_predecls(code
)
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
117 # default for printing to .json file is regular string conversion.
118 # will be overridden in some cases, mostly to use native Python
119 # types where there are similar JSON types
120 def config_value(self
):
123 # Prerequisites for .ini parsing with cxx_ini_parse
125 def cxx_ini_predecls(cls
, code
):
128 # parse a .ini file entry for this param from string expression
129 # src into lvalue dest (of the param's C++ type)
131 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
132 code('// Unhandled param type: %s' % cls
.__name
__)
133 code('%s false;' % ret
)
135 # allows us to blithely call unproxy() on things without checking
136 # if they're really proxies or not
137 def unproxy(self
, base
):
140 # Produce a human readable version of the stored value
141 def pretty_print(self
, value
):
144 # Regular parameter description.
145 class ParamDesc(object):
146 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
147 self
.ptype_str
= ptype_str
148 # remember ptype only if it is provided
156 self
.default
= args
[0]
159 raise TypeError('too many arguments')
162 assert(not hasattr(self
, 'desc'))
163 self
.desc
= kwargs
['desc']
166 if 'default' in kwargs
:
167 assert(not hasattr(self
, 'default'))
168 self
.default
= kwargs
['default']
169 del kwargs
['default']
172 raise TypeError('extra unknown kwargs %s' % kwargs
)
174 if not hasattr(self
, 'desc'):
175 raise TypeError('desc attribute missing')
177 def __getattr__(self
, attr
):
179 from . import SimObject
180 ptype
= SimObject
.allClasses
[self
.ptype_str
]
181 assert isSimObjectClass(ptype
)
185 raise AttributeError("'%s' object has no attribute '%s'" % \
186 (type(self
).__name
__, attr
))
188 def example_str(self
):
189 if hasattr(self
.ptype
, "ex_str"):
190 return self
.ptype
.ex_str
192 return self
.ptype_str
194 # Is the param available to be exposed on the command line
195 def isCmdLineSettable(self
):
196 if hasattr(self
.ptype
, "cmd_line_settable"):
197 return self
.ptype
.cmd_line_settable
201 def convert(self
, value
):
202 if isinstance(value
, proxy
.BaseProxy
):
203 value
.set_param_desc(self
)
205 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
206 # deferred evaluation of SimObject; continue to defer if
207 # we're just assigning a null pointer
209 if isinstance(value
, self
.ptype
):
211 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
213 return self
.ptype(value
)
215 def pretty_print(self
, value
):
216 if isinstance(value
, proxy
.BaseProxy
):
218 if isNullPointer(value
):
220 return self
.ptype(value
).pretty_print(value
)
222 def cxx_predecls(self
, code
):
223 code('#include <cstddef>')
224 self
.ptype
.cxx_predecls(code
)
226 def pybind_predecls(self
, code
):
227 self
.ptype
.pybind_predecls(code
)
229 def cxx_decl(self
, code
):
230 code('${{self.ptype.cxx_type}} ${{self.name}};')
232 # Vector-valued parameter description. Just like ParamDesc, except
233 # that the value is a vector (list) of the specified type instead of a
236 class VectorParamValue(list):
237 __metaclass__
= MetaParamValue
238 def __setattr__(self
, attr
, value
):
239 raise AttributeError("Not allowed to set %s on '%s'" % \
240 (attr
, type(self
).__name
__))
242 def config_value(self
):
243 return [v
.config_value() for v
in self
]
246 return ' '.join([v
.ini_str() for v
in self
])
249 return [ v
.getValue() for v
in self
]
251 def unproxy(self
, base
):
252 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
253 # The value is a proxy (e.g. Parent.any, Parent.all or
254 # Parent.x) therefore try resolve it
255 return self
[0].unproxy(base
)
257 return [v
.unproxy(base
) for v
in self
]
259 class SimObjectVector(VectorParamValue
):
260 # support clone operation
261 def __call__(self
, **kwargs
):
262 return SimObjectVector([v(**kwargs
) for v
in self
])
264 def clear_parent(self
, old_parent
):
266 v
.clear_parent(old_parent
)
268 def set_parent(self
, parent
, name
):
270 self
[0].set_parent(parent
, name
)
272 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
273 for i
,v
in enumerate(self
):
274 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
276 def has_parent(self
):
277 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
279 # return 'cpu0 cpu1' etc. for print_ini()
281 return ' '.join([v
._name
for v
in self
])
283 # By iterating through the constituent members of the vector here
284 # we can nicely handle iterating over all a SimObject's children
285 # without having to provide lots of special functions on
286 # SimObjectVector directly.
287 def descendants(self
):
289 for obj
in v
.descendants():
292 def get_config_as_dict(self
):
295 a
.append(v
.get_config_as_dict())
298 # If we are replacing an item in the vector, make sure to set the
299 # parent reference of the new SimObject to be the same as the parent
300 # of the SimObject being replaced. Useful to have if we created
301 # a SimObjectVector of temporary objects that will be modified later in
302 # configuration scripts.
303 def __setitem__(self
, key
, value
):
305 if value
.has_parent():
306 warn("SimObject %s already has a parent" % value
.get_name() +\
307 " that is being overwritten by a SimObjectVector")
308 value
.set_parent(val
.get_parent(), val
._name
)
309 super(SimObjectVector
, self
).__setitem
__(key
, value
)
311 # Enumerate the params of each member of the SimObject vector. Creates
312 # strings that will allow indexing into the vector by the python code and
313 # allow it to be specified on the command line.
314 def enumerateParams(self
, flags_dict
= {},
317 if hasattr(self
, "_paramEnumed"):
318 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
322 # Each entry in the SimObjectVector should be an
323 # instance of a SimObject
324 flags_dict
= vals
.enumerateParams(flags_dict
,
325 cmd_line_str
+ "%d." % x
,
326 access_str
+ "[%d]." % x
)
331 class VectorParamDesc(ParamDesc
):
332 # Convert assigned value to appropriate type. If the RHS is not a
333 # list or tuple, it generates a single-element list.
334 def convert(self
, value
):
335 if isinstance(value
, (list, tuple)):
336 # list: coerce each element into new list
337 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
338 elif isinstance(value
, str):
339 # If input is a csv string
340 tmp_list
= [ ParamDesc
.convert(self
, v
) \
341 for v
in value
.strip('[').strip(']').split(',') ]
343 # singleton: coerce to a single-element list
344 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
346 if isSimObjectSequence(tmp_list
):
347 return SimObjectVector(tmp_list
)
349 return VectorParamValue(tmp_list
)
351 # Produce a human readable example string that describes
352 # how to set this vector parameter in the absence of a default
354 def example_str(self
):
355 s
= super(VectorParamDesc
, self
).example_str()
356 help_str
= "[" + s
+ "," + s
+ ", ...]"
359 # Produce a human readable representation of the value of this vector param.
360 def pretty_print(self
, value
):
361 if isinstance(value
, (list, tuple)):
362 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
363 elif isinstance(value
, str):
364 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
366 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
370 # This is a helper function for the new config system
371 def __call__(self
, value
):
372 if isinstance(value
, (list, tuple)):
373 # list: coerce each element into new list
374 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
375 elif isinstance(value
, str):
376 # If input is a csv string
377 tmp_list
= [ ParamDesc
.convert(self
, v
) \
378 for v
in value
.strip('[').strip(']').split(',') ]
380 # singleton: coerce to a single-element list
381 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
383 return VectorParamValue(tmp_list
)
385 def cxx_predecls(self
, code
):
386 code('#include <vector>')
387 self
.ptype
.cxx_predecls(code
)
389 def pybind_predecls(self
, code
):
390 code('#include <vector>')
391 self
.ptype
.pybind_predecls(code
)
393 def cxx_decl(self
, code
):
394 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
396 class ParamFactory(object):
397 def __init__(self
, param_desc_class
, ptype_str
= None):
398 self
.param_desc_class
= param_desc_class
399 self
.ptype_str
= ptype_str
401 def __getattr__(self
, attr
):
403 attr
= self
.ptype_str
+ '.' + attr
404 return ParamFactory(self
.param_desc_class
, attr
)
406 # E.g., Param.Int(5, "number of widgets")
407 def __call__(self
, *args
, **kwargs
):
410 ptype
= allParams
[self
.ptype_str
]
412 # if name isn't defined yet, assume it's a SimObject, and
413 # try to resolve it later
415 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
417 Param
= ParamFactory(ParamDesc
)
418 VectorParam
= ParamFactory(VectorParamDesc
)
420 #####################################################################
424 # Though native Python types could be used to specify parameter types
425 # (the 'ptype' field of the Param and VectorParam classes), it's more
426 # flexible to define our own set of types. This gives us more control
427 # over how Python expressions are converted to values (via the
428 # __init__() constructor) and how these values are printed out (via
429 # the __str__() conversion method).
431 #####################################################################
433 # String-valued parameter. Just mixin the ParamValue class with the
434 # built-in str class.
435 class String(ParamValue
,str):
436 cxx_type
= 'std::string'
437 cmd_line_settable
= True
440 def cxx_predecls(self
, code
):
441 code('#include <string>')
443 def __call__(self
, value
):
448 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
449 code('%s = %s;' % (dest
, src
))
450 code('%s true;' % ret
)
455 # superclass for "numeric" parameter values, to emulate math
456 # operations in a type-safe way. e.g., a Latency times an int returns
457 # a new Latency object.
458 class NumericParamValue(ParamValue
):
461 return v
.value
if isinstance(v
, NumericParamValue
) else v
464 return str(self
.value
)
467 return float(self
.value
)
470 return long(self
.value
)
473 return int(self
.value
)
475 # hook for bounds checking
479 def __mul__(self
, other
):
480 newobj
= self
.__class
__(self
)
481 newobj
.value
*= NumericParamValue
.unwrap(other
)
487 def __truediv__(self
, other
):
488 newobj
= self
.__class
__(self
)
489 newobj
.value
/= NumericParamValue
.unwrap(other
)
493 def __floordiv__(self
, other
):
494 newobj
= self
.__class
__(self
)
495 newobj
.value
//= NumericParamValue
.unwrap(other
)
500 def __add__(self
, other
):
501 newobj
= self
.__class
__(self
)
502 newobj
.value
+= NumericParamValue
.unwrap(other
)
506 def __sub__(self
, other
):
507 newobj
= self
.__class
__(self
)
508 newobj
.value
-= NumericParamValue
.unwrap(other
)
512 def __iadd__(self
, other
):
513 self
.value
+= NumericParamValue
.unwrap(other
)
517 def __isub__(self
, other
):
518 self
.value
-= NumericParamValue
.unwrap(other
)
522 def __imul__(self
, other
):
523 self
.value
*= NumericParamValue
.unwrap(other
)
527 def __itruediv__(self
, other
):
528 self
.value
/= NumericParamValue
.unwrap(other
)
532 def __ifloordiv__(self
, other
):
533 self
.value
//= NumericParamValue
.unwrap(other
)
537 def __lt__(self
, other
):
538 return self
.value
< NumericParamValue
.unwrap(other
)
540 # Python 2.7 pre __future__.division operators
541 # TODO: Remove these when after "import division from __future__"
542 __div__
= __truediv__
543 __idiv__
= __itruediv__
545 def config_value(self
):
549 def cxx_ini_predecls(cls
, code
):
550 # Assume that base/str.hh will be included anyway
551 # code('#include "base/str.hh"')
554 # The default for parsing PODs from an .ini entry is to extract from an
555 # istringstream and let overloading choose the right type according to
558 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
559 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
561 # Metaclass for bounds-checked integer parameters. See CheckedInt.
562 class CheckedIntType(MetaParamValue
):
563 def __init__(cls
, name
, bases
, dict):
564 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
566 # CheckedInt is an abstract base class, so we actually don't
567 # want to do any processing on it... the rest of this code is
568 # just for classes that derive from CheckedInt.
569 if name
== 'CheckedInt':
572 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
573 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
574 panic("CheckedInt subclass %s must define either\n" \
575 " 'min' and 'max' or 'size' and 'unsigned'\n",
579 cls
.max = 2 ** cls
.size
- 1
581 cls
.min = -(2 ** (cls
.size
- 1))
582 cls
.max = (2 ** (cls
.size
- 1)) - 1
584 # Abstract superclass for bounds-checked integer parameters. This
585 # class is subclassed to generate parameter classes with specific
586 # bounds. Initialization of the min and max bounds is done in the
587 # metaclass CheckedIntType.__init__.
588 class CheckedInt(NumericParamValue
):
589 __metaclass__
= CheckedIntType
590 cmd_line_settable
= True
593 if not self
.min <= self
.value
<= self
.max:
594 raise TypeError('Integer param out of bounds %d < %d < %d' % \
595 (self
.min, self
.value
, self
.max))
597 def __init__(self
, value
):
598 if isinstance(value
, str):
599 self
.value
= convert
.toInteger(value
)
600 elif isinstance(value
, (int, long, float, NumericParamValue
)):
601 self
.value
= long(value
)
603 raise TypeError("Can't convert object of type %s to CheckedInt" \
604 % type(value
).__name
__)
607 def __call__(self
, value
):
612 return int(self
.value
)
615 def cxx_predecls(cls
, code
):
616 # most derived types require this, so we just do it here once
617 code('#include "base/types.hh"')
620 return long(self
.value
)
622 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
623 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
625 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
626 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
627 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
628 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
629 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
630 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
631 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
632 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
634 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
635 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
636 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
637 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
639 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
641 class Cycles(CheckedInt
):
647 from _m5
.core
import Cycles
648 return Cycles(self
.value
)
651 def cxx_ini_predecls(cls
, code
):
652 # Assume that base/str.hh will be included anyway
653 # code('#include "base/str.hh"')
657 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
658 code('uint64_t _temp;')
659 code('bool _ret = to_number(%s, _temp);' % src
)
661 code(' %s = Cycles(_temp);' % dest
)
662 code('%s _ret;' % ret
)
664 class Float(ParamValue
, float):
666 cmd_line_settable
= True
668 def __init__(self
, value
):
669 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
670 self
.value
= float(value
)
672 raise TypeError("Can't convert object of type %s to Float" \
673 % type(value
).__name
__)
675 def __call__(self
, value
):
680 return float(self
.value
)
682 def config_value(self
):
686 def cxx_ini_predecls(cls
, code
):
687 code('#include <sstream>')
690 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
691 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
693 class MemorySize(CheckedInt
):
694 cxx_type
= 'uint64_t'
698 def __init__(self
, value
):
699 if isinstance(value
, MemorySize
):
700 self
.value
= value
.value
702 self
.value
= convert
.toMemorySize(value
)
705 class MemorySize32(CheckedInt
):
706 cxx_type
= 'uint32_t'
710 def __init__(self
, value
):
711 if isinstance(value
, MemorySize
):
712 self
.value
= value
.value
714 self
.value
= convert
.toMemorySize(value
)
717 class Addr(CheckedInt
):
721 def __init__(self
, value
):
722 if isinstance(value
, Addr
):
723 self
.value
= value
.value
726 # Often addresses are referred to with sizes. Ex: A device
727 # base address is at "512MB". Use toMemorySize() to convert
728 # these into addresses. If the address is not specified with a
729 # "size", an exception will occur and numeric translation will
731 self
.value
= convert
.toMemorySize(value
)
732 except (TypeError, ValueError):
733 # Convert number to string and use long() to do automatic
734 # base conversion (requires base=0 for auto-conversion)
735 self
.value
= long(str(value
), base
=0)
738 def __add__(self
, other
):
739 if isinstance(other
, Addr
):
740 return self
.value
+ other
.value
742 return self
.value
+ other
743 def pretty_print(self
, value
):
745 val
= convert
.toMemorySize(value
)
748 return "0x%x" % long(val
)
750 class AddrRange(ParamValue
):
751 cxx_type
= 'AddrRange'
753 def __init__(self
, *args
, **kwargs
):
754 # Disable interleaving and hashing by default
759 def handle_kwargs(self
, kwargs
):
760 # An address range needs to have an upper limit, specified
761 # either explicitly with an end, or as an offset using the
764 self
.end
= Addr(kwargs
.pop('end'))
765 elif 'size' in kwargs
:
766 self
.end
= self
.start
+ Addr(kwargs
.pop('size'))
768 raise TypeError("Either end or size must be specified")
770 # Now on to the optional bit
771 if 'intlvMatch' in kwargs
:
772 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
774 if 'masks' in kwargs
:
775 self
.masks
= [ long(x
) for x
in list(kwargs
.pop('masks')) ]
776 self
.intlvBits
= len(self
.masks
)
778 if 'intlvBits' in kwargs
:
779 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
780 self
.masks
= [0] * self
.intlvBits
781 if 'intlvHighBit' not in kwargs
:
782 raise TypeError("No interleave bits specified")
783 intlv_high_bit
= int(kwargs
.pop('intlvHighBit'))
785 if 'xorHighBit' in kwargs
:
786 xor_high_bit
= int(kwargs
.pop('xorHighBit'))
787 for i
in range(0, self
.intlvBits
):
788 bit1
= intlv_high_bit
- i
790 if xor_high_bit
!= 0:
791 bit2
= xor_high_bit
- i
793 self
.masks
[self
.intlvBits
- i
- 1] = mask
796 self
.start
= Addr(kwargs
.pop('start'))
797 handle_kwargs(self
, kwargs
)
801 self
.start
= Addr(args
[0])
802 handle_kwargs(self
, kwargs
)
803 elif isinstance(args
[0], (list, tuple)):
804 self
.start
= Addr(args
[0][0])
805 self
.end
= Addr(args
[0][1])
808 self
.end
= Addr(args
[0])
811 self
.start
= Addr(args
[0])
812 self
.end
= Addr(args
[1])
814 raise TypeError("Too many arguments specified")
817 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
820 if len(self
.masks
) == 0:
821 return '%s:%s' % (self
.start
, self
.end
)
823 return '%s:%s:%s:%s' % (self
.start
, self
.end
, self
.intlvMatch
,
824 ':'.join(str(m
) for m
in self
.masks
))
827 # Divide the size by the size of the interleaving slice
828 return (long(self
.end
) - long(self
.start
)) >> self
.intlvBits
831 def cxx_predecls(cls
, code
):
832 Addr
.cxx_predecls(code
)
833 code('#include "base/addr_range.hh"')
836 def pybind_predecls(cls
, code
):
837 Addr
.pybind_predecls(code
)
838 code('#include "base/addr_range.hh"')
841 def cxx_ini_predecls(cls
, code
):
842 code('#include <sstream>')
843 code('#include <vector>')
844 code('#include "base/types.hh"')
847 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
848 code('bool _ret = true;')
849 code('uint64_t _start, _end, _intlvMatch = 0;')
850 code('std::vector<Addr> _masks;')
852 code('std::istringstream _stream(${src});')
853 code('_stream >> _start;')
854 code('_stream.get(_sep);')
855 code('_ret = _sep == \':\';')
856 code('_stream >> _end;')
857 code('if (!_stream.fail() && !_stream.eof()) {')
858 code(' _stream.get(_sep);')
859 code(' _ret = ret && _sep == \':\';')
860 code(' _stream >> _intlvMatch;')
861 code(' while (!_stream.fail() && !_stream.eof()) {')
862 code(' _stream.get(_sep);')
863 code(' _ret = ret && _sep == \':\';')
865 code(' _stream >> mask;')
866 code(' _masks.push_back(mask);')
869 code('_ret = _ret && !_stream.fail() && _stream.eof();')
871 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
875 # Go from the Python class to the wrapped C++ class
876 from _m5
.range import AddrRange
878 return AddrRange(long(self
.start
), long(self
.end
),
879 self
.masks
, int(self
.intlvMatch
))
881 # Boolean parameter type. Python doesn't let you subclass bool, since
882 # it doesn't want to let you create multiple instances of True and
883 # False. Thus this is a little more complicated than String.
884 class Bool(ParamValue
):
886 cmd_line_settable
= True
888 def __init__(self
, value
):
890 self
.value
= convert
.toBool(value
)
892 self
.value
= bool(value
)
894 def __call__(self
, value
):
899 return bool(self
.value
)
902 return str(self
.value
)
904 # implement truth value testing for Bool parameters so that these params
905 # evaluate correctly during the python configuration phase
907 return bool(self
.value
)
909 # Python 2.7 uses __nonzero__ instead of __bool__
910 __nonzero__
= __bool__
917 def config_value(self
):
921 def cxx_ini_predecls(cls
, code
):
922 # Assume that base/str.hh will be included anyway
923 # code('#include "base/str.hh"')
927 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
928 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
930 def IncEthernetAddr(addr
, val
= 1):
931 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
933 for i
in (5, 4, 3, 2, 1):
934 val
,rem
= divmod(bytes
[i
], 256)
939 assert(bytes
[0] <= 255)
940 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
942 _NextEthernetAddr
= "00:90:00:00:00:01"
943 def NextEthernetAddr():
944 global _NextEthernetAddr
946 value
= _NextEthernetAddr
947 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
950 class EthernetAddr(ParamValue
):
951 cxx_type
= 'Net::EthAddr'
952 ex_str
= "00:90:00:00:00:01"
953 cmd_line_settable
= True
956 def cxx_predecls(cls
, code
):
957 code('#include "base/inet.hh"')
959 def __init__(self
, value
):
960 if value
== NextEthernetAddr
:
964 if not isinstance(value
, str):
965 raise TypeError("expected an ethernet address and didn't get one")
967 bytes
= value
.split(':')
969 raise TypeError('invalid ethernet address %s' % value
)
972 if not 0 <= int(byte
, base
=16) <= 0xff:
973 raise TypeError('invalid ethernet address %s' % value
)
977 def __call__(self
, value
):
981 def unproxy(self
, base
):
982 if self
.value
== NextEthernetAddr
:
983 return EthernetAddr(self
.value())
987 from _m5
.net
import EthAddr
988 return EthAddr(self
.value
)
997 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
998 code('%s = Net::EthAddr(%s);' % (dest
, src
))
999 code('%s true;' % ret
)
1001 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1002 # the form "a.b.c.d", or an integer representing an IP.
1003 class IpAddress(ParamValue
):
1004 cxx_type
= 'Net::IpAddress'
1005 ex_str
= "127.0.0.1"
1006 cmd_line_settable
= True
1009 def cxx_predecls(cls
, code
):
1010 code('#include "base/inet.hh"')
1012 def __init__(self
, value
):
1013 if isinstance(value
, IpAddress
):
1017 self
.ip
= convert
.toIpAddress(value
)
1019 self
.ip
= long(value
)
1022 def __call__(self
, value
):
1023 self
.__init
__(value
)
1027 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1028 return '%d.%d.%d.%d' % tuple(tup
)
1030 def __eq__(self
, other
):
1031 if isinstance(other
, IpAddress
):
1032 return self
.ip
== other
.ip
1033 elif isinstance(other
, str):
1035 return self
.ip
== convert
.toIpAddress(other
)
1039 return self
.ip
== other
1041 def __ne__(self
, other
):
1042 return not (self
== other
)
1045 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1046 raise TypeError("invalid ip address %#08x" % self
.ip
)
1049 from _m5
.net
import IpAddress
1050 return IpAddress(self
.ip
)
1052 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1053 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1054 # positional or keyword arguments.
1055 class IpNetmask(IpAddress
):
1056 cxx_type
= 'Net::IpNetmask'
1057 ex_str
= "127.0.0.0/24"
1058 cmd_line_settable
= True
1061 def cxx_predecls(cls
, code
):
1062 code('#include "base/inet.hh"')
1064 def __init__(self
, *args
, **kwargs
):
1065 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1067 setattr(self
, key
, kwargs
.pop(key
))
1069 setattr(self
, key
, elseVal
)
1071 raise TypeError("No value set for %s" % key
)
1074 handle_kwarg(self
, kwargs
, 'ip')
1075 handle_kwarg(self
, kwargs
, 'netmask')
1077 elif len(args
) == 1:
1079 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1080 raise TypeError("Invalid arguments")
1081 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1082 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1083 elif isinstance(args
[0], IpNetmask
):
1084 self
.ip
= args
[0].ip
1085 self
.netmask
= args
[0].netmask
1087 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1089 elif len(args
) == 2:
1091 self
.netmask
= args
[1]
1093 raise TypeError("Too many arguments specified")
1096 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1100 def __call__(self
, value
):
1101 self
.__init
__(value
)
1105 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1107 def __eq__(self
, other
):
1108 if isinstance(other
, IpNetmask
):
1109 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1110 elif isinstance(other
, str):
1112 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1120 if self
.netmask
< 0 or self
.netmask
> 32:
1121 raise TypeError("invalid netmask %d" % netmask
)
1124 from _m5
.net
import IpNetmask
1125 return IpNetmask(self
.ip
, self
.netmask
)
1127 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1128 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1129 class IpWithPort(IpAddress
):
1130 cxx_type
= 'Net::IpWithPort'
1131 ex_str
= "127.0.0.1:80"
1132 cmd_line_settable
= True
1135 def cxx_predecls(cls
, code
):
1136 code('#include "base/inet.hh"')
1138 def __init__(self
, *args
, **kwargs
):
1139 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1141 setattr(self
, key
, kwargs
.pop(key
))
1143 setattr(self
, key
, elseVal
)
1145 raise TypeError("No value set for %s" % key
)
1148 handle_kwarg(self
, kwargs
, 'ip')
1149 handle_kwarg(self
, kwargs
, 'port')
1151 elif len(args
) == 1:
1153 if not 'ip' in kwargs
and not 'port' in kwargs
:
1154 raise TypeError("Invalid arguments")
1155 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1156 handle_kwarg(self
, kwargs
, 'port', args
[0])
1157 elif isinstance(args
[0], IpWithPort
):
1158 self
.ip
= args
[0].ip
1159 self
.port
= args
[0].port
1161 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1163 elif len(args
) == 2:
1167 raise TypeError("Too many arguments specified")
1170 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1174 def __call__(self
, value
):
1175 self
.__init
__(value
)
1179 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1181 def __eq__(self
, other
):
1182 if isinstance(other
, IpWithPort
):
1183 return self
.ip
== other
.ip
and self
.port
== other
.port
1184 elif isinstance(other
, str):
1186 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1194 if self
.port
< 0 or self
.port
> 0xffff:
1195 raise TypeError("invalid port %d" % self
.port
)
1198 from _m5
.net
import IpWithPort
1199 return IpWithPort(self
.ip
, self
.port
)
1201 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1202 "%a %b %d %H:%M:%S %Y",
1203 "%Y/%m/%d %H:%M:%S",
1206 "%m/%d/%Y %H:%M:%S",
1209 "%m/%d/%y %H:%M:%S",
1214 def parse_time(value
):
1215 from time
import gmtime
, strptime
, struct_time
, time
1216 from datetime
import datetime
, date
1218 if isinstance(value
, struct_time
):
1221 if isinstance(value
, (int, long)):
1222 return gmtime(value
)
1224 if isinstance(value
, (datetime
, date
)):
1225 return value
.timetuple()
1227 if isinstance(value
, str):
1228 if value
in ('Now', 'Today'):
1229 return time
.gmtime(time
.time())
1231 for format
in time_formats
:
1233 return strptime(value
, format
)
1237 raise ValueError("Could not parse '%s' as a time" % value
)
1239 class Time(ParamValue
):
1243 def cxx_predecls(cls
, code
):
1244 code('#include <time.h>')
1246 def __init__(self
, value
):
1247 self
.value
= parse_time(value
)
1249 def __call__(self
, value
):
1250 self
.__init
__(value
)
1254 from _m5
.core
import tm
1257 return tm
.gmtime(calendar
.timegm(self
.value
))
1260 return time
.asctime(self
.value
)
1265 def get_config_as_dict(self
):
1270 def cxx_ini_predecls(cls
, code
):
1271 code('#include <time.h>')
1274 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1275 code('char *_parse_ret = strptime((${src}).c_str(),')
1276 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1277 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1279 # Enumerated types are a little more complex. The user specifies the
1280 # type as Enum(foo) where foo is either a list or dictionary of
1281 # alternatives (typically strings, but not necessarily so). (In the
1282 # long run, the integer value of the parameter will be the list index
1283 # or the corresponding dictionary value. For now, since we only check
1284 # that the alternative is valid and then spit it into a .ini file,
1285 # there's not much point in using the dictionary.)
1287 # What Enum() must do is generate a new type encapsulating the
1288 # provided list/dictionary so that specific values of the parameter
1289 # can be instances of that type. We define two hidden internal
1290 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1291 # derive the new type from the appropriate base class on the fly.
1294 # Metaclass for Enum types
1295 class MetaEnum(MetaParamValue
):
1296 def __new__(mcls
, name
, bases
, dict):
1297 assert name
not in allEnums
1299 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1300 allEnums
[name
] = cls
1303 def __init__(cls
, name
, bases
, init_dict
):
1304 if 'map' in init_dict
:
1305 if not isinstance(cls
.map, dict):
1306 raise TypeError("Enum-derived class attribute 'map' " \
1307 "must be of type dict")
1308 # build list of value strings from map
1309 cls
.vals
= list(cls
.map.keys())
1311 elif 'vals' in init_dict
:
1312 if not isinstance(cls
.vals
, list):
1313 raise TypeError("Enum-derived class attribute 'vals' " \
1314 "must be of type list")
1315 # build string->value map from vals sequence
1317 for idx
,val
in enumerate(cls
.vals
):
1320 raise TypeError("Enum-derived class must define "\
1321 "attribute 'map' or 'vals'")
1324 cls
.cxx_type
= '%s' % name
1326 cls
.cxx_type
= 'Enums::%s' % name
1328 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1330 # Generate C++ class declaration for this enum type.
1331 # Note that we wrap the enum in a class/struct to act as a namespace,
1332 # so that the enum strings can be brief w/o worrying about collisions.
1333 def cxx_decl(cls
, code
):
1334 wrapper_name
= cls
.wrapper_name
1335 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1336 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1337 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1350 $wrapper $wrapper_name {
1355 for val
in cls
.vals
:
1356 code('$val = ${{cls.map[val]}},')
1357 code('Num_$name = ${{len(cls.vals)}}')
1363 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1365 elif cls
.wrapper_is_struct
:
1366 code('static const char *${name}Strings[Num_${name}];')
1368 code('extern const char *${name}Strings[Num_${name}];')
1370 if not cls
.is_class
:
1375 code('#endif // $idem_macro')
1377 def cxx_def(cls
, code
):
1378 wrapper_name
= cls
.wrapper_name
1379 file_name
= cls
.__name
__
1380 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1382 code('#include "enums/$file_name.hh"')
1383 if cls
.wrapper_is_struct
:
1384 code('const char *${wrapper_name}::${name}Strings'
1389 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1392 code('namespace Enums {')
1394 code('const char *${name}Strings[Num_${name}] =')
1398 for val
in cls
.vals
:
1403 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1405 code('} // namespace $wrapper_name')
1408 def pybind_def(cls
, code
):
1410 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1411 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1413 code('''#include "pybind11/pybind11.h"
1414 #include "pybind11/stl.h"
1416 #include <sim/init.hh>
1418 namespace py = pybind11;
1421 module_init(py::module &m_internal)
1423 py::module m = m_internal.def_submodule("enum_${name}");
1427 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1429 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1433 for val
in cls
.vals
:
1434 code('.value("${val}", ${wrapper_name}::${val})')
1435 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1436 if not cls
.is_class
:
1437 code('.export_values()')
1444 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1447 # Base class for enum types.
1448 class Enum(ParamValue
):
1449 __metaclass__
= MetaEnum
1451 cmd_line_settable
= True
1453 # The name of the wrapping namespace or struct
1454 wrapper_name
= 'Enums'
1456 # If true, the enum is wrapped in a struct rather than a namespace
1457 wrapper_is_struct
= False
1461 # If not None, use this as the enum name rather than this class name
1464 def __init__(self
, value
):
1465 if value
not in self
.map:
1466 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1467 % (value
, self
.vals
))
1470 def __call__(self
, value
):
1471 self
.__init
__(value
)
1475 def cxx_predecls(cls
, code
):
1476 code('#include "enums/$0.hh"', cls
.__name
__)
1479 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1480 code('if (false) {')
1481 for elem_name
in cls
.map.keys():
1482 code('} else if (%s == "%s") {' % (src
, elem_name
))
1484 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1485 code('%s = %s::%s;' % (dest
, name
if cls
.is_class
else 'Enums',
1487 code('%s true;' % ret
)
1490 code(' %s false;' % ret
)
1494 import m5
.internal
.params
1495 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1496 return e(self
.map[self
.value
])
1501 # This param will generate a scoped c++ enum and its python bindings.
1502 class ScopedEnum(Enum
):
1503 __metaclass__
= MetaEnum
1505 cmd_line_settable
= True
1507 # The name of the wrapping namespace or struct
1510 # If true, the enum is wrapped in a struct rather than a namespace
1511 wrapper_is_struct
= False
1513 # If true, the generated enum is a scoped enum
1516 # If not None, use this as the enum name rather than this class name
1519 # how big does a rounding error need to be before we warn about it?
1520 frequency_tolerance
= 0.001 # 0.1%
1522 class TickParamValue(NumericParamValue
):
1525 cmd_line_settable
= True
1528 def cxx_predecls(cls
, code
):
1529 code('#include "base/types.hh"')
1531 def __call__(self
, value
):
1532 self
.__init
__(value
)
1536 return long(self
.value
)
1539 def cxx_ini_predecls(cls
, code
):
1540 code('#include <sstream>')
1542 # Ticks are expressed in seconds in JSON files and in plain
1543 # Ticks in .ini files. Switch based on a config flag
1545 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1546 code('${ret} to_number(${src}, ${dest});')
1548 class Latency(TickParamValue
):
1551 def __init__(self
, value
):
1552 if isinstance(value
, (Latency
, Clock
)):
1553 self
.ticks
= value
.ticks
1554 self
.value
= value
.value
1555 elif isinstance(value
, Frequency
):
1556 self
.ticks
= value
.ticks
1557 self
.value
= 1.0 / value
.value
1558 elif value
.endswith('t'):
1560 self
.value
= int(value
[:-1])
1563 self
.value
= convert
.toLatency(value
)
1565 def __call__(self
, value
):
1566 self
.__init
__(value
)
1569 def __getattr__(self
, attr
):
1570 if attr
in ('latency', 'period'):
1572 if attr
== 'frequency':
1573 return Frequency(self
)
1574 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1577 if self
.ticks
or self
.value
== 0:
1580 value
= ticks
.fromSeconds(self
.value
)
1583 def config_value(self
):
1584 return self
.getValue()
1586 # convert latency to ticks
1588 return '%d' % self
.getValue()
1590 class Frequency(TickParamValue
):
1593 def __init__(self
, value
):
1594 if isinstance(value
, (Latency
, Clock
)):
1595 if value
.value
== 0:
1598 self
.value
= 1.0 / value
.value
1599 self
.ticks
= value
.ticks
1600 elif isinstance(value
, Frequency
):
1601 self
.value
= value
.value
1602 self
.ticks
= value
.ticks
1605 self
.value
= convert
.toFrequency(value
)
1607 def __call__(self
, value
):
1608 self
.__init
__(value
)
1611 def __getattr__(self
, attr
):
1612 if attr
== 'frequency':
1614 if attr
in ('latency', 'period'):
1615 return Latency(self
)
1616 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1618 # convert latency to ticks
1620 if self
.ticks
or self
.value
== 0:
1623 value
= ticks
.fromSeconds(1.0 / self
.value
)
1626 def config_value(self
):
1627 return self
.getValue()
1630 return '%d' % self
.getValue()
1632 # A generic Frequency and/or Latency value. Value is stored as a
1633 # latency, just like Latency and Frequency.
1634 class Clock(TickParamValue
):
1635 def __init__(self
, value
):
1636 if isinstance(value
, (Latency
, Clock
)):
1637 self
.ticks
= value
.ticks
1638 self
.value
= value
.value
1639 elif isinstance(value
, Frequency
):
1640 self
.ticks
= value
.ticks
1641 self
.value
= 1.0 / value
.value
1642 elif value
.endswith('t'):
1644 self
.value
= int(value
[:-1])
1647 self
.value
= convert
.anyToLatency(value
)
1649 def __call__(self
, value
):
1650 self
.__init
__(value
)
1654 return "%s" % Latency(self
)
1656 def __getattr__(self
, attr
):
1657 if attr
== 'frequency':
1658 return Frequency(self
)
1659 if attr
in ('latency', 'period'):
1660 return Latency(self
)
1661 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1664 return self
.period
.getValue()
1666 def config_value(self
):
1667 return self
.period
.config_value()
1670 return self
.period
.ini_str()
1672 class Voltage(Float
):
1675 def __new__(cls
, value
):
1676 value
= convert
.toVoltage(value
)
1677 return super(cls
, Voltage
).__new
__(cls
, value
)
1679 def __init__(self
, value
):
1680 value
= convert
.toVoltage(value
)
1681 super(Voltage
, self
).__init
__(value
)
1683 class Current(Float
):
1686 def __new__(cls
, value
):
1687 value
= convert
.toCurrent(value
)
1688 return super(cls
, Current
).__new
__(cls
, value
)
1690 def __init__(self
, value
):
1691 value
= convert
.toCurrent(value
)
1692 super(Current
, self
).__init
__(value
)
1694 class Energy(Float
):
1697 def __new__(cls
, value
):
1698 value
= convert
.toEnergy(value
)
1699 return super(cls
, Energy
).__new
__(cls
, value
)
1701 def __init__(self
, value
):
1702 value
= convert
.toEnergy(value
)
1703 super(Energy
, self
).__init
__(value
)
1705 class NetworkBandwidth(float,ParamValue
):
1708 cmd_line_settable
= True
1710 def __new__(cls
, value
):
1711 # convert to bits per second
1712 val
= convert
.toNetworkBandwidth(value
)
1713 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1716 return str(self
.val
)
1718 def __call__(self
, value
):
1719 val
= convert
.toNetworkBandwidth(value
)
1724 # convert to seconds per byte
1725 value
= 8.0 / float(self
)
1726 # convert to ticks per byte
1727 value
= ticks
.fromSeconds(value
)
1731 return '%f' % self
.getValue()
1733 def config_value(self
):
1734 return '%f' % self
.getValue()
1737 def cxx_ini_predecls(cls
, code
):
1738 code('#include <sstream>')
1741 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1742 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1744 class MemoryBandwidth(float,ParamValue
):
1747 cmd_line_settable
= True
1749 def __new__(cls
, value
):
1750 # convert to bytes per second
1751 val
= convert
.toMemoryBandwidth(value
)
1752 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1754 def __call__(self
, value
):
1755 val
= convert
.toMemoryBandwidth(value
)
1760 # convert to seconds per byte
1763 value
= 1.0 / float(self
)
1764 # convert to ticks per byte
1765 value
= ticks
.fromSeconds(value
)
1769 return '%f' % self
.getValue()
1771 def config_value(self
):
1772 return '%f' % self
.getValue()
1775 def cxx_ini_predecls(cls
, code
):
1776 code('#include <sstream>')
1779 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1780 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1783 # "Constants"... handy aliases for various values.
1786 # Special class for NULL pointers. Note the special check in
1787 # make_param_value() above that lets these be assigned where a
1788 # SimObject is required.
1789 # only one copy of a particular node
1790 class NullSimObject(object):
1791 __metaclass__
= Singleton
1797 def _instantiate(self
, parent
= None, path
= ''):
1803 def unproxy(self
, base
):
1806 def set_path(self
, parent
, name
):
1809 def set_parent(self
, parent
, name
):
1812 def clear_parent(self
, old_parent
):
1815 def descendants(self
):
1819 def get_config_as_dict(self
):
1825 def config_value(self
):
1831 # The only instance you'll ever need...
1832 NULL
= NullSimObject()
1834 def isNullPointer(value
):
1835 return isinstance(value
, NullSimObject
)
1837 # Some memory range specifications use this as a default upper bound.
1840 AllMemory
= AddrRange(0, MaxAddr
)
1843 #####################################################################
1847 # Ports are used to interconnect objects in the memory system.
1849 #####################################################################
1851 # Port reference: encapsulates a reference to a particular port on a
1852 # particular SimObject.
1853 class PortRef(object):
1854 def __init__(self
, simobj
, name
, role
, is_source
):
1855 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1856 self
.simobj
= simobj
1859 self
.is_source
= is_source
1860 self
.peer
= None # not associated with another port yet
1861 self
.ccConnected
= False # C++ port connection done?
1862 self
.index
= -1 # always -1 for non-vector ports
1865 return '%s.%s' % (self
.simobj
, self
.name
)
1868 # Return the number of connected ports, i.e. 0 is we have no
1869 # peer and 1 if we do.
1870 return int(self
.peer
!= None)
1872 # for config.ini, print peer's name (not ours)
1874 return str(self
.peer
)
1877 def get_config_as_dict(self
):
1878 return {'role' : self
.role
, 'peer' : str(self
.peer
),
1879 'is_source' : str(self
.is_source
)}
1881 def __getattr__(self
, attr
):
1882 if attr
== 'peerObj':
1883 # shorthand for proxies
1884 return self
.peer
.simobj
1885 raise AttributeError("'%s' object has no attribute '%s'" % \
1886 (self
.__class
__.__name
__, attr
))
1888 # Full connection is symmetric (both ways). Called via
1889 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1890 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1891 # e.g., "obj1.portA[3] = obj2.portB".
1892 def connect(self
, other
):
1893 if isinstance(other
, VectorPortRef
):
1894 # reference to plain VectorPort is implicit append
1895 other
= other
._get
_next
()
1896 if self
.peer
and not proxy
.isproxy(self
.peer
):
1897 fatal("Port %s is already connected to %s, cannot connect %s\n",
1898 self
, self
.peer
, other
);
1901 if proxy
.isproxy(other
):
1902 other
.set_param_desc(PortParamDesc())
1904 elif not isinstance(other
, PortRef
):
1905 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1908 if not Port
.is_compat(self
, other
):
1909 fatal("Ports %s and %s with roles '%s' and '%s' "
1910 "are not compatible", self
, other
, self
.role
, other
.role
)
1912 if other
.peer
is not self
:
1915 # Allow a compatible port pair to be spliced between a port and its
1916 # connected peer. Useful operation for connecting instrumentation
1917 # structures into a system when it is necessary to connect the
1918 # instrumentation after the full system has been constructed.
1919 def splice(self
, new_1
, new_2
):
1920 if not self
.peer
or proxy
.isproxy(self
.peer
):
1921 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1923 if not isinstance(new_1
, PortRef
) or not isinstance(new_2
, PortRef
):
1925 "Splicing non-port references '%s','%s' to port '%s'" % \
1926 (new_1
, new_2
, self
))
1928 old_peer
= self
.peer
1930 if Port
.is_compat(old_peer
, new_1
) and Port
.is_compat(self
, new_2
):
1931 old_peer
.peer
= new_1
1932 new_1
.peer
= old_peer
1935 elif Port
.is_compat(old_peer
, new_2
) and Port
.is_compat(self
, new_1
):
1936 old_peer
.peer
= new_2
1937 new_2
.peer
= old_peer
1941 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
1942 "%s(%s) and %s(%s)", self
, self
.role
,
1943 old_peer
, old_peer
.role
, new_1
, new_1
.role
,
1946 def clone(self
, simobj
, memo
):
1949 newRef
= copy
.copy(self
)
1951 newRef
.simobj
= simobj
1952 assert(isSimObject(newRef
.simobj
))
1953 if self
.peer
and not proxy
.isproxy(self
.peer
):
1954 peerObj
= self
.peer
.simobj(_memo
=memo
)
1955 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1956 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1959 def unproxy(self
, simobj
):
1960 assert(simobj
is self
.simobj
)
1961 if proxy
.isproxy(self
.peer
):
1963 realPeer
= self
.peer
.unproxy(self
.simobj
)
1965 print("Error in unproxying port '%s' of %s" %
1966 (self
.name
, self
.simobj
.path()))
1968 self
.connect(realPeer
)
1970 # Call C++ to create corresponding port connection between C++ objects
1971 def ccConnect(self
):
1972 if self
.ccConnected
: # already done this
1976 if not self
.peer
: # nothing to connect to
1979 port
= self
.simobj
.getPort(self
.name
, self
.index
)
1980 peer_port
= peer
.simobj
.getPort(peer
.name
, peer
.index
)
1981 port
.bind(peer_port
)
1983 self
.ccConnected
= True
1985 # A reference to an individual element of a VectorPort... much like a
1986 # PortRef, but has an index.
1987 class VectorPortElementRef(PortRef
):
1988 def __init__(self
, simobj
, name
, role
, is_source
, index
):
1989 PortRef
.__init
__(self
, simobj
, name
, role
, is_source
)
1993 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1995 # A reference to a complete vector-valued port (not just a single element).
1996 # Can be indexed to retrieve individual VectorPortElementRef instances.
1997 class VectorPortRef(object):
1998 def __init__(self
, simobj
, name
, role
, is_source
):
1999 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
2000 self
.simobj
= simobj
2003 self
.is_source
= is_source
2007 return '%s.%s[:]' % (self
.simobj
, self
.name
)
2010 # Return the number of connected peers, corresponding the the
2011 # length of the elements.
2012 return len(self
.elements
)
2014 # for config.ini, print peer's name (not ours)
2016 return ' '.join([el
.ini_str() for el
in self
.elements
])
2019 def get_config_as_dict(self
):
2020 return {'role' : self
.role
,
2021 'peer' : [el
.ini_str() for el
in self
.elements
],
2022 'is_source' : str(self
.is_source
)}
2024 def __getitem__(self
, key
):
2025 if not isinstance(key
, int):
2026 raise TypeError("VectorPort index must be integer")
2027 if key
>= len(self
.elements
):
2028 # need to extend list
2029 ext
= [VectorPortElementRef(
2030 self
.simobj
, self
.name
, self
.role
, self
.is_source
, i
)
2031 for i
in range(len(self
.elements
), key
+1)]
2032 self
.elements
.extend(ext
)
2033 return self
.elements
[key
]
2035 def _get_next(self
):
2036 return self
[len(self
.elements
)]
2038 def __setitem__(self
, key
, value
):
2039 if not isinstance(key
, int):
2040 raise TypeError("VectorPort index must be integer")
2041 self
[key
].connect(value
)
2043 def connect(self
, other
):
2044 if isinstance(other
, (list, tuple)):
2045 # Assign list of port refs to vector port.
2046 # For now, append them... not sure if that's the right semantics
2047 # or if it should replace the current vector.
2049 self
._get
_next
().connect(ref
)
2051 # scalar assignment to plain VectorPort is implicit append
2052 self
._get
_next
().connect(other
)
2054 def clone(self
, simobj
, memo
):
2057 newRef
= copy
.copy(self
)
2059 newRef
.simobj
= simobj
2060 assert(isSimObject(newRef
.simobj
))
2061 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2064 def unproxy(self
, simobj
):
2065 [el
.unproxy(simobj
) for el
in self
.elements
]
2067 def ccConnect(self
):
2068 [el
.ccConnect() for el
in self
.elements
]
2070 # Port description object. Like a ParamDesc object, this represents a
2071 # logical port in the SimObject class, not a particular port on a
2072 # SimObject instance. The latter are represented by PortRef objects.
2074 # Port("role", "description")
2079 def compat(cls
, role
, peer
):
2080 cls
._compat
_dict
.setdefault(role
, set()).add(peer
)
2081 cls
._compat
_dict
.setdefault(peer
, set()).add(role
)
2084 def is_compat(cls
, one
, two
):
2085 for port
in one
, two
:
2086 if not port
.role
in Port
._compat
_dict
:
2087 fatal("Unrecognized role '%s' for port %s\n", port
.role
, port
)
2088 return one
.role
in Port
._compat
_dict
[two
.role
]
2090 def __init__(self
, role
, desc
, is_source
=False):
2093 self
.is_source
= is_source
2095 # Generate a PortRef for this port on the given SimObject with the
2097 def makeRef(self
, simobj
):
2098 return PortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2100 # Connect an instance of this port (on the given SimObject with
2101 # the given name) with the port described by the supplied PortRef
2102 def connect(self
, simobj
, ref
):
2103 self
.makeRef(simobj
).connect(ref
)
2105 # No need for any pre-declarations at the moment as we merely rely
2106 # on an unsigned int.
2107 def cxx_predecls(self
, code
):
2110 def pybind_predecls(self
, code
):
2111 cls
.cxx_predecls(self
, code
)
2113 # Declare an unsigned int with the same name as the port, that
2114 # will eventually hold the number of connected ports (and thus the
2115 # number of elements for a VectorPort).
2116 def cxx_decl(self
, code
):
2117 code('unsigned int port_${{self.name}}_connection_count;')
2119 Port
.compat('GEM5 REQUESTER', 'GEM5 RESPONDER')
2121 class RequestPort(Port
):
2122 # RequestPort("description")
2123 def __init__(self
, desc
):
2124 super(RequestPort
, self
).__init
__(
2125 'GEM5 REQUESTER', desc
, is_source
=True)
2127 class ResponsePort(Port
):
2128 # ResponsePort("description")
2129 def __init__(self
, desc
):
2130 super(ResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2132 # VectorPort description object. Like Port, but represents a vector
2133 # of connections (e.g., as on a XBar).
2134 class VectorPort(Port
):
2135 def makeRef(self
, simobj
):
2136 return VectorPortRef(simobj
, self
.name
, self
.role
, self
.is_source
)
2138 class VectorRequestPort(VectorPort
):
2139 # VectorRequestPort("description")
2140 def __init__(self
, desc
):
2141 super(VectorRequestPort
, self
).__init
__(
2142 'GEM5 REQUESTER', desc
, is_source
=True)
2144 class VectorResponsePort(VectorPort
):
2145 # VectorResponsePort("description")
2146 def __init__(self
, desc
):
2147 super(VectorResponsePort
, self
).__init
__('GEM5 RESPONDER', desc
)
2149 # Old names, maintained for compatibility.
2150 MasterPort
= RequestPort
2151 SlavePort
= ResponsePort
2152 VectorMasterPort
= VectorRequestPort
2153 VectorSlavePort
= VectorResponsePort
2155 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2156 # proxy objects (via set_param_desc()) so that proxy error messages
2158 class PortParamDesc(object):
2159 __metaclass__
= Singleton
2164 baseEnums
= allEnums
.copy()
2165 baseParams
= allParams
.copy()
2168 global allEnums
, allParams
2170 allEnums
= baseEnums
.copy()
2171 allParams
= baseParams
.copy()
2173 __all__
= ['Param', 'VectorParam',
2174 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2175 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2176 'Int32', 'UInt32', 'Int64', 'UInt64',
2177 'Counter', 'Addr', 'Tick', 'Percent',
2178 'TcpPort', 'UdpPort', 'EthernetAddr',
2179 'IpAddress', 'IpNetmask', 'IpWithPort',
2180 'MemorySize', 'MemorySize32',
2181 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2182 'NetworkBandwidth', 'MemoryBandwidth',
2184 'MaxAddr', 'MaxTick', 'AllMemory',
2186 'NextEthernetAddr', 'NULL',
2187 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2188 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2189 'VectorMasterPort', 'VectorSlavePort']