757a4f2385a135a88676f4fd777347e75277b5c0
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 from . import SimObject
77 return SimObject
.isSimObject(*args
, **kwargs
)
79 def isSimObjectSequence(*args
, **kwargs
):
80 from . import SimObject
81 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
83 def isSimObjectClass(*args
, **kwargs
):
84 from . import SimObject
85 return SimObject
.isSimObjectClass(*args
, **kwargs
)
89 class MetaParamValue(type):
90 def __new__(mcls
, name
, bases
, dct
):
91 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
92 assert name
not in allParams
97 # Dummy base class to identify types that are legitimate for SimObject
99 class ParamValue(object):
100 __metaclass__
= MetaParamValue
101 cmd_line_settable
= False
103 # Generate the code needed as a prerequisite for declaring a C++
104 # object of this type. Typically generates one or more #include
105 # statements. Used when declaring parameters of this type.
107 def cxx_predecls(cls
, code
):
111 def pybind_predecls(cls
, code
):
112 cls
.cxx_predecls(code
)
114 # default for printing to .ini file is regular string conversion.
115 # will be overridden in some cases
119 # default for printing to .json file is regular string conversion.
120 # will be overridden in some cases, mostly to use native Python
121 # types where there are similar JSON types
122 def config_value(self
):
125 # Prerequisites for .ini parsing with cxx_ini_parse
127 def cxx_ini_predecls(cls
, code
):
130 # parse a .ini file entry for this param from string expression
131 # src into lvalue dest (of the param's C++ type)
133 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
134 code('// Unhandled param type: %s' % cls
.__name
__)
135 code('%s false;' % ret
)
137 # allows us to blithely call unproxy() on things without checking
138 # if they're really proxies or not
139 def unproxy(self
, base
):
142 # Produce a human readable version of the stored value
143 def pretty_print(self
, value
):
146 # Regular parameter description.
147 class ParamDesc(object):
148 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
149 self
.ptype_str
= ptype_str
150 # remember ptype only if it is provided
158 self
.default
= args
[0]
161 raise TypeError('too many arguments')
164 assert(not hasattr(self
, 'desc'))
165 self
.desc
= kwargs
['desc']
168 if 'default' in kwargs
:
169 assert(not hasattr(self
, 'default'))
170 self
.default
= kwargs
['default']
171 del kwargs
['default']
174 raise TypeError('extra unknown kwargs %s' % kwargs
)
176 if not hasattr(self
, 'desc'):
177 raise TypeError('desc attribute missing')
179 def __getattr__(self
, attr
):
181 from . import SimObject
182 ptype
= SimObject
.allClasses
[self
.ptype_str
]
183 assert isSimObjectClass(ptype
)
187 raise AttributeError("'%s' object has no attribute '%s'" % \
188 (type(self
).__name
__, attr
))
190 def example_str(self
):
191 if hasattr(self
.ptype
, "ex_str"):
192 return self
.ptype
.ex_str
194 return self
.ptype_str
196 # Is the param available to be exposed on the command line
197 def isCmdLineSettable(self
):
198 if hasattr(self
.ptype
, "cmd_line_settable"):
199 return self
.ptype
.cmd_line_settable
203 def convert(self
, value
):
204 if isinstance(value
, proxy
.BaseProxy
):
205 value
.set_param_desc(self
)
207 if 'ptype' not in self
.__dict
__ and isNullPointer(value
):
208 # deferred evaluation of SimObject; continue to defer if
209 # we're just assigning a null pointer
211 if isinstance(value
, self
.ptype
):
213 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
215 return self
.ptype(value
)
217 def pretty_print(self
, value
):
218 if isinstance(value
, proxy
.BaseProxy
):
220 if isNullPointer(value
):
222 return self
.ptype(value
).pretty_print(value
)
224 def cxx_predecls(self
, code
):
225 code('#include <cstddef>')
226 self
.ptype
.cxx_predecls(code
)
228 def pybind_predecls(self
, code
):
229 self
.ptype
.pybind_predecls(code
)
231 def cxx_decl(self
, code
):
232 code('${{self.ptype.cxx_type}} ${{self.name}};')
234 # Vector-valued parameter description. Just like ParamDesc, except
235 # that the value is a vector (list) of the specified type instead of a
238 class VectorParamValue(list):
239 __metaclass__
= MetaParamValue
240 def __setattr__(self
, attr
, value
):
241 raise AttributeError("Not allowed to set %s on '%s'" % \
242 (attr
, type(self
).__name
__))
244 def config_value(self
):
245 return [v
.config_value() for v
in self
]
248 return ' '.join([v
.ini_str() for v
in self
])
251 return [ v
.getValue() for v
in self
]
253 def unproxy(self
, base
):
254 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
255 # The value is a proxy (e.g. Parent.any, Parent.all or
256 # Parent.x) therefore try resolve it
257 return self
[0].unproxy(base
)
259 return [v
.unproxy(base
) for v
in self
]
261 class SimObjectVector(VectorParamValue
):
262 # support clone operation
263 def __call__(self
, **kwargs
):
264 return SimObjectVector([v(**kwargs
) for v
in self
])
266 def clear_parent(self
, old_parent
):
268 v
.clear_parent(old_parent
)
270 def set_parent(self
, parent
, name
):
272 self
[0].set_parent(parent
, name
)
274 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
275 for i
,v
in enumerate(self
):
276 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
278 def has_parent(self
):
279 return any([e
.has_parent() for e
in self
if not isNullPointer(e
)])
281 # return 'cpu0 cpu1' etc. for print_ini()
283 return ' '.join([v
._name
for v
in self
])
285 # By iterating through the constituent members of the vector here
286 # we can nicely handle iterating over all a SimObject's children
287 # without having to provide lots of special functions on
288 # SimObjectVector directly.
289 def descendants(self
):
291 for obj
in v
.descendants():
294 def get_config_as_dict(self
):
297 a
.append(v
.get_config_as_dict())
300 # If we are replacing an item in the vector, make sure to set the
301 # parent reference of the new SimObject to be the same as the parent
302 # of the SimObject being replaced. Useful to have if we created
303 # a SimObjectVector of temporary objects that will be modified later in
304 # configuration scripts.
305 def __setitem__(self
, key
, value
):
307 if value
.has_parent():
308 warn("SimObject %s already has a parent" % value
.get_name() +\
309 " that is being overwritten by a SimObjectVector")
310 value
.set_parent(val
.get_parent(), val
._name
)
311 super(SimObjectVector
, self
).__setitem
__(key
, value
)
313 # Enumerate the params of each member of the SimObject vector. Creates
314 # strings that will allow indexing into the vector by the python code and
315 # allow it to be specified on the command line.
316 def enumerateParams(self
, flags_dict
= {},
319 if hasattr(self
, "_paramEnumed"):
320 print("Cycle detected enumerating params at %s?!" % (cmd_line_str
))
324 # Each entry in the SimObjectVector should be an
325 # instance of a SimObject
326 flags_dict
= vals
.enumerateParams(flags_dict
,
327 cmd_line_str
+ "%d." % x
,
328 access_str
+ "[%d]." % x
)
333 class VectorParamDesc(ParamDesc
):
334 # Convert assigned value to appropriate type. If the RHS is not a
335 # list or tuple, it generates a single-element list.
336 def convert(self
, value
):
337 if isinstance(value
, (list, tuple)):
338 # list: coerce each element into new list
339 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
340 elif isinstance(value
, str):
341 # If input is a csv string
342 tmp_list
= [ ParamDesc
.convert(self
, v
) \
343 for v
in value
.strip('[').strip(']').split(',') ]
345 # singleton: coerce to a single-element list
346 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
348 if isSimObjectSequence(tmp_list
):
349 return SimObjectVector(tmp_list
)
351 return VectorParamValue(tmp_list
)
353 # Produce a human readable example string that describes
354 # how to set this vector parameter in the absence of a default
356 def example_str(self
):
357 s
= super(VectorParamDesc
, self
).example_str()
358 help_str
= "[" + s
+ "," + s
+ ", ...]"
361 # Produce a human readable representation of the value of this vector param.
362 def pretty_print(self
, value
):
363 if isinstance(value
, (list, tuple)):
364 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
365 elif isinstance(value
, str):
366 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
368 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
372 # This is a helper function for the new config system
373 def __call__(self
, value
):
374 if isinstance(value
, (list, tuple)):
375 # list: coerce each element into new list
376 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
377 elif isinstance(value
, str):
378 # If input is a csv string
379 tmp_list
= [ ParamDesc
.convert(self
, v
) \
380 for v
in value
.strip('[').strip(']').split(',') ]
382 # singleton: coerce to a single-element list
383 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
385 return VectorParamValue(tmp_list
)
387 def cxx_predecls(self
, code
):
388 code('#include <vector>')
389 self
.ptype
.cxx_predecls(code
)
391 def pybind_predecls(self
, code
):
392 code('#include <vector>')
393 self
.ptype
.pybind_predecls(code
)
395 def cxx_decl(self
, code
):
396 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
398 class ParamFactory(object):
399 def __init__(self
, param_desc_class
, ptype_str
= None):
400 self
.param_desc_class
= param_desc_class
401 self
.ptype_str
= ptype_str
403 def __getattr__(self
, attr
):
405 attr
= self
.ptype_str
+ '.' + attr
406 return ParamFactory(self
.param_desc_class
, attr
)
408 # E.g., Param.Int(5, "number of widgets")
409 def __call__(self
, *args
, **kwargs
):
412 ptype
= allParams
[self
.ptype_str
]
414 # if name isn't defined yet, assume it's a SimObject, and
415 # try to resolve it later
417 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
419 Param
= ParamFactory(ParamDesc
)
420 VectorParam
= ParamFactory(VectorParamDesc
)
422 #####################################################################
426 # Though native Python types could be used to specify parameter types
427 # (the 'ptype' field of the Param and VectorParam classes), it's more
428 # flexible to define our own set of types. This gives us more control
429 # over how Python expressions are converted to values (via the
430 # __init__() constructor) and how these values are printed out (via
431 # the __str__() conversion method).
433 #####################################################################
435 # String-valued parameter. Just mixin the ParamValue class with the
436 # built-in str class.
437 class String(ParamValue
,str):
438 cxx_type
= 'std::string'
439 cmd_line_settable
= True
442 def cxx_predecls(self
, code
):
443 code('#include <string>')
445 def __call__(self
, value
):
450 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
451 code('%s = %s;' % (dest
, src
))
452 code('%s true;' % ret
)
457 # superclass for "numeric" parameter values, to emulate math
458 # operations in a type-safe way. e.g., a Latency times an int returns
459 # a new Latency object.
460 class NumericParamValue(ParamValue
):
463 return v
.value
if isinstance(v
, NumericParamValue
) else v
466 return str(self
.value
)
469 return float(self
.value
)
472 return long(self
.value
)
475 return int(self
.value
)
477 # hook for bounds checking
481 def __mul__(self
, other
):
482 newobj
= self
.__class
__(self
)
483 newobj
.value
*= NumericParamValue
.unwrap(other
)
489 def __truediv__(self
, other
):
490 newobj
= self
.__class
__(self
)
491 newobj
.value
/= NumericParamValue
.unwrap(other
)
495 def __floordiv__(self
, other
):
496 newobj
= self
.__class
__(self
)
497 newobj
.value
//= NumericParamValue
.unwrap(other
)
502 def __add__(self
, other
):
503 newobj
= self
.__class
__(self
)
504 newobj
.value
+= NumericParamValue
.unwrap(other
)
508 def __sub__(self
, other
):
509 newobj
= self
.__class
__(self
)
510 newobj
.value
-= NumericParamValue
.unwrap(other
)
514 def __iadd__(self
, other
):
515 self
.value
+= NumericParamValue
.unwrap(other
)
519 def __isub__(self
, other
):
520 self
.value
-= NumericParamValue
.unwrap(other
)
524 def __imul__(self
, other
):
525 self
.value
*= NumericParamValue
.unwrap(other
)
529 def __itruediv__(self
, other
):
530 self
.value
/= NumericParamValue
.unwrap(other
)
534 def __ifloordiv__(self
, other
):
535 self
.value
//= NumericParamValue
.unwrap(other
)
539 def __lt__(self
, other
):
540 return self
.value
< NumericParamValue
.unwrap(other
)
542 # Python 2.7 pre __future__.division operators
543 # TODO: Remove these when after "import division from __future__"
544 __div__
= __truediv__
545 __idiv__
= __itruediv__
547 def config_value(self
):
551 def cxx_ini_predecls(cls
, code
):
552 # Assume that base/str.hh will be included anyway
553 # code('#include "base/str.hh"')
556 # The default for parsing PODs from an .ini entry is to extract from an
557 # istringstream and let overloading choose the right type according to
560 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
561 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
563 # Metaclass for bounds-checked integer parameters. See CheckedInt.
564 class CheckedIntType(MetaParamValue
):
565 def __init__(cls
, name
, bases
, dict):
566 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
568 # CheckedInt is an abstract base class, so we actually don't
569 # want to do any processing on it... the rest of this code is
570 # just for classes that derive from CheckedInt.
571 if name
== 'CheckedInt':
574 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
575 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
576 panic("CheckedInt subclass %s must define either\n" \
577 " 'min' and 'max' or 'size' and 'unsigned'\n",
581 cls
.max = 2 ** cls
.size
- 1
583 cls
.min = -(2 ** (cls
.size
- 1))
584 cls
.max = (2 ** (cls
.size
- 1)) - 1
586 # Abstract superclass for bounds-checked integer parameters. This
587 # class is subclassed to generate parameter classes with specific
588 # bounds. Initialization of the min and max bounds is done in the
589 # metaclass CheckedIntType.__init__.
590 class CheckedInt(NumericParamValue
):
591 __metaclass__
= CheckedIntType
592 cmd_line_settable
= True
595 if not self
.min <= self
.value
<= self
.max:
596 raise TypeError('Integer param out of bounds %d < %d < %d' % \
597 (self
.min, self
.value
, self
.max))
599 def __init__(self
, value
):
600 if isinstance(value
, str):
601 self
.value
= convert
.toInteger(value
)
602 elif isinstance(value
, (int, long, float, NumericParamValue
)):
603 self
.value
= long(value
)
605 raise TypeError("Can't convert object of type %s to CheckedInt" \
606 % type(value
).__name
__)
609 def __call__(self
, value
):
614 return int(self
.value
)
617 def cxx_predecls(cls
, code
):
618 # most derived types require this, so we just do it here once
619 code('#include "base/types.hh"')
622 return long(self
.value
)
624 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
625 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
627 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
628 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
629 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
630 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
631 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
632 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
633 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
634 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
636 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
637 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
638 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
639 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
641 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
643 class Cycles(CheckedInt
):
649 from _m5
.core
import Cycles
650 return Cycles(self
.value
)
653 def cxx_ini_predecls(cls
, code
):
654 # Assume that base/str.hh will be included anyway
655 # code('#include "base/str.hh"')
659 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
660 code('uint64_t _temp;')
661 code('bool _ret = to_number(%s, _temp);' % src
)
663 code(' %s = Cycles(_temp);' % dest
)
664 code('%s _ret;' % ret
)
666 class Float(ParamValue
, float):
668 cmd_line_settable
= True
670 def __init__(self
, value
):
671 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
672 self
.value
= float(value
)
674 raise TypeError("Can't convert object of type %s to Float" \
675 % type(value
).__name
__)
677 def __call__(self
, value
):
682 return float(self
.value
)
684 def config_value(self
):
688 def cxx_ini_predecls(cls
, code
):
689 code('#include <sstream>')
692 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
693 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
695 class MemorySize(CheckedInt
):
696 cxx_type
= 'uint64_t'
700 def __init__(self
, value
):
701 if isinstance(value
, MemorySize
):
702 self
.value
= value
.value
704 self
.value
= convert
.toMemorySize(value
)
707 class MemorySize32(CheckedInt
):
708 cxx_type
= 'uint32_t'
712 def __init__(self
, value
):
713 if isinstance(value
, MemorySize
):
714 self
.value
= value
.value
716 self
.value
= convert
.toMemorySize(value
)
719 class Addr(CheckedInt
):
723 def __init__(self
, value
):
724 if isinstance(value
, Addr
):
725 self
.value
= value
.value
728 # Often addresses are referred to with sizes. Ex: A device
729 # base address is at "512MB". Use toMemorySize() to convert
730 # these into addresses. If the address is not specified with a
731 # "size", an exception will occur and numeric translation will
733 self
.value
= convert
.toMemorySize(value
)
734 except (TypeError, ValueError):
735 # Convert number to string and use long() to do automatic
736 # base conversion (requires base=0 for auto-conversion)
737 self
.value
= long(str(value
), base
=0)
740 def __add__(self
, other
):
741 if isinstance(other
, Addr
):
742 return self
.value
+ other
.value
744 return self
.value
+ other
745 def pretty_print(self
, value
):
747 val
= convert
.toMemorySize(value
)
750 return "0x%x" % long(val
)
752 class AddrRange(ParamValue
):
753 cxx_type
= 'AddrRange'
755 def __init__(self
, *args
, **kwargs
):
756 # Disable interleaving and hashing by default
757 self
.intlvHighBit
= 0
762 def handle_kwargs(self
, kwargs
):
763 # An address range needs to have an upper limit, specified
764 # either explicitly with an end, or as an offset using the
767 self
.end
= Addr(kwargs
.pop('end'))
768 elif 'size' in kwargs
:
769 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
771 raise TypeError("Either end or size must be specified")
773 # Now on to the optional bit
774 if 'intlvHighBit' in kwargs
:
775 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
776 if 'xorHighBit' in kwargs
:
777 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
778 if 'intlvBits' in kwargs
:
779 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
780 if 'intlvMatch' in kwargs
:
781 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
784 self
.start
= Addr(kwargs
.pop('start'))
785 handle_kwargs(self
, kwargs
)
789 self
.start
= Addr(args
[0])
790 handle_kwargs(self
, kwargs
)
791 elif isinstance(args
[0], (list, tuple)):
792 self
.start
= Addr(args
[0][0])
793 self
.end
= Addr(args
[0][1])
796 self
.end
= Addr(args
[0]) - 1
799 self
.start
= Addr(args
[0])
800 self
.end
= Addr(args
[1])
802 raise TypeError("Too many arguments specified")
805 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
808 return '%s:%s:%s:%s:%s:%s' \
809 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
810 self
.intlvBits
, self
.intlvMatch
)
813 # Divide the size by the size of the interleaving slice
814 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
817 def cxx_predecls(cls
, code
):
818 Addr
.cxx_predecls(code
)
819 code('#include "base/addr_range.hh"')
822 def pybind_predecls(cls
, code
):
823 Addr
.pybind_predecls(code
)
824 code('#include "base/addr_range.hh"')
827 def cxx_ini_predecls(cls
, code
):
828 code('#include <sstream>')
831 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
832 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
833 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
835 code('std::istringstream _stream(${src});')
836 code('_stream >> _start;')
837 code('_stream.get(_sep);')
838 code('_stream >> _end;')
839 code('if (!_stream.fail() && !_stream.eof()) {')
840 code(' _stream.get(_sep);')
841 code(' _stream >> _intlvHighBit;')
842 code(' _stream.get(_sep);')
843 code(' _stream >> _xorHighBit;')
844 code(' _stream.get(_sep);')
845 code(' _stream >> _intlvBits;')
846 code(' _stream.get(_sep);')
847 code(' _stream >> _intlvMatch;')
849 code('bool _ret = !_stream.fail() &&'
850 '_stream.eof() && _sep == \':\';')
852 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
853 _xorHighBit, _intlvBits, _intlvMatch);')
857 # Go from the Python class to the wrapped C++ class
858 from _m5
.range import AddrRange
860 return AddrRange(long(self
.start
), long(self
.end
),
861 int(self
.intlvHighBit
), int(self
.xorHighBit
),
862 int(self
.intlvBits
), int(self
.intlvMatch
))
864 # Boolean parameter type. Python doesn't let you subclass bool, since
865 # it doesn't want to let you create multiple instances of True and
866 # False. Thus this is a little more complicated than String.
867 class Bool(ParamValue
):
869 cmd_line_settable
= True
871 def __init__(self
, value
):
873 self
.value
= convert
.toBool(value
)
875 self
.value
= bool(value
)
877 def __call__(self
, value
):
882 return bool(self
.value
)
885 return str(self
.value
)
887 # implement truth value testing for Bool parameters so that these params
888 # evaluate correctly during the python configuration phase
890 return bool(self
.value
)
892 # Python 2.7 uses __nonzero__ instead of __bool__
893 __nonzero__
= __bool__
900 def config_value(self
):
904 def cxx_ini_predecls(cls
, code
):
905 # Assume that base/str.hh will be included anyway
906 # code('#include "base/str.hh"')
910 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
911 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
913 def IncEthernetAddr(addr
, val
= 1):
914 bytes
= [ int(x
, 16) for x
in addr
.split(':') ]
916 for i
in (5, 4, 3, 2, 1):
917 val
,rem
= divmod(bytes
[i
], 256)
922 assert(bytes
[0] <= 255)
923 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
925 _NextEthernetAddr
= "00:90:00:00:00:01"
926 def NextEthernetAddr():
927 global _NextEthernetAddr
929 value
= _NextEthernetAddr
930 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
933 class EthernetAddr(ParamValue
):
934 cxx_type
= 'Net::EthAddr'
935 ex_str
= "00:90:00:00:00:01"
936 cmd_line_settable
= True
939 def cxx_predecls(cls
, code
):
940 code('#include "base/inet.hh"')
942 def __init__(self
, value
):
943 if value
== NextEthernetAddr
:
947 if not isinstance(value
, str):
948 raise TypeError("expected an ethernet address and didn't get one")
950 bytes
= value
.split(':')
952 raise TypeError('invalid ethernet address %s' % value
)
955 if not 0 <= int(byte
, base
=16) <= 0xff:
956 raise TypeError('invalid ethernet address %s' % value
)
960 def __call__(self
, value
):
964 def unproxy(self
, base
):
965 if self
.value
== NextEthernetAddr
:
966 return EthernetAddr(self
.value())
970 from _m5
.net
import EthAddr
971 return EthAddr(self
.value
)
980 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
981 code('%s = Net::EthAddr(%s);' % (dest
, src
))
982 code('%s true;' % ret
)
984 # When initializing an IpAddress, pass in an existing IpAddress, a string of
985 # the form "a.b.c.d", or an integer representing an IP.
986 class IpAddress(ParamValue
):
987 cxx_type
= 'Net::IpAddress'
989 cmd_line_settable
= True
992 def cxx_predecls(cls
, code
):
993 code('#include "base/inet.hh"')
995 def __init__(self
, value
):
996 if isinstance(value
, IpAddress
):
1000 self
.ip
= convert
.toIpAddress(value
)
1002 self
.ip
= long(value
)
1005 def __call__(self
, value
):
1006 self
.__init
__(value
)
1010 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
1011 return '%d.%d.%d.%d' % tuple(tup
)
1013 def __eq__(self
, other
):
1014 if isinstance(other
, IpAddress
):
1015 return self
.ip
== other
.ip
1016 elif isinstance(other
, str):
1018 return self
.ip
== convert
.toIpAddress(other
)
1022 return self
.ip
== other
1024 def __ne__(self
, other
):
1025 return not (self
== other
)
1028 if self
.ip
< 0 or self
.ip
>= (1 << 32):
1029 raise TypeError("invalid ip address %#08x" % self
.ip
)
1032 from _m5
.net
import IpAddress
1033 return IpAddress(self
.ip
)
1035 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1036 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1037 # positional or keyword arguments.
1038 class IpNetmask(IpAddress
):
1039 cxx_type
= 'Net::IpNetmask'
1040 ex_str
= "127.0.0.0/24"
1041 cmd_line_settable
= True
1044 def cxx_predecls(cls
, code
):
1045 code('#include "base/inet.hh"')
1047 def __init__(self
, *args
, **kwargs
):
1048 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1050 setattr(self
, key
, kwargs
.pop(key
))
1052 setattr(self
, key
, elseVal
)
1054 raise TypeError("No value set for %s" % key
)
1057 handle_kwarg(self
, kwargs
, 'ip')
1058 handle_kwarg(self
, kwargs
, 'netmask')
1060 elif len(args
) == 1:
1062 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1063 raise TypeError("Invalid arguments")
1064 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1065 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1066 elif isinstance(args
[0], IpNetmask
):
1067 self
.ip
= args
[0].ip
1068 self
.netmask
= args
[0].netmask
1070 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1072 elif len(args
) == 2:
1074 self
.netmask
= args
[1]
1076 raise TypeError("Too many arguments specified")
1079 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1083 def __call__(self
, value
):
1084 self
.__init
__(value
)
1088 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1090 def __eq__(self
, other
):
1091 if isinstance(other
, IpNetmask
):
1092 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1093 elif isinstance(other
, str):
1095 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1103 if self
.netmask
< 0 or self
.netmask
> 32:
1104 raise TypeError("invalid netmask %d" % netmask
)
1107 from _m5
.net
import IpNetmask
1108 return IpNetmask(self
.ip
, self
.netmask
)
1110 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1111 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1112 class IpWithPort(IpAddress
):
1113 cxx_type
= 'Net::IpWithPort'
1114 ex_str
= "127.0.0.1:80"
1115 cmd_line_settable
= True
1118 def cxx_predecls(cls
, code
):
1119 code('#include "base/inet.hh"')
1121 def __init__(self
, *args
, **kwargs
):
1122 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1124 setattr(self
, key
, kwargs
.pop(key
))
1126 setattr(self
, key
, elseVal
)
1128 raise TypeError("No value set for %s" % key
)
1131 handle_kwarg(self
, kwargs
, 'ip')
1132 handle_kwarg(self
, kwargs
, 'port')
1134 elif len(args
) == 1:
1136 if not 'ip' in kwargs
and not 'port' in kwargs
:
1137 raise TypeError("Invalid arguments")
1138 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1139 handle_kwarg(self
, kwargs
, 'port', args
[0])
1140 elif isinstance(args
[0], IpWithPort
):
1141 self
.ip
= args
[0].ip
1142 self
.port
= args
[0].port
1144 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1146 elif len(args
) == 2:
1150 raise TypeError("Too many arguments specified")
1153 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1157 def __call__(self
, value
):
1158 self
.__init
__(value
)
1162 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1164 def __eq__(self
, other
):
1165 if isinstance(other
, IpWithPort
):
1166 return self
.ip
== other
.ip
and self
.port
== other
.port
1167 elif isinstance(other
, str):
1169 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1177 if self
.port
< 0 or self
.port
> 0xffff:
1178 raise TypeError("invalid port %d" % self
.port
)
1181 from _m5
.net
import IpWithPort
1182 return IpWithPort(self
.ip
, self
.port
)
1184 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1185 "%a %b %d %H:%M:%S %Y",
1186 "%Y/%m/%d %H:%M:%S",
1189 "%m/%d/%Y %H:%M:%S",
1192 "%m/%d/%y %H:%M:%S",
1197 def parse_time(value
):
1198 from time
import gmtime
, strptime
, struct_time
, time
1199 from datetime
import datetime
, date
1201 if isinstance(value
, struct_time
):
1204 if isinstance(value
, (int, long)):
1205 return gmtime(value
)
1207 if isinstance(value
, (datetime
, date
)):
1208 return value
.timetuple()
1210 if isinstance(value
, str):
1211 if value
in ('Now', 'Today'):
1212 return time
.gmtime(time
.time())
1214 for format
in time_formats
:
1216 return strptime(value
, format
)
1220 raise ValueError("Could not parse '%s' as a time" % value
)
1222 class Time(ParamValue
):
1226 def cxx_predecls(cls
, code
):
1227 code('#include <time.h>')
1229 def __init__(self
, value
):
1230 self
.value
= parse_time(value
)
1232 def __call__(self
, value
):
1233 self
.__init
__(value
)
1237 from _m5
.core
import tm
1240 return tm
.gmtime(calendar
.timegm(self
.value
))
1243 return time
.asctime(self
.value
)
1248 def get_config_as_dict(self
):
1253 def cxx_ini_predecls(cls
, code
):
1254 code('#include <time.h>')
1257 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1258 code('char *_parse_ret = strptime((${src}).c_str(),')
1259 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1260 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1262 # Enumerated types are a little more complex. The user specifies the
1263 # type as Enum(foo) where foo is either a list or dictionary of
1264 # alternatives (typically strings, but not necessarily so). (In the
1265 # long run, the integer value of the parameter will be the list index
1266 # or the corresponding dictionary value. For now, since we only check
1267 # that the alternative is valid and then spit it into a .ini file,
1268 # there's not much point in using the dictionary.)
1270 # What Enum() must do is generate a new type encapsulating the
1271 # provided list/dictionary so that specific values of the parameter
1272 # can be instances of that type. We define two hidden internal
1273 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1274 # derive the new type from the appropriate base class on the fly.
1277 # Metaclass for Enum types
1278 class MetaEnum(MetaParamValue
):
1279 def __new__(mcls
, name
, bases
, dict):
1280 assert name
not in allEnums
1282 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1283 allEnums
[name
] = cls
1286 def __init__(cls
, name
, bases
, init_dict
):
1287 if 'map' in init_dict
:
1288 if not isinstance(cls
.map, dict):
1289 raise TypeError("Enum-derived class attribute 'map' " \
1290 "must be of type dict")
1291 # build list of value strings from map
1292 cls
.vals
= list(cls
.map.keys())
1294 elif 'vals' in init_dict
:
1295 if not isinstance(cls
.vals
, list):
1296 raise TypeError("Enum-derived class attribute 'vals' " \
1297 "must be of type list")
1298 # build string->value map from vals sequence
1300 for idx
,val
in enumerate(cls
.vals
):
1303 raise TypeError("Enum-derived class must define "\
1304 "attribute 'map' or 'vals'")
1307 cls
.cxx_type
= '%s' % name
1309 cls
.cxx_type
= 'Enums::%s' % name
1311 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1313 # Generate C++ class declaration for this enum type.
1314 # Note that we wrap the enum in a class/struct to act as a namespace,
1315 # so that the enum strings can be brief w/o worrying about collisions.
1316 def cxx_decl(cls
, code
):
1317 wrapper_name
= cls
.wrapper_name
1318 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1319 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1320 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1333 $wrapper $wrapper_name {
1338 for val
in cls
.vals
:
1339 code('$val = ${{cls.map[val]}},')
1340 code('Num_$name = ${{len(cls.vals)}}')
1346 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1348 elif cls
.wrapper_is_struct
:
1349 code('static const char *${name}Strings[Num_${name}];')
1351 code('extern const char *${name}Strings[Num_${name}];')
1353 if not cls
.is_class
:
1358 code('#endif // $idem_macro')
1360 def cxx_def(cls
, code
):
1361 wrapper_name
= cls
.wrapper_name
1362 file_name
= cls
.__name
__
1363 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1365 code('#include "enums/$file_name.hh"')
1366 if cls
.wrapper_is_struct
:
1367 code('const char *${wrapper_name}::${name}Strings'
1372 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1375 code('namespace Enums {')
1377 code('const char *${name}Strings[Num_${name}] =')
1381 for val
in cls
.vals
:
1386 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1388 code('} // namespace $wrapper_name')
1391 def pybind_def(cls
, code
):
1393 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1394 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1396 code('''#include "pybind11/pybind11.h"
1397 #include "pybind11/stl.h"
1399 #include <sim/init.hh>
1401 namespace py = pybind11;
1404 module_init(py::module &m_internal)
1406 py::module m = m_internal.def_submodule("enum_${name}");
1410 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1412 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1416 for val
in cls
.vals
:
1417 code('.value("${val}", ${wrapper_name}::${val})')
1418 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1419 code('.export_values()')
1426 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1429 # Base class for enum types.
1430 class Enum(ParamValue
):
1431 __metaclass__
= MetaEnum
1433 cmd_line_settable
= True
1435 # The name of the wrapping namespace or struct
1436 wrapper_name
= 'Enums'
1438 # If true, the enum is wrapped in a struct rather than a namespace
1439 wrapper_is_struct
= False
1443 # If not None, use this as the enum name rather than this class name
1446 def __init__(self
, value
):
1447 if value
not in self
.map:
1448 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1449 % (value
, self
.vals
))
1452 def __call__(self
, value
):
1453 self
.__init
__(value
)
1457 def cxx_predecls(cls
, code
):
1458 code('#include "enums/$0.hh"', cls
.__name
__)
1461 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1462 code('if (false) {')
1463 for elem_name
in cls
.map.keys():
1464 code('} else if (%s == "%s") {' % (src
, elem_name
))
1466 code('%s = Enums::%s;' % (dest
, elem_name
))
1467 code('%s true;' % ret
)
1470 code(' %s false;' % ret
)
1474 import m5
.internal
.params
1475 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1476 return e(self
.map[self
.value
])
1481 # This param will generate a scoped c++ enum and its python bindings.
1482 class ScopedEnum(Enum
):
1483 __metaclass__
= MetaEnum
1485 cmd_line_settable
= True
1487 # The name of the wrapping namespace or struct
1490 # If true, the enum is wrapped in a struct rather than a namespace
1491 wrapper_is_struct
= False
1493 # If true, the generated enum is a scoped enum
1496 # If not None, use this as the enum name rather than this class name
1499 # how big does a rounding error need to be before we warn about it?
1500 frequency_tolerance
= 0.001 # 0.1%
1502 class TickParamValue(NumericParamValue
):
1505 cmd_line_settable
= True
1508 def cxx_predecls(cls
, code
):
1509 code('#include "base/types.hh"')
1511 def __call__(self
, value
):
1512 self
.__init
__(value
)
1516 return long(self
.value
)
1519 def cxx_ini_predecls(cls
, code
):
1520 code('#include <sstream>')
1522 # Ticks are expressed in seconds in JSON files and in plain
1523 # Ticks in .ini files. Switch based on a config flag
1525 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1526 code('${ret} to_number(${src}, ${dest});')
1528 class Latency(TickParamValue
):
1531 def __init__(self
, value
):
1532 if isinstance(value
, (Latency
, Clock
)):
1533 self
.ticks
= value
.ticks
1534 self
.value
= value
.value
1535 elif isinstance(value
, Frequency
):
1536 self
.ticks
= value
.ticks
1537 self
.value
= 1.0 / value
.value
1538 elif value
.endswith('t'):
1540 self
.value
= int(value
[:-1])
1543 self
.value
= convert
.toLatency(value
)
1545 def __call__(self
, value
):
1546 self
.__init
__(value
)
1549 def __getattr__(self
, attr
):
1550 if attr
in ('latency', 'period'):
1552 if attr
== 'frequency':
1553 return Frequency(self
)
1554 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1557 if self
.ticks
or self
.value
== 0:
1560 value
= ticks
.fromSeconds(self
.value
)
1563 def config_value(self
):
1564 return self
.getValue()
1566 # convert latency to ticks
1568 return '%d' % self
.getValue()
1570 class Frequency(TickParamValue
):
1573 def __init__(self
, value
):
1574 if isinstance(value
, (Latency
, Clock
)):
1575 if value
.value
== 0:
1578 self
.value
= 1.0 / value
.value
1579 self
.ticks
= value
.ticks
1580 elif isinstance(value
, Frequency
):
1581 self
.value
= value
.value
1582 self
.ticks
= value
.ticks
1585 self
.value
= convert
.toFrequency(value
)
1587 def __call__(self
, value
):
1588 self
.__init
__(value
)
1591 def __getattr__(self
, attr
):
1592 if attr
== 'frequency':
1594 if attr
in ('latency', 'period'):
1595 return Latency(self
)
1596 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1598 # convert latency to ticks
1600 if self
.ticks
or self
.value
== 0:
1603 value
= ticks
.fromSeconds(1.0 / self
.value
)
1606 def config_value(self
):
1607 return self
.getValue()
1610 return '%d' % self
.getValue()
1612 # A generic Frequency and/or Latency value. Value is stored as a
1613 # latency, just like Latency and Frequency.
1614 class Clock(TickParamValue
):
1615 def __init__(self
, value
):
1616 if isinstance(value
, (Latency
, Clock
)):
1617 self
.ticks
= value
.ticks
1618 self
.value
= value
.value
1619 elif isinstance(value
, Frequency
):
1620 self
.ticks
= value
.ticks
1621 self
.value
= 1.0 / value
.value
1622 elif value
.endswith('t'):
1624 self
.value
= int(value
[:-1])
1627 self
.value
= convert
.anyToLatency(value
)
1629 def __call__(self
, value
):
1630 self
.__init
__(value
)
1634 return "%s" % Latency(self
)
1636 def __getattr__(self
, attr
):
1637 if attr
== 'frequency':
1638 return Frequency(self
)
1639 if attr
in ('latency', 'period'):
1640 return Latency(self
)
1641 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1644 return self
.period
.getValue()
1646 def config_value(self
):
1647 return self
.period
.config_value()
1650 return self
.period
.ini_str()
1652 class Voltage(Float
):
1655 def __new__(cls
, value
):
1656 value
= convert
.toVoltage(value
)
1657 return super(cls
, Voltage
).__new
__(cls
, value
)
1659 def __init__(self
, value
):
1660 value
= convert
.toVoltage(value
)
1661 super(Voltage
, self
).__init
__(value
)
1663 class Current(Float
):
1666 def __new__(cls
, value
):
1667 value
= convert
.toCurrent(value
)
1668 return super(cls
, Current
).__new
__(cls
, value
)
1670 def __init__(self
, value
):
1671 value
= convert
.toCurrent(value
)
1672 super(Current
, self
).__init
__(value
)
1674 class Energy(Float
):
1677 def __new__(cls
, value
):
1678 value
= convert
.toEnergy(value
)
1679 return super(cls
, Energy
).__new
__(cls
, value
)
1681 def __init__(self
, value
):
1682 value
= convert
.toEnergy(value
)
1683 super(Energy
, self
).__init
__(value
)
1685 class NetworkBandwidth(float,ParamValue
):
1688 cmd_line_settable
= True
1690 def __new__(cls
, value
):
1691 # convert to bits per second
1692 val
= convert
.toNetworkBandwidth(value
)
1693 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1696 return str(self
.val
)
1698 def __call__(self
, value
):
1699 val
= convert
.toNetworkBandwidth(value
)
1704 # convert to seconds per byte
1705 value
= 8.0 / float(self
)
1706 # convert to ticks per byte
1707 value
= ticks
.fromSeconds(value
)
1711 return '%f' % self
.getValue()
1713 def config_value(self
):
1714 return '%f' % self
.getValue()
1717 def cxx_ini_predecls(cls
, code
):
1718 code('#include <sstream>')
1721 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1722 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1724 class MemoryBandwidth(float,ParamValue
):
1727 cmd_line_settable
= True
1729 def __new__(cls
, value
):
1730 # convert to bytes per second
1731 val
= convert
.toMemoryBandwidth(value
)
1732 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1734 def __call__(self
, value
):
1735 val
= convert
.toMemoryBandwidth(value
)
1740 # convert to seconds per byte
1743 value
= 1.0 / float(self
)
1744 # convert to ticks per byte
1745 value
= ticks
.fromSeconds(value
)
1749 return '%f' % self
.getValue()
1751 def config_value(self
):
1752 return '%f' % self
.getValue()
1755 def cxx_ini_predecls(cls
, code
):
1756 code('#include <sstream>')
1759 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1760 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1763 # "Constants"... handy aliases for various values.
1766 # Special class for NULL pointers. Note the special check in
1767 # make_param_value() above that lets these be assigned where a
1768 # SimObject is required.
1769 # only one copy of a particular node
1770 class NullSimObject(object):
1771 __metaclass__
= Singleton
1777 def _instantiate(self
, parent
= None, path
= ''):
1783 def unproxy(self
, base
):
1786 def set_path(self
, parent
, name
):
1789 def set_parent(self
, parent
, name
):
1792 def clear_parent(self
, old_parent
):
1795 def descendants(self
):
1799 def get_config_as_dict(self
):
1805 def config_value(self
):
1811 # The only instance you'll ever need...
1812 NULL
= NullSimObject()
1814 def isNullPointer(value
):
1815 return isinstance(value
, NullSimObject
)
1817 # Some memory range specifications use this as a default upper bound.
1820 AllMemory
= AddrRange(0, MaxAddr
)
1823 #####################################################################
1827 # Ports are used to interconnect objects in the memory system.
1829 #####################################################################
1831 # Port reference: encapsulates a reference to a particular port on a
1832 # particular SimObject.
1833 class PortRef(object):
1834 def __init__(self
, simobj
, name
, role
):
1835 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1836 self
.simobj
= simobj
1839 self
.peer
= None # not associated with another port yet
1840 self
.ccConnected
= False # C++ port connection done?
1841 self
.index
= -1 # always -1 for non-vector ports
1844 return '%s.%s' % (self
.simobj
, self
.name
)
1847 # Return the number of connected ports, i.e. 0 is we have no
1848 # peer and 1 if we do.
1849 return int(self
.peer
!= None)
1851 # for config.ini, print peer's name (not ours)
1853 return str(self
.peer
)
1856 def get_config_as_dict(self
):
1857 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1859 def __getattr__(self
, attr
):
1860 if attr
== 'peerObj':
1861 # shorthand for proxies
1862 return self
.peer
.simobj
1863 raise AttributeError("'%s' object has no attribute '%s'" % \
1864 (self
.__class
__.__name
__, attr
))
1866 # Full connection is symmetric (both ways). Called via
1867 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1868 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1869 # e.g., "obj1.portA[3] = obj2.portB".
1870 def connect(self
, other
):
1871 if isinstance(other
, VectorPortRef
):
1872 # reference to plain VectorPort is implicit append
1873 other
= other
._get
_next
()
1874 if self
.peer
and not proxy
.isproxy(self
.peer
):
1875 fatal("Port %s is already connected to %s, cannot connect %s\n",
1876 self
, self
.peer
, other
);
1878 if proxy
.isproxy(other
):
1879 other
.set_param_desc(PortParamDesc())
1880 elif isinstance(other
, PortRef
):
1881 if other
.peer
is not self
:
1884 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1887 # Allow a master/slave port pair to be spliced between
1888 # a port and its connected peer. Useful operation for connecting
1889 # instrumentation structures into a system when it is necessary
1890 # to connect the instrumentation after the full system has been
1892 def splice(self
, new_master_peer
, new_slave_peer
):
1893 if not self
.peer
or proxy
.isproxy(self
.peer
):
1894 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1896 if not isinstance(new_master_peer
, PortRef
) or \
1897 not isinstance(new_slave_peer
, PortRef
):
1899 "Splicing non-port references '%s','%s' to port '%s'" % \
1900 (new_master_peer
, new_slave_peer
, self
))
1902 old_peer
= self
.peer
1903 if self
.role
== 'SLAVE':
1904 self
.peer
= new_master_peer
1905 old_peer
.peer
= new_slave_peer
1906 new_master_peer
.connect(self
)
1907 new_slave_peer
.connect(old_peer
)
1908 elif self
.role
== 'MASTER':
1909 self
.peer
= new_slave_peer
1910 old_peer
.peer
= new_master_peer
1911 new_slave_peer
.connect(self
)
1912 new_master_peer
.connect(old_peer
)
1914 panic("Port %s has unknown role, "+\
1915 "cannot splice in new peers\n", self
)
1917 def clone(self
, simobj
, memo
):
1920 newRef
= copy
.copy(self
)
1922 newRef
.simobj
= simobj
1923 assert(isSimObject(newRef
.simobj
))
1924 if self
.peer
and not proxy
.isproxy(self
.peer
):
1925 peerObj
= self
.peer
.simobj(_memo
=memo
)
1926 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1927 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1930 def unproxy(self
, simobj
):
1931 assert(simobj
is self
.simobj
)
1932 if proxy
.isproxy(self
.peer
):
1934 realPeer
= self
.peer
.unproxy(self
.simobj
)
1936 print("Error in unproxying port '%s' of %s" %
1937 (self
.name
, self
.simobj
.path()))
1939 self
.connect(realPeer
)
1941 # Call C++ to create corresponding port connection between C++ objects
1942 def ccConnect(self
):
1943 from _m5
.pyobject
import connectPorts
1945 if self
.ccConnected
: # already done this
1949 if not self
.peer
: # nothing to connect to
1952 # check that we connect a master to a slave
1953 if self
.role
== peer
.role
:
1955 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1956 (peer
, self
, self
.role
))
1958 if self
.role
== 'SLAVE':
1959 # do nothing and let the master take care of it
1963 # self is always the master and peer the slave
1964 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1965 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1967 print("Error connecting port %s.%s to %s.%s" %
1968 (self
.simobj
.path(), self
.name
,
1969 peer
.simobj
.path(), peer
.name
))
1971 self
.ccConnected
= True
1972 peer
.ccConnected
= True
1974 # A reference to an individual element of a VectorPort... much like a
1975 # PortRef, but has an index.
1976 class VectorPortElementRef(PortRef
):
1977 def __init__(self
, simobj
, name
, role
, index
):
1978 PortRef
.__init
__(self
, simobj
, name
, role
)
1982 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1984 # A reference to a complete vector-valued port (not just a single element).
1985 # Can be indexed to retrieve individual VectorPortElementRef instances.
1986 class VectorPortRef(object):
1987 def __init__(self
, simobj
, name
, role
):
1988 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1989 self
.simobj
= simobj
1995 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1998 # Return the number of connected peers, corresponding the the
1999 # length of the elements.
2000 return len(self
.elements
)
2002 # for config.ini, print peer's name (not ours)
2004 return ' '.join([el
.ini_str() for el
in self
.elements
])
2007 def get_config_as_dict(self
):
2008 return {'role' : self
.role
,
2009 'peer' : [el
.ini_str() for el
in self
.elements
]}
2011 def __getitem__(self
, key
):
2012 if not isinstance(key
, int):
2013 raise TypeError("VectorPort index must be integer")
2014 if key
>= len(self
.elements
):
2015 # need to extend list
2016 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
2017 for i
in range(len(self
.elements
), key
+1)]
2018 self
.elements
.extend(ext
)
2019 return self
.elements
[key
]
2021 def _get_next(self
):
2022 return self
[len(self
.elements
)]
2024 def __setitem__(self
, key
, value
):
2025 if not isinstance(key
, int):
2026 raise TypeError("VectorPort index must be integer")
2027 self
[key
].connect(value
)
2029 def connect(self
, other
):
2030 if isinstance(other
, (list, tuple)):
2031 # Assign list of port refs to vector port.
2032 # For now, append them... not sure if that's the right semantics
2033 # or if it should replace the current vector.
2035 self
._get
_next
().connect(ref
)
2037 # scalar assignment to plain VectorPort is implicit append
2038 self
._get
_next
().connect(other
)
2040 def clone(self
, simobj
, memo
):
2043 newRef
= copy
.copy(self
)
2045 newRef
.simobj
= simobj
2046 assert(isSimObject(newRef
.simobj
))
2047 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2050 def unproxy(self
, simobj
):
2051 [el
.unproxy(simobj
) for el
in self
.elements
]
2053 def ccConnect(self
):
2054 [el
.ccConnect() for el
in self
.elements
]
2056 # Port description object. Like a ParamDesc object, this represents a
2057 # logical port in the SimObject class, not a particular port on a
2058 # SimObject instance. The latter are represented by PortRef objects.
2060 # Generate a PortRef for this port on the given SimObject with the
2062 def makeRef(self
, simobj
):
2063 return PortRef(simobj
, self
.name
, self
.role
)
2065 # Connect an instance of this port (on the given SimObject with
2066 # the given name) with the port described by the supplied PortRef
2067 def connect(self
, simobj
, ref
):
2068 self
.makeRef(simobj
).connect(ref
)
2070 # No need for any pre-declarations at the moment as we merely rely
2071 # on an unsigned int.
2072 def cxx_predecls(self
, code
):
2075 def pybind_predecls(self
, code
):
2076 cls
.cxx_predecls(self
, code
)
2078 # Declare an unsigned int with the same name as the port, that
2079 # will eventually hold the number of connected ports (and thus the
2080 # number of elements for a VectorPort).
2081 def cxx_decl(self
, code
):
2082 code('unsigned int port_${{self.name}}_connection_count;')
2084 class MasterPort(Port
):
2085 # MasterPort("description")
2086 def __init__(self
, *args
):
2089 self
.role
= 'MASTER'
2091 raise TypeError('wrong number of arguments')
2093 class SlavePort(Port
):
2094 # SlavePort("description")
2095 def __init__(self
, *args
):
2100 raise TypeError('wrong number of arguments')
2102 # VectorPort description object. Like Port, but represents a vector
2103 # of connections (e.g., as on a XBar).
2104 class VectorPort(Port
):
2105 def __init__(self
, *args
):
2108 def makeRef(self
, simobj
):
2109 return VectorPortRef(simobj
, self
.name
, self
.role
)
2111 class VectorMasterPort(VectorPort
):
2112 # VectorMasterPort("description")
2113 def __init__(self
, *args
):
2116 self
.role
= 'MASTER'
2117 VectorPort
.__init
__(self
, *args
)
2119 raise TypeError('wrong number of arguments')
2121 class VectorSlavePort(VectorPort
):
2122 # VectorSlavePort("description")
2123 def __init__(self
, *args
):
2127 VectorPort
.__init
__(self
, *args
)
2129 raise TypeError('wrong number of arguments')
2131 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2132 # proxy objects (via set_param_desc()) so that proxy error messages
2134 class PortParamDesc(object):
2135 __metaclass__
= Singleton
2140 baseEnums
= allEnums
.copy()
2141 baseParams
= allParams
.copy()
2144 global allEnums
, allParams
2146 allEnums
= baseEnums
.copy()
2147 allParams
= baseParams
.copy()
2149 __all__
= ['Param', 'VectorParam',
2150 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2151 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2152 'Int32', 'UInt32', 'Int64', 'UInt64',
2153 'Counter', 'Addr', 'Tick', 'Percent',
2154 'TcpPort', 'UdpPort', 'EthernetAddr',
2155 'IpAddress', 'IpNetmask', 'IpWithPort',
2156 'MemorySize', 'MemorySize32',
2157 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2158 'NetworkBandwidth', 'MemoryBandwidth',
2160 'MaxAddr', 'MaxTick', 'AllMemory',
2162 'NextEthernetAddr', 'NULL',
2163 'MasterPort', 'SlavePort',
2164 'VectorMasterPort', 'VectorSlavePort']