1 # Copyright (c) 2012-2014, 2017, 2018 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
765 def handle_kwargs(self
, kwargs
):
766 # An address range needs to have an upper limit, specified
767 # either explicitly with an end, or as an offset using the
770 self
.end
= Addr(kwargs
.pop('end'))
771 elif 'size' in kwargs
:
772 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
774 raise TypeError("Either end or size must be specified")
776 # Now on to the optional bit
777 if 'intlvHighBit' in kwargs
:
778 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
779 if 'xorHighBit' in kwargs
:
780 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
781 if 'intlvBits' in kwargs
:
782 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
783 if 'intlvMatch' in kwargs
:
784 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
787 self
.start
= Addr(kwargs
.pop('start'))
788 handle_kwargs(self
, kwargs
)
792 self
.start
= Addr(args
[0])
793 handle_kwargs(self
, kwargs
)
794 elif isinstance(args
[0], (list, tuple)):
795 self
.start
= Addr(args
[0][0])
796 self
.end
= Addr(args
[0][1])
799 self
.end
= Addr(args
[0]) - 1
802 self
.start
= Addr(args
[0])
803 self
.end
= Addr(args
[1])
805 raise TypeError("Too many arguments specified")
808 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
811 return '%s:%s:%s:%s:%s:%s' \
812 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
813 self
.intlvBits
, self
.intlvMatch
)
816 # Divide the size by the size of the interleaving slice
817 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
820 def cxx_predecls(cls
, code
):
821 Addr
.cxx_predecls(code
)
822 code('#include "base/addr_range.hh"')
825 def pybind_predecls(cls
, code
):
826 Addr
.pybind_predecls(code
)
827 code('#include "base/addr_range.hh"')
830 def cxx_ini_predecls(cls
, code
):
831 code('#include <sstream>')
834 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
835 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
836 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
838 code('std::istringstream _stream(${src});')
839 code('_stream >> _start;')
840 code('_stream.get(_sep);')
841 code('_stream >> _end;')
842 code('if (!_stream.fail() && !_stream.eof()) {')
843 code(' _stream.get(_sep);')
844 code(' _stream >> _intlvHighBit;')
845 code(' _stream.get(_sep);')
846 code(' _stream >> _xorHighBit;')
847 code(' _stream.get(_sep);')
848 code(' _stream >> _intlvBits;')
849 code(' _stream.get(_sep);')
850 code(' _stream >> _intlvMatch;')
852 code('bool _ret = !_stream.fail() &&'
853 '_stream.eof() && _sep == \':\';')
855 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
856 _xorHighBit, _intlvBits, _intlvMatch);')
860 # Go from the Python class to the wrapped C++ class
861 from _m5
.range import AddrRange
863 return AddrRange(long(self
.start
), long(self
.end
),
864 int(self
.intlvHighBit
), int(self
.xorHighBit
),
865 int(self
.intlvBits
), int(self
.intlvMatch
))
867 # Boolean parameter type. Python doesn't let you subclass bool, since
868 # it doesn't want to let you create multiple instances of True and
869 # False. Thus this is a little more complicated than String.
870 class Bool(ParamValue
):
872 cmd_line_settable
= True
874 def __init__(self
, value
):
876 self
.value
= convert
.toBool(value
)
878 self
.value
= bool(value
)
880 def __call__(self
, value
):
885 return bool(self
.value
)
888 return str(self
.value
)
890 # implement truth value testing for Bool parameters so that these params
891 # evaluate correctly during the python configuration phase
893 return bool(self
.value
)
895 # Python 2.7 uses __nonzero__ instead of __bool__
896 __nonzero__
= __bool__
903 def config_value(self
):
907 def cxx_ini_predecls(cls
, code
):
908 # Assume that base/str.hh will be included anyway
909 # code('#include "base/str.hh"')
913 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
914 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
916 def IncEthernetAddr(addr
, val
= 1):
917 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
919 for i
in (5, 4, 3, 2, 1):
920 val
,rem
= divmod(bytes
[i
], 256)
925 assert(bytes
[0] <= 255)
926 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
928 _NextEthernetAddr
= "00:90:00:00:00:01"
929 def NextEthernetAddr():
930 global _NextEthernetAddr
932 value
= _NextEthernetAddr
933 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
936 class EthernetAddr(ParamValue
):
937 cxx_type
= 'Net::EthAddr'
938 ex_str
= "00:90:00:00:00:01"
939 cmd_line_settable
= True
942 def cxx_predecls(cls
, code
):
943 code('#include "base/inet.hh"')
945 def __init__(self
, value
):
946 if value
== NextEthernetAddr
:
950 if not isinstance(value
, str):
951 raise TypeError("expected an ethernet address and didn't get one")
953 bytes
= value
.split(':')
955 raise TypeError('invalid ethernet address %s' % value
)
958 if not 0 <= int(byte
, base
=16) <= 0xff:
959 raise TypeError('invalid ethernet address %s' % value
)
963 def __call__(self
, value
):
967 def unproxy(self
, base
):
968 if self
.value
== NextEthernetAddr
:
969 return EthernetAddr(self
.value())
973 from _m5
.net
import EthAddr
974 return EthAddr(self
.value
)
983 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
984 code('%s = Net::EthAddr(%s);' % (dest
, src
))
985 code('%s true;' % ret
)
987 # When initializing an IpAddress, pass in an existing IpAddress, a string of
988 # the form "a.b.c.d", or an integer representing an IP.
989 class IpAddress(ParamValue
):
990 cxx_type
= 'Net::IpAddress'
992 cmd_line_settable
= True
995 def cxx_predecls(cls
, code
):
996 code('#include "base/inet.hh"')
998 def __init__(self
, value
):
999 if isinstance(value
, IpAddress
):
1003 self
.ip
= convert
.toIpAddress(value
)
1005 self
.ip
= long(value
)
1008 def __call__(self
, value
):
1009 self
.__init
__(value
)
1013 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1014 return '%d.%d.%d.%d' % tuple(tup
)
1016 def __eq__(self
, other
):
1017 if isinstance(other
, IpAddress
):
1018 return self
.ip
== other
.ip
1019 elif isinstance(other
, str):
1021 return self
.ip
== convert
.toIpAddress(other
)
1025 return self
.ip
== other
1027 def __ne__(self
, other
):
1028 return not (self
== other
)
1031 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1032 raise TypeError("invalid ip address %#08x" % self
.ip
)
1035 from _m5
.net
import IpAddress
1036 return IpAddress(self
.ip
)
1038 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1039 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1040 # positional or keyword arguments.
1041 class IpNetmask(IpAddress
):
1042 cxx_type
= 'Net::IpNetmask'
1043 ex_str
= "127.0.0.0/24"
1044 cmd_line_settable
= True
1047 def cxx_predecls(cls
, code
):
1048 code('#include "base/inet.hh"')
1050 def __init__(self
, *args
, **kwargs
):
1051 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1053 setattr(self
, key
, kwargs
.pop(key
))
1055 setattr(self
, key
, elseVal
)
1057 raise TypeError("No value set for %s" % key
)
1060 handle_kwarg(self
, kwargs
, 'ip')
1061 handle_kwarg(self
, kwargs
, 'netmask')
1063 elif len(args
) == 1:
1065 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1066 raise TypeError("Invalid arguments")
1067 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1068 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1069 elif isinstance(args
[0], IpNetmask
):
1070 self
.ip
= args
[0].ip
1071 self
.netmask
= args
[0].netmask
1073 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1075 elif len(args
) == 2:
1077 self
.netmask
= args
[1]
1079 raise TypeError("Too many arguments specified")
1082 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1086 def __call__(self
, value
):
1087 self
.__init
__(value
)
1091 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1093 def __eq__(self
, other
):
1094 if isinstance(other
, IpNetmask
):
1095 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1096 elif isinstance(other
, str):
1098 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1106 if self
.netmask
< 0 or self
.netmask
> 32:
1107 raise TypeError("invalid netmask %d" % netmask
)
1110 from _m5
.net
import IpNetmask
1111 return IpNetmask(self
.ip
, self
.netmask
)
1113 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1114 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1115 class IpWithPort(IpAddress
):
1116 cxx_type
= 'Net::IpWithPort'
1117 ex_str
= "127.0.0.1:80"
1118 cmd_line_settable
= True
1121 def cxx_predecls(cls
, code
):
1122 code('#include "base/inet.hh"')
1124 def __init__(self
, *args
, **kwargs
):
1125 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1127 setattr(self
, key
, kwargs
.pop(key
))
1129 setattr(self
, key
, elseVal
)
1131 raise TypeError("No value set for %s" % key
)
1134 handle_kwarg(self
, kwargs
, 'ip')
1135 handle_kwarg(self
, kwargs
, 'port')
1137 elif len(args
) == 1:
1139 if not 'ip' in kwargs
and not 'port' in kwargs
:
1140 raise TypeError("Invalid arguments")
1141 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1142 handle_kwarg(self
, kwargs
, 'port', args
[0])
1143 elif isinstance(args
[0], IpWithPort
):
1144 self
.ip
= args
[0].ip
1145 self
.port
= args
[0].port
1147 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1149 elif len(args
) == 2:
1153 raise TypeError("Too many arguments specified")
1156 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1160 def __call__(self
, value
):
1161 self
.__init
__(value
)
1165 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1167 def __eq__(self
, other
):
1168 if isinstance(other
, IpWithPort
):
1169 return self
.ip
== other
.ip
and self
.port
== other
.port
1170 elif isinstance(other
, str):
1172 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1180 if self
.port
< 0 or self
.port
> 0xffff:
1181 raise TypeError("invalid port %d" % self
.port
)
1184 from _m5
.net
import IpWithPort
1185 return IpWithPort(self
.ip
, self
.port
)
1187 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1188 "%a %b %d %H:%M:%S %Y",
1189 "%Y/%m/%d %H:%M:%S",
1192 "%m/%d/%Y %H:%M:%S",
1195 "%m/%d/%y %H:%M:%S",
1200 def parse_time(value
):
1201 from time
import gmtime
, strptime
, struct_time
, time
1202 from datetime
import datetime
, date
1204 if isinstance(value
, struct_time
):
1207 if isinstance(value
, (int, long)):
1208 return gmtime(value
)
1210 if isinstance(value
, (datetime
, date
)):
1211 return value
.timetuple()
1213 if isinstance(value
, str):
1214 if value
in ('Now', 'Today'):
1215 return time
.gmtime(time
.time())
1217 for format
in time_formats
:
1219 return strptime(value
, format
)
1223 raise ValueError("Could not parse '%s' as a time" % value
)
1225 class Time(ParamValue
):
1229 def cxx_predecls(cls
, code
):
1230 code('#include <time.h>')
1232 def __init__(self
, value
):
1233 self
.value
= parse_time(value
)
1235 def __call__(self
, value
):
1236 self
.__init
__(value
)
1240 from _m5
.core
import tm
1243 return tm
.gmtime(calendar
.timegm(self
.value
))
1246 return time
.asctime(self
.value
)
1251 def get_config_as_dict(self
):
1256 def cxx_ini_predecls(cls
, code
):
1257 code('#include <time.h>')
1260 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1261 code('char *_parse_ret = strptime((${src}).c_str(),')
1262 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1263 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1265 # Enumerated types are a little more complex. The user specifies the
1266 # type as Enum(foo) where foo is either a list or dictionary of
1267 # alternatives (typically strings, but not necessarily so). (In the
1268 # long run, the integer value of the parameter will be the list index
1269 # or the corresponding dictionary value. For now, since we only check
1270 # that the alternative is valid and then spit it into a .ini file,
1271 # there's not much point in using the dictionary.)
1273 # What Enum() must do is generate a new type encapsulating the
1274 # provided list/dictionary so that specific values of the parameter
1275 # can be instances of that type. We define two hidden internal
1276 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1277 # derive the new type from the appropriate base class on the fly.
1280 # Metaclass for Enum types
1281 class MetaEnum(MetaParamValue
):
1282 def __new__(mcls
, name
, bases
, dict):
1283 assert name
not in allEnums
1285 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1286 allEnums
[name
] = cls
1289 def __init__(cls
, name
, bases
, init_dict
):
1290 if 'map' in init_dict
:
1291 if not isinstance(cls
.map, dict):
1292 raise TypeError("Enum-derived class attribute 'map' " \
1293 "must be of type dict")
1294 # build list of value strings from map
1295 cls
.vals
= list(cls
.map.keys())
1297 elif 'vals' in init_dict
:
1298 if not isinstance(cls
.vals
, list):
1299 raise TypeError("Enum-derived class attribute 'vals' " \
1300 "must be of type list")
1301 # build string->value map from vals sequence
1303 for idx
,val
in enumerate(cls
.vals
):
1306 raise TypeError("Enum-derived class must define "\
1307 "attribute 'map' or 'vals'")
1310 cls
.cxx_type
= '%s' % name
1312 cls
.cxx_type
= 'Enums::%s' % name
1314 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1316 # Generate C++ class declaration for this enum type.
1317 # Note that we wrap the enum in a class/struct to act as a namespace,
1318 # so that the enum strings can be brief w/o worrying about collisions.
1319 def cxx_decl(cls
, code
):
1320 wrapper_name
= cls
.wrapper_name
1321 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1322 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1323 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1336 $wrapper $wrapper_name {
1341 for val
in cls
.vals
:
1342 code('$val = ${{cls.map[val]}},')
1343 code('Num_$name = ${{len(cls.vals)}}')
1349 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1351 elif cls
.wrapper_is_struct
:
1352 code('static const char *${name}Strings[Num_${name}];')
1354 code('extern const char *${name}Strings[Num_${name}];')
1356 if not cls
.is_class
:
1361 code('#endif // $idem_macro')
1363 def cxx_def(cls
, code
):
1364 wrapper_name
= cls
.wrapper_name
1365 file_name
= cls
.__name
__
1366 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1368 code('#include "enums/$file_name.hh"')
1369 if cls
.wrapper_is_struct
:
1370 code('const char *${wrapper_name}::${name}Strings'
1375 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1378 code('namespace Enums {')
1380 code('const char *${name}Strings[Num_${name}] =')
1384 for val
in cls
.vals
:
1389 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1391 code('} // namespace $wrapper_name')
1394 def pybind_def(cls
, code
):
1396 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1397 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1399 code('''#include "pybind11/pybind11.h"
1400 #include "pybind11/stl.h"
1402 #include <sim/init.hh>
1404 namespace py = pybind11;
1407 module_init(py::module &m_internal)
1409 py::module m = m_internal.def_submodule("enum_${name}");
1413 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1415 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1419 for val
in cls
.vals
:
1420 code('.value("${val}", ${wrapper_name}::${val})')
1421 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1422 code('.export_values()')
1429 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1432 # Base class for enum types.
1433 class Enum(ParamValue
):
1434 __metaclass__
= MetaEnum
1436 cmd_line_settable
= True
1438 # The name of the wrapping namespace or struct
1439 wrapper_name
= 'Enums'
1441 # If true, the enum is wrapped in a struct rather than a namespace
1442 wrapper_is_struct
= False
1446 # If not None, use this as the enum name rather than this class name
1449 def __init__(self
, value
):
1450 if value
not in self
.map:
1451 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1452 % (value
, self
.vals
))
1455 def __call__(self
, value
):
1456 self
.__init
__(value
)
1460 def cxx_predecls(cls
, code
):
1461 code('#include "enums/$0.hh"', cls
.__name
__)
1464 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1465 code('if (false) {')
1466 for elem_name
in cls
.map.keys():
1467 code('} else if (%s == "%s") {' % (src
, elem_name
))
1469 code('%s = Enums::%s;' % (dest
, elem_name
))
1470 code('%s true;' % ret
)
1473 code(' %s false;' % ret
)
1477 import m5
.internal
.params
1478 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1479 return e(self
.map[self
.value
])
1484 # This param will generate a scoped c++ enum and its python bindings.
1485 class ScopedEnum(Enum
):
1486 __metaclass__
= MetaEnum
1488 cmd_line_settable
= True
1490 # The name of the wrapping namespace or struct
1493 # If true, the enum is wrapped in a struct rather than a namespace
1494 wrapper_is_struct
= False
1496 # If true, the generated enum is a scoped enum
1499 # If not None, use this as the enum name rather than this class name
1502 # how big does a rounding error need to be before we warn about it?
1503 frequency_tolerance
= 0.001 # 0.1%
1505 class TickParamValue(NumericParamValue
):
1508 cmd_line_settable
= True
1511 def cxx_predecls(cls
, code
):
1512 code('#include "base/types.hh"')
1514 def __call__(self
, value
):
1515 self
.__init
__(value
)
1519 return long(self
.value
)
1522 def cxx_ini_predecls(cls
, code
):
1523 code('#include <sstream>')
1525 # Ticks are expressed in seconds in JSON files and in plain
1526 # Ticks in .ini files. Switch based on a config flag
1528 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1529 code('${ret} to_number(${src}, ${dest});')
1531 class Latency(TickParamValue
):
1534 def __init__(self
, value
):
1535 if isinstance(value
, (Latency
, Clock
)):
1536 self
.ticks
= value
.ticks
1537 self
.value
= value
.value
1538 elif isinstance(value
, Frequency
):
1539 self
.ticks
= value
.ticks
1540 self
.value
= 1.0 / value
.value
1541 elif value
.endswith('t'):
1543 self
.value
= int(value
[:-1])
1546 self
.value
= convert
.toLatency(value
)
1548 def __call__(self
, value
):
1549 self
.__init
__(value
)
1552 def __getattr__(self
, attr
):
1553 if attr
in ('latency', 'period'):
1555 if attr
== 'frequency':
1556 return Frequency(self
)
1557 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1560 if self
.ticks
or self
.value
== 0:
1563 value
= ticks
.fromSeconds(self
.value
)
1566 def config_value(self
):
1567 return self
.getValue()
1569 # convert latency to ticks
1571 return '%d' % self
.getValue()
1573 class Frequency(TickParamValue
):
1576 def __init__(self
, value
):
1577 if isinstance(value
, (Latency
, Clock
)):
1578 if value
.value
== 0:
1581 self
.value
= 1.0 / value
.value
1582 self
.ticks
= value
.ticks
1583 elif isinstance(value
, Frequency
):
1584 self
.value
= value
.value
1585 self
.ticks
= value
.ticks
1588 self
.value
= convert
.toFrequency(value
)
1590 def __call__(self
, value
):
1591 self
.__init
__(value
)
1594 def __getattr__(self
, attr
):
1595 if attr
== 'frequency':
1597 if attr
in ('latency', 'period'):
1598 return Latency(self
)
1599 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1601 # convert latency to ticks
1603 if self
.ticks
or self
.value
== 0:
1606 value
= ticks
.fromSeconds(1.0 / self
.value
)
1609 def config_value(self
):
1610 return self
.getValue()
1613 return '%d' % self
.getValue()
1615 # A generic Frequency and/or Latency value. Value is stored as a
1616 # latency, just like Latency and Frequency.
1617 class Clock(TickParamValue
):
1618 def __init__(self
, value
):
1619 if isinstance(value
, (Latency
, Clock
)):
1620 self
.ticks
= value
.ticks
1621 self
.value
= value
.value
1622 elif isinstance(value
, Frequency
):
1623 self
.ticks
= value
.ticks
1624 self
.value
= 1.0 / value
.value
1625 elif value
.endswith('t'):
1627 self
.value
= int(value
[:-1])
1630 self
.value
= convert
.anyToLatency(value
)
1632 def __call__(self
, value
):
1633 self
.__init
__(value
)
1637 return "%s" % Latency(self
)
1639 def __getattr__(self
, attr
):
1640 if attr
== 'frequency':
1641 return Frequency(self
)
1642 if attr
in ('latency', 'period'):
1643 return Latency(self
)
1644 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1647 return self
.period
.getValue()
1649 def config_value(self
):
1650 return self
.period
.config_value()
1653 return self
.period
.ini_str()
1655 class Voltage(Float
):
1658 def __new__(cls
, value
):
1659 value
= convert
.toVoltage(value
)
1660 return super(cls
, Voltage
).__new
__(cls
, value
)
1662 def __init__(self
, value
):
1663 value
= convert
.toVoltage(value
)
1664 super(Voltage
, self
).__init
__(value
)
1666 class Current(Float
):
1669 def __new__(cls
, value
):
1670 value
= convert
.toCurrent(value
)
1671 return super(cls
, Current
).__new
__(cls
, value
)
1673 def __init__(self
, value
):
1674 value
= convert
.toCurrent(value
)
1675 super(Current
, self
).__init
__(value
)
1677 class Energy(Float
):
1680 def __new__(cls
, value
):
1681 value
= convert
.toEnergy(value
)
1682 return super(cls
, Energy
).__new
__(cls
, value
)
1684 def __init__(self
, value
):
1685 value
= convert
.toEnergy(value
)
1686 super(Energy
, self
).__init
__(value
)
1688 class NetworkBandwidth(float,ParamValue
):
1691 cmd_line_settable
= True
1693 def __new__(cls
, value
):
1694 # convert to bits per second
1695 val
= convert
.toNetworkBandwidth(value
)
1696 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1699 return str(self
.val
)
1701 def __call__(self
, value
):
1702 val
= convert
.toNetworkBandwidth(value
)
1707 # convert to seconds per byte
1708 value
= 8.0 / float(self
)
1709 # convert to ticks per byte
1710 value
= ticks
.fromSeconds(value
)
1714 return '%f' % self
.getValue()
1716 def config_value(self
):
1717 return '%f' % self
.getValue()
1720 def cxx_ini_predecls(cls
, code
):
1721 code('#include <sstream>')
1724 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1725 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1727 class MemoryBandwidth(float,ParamValue
):
1730 cmd_line_settable
= True
1732 def __new__(cls
, value
):
1733 # convert to bytes per second
1734 val
= convert
.toMemoryBandwidth(value
)
1735 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1737 def __call__(self
, value
):
1738 val
= convert
.toMemoryBandwidth(value
)
1743 # convert to seconds per byte
1746 value
= 1.0 / float(self
)
1747 # convert to ticks per byte
1748 value
= ticks
.fromSeconds(value
)
1752 return '%f' % self
.getValue()
1754 def config_value(self
):
1755 return '%f' % self
.getValue()
1758 def cxx_ini_predecls(cls
, code
):
1759 code('#include <sstream>')
1762 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1763 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1766 # "Constants"... handy aliases for various values.
1769 # Special class for NULL pointers. Note the special check in
1770 # make_param_value() above that lets these be assigned where a
1771 # SimObject is required.
1772 # only one copy of a particular node
1773 class NullSimObject(object):
1774 __metaclass__
= Singleton
1780 def _instantiate(self
, parent
= None, path
= ''):
1786 def unproxy(self
, base
):
1789 def set_path(self
, parent
, name
):
1792 def set_parent(self
, parent
, name
):
1795 def clear_parent(self
, old_parent
):
1798 def descendants(self
):
1802 def get_config_as_dict(self
):
1808 def config_value(self
):
1814 # The only instance you'll ever need...
1815 NULL
= NullSimObject()
1817 def isNullPointer(value
):
1818 return isinstance(value
, NullSimObject
)
1820 # Some memory range specifications use this as a default upper bound.
1823 AllMemory
= AddrRange(0, MaxAddr
)
1826 #####################################################################
1830 # Ports are used to interconnect objects in the memory system.
1832 #####################################################################
1834 # Port reference: encapsulates a reference to a particular port on a
1835 # particular SimObject.
1836 class PortRef(object):
1837 def __init__(self
, simobj
, name
, role
):
1838 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1839 self
.simobj
= simobj
1842 self
.peer
= None # not associated with another port yet
1843 self
.ccConnected
= False # C++ port connection done?
1844 self
.index
= -1 # always -1 for non-vector ports
1847 return '%s.%s' % (self
.simobj
, self
.name
)
1850 # Return the number of connected ports, i.e. 0 is we have no
1851 # peer and 1 if we do.
1852 return int(self
.peer
!= None)
1854 # for config.ini, print peer's name (not ours)
1856 return str(self
.peer
)
1859 def get_config_as_dict(self
):
1860 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1862 def __getattr__(self
, attr
):
1863 if attr
== 'peerObj':
1864 # shorthand for proxies
1865 return self
.peer
.simobj
1866 raise AttributeError("'%s' object has no attribute '%s'" % \
1867 (self
.__class
__.__name
__, attr
))
1869 # Full connection is symmetric (both ways). Called via
1870 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1871 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1872 # e.g., "obj1.portA[3] = obj2.portB".
1873 def connect(self
, other
):
1874 if isinstance(other
, VectorPortRef
):
1875 # reference to plain VectorPort is implicit append
1876 other
= other
._get
_next
()
1877 if self
.peer
and not proxy
.isproxy(self
.peer
):
1878 fatal("Port %s is already connected to %s, cannot connect %s\n",
1879 self
, self
.peer
, other
);
1881 if proxy
.isproxy(other
):
1882 other
.set_param_desc(PortParamDesc())
1883 elif isinstance(other
, PortRef
):
1884 if other
.peer
is not self
:
1887 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1890 # Allow a master/slave port pair to be spliced between
1891 # a port and its connected peer. Useful operation for connecting
1892 # instrumentation structures into a system when it is necessary
1893 # to connect the instrumentation after the full system has been
1895 def splice(self
, new_master_peer
, new_slave_peer
):
1896 if not self
.peer
or proxy
.isproxy(self
.peer
):
1897 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1899 if not isinstance(new_master_peer
, PortRef
) or \
1900 not isinstance(new_slave_peer
, PortRef
):
1902 "Splicing non-port references '%s','%s' to port '%s'" % \
1903 (new_master_peer
, new_slave_peer
, self
))
1905 old_peer
= self
.peer
1906 if self
.role
== 'SLAVE':
1907 self
.peer
= new_master_peer
1908 old_peer
.peer
= new_slave_peer
1909 new_master_peer
.connect(self
)
1910 new_slave_peer
.connect(old_peer
)
1911 elif self
.role
== 'MASTER':
1912 self
.peer
= new_slave_peer
1913 old_peer
.peer
= new_master_peer
1914 new_slave_peer
.connect(self
)
1915 new_master_peer
.connect(old_peer
)
1917 panic("Port %s has unknown role, "+\
1918 "cannot splice in new peers\n", self
)
1920 def clone(self
, simobj
, memo
):
1923 newRef
= copy
.copy(self
)
1925 newRef
.simobj
= simobj
1926 assert(isSimObject(newRef
.simobj
))
1927 if self
.peer
and not proxy
.isproxy(self
.peer
):
1928 peerObj
= self
.peer
.simobj(_memo
=memo
)
1929 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1930 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1933 def unproxy(self
, simobj
):
1934 assert(simobj
is self
.simobj
)
1935 if proxy
.isproxy(self
.peer
):
1937 realPeer
= self
.peer
.unproxy(self
.simobj
)
1939 print("Error in unproxying port '%s' of %s" %
1940 (self
.name
, self
.simobj
.path()))
1942 self
.connect(realPeer
)
1944 # Call C++ to create corresponding port connection between C++ objects
1945 def ccConnect(self
):
1946 from _m5
.pyobject
import connectPorts
1948 if self
.ccConnected
: # already done this
1952 if not self
.peer
: # nothing to connect to
1955 # check that we connect a master to a slave
1956 if self
.role
== peer
.role
:
1958 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1959 (peer
, self
, self
.role
))
1961 if self
.role
== 'SLAVE':
1962 # do nothing and let the master take care of it
1966 # self is always the master and peer the slave
1967 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1968 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1970 print("Error connecting port %s.%s to %s.%s" %
1971 (self
.simobj
.path(), self
.name
,
1972 peer
.simobj
.path(), peer
.name
))
1974 self
.ccConnected
= True
1975 peer
.ccConnected
= True
1977 # A reference to an individual element of a VectorPort... much like a
1978 # PortRef, but has an index.
1979 class VectorPortElementRef(PortRef
):
1980 def __init__(self
, simobj
, name
, role
, index
):
1981 PortRef
.__init
__(self
, simobj
, name
, role
)
1985 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1987 # A reference to a complete vector-valued port (not just a single element).
1988 # Can be indexed to retrieve individual VectorPortElementRef instances.
1989 class VectorPortRef(object):
1990 def __init__(self
, simobj
, name
, role
):
1991 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1992 self
.simobj
= simobj
1998 return '%s.%s[:]' % (self
.simobj
, self
.name
)
2001 # Return the number of connected peers, corresponding the the
2002 # length of the elements.
2003 return len(self
.elements
)
2005 # for config.ini, print peer's name (not ours)
2007 return ' '.join([el
.ini_str() for el
in self
.elements
])
2010 def get_config_as_dict(self
):
2011 return {'role' : self
.role
,
2012 'peer' : [el
.ini_str() for el
in self
.elements
]}
2014 def __getitem__(self
, key
):
2015 if not isinstance(key
, int):
2016 raise TypeError("VectorPort index must be integer")
2017 if key
>= len(self
.elements
):
2018 # need to extend list
2019 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
2020 for i
in range(len(self
.elements
), key
+1)]
2021 self
.elements
.extend(ext
)
2022 return self
.elements
[key
]
2024 def _get_next(self
):
2025 return self
[len(self
.elements
)]
2027 def __setitem__(self
, key
, value
):
2028 if not isinstance(key
, int):
2029 raise TypeError("VectorPort index must be integer")
2030 self
[key
].connect(value
)
2032 def connect(self
, other
):
2033 if isinstance(other
, (list, tuple)):
2034 # Assign list of port refs to vector port.
2035 # For now, append them... not sure if that's the right semantics
2036 # or if it should replace the current vector.
2038 self
._get
_next
().connect(ref
)
2040 # scalar assignment to plain VectorPort is implicit append
2041 self
._get
_next
().connect(other
)
2043 def clone(self
, simobj
, memo
):
2046 newRef
= copy
.copy(self
)
2048 newRef
.simobj
= simobj
2049 assert(isSimObject(newRef
.simobj
))
2050 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2053 def unproxy(self
, simobj
):
2054 [el
.unproxy(simobj
) for el
in self
.elements
]
2056 def ccConnect(self
):
2057 [el
.ccConnect() for el
in self
.elements
]
2059 # Port description object. Like a ParamDesc object, this represents a
2060 # logical port in the SimObject class, not a particular port on a
2061 # SimObject instance. The latter are represented by PortRef objects.
2063 # Generate a PortRef for this port on the given SimObject with the
2065 def makeRef(self
, simobj
):
2066 return PortRef(simobj
, self
.name
, self
.role
)
2068 # Connect an instance of this port (on the given SimObject with
2069 # the given name) with the port described by the supplied PortRef
2070 def connect(self
, simobj
, ref
):
2071 self
.makeRef(simobj
).connect(ref
)
2073 # No need for any pre-declarations at the moment as we merely rely
2074 # on an unsigned int.
2075 def cxx_predecls(self
, code
):
2078 def pybind_predecls(self
, code
):
2079 cls
.cxx_predecls(self
, code
)
2081 # Declare an unsigned int with the same name as the port, that
2082 # will eventually hold the number of connected ports (and thus the
2083 # number of elements for a VectorPort).
2084 def cxx_decl(self
, code
):
2085 code('unsigned int port_${{self.name}}_connection_count;')
2087 class MasterPort(Port
):
2088 # MasterPort("description")
2089 def __init__(self
, *args
):
2092 self
.role
= 'MASTER'
2094 raise TypeError('wrong number of arguments')
2096 class SlavePort(Port
):
2097 # SlavePort("description")
2098 def __init__(self
, *args
):
2103 raise TypeError('wrong number of arguments')
2105 # VectorPort description object. Like Port, but represents a vector
2106 # of connections (e.g., as on a XBar).
2107 class VectorPort(Port
):
2108 def __init__(self
, *args
):
2111 def makeRef(self
, simobj
):
2112 return VectorPortRef(simobj
, self
.name
, self
.role
)
2114 class VectorMasterPort(VectorPort
):
2115 # VectorMasterPort("description")
2116 def __init__(self
, *args
):
2119 self
.role
= 'MASTER'
2120 VectorPort
.__init
__(self
, *args
)
2122 raise TypeError('wrong number of arguments')
2124 class VectorSlavePort(VectorPort
):
2125 # VectorSlavePort("description")
2126 def __init__(self
, *args
):
2130 VectorPort
.__init
__(self
, *args
)
2132 raise TypeError('wrong number of arguments')
2134 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2135 # proxy objects (via set_param_desc()) so that proxy error messages
2137 class PortParamDesc(object):
2138 __metaclass__
= Singleton
2143 baseEnums
= allEnums
.copy()
2144 baseParams
= allParams
.copy()
2147 global allEnums
, allParams
2149 allEnums
= baseEnums
.copy()
2150 allParams
= baseParams
.copy()
2152 __all__
= ['Param', 'VectorParam',
2153 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2154 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2155 'Int32', 'UInt32', 'Int64', 'UInt64',
2156 'Counter', 'Addr', 'Tick', 'Percent',
2157 'TcpPort', 'UdpPort', 'EthernetAddr',
2158 'IpAddress', 'IpNetmask', 'IpWithPort',
2159 'MemorySize', 'MemorySize32',
2160 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2161 'NetworkBandwidth', 'MemoryBandwidth',
2163 'MaxAddr', 'MaxTick', 'AllMemory',
2165 'NextEthernetAddr', 'NULL',
2166 'MasterPort', 'SlavePort',
2167 'VectorMasterPort', 'VectorSlavePort']