1 # Copyright (c) 2012-2014, 2017 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'
160 if kwargs
.has_key('desc'):
161 assert(not hasattr(self
, 'desc'))
162 self
.desc
= kwargs
['desc']
165 if kwargs
.has_key('default'):
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 not hasattr(self
, 'ptype') 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, \
238 "Not allowed to set %s on '%s'" % (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" % 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
832 def __nonzero__(self
):
833 return bool(self
.value
)
840 def config_value(self
):
844 def cxx_ini_predecls(cls
, code
):
845 # Assume that base/str.hh will be included anyway
846 # code('#include "base/str.hh"')
850 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
851 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
853 def IncEthernetAddr(addr
, val
= 1):
854 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
856 for i
in (5, 4, 3, 2, 1):
857 val
,rem
= divmod(bytes
[i
], 256)
862 assert(bytes
[0] <= 255)
863 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
865 _NextEthernetAddr
= "00:90:00:00:00:01"
866 def NextEthernetAddr():
867 global _NextEthernetAddr
869 value
= _NextEthernetAddr
870 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
873 class EthernetAddr(ParamValue
):
874 cxx_type
= 'Net::EthAddr'
875 ex_str
= "00:90:00:00:00:01"
876 cmd_line_settable
= True
879 def cxx_predecls(cls
, code
):
880 code('#include "base/inet.hh"')
882 def __init__(self
, value
):
883 if value
== NextEthernetAddr
:
887 if not isinstance(value
, str):
888 raise TypeError, "expected an ethernet address and didn't get one"
890 bytes
= value
.split(':')
892 raise TypeError, 'invalid ethernet address %s' % value
895 if not 0 <= int(byte
, base
=16) <= 0xff:
896 raise TypeError, 'invalid ethernet address %s' % value
900 def __call__(self
, value
):
904 def unproxy(self
, base
):
905 if self
.value
== NextEthernetAddr
:
906 return EthernetAddr(self
.value())
910 from _m5
.net
import EthAddr
911 return EthAddr(self
.value
)
920 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
921 code('%s = Net::EthAddr(%s);' % (dest
, src
))
922 code('%s true;' % ret
)
924 # When initializing an IpAddress, pass in an existing IpAddress, a string of
925 # the form "a.b.c.d", or an integer representing an IP.
926 class IpAddress(ParamValue
):
927 cxx_type
= 'Net::IpAddress'
929 cmd_line_settable
= True
932 def cxx_predecls(cls
, code
):
933 code('#include "base/inet.hh"')
935 def __init__(self
, value
):
936 if isinstance(value
, IpAddress
):
940 self
.ip
= convert
.toIpAddress(value
)
942 self
.ip
= long(value
)
945 def __call__(self
, value
):
950 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
951 return '%d.%d.%d.%d' % tuple(tup
)
953 def __eq__(self
, other
):
954 if isinstance(other
, IpAddress
):
955 return self
.ip
== other
.ip
956 elif isinstance(other
, str):
958 return self
.ip
== convert
.toIpAddress(other
)
962 return self
.ip
== other
964 def __ne__(self
, other
):
965 return not (self
== other
)
968 if self
.ip
< 0 or self
.ip
>= (1 << 32):
969 raise TypeError, "invalid ip address %#08x" % self
.ip
972 from _m5
.net
import IpAddress
973 return IpAddress(self
.ip
)
975 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
976 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
977 # positional or keyword arguments.
978 class IpNetmask(IpAddress
):
979 cxx_type
= 'Net::IpNetmask'
980 ex_str
= "127.0.0.0/24"
981 cmd_line_settable
= True
984 def cxx_predecls(cls
, code
):
985 code('#include "base/inet.hh"')
987 def __init__(self
, *args
, **kwargs
):
988 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
990 setattr(self
, key
, kwargs
.pop(key
))
992 setattr(self
, key
, elseVal
)
994 raise TypeError, "No value set for %s" % key
997 handle_kwarg(self
, kwargs
, 'ip')
998 handle_kwarg(self
, kwargs
, 'netmask')
1000 elif len(args
) == 1:
1002 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1003 raise TypeError, "Invalid arguments"
1004 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1005 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1006 elif isinstance(args
[0], IpNetmask
):
1007 self
.ip
= args
[0].ip
1008 self
.netmask
= args
[0].netmask
1010 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1012 elif len(args
) == 2:
1014 self
.netmask
= args
[1]
1016 raise TypeError, "Too many arguments specified"
1019 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1023 def __call__(self
, value
):
1024 self
.__init
__(value
)
1028 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1030 def __eq__(self
, other
):
1031 if isinstance(other
, IpNetmask
):
1032 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1033 elif isinstance(other
, str):
1035 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1043 if self
.netmask
< 0 or self
.netmask
> 32:
1044 raise TypeError, "invalid netmask %d" % netmask
1047 from _m5
.net
import IpNetmask
1048 return IpNetmask(self
.ip
, self
.netmask
)
1050 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1051 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1052 class IpWithPort(IpAddress
):
1053 cxx_type
= 'Net::IpWithPort'
1054 ex_str
= "127.0.0.1:80"
1055 cmd_line_settable
= True
1058 def cxx_predecls(cls
, code
):
1059 code('#include "base/inet.hh"')
1061 def __init__(self
, *args
, **kwargs
):
1062 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1064 setattr(self
, key
, kwargs
.pop(key
))
1066 setattr(self
, key
, elseVal
)
1068 raise TypeError, "No value set for %s" % key
1071 handle_kwarg(self
, kwargs
, 'ip')
1072 handle_kwarg(self
, kwargs
, 'port')
1074 elif len(args
) == 1:
1076 if not 'ip' in kwargs
and not 'port' in kwargs
:
1077 raise TypeError, "Invalid arguments"
1078 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1079 handle_kwarg(self
, kwargs
, 'port', args
[0])
1080 elif isinstance(args
[0], IpWithPort
):
1081 self
.ip
= args
[0].ip
1082 self
.port
= args
[0].port
1084 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1086 elif len(args
) == 2:
1090 raise TypeError, "Too many arguments specified"
1093 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1097 def __call__(self
, value
):
1098 self
.__init
__(value
)
1102 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1104 def __eq__(self
, other
):
1105 if isinstance(other
, IpWithPort
):
1106 return self
.ip
== other
.ip
and self
.port
== other
.port
1107 elif isinstance(other
, str):
1109 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1117 if self
.port
< 0 or self
.port
> 0xffff:
1118 raise TypeError, "invalid port %d" % self
.port
1121 from _m5
.net
import IpWithPort
1122 return IpWithPort(self
.ip
, self
.port
)
1124 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1125 "%a %b %d %H:%M:%S %Y",
1126 "%Y/%m/%d %H:%M:%S",
1129 "%m/%d/%Y %H:%M:%S",
1132 "%m/%d/%y %H:%M:%S",
1137 def parse_time(value
):
1138 from time
import gmtime
, strptime
, struct_time
, time
1139 from datetime
import datetime
, date
1141 if isinstance(value
, struct_time
):
1144 if isinstance(value
, (int, long)):
1145 return gmtime(value
)
1147 if isinstance(value
, (datetime
, date
)):
1148 return value
.timetuple()
1150 if isinstance(value
, str):
1151 if value
in ('Now', 'Today'):
1152 return time
.gmtime(time
.time())
1154 for format
in time_formats
:
1156 return strptime(value
, format
)
1160 raise ValueError, "Could not parse '%s' as a time" % value
1162 class Time(ParamValue
):
1166 def cxx_predecls(cls
, code
):
1167 code('#include <time.h>')
1169 def __init__(self
, value
):
1170 self
.value
= parse_time(value
)
1172 def __call__(self
, value
):
1173 self
.__init
__(value
)
1177 from _m5
.core
import tm
1180 return tm
.gmtime(calendar
.timegm(self
.value
))
1183 return time
.asctime(self
.value
)
1188 def get_config_as_dict(self
):
1193 def cxx_ini_predecls(cls
, code
):
1194 code('#include <time.h>')
1197 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1198 code('char *_parse_ret = strptime((${src}).c_str(),')
1199 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1200 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1202 # Enumerated types are a little more complex. The user specifies the
1203 # type as Enum(foo) where foo is either a list or dictionary of
1204 # alternatives (typically strings, but not necessarily so). (In the
1205 # long run, the integer value of the parameter will be the list index
1206 # or the corresponding dictionary value. For now, since we only check
1207 # that the alternative is valid and then spit it into a .ini file,
1208 # there's not much point in using the dictionary.)
1210 # What Enum() must do is generate a new type encapsulating the
1211 # provided list/dictionary so that specific values of the parameter
1212 # can be instances of that type. We define two hidden internal
1213 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1214 # derive the new type from the appropriate base class on the fly.
1217 # Metaclass for Enum types
1218 class MetaEnum(MetaParamValue
):
1219 def __new__(mcls
, name
, bases
, dict):
1220 assert name
not in allEnums
1222 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1223 allEnums
[name
] = cls
1226 def __init__(cls
, name
, bases
, init_dict
):
1227 if init_dict
.has_key('map'):
1228 if not isinstance(cls
.map, dict):
1229 raise TypeError, "Enum-derived class attribute 'map' " \
1230 "must be of type dict"
1231 # build list of value strings from map
1232 cls
.vals
= cls
.map.keys()
1234 elif init_dict
.has_key('vals'):
1235 if not isinstance(cls
.vals
, list):
1236 raise TypeError, "Enum-derived class attribute 'vals' " \
1237 "must be of type list"
1238 # build string->value map from vals sequence
1240 for idx
,val
in enumerate(cls
.vals
):
1243 raise TypeError, "Enum-derived class must define "\
1244 "attribute 'map' or 'vals'"
1246 cls
.cxx_type
= 'Enums::%s' % name
1248 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1250 # Generate C++ class declaration for this enum type.
1251 # Note that we wrap the enum in a class/struct to act as a namespace,
1252 # so that the enum strings can be brief w/o worrying about collisions.
1253 def cxx_decl(cls
, code
):
1254 wrapper_name
= cls
.wrapper_name
1255 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1256 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1257 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1263 $wrapper $wrapper_name {
1267 for val
in cls
.vals
:
1268 code('$val = ${{cls.map[val]}},')
1269 code('Num_$name = ${{len(cls.vals)}}')
1273 if cls
.wrapper_is_struct
:
1274 code(' static const char *${name}Strings[Num_${name}];')
1277 code('extern const char *${name}Strings[Num_${name}];')
1281 code('#endif // $idem_macro')
1283 def cxx_def(cls
, code
):
1284 wrapper_name
= cls
.wrapper_name
1285 file_name
= cls
.__name
__
1286 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1288 code('#include "enums/$file_name.hh"')
1289 if cls
.wrapper_is_struct
:
1290 code('const char *${wrapper_name}::${name}Strings'
1293 code('namespace Enums {')
1295 code(' const char *${name}Strings[Num_${name}] =')
1299 for val
in cls
.vals
:
1304 if not cls
.wrapper_is_struct
:
1305 code('} // namespace $wrapper_name')
1308 def pybind_def(cls
, code
):
1310 wrapper_name
= cls
.wrapper_name
1311 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1313 code('''#include "pybind11/pybind11.h"
1314 #include "pybind11/stl.h"
1316 #include <sim/init.hh>
1318 namespace py = pybind11;
1321 module_init(py::module &m_internal)
1323 py::module m = m_internal.def_submodule("enum_${name}");
1325 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
1330 for val
in cls
.vals
:
1331 code('.value("${val}", ${wrapper_name}::${val})')
1332 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1333 code('.export_values()')
1340 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1343 # Base class for enum types.
1344 class Enum(ParamValue
):
1345 __metaclass__
= MetaEnum
1347 cmd_line_settable
= True
1349 # The name of the wrapping namespace or struct
1350 wrapper_name
= 'Enums'
1352 # If true, the enum is wrapped in a struct rather than a namespace
1353 wrapper_is_struct
= False
1355 # If not None, use this as the enum name rather than this class name
1358 def __init__(self
, value
):
1359 if value
not in self
.map:
1360 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1361 % (value
, self
.vals
)
1364 def __call__(self
, value
):
1365 self
.__init
__(value
)
1369 def cxx_predecls(cls
, code
):
1370 code('#include "enums/$0.hh"', cls
.__name
__)
1373 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1374 code('if (false) {')
1375 for elem_name
in cls
.map.iterkeys():
1376 code('} else if (%s == "%s") {' % (src
, elem_name
))
1378 code('%s = Enums::%s;' % (dest
, elem_name
))
1379 code('%s true;' % ret
)
1382 code(' %s false;' % ret
)
1386 import m5
.internal
.params
1387 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1388 return e(self
.map[self
.value
])
1393 # how big does a rounding error need to be before we warn about it?
1394 frequency_tolerance
= 0.001 # 0.1%
1396 class TickParamValue(NumericParamValue
):
1399 cmd_line_settable
= True
1402 def cxx_predecls(cls
, code
):
1403 code('#include "base/types.hh"')
1405 def __call__(self
, value
):
1406 self
.__init
__(value
)
1410 return long(self
.value
)
1413 def cxx_ini_predecls(cls
, code
):
1414 code('#include <sstream>')
1416 # Ticks are expressed in seconds in JSON files and in plain
1417 # Ticks in .ini files. Switch based on a config flag
1419 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1420 code('${ret} to_number(${src}, ${dest});')
1422 class Latency(TickParamValue
):
1425 def __init__(self
, value
):
1426 if isinstance(value
, (Latency
, Clock
)):
1427 self
.ticks
= value
.ticks
1428 self
.value
= value
.value
1429 elif isinstance(value
, Frequency
):
1430 self
.ticks
= value
.ticks
1431 self
.value
= 1.0 / value
.value
1432 elif value
.endswith('t'):
1434 self
.value
= int(value
[:-1])
1437 self
.value
= convert
.toLatency(value
)
1439 def __call__(self
, value
):
1440 self
.__init
__(value
)
1443 def __getattr__(self
, attr
):
1444 if attr
in ('latency', 'period'):
1446 if attr
== 'frequency':
1447 return Frequency(self
)
1448 raise AttributeError, "Latency object has no attribute '%s'" % attr
1451 if self
.ticks
or self
.value
== 0:
1454 value
= ticks
.fromSeconds(self
.value
)
1457 def config_value(self
):
1458 return self
.getValue()
1460 # convert latency to ticks
1462 return '%d' % self
.getValue()
1464 class Frequency(TickParamValue
):
1467 def __init__(self
, value
):
1468 if isinstance(value
, (Latency
, Clock
)):
1469 if value
.value
== 0:
1472 self
.value
= 1.0 / value
.value
1473 self
.ticks
= value
.ticks
1474 elif isinstance(value
, Frequency
):
1475 self
.value
= value
.value
1476 self
.ticks
= value
.ticks
1479 self
.value
= convert
.toFrequency(value
)
1481 def __call__(self
, value
):
1482 self
.__init
__(value
)
1485 def __getattr__(self
, attr
):
1486 if attr
== 'frequency':
1488 if attr
in ('latency', 'period'):
1489 return Latency(self
)
1490 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1492 # convert latency to ticks
1494 if self
.ticks
or self
.value
== 0:
1497 value
= ticks
.fromSeconds(1.0 / self
.value
)
1500 def config_value(self
):
1501 return self
.getValue()
1504 return '%d' % self
.getValue()
1506 # A generic Frequency and/or Latency value. Value is stored as a
1507 # latency, just like Latency and Frequency.
1508 class Clock(TickParamValue
):
1509 def __init__(self
, value
):
1510 if isinstance(value
, (Latency
, Clock
)):
1511 self
.ticks
= value
.ticks
1512 self
.value
= value
.value
1513 elif isinstance(value
, Frequency
):
1514 self
.ticks
= value
.ticks
1515 self
.value
= 1.0 / value
.value
1516 elif value
.endswith('t'):
1518 self
.value
= int(value
[:-1])
1521 self
.value
= convert
.anyToLatency(value
)
1523 def __call__(self
, value
):
1524 self
.__init
__(value
)
1528 return "%s" % Latency(self
)
1530 def __getattr__(self
, attr
):
1531 if attr
== 'frequency':
1532 return Frequency(self
)
1533 if attr
in ('latency', 'period'):
1534 return Latency(self
)
1535 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1538 return self
.period
.getValue()
1540 def config_value(self
):
1541 return self
.period
.config_value()
1544 return self
.period
.ini_str()
1546 class Voltage(Float
):
1549 def __new__(cls
, value
):
1550 value
= convert
.toVoltage(value
)
1551 return super(cls
, Voltage
).__new
__(cls
, value
)
1553 def __init__(self
, value
):
1554 value
= convert
.toVoltage(value
)
1555 super(Voltage
, self
).__init
__(value
)
1557 class Current(Float
):
1560 def __new__(cls
, value
):
1561 value
= convert
.toCurrent(value
)
1562 return super(cls
, Current
).__new
__(cls
, value
)
1564 def __init__(self
, value
):
1565 value
= convert
.toCurrent(value
)
1566 super(Current
, self
).__init
__(value
)
1568 class Energy(Float
):
1571 def __new__(cls
, value
):
1572 value
= convert
.toEnergy(value
)
1573 return super(cls
, Energy
).__new
__(cls
, value
)
1575 def __init__(self
, value
):
1576 value
= convert
.toEnergy(value
)
1577 super(Energy
, self
).__init
__(value
)
1579 class NetworkBandwidth(float,ParamValue
):
1582 cmd_line_settable
= True
1584 def __new__(cls
, value
):
1585 # convert to bits per second
1586 val
= convert
.toNetworkBandwidth(value
)
1587 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1590 return str(self
.val
)
1592 def __call__(self
, value
):
1593 val
= convert
.toNetworkBandwidth(value
)
1598 # convert to seconds per byte
1599 value
= 8.0 / float(self
)
1600 # convert to ticks per byte
1601 value
= ticks
.fromSeconds(value
)
1605 return '%f' % self
.getValue()
1607 def config_value(self
):
1608 return '%f' % self
.getValue()
1611 def cxx_ini_predecls(cls
, code
):
1612 code('#include <sstream>')
1615 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1616 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1618 class MemoryBandwidth(float,ParamValue
):
1621 cmd_line_settable
= True
1623 def __new__(cls
, value
):
1624 # convert to bytes per second
1625 val
= convert
.toMemoryBandwidth(value
)
1626 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1628 def __call__(self
, value
):
1629 val
= convert
.toMemoryBandwidth(value
)
1634 # convert to seconds per byte
1637 value
= 1.0 / float(self
)
1638 # convert to ticks per byte
1639 value
= ticks
.fromSeconds(value
)
1643 return '%f' % self
.getValue()
1645 def config_value(self
):
1646 return '%f' % self
.getValue()
1649 def cxx_ini_predecls(cls
, code
):
1650 code('#include <sstream>')
1653 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1654 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1657 # "Constants"... handy aliases for various values.
1660 # Special class for NULL pointers. Note the special check in
1661 # make_param_value() above that lets these be assigned where a
1662 # SimObject is required.
1663 # only one copy of a particular node
1664 class NullSimObject(object):
1665 __metaclass__
= Singleton
1671 def _instantiate(self
, parent
= None, path
= ''):
1677 def unproxy(self
, base
):
1680 def set_path(self
, parent
, name
):
1683 def set_parent(self
, parent
, name
):
1686 def clear_parent(self
, old_parent
):
1689 def descendants(self
):
1693 def get_config_as_dict(self
):
1699 def config_value(self
):
1705 # The only instance you'll ever need...
1706 NULL
= NullSimObject()
1708 def isNullPointer(value
):
1709 return isinstance(value
, NullSimObject
)
1711 # Some memory range specifications use this as a default upper bound.
1714 AllMemory
= AddrRange(0, MaxAddr
)
1717 #####################################################################
1721 # Ports are used to interconnect objects in the memory system.
1723 #####################################################################
1725 # Port reference: encapsulates a reference to a particular port on a
1726 # particular SimObject.
1727 class PortRef(object):
1728 def __init__(self
, simobj
, name
, role
):
1729 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1730 self
.simobj
= simobj
1733 self
.peer
= None # not associated with another port yet
1734 self
.ccConnected
= False # C++ port connection done?
1735 self
.index
= -1 # always -1 for non-vector ports
1738 return '%s.%s' % (self
.simobj
, self
.name
)
1741 # Return the number of connected ports, i.e. 0 is we have no
1742 # peer and 1 if we do.
1743 return int(self
.peer
!= None)
1745 # for config.ini, print peer's name (not ours)
1747 return str(self
.peer
)
1750 def get_config_as_dict(self
):
1751 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1753 def __getattr__(self
, attr
):
1754 if attr
== 'peerObj':
1755 # shorthand for proxies
1756 return self
.peer
.simobj
1757 raise AttributeError, "'%s' object has no attribute '%s'" % \
1758 (self
.__class
__.__name
__, attr
)
1760 # Full connection is symmetric (both ways). Called via
1761 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1762 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1763 # e.g., "obj1.portA[3] = obj2.portB".
1764 def connect(self
, other
):
1765 if isinstance(other
, VectorPortRef
):
1766 # reference to plain VectorPort is implicit append
1767 other
= other
._get
_next
()
1768 if self
.peer
and not proxy
.isproxy(self
.peer
):
1769 fatal("Port %s is already connected to %s, cannot connect %s\n",
1770 self
, self
.peer
, other
);
1772 if proxy
.isproxy(other
):
1773 other
.set_param_desc(PortParamDesc())
1774 elif isinstance(other
, PortRef
):
1775 if other
.peer
is not self
:
1779 "assigning non-port reference '%s' to port '%s'" \
1782 # Allow a master/slave port pair to be spliced between
1783 # a port and its connected peer. Useful operation for connecting
1784 # instrumentation structures into a system when it is necessary
1785 # to connect the instrumentation after the full system has been
1787 def splice(self
, new_master_peer
, new_slave_peer
):
1788 if self
.peer
and not proxy
.isproxy(self
.peer
):
1789 if isinstance(new_master_peer
, PortRef
) and \
1790 isinstance(new_slave_peer
, PortRef
):
1791 old_peer
= self
.peer
1792 if self
.role
== 'SLAVE':
1793 self
.peer
= new_master_peer
1794 old_peer
.peer
= new_slave_peer
1795 new_master_peer
.connect(self
)
1796 new_slave_peer
.connect(old_peer
)
1797 elif self
.role
== 'MASTER':
1798 self
.peer
= new_slave_peer
1799 old_peer
.peer
= new_master_peer
1800 new_slave_peer
.connect(self
)
1801 new_master_peer
.connect(old_peer
)
1803 panic("Port %s has unknown role, "+\
1804 "cannot splice in new peers\n", self
)
1807 "Splicing non-port references '%s','%s' to port '%s'"\
1808 % (new_master_peer
, new_slave_peer
, self
)
1810 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1812 def clone(self
, simobj
, memo
):
1813 if memo
.has_key(self
):
1815 newRef
= copy
.copy(self
)
1817 newRef
.simobj
= simobj
1818 assert(isSimObject(newRef
.simobj
))
1819 if self
.peer
and not proxy
.isproxy(self
.peer
):
1820 peerObj
= self
.peer
.simobj(_memo
=memo
)
1821 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1822 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1825 def unproxy(self
, simobj
):
1826 assert(simobj
is self
.simobj
)
1827 if proxy
.isproxy(self
.peer
):
1829 realPeer
= self
.peer
.unproxy(self
.simobj
)
1831 print("Error in unproxying port '%s' of %s" %
1832 (self
.name
, self
.simobj
.path()))
1834 self
.connect(realPeer
)
1836 # Call C++ to create corresponding port connection between C++ objects
1837 def ccConnect(self
):
1838 from _m5
.pyobject
import connectPorts
1840 if self
.role
== 'SLAVE':
1841 # do nothing and let the master take care of it
1844 if self
.ccConnected
: # already done this
1847 if not self
.peer
: # nothing to connect to
1850 # check that we connect a master to a slave
1851 if self
.role
== peer
.role
:
1853 "cannot connect '%s' and '%s' due to identical role '%s'" \
1854 % (peer
, self
, self
.role
)
1857 # self is always the master and peer the slave
1858 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1859 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1861 print("Error connecting port %s.%s to %s.%s" %
1862 (self
.simobj
.path(), self
.name
,
1863 peer
.simobj
.path(), peer
.name
))
1865 self
.ccConnected
= True
1866 peer
.ccConnected
= True
1868 # A reference to an individual element of a VectorPort... much like a
1869 # PortRef, but has an index.
1870 class VectorPortElementRef(PortRef
):
1871 def __init__(self
, simobj
, name
, role
, index
):
1872 PortRef
.__init
__(self
, simobj
, name
, role
)
1876 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1878 # A reference to a complete vector-valued port (not just a single element).
1879 # Can be indexed to retrieve individual VectorPortElementRef instances.
1880 class VectorPortRef(object):
1881 def __init__(self
, simobj
, name
, role
):
1882 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1883 self
.simobj
= simobj
1889 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1892 # Return the number of connected peers, corresponding the the
1893 # length of the elements.
1894 return len(self
.elements
)
1896 # for config.ini, print peer's name (not ours)
1898 return ' '.join([el
.ini_str() for el
in self
.elements
])
1901 def get_config_as_dict(self
):
1902 return {'role' : self
.role
,
1903 'peer' : [el
.ini_str() for el
in self
.elements
]}
1905 def __getitem__(self
, key
):
1906 if not isinstance(key
, int):
1907 raise TypeError, "VectorPort index must be integer"
1908 if key
>= len(self
.elements
):
1909 # need to extend list
1910 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1911 for i
in range(len(self
.elements
), key
+1)]
1912 self
.elements
.extend(ext
)
1913 return self
.elements
[key
]
1915 def _get_next(self
):
1916 return self
[len(self
.elements
)]
1918 def __setitem__(self
, key
, value
):
1919 if not isinstance(key
, int):
1920 raise TypeError, "VectorPort index must be integer"
1921 self
[key
].connect(value
)
1923 def connect(self
, other
):
1924 if isinstance(other
, (list, tuple)):
1925 # Assign list of port refs to vector port.
1926 # For now, append them... not sure if that's the right semantics
1927 # or if it should replace the current vector.
1929 self
._get
_next
().connect(ref
)
1931 # scalar assignment to plain VectorPort is implicit append
1932 self
._get
_next
().connect(other
)
1934 def clone(self
, simobj
, memo
):
1935 if memo
.has_key(self
):
1937 newRef
= copy
.copy(self
)
1939 newRef
.simobj
= simobj
1940 assert(isSimObject(newRef
.simobj
))
1941 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1944 def unproxy(self
, simobj
):
1945 [el
.unproxy(simobj
) for el
in self
.elements
]
1947 def ccConnect(self
):
1948 [el
.ccConnect() for el
in self
.elements
]
1950 # Port description object. Like a ParamDesc object, this represents a
1951 # logical port in the SimObject class, not a particular port on a
1952 # SimObject instance. The latter are represented by PortRef objects.
1954 # Generate a PortRef for this port on the given SimObject with the
1956 def makeRef(self
, simobj
):
1957 return PortRef(simobj
, self
.name
, self
.role
)
1959 # Connect an instance of this port (on the given SimObject with
1960 # the given name) with the port described by the supplied PortRef
1961 def connect(self
, simobj
, ref
):
1962 self
.makeRef(simobj
).connect(ref
)
1964 # No need for any pre-declarations at the moment as we merely rely
1965 # on an unsigned int.
1966 def cxx_predecls(self
, code
):
1969 def pybind_predecls(self
, code
):
1970 cls
.cxx_predecls(self
, code
)
1972 # Declare an unsigned int with the same name as the port, that
1973 # will eventually hold the number of connected ports (and thus the
1974 # number of elements for a VectorPort).
1975 def cxx_decl(self
, code
):
1976 code('unsigned int port_${{self.name}}_connection_count;')
1978 class MasterPort(Port
):
1979 # MasterPort("description")
1980 def __init__(self
, *args
):
1983 self
.role
= 'MASTER'
1985 raise TypeError, 'wrong number of arguments'
1987 class SlavePort(Port
):
1988 # SlavePort("description")
1989 def __init__(self
, *args
):
1994 raise TypeError, 'wrong number of arguments'
1996 # VectorPort description object. Like Port, but represents a vector
1997 # of connections (e.g., as on a XBar).
1998 class VectorPort(Port
):
1999 def __init__(self
, *args
):
2002 def makeRef(self
, simobj
):
2003 return VectorPortRef(simobj
, self
.name
, self
.role
)
2005 class VectorMasterPort(VectorPort
):
2006 # VectorMasterPort("description")
2007 def __init__(self
, *args
):
2010 self
.role
= 'MASTER'
2011 VectorPort
.__init
__(self
, *args
)
2013 raise TypeError, 'wrong number of arguments'
2015 class VectorSlavePort(VectorPort
):
2016 # VectorSlavePort("description")
2017 def __init__(self
, *args
):
2021 VectorPort
.__init
__(self
, *args
)
2023 raise TypeError, 'wrong number of arguments'
2025 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2026 # proxy objects (via set_param_desc()) so that proxy error messages
2028 class PortParamDesc(object):
2029 __metaclass__
= Singleton
2034 baseEnums
= allEnums
.copy()
2035 baseParams
= allParams
.copy()
2038 global allEnums
, allParams
2040 allEnums
= baseEnums
.copy()
2041 allParams
= baseParams
.copy()
2043 __all__
= ['Param', 'VectorParam',
2044 'Enum', 'Bool', 'String', 'Float',
2045 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2046 'Int32', 'UInt32', 'Int64', 'UInt64',
2047 'Counter', 'Addr', 'Tick', 'Percent',
2048 'TcpPort', 'UdpPort', 'EthernetAddr',
2049 'IpAddress', 'IpNetmask', 'IpWithPort',
2050 'MemorySize', 'MemorySize32',
2051 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2052 'NetworkBandwidth', 'MemoryBandwidth',
2054 'MaxAddr', 'MaxTick', 'AllMemory',
2056 'NextEthernetAddr', 'NULL',
2057 'MasterPort', 'SlavePort',
2058 'VectorMasterPort', 'VectorSlavePort']