5eabce1cd64da4bea47911c19cc929b2f0959049
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
):
458 return str(self
.value
)
461 return float(self
.value
)
464 return long(self
.value
)
467 return int(self
.value
)
469 # hook for bounds checking
473 def __mul__(self
, other
):
474 newobj
= self
.__class
__(self
)
475 newobj
.value
*= other
481 def __div__(self
, other
):
482 newobj
= self
.__class
__(self
)
483 newobj
.value
/= other
487 def __sub__(self
, other
):
488 newobj
= self
.__class
__(self
)
489 newobj
.value
-= other
493 def config_value(self
):
497 def cxx_ini_predecls(cls
, code
):
498 # Assume that base/str.hh will be included anyway
499 # code('#include "base/str.hh"')
502 # The default for parsing PODs from an .ini entry is to extract from an
503 # istringstream and let overloading choose the right type according to
506 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
507 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
509 # Metaclass for bounds-checked integer parameters. See CheckedInt.
510 class CheckedIntType(MetaParamValue
):
511 def __init__(cls
, name
, bases
, dict):
512 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
514 # CheckedInt is an abstract base class, so we actually don't
515 # want to do any processing on it... the rest of this code is
516 # just for classes that derive from CheckedInt.
517 if name
== 'CheckedInt':
520 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
521 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
522 panic("CheckedInt subclass %s must define either\n" \
523 " 'min' and 'max' or 'size' and 'unsigned'\n",
527 cls
.max = 2 ** cls
.size
- 1
529 cls
.min = -(2 ** (cls
.size
- 1))
530 cls
.max = (2 ** (cls
.size
- 1)) - 1
532 # Abstract superclass for bounds-checked integer parameters. This
533 # class is subclassed to generate parameter classes with specific
534 # bounds. Initialization of the min and max bounds is done in the
535 # metaclass CheckedIntType.__init__.
536 class CheckedInt(NumericParamValue
):
537 __metaclass__
= CheckedIntType
538 cmd_line_settable
= True
541 if not self
.min <= self
.value
<= self
.max:
542 raise TypeError('Integer param out of bounds %d < %d < %d' % \
543 (self
.min, self
.value
, self
.max))
545 def __init__(self
, value
):
546 if isinstance(value
, str):
547 self
.value
= convert
.toInteger(value
)
548 elif isinstance(value
, (int, long, float, NumericParamValue
)):
549 self
.value
= long(value
)
551 raise TypeError("Can't convert object of type %s to CheckedInt" \
552 % type(value
).__name
__)
555 def __call__(self
, value
):
560 def cxx_predecls(cls
, code
):
561 # most derived types require this, so we just do it here once
562 code('#include "base/types.hh"')
565 return long(self
.value
)
567 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
568 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
570 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
571 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
572 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
573 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
574 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
575 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
576 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
577 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
579 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
580 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
581 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
582 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
584 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
586 class Cycles(CheckedInt
):
592 from _m5
.core
import Cycles
593 return Cycles(self
.value
)
596 def cxx_ini_predecls(cls
, code
):
597 # Assume that base/str.hh will be included anyway
598 # code('#include "base/str.hh"')
602 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
603 code('uint64_t _temp;')
604 code('bool _ret = to_number(%s, _temp);' % src
)
606 code(' %s = Cycles(_temp);' % dest
)
607 code('%s _ret;' % ret
)
609 class Float(ParamValue
, float):
611 cmd_line_settable
= True
613 def __init__(self
, value
):
614 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
615 self
.value
= float(value
)
617 raise TypeError("Can't convert object of type %s to Float" \
618 % type(value
).__name
__)
620 def __call__(self
, value
):
625 return float(self
.value
)
627 def config_value(self
):
631 def cxx_ini_predecls(cls
, code
):
632 code('#include <sstream>')
635 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
636 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
638 class MemorySize(CheckedInt
):
639 cxx_type
= 'uint64_t'
643 def __init__(self
, value
):
644 if isinstance(value
, MemorySize
):
645 self
.value
= value
.value
647 self
.value
= convert
.toMemorySize(value
)
650 class MemorySize32(CheckedInt
):
651 cxx_type
= 'uint32_t'
655 def __init__(self
, value
):
656 if isinstance(value
, MemorySize
):
657 self
.value
= value
.value
659 self
.value
= convert
.toMemorySize(value
)
662 class Addr(CheckedInt
):
666 def __init__(self
, value
):
667 if isinstance(value
, Addr
):
668 self
.value
= value
.value
671 # Often addresses are referred to with sizes. Ex: A device
672 # base address is at "512MB". Use toMemorySize() to convert
673 # these into addresses. If the address is not specified with a
674 # "size", an exception will occur and numeric translation will
676 self
.value
= convert
.toMemorySize(value
)
677 except (TypeError, ValueError):
678 # Convert number to string and use long() to do automatic
679 # base conversion (requires base=0 for auto-conversion)
680 self
.value
= long(str(value
), base
=0)
683 def __add__(self
, other
):
684 if isinstance(other
, Addr
):
685 return self
.value
+ other
.value
687 return self
.value
+ other
688 def pretty_print(self
, value
):
690 val
= convert
.toMemorySize(value
)
693 return "0x%x" % long(val
)
695 class AddrRange(ParamValue
):
696 cxx_type
= 'AddrRange'
698 def __init__(self
, *args
, **kwargs
):
699 # Disable interleaving and hashing by default
700 self
.intlvHighBit
= 0
705 def handle_kwargs(self
, kwargs
):
706 # An address range needs to have an upper limit, specified
707 # either explicitly with an end, or as an offset using the
710 self
.end
= Addr(kwargs
.pop('end'))
711 elif 'size' in kwargs
:
712 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
714 raise TypeError("Either end or size must be specified")
716 # Now on to the optional bit
717 if 'intlvHighBit' in kwargs
:
718 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
719 if 'xorHighBit' in kwargs
:
720 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
721 if 'intlvBits' in kwargs
:
722 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
723 if 'intlvMatch' in kwargs
:
724 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
727 self
.start
= Addr(kwargs
.pop('start'))
728 handle_kwargs(self
, kwargs
)
732 self
.start
= Addr(args
[0])
733 handle_kwargs(self
, kwargs
)
734 elif isinstance(args
[0], (list, tuple)):
735 self
.start
= Addr(args
[0][0])
736 self
.end
= Addr(args
[0][1])
739 self
.end
= Addr(args
[0]) - 1
742 self
.start
= Addr(args
[0])
743 self
.end
= Addr(args
[1])
745 raise TypeError("Too many arguments specified")
748 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
751 return '%s:%s:%s:%s:%s:%s' \
752 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
753 self
.intlvBits
, self
.intlvMatch
)
756 # Divide the size by the size of the interleaving slice
757 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
760 def cxx_predecls(cls
, code
):
761 Addr
.cxx_predecls(code
)
762 code('#include "base/addr_range.hh"')
765 def pybind_predecls(cls
, code
):
766 Addr
.pybind_predecls(code
)
767 code('#include "base/addr_range.hh"')
770 def cxx_ini_predecls(cls
, code
):
771 code('#include <sstream>')
774 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
775 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
776 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
778 code('std::istringstream _stream(${src});')
779 code('_stream >> _start;')
780 code('_stream.get(_sep);')
781 code('_stream >> _end;')
782 code('if (!_stream.fail() && !_stream.eof()) {')
783 code(' _stream.get(_sep);')
784 code(' _stream >> _intlvHighBit;')
785 code(' _stream.get(_sep);')
786 code(' _stream >> _xorHighBit;')
787 code(' _stream.get(_sep);')
788 code(' _stream >> _intlvBits;')
789 code(' _stream.get(_sep);')
790 code(' _stream >> _intlvMatch;')
792 code('bool _ret = !_stream.fail() &&'
793 '_stream.eof() && _sep == \':\';')
795 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
796 _xorHighBit, _intlvBits, _intlvMatch);')
800 # Go from the Python class to the wrapped C++ class
801 from _m5
.range import AddrRange
803 return AddrRange(long(self
.start
), long(self
.end
),
804 int(self
.intlvHighBit
), int(self
.xorHighBit
),
805 int(self
.intlvBits
), int(self
.intlvMatch
))
807 # Boolean parameter type. Python doesn't let you subclass bool, since
808 # it doesn't want to let you create multiple instances of True and
809 # False. Thus this is a little more complicated than String.
810 class Bool(ParamValue
):
812 cmd_line_settable
= True
814 def __init__(self
, value
):
816 self
.value
= convert
.toBool(value
)
818 self
.value
= bool(value
)
820 def __call__(self
, value
):
825 return bool(self
.value
)
828 return str(self
.value
)
830 # implement truth value testing for Bool parameters so that these params
831 # evaluate correctly during the python configuration phase
833 return bool(self
.value
)
835 # Python 2.7 uses __nonzero__ instead of __bool__
836 __nonzero__
= __bool__
843 def config_value(self
):
847 def cxx_ini_predecls(cls
, code
):
848 # Assume that base/str.hh will be included anyway
849 # code('#include "base/str.hh"')
853 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
854 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
856 def IncEthernetAddr(addr
, val
= 1):
857 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
859 for i
in (5, 4, 3, 2, 1):
860 val
,rem
= divmod(bytes
[i
], 256)
865 assert(bytes
[0] <= 255)
866 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
868 _NextEthernetAddr
= "00:90:00:00:00:01"
869 def NextEthernetAddr():
870 global _NextEthernetAddr
872 value
= _NextEthernetAddr
873 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
876 class EthernetAddr(ParamValue
):
877 cxx_type
= 'Net::EthAddr'
878 ex_str
= "00:90:00:00:00:01"
879 cmd_line_settable
= True
882 def cxx_predecls(cls
, code
):
883 code('#include "base/inet.hh"')
885 def __init__(self
, value
):
886 if value
== NextEthernetAddr
:
890 if not isinstance(value
, str):
891 raise TypeError("expected an ethernet address and didn't get one")
893 bytes
= value
.split(':')
895 raise TypeError('invalid ethernet address %s' % value
)
898 if not 0 <= int(byte
, base
=16) <= 0xff:
899 raise TypeError('invalid ethernet address %s' % value
)
903 def __call__(self
, value
):
907 def unproxy(self
, base
):
908 if self
.value
== NextEthernetAddr
:
909 return EthernetAddr(self
.value())
913 from _m5
.net
import EthAddr
914 return EthAddr(self
.value
)
923 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
924 code('%s = Net::EthAddr(%s);' % (dest
, src
))
925 code('%s true;' % ret
)
927 # When initializing an IpAddress, pass in an existing IpAddress, a string of
928 # the form "a.b.c.d", or an integer representing an IP.
929 class IpAddress(ParamValue
):
930 cxx_type
= 'Net::IpAddress'
932 cmd_line_settable
= True
935 def cxx_predecls(cls
, code
):
936 code('#include "base/inet.hh"')
938 def __init__(self
, value
):
939 if isinstance(value
, IpAddress
):
943 self
.ip
= convert
.toIpAddress(value
)
945 self
.ip
= long(value
)
948 def __call__(self
, value
):
953 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
954 return '%d.%d.%d.%d' % tuple(tup
)
956 def __eq__(self
, other
):
957 if isinstance(other
, IpAddress
):
958 return self
.ip
== other
.ip
959 elif isinstance(other
, str):
961 return self
.ip
== convert
.toIpAddress(other
)
965 return self
.ip
== other
967 def __ne__(self
, other
):
968 return not (self
== other
)
971 if self
.ip
< 0 or self
.ip
>= (1 << 32):
972 raise TypeError("invalid ip address %#08x" % self
.ip
)
975 from _m5
.net
import IpAddress
976 return IpAddress(self
.ip
)
978 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
979 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
980 # positional or keyword arguments.
981 class IpNetmask(IpAddress
):
982 cxx_type
= 'Net::IpNetmask'
983 ex_str
= "127.0.0.0/24"
984 cmd_line_settable
= True
987 def cxx_predecls(cls
, code
):
988 code('#include "base/inet.hh"')
990 def __init__(self
, *args
, **kwargs
):
991 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
993 setattr(self
, key
, kwargs
.pop(key
))
995 setattr(self
, key
, elseVal
)
997 raise TypeError("No value set for %s" % key
)
1000 handle_kwarg(self
, kwargs
, 'ip')
1001 handle_kwarg(self
, kwargs
, 'netmask')
1003 elif len(args
) == 1:
1005 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1006 raise TypeError("Invalid arguments")
1007 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1008 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1009 elif isinstance(args
[0], IpNetmask
):
1010 self
.ip
= args
[0].ip
1011 self
.netmask
= args
[0].netmask
1013 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1015 elif len(args
) == 2:
1017 self
.netmask
= args
[1]
1019 raise TypeError("Too many arguments specified")
1022 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1026 def __call__(self
, value
):
1027 self
.__init
__(value
)
1031 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1033 def __eq__(self
, other
):
1034 if isinstance(other
, IpNetmask
):
1035 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1036 elif isinstance(other
, str):
1038 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1046 if self
.netmask
< 0 or self
.netmask
> 32:
1047 raise TypeError("invalid netmask %d" % netmask
)
1050 from _m5
.net
import IpNetmask
1051 return IpNetmask(self
.ip
, self
.netmask
)
1053 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1054 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1055 class IpWithPort(IpAddress
):
1056 cxx_type
= 'Net::IpWithPort'
1057 ex_str
= "127.0.0.1:80"
1058 cmd_line_settable
= True
1061 def cxx_predecls(cls
, code
):
1062 code('#include "base/inet.hh"')
1064 def __init__(self
, *args
, **kwargs
):
1065 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1067 setattr(self
, key
, kwargs
.pop(key
))
1069 setattr(self
, key
, elseVal
)
1071 raise TypeError("No value set for %s" % key
)
1074 handle_kwarg(self
, kwargs
, 'ip')
1075 handle_kwarg(self
, kwargs
, 'port')
1077 elif len(args
) == 1:
1079 if not 'ip' in kwargs
and not 'port' in kwargs
:
1080 raise TypeError("Invalid arguments")
1081 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1082 handle_kwarg(self
, kwargs
, 'port', args
[0])
1083 elif isinstance(args
[0], IpWithPort
):
1084 self
.ip
= args
[0].ip
1085 self
.port
= args
[0].port
1087 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1089 elif len(args
) == 2:
1093 raise TypeError("Too many arguments specified")
1096 raise TypeError("Too many keywords: %s" % list(kwargs
.keys()))
1100 def __call__(self
, value
):
1101 self
.__init
__(value
)
1105 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1107 def __eq__(self
, other
):
1108 if isinstance(other
, IpWithPort
):
1109 return self
.ip
== other
.ip
and self
.port
== other
.port
1110 elif isinstance(other
, str):
1112 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1120 if self
.port
< 0 or self
.port
> 0xffff:
1121 raise TypeError("invalid port %d" % self
.port
)
1124 from _m5
.net
import IpWithPort
1125 return IpWithPort(self
.ip
, self
.port
)
1127 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1128 "%a %b %d %H:%M:%S %Y",
1129 "%Y/%m/%d %H:%M:%S",
1132 "%m/%d/%Y %H:%M:%S",
1135 "%m/%d/%y %H:%M:%S",
1140 def parse_time(value
):
1141 from time
import gmtime
, strptime
, struct_time
, time
1142 from datetime
import datetime
, date
1144 if isinstance(value
, struct_time
):
1147 if isinstance(value
, (int, long)):
1148 return gmtime(value
)
1150 if isinstance(value
, (datetime
, date
)):
1151 return value
.timetuple()
1153 if isinstance(value
, str):
1154 if value
in ('Now', 'Today'):
1155 return time
.gmtime(time
.time())
1157 for format
in time_formats
:
1159 return strptime(value
, format
)
1163 raise ValueError("Could not parse '%s' as a time" % value
)
1165 class Time(ParamValue
):
1169 def cxx_predecls(cls
, code
):
1170 code('#include <time.h>')
1172 def __init__(self
, value
):
1173 self
.value
= parse_time(value
)
1175 def __call__(self
, value
):
1176 self
.__init
__(value
)
1180 from _m5
.core
import tm
1183 return tm
.gmtime(calendar
.timegm(self
.value
))
1186 return time
.asctime(self
.value
)
1191 def get_config_as_dict(self
):
1196 def cxx_ini_predecls(cls
, code
):
1197 code('#include <time.h>')
1200 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1201 code('char *_parse_ret = strptime((${src}).c_str(),')
1202 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1203 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1205 # Enumerated types are a little more complex. The user specifies the
1206 # type as Enum(foo) where foo is either a list or dictionary of
1207 # alternatives (typically strings, but not necessarily so). (In the
1208 # long run, the integer value of the parameter will be the list index
1209 # or the corresponding dictionary value. For now, since we only check
1210 # that the alternative is valid and then spit it into a .ini file,
1211 # there's not much point in using the dictionary.)
1213 # What Enum() must do is generate a new type encapsulating the
1214 # provided list/dictionary so that specific values of the parameter
1215 # can be instances of that type. We define two hidden internal
1216 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1217 # derive the new type from the appropriate base class on the fly.
1220 # Metaclass for Enum types
1221 class MetaEnum(MetaParamValue
):
1222 def __new__(mcls
, name
, bases
, dict):
1223 assert name
not in allEnums
1225 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1226 allEnums
[name
] = cls
1229 def __init__(cls
, name
, bases
, init_dict
):
1230 if 'map' in init_dict
:
1231 if not isinstance(cls
.map, dict):
1232 raise TypeError("Enum-derived class attribute 'map' " \
1233 "must be of type dict")
1234 # build list of value strings from map
1235 cls
.vals
= cls
.map.keys()
1237 elif 'vals' in init_dict
:
1238 if not isinstance(cls
.vals
, list):
1239 raise TypeError("Enum-derived class attribute 'vals' " \
1240 "must be of type list")
1241 # build string->value map from vals sequence
1243 for idx
,val
in enumerate(cls
.vals
):
1246 raise TypeError("Enum-derived class must define "\
1247 "attribute 'map' or 'vals'")
1250 cls
.cxx_type
= '%s' % name
1252 cls
.cxx_type
= 'Enums::%s' % name
1254 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1256 # Generate C++ class declaration for this enum type.
1257 # Note that we wrap the enum in a class/struct to act as a namespace,
1258 # so that the enum strings can be brief w/o worrying about collisions.
1259 def cxx_decl(cls
, code
):
1260 wrapper_name
= cls
.wrapper_name
1261 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1262 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1263 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1276 $wrapper $wrapper_name {
1281 for val
in cls
.vals
:
1282 code('$val = ${{cls.map[val]}},')
1283 code('Num_$name = ${{len(cls.vals)}}')
1289 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1291 elif cls
.wrapper_is_struct
:
1292 code('static const char *${name}Strings[Num_${name}];')
1294 code('extern const char *${name}Strings[Num_${name}];')
1296 if not cls
.is_class
:
1301 code('#endif // $idem_macro')
1303 def cxx_def(cls
, code
):
1304 wrapper_name
= cls
.wrapper_name
1305 file_name
= cls
.__name
__
1306 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1308 code('#include "enums/$file_name.hh"')
1309 if cls
.wrapper_is_struct
:
1310 code('const char *${wrapper_name}::${name}Strings'
1315 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1318 code('namespace Enums {')
1320 code('const char *${name}Strings[Num_${name}] =')
1324 for val
in cls
.vals
:
1329 if not cls
.wrapper_is_struct
and not cls
.is_class
:
1331 code('} // namespace $wrapper_name')
1334 def pybind_def(cls
, code
):
1336 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1337 wrapper_name
= enum_name
if cls
.is_class
else cls
.wrapper_name
1339 code('''#include "pybind11/pybind11.h"
1340 #include "pybind11/stl.h"
1342 #include <sim/init.hh>
1344 namespace py = pybind11;
1347 module_init(py::module &m_internal)
1349 py::module m = m_internal.def_submodule("enum_${name}");
1353 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1355 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1359 for val
in cls
.vals
:
1360 code('.value("${val}", ${wrapper_name}::${val})')
1361 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1362 code('.export_values()')
1369 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1372 # Base class for enum types.
1373 class Enum(ParamValue
):
1374 __metaclass__
= MetaEnum
1376 cmd_line_settable
= True
1378 # The name of the wrapping namespace or struct
1379 wrapper_name
= 'Enums'
1381 # If true, the enum is wrapped in a struct rather than a namespace
1382 wrapper_is_struct
= False
1386 # If not None, use this as the enum name rather than this class name
1389 def __init__(self
, value
):
1390 if value
not in self
.map:
1391 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1392 % (value
, self
.vals
))
1395 def __call__(self
, value
):
1396 self
.__init
__(value
)
1400 def cxx_predecls(cls
, code
):
1401 code('#include "enums/$0.hh"', cls
.__name
__)
1404 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1405 code('if (false) {')
1406 for elem_name
in cls
.map.iterkeys():
1407 code('} else if (%s == "%s") {' % (src
, elem_name
))
1409 code('%s = Enums::%s;' % (dest
, elem_name
))
1410 code('%s true;' % ret
)
1413 code(' %s false;' % ret
)
1417 import m5
.internal
.params
1418 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1419 return e(self
.map[self
.value
])
1424 # This param will generate a scoped c++ enum and its python bindings.
1425 class ScopedEnum(Enum
):
1426 __metaclass__
= MetaEnum
1428 cmd_line_settable
= True
1430 # The name of the wrapping namespace or struct
1433 # If true, the enum is wrapped in a struct rather than a namespace
1434 wrapper_is_struct
= False
1436 # If true, the generated enum is a scoped enum
1439 # If not None, use this as the enum name rather than this class name
1442 # how big does a rounding error need to be before we warn about it?
1443 frequency_tolerance
= 0.001 # 0.1%
1445 class TickParamValue(NumericParamValue
):
1448 cmd_line_settable
= True
1451 def cxx_predecls(cls
, code
):
1452 code('#include "base/types.hh"')
1454 def __call__(self
, value
):
1455 self
.__init
__(value
)
1459 return long(self
.value
)
1462 def cxx_ini_predecls(cls
, code
):
1463 code('#include <sstream>')
1465 # Ticks are expressed in seconds in JSON files and in plain
1466 # Ticks in .ini files. Switch based on a config flag
1468 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1469 code('${ret} to_number(${src}, ${dest});')
1471 class Latency(TickParamValue
):
1474 def __init__(self
, value
):
1475 if isinstance(value
, (Latency
, Clock
)):
1476 self
.ticks
= value
.ticks
1477 self
.value
= value
.value
1478 elif isinstance(value
, Frequency
):
1479 self
.ticks
= value
.ticks
1480 self
.value
= 1.0 / value
.value
1481 elif value
.endswith('t'):
1483 self
.value
= int(value
[:-1])
1486 self
.value
= convert
.toLatency(value
)
1488 def __call__(self
, value
):
1489 self
.__init
__(value
)
1492 def __getattr__(self
, attr
):
1493 if attr
in ('latency', 'period'):
1495 if attr
== 'frequency':
1496 return Frequency(self
)
1497 raise AttributeError("Latency object has no attribute '%s'" % attr
)
1500 if self
.ticks
or self
.value
== 0:
1503 value
= ticks
.fromSeconds(self
.value
)
1506 def config_value(self
):
1507 return self
.getValue()
1509 # convert latency to ticks
1511 return '%d' % self
.getValue()
1513 class Frequency(TickParamValue
):
1516 def __init__(self
, value
):
1517 if isinstance(value
, (Latency
, Clock
)):
1518 if value
.value
== 0:
1521 self
.value
= 1.0 / value
.value
1522 self
.ticks
= value
.ticks
1523 elif isinstance(value
, Frequency
):
1524 self
.value
= value
.value
1525 self
.ticks
= value
.ticks
1528 self
.value
= convert
.toFrequency(value
)
1530 def __call__(self
, value
):
1531 self
.__init
__(value
)
1534 def __getattr__(self
, attr
):
1535 if attr
== 'frequency':
1537 if attr
in ('latency', 'period'):
1538 return Latency(self
)
1539 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1541 # convert latency to ticks
1543 if self
.ticks
or self
.value
== 0:
1546 value
= ticks
.fromSeconds(1.0 / self
.value
)
1549 def config_value(self
):
1550 return self
.getValue()
1553 return '%d' % self
.getValue()
1555 # A generic Frequency and/or Latency value. Value is stored as a
1556 # latency, just like Latency and Frequency.
1557 class Clock(TickParamValue
):
1558 def __init__(self
, value
):
1559 if isinstance(value
, (Latency
, Clock
)):
1560 self
.ticks
= value
.ticks
1561 self
.value
= value
.value
1562 elif isinstance(value
, Frequency
):
1563 self
.ticks
= value
.ticks
1564 self
.value
= 1.0 / value
.value
1565 elif value
.endswith('t'):
1567 self
.value
= int(value
[:-1])
1570 self
.value
= convert
.anyToLatency(value
)
1572 def __call__(self
, value
):
1573 self
.__init
__(value
)
1577 return "%s" % Latency(self
)
1579 def __getattr__(self
, attr
):
1580 if attr
== 'frequency':
1581 return Frequency(self
)
1582 if attr
in ('latency', 'period'):
1583 return Latency(self
)
1584 raise AttributeError("Frequency object has no attribute '%s'" % attr
)
1587 return self
.period
.getValue()
1589 def config_value(self
):
1590 return self
.period
.config_value()
1593 return self
.period
.ini_str()
1595 class Voltage(Float
):
1598 def __new__(cls
, value
):
1599 value
= convert
.toVoltage(value
)
1600 return super(cls
, Voltage
).__new
__(cls
, value
)
1602 def __init__(self
, value
):
1603 value
= convert
.toVoltage(value
)
1604 super(Voltage
, self
).__init
__(value
)
1606 class Current(Float
):
1609 def __new__(cls
, value
):
1610 value
= convert
.toCurrent(value
)
1611 return super(cls
, Current
).__new
__(cls
, value
)
1613 def __init__(self
, value
):
1614 value
= convert
.toCurrent(value
)
1615 super(Current
, self
).__init
__(value
)
1617 class Energy(Float
):
1620 def __new__(cls
, value
):
1621 value
= convert
.toEnergy(value
)
1622 return super(cls
, Energy
).__new
__(cls
, value
)
1624 def __init__(self
, value
):
1625 value
= convert
.toEnergy(value
)
1626 super(Energy
, self
).__init
__(value
)
1628 class NetworkBandwidth(float,ParamValue
):
1631 cmd_line_settable
= True
1633 def __new__(cls
, value
):
1634 # convert to bits per second
1635 val
= convert
.toNetworkBandwidth(value
)
1636 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1639 return str(self
.val
)
1641 def __call__(self
, value
):
1642 val
= convert
.toNetworkBandwidth(value
)
1647 # convert to seconds per byte
1648 value
= 8.0 / float(self
)
1649 # convert to ticks per byte
1650 value
= ticks
.fromSeconds(value
)
1654 return '%f' % self
.getValue()
1656 def config_value(self
):
1657 return '%f' % self
.getValue()
1660 def cxx_ini_predecls(cls
, code
):
1661 code('#include <sstream>')
1664 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1665 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1667 class MemoryBandwidth(float,ParamValue
):
1670 cmd_line_settable
= True
1672 def __new__(cls
, value
):
1673 # convert to bytes per second
1674 val
= convert
.toMemoryBandwidth(value
)
1675 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1677 def __call__(self
, value
):
1678 val
= convert
.toMemoryBandwidth(value
)
1683 # convert to seconds per byte
1686 value
= 1.0 / float(self
)
1687 # convert to ticks per byte
1688 value
= ticks
.fromSeconds(value
)
1692 return '%f' % self
.getValue()
1694 def config_value(self
):
1695 return '%f' % self
.getValue()
1698 def cxx_ini_predecls(cls
, code
):
1699 code('#include <sstream>')
1702 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1703 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1706 # "Constants"... handy aliases for various values.
1709 # Special class for NULL pointers. Note the special check in
1710 # make_param_value() above that lets these be assigned where a
1711 # SimObject is required.
1712 # only one copy of a particular node
1713 class NullSimObject(object):
1714 __metaclass__
= Singleton
1720 def _instantiate(self
, parent
= None, path
= ''):
1726 def unproxy(self
, base
):
1729 def set_path(self
, parent
, name
):
1732 def set_parent(self
, parent
, name
):
1735 def clear_parent(self
, old_parent
):
1738 def descendants(self
):
1742 def get_config_as_dict(self
):
1748 def config_value(self
):
1754 # The only instance you'll ever need...
1755 NULL
= NullSimObject()
1757 def isNullPointer(value
):
1758 return isinstance(value
, NullSimObject
)
1760 # Some memory range specifications use this as a default upper bound.
1763 AllMemory
= AddrRange(0, MaxAddr
)
1766 #####################################################################
1770 # Ports are used to interconnect objects in the memory system.
1772 #####################################################################
1774 # Port reference: encapsulates a reference to a particular port on a
1775 # particular SimObject.
1776 class PortRef(object):
1777 def __init__(self
, simobj
, name
, role
):
1778 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1779 self
.simobj
= simobj
1782 self
.peer
= None # not associated with another port yet
1783 self
.ccConnected
= False # C++ port connection done?
1784 self
.index
= -1 # always -1 for non-vector ports
1787 return '%s.%s' % (self
.simobj
, self
.name
)
1790 # Return the number of connected ports, i.e. 0 is we have no
1791 # peer and 1 if we do.
1792 return int(self
.peer
!= None)
1794 # for config.ini, print peer's name (not ours)
1796 return str(self
.peer
)
1799 def get_config_as_dict(self
):
1800 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1802 def __getattr__(self
, attr
):
1803 if attr
== 'peerObj':
1804 # shorthand for proxies
1805 return self
.peer
.simobj
1806 raise AttributeError("'%s' object has no attribute '%s'" % \
1807 (self
.__class
__.__name
__, attr
))
1809 # Full connection is symmetric (both ways). Called via
1810 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1811 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1812 # e.g., "obj1.portA[3] = obj2.portB".
1813 def connect(self
, other
):
1814 if isinstance(other
, VectorPortRef
):
1815 # reference to plain VectorPort is implicit append
1816 other
= other
._get
_next
()
1817 if self
.peer
and not proxy
.isproxy(self
.peer
):
1818 fatal("Port %s is already connected to %s, cannot connect %s\n",
1819 self
, self
.peer
, other
);
1821 if proxy
.isproxy(other
):
1822 other
.set_param_desc(PortParamDesc())
1823 elif isinstance(other
, PortRef
):
1824 if other
.peer
is not self
:
1827 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1830 # Allow a master/slave port pair to be spliced between
1831 # a port and its connected peer. Useful operation for connecting
1832 # instrumentation structures into a system when it is necessary
1833 # to connect the instrumentation after the full system has been
1835 def splice(self
, new_master_peer
, new_slave_peer
):
1836 if not self
.peer
or proxy
.isproxy(self
.peer
):
1837 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1839 if not isinstance(new_master_peer
, PortRef
) or \
1840 not isinstance(new_slave_peer
, PortRef
):
1842 "Splicing non-port references '%s','%s' to port '%s'" % \
1843 (new_master_peer
, new_slave_peer
, self
))
1845 old_peer
= self
.peer
1846 if self
.role
== 'SLAVE':
1847 self
.peer
= new_master_peer
1848 old_peer
.peer
= new_slave_peer
1849 new_master_peer
.connect(self
)
1850 new_slave_peer
.connect(old_peer
)
1851 elif self
.role
== 'MASTER':
1852 self
.peer
= new_slave_peer
1853 old_peer
.peer
= new_master_peer
1854 new_slave_peer
.connect(self
)
1855 new_master_peer
.connect(old_peer
)
1857 panic("Port %s has unknown role, "+\
1858 "cannot splice in new peers\n", self
)
1860 def clone(self
, simobj
, memo
):
1863 newRef
= copy
.copy(self
)
1865 newRef
.simobj
= simobj
1866 assert(isSimObject(newRef
.simobj
))
1867 if self
.peer
and not proxy
.isproxy(self
.peer
):
1868 peerObj
= self
.peer
.simobj(_memo
=memo
)
1869 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1870 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1873 def unproxy(self
, simobj
):
1874 assert(simobj
is self
.simobj
)
1875 if proxy
.isproxy(self
.peer
):
1877 realPeer
= self
.peer
.unproxy(self
.simobj
)
1879 print("Error in unproxying port '%s' of %s" %
1880 (self
.name
, self
.simobj
.path()))
1882 self
.connect(realPeer
)
1884 # Call C++ to create corresponding port connection between C++ objects
1885 def ccConnect(self
):
1886 from _m5
.pyobject
import connectPorts
1888 if self
.ccConnected
: # already done this
1892 if not self
.peer
: # nothing to connect to
1895 # check that we connect a master to a slave
1896 if self
.role
== peer
.role
:
1898 "cannot connect '%s' and '%s' due to identical role '%s'" % \
1899 (peer
, self
, self
.role
))
1901 if self
.role
== 'SLAVE':
1902 # do nothing and let the master take care of it
1906 # self is always the master and peer the slave
1907 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1908 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1910 print("Error connecting port %s.%s to %s.%s" %
1911 (self
.simobj
.path(), self
.name
,
1912 peer
.simobj
.path(), peer
.name
))
1914 self
.ccConnected
= True
1915 peer
.ccConnected
= True
1917 # A reference to an individual element of a VectorPort... much like a
1918 # PortRef, but has an index.
1919 class VectorPortElementRef(PortRef
):
1920 def __init__(self
, simobj
, name
, role
, index
):
1921 PortRef
.__init
__(self
, simobj
, name
, role
)
1925 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1927 # A reference to a complete vector-valued port (not just a single element).
1928 # Can be indexed to retrieve individual VectorPortElementRef instances.
1929 class VectorPortRef(object):
1930 def __init__(self
, simobj
, name
, role
):
1931 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1932 self
.simobj
= simobj
1938 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1941 # Return the number of connected peers, corresponding the the
1942 # length of the elements.
1943 return len(self
.elements
)
1945 # for config.ini, print peer's name (not ours)
1947 return ' '.join([el
.ini_str() for el
in self
.elements
])
1950 def get_config_as_dict(self
):
1951 return {'role' : self
.role
,
1952 'peer' : [el
.ini_str() for el
in self
.elements
]}
1954 def __getitem__(self
, key
):
1955 if not isinstance(key
, int):
1956 raise TypeError("VectorPort index must be integer")
1957 if key
>= len(self
.elements
):
1958 # need to extend list
1959 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1960 for i
in range(len(self
.elements
), key
+1)]
1961 self
.elements
.extend(ext
)
1962 return self
.elements
[key
]
1964 def _get_next(self
):
1965 return self
[len(self
.elements
)]
1967 def __setitem__(self
, key
, value
):
1968 if not isinstance(key
, int):
1969 raise TypeError("VectorPort index must be integer")
1970 self
[key
].connect(value
)
1972 def connect(self
, other
):
1973 if isinstance(other
, (list, tuple)):
1974 # Assign list of port refs to vector port.
1975 # For now, append them... not sure if that's the right semantics
1976 # or if it should replace the current vector.
1978 self
._get
_next
().connect(ref
)
1980 # scalar assignment to plain VectorPort is implicit append
1981 self
._get
_next
().connect(other
)
1983 def clone(self
, simobj
, memo
):
1986 newRef
= copy
.copy(self
)
1988 newRef
.simobj
= simobj
1989 assert(isSimObject(newRef
.simobj
))
1990 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1993 def unproxy(self
, simobj
):
1994 [el
.unproxy(simobj
) for el
in self
.elements
]
1996 def ccConnect(self
):
1997 [el
.ccConnect() for el
in self
.elements
]
1999 # Port description object. Like a ParamDesc object, this represents a
2000 # logical port in the SimObject class, not a particular port on a
2001 # SimObject instance. The latter are represented by PortRef objects.
2003 # Generate a PortRef for this port on the given SimObject with the
2005 def makeRef(self
, simobj
):
2006 return PortRef(simobj
, self
.name
, self
.role
)
2008 # Connect an instance of this port (on the given SimObject with
2009 # the given name) with the port described by the supplied PortRef
2010 def connect(self
, simobj
, ref
):
2011 self
.makeRef(simobj
).connect(ref
)
2013 # No need for any pre-declarations at the moment as we merely rely
2014 # on an unsigned int.
2015 def cxx_predecls(self
, code
):
2018 def pybind_predecls(self
, code
):
2019 cls
.cxx_predecls(self
, code
)
2021 # Declare an unsigned int with the same name as the port, that
2022 # will eventually hold the number of connected ports (and thus the
2023 # number of elements for a VectorPort).
2024 def cxx_decl(self
, code
):
2025 code('unsigned int port_${{self.name}}_connection_count;')
2027 class MasterPort(Port
):
2028 # MasterPort("description")
2029 def __init__(self
, *args
):
2032 self
.role
= 'MASTER'
2034 raise TypeError('wrong number of arguments')
2036 class SlavePort(Port
):
2037 # SlavePort("description")
2038 def __init__(self
, *args
):
2043 raise TypeError('wrong number of arguments')
2045 # VectorPort description object. Like Port, but represents a vector
2046 # of connections (e.g., as on a XBar).
2047 class VectorPort(Port
):
2048 def __init__(self
, *args
):
2051 def makeRef(self
, simobj
):
2052 return VectorPortRef(simobj
, self
.name
, self
.role
)
2054 class VectorMasterPort(VectorPort
):
2055 # VectorMasterPort("description")
2056 def __init__(self
, *args
):
2059 self
.role
= 'MASTER'
2060 VectorPort
.__init
__(self
, *args
)
2062 raise TypeError('wrong number of arguments')
2064 class VectorSlavePort(VectorPort
):
2065 # VectorSlavePort("description")
2066 def __init__(self
, *args
):
2070 VectorPort
.__init
__(self
, *args
)
2072 raise TypeError('wrong number of arguments')
2074 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2075 # proxy objects (via set_param_desc()) so that proxy error messages
2077 class PortParamDesc(object):
2078 __metaclass__
= Singleton
2083 baseEnums
= allEnums
.copy()
2084 baseParams
= allParams
.copy()
2087 global allEnums
, allParams
2089 allEnums
= baseEnums
.copy()
2090 allParams
= baseParams
.copy()
2092 __all__
= ['Param', 'VectorParam',
2093 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2094 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2095 'Int32', 'UInt32', 'Int64', 'UInt64',
2096 'Counter', 'Addr', 'Tick', 'Percent',
2097 'TcpPort', 'UdpPort', 'EthernetAddr',
2098 'IpAddress', 'IpNetmask', 'IpWithPort',
2099 'MemorySize', 'MemorySize32',
2100 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2101 'NetworkBandwidth', 'MemoryBandwidth',
2103 'MaxAddr', 'MaxTick', 'AllMemory',
2105 'NextEthernetAddr', 'NULL',
2106 'MasterPort', 'SlavePort',
2107 'VectorMasterPort', 'VectorSlavePort']