729fc1242af5a3a78d6c6c9091a8f75e75f504e1
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
75 def isSimObject(*args
, **kwargs
):
76 return SimObject
.isSimObject(*args
, **kwargs
)
78 def isSimObjectSequence(*args
, **kwargs
):
79 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
81 def isSimObjectClass(*args
, **kwargs
):
82 return SimObject
.isSimObjectClass(*args
, **kwargs
)
86 class MetaParamValue(type):
87 def __new__(mcls
, name
, bases
, dct
):
88 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
89 assert name
not in allParams
94 # Dummy base class to identify types that are legitimate for SimObject
96 class ParamValue(object):
97 __metaclass__
= MetaParamValue
98 cmd_line_settable
= False
100 # Generate the code needed as a prerequisite for declaring a C++
101 # object of this type. Typically generates one or more #include
102 # statements. Used when declaring parameters of this type.
104 def cxx_predecls(cls
, code
):
108 def pybind_predecls(cls
, code
):
109 cls
.cxx_predecls(code
)
111 # default for printing to .ini file is regular string conversion.
112 # will be overridden in some cases
116 # default for printing to .json file is regular string conversion.
117 # will be overridden in some cases, mostly to use native Python
118 # types where there are similar JSON types
119 def config_value(self
):
122 # Prerequisites for .ini parsing with cxx_ini_parse
124 def cxx_ini_predecls(cls
, code
):
127 # parse a .ini file entry for this param from string expression
128 # src into lvalue dest (of the param's C++ type)
130 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
131 code('// Unhandled param type: %s' % cls
.__name
__)
132 code('%s false;' % ret
)
134 # allows us to blithely call unproxy() on things without checking
135 # if they're really proxies or not
136 def unproxy(self
, base
):
139 # Produce a human readable version of the stored value
140 def pretty_print(self
, value
):
143 # Regular parameter description.
144 class ParamDesc(object):
145 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
146 self
.ptype_str
= ptype_str
147 # remember ptype only if it is provided
155 self
.default
= args
[0]
158 raise TypeError('too many arguments')
161 assert(not hasattr(self
, 'desc'))
162 self
.desc
= kwargs
['desc']
165 if 'default' in kwargs
:
166 assert(not hasattr(self
, 'default'))
167 self
.default
= kwargs
['default']
168 del kwargs
['default']
171 raise TypeError('extra unknown kwargs %s' % kwargs
)
173 if not hasattr(self
, 'desc'):
174 raise TypeError('desc attribute missing')
176 def __getattr__(self
, attr
):
178 ptype
= SimObject
.allClasses
[self
.ptype_str
]
179 assert isSimObjectClass(ptype
)
183 raise AttributeError("'%s' object has no attribute '%s'" % \
184 (type(self
).__name
__, attr
))
186 def example_str(self
):
187 if hasattr(self
.ptype
, "ex_str"):
188 return self
.ptype
.ex_str
190 return self
.ptype_str
192 # Is the param available to be exposed on the command line
193 def isCmdLineSettable(self
):
194 if hasattr(self
.ptype
, "cmd_line_settable"):
195 return self
.ptype
.cmd_line_settable
199 def convert(self
, value
):
200 if isinstance(value
, proxy
.BaseProxy
):
201 value
.set_param_desc(self
)
203 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
204 # deferred evaluation of SimObject; continue to defer if
205 # we're just assigning a null pointer
207 if isinstance(value
, self
.ptype
):
209 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
211 return self
.ptype(value
)
213 def pretty_print(self
, value
):
214 if isinstance(value
, proxy
.BaseProxy
):
216 if isNullPointer(value
):
218 return self
.ptype(value
).pretty_print(value
)
220 def cxx_predecls(self
, code
):
221 code('#include <cstddef>')
222 self
.ptype
.cxx_predecls(code
)
224 def pybind_predecls(self
, code
):
225 self
.ptype
.pybind_predecls(code
)
227 def cxx_decl(self
, code
):
228 code('${{self.ptype.cxx_type}} ${{self.name}};')
230 # Vector-valued parameter description. Just like ParamDesc, except
231 # that the value is a vector (list) of the specified type instead of a
234 class VectorParamValue(list):
235 __metaclass__
= MetaParamValue
236 def __setattr__(self
, attr
, value
):
237 raise AttributeError("Not allowed to set %s on '%s'" % \
238 (attr
, type(self
).__name
__))
240 def config_value(self
):
241 return [v
.config_value() for v
in self
]
244 return ' '.join([v
.ini_str() for v
in self
])
247 return [ v
.getValue() for v
in self
]
249 def unproxy(self
, base
):
250 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
251 # The value is a proxy (e.g. Parent.any, Parent.all or
252 # Parent.x) therefore try resolve it
253 return self
[0].unproxy(base
)
255 return [v
.unproxy(base
) for v
in self
]
257 class SimObjectVector(VectorParamValue
):
258 # support clone operation
259 def __call__(self
, **kwargs
):
260 return SimObjectVector([v(**kwargs
) for v
in self
])
262 def clear_parent(self
, old_parent
):
264 v
.clear_parent(old_parent
)
266 def set_parent(self
, parent
, name
):
268 self
[0].set_parent(parent
, name
)
270 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
271 for i
,v
in enumerate(self
):
272 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
274 def has_parent(self
):
275 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
277 # return 'cpu0 cpu1' etc. for print_ini()
279 return ' '.join([v
._name
for v
in self
])
281 # By iterating through the constituent members of the vector here
282 # we can nicely handle iterating over all a SimObject's children
283 # without having to provide lots of special functions on
284 # SimObjectVector directly.
285 def descendants(self
):
287 for obj
in v
.descendants():
290 def get_config_as_dict(self
):
293 a
.append(v
.get_config_as_dict())
296 # If we are replacing an item in the vector, make sure to set the
297 # parent reference of the new SimObject to be the same as the parent
298 # of the SimObject being replaced. Useful to have if we created
299 # a SimObjectVector of temporary objects that will be modified later in
300 # configuration scripts.
301 def __setitem__(self
, key
, value
):
303 if value
.has_parent():
304 warn("SimObject %s already has a parent" % value
.get_name() +\
305 " that is being overwritten by a SimObjectVector")
306 value
.set_parent(val
.get_parent(), val
._name
)
307 super(SimObjectVector
, self
).__setitem
__(key
, value
)
309 # Enumerate the params of each member of the SimObject vector. Creates
310 # strings that will allow indexing into the vector by the python code and
311 # allow it to be specified on the command line.
312 def enumerateParams(self
, flags_dict
= {},
315 if hasattr(self
, "_paramEnumed"):
316 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
320 # Each entry in the SimObjectVector should be an
321 # instance of a SimObject
322 flags_dict
= vals
.enumerateParams(flags_dict
,
323 cmd_line_str
+ "%d." % x
,
324 access_str
+ "[%d]." % x
)
329 class VectorParamDesc(ParamDesc
):
330 # Convert assigned value to appropriate type. If the RHS is not a
331 # list or tuple, it generates a single-element list.
332 def convert(self
, value
):
333 if isinstance(value
, (list, tuple)):
334 # list: coerce each element into new list
335 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
336 elif isinstance(value
, str):
337 # If input is a csv string
338 tmp_list
= [ ParamDesc
.convert(self
, v
) \
339 for v
in value
.strip('[').strip(']').split(',') ]
341 # singleton: coerce to a single-element list
342 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
344 if isSimObjectSequence(tmp_list
):
345 return SimObjectVector(tmp_list
)
347 return VectorParamValue(tmp_list
)
349 # Produce a human readable example string that describes
350 # how to set this vector parameter in the absence of a default
352 def example_str(self
):
353 s
= super(VectorParamDesc
, self
).example_str()
354 help_str
= "[" + s
+ "," + s
+ ", ...]"
357 # Produce a human readable representation of the value of this vector param.
358 def pretty_print(self
, value
):
359 if isinstance(value
, (list, tuple)):
360 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
361 elif isinstance(value
, str):
362 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
364 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
368 # This is a helper function for the new config system
369 def __call__(self
, value
):
370 if isinstance(value
, (list, tuple)):
371 # list: coerce each element into new list
372 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
373 elif isinstance(value
, str):
374 # If input is a csv string
375 tmp_list
= [ ParamDesc
.convert(self
, v
) \
376 for v
in value
.strip('[').strip(']').split(',') ]
378 # singleton: coerce to a single-element list
379 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
381 return VectorParamValue(tmp_list
)
383 def cxx_predecls(self
, code
):
384 code('#include <vector>')
385 self
.ptype
.cxx_predecls(code
)
387 def pybind_predecls(self
, code
):
388 code('#include <vector>')
389 self
.ptype
.pybind_predecls(code
)
391 def cxx_decl(self
, code
):
392 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
394 class ParamFactory(object):
395 def __init__(self
, param_desc_class
, ptype_str
= None):
396 self
.param_desc_class
= param_desc_class
397 self
.ptype_str
= ptype_str
399 def __getattr__(self
, attr
):
401 attr
= self
.ptype_str
+ '.' + attr
402 return ParamFactory(self
.param_desc_class
, attr
)
404 # E.g., Param.Int(5, "number of widgets")
405 def __call__(self
, *args
, **kwargs
):
408 ptype
= allParams
[self
.ptype_str
]
410 # if name isn't defined yet, assume it's a SimObject, and
411 # try to resolve it later
413 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
415 Param
= ParamFactory(ParamDesc
)
416 VectorParam
= ParamFactory(VectorParamDesc
)
418 #####################################################################
422 # Though native Python types could be used to specify parameter types
423 # (the 'ptype' field of the Param and VectorParam classes), it's more
424 # flexible to define our own set of types. This gives us more control
425 # over how Python expressions are converted to values (via the
426 # __init__() constructor) and how these values are printed out (via
427 # the __str__() conversion method).
429 #####################################################################
431 # String-valued parameter. Just mixin the ParamValue class with the
432 # built-in str class.
433 class String(ParamValue
,str):
434 cxx_type
= 'std::string'
435 cmd_line_settable
= True
438 def cxx_predecls(self
, code
):
439 code('#include <string>')
441 def __call__(self
, value
):
446 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
447 code('%s = %s;' % (dest
, src
))
448 code('%s true;' % ret
)
453 # superclass for "numeric" parameter values, to emulate math
454 # operations in a type-safe way. e.g., a Latency times an int returns
455 # a new Latency object.
456 class NumericParamValue(ParamValue
):
459 return v
.value
if isinstance(v
, NumericParamValue
) else v
462 return str(self
.value
)
465 return float(self
.value
)
468 return long(self
.value
)
471 return int(self
.value
)
473 # hook for bounds checking
477 def __mul__(self
, other
):
478 newobj
= self
.__class
__(self
)
479 newobj
.value
*= NumericParamValue
.unwrap(other
)
485 def __truediv__(self
, other
):
486 newobj
= self
.__class
__(self
)
487 newobj
.value
/= NumericParamValue
.unwrap(other
)
491 def __floordiv__(self
, other
):
492 newobj
= self
.__class
__(self
)
493 newobj
.value
//= NumericParamValue
.unwrap(other
)
498 def __add__(self
, other
):
499 newobj
= self
.__class
__(self
)
500 newobj
.value
+= NumericParamValue
.unwrap(other
)
504 def __sub__(self
, other
):
505 newobj
= self
.__class
__(self
)
506 newobj
.value
-= NumericParamValue
.unwrap(other
)
510 def __iadd__(self
, other
):
511 self
.value
+= NumericParamValue
.unwrap(other
)
515 def __isub__(self
, other
):
516 self
.value
-= NumericParamValue
.unwrap(other
)
520 def __imul__(self
, other
):
521 self
.value
*= NumericParamValue
.unwrap(other
)
525 def __itruediv__(self
, other
):
526 self
.value
/= NumericParamValue
.unwrap(other
)
530 def __ifloordiv__(self
, other
):
531 self
.value
//= NumericParamValue
.unwrap(other
)
535 def __lt__(self
, other
):
536 return self
.value
< NumericParamValue
.unwrap(other
)
538 # Python 2.7 pre __future__.division operators
539 # TODO: Remove these when after "import division from __future__"
540 __div__
= __truediv__
541 __idiv__
= __itruediv__
543 def config_value(self
):
547 def cxx_ini_predecls(cls
, code
):
548 # Assume that base/str.hh will be included anyway
549 # code('#include "base/str.hh"')
552 # The default for parsing PODs from an .ini entry is to extract from an
553 # istringstream and let overloading choose the right type according to
556 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
557 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
559 # Metaclass for bounds-checked integer parameters. See CheckedInt.
560 class CheckedIntType(MetaParamValue
):
561 def __init__(cls
, name
, bases
, dict):
562 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
564 # CheckedInt is an abstract base class, so we actually don't
565 # want to do any processing on it... the rest of this code is
566 # just for classes that derive from CheckedInt.
567 if name
== 'CheckedInt':
570 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
571 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
572 panic("CheckedInt subclass %s must define either\n" \
573 " 'min' and 'max' or 'size' and 'unsigned'\n",
577 cls
.max = 2 ** cls
.size
- 1
579 cls
.min = -(2 ** (cls
.size
- 1))
580 cls
.max = (2 ** (cls
.size
- 1)) - 1
582 # Abstract superclass for bounds-checked integer parameters. This
583 # class is subclassed to generate parameter classes with specific
584 # bounds. Initialization of the min and max bounds is done in the
585 # metaclass CheckedIntType.__init__.
586 class CheckedInt(NumericParamValue
):
587 __metaclass__
= CheckedIntType
588 cmd_line_settable
= True
591 if not self
.min <= self
.value
<= self
.max:
592 raise TypeError('Integer param out of bounds %d < %d < %d' % \
593 (self
.min, self
.value
, self
.max))
595 def __init__(self
, value
):
596 if isinstance(value
, str):
597 self
.value
= convert
.toInteger(value
)
598 elif isinstance(value
, (int, long, float, NumericParamValue
)):
599 self
.value
= long(value
)
601 raise TypeError("Can't convert object of type %s to CheckedInt" \
602 % type(value
).__name
__)
605 def __call__(self
, value
):
610 def cxx_predecls(cls
, code
):
611 # most derived types require this, so we just do it here once
612 code('#include "base/types.hh"')
615 return long(self
.value
)
617 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
618 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
620 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
621 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
622 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
623 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
624 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
625 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
626 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
627 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
629 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
630 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
631 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
632 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
634 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
636 class Cycles(CheckedInt
):
642 from _m5
.core
import Cycles
643 return Cycles(self
.value
)
646 def cxx_ini_predecls(cls
, code
):
647 # Assume that base/str.hh will be included anyway
648 # code('#include "base/str.hh"')
652 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
653 code('uint64_t _temp;')
654 code('bool _ret = to_number(%s, _temp);' % src
)
656 code(' %s = Cycles(_temp);' % dest
)
657 code('%s _ret;' % ret
)
659 class Float(ParamValue
, float):
661 cmd_line_settable
= True
663 def __init__(self
, value
):
664 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
665 self
.value
= float(value
)
667 raise TypeError("Can't convert object of type %s to Float" \
668 % type(value
).__name
__)
670 def __call__(self
, value
):
675 return float(self
.value
)
677 def config_value(self
):
681 def cxx_ini_predecls(cls
, code
):
682 code('#include <sstream>')
685 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
686 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
688 class MemorySize(CheckedInt
):
689 cxx_type
= 'uint64_t'
693 def __init__(self
, value
):
694 if isinstance(value
, MemorySize
):
695 self
.value
= value
.value
697 self
.value
= convert
.toMemorySize(value
)
700 class MemorySize32(CheckedInt
):
701 cxx_type
= 'uint32_t'
705 def __init__(self
, value
):
706 if isinstance(value
, MemorySize
):
707 self
.value
= value
.value
709 self
.value
= convert
.toMemorySize(value
)
712 class Addr(CheckedInt
):
716 def __init__(self
, value
):
717 if isinstance(value
, Addr
):
718 self
.value
= value
.value
721 # Often addresses are referred to with sizes. Ex: A device
722 # base address is at "512MB". Use toMemorySize() to convert
723 # these into addresses. If the address is not specified with a
724 # "size", an exception will occur and numeric translation will
726 self
.value
= convert
.toMemorySize(value
)
727 except (TypeError, ValueError):
728 # Convert number to string and use long() to do automatic
729 # base conversion (requires base=0 for auto-conversion)
730 self
.value
= long(str(value
), base
=0)
733 def __add__(self
, other
):
734 if isinstance(other
, Addr
):
735 return self
.value
+ other
.value
737 return self
.value
+ other
738 def pretty_print(self
, value
):
740 val
= convert
.toMemorySize(value
)
743 return "0x%x" % long(val
)
745 class AddrRange(ParamValue
):
746 cxx_type
= 'AddrRange'
748 def __init__(self
, *args
, **kwargs
):
749 # Disable interleaving and hashing by default
750 self
.intlvHighBit
= 0
755 def handle_kwargs(self
, kwargs
):
756 # An address range needs to have an upper limit, specified
757 # either explicitly with an end, or as an offset using the
760 self
.end
= Addr(kwargs
.pop('end'))
761 elif 'size' in kwargs
:
762 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
764 raise TypeError("Either end or size must be specified")
766 # Now on to the optional bit
767 if 'intlvHighBit' in kwargs
:
768 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
769 if 'xorHighBit' in kwargs
:
770 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
771 if 'intlvBits' in kwargs
:
772 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
773 if 'intlvMatch' in kwargs
:
774 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
777 self
.start
= Addr(kwargs
.pop('start'))
778 handle_kwargs(self
, kwargs
)
782 self
.start
= Addr(args
[0])
783 handle_kwargs(self
, kwargs
)
784 elif isinstance(args
[0], (list, tuple)):
785 self
.start
= Addr(args
[0][0])
786 self
.end
= Addr(args
[0][1])
789 self
.end
= Addr(args
[0]) - 1
792 self
.start
= Addr(args
[0])
793 self
.end
= Addr(args
[1])
795 raise TypeError("Too many arguments specified")
798 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
801 return '%s:%s:%s:%s:%s:%s' \
802 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
803 self
.intlvBits
, self
.intlvMatch
)
806 # Divide the size by the size of the interleaving slice
807 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
810 def cxx_predecls(cls
, code
):
811 Addr
.cxx_predecls(code
)
812 code('#include "base/addr_range.hh"')
815 def pybind_predecls(cls
, code
):
816 Addr
.pybind_predecls(code
)
817 code('#include "base/addr_range.hh"')
820 def cxx_ini_predecls(cls
, code
):
821 code('#include <sstream>')
824 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
825 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
826 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
828 code('std::istringstream _stream(${src});')
829 code('_stream >> _start;')
830 code('_stream.get(_sep);')
831 code('_stream >> _end;')
832 code('if (!_stream.fail() && !_stream.eof()) {')
833 code(' _stream.get(_sep);')
834 code(' _stream >> _intlvHighBit;')
835 code(' _stream.get(_sep);')
836 code(' _stream >> _xorHighBit;')
837 code(' _stream.get(_sep);')
838 code(' _stream >> _intlvBits;')
839 code(' _stream.get(_sep);')
840 code(' _stream >> _intlvMatch;')
842 code('bool _ret = !_stream.fail() &&'
843 '_stream.eof() && _sep == \':\';')
845 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
846 _xorHighBit, _intlvBits, _intlvMatch);')
850 # Go from the Python class to the wrapped C++ class
851 from _m5
.range import AddrRange
853 return AddrRange(long(self
.start
), long(self
.end
),
854 int(self
.intlvHighBit
), int(self
.xorHighBit
),
855 int(self
.intlvBits
), int(self
.intlvMatch
))
857 # Boolean parameter type. Python doesn't let you subclass bool, since
858 # it doesn't want to let you create multiple instances of True and
859 # False. Thus this is a little more complicated than String.
860 class Bool(ParamValue
):
862 cmd_line_settable
= True
864 def __init__(self
, value
):
866 self
.value
= convert
.toBool(value
)
868 self
.value
= bool(value
)
870 def __call__(self
, value
):
875 return bool(self
.value
)
878 return str(self
.value
)
880 # implement truth value testing for Bool parameters so that these params
881 # evaluate correctly during the python configuration phase
883 return bool(self
.value
)
885 # Python 2.7 uses __nonzero__ instead of __bool__
886 __nonzero__
= __bool__
893 def config_value(self
):
897 def cxx_ini_predecls(cls
, code
):
898 # Assume that base/str.hh will be included anyway
899 # code('#include "base/str.hh"')
903 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
904 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
906 def IncEthernetAddr(addr
, val
= 1):
907 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
909 for i
in (5, 4, 3, 2, 1):
910 val
,rem
= divmod(bytes
[i
], 256)
915 assert(bytes
[0] <= 255)
916 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
918 _NextEthernetAddr
= "00:90:00:00:00:01"
919 def NextEthernetAddr():
920 global _NextEthernetAddr
922 value
= _NextEthernetAddr
923 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
926 class EthernetAddr(ParamValue
):
927 cxx_type
= 'Net::EthAddr'
928 ex_str
= "00:90:00:00:00:01"
929 cmd_line_settable
= True
932 def cxx_predecls(cls
, code
):
933 code('#include "base/inet.hh"')
935 def __init__(self
, value
):
936 if value
== NextEthernetAddr
:
940 if not isinstance(value
, str):
941 raise TypeError("expected an ethernet address and didn't get one")
943 bytes
= value
.split(':')
945 raise TypeError('invalid ethernet address %s' % value
)
948 if not 0 <= int(byte
, base
=16) <= 0xff:
949 raise TypeError('invalid ethernet address %s' % value
)
953 def __call__(self
, value
):
957 def unproxy(self
, base
):
958 if self
.value
== NextEthernetAddr
:
959 return EthernetAddr(self
.value())
963 from _m5
.net
import EthAddr
964 return EthAddr(self
.value
)
973 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
974 code('%s = Net::EthAddr(%s);' % (dest
, src
))
975 code('%s true;' % ret
)
977 # When initializing an IpAddress, pass in an existing IpAddress, a string of
978 # the form "a.b.c.d", or an integer representing an IP.
979 class IpAddress(ParamValue
):
980 cxx_type
= 'Net::IpAddress'
982 cmd_line_settable
= True
985 def cxx_predecls(cls
, code
):
986 code('#include "base/inet.hh"')
988 def __init__(self
, value
):
989 if isinstance(value
, IpAddress
):
993 self
.ip
= convert
.toIpAddress(value
)
995 self
.ip
= long(value
)
998 def __call__(self
, value
):
1003 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1004 return '%d.%d.%d.%d' % tuple(tup
)
1006 def __eq__(self
, other
):
1007 if isinstance(other
, IpAddress
):
1008 return self
.ip
== other
.ip
1009 elif isinstance(other
, str):
1011 return self
.ip
== convert
.toIpAddress(other
)
1015 return self
.ip
== other
1017 def __ne__(self
, other
):
1018 return not (self
== other
)
1021 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1022 raise TypeError("invalid ip address %#08x" % self
.ip
)
1025 from _m5
.net
import IpAddress
1026 return IpAddress(self
.ip
)
1028 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1029 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1030 # positional or keyword arguments.
1031 class IpNetmask(IpAddress
):
1032 cxx_type
= 'Net::IpNetmask'
1033 ex_str
= "127.0.0.0/24"
1034 cmd_line_settable
= True
1037 def cxx_predecls(cls
, code
):
1038 code('#include "base/inet.hh"')
1040 def __init__(self
, *args
, **kwargs
):
1041 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1043 setattr(self
, key
, kwargs
.pop(key
))
1045 setattr(self
, key
, elseVal
)
1047 raise TypeError("No value set for %s" % key
)
1050 handle_kwarg(self
, kwargs
, 'ip')
1051 handle_kwarg(self
, kwargs
, 'netmask')
1053 elif len(args
) == 1:
1055 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1056 raise TypeError("Invalid arguments")
1057 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1058 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1059 elif isinstance(args
[0], IpNetmask
):
1060 self
.ip
= args
[0].ip
1061 self
.netmask
= args
[0].netmask
1063 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1065 elif len(args
) == 2:
1067 self
.netmask
= args
[1]
1069 raise TypeError("Too many arguments specified")
1072 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1076 def __call__(self
, value
):
1077 self
.__init
__(value
)
1081 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1083 def __eq__(self
, other
):
1084 if isinstance(other
, IpNetmask
):
1085 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1086 elif isinstance(other
, str):
1088 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1096 if self
.netmask
< 0 or self
.netmask
> 32:
1097 raise TypeError("invalid netmask %d" % netmask
)
1100 from _m5
.net
import IpNetmask
1101 return IpNetmask(self
.ip
, self
.netmask
)
1103 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1104 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1105 class IpWithPort(IpAddress
):
1106 cxx_type
= 'Net::IpWithPort'
1107 ex_str
= "127.0.0.1:80"
1108 cmd_line_settable
= True
1111 def cxx_predecls(cls
, code
):
1112 code('#include "base/inet.hh"')
1114 def __init__(self
, *args
, **kwargs
):
1115 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1117 setattr(self
, key
, kwargs
.pop(key
))
1119 setattr(self
, key
, elseVal
)
1121 raise TypeError("No value set for %s" % key
)
1124 handle_kwarg(self
, kwargs
, 'ip')
1125 handle_kwarg(self
, kwargs
, 'port')
1127 elif len(args
) == 1:
1129 if not 'ip' in kwargs
and not 'port' in kwargs
:
1130 raise TypeError("Invalid arguments")
1131 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1132 handle_kwarg(self
, kwargs
, 'port', args
[0])
1133 elif isinstance(args
[0], IpWithPort
):
1134 self
.ip
= args
[0].ip
1135 self
.port
= args
[0].port
1137 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1139 elif len(args
) == 2:
1143 raise TypeError("Too many arguments specified")
1146 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1150 def __call__(self
, value
):
1151 self
.__init
__(value
)
1155 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1157 def __eq__(self
, other
):
1158 if isinstance(other
, IpWithPort
):
1159 return self
.ip
== other
.ip
and self
.port
== other
.port
1160 elif isinstance(other
, str):
1162 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1170 if self
.port
< 0 or self
.port
> 0xffff:
1171 raise TypeError("invalid port %d" % self
.port
)
1174 from _m5
.net
import IpWithPort
1175 return IpWithPort(self
.ip
, self
.port
)
1177 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1178 "%a %b %d %H:%M:%S %Y",
1179 "%Y/%m/%d %H:%M:%S",
1182 "%m/%d/%Y %H:%M:%S",
1185 "%m/%d/%y %H:%M:%S",
1190 def parse_time(value
):
1191 from time
import gmtime
, strptime
, struct_time
, time
1192 from datetime
import datetime
, date
1194 if isinstance(value
, struct_time
):
1197 if isinstance(value
, (int, long)):
1198 return gmtime(value
)
1200 if isinstance(value
, (datetime
, date
)):
1201 return value
.timetuple()
1203 if isinstance(value
, str):
1204 if value
in ('Now', 'Today'):
1205 return time
.gmtime(time
.time())
1207 for format
in time_formats
:
1209 return strptime(value
, format
)
1213 raise ValueError("Could not parse '%s' as a time" % value
)
1215 class Time(ParamValue
):
1219 def cxx_predecls(cls
, code
):
1220 code('#include <time.h>')
1222 def __init__(self
, value
):
1223 self
.value
= parse_time(value
)
1225 def __call__(self
, value
):
1226 self
.__init
__(value
)
1230 from _m5
.core
import tm
1233 return tm
.gmtime(calendar
.timegm(self
.value
))
1236 return time
.asctime(self
.value
)
1241 def get_config_as_dict(self
):
1246 def cxx_ini_predecls(cls
, code
):
1247 code('#include <time.h>')
1250 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1251 code('char *_parse_ret = strptime((${src}).c_str(),')
1252 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1253 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1255 # Enumerated types are a little more complex. The user specifies the
1256 # type as Enum(foo) where foo is either a list or dictionary of
1257 # alternatives (typically strings, but not necessarily so). (In the
1258 # long run, the integer value of the parameter will be the list index
1259 # or the corresponding dictionary value. For now, since we only check
1260 # that the alternative is valid and then spit it into a .ini file,
1261 # there's not much point in using the dictionary.)
1263 # What Enum() must do is generate a new type encapsulating the
1264 # provided list/dictionary so that specific values of the parameter
1265 # can be instances of that type. We define two hidden internal
1266 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1267 # derive the new type from the appropriate base class on the fly.
1270 # Metaclass for Enum types
1271 class MetaEnum(MetaParamValue
):
1272 def __new__(mcls
, name
, bases
, dict):
1273 assert name
not in allEnums
1275 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1276 allEnums
[name
] = cls
1279 def __init__(cls
, name
, bases
, init_dict
):
1280 if 'map' in init_dict
:
1281 if not isinstance(cls
.map, dict):
1282 raise TypeError("Enum-derived class attribute 'map' " \
1283 "must be of type dict")
1284 # build list of value strings from map
1285 cls
.vals
= list(cls
.map.keys())
1287 elif 'vals' in init_dict
:
1288 if not isinstance(cls
.vals
, list):
1289 raise TypeError("Enum-derived class attribute 'vals' " \
1290 "must be of type list")
1291 # build string->value map from vals sequence
1293 for idx
,val
in enumerate(cls
.vals
):
1296 raise TypeError("Enum-derived class must define "\
1297 "attribute 'map' or 'vals'")
1300 cls
.cxx_type
= '%s' % name
1302 cls
.cxx_type
= 'Enums::%s' % name
1304 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1306 # Generate C++ class declaration for this enum type.
1307 # Note that we wrap the enum in a class/struct to act as a namespace,
1308 # so that the enum strings can be brief w/o worrying about collisions.
1309 def cxx_decl(cls
, code
):
1310 wrapper_name
= cls
.wrapper_name
1311 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1312 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1313 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1326 $wrapper $wrapper_name {
1331 for val
in cls
.vals
:
1332 code('$val = ${{cls.map[val]}},')
1333 code('Num_$name = ${{len(cls.vals)}}')
1339 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1341 elif cls
.wrapper_is_struct
:
1342 code('static const char *${name}Strings[Num_${name}];')
1344 code('extern const char *${name}Strings[Num_${name}];')
1346 if not cls
.is_class
:
1351 code('#endif // $idem_macro')
1353 def cxx_def(cls
, code
):
1354 wrapper_name
= cls
.wrapper_name
1355 file_name
= cls
.__name
__
1356 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1358 code('#include "enums/$file_name.hh"')
1359 if cls
.wrapper_is_struct
:
1360 code('const char *${wrapper_name}::${name}Strings'
1365 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1368 code('namespace Enums {')
1370 code('const char *${name}Strings[Num_${name}] =')
1374 for val
in cls
.vals
:
1379 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1381 code('} // namespace $wrapper_name')
1384 def pybind_def(cls
, code
):
1386 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1387 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1389 code('''#include "pybind11/pybind11.h"
1390 #include "pybind11/stl.h"
1392 #include <sim/init.hh>
1394 namespace py = pybind11;
1397 module_init(py::module &m_internal)
1399 py::module m = m_internal.def_submodule("enum_${name}");
1403 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1405 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1409 for val
in cls
.vals
:
1410 code('.value("${val}", ${wrapper_name}::${val})')
1411 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1412 code('.export_values()')
1419 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1422 # Base class for enum types.
1423 class Enum(ParamValue
):
1424 __metaclass__
= MetaEnum
1426 cmd_line_settable
= True
1428 # The name of the wrapping namespace or struct
1429 wrapper_name
= 'Enums'
1431 # If true, the enum is wrapped in a struct rather than a namespace
1432 wrapper_is_struct
= False
1436 # If not None, use this as the enum name rather than this class name
1439 def __init__(self
, value
):
1440 if value
not in self
.map:
1441 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1442 % (value
, self
.vals
))
1445 def __call__(self
, value
):
1446 self
.__init
__(value
)
1450 def cxx_predecls(cls
, code
):
1451 code('#include "enums/$0.hh"', cls
.__name
__)
1454 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1455 code('if (false) {')
1456 for elem_name
in cls
.map.keys():
1457 code('} else if (%s == "%s") {' % (src
, elem_name
))
1459 code('%s = Enums::%s;' % (dest
, elem_name
))
1460 code('%s true;' % ret
)
1463 code(' %s false;' % ret
)
1467 import m5
.internal
.params
1468 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1469 return e(self
.map[self
.value
])
1474 # This param will generate a scoped c++ enum and its python bindings.
1475 class ScopedEnum(Enum
):
1476 __metaclass__
= MetaEnum
1478 cmd_line_settable
= True
1480 # The name of the wrapping namespace or struct
1483 # If true, the enum is wrapped in a struct rather than a namespace
1484 wrapper_is_struct
= False
1486 # If true, the generated enum is a scoped enum
1489 # If not None, use this as the enum name rather than this class name
1492 # how big does a rounding error need to be before we warn about it?
1493 frequency_tolerance
= 0.001 # 0.1%
1495 class TickParamValue(NumericParamValue
):
1498 cmd_line_settable
= True
1501 def cxx_predecls(cls
, code
):
1502 code('#include "base/types.hh"')
1504 def __call__(self
, value
):
1505 self
.__init
__(value
)
1509 return long(self
.value
)
1512 def cxx_ini_predecls(cls
, code
):
1513 code('#include <sstream>')
1515 # Ticks are expressed in seconds in JSON files and in plain
1516 # Ticks in .ini files. Switch based on a config flag
1518 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1519 code('${ret} to_number(${src}, ${dest});')
1521 class Latency(TickParamValue
):
1524 def __init__(self
, value
):
1525 if isinstance(value
, (Latency
, Clock
)):
1526 self
.ticks
= value
.ticks
1527 self
.value
= value
.value
1528 elif isinstance(value
, Frequency
):
1529 self
.ticks
= value
.ticks
1530 self
.value
= 1.0 / value
.value
1531 elif value
.endswith('t'):
1533 self
.value
= int(value
[:-1])
1536 self
.value
= convert
.toLatency(value
)
1538 def __call__(self
, value
):
1539 self
.__init
__(value
)
1542 def __getattr__(self
, attr
):
1543 if attr
in ('latency', 'period'):
1545 if attr
== 'frequency':
1546 return Frequency(self
)
1547 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1550 if self
.ticks
or self
.value
== 0:
1553 value
= ticks
.fromSeconds(self
.value
)
1556 def config_value(self
):
1557 return self
.getValue()
1559 # convert latency to ticks
1561 return '%d' % self
.getValue()
1563 class Frequency(TickParamValue
):
1566 def __init__(self
, value
):
1567 if isinstance(value
, (Latency
, Clock
)):
1568 if value
.value
== 0:
1571 self
.value
= 1.0 / value
.value
1572 self
.ticks
= value
.ticks
1573 elif isinstance(value
, Frequency
):
1574 self
.value
= value
.value
1575 self
.ticks
= value
.ticks
1578 self
.value
= convert
.toFrequency(value
)
1580 def __call__(self
, value
):
1581 self
.__init
__(value
)
1584 def __getattr__(self
, attr
):
1585 if attr
== 'frequency':
1587 if attr
in ('latency', 'period'):
1588 return Latency(self
)
1589 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1591 # convert latency to ticks
1593 if self
.ticks
or self
.value
== 0:
1596 value
= ticks
.fromSeconds(1.0 / self
.value
)
1599 def config_value(self
):
1600 return self
.getValue()
1603 return '%d' % self
.getValue()
1605 # A generic Frequency and/or Latency value. Value is stored as a
1606 # latency, just like Latency and Frequency.
1607 class Clock(TickParamValue
):
1608 def __init__(self
, value
):
1609 if isinstance(value
, (Latency
, Clock
)):
1610 self
.ticks
= value
.ticks
1611 self
.value
= value
.value
1612 elif isinstance(value
, Frequency
):
1613 self
.ticks
= value
.ticks
1614 self
.value
= 1.0 / value
.value
1615 elif value
.endswith('t'):
1617 self
.value
= int(value
[:-1])
1620 self
.value
= convert
.anyToLatency(value
)
1622 def __call__(self
, value
):
1623 self
.__init
__(value
)
1627 return "%s" % Latency(self
)
1629 def __getattr__(self
, attr
):
1630 if attr
== 'frequency':
1631 return Frequency(self
)
1632 if attr
in ('latency', 'period'):
1633 return Latency(self
)
1634 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1637 return self
.period
.getValue()
1639 def config_value(self
):
1640 return self
.period
.config_value()
1643 return self
.period
.ini_str()
1645 class Voltage(Float
):
1648 def __new__(cls
, value
):
1649 value
= convert
.toVoltage(value
)
1650 return super(cls
, Voltage
).__new
__(cls
, value
)
1652 def __init__(self
, value
):
1653 value
= convert
.toVoltage(value
)
1654 super(Voltage
, self
).__init
__(value
)
1656 class Current(Float
):
1659 def __new__(cls
, value
):
1660 value
= convert
.toCurrent(value
)
1661 return super(cls
, Current
).__new
__(cls
, value
)
1663 def __init__(self
, value
):
1664 value
= convert
.toCurrent(value
)
1665 super(Current
, self
).__init
__(value
)
1667 class Energy(Float
):
1670 def __new__(cls
, value
):
1671 value
= convert
.toEnergy(value
)
1672 return super(cls
, Energy
).__new
__(cls
, value
)
1674 def __init__(self
, value
):
1675 value
= convert
.toEnergy(value
)
1676 super(Energy
, self
).__init
__(value
)
1678 class NetworkBandwidth(float,ParamValue
):
1681 cmd_line_settable
= True
1683 def __new__(cls
, value
):
1684 # convert to bits per second
1685 val
= convert
.toNetworkBandwidth(value
)
1686 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1689 return str(self
.val
)
1691 def __call__(self
, value
):
1692 val
= convert
.toNetworkBandwidth(value
)
1697 # convert to seconds per byte
1698 value
= 8.0 / float(self
)
1699 # convert to ticks per byte
1700 value
= ticks
.fromSeconds(value
)
1704 return '%f' % self
.getValue()
1706 def config_value(self
):
1707 return '%f' % self
.getValue()
1710 def cxx_ini_predecls(cls
, code
):
1711 code('#include <sstream>')
1714 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1715 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1717 class MemoryBandwidth(float,ParamValue
):
1720 cmd_line_settable
= True
1722 def __new__(cls
, value
):
1723 # convert to bytes per second
1724 val
= convert
.toMemoryBandwidth(value
)
1725 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1727 def __call__(self
, value
):
1728 val
= convert
.toMemoryBandwidth(value
)
1733 # convert to seconds per byte
1736 value
= 1.0 / float(self
)
1737 # convert to ticks per byte
1738 value
= ticks
.fromSeconds(value
)
1742 return '%f' % self
.getValue()
1744 def config_value(self
):
1745 return '%f' % self
.getValue()
1748 def cxx_ini_predecls(cls
, code
):
1749 code('#include <sstream>')
1752 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1753 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1756 # "Constants"... handy aliases for various values.
1759 # Special class for NULL pointers. Note the special check in
1760 # make_param_value() above that lets these be assigned where a
1761 # SimObject is required.
1762 # only one copy of a particular node
1763 class NullSimObject(object):
1764 __metaclass__
= Singleton
1770 def _instantiate(self
, parent
= None, path
= ''):
1776 def unproxy(self
, base
):
1779 def set_path(self
, parent
, name
):
1782 def set_parent(self
, parent
, name
):
1785 def clear_parent(self
, old_parent
):
1788 def descendants(self
):
1792 def get_config_as_dict(self
):
1798 def config_value(self
):
1804 # The only instance you'll ever need...
1805 NULL
= NullSimObject()
1807 def isNullPointer(value
):
1808 return isinstance(value
, NullSimObject
)
1810 # Some memory range specifications use this as a default upper bound.
1813 AllMemory
= AddrRange(0, MaxAddr
)
1816 #####################################################################
1820 # Ports are used to interconnect objects in the memory system.
1822 #####################################################################
1824 # Port reference: encapsulates a reference to a particular port on a
1825 # particular SimObject.
1826 class PortRef(object):
1827 def __init__(self
, simobj
, name
, role
):
1828 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1829 self
.simobj
= simobj
1832 self
.peer
= None # not associated with another port yet
1833 self
.ccConnected
= False # C++ port connection done?
1834 self
.index
= -1 # always -1 for non-vector ports
1837 return '%s.%s' % (self
.simobj
, self
.name
)
1840 # Return the number of connected ports, i.e. 0 is we have no
1841 # peer and 1 if we do.
1842 return int(self
.peer
!= None)
1844 # for config.ini, print peer's name (not ours)
1846 return str(self
.peer
)
1849 def get_config_as_dict(self
):
1850 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1852 def __getattr__(self
, attr
):
1853 if attr
== 'peerObj':
1854 # shorthand for proxies
1855 return self
.peer
.simobj
1856 raise AttributeError("'%s' object has no attribute '%s'" % \
1857 (self
.__class
__.__name
__, attr
))
1859 # Full connection is symmetric (both ways). Called via
1860 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1861 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1862 # e.g., "obj1.portA[3] = obj2.portB".
1863 def connect(self
, other
):
1864 if isinstance(other
, VectorPortRef
):
1865 # reference to plain VectorPort is implicit append
1866 other
= other
._get
_next
()
1867 if self
.peer
and not proxy
.isproxy(self
.peer
):
1868 fatal("Port %s is already connected to %s, cannot connect %s\n",
1869 self
, self
.peer
, other
);
1871 if proxy
.isproxy(other
):
1872 other
.set_param_desc(PortParamDesc())
1873 elif isinstance(other
, PortRef
):
1874 if other
.peer
is not self
:
1877 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1880 # Allow a master/slave port pair to be spliced between
1881 # a port and its connected peer. Useful operation for connecting
1882 # instrumentation structures into a system when it is necessary
1883 # to connect the instrumentation after the full system has been
1885 def splice(self
, new_master_peer
, new_slave_peer
):
1886 if not self
.peer
or proxy
.isproxy(self
.peer
):
1887 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1889 if not isinstance(new_master_peer
, PortRef
) or \
1890 not isinstance(new_slave_peer
, PortRef
):
1892 "Splicing non-port references '%s','%s' to port '%s'" % \
1893 (new_master_peer
, new_slave_peer
, self
))
1895 old_peer
= self
.peer
1896 if self
.role
== 'SLAVE':
1897 self
.peer
= new_master_peer
1898 old_peer
.peer
= new_slave_peer
1899 new_master_peer
.connect(self
)
1900 new_slave_peer
.connect(old_peer
)
1901 elif self
.role
== 'MASTER':
1902 self
.peer
= new_slave_peer
1903 old_peer
.peer
= new_master_peer
1904 new_slave_peer
.connect(self
)
1905 new_master_peer
.connect(old_peer
)
1907 panic("Port %s has unknown role, "+\
1908 "cannot splice in new peers\n", self
)
1910 def clone(self
, simobj
, memo
):
1913 newRef
= copy
.copy(self
)
1915 newRef
.simobj
= simobj
1916 assert(isSimObject(newRef
.simobj
))
1917 if self
.peer
and not proxy
.isproxy(self
.peer
):
1918 peerObj
= self
.peer
.simobj(_memo
=memo
)
1919 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1920 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1923 def unproxy(self
, simobj
):
1924 assert(simobj
is self
.simobj
)
1925 if proxy
.isproxy(self
.peer
):
1927 realPeer
= self
.peer
.unproxy(self
.simobj
)
1929 print("Error in unproxying port '%s' of %s" %
1930 (self
.name
, self
.simobj
.path()))
1932 self
.connect(realPeer
)
1934 # Call C++ to create corresponding port connection between C++ objects
1935 def ccConnect(self
):
1936 from _m5
.pyobject
import connectPorts
1938 if self
.ccConnected
: # already done this
1942 if not self
.peer
: # nothing to connect to
1945 # check that we connect a master to a slave
1946 if self
.role
== peer
.role
:
1948 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1949 (peer
, self
, self
.role
))
1951 if self
.role
== 'SLAVE':
1952 # do nothing and let the master take care of it
1956 # self is always the master and peer the slave
1957 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1958 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1960 print("Error connecting port %s.%s to %s.%s" %
1961 (self
.simobj
.path(), self
.name
,
1962 peer
.simobj
.path(), peer
.name
))
1964 self
.ccConnected
= True
1965 peer
.ccConnected
= True
1967 # A reference to an individual element of a VectorPort... much like a
1968 # PortRef, but has an index.
1969 class VectorPortElementRef(PortRef
):
1970 def __init__(self
, simobj
, name
, role
, index
):
1971 PortRef
.__init
__(self
, simobj
, name
, role
)
1975 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1977 # A reference to a complete vector-valued port (not just a single element).
1978 # Can be indexed to retrieve individual VectorPortElementRef instances.
1979 class VectorPortRef(object):
1980 def __init__(self
, simobj
, name
, role
):
1981 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1982 self
.simobj
= simobj
1988 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1991 # Return the number of connected peers, corresponding the the
1992 # length of the elements.
1993 return len(self
.elements
)
1995 # for config.ini, print peer's name (not ours)
1997 return ' '.join([el
.ini_str() for el
in self
.elements
])
2000 def get_config_as_dict(self
):
2001 return {'role' : self
.role
,
2002 'peer' : [el
.ini_str() for el
in self
.elements
]}
2004 def __getitem__(self
, key
):
2005 if not isinstance(key
, int):
2006 raise TypeError("VectorPort index must be integer")
2007 if key
>= len(self
.elements
):
2008 # need to extend list
2009 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
2010 for i
in range(len(self
.elements
), key
+1)]
2011 self
.elements
.extend(ext
)
2012 return self
.elements
[key
]
2014 def _get_next(self
):
2015 return self
[len(self
.elements
)]
2017 def __setitem__(self
, key
, value
):
2018 if not isinstance(key
, int):
2019 raise TypeError("VectorPort index must be integer")
2020 self
[key
].connect(value
)
2022 def connect(self
, other
):
2023 if isinstance(other
, (list, tuple)):
2024 # Assign list of port refs to vector port.
2025 # For now, append them... not sure if that's the right semantics
2026 # or if it should replace the current vector.
2028 self
._get
_next
().connect(ref
)
2030 # scalar assignment to plain VectorPort is implicit append
2031 self
._get
_next
().connect(other
)
2033 def clone(self
, simobj
, memo
):
2036 newRef
= copy
.copy(self
)
2038 newRef
.simobj
= simobj
2039 assert(isSimObject(newRef
.simobj
))
2040 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2043 def unproxy(self
, simobj
):
2044 [el
.unproxy(simobj
) for el
in self
.elements
]
2046 def ccConnect(self
):
2047 [el
.ccConnect() for el
in self
.elements
]
2049 # Port description object. Like a ParamDesc object, this represents a
2050 # logical port in the SimObject class, not a particular port on a
2051 # SimObject instance. The latter are represented by PortRef objects.
2053 # Generate a PortRef for this port on the given SimObject with the
2055 def makeRef(self
, simobj
):
2056 return PortRef(simobj
, self
.name
, self
.role
)
2058 # Connect an instance of this port (on the given SimObject with
2059 # the given name) with the port described by the supplied PortRef
2060 def connect(self
, simobj
, ref
):
2061 self
.makeRef(simobj
).connect(ref
)
2063 # No need for any pre-declarations at the moment as we merely rely
2064 # on an unsigned int.
2065 def cxx_predecls(self
, code
):
2068 def pybind_predecls(self
, code
):
2069 cls
.cxx_predecls(self
, code
)
2071 # Declare an unsigned int with the same name as the port, that
2072 # will eventually hold the number of connected ports (and thus the
2073 # number of elements for a VectorPort).
2074 def cxx_decl(self
, code
):
2075 code('unsigned int port_${{self.name}}_connection_count;')
2077 class MasterPort(Port
):
2078 # MasterPort("description")
2079 def __init__(self
, *args
):
2082 self
.role
= 'MASTER'
2084 raise TypeError('wrong number of arguments')
2086 class SlavePort(Port
):
2087 # SlavePort("description")
2088 def __init__(self
, *args
):
2093 raise TypeError('wrong number of arguments')
2095 # VectorPort description object. Like Port, but represents a vector
2096 # of connections (e.g., as on a XBar).
2097 class VectorPort(Port
):
2098 def __init__(self
, *args
):
2101 def makeRef(self
, simobj
):
2102 return VectorPortRef(simobj
, self
.name
, self
.role
)
2104 class VectorMasterPort(VectorPort
):
2105 # VectorMasterPort("description")
2106 def __init__(self
, *args
):
2109 self
.role
= 'MASTER'
2110 VectorPort
.__init
__(self
, *args
)
2112 raise TypeError('wrong number of arguments')
2114 class VectorSlavePort(VectorPort
):
2115 # VectorSlavePort("description")
2116 def __init__(self
, *args
):
2120 VectorPort
.__init
__(self
, *args
)
2122 raise TypeError('wrong number of arguments')
2124 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2125 # proxy objects (via set_param_desc()) so that proxy error messages
2127 class PortParamDesc(object):
2128 __metaclass__
= Singleton
2133 baseEnums
= allEnums
.copy()
2134 baseParams
= allParams
.copy()
2137 global allEnums
, allParams
2139 allEnums
= baseEnums
.copy()
2140 allParams
= baseParams
.copy()
2142 __all__
= ['Param', 'VectorParam',
2143 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2144 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2145 'Int32', 'UInt32', 'Int64', 'UInt64',
2146 'Counter', 'Addr', 'Tick', 'Percent',
2147 'TcpPort', 'UdpPort', 'EthernetAddr',
2148 'IpAddress', 'IpNetmask', 'IpWithPort',
2149 'MemorySize', 'MemorySize32',
2150 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2151 'NetworkBandwidth', 'MemoryBandwidth',
2153 'MaxAddr', 'MaxTick', 'AllMemory',
2155 'NextEthernetAddr', 'NULL',
2156 'MasterPort', 'SlavePort',
2157 'VectorMasterPort', 'VectorSlavePort']