misc: Merged m5ops_base hotfix into develop
[gem5.git] / src / python / m5 / params.py
1 # Copyright (c) 2012-2014, 2017-2019 ARM Limited
2 # All rights reserved.
3 #
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.
12 #
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.
16 #
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.
27 #
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.
39
40 #####################################################################
41 #
42 # Parameter description classes
43 #
44 # The _params dictionary in each class maps parameter names to either
45 # a Param or a VectorParam object. These objects contain the
46 # parameter description string, the parameter type, and the default
47 # value (if any). The convert() method on these objects is used to
48 # force whatever value is assigned to the parameter to the appropriate
49 # type.
50 #
51 # Note that the default values are loaded into the class's attribute
52 # space when the parameter dictionary is initialized (in
53 # MetaSimObject._new_param()); after that point they aren't used.
54 #
55 #####################################################################
56
57 from __future__ import print_function
58 from six import add_metaclass
59 import six
60 if six.PY3:
61 long = int
62
63 import copy
64 import datetime
65 import re
66 import sys
67 import time
68 import math
69
70 from . import proxy
71 from . import ticks
72 from .util import *
73
74 def isSimObject(*args, **kwargs):
75 from . import SimObject
76 return SimObject.isSimObject(*args, **kwargs)
77
78 def isSimObjectSequence(*args, **kwargs):
79 from . import SimObject
80 return SimObject.isSimObjectSequence(*args, **kwargs)
81
82 def isSimObjectClass(*args, **kwargs):
83 from . import SimObject
84 return SimObject.isSimObjectClass(*args, **kwargs)
85
86 allParams = {}
87
88 class MetaParamValue(type):
89 def __new__(mcls, name, bases, dct):
90 cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
91 if name in allParams:
92 warn("%s already exists in allParams. This may be caused by the " \
93 "Python 2.7 compatibility layer." % (name, ))
94 allParams[name] = cls
95 return cls
96
97
98 # Dummy base class to identify types that are legitimate for SimObject
99 # parameters.
100 @add_metaclass(MetaParamValue)
101 class ParamValue(object):
102 cmd_line_settable = False
103
104 # Generate the code needed as a prerequisite for declaring a C++
105 # object of this type. Typically generates one or more #include
106 # statements. Used when declaring parameters of this type.
107 @classmethod
108 def cxx_predecls(cls, code):
109 pass
110
111 @classmethod
112 def pybind_predecls(cls, code):
113 cls.cxx_predecls(code)
114
115 # default for printing to .ini file is regular string conversion.
116 # will be overridden in some cases
117 def ini_str(self):
118 return str(self)
119
120 # default for printing to .json file is regular string conversion.
121 # will be overridden in some cases, mostly to use native Python
122 # types where there are similar JSON types
123 def config_value(self):
124 return str(self)
125
126 # Prerequisites for .ini parsing with cxx_ini_parse
127 @classmethod
128 def cxx_ini_predecls(cls, code):
129 pass
130
131 # parse a .ini file entry for this param from string expression
132 # src into lvalue dest (of the param's C++ type)
133 @classmethod
134 def cxx_ini_parse(cls, code, src, dest, ret):
135 code('// Unhandled param type: %s' % cls.__name__)
136 code('%s false;' % ret)
137
138 # allows us to blithely call unproxy() on things without checking
139 # if they're really proxies or not
140 def unproxy(self, base):
141 return self
142
143 # Produce a human readable version of the stored value
144 def pretty_print(self, value):
145 return str(value)
146
147 # Regular parameter description.
148 class ParamDesc(object):
149 def __init__(self, ptype_str, ptype, *args, **kwargs):
150 self.ptype_str = ptype_str
151 # remember ptype only if it is provided
152 if ptype != None:
153 self.ptype = ptype
154
155 if args:
156 if len(args) == 1:
157 self.desc = args[0]
158 elif len(args) == 2:
159 self.default = args[0]
160 self.desc = args[1]
161 else:
162 raise TypeError('too many arguments')
163
164 if 'desc' in kwargs:
165 assert(not hasattr(self, 'desc'))
166 self.desc = kwargs['desc']
167 del kwargs['desc']
168
169 if 'default' in kwargs:
170 assert(not hasattr(self, 'default'))
171 self.default = kwargs['default']
172 del kwargs['default']
173
174 if kwargs:
175 raise TypeError('extra unknown kwargs %s' % kwargs)
176
177 if not hasattr(self, 'desc'):
178 raise TypeError('desc attribute missing')
179
180 def __getattr__(self, attr):
181 if attr == 'ptype':
182 from . import SimObject
183 ptype = SimObject.allClasses[self.ptype_str]
184 assert isSimObjectClass(ptype)
185 self.ptype = ptype
186 return ptype
187
188 raise AttributeError("'%s' object has no attribute '%s'" % \
189 (type(self).__name__, attr))
190
191 def example_str(self):
192 if hasattr(self.ptype, "ex_str"):
193 return self.ptype.ex_str
194 else:
195 return self.ptype_str
196
197 # Is the param available to be exposed on the command line
198 def isCmdLineSettable(self):
199 if hasattr(self.ptype, "cmd_line_settable"):
200 return self.ptype.cmd_line_settable
201 else:
202 return False
203
204 def convert(self, value):
205 if isinstance(value, proxy.BaseProxy):
206 value.set_param_desc(self)
207 return value
208 if 'ptype' not in self.__dict__ and isNullPointer(value):
209 # deferred evaluation of SimObject; continue to defer if
210 # we're just assigning a null pointer
211 return value
212 if isinstance(value, self.ptype):
213 return value
214 if isNullPointer(value) and isSimObjectClass(self.ptype):
215 return value
216 return self.ptype(value)
217
218 def pretty_print(self, value):
219 if isinstance(value, proxy.BaseProxy):
220 return str(value)
221 if isNullPointer(value):
222 return NULL
223 return self.ptype(value).pretty_print(value)
224
225 def cxx_predecls(self, code):
226 code('#include <cstddef>')
227 self.ptype.cxx_predecls(code)
228
229 def pybind_predecls(self, code):
230 self.ptype.pybind_predecls(code)
231
232 def cxx_decl(self, code):
233 code('${{self.ptype.cxx_type}} ${{self.name}};')
234
235 # Vector-valued parameter description. Just like ParamDesc, except
236 # that the value is a vector (list) of the specified type instead of a
237 # single value.
238
239 @add_metaclass(MetaParamValue)
240 class VectorParamValue(list):
241 def __setattr__(self, attr, value):
242 raise AttributeError("Not allowed to set %s on '%s'" % \
243 (attr, type(self).__name__))
244
245 def config_value(self):
246 return [v.config_value() for v in self]
247
248 def ini_str(self):
249 return ' '.join([v.ini_str() for v in self])
250
251 def getValue(self):
252 return [ v.getValue() for v in self ]
253
254 def unproxy(self, base):
255 if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
256 # The value is a proxy (e.g. Parent.any, Parent.all or
257 # Parent.x) therefore try resolve it
258 return self[0].unproxy(base)
259 else:
260 return [v.unproxy(base) for v in self]
261
262 class SimObjectVector(VectorParamValue):
263 # support clone operation
264 def __call__(self, **kwargs):
265 return SimObjectVector([v(**kwargs) for v in self])
266
267 def clear_parent(self, old_parent):
268 for v in self:
269 v.clear_parent(old_parent)
270
271 def set_parent(self, parent, name):
272 if len(self) == 1:
273 self[0].set_parent(parent, name)
274 else:
275 width = int(math.ceil(math.log(len(self))/math.log(10)))
276 for i,v in enumerate(self):
277 v.set_parent(parent, "%s%0*d" % (name, width, i))
278
279 def has_parent(self):
280 return any([e.has_parent() for e in self if not isNullPointer(e)])
281
282 # return 'cpu0 cpu1' etc. for print_ini()
283 def get_name(self):
284 return ' '.join([v._name for v in self])
285
286 # By iterating through the constituent members of the vector here
287 # we can nicely handle iterating over all a SimObject's children
288 # without having to provide lots of special functions on
289 # SimObjectVector directly.
290 def descendants(self):
291 for v in self:
292 for obj in v.descendants():
293 yield obj
294
295 def get_config_as_dict(self):
296 a = []
297 for v in self:
298 a.append(v.get_config_as_dict())
299 return a
300
301 # If we are replacing an item in the vector, make sure to set the
302 # parent reference of the new SimObject to be the same as the parent
303 # of the SimObject being replaced. Useful to have if we created
304 # a SimObjectVector of temporary objects that will be modified later in
305 # configuration scripts.
306 def __setitem__(self, key, value):
307 val = self[key]
308 if value.has_parent():
309 warn("SimObject %s already has a parent" % value.get_name() +\
310 " that is being overwritten by a SimObjectVector")
311 value.set_parent(val.get_parent(), val._name)
312 super(SimObjectVector, self).__setitem__(key, value)
313
314 # Enumerate the params of each member of the SimObject vector. Creates
315 # strings that will allow indexing into the vector by the python code and
316 # allow it to be specified on the command line.
317 def enumerateParams(self, flags_dict = {},
318 cmd_line_str = "",
319 access_str = ""):
320 if hasattr(self, "_paramEnumed"):
321 print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
322 else:
323 x = 0
324 for vals in self:
325 # Each entry in the SimObjectVector should be an
326 # instance of a SimObject
327 flags_dict = vals.enumerateParams(flags_dict,
328 cmd_line_str + "%d." % x,
329 access_str + "[%d]." % x)
330 x = x + 1
331
332 return flags_dict
333
334 class VectorParamDesc(ParamDesc):
335 # Convert assigned value to appropriate type. If the RHS is not a
336 # list or tuple, it generates a single-element list.
337 def convert(self, value):
338 if isinstance(value, (list, tuple)):
339 # list: coerce each element into new list
340 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
341 elif isinstance(value, str):
342 # If input is a csv string
343 tmp_list = [ ParamDesc.convert(self, v) \
344 for v in value.strip('[').strip(']').split(',') ]
345 else:
346 # singleton: coerce to a single-element list
347 tmp_list = [ ParamDesc.convert(self, value) ]
348
349 if isSimObjectSequence(tmp_list):
350 return SimObjectVector(tmp_list)
351 else:
352 return VectorParamValue(tmp_list)
353
354 # Produce a human readable example string that describes
355 # how to set this vector parameter in the absence of a default
356 # value.
357 def example_str(self):
358 s = super(VectorParamDesc, self).example_str()
359 help_str = "[" + s + "," + s + ", ...]"
360 return help_str
361
362 # Produce a human readable representation of the value of this vector param.
363 def pretty_print(self, value):
364 if isinstance(value, (list, tuple)):
365 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
366 elif isinstance(value, str):
367 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
368 else:
369 tmp_list = [ ParamDesc.pretty_print(self, value) ]
370
371 return tmp_list
372
373 # This is a helper function for the new config system
374 def __call__(self, value):
375 if isinstance(value, (list, tuple)):
376 # list: coerce each element into new list
377 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
378 elif isinstance(value, str):
379 # If input is a csv string
380 tmp_list = [ ParamDesc.convert(self, v) \
381 for v in value.strip('[').strip(']').split(',') ]
382 else:
383 # singleton: coerce to a single-element list
384 tmp_list = [ ParamDesc.convert(self, value) ]
385
386 return VectorParamValue(tmp_list)
387
388 def cxx_predecls(self, code):
389 code('#include <vector>')
390 self.ptype.cxx_predecls(code)
391
392 def pybind_predecls(self, code):
393 code('#include <vector>')
394 self.ptype.pybind_predecls(code)
395
396 def cxx_decl(self, code):
397 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
398
399 class ParamFactory(object):
400 def __init__(self, param_desc_class, ptype_str = None):
401 self.param_desc_class = param_desc_class
402 self.ptype_str = ptype_str
403
404 def __getattr__(self, attr):
405 if self.ptype_str:
406 attr = self.ptype_str + '.' + attr
407 return ParamFactory(self.param_desc_class, attr)
408
409 # E.g., Param.Int(5, "number of widgets")
410 def __call__(self, *args, **kwargs):
411 ptype = None
412 try:
413 ptype = allParams[self.ptype_str]
414 except KeyError:
415 # if name isn't defined yet, assume it's a SimObject, and
416 # try to resolve it later
417 pass
418 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
419
420 Param = ParamFactory(ParamDesc)
421 VectorParam = ParamFactory(VectorParamDesc)
422
423 #####################################################################
424 #
425 # Parameter Types
426 #
427 # Though native Python types could be used to specify parameter types
428 # (the 'ptype' field of the Param and VectorParam classes), it's more
429 # flexible to define our own set of types. This gives us more control
430 # over how Python expressions are converted to values (via the
431 # __init__() constructor) and how these values are printed out (via
432 # the __str__() conversion method).
433 #
434 #####################################################################
435
436 # String-valued parameter. Just mixin the ParamValue class with the
437 # built-in str class.
438 class String(ParamValue,str):
439 cxx_type = 'std::string'
440 cmd_line_settable = True
441
442 @classmethod
443 def cxx_predecls(self, code):
444 code('#include <string>')
445
446 def __call__(self, value):
447 self = value
448 return value
449
450 @classmethod
451 def cxx_ini_parse(self, code, src, dest, ret):
452 code('%s = %s;' % (dest, src))
453 code('%s true;' % ret)
454
455 def getValue(self):
456 return self
457
458 # superclass for "numeric" parameter values, to emulate math
459 # operations in a type-safe way. e.g., a Latency times an int returns
460 # a new Latency object.
461 class NumericParamValue(ParamValue):
462 @staticmethod
463 def unwrap(v):
464 return v.value if isinstance(v, NumericParamValue) else v
465
466 def __str__(self):
467 return str(self.value)
468
469 def __float__(self):
470 return float(self.value)
471
472 def __long__(self):
473 return long(self.value)
474
475 def __int__(self):
476 return int(self.value)
477
478 # hook for bounds checking
479 def _check(self):
480 return
481
482 def __mul__(self, other):
483 newobj = self.__class__(self)
484 newobj.value *= NumericParamValue.unwrap(other)
485 newobj._check()
486 return newobj
487
488 __rmul__ = __mul__
489
490 def __truediv__(self, other):
491 newobj = self.__class__(self)
492 newobj.value /= NumericParamValue.unwrap(other)
493 newobj._check()
494 return newobj
495
496 def __floordiv__(self, other):
497 newobj = self.__class__(self)
498 newobj.value //= NumericParamValue.unwrap(other)
499 newobj._check()
500 return newobj
501
502
503 def __add__(self, other):
504 newobj = self.__class__(self)
505 newobj.value += NumericParamValue.unwrap(other)
506 newobj._check()
507 return newobj
508
509 def __sub__(self, other):
510 newobj = self.__class__(self)
511 newobj.value -= NumericParamValue.unwrap(other)
512 newobj._check()
513 return newobj
514
515 def __iadd__(self, other):
516 self.value += NumericParamValue.unwrap(other)
517 self._check()
518 return self
519
520 def __isub__(self, other):
521 self.value -= NumericParamValue.unwrap(other)
522 self._check()
523 return self
524
525 def __imul__(self, other):
526 self.value *= NumericParamValue.unwrap(other)
527 self._check()
528 return self
529
530 def __itruediv__(self, other):
531 self.value /= NumericParamValue.unwrap(other)
532 self._check()
533 return self
534
535 def __ifloordiv__(self, other):
536 self.value //= NumericParamValue.unwrap(other)
537 self._check()
538 return self
539
540 def __lt__(self, other):
541 return self.value < NumericParamValue.unwrap(other)
542
543 # Python 2.7 pre __future__.division operators
544 # TODO: Remove these when after "import division from __future__"
545 __div__ = __truediv__
546 __idiv__ = __itruediv__
547
548 def config_value(self):
549 return self.value
550
551 @classmethod
552 def cxx_ini_predecls(cls, code):
553 # Assume that base/str.hh will be included anyway
554 # code('#include "base/str.hh"')
555 pass
556
557 # The default for parsing PODs from an .ini entry is to extract from an
558 # istringstream and let overloading choose the right type according to
559 # the dest type.
560 @classmethod
561 def cxx_ini_parse(self, code, src, dest, ret):
562 code('%s to_number(%s, %s);' % (ret, src, dest))
563
564 # Metaclass for bounds-checked integer parameters. See CheckedInt.
565 class CheckedIntType(MetaParamValue):
566 def __init__(cls, name, bases, dict):
567 super(CheckedIntType, cls).__init__(name, bases, dict)
568
569 # CheckedInt is an abstract base class, so we actually don't
570 # want to do any processing on it... the rest of this code is
571 # just for classes that derive from CheckedInt.
572 if name == 'CheckedInt':
573 return
574
575 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
576 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
577 panic("CheckedInt subclass %s must define either\n" \
578 " 'min' and 'max' or 'size' and 'unsigned'\n",
579 name);
580 if cls.unsigned:
581 cls.min = 0
582 cls.max = 2 ** cls.size - 1
583 else:
584 cls.min = -(2 ** (cls.size - 1))
585 cls.max = (2 ** (cls.size - 1)) - 1
586
587 # Abstract superclass for bounds-checked integer parameters. This
588 # class is subclassed to generate parameter classes with specific
589 # bounds. Initialization of the min and max bounds is done in the
590 # metaclass CheckedIntType.__init__.
591 @add_metaclass(CheckedIntType)
592 class CheckedInt(NumericParamValue):
593 cmd_line_settable = True
594
595 def _check(self):
596 if not self.min <= self.value <= self.max:
597 raise TypeError('Integer param out of bounds %d < %d < %d' % \
598 (self.min, self.value, self.max))
599
600 def __init__(self, value):
601 if isinstance(value, str):
602 self.value = convert.toInteger(value)
603 elif isinstance(value, (int, long, float, NumericParamValue)):
604 self.value = long(value)
605 else:
606 raise TypeError("Can't convert object of type %s to CheckedInt" \
607 % type(value).__name__)
608 self._check()
609
610 def __call__(self, value):
611 self.__init__(value)
612 return value
613
614 def __index__(self):
615 return int(self.value)
616
617 @classmethod
618 def cxx_predecls(cls, code):
619 # most derived types require this, so we just do it here once
620 code('#include "base/types.hh"')
621
622 def getValue(self):
623 return long(self.value)
624
625 class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
626 class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
627
628 class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
629 class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
630 class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
631 class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
632 class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
633 class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
634 class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
635 class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
636
637 class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
638 class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
639 class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
640 class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
641
642 class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
643
644 class Cycles(CheckedInt):
645 cxx_type = 'Cycles'
646 size = 64
647 unsigned = True
648
649 def getValue(self):
650 from _m5.core import Cycles
651 return Cycles(self.value)
652
653 @classmethod
654 def cxx_ini_predecls(cls, code):
655 # Assume that base/str.hh will be included anyway
656 # code('#include "base/str.hh"')
657 pass
658
659 @classmethod
660 def cxx_ini_parse(cls, code, src, dest, ret):
661 code('uint64_t _temp;')
662 code('bool _ret = to_number(%s, _temp);' % src)
663 code('if (_ret)')
664 code(' %s = Cycles(_temp);' % dest)
665 code('%s _ret;' % ret)
666
667 class Float(ParamValue, float):
668 cxx_type = 'double'
669 cmd_line_settable = True
670
671 def __init__(self, value):
672 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
673 self.value = float(value)
674 else:
675 raise TypeError("Can't convert object of type %s to Float" \
676 % type(value).__name__)
677
678 def __call__(self, value):
679 self.__init__(value)
680 return value
681
682 def getValue(self):
683 return float(self.value)
684
685 def config_value(self):
686 return self
687
688 @classmethod
689 def cxx_ini_predecls(cls, code):
690 code('#include <sstream>')
691
692 @classmethod
693 def cxx_ini_parse(self, code, src, dest, ret):
694 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
695
696 class MemorySize(CheckedInt):
697 cxx_type = 'uint64_t'
698 ex_str = '512MB'
699 size = 64
700 unsigned = True
701 def __init__(self, value):
702 if isinstance(value, MemorySize):
703 self.value = value.value
704 else:
705 self.value = convert.toMemorySize(value)
706 self._check()
707
708 class MemorySize32(CheckedInt):
709 cxx_type = 'uint32_t'
710 ex_str = '512MB'
711 size = 32
712 unsigned = True
713 def __init__(self, value):
714 if isinstance(value, MemorySize):
715 self.value = value.value
716 else:
717 self.value = convert.toMemorySize(value)
718 self._check()
719
720 class Addr(CheckedInt):
721 cxx_type = 'Addr'
722 size = 64
723 unsigned = True
724 def __init__(self, value):
725 if isinstance(value, Addr):
726 self.value = value.value
727 else:
728 try:
729 # Often addresses are referred to with sizes. Ex: A device
730 # base address is at "512MB". Use toMemorySize() to convert
731 # these into addresses. If the address is not specified with a
732 # "size", an exception will occur and numeric translation will
733 # proceed below.
734 self.value = convert.toMemorySize(value)
735 except (TypeError, ValueError):
736 # Convert number to string and use long() to do automatic
737 # base conversion (requires base=0 for auto-conversion)
738 self.value = long(str(value), base=0)
739
740 self._check()
741 def __add__(self, other):
742 if isinstance(other, Addr):
743 return self.value + other.value
744 else:
745 return self.value + other
746 def pretty_print(self, value):
747 try:
748 val = convert.toMemorySize(value)
749 except TypeError:
750 val = long(value)
751 return "0x%x" % long(val)
752
753 class AddrRange(ParamValue):
754 cxx_type = 'AddrRange'
755
756 def __init__(self, *args, **kwargs):
757 # Disable interleaving and hashing by default
758 self.intlvBits = 0
759 self.intlvMatch = 0
760 self.masks = []
761
762 def handle_kwargs(self, kwargs):
763 # An address range needs to have an upper limit, specified
764 # either explicitly with an end, or as an offset using the
765 # size keyword.
766 if 'end' in kwargs:
767 self.end = Addr(kwargs.pop('end'))
768 elif 'size' in kwargs:
769 self.end = self.start + Addr(kwargs.pop('size'))
770 else:
771 raise TypeError("Either end or size must be specified")
772
773 # Now on to the optional bit
774 if 'intlvMatch' in kwargs:
775 self.intlvMatch = int(kwargs.pop('intlvMatch'))
776
777 if 'masks' in kwargs:
778 self.masks = [ long(x) for x in list(kwargs.pop('masks')) ]
779 self.intlvBits = len(self.masks)
780 else:
781 if 'intlvBits' in kwargs:
782 self.intlvBits = int(kwargs.pop('intlvBits'))
783 self.masks = [0] * self.intlvBits
784 if 'intlvHighBit' not in kwargs:
785 raise TypeError("No interleave bits specified")
786 intlv_high_bit = int(kwargs.pop('intlvHighBit'))
787 xor_high_bit = 0
788 if 'xorHighBit' in kwargs:
789 xor_high_bit = int(kwargs.pop('xorHighBit'))
790 for i in range(0, self.intlvBits):
791 bit1 = intlv_high_bit - i
792 mask = 1 << bit1
793 if xor_high_bit != 0:
794 bit2 = xor_high_bit - i
795 mask |= 1 << bit2
796 self.masks[self.intlvBits - i - 1] = mask
797
798 if len(args) == 0:
799 self.start = Addr(kwargs.pop('start'))
800 handle_kwargs(self, kwargs)
801
802 elif len(args) == 1:
803 if kwargs:
804 self.start = Addr(args[0])
805 handle_kwargs(self, kwargs)
806 elif isinstance(args[0], (list, tuple)):
807 self.start = Addr(args[0][0])
808 self.end = Addr(args[0][1])
809 else:
810 self.start = Addr(0)
811 self.end = Addr(args[0])
812
813 elif len(args) == 2:
814 self.start = Addr(args[0])
815 self.end = Addr(args[1])
816 else:
817 raise TypeError("Too many arguments specified")
818
819 if kwargs:
820 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
821
822 def __str__(self):
823 if len(self.masks) == 0:
824 return '%s:%s' % (self.start, self.end)
825 else:
826 return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch,
827 ':'.join(str(m) for m in self.masks))
828
829 def size(self):
830 # Divide the size by the size of the interleaving slice
831 return (long(self.end) - long(self.start)) >> self.intlvBits
832
833 @classmethod
834 def cxx_predecls(cls, code):
835 Addr.cxx_predecls(code)
836 code('#include "base/addr_range.hh"')
837
838 @classmethod
839 def pybind_predecls(cls, code):
840 Addr.pybind_predecls(code)
841 code('#include "base/addr_range.hh"')
842
843 @classmethod
844 def cxx_ini_predecls(cls, code):
845 code('#include <sstream>')
846 code('#include <vector>')
847 code('#include "base/types.hh"')
848
849 @classmethod
850 def cxx_ini_parse(cls, code, src, dest, ret):
851 code('bool _ret = true;')
852 code('uint64_t _start, _end, _intlvMatch = 0;')
853 code('std::vector<Addr> _masks;')
854 code('char _sep;')
855 code('std::istringstream _stream(${src});')
856 code('_stream >> _start;')
857 code('_stream.get(_sep);')
858 code('_ret = _sep == \':\';')
859 code('_stream >> _end;')
860 code('if (!_stream.fail() && !_stream.eof()) {')
861 code(' _stream.get(_sep);')
862 code(' _ret = ret && _sep == \':\';')
863 code(' _stream >> _intlvMatch;')
864 code(' while (!_stream.fail() && !_stream.eof()) {')
865 code(' _stream.get(_sep);')
866 code(' _ret = ret && _sep == \':\';')
867 code(' Addr mask;')
868 code(' _stream >> mask;')
869 code(' _masks.push_back(mask);')
870 code(' }')
871 code('}')
872 code('_ret = _ret && !_stream.fail() && _stream.eof();')
873 code('if (_ret)')
874 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
875 code('${ret} _ret;')
876
877 def getValue(self):
878 # Go from the Python class to the wrapped C++ class
879 from _m5.range import AddrRange
880
881 return AddrRange(long(self.start), long(self.end),
882 self.masks, int(self.intlvMatch))
883
884 # Boolean parameter type. Python doesn't let you subclass bool, since
885 # it doesn't want to let you create multiple instances of True and
886 # False. Thus this is a little more complicated than String.
887 class Bool(ParamValue):
888 cxx_type = 'bool'
889 cmd_line_settable = True
890
891 def __init__(self, value):
892 try:
893 self.value = convert.toBool(value)
894 except TypeError:
895 self.value = bool(value)
896
897 def __call__(self, value):
898 self.__init__(value)
899 return value
900
901 def getValue(self):
902 return bool(self.value)
903
904 def __str__(self):
905 return str(self.value)
906
907 # implement truth value testing for Bool parameters so that these params
908 # evaluate correctly during the python configuration phase
909 def __bool__(self):
910 return bool(self.value)
911
912 # Python 2.7 uses __nonzero__ instead of __bool__
913 __nonzero__ = __bool__
914
915 def ini_str(self):
916 if self.value:
917 return 'true'
918 return 'false'
919
920 def config_value(self):
921 return self.value
922
923 @classmethod
924 def cxx_ini_predecls(cls, code):
925 # Assume that base/str.hh will be included anyway
926 # code('#include "base/str.hh"')
927 pass
928
929 @classmethod
930 def cxx_ini_parse(cls, code, src, dest, ret):
931 code('%s to_bool(%s, %s);' % (ret, src, dest))
932
933 def IncEthernetAddr(addr, val = 1):
934 bytes = [ int(x, 16) for x in addr.split(':') ]
935 bytes[5] += val
936 for i in (5, 4, 3, 2, 1):
937 val,rem = divmod(bytes[i], 256)
938 bytes[i] = rem
939 if val == 0:
940 break
941 bytes[i - 1] += val
942 assert(bytes[0] <= 255)
943 return ':'.join(map(lambda x: '%02x' % x, bytes))
944
945 _NextEthernetAddr = "00:90:00:00:00:01"
946 def NextEthernetAddr():
947 global _NextEthernetAddr
948
949 value = _NextEthernetAddr
950 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
951 return value
952
953 class EthernetAddr(ParamValue):
954 cxx_type = 'Net::EthAddr'
955 ex_str = "00:90:00:00:00:01"
956 cmd_line_settable = True
957
958 @classmethod
959 def cxx_predecls(cls, code):
960 code('#include "base/inet.hh"')
961
962 def __init__(self, value):
963 if value == NextEthernetAddr:
964 self.value = value
965 return
966
967 if not isinstance(value, str):
968 raise TypeError("expected an ethernet address and didn't get one")
969
970 bytes = value.split(':')
971 if len(bytes) != 6:
972 raise TypeError('invalid ethernet address %s' % value)
973
974 for byte in bytes:
975 if not 0 <= int(byte, base=16) <= 0xff:
976 raise TypeError('invalid ethernet address %s' % value)
977
978 self.value = value
979
980 def __call__(self, value):
981 self.__init__(value)
982 return value
983
984 def unproxy(self, base):
985 if self.value == NextEthernetAddr:
986 return EthernetAddr(self.value())
987 return self
988
989 def getValue(self):
990 from _m5.net import EthAddr
991 return EthAddr(self.value)
992
993 def __str__(self):
994 return self.value
995
996 def ini_str(self):
997 return self.value
998
999 @classmethod
1000 def cxx_ini_parse(self, code, src, dest, ret):
1001 code('%s = Net::EthAddr(%s);' % (dest, src))
1002 code('%s true;' % ret)
1003
1004 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1005 # the form "a.b.c.d", or an integer representing an IP.
1006 class IpAddress(ParamValue):
1007 cxx_type = 'Net::IpAddress'
1008 ex_str = "127.0.0.1"
1009 cmd_line_settable = True
1010
1011 @classmethod
1012 def cxx_predecls(cls, code):
1013 code('#include "base/inet.hh"')
1014
1015 def __init__(self, value):
1016 if isinstance(value, IpAddress):
1017 self.ip = value.ip
1018 else:
1019 try:
1020 self.ip = convert.toIpAddress(value)
1021 except TypeError:
1022 self.ip = long(value)
1023 self.verifyIp()
1024
1025 def __call__(self, value):
1026 self.__init__(value)
1027 return value
1028
1029 def __str__(self):
1030 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
1031 return '%d.%d.%d.%d' % tuple(tup)
1032
1033 def __eq__(self, other):
1034 if isinstance(other, IpAddress):
1035 return self.ip == other.ip
1036 elif isinstance(other, str):
1037 try:
1038 return self.ip == convert.toIpAddress(other)
1039 except:
1040 return False
1041 else:
1042 return self.ip == other
1043
1044 def __ne__(self, other):
1045 return not (self == other)
1046
1047 def verifyIp(self):
1048 if self.ip < 0 or self.ip >= (1 << 32):
1049 raise TypeError("invalid ip address %#08x" % self.ip)
1050
1051 def getValue(self):
1052 from _m5.net import IpAddress
1053 return IpAddress(self.ip)
1054
1055 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1056 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1057 # positional or keyword arguments.
1058 class IpNetmask(IpAddress):
1059 cxx_type = 'Net::IpNetmask'
1060 ex_str = "127.0.0.0/24"
1061 cmd_line_settable = True
1062
1063 @classmethod
1064 def cxx_predecls(cls, code):
1065 code('#include "base/inet.hh"')
1066
1067 def __init__(self, *args, **kwargs):
1068 def handle_kwarg(self, kwargs, key, elseVal = None):
1069 if key in kwargs:
1070 setattr(self, key, kwargs.pop(key))
1071 elif elseVal:
1072 setattr(self, key, elseVal)
1073 else:
1074 raise TypeError("No value set for %s" % key)
1075
1076 if len(args) == 0:
1077 handle_kwarg(self, kwargs, 'ip')
1078 handle_kwarg(self, kwargs, 'netmask')
1079
1080 elif len(args) == 1:
1081 if kwargs:
1082 if not 'ip' in kwargs and not 'netmask' in kwargs:
1083 raise TypeError("Invalid arguments")
1084 handle_kwarg(self, kwargs, 'ip', args[0])
1085 handle_kwarg(self, kwargs, 'netmask', args[0])
1086 elif isinstance(args[0], IpNetmask):
1087 self.ip = args[0].ip
1088 self.netmask = args[0].netmask
1089 else:
1090 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1091
1092 elif len(args) == 2:
1093 self.ip = args[0]
1094 self.netmask = args[1]
1095 else:
1096 raise TypeError("Too many arguments specified")
1097
1098 if kwargs:
1099 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1100
1101 self.verify()
1102
1103 def __call__(self, value):
1104 self.__init__(value)
1105 return value
1106
1107 def __str__(self):
1108 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1109
1110 def __eq__(self, other):
1111 if isinstance(other, IpNetmask):
1112 return self.ip == other.ip and self.netmask == other.netmask
1113 elif isinstance(other, str):
1114 try:
1115 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1116 except:
1117 return False
1118 else:
1119 return False
1120
1121 def verify(self):
1122 self.verifyIp()
1123 if self.netmask < 0 or self.netmask > 32:
1124 raise TypeError("invalid netmask %d" % netmask)
1125
1126 def getValue(self):
1127 from _m5.net import IpNetmask
1128 return IpNetmask(self.ip, self.netmask)
1129
1130 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1131 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1132 class IpWithPort(IpAddress):
1133 cxx_type = 'Net::IpWithPort'
1134 ex_str = "127.0.0.1:80"
1135 cmd_line_settable = True
1136
1137 @classmethod
1138 def cxx_predecls(cls, code):
1139 code('#include "base/inet.hh"')
1140
1141 def __init__(self, *args, **kwargs):
1142 def handle_kwarg(self, kwargs, key, elseVal = None):
1143 if key in kwargs:
1144 setattr(self, key, kwargs.pop(key))
1145 elif elseVal:
1146 setattr(self, key, elseVal)
1147 else:
1148 raise TypeError("No value set for %s" % key)
1149
1150 if len(args) == 0:
1151 handle_kwarg(self, kwargs, 'ip')
1152 handle_kwarg(self, kwargs, 'port')
1153
1154 elif len(args) == 1:
1155 if kwargs:
1156 if not 'ip' in kwargs and not 'port' in kwargs:
1157 raise TypeError("Invalid arguments")
1158 handle_kwarg(self, kwargs, 'ip', args[0])
1159 handle_kwarg(self, kwargs, 'port', args[0])
1160 elif isinstance(args[0], IpWithPort):
1161 self.ip = args[0].ip
1162 self.port = args[0].port
1163 else:
1164 (self.ip, self.port) = convert.toIpWithPort(args[0])
1165
1166 elif len(args) == 2:
1167 self.ip = args[0]
1168 self.port = args[1]
1169 else:
1170 raise TypeError("Too many arguments specified")
1171
1172 if kwargs:
1173 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1174
1175 self.verify()
1176
1177 def __call__(self, value):
1178 self.__init__(value)
1179 return value
1180
1181 def __str__(self):
1182 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1183
1184 def __eq__(self, other):
1185 if isinstance(other, IpWithPort):
1186 return self.ip == other.ip and self.port == other.port
1187 elif isinstance(other, str):
1188 try:
1189 return (self.ip, self.port) == convert.toIpWithPort(other)
1190 except:
1191 return False
1192 else:
1193 return False
1194
1195 def verify(self):
1196 self.verifyIp()
1197 if self.port < 0 or self.port > 0xffff:
1198 raise TypeError("invalid port %d" % self.port)
1199
1200 def getValue(self):
1201 from _m5.net import IpWithPort
1202 return IpWithPort(self.ip, self.port)
1203
1204 time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1205 "%a %b %d %H:%M:%S %Y",
1206 "%Y/%m/%d %H:%M:%S",
1207 "%Y/%m/%d %H:%M",
1208 "%Y/%m/%d",
1209 "%m/%d/%Y %H:%M:%S",
1210 "%m/%d/%Y %H:%M",
1211 "%m/%d/%Y",
1212 "%m/%d/%y %H:%M:%S",
1213 "%m/%d/%y %H:%M",
1214 "%m/%d/%y"]
1215
1216
1217 def parse_time(value):
1218 from time import gmtime, strptime, struct_time, time
1219 from datetime import datetime, date
1220
1221 if isinstance(value, struct_time):
1222 return value
1223
1224 if isinstance(value, (int, long)):
1225 return gmtime(value)
1226
1227 if isinstance(value, (datetime, date)):
1228 return value.timetuple()
1229
1230 if isinstance(value, str):
1231 if value in ('Now', 'Today'):
1232 return time.gmtime(time.time())
1233
1234 for format in time_formats:
1235 try:
1236 return strptime(value, format)
1237 except ValueError:
1238 pass
1239
1240 raise ValueError("Could not parse '%s' as a time" % value)
1241
1242 class Time(ParamValue):
1243 cxx_type = 'tm'
1244
1245 @classmethod
1246 def cxx_predecls(cls, code):
1247 code('#include <time.h>')
1248
1249 def __init__(self, value):
1250 self.value = parse_time(value)
1251
1252 def __call__(self, value):
1253 self.__init__(value)
1254 return value
1255
1256 def getValue(self):
1257 from _m5.core import tm
1258 import calendar
1259
1260 return tm.gmtime(calendar.timegm(self.value))
1261
1262 def __str__(self):
1263 return time.asctime(self.value)
1264
1265 def ini_str(self):
1266 return str(self)
1267
1268 def get_config_as_dict(self):
1269 assert false
1270 return str(self)
1271
1272 @classmethod
1273 def cxx_ini_predecls(cls, code):
1274 code('#include <time.h>')
1275
1276 @classmethod
1277 def cxx_ini_parse(cls, code, src, dest, ret):
1278 code('char *_parse_ret = strptime((${src}).c_str(),')
1279 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1280 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1281
1282 # Enumerated types are a little more complex. The user specifies the
1283 # type as Enum(foo) where foo is either a list or dictionary of
1284 # alternatives (typically strings, but not necessarily so). (In the
1285 # long run, the integer value of the parameter will be the list index
1286 # or the corresponding dictionary value. For now, since we only check
1287 # that the alternative is valid and then spit it into a .ini file,
1288 # there's not much point in using the dictionary.)
1289
1290 # What Enum() must do is generate a new type encapsulating the
1291 # provided list/dictionary so that specific values of the parameter
1292 # can be instances of that type. We define two hidden internal
1293 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1294 # derive the new type from the appropriate base class on the fly.
1295
1296 allEnums = {}
1297 # Metaclass for Enum types
1298 class MetaEnum(MetaParamValue):
1299 def __new__(mcls, name, bases, dict):
1300
1301 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1302 allEnums[name] = cls
1303 return cls
1304
1305 def __init__(cls, name, bases, init_dict):
1306 if 'map' in init_dict:
1307 if not isinstance(cls.map, dict):
1308 raise TypeError("Enum-derived class attribute 'map' " \
1309 "must be of type dict")
1310 # build list of value strings from map
1311 cls.vals = list(cls.map.keys())
1312 cls.vals.sort()
1313 elif 'vals' in init_dict:
1314 if not isinstance(cls.vals, list):
1315 raise TypeError("Enum-derived class attribute 'vals' " \
1316 "must be of type list")
1317 # build string->value map from vals sequence
1318 cls.map = {}
1319 for idx,val in enumerate(cls.vals):
1320 cls.map[val] = idx
1321 else:
1322 raise TypeError("Enum-derived class must define "\
1323 "attribute 'map' or 'vals'")
1324
1325 if cls.is_class:
1326 cls.cxx_type = '%s' % name
1327 else:
1328 cls.cxx_type = 'Enums::%s' % name
1329
1330 super(MetaEnum, cls).__init__(name, bases, init_dict)
1331
1332 # Generate C++ class declaration for this enum type.
1333 # Note that we wrap the enum in a class/struct to act as a namespace,
1334 # so that the enum strings can be brief w/o worrying about collisions.
1335 def cxx_decl(cls, code):
1336 wrapper_name = cls.wrapper_name
1337 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1338 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1339 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1340
1341 code('''\
1342 #ifndef $idem_macro
1343 #define $idem_macro
1344
1345 ''')
1346 if cls.is_class:
1347 code('''\
1348 enum class $name {
1349 ''')
1350 else:
1351 code('''\
1352 $wrapper $wrapper_name {
1353 enum $name {
1354 ''')
1355 code.indent(1)
1356 code.indent(1)
1357 for val in cls.vals:
1358 code('$val = ${{cls.map[val]}},')
1359 code('Num_$name = ${{len(cls.vals)}}')
1360 code.dedent(1)
1361 code('};')
1362
1363 if cls.is_class:
1364 code('''\
1365 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1366 ''')
1367 elif cls.wrapper_is_struct:
1368 code('static const char *${name}Strings[Num_${name}];')
1369 else:
1370 code('extern const char *${name}Strings[Num_${name}];')
1371
1372 if not cls.is_class:
1373 code.dedent(1)
1374 code('};')
1375
1376 code()
1377 code('#endif // $idem_macro')
1378
1379 def cxx_def(cls, code):
1380 wrapper_name = cls.wrapper_name
1381 file_name = cls.__name__
1382 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1383
1384 code('#include "enums/$file_name.hh"')
1385 if cls.wrapper_is_struct:
1386 code('const char *${wrapper_name}::${name}Strings'
1387 '[Num_${name}] =')
1388 else:
1389 if cls.is_class:
1390 code('''\
1391 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1392 ''')
1393 else:
1394 code('namespace Enums {')
1395 code.indent(1)
1396 code('const char *${name}Strings[Num_${name}] =')
1397
1398 code('{')
1399 code.indent(1)
1400 for val in cls.vals:
1401 code('"$val",')
1402 code.dedent(1)
1403 code('};')
1404
1405 if not cls.wrapper_is_struct and not cls.is_class:
1406 code.dedent(1)
1407 code('} // namespace $wrapper_name')
1408
1409
1410 def pybind_def(cls, code):
1411 name = cls.__name__
1412 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1413 wrapper_name = enum_name if cls.is_class else cls.wrapper_name
1414
1415 code('''#include "pybind11/pybind11.h"
1416 #include "pybind11/stl.h"
1417
1418 #include <sim/init.hh>
1419
1420 namespace py = pybind11;
1421
1422 static void
1423 module_init(py::module &m_internal)
1424 {
1425 py::module m = m_internal.def_submodule("enum_${name}");
1426
1427 ''')
1428 if cls.is_class:
1429 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1430 else:
1431 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1432
1433 code.indent()
1434 code.indent()
1435 for val in cls.vals:
1436 code('.value("${val}", ${wrapper_name}::${val})')
1437 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1438 if not cls.is_class:
1439 code('.export_values()')
1440 code(';')
1441 code.dedent()
1442
1443 code('}')
1444 code.dedent()
1445 code()
1446 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1447
1448
1449 # Base class for enum types.
1450 @add_metaclass(MetaEnum)
1451 class Enum(ParamValue):
1452 vals = []
1453 cmd_line_settable = True
1454
1455 # The name of the wrapping namespace or struct
1456 wrapper_name = 'Enums'
1457
1458 # If true, the enum is wrapped in a struct rather than a namespace
1459 wrapper_is_struct = False
1460
1461 is_class = False
1462
1463 # If not None, use this as the enum name rather than this class name
1464 enum_name = None
1465
1466 def __init__(self, value):
1467 if value not in self.map:
1468 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1469 % (value, self.vals))
1470 self.value = value
1471
1472 def __call__(self, value):
1473 self.__init__(value)
1474 return value
1475
1476 @classmethod
1477 def cxx_predecls(cls, code):
1478 code('#include "enums/$0.hh"', cls.__name__)
1479
1480 @classmethod
1481 def cxx_ini_parse(cls, code, src, dest, ret):
1482 code('if (false) {')
1483 for elem_name in cls.map.keys():
1484 code('} else if (%s == "%s") {' % (src, elem_name))
1485 code.indent()
1486 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1487 code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums',
1488 elem_name))
1489 code('%s true;' % ret)
1490 code.dedent()
1491 code('} else {')
1492 code(' %s false;' % ret)
1493 code('}')
1494
1495 def getValue(self):
1496 import m5.internal.params
1497 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1498 return e(self.map[self.value])
1499
1500 def __str__(self):
1501 return self.value
1502
1503 # This param will generate a scoped c++ enum and its python bindings.
1504 @add_metaclass(MetaEnum)
1505 class ScopedEnum(Enum):
1506 vals = []
1507 cmd_line_settable = True
1508
1509 # The name of the wrapping namespace or struct
1510 wrapper_name = None
1511
1512 # If true, the enum is wrapped in a struct rather than a namespace
1513 wrapper_is_struct = False
1514
1515 # If true, the generated enum is a scoped enum
1516 is_class = True
1517
1518 # If not None, use this as the enum name rather than this class name
1519 enum_name = None
1520
1521 # how big does a rounding error need to be before we warn about it?
1522 frequency_tolerance = 0.001 # 0.1%
1523
1524 class TickParamValue(NumericParamValue):
1525 cxx_type = 'Tick'
1526 ex_str = "1MHz"
1527 cmd_line_settable = True
1528
1529 @classmethod
1530 def cxx_predecls(cls, code):
1531 code('#include "base/types.hh"')
1532
1533 def __call__(self, value):
1534 self.__init__(value)
1535 return value
1536
1537 def getValue(self):
1538 return long(self.value)
1539
1540 @classmethod
1541 def cxx_ini_predecls(cls, code):
1542 code('#include <sstream>')
1543
1544 # Ticks are expressed in seconds in JSON files and in plain
1545 # Ticks in .ini files. Switch based on a config flag
1546 @classmethod
1547 def cxx_ini_parse(self, code, src, dest, ret):
1548 code('${ret} to_number(${src}, ${dest});')
1549
1550 class Latency(TickParamValue):
1551 ex_str = "100ns"
1552
1553 def __init__(self, value):
1554 if isinstance(value, (Latency, Clock)):
1555 self.ticks = value.ticks
1556 self.value = value.value
1557 elif isinstance(value, Frequency):
1558 self.ticks = value.ticks
1559 self.value = 1.0 / value.value
1560 elif value.endswith('t'):
1561 self.ticks = True
1562 self.value = int(value[:-1])
1563 else:
1564 self.ticks = False
1565 self.value = convert.toLatency(value)
1566
1567 def __call__(self, value):
1568 self.__init__(value)
1569 return value
1570
1571 def __getattr__(self, attr):
1572 if attr in ('latency', 'period'):
1573 return self
1574 if attr == 'frequency':
1575 return Frequency(self)
1576 raise AttributeError("Latency object has no attribute '%s'" % attr)
1577
1578 def getValue(self):
1579 if self.ticks or self.value == 0:
1580 value = self.value
1581 else:
1582 value = ticks.fromSeconds(self.value)
1583 return long(value)
1584
1585 def config_value(self):
1586 return self.getValue()
1587
1588 # convert latency to ticks
1589 def ini_str(self):
1590 return '%d' % self.getValue()
1591
1592 class Frequency(TickParamValue):
1593 ex_str = "1GHz"
1594
1595 def __init__(self, value):
1596 if isinstance(value, (Latency, Clock)):
1597 if value.value == 0:
1598 self.value = 0
1599 else:
1600 self.value = 1.0 / value.value
1601 self.ticks = value.ticks
1602 elif isinstance(value, Frequency):
1603 self.value = value.value
1604 self.ticks = value.ticks
1605 else:
1606 self.ticks = False
1607 self.value = convert.toFrequency(value)
1608
1609 def __call__(self, value):
1610 self.__init__(value)
1611 return value
1612
1613 def __getattr__(self, attr):
1614 if attr == 'frequency':
1615 return self
1616 if attr in ('latency', 'period'):
1617 return Latency(self)
1618 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1619
1620 # convert latency to ticks
1621 def getValue(self):
1622 if self.ticks or self.value == 0:
1623 value = self.value
1624 else:
1625 value = ticks.fromSeconds(1.0 / self.value)
1626 return long(value)
1627
1628 def config_value(self):
1629 return self.getValue()
1630
1631 def ini_str(self):
1632 return '%d' % self.getValue()
1633
1634 # A generic Frequency and/or Latency value. Value is stored as a
1635 # latency, just like Latency and Frequency.
1636 class Clock(TickParamValue):
1637 def __init__(self, value):
1638 if isinstance(value, (Latency, Clock)):
1639 self.ticks = value.ticks
1640 self.value = value.value
1641 elif isinstance(value, Frequency):
1642 self.ticks = value.ticks
1643 self.value = 1.0 / value.value
1644 elif value.endswith('t'):
1645 self.ticks = True
1646 self.value = int(value[:-1])
1647 else:
1648 self.ticks = False
1649 self.value = convert.anyToLatency(value)
1650
1651 def __call__(self, value):
1652 self.__init__(value)
1653 return value
1654
1655 def __str__(self):
1656 return "%s" % Latency(self)
1657
1658 def __getattr__(self, attr):
1659 if attr == 'frequency':
1660 return Frequency(self)
1661 if attr in ('latency', 'period'):
1662 return Latency(self)
1663 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1664
1665 def getValue(self):
1666 return self.period.getValue()
1667
1668 def config_value(self):
1669 return self.period.config_value()
1670
1671 def ini_str(self):
1672 return self.period.ini_str()
1673
1674 class Voltage(Float):
1675 ex_str = "1V"
1676
1677 def __new__(cls, value):
1678 value = convert.toVoltage(value)
1679 return super(cls, Voltage).__new__(cls, value)
1680
1681 def __init__(self, value):
1682 value = convert.toVoltage(value)
1683 super(Voltage, self).__init__(value)
1684
1685 class Current(Float):
1686 ex_str = "1mA"
1687
1688 def __new__(cls, value):
1689 value = convert.toCurrent(value)
1690 return super(cls, Current).__new__(cls, value)
1691
1692 def __init__(self, value):
1693 value = convert.toCurrent(value)
1694 super(Current, self).__init__(value)
1695
1696 class Energy(Float):
1697 ex_str = "1pJ"
1698
1699 def __new__(cls, value):
1700 value = convert.toEnergy(value)
1701 return super(cls, Energy).__new__(cls, value)
1702
1703 def __init__(self, value):
1704 value = convert.toEnergy(value)
1705 super(Energy, self).__init__(value)
1706
1707 class NetworkBandwidth(float,ParamValue):
1708 cxx_type = 'float'
1709 ex_str = "1Gbps"
1710 cmd_line_settable = True
1711
1712 def __new__(cls, value):
1713 # convert to bits per second
1714 val = convert.toNetworkBandwidth(value)
1715 return super(cls, NetworkBandwidth).__new__(cls, val)
1716
1717 def __str__(self):
1718 return str(self.val)
1719
1720 def __call__(self, value):
1721 val = convert.toNetworkBandwidth(value)
1722 self.__init__(val)
1723 return value
1724
1725 def getValue(self):
1726 # convert to seconds per byte
1727 value = 8.0 / float(self)
1728 # convert to ticks per byte
1729 value = ticks.fromSeconds(value)
1730 return float(value)
1731
1732 def ini_str(self):
1733 return '%f' % self.getValue()
1734
1735 def config_value(self):
1736 return '%f' % self.getValue()
1737
1738 @classmethod
1739 def cxx_ini_predecls(cls, code):
1740 code('#include <sstream>')
1741
1742 @classmethod
1743 def cxx_ini_parse(self, code, src, dest, ret):
1744 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1745
1746 class MemoryBandwidth(float,ParamValue):
1747 cxx_type = 'float'
1748 ex_str = "1GB/s"
1749 cmd_line_settable = True
1750
1751 def __new__(cls, value):
1752 # convert to bytes per second
1753 val = convert.toMemoryBandwidth(value)
1754 return super(cls, MemoryBandwidth).__new__(cls, val)
1755
1756 def __call__(self, value):
1757 val = convert.toMemoryBandwidth(value)
1758 self.__init__(val)
1759 return value
1760
1761 def getValue(self):
1762 # convert to seconds per byte
1763 value = float(self)
1764 if value:
1765 value = 1.0 / float(self)
1766 # convert to ticks per byte
1767 value = ticks.fromSeconds(value)
1768 return float(value)
1769
1770 def ini_str(self):
1771 return '%f' % self.getValue()
1772
1773 def config_value(self):
1774 return '%f' % self.getValue()
1775
1776 @classmethod
1777 def cxx_ini_predecls(cls, code):
1778 code('#include <sstream>')
1779
1780 @classmethod
1781 def cxx_ini_parse(self, code, src, dest, ret):
1782 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1783
1784 #
1785 # "Constants"... handy aliases for various values.
1786 #
1787
1788 # Special class for NULL pointers. Note the special check in
1789 # make_param_value() above that lets these be assigned where a
1790 # SimObject is required.
1791 # only one copy of a particular node
1792 @add_metaclass(Singleton)
1793 class NullSimObject(object):
1794 _name = 'Null'
1795
1796 def __call__(cls):
1797 return cls
1798
1799 def _instantiate(self, parent = None, path = ''):
1800 pass
1801
1802 def ini_str(self):
1803 return 'Null'
1804
1805 def unproxy(self, base):
1806 return self
1807
1808 def set_path(self, parent, name):
1809 pass
1810
1811 def set_parent(self, parent, name):
1812 pass
1813
1814 def clear_parent(self, old_parent):
1815 pass
1816
1817 def descendants(self):
1818 return
1819 yield None
1820
1821 def get_config_as_dict(self):
1822 return {}
1823
1824 def __str__(self):
1825 return self._name
1826
1827 def config_value(self):
1828 return None
1829
1830 def getValue(self):
1831 return None
1832
1833 # The only instance you'll ever need...
1834 NULL = NullSimObject()
1835
1836 def isNullPointer(value):
1837 return isinstance(value, NullSimObject)
1838
1839 # Some memory range specifications use this as a default upper bound.
1840 MaxAddr = Addr.max
1841 MaxTick = Tick.max
1842 AllMemory = AddrRange(0, MaxAddr)
1843
1844
1845 #####################################################################
1846 #
1847 # Port objects
1848 #
1849 # Ports are used to interconnect objects in the memory system.
1850 #
1851 #####################################################################
1852
1853 # Port reference: encapsulates a reference to a particular port on a
1854 # particular SimObject.
1855 class PortRef(object):
1856 def __init__(self, simobj, name, role, is_source):
1857 assert(isSimObject(simobj) or isSimObjectClass(simobj))
1858 self.simobj = simobj
1859 self.name = name
1860 self.role = role
1861 self.is_source = is_source
1862 self.peer = None # not associated with another port yet
1863 self.ccConnected = False # C++ port connection done?
1864 self.index = -1 # always -1 for non-vector ports
1865
1866 def __str__(self):
1867 return '%s.%s' % (self.simobj, self.name)
1868
1869 def __len__(self):
1870 # Return the number of connected ports, i.e. 0 is we have no
1871 # peer and 1 if we do.
1872 return int(self.peer != None)
1873
1874 # for config.ini, print peer's name (not ours)
1875 def ini_str(self):
1876 return str(self.peer)
1877
1878 # for config.json
1879 def get_config_as_dict(self):
1880 return {'role' : self.role, 'peer' : str(self.peer),
1881 'is_source' : str(self.is_source)}
1882
1883 def __getattr__(self, attr):
1884 if attr == 'peerObj':
1885 # shorthand for proxies
1886 return self.peer.simobj
1887 raise AttributeError("'%s' object has no attribute '%s'" % \
1888 (self.__class__.__name__, attr))
1889
1890 # Full connection is symmetric (both ways). Called via
1891 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1892 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1893 # e.g., "obj1.portA[3] = obj2.portB".
1894 def connect(self, other):
1895 if isinstance(other, VectorPortRef):
1896 # reference to plain VectorPort is implicit append
1897 other = other._get_next()
1898 if self.peer and not proxy.isproxy(self.peer):
1899 fatal("Port %s is already connected to %s, cannot connect %s\n",
1900 self, self.peer, other);
1901 self.peer = other
1902
1903 if proxy.isproxy(other):
1904 other.set_param_desc(PortParamDesc())
1905 return
1906 elif not isinstance(other, PortRef):
1907 raise TypeError("assigning non-port reference '%s' to port '%s'" \
1908 % (other, self))
1909
1910 if not Port.is_compat(self, other):
1911 fatal("Ports %s and %s with roles '%s' and '%s' "
1912 "are not compatible", self, other, self.role, other.role)
1913
1914 if other.peer is not self:
1915 other.connect(self)
1916
1917 # Allow a compatible port pair to be spliced between a port and its
1918 # connected peer. Useful operation for connecting instrumentation
1919 # structures into a system when it is necessary to connect the
1920 # instrumentation after the full system has been constructed.
1921 def splice(self, new_1, new_2):
1922 if not self.peer or proxy.isproxy(self.peer):
1923 fatal("Port %s not connected, cannot splice in new peers\n", self)
1924
1925 if not isinstance(new_1, PortRef) or not isinstance(new_2, PortRef):
1926 raise TypeError(
1927 "Splicing non-port references '%s','%s' to port '%s'" % \
1928 (new_1, new_2, self))
1929
1930 old_peer = self.peer
1931
1932 if Port.is_compat(old_peer, new_1) and Port.is_compat(self, new_2):
1933 old_peer.peer = new_1
1934 new_1.peer = old_peer
1935 self.peer = new_2
1936 new_2.peer = self
1937 elif Port.is_compat(old_peer, new_2) and Port.is_compat(self, new_1):
1938 old_peer.peer = new_2
1939 new_2.peer = old_peer
1940 self.peer = new_1
1941 new_1.peer = self
1942 else:
1943 fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
1944 "%s(%s) and %s(%s)", self, self.role,
1945 old_peer, old_peer.role, new_1, new_1.role,
1946 new_2, new_2.role)
1947
1948 def clone(self, simobj, memo):
1949 if self in memo:
1950 return memo[self]
1951 newRef = copy.copy(self)
1952 memo[self] = newRef
1953 newRef.simobj = simobj
1954 assert(isSimObject(newRef.simobj))
1955 if self.peer and not proxy.isproxy(self.peer):
1956 peerObj = self.peer.simobj(_memo=memo)
1957 newRef.peer = self.peer.clone(peerObj, memo)
1958 assert(not isinstance(newRef.peer, VectorPortRef))
1959 return newRef
1960
1961 def unproxy(self, simobj):
1962 assert(simobj is self.simobj)
1963 if proxy.isproxy(self.peer):
1964 try:
1965 realPeer = self.peer.unproxy(self.simobj)
1966 except:
1967 print("Error in unproxying port '%s' of %s" %
1968 (self.name, self.simobj.path()))
1969 raise
1970 self.connect(realPeer)
1971
1972 # Call C++ to create corresponding port connection between C++ objects
1973 def ccConnect(self):
1974 if self.ccConnected: # already done this
1975 return
1976
1977 peer = self.peer
1978 if not self.peer: # nothing to connect to
1979 return
1980
1981 port = self.simobj.getPort(self.name, self.index)
1982 peer_port = peer.simobj.getPort(peer.name, peer.index)
1983 port.bind(peer_port)
1984
1985 self.ccConnected = True
1986
1987 # A reference to an individual element of a VectorPort... much like a
1988 # PortRef, but has an index.
1989 class VectorPortElementRef(PortRef):
1990 def __init__(self, simobj, name, role, is_source, index):
1991 PortRef.__init__(self, simobj, name, role, is_source)
1992 self.index = index
1993
1994 def __str__(self):
1995 return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1996
1997 # A reference to a complete vector-valued port (not just a single element).
1998 # Can be indexed to retrieve individual VectorPortElementRef instances.
1999 class VectorPortRef(object):
2000 def __init__(self, simobj, name, role, is_source):
2001 assert(isSimObject(simobj) or isSimObjectClass(simobj))
2002 self.simobj = simobj
2003 self.name = name
2004 self.role = role
2005 self.is_source = is_source
2006 self.elements = []
2007
2008 def __str__(self):
2009 return '%s.%s[:]' % (self.simobj, self.name)
2010
2011 def __len__(self):
2012 # Return the number of connected peers, corresponding the the
2013 # length of the elements.
2014 return len(self.elements)
2015
2016 # for config.ini, print peer's name (not ours)
2017 def ini_str(self):
2018 return ' '.join([el.ini_str() for el in self.elements])
2019
2020 # for config.json
2021 def get_config_as_dict(self):
2022 return {'role' : self.role,
2023 'peer' : [el.ini_str() for el in self.elements],
2024 'is_source' : str(self.is_source)}
2025
2026 def __getitem__(self, key):
2027 if not isinstance(key, int):
2028 raise TypeError("VectorPort index must be integer")
2029 if key >= len(self.elements):
2030 # need to extend list
2031 ext = [VectorPortElementRef(
2032 self.simobj, self.name, self.role, self.is_source, i)
2033 for i in range(len(self.elements), key+1)]
2034 self.elements.extend(ext)
2035 return self.elements[key]
2036
2037 def _get_next(self):
2038 return self[len(self.elements)]
2039
2040 def __setitem__(self, key, value):
2041 if not isinstance(key, int):
2042 raise TypeError("VectorPort index must be integer")
2043 self[key].connect(value)
2044
2045 def connect(self, other):
2046 if isinstance(other, (list, tuple)):
2047 # Assign list of port refs to vector port.
2048 # For now, append them... not sure if that's the right semantics
2049 # or if it should replace the current vector.
2050 for ref in other:
2051 self._get_next().connect(ref)
2052 else:
2053 # scalar assignment to plain VectorPort is implicit append
2054 self._get_next().connect(other)
2055
2056 def clone(self, simobj, memo):
2057 if self in memo:
2058 return memo[self]
2059 newRef = copy.copy(self)
2060 memo[self] = newRef
2061 newRef.simobj = simobj
2062 assert(isSimObject(newRef.simobj))
2063 newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2064 return newRef
2065
2066 def unproxy(self, simobj):
2067 [el.unproxy(simobj) for el in self.elements]
2068
2069 def ccConnect(self):
2070 [el.ccConnect() for el in self.elements]
2071
2072 # Port description object. Like a ParamDesc object, this represents a
2073 # logical port in the SimObject class, not a particular port on a
2074 # SimObject instance. The latter are represented by PortRef objects.
2075 class Port(object):
2076 # Port("role", "description")
2077
2078 _compat_dict = { }
2079
2080 @classmethod
2081 def compat(cls, role, peer):
2082 cls._compat_dict.setdefault(role, set()).add(peer)
2083 cls._compat_dict.setdefault(peer, set()).add(role)
2084
2085 @classmethod
2086 def is_compat(cls, one, two):
2087 for port in one, two:
2088 if not port.role in Port._compat_dict:
2089 fatal("Unrecognized role '%s' for port %s\n", port.role, port)
2090 return one.role in Port._compat_dict[two.role]
2091
2092 def __init__(self, role, desc, is_source=False):
2093 self.desc = desc
2094 self.role = role
2095 self.is_source = is_source
2096
2097 # Generate a PortRef for this port on the given SimObject with the
2098 # given name
2099 def makeRef(self, simobj):
2100 return PortRef(simobj, self.name, self.role, self.is_source)
2101
2102 # Connect an instance of this port (on the given SimObject with
2103 # the given name) with the port described by the supplied PortRef
2104 def connect(self, simobj, ref):
2105 self.makeRef(simobj).connect(ref)
2106
2107 # No need for any pre-declarations at the moment as we merely rely
2108 # on an unsigned int.
2109 def cxx_predecls(self, code):
2110 pass
2111
2112 def pybind_predecls(self, code):
2113 cls.cxx_predecls(self, code)
2114
2115 # Declare an unsigned int with the same name as the port, that
2116 # will eventually hold the number of connected ports (and thus the
2117 # number of elements for a VectorPort).
2118 def cxx_decl(self, code):
2119 code('unsigned int port_${{self.name}}_connection_count;')
2120
2121 Port.compat('GEM5 REQUESTER', 'GEM5 RESPONDER')
2122
2123 class RequestPort(Port):
2124 # RequestPort("description")
2125 def __init__(self, desc):
2126 super(RequestPort, self).__init__(
2127 'GEM5 REQUESTER', desc, is_source=True)
2128
2129 class ResponsePort(Port):
2130 # ResponsePort("description")
2131 def __init__(self, desc):
2132 super(ResponsePort, self).__init__('GEM5 RESPONDER', desc)
2133
2134 # VectorPort description object. Like Port, but represents a vector
2135 # of connections (e.g., as on a XBar).
2136 class VectorPort(Port):
2137 def makeRef(self, simobj):
2138 return VectorPortRef(simobj, self.name, self.role, self.is_source)
2139
2140 class VectorRequestPort(VectorPort):
2141 # VectorRequestPort("description")
2142 def __init__(self, desc):
2143 super(VectorRequestPort, self).__init__(
2144 'GEM5 REQUESTER', desc, is_source=True)
2145
2146 class VectorResponsePort(VectorPort):
2147 # VectorResponsePort("description")
2148 def __init__(self, desc):
2149 super(VectorResponsePort, self).__init__('GEM5 RESPONDER', desc)
2150
2151 # Old names, maintained for compatibility.
2152 MasterPort = RequestPort
2153 SlavePort = ResponsePort
2154 VectorMasterPort = VectorRequestPort
2155 VectorSlavePort = VectorResponsePort
2156
2157 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2158 # proxy objects (via set_param_desc()) so that proxy error messages
2159 # make sense.
2160 @add_metaclass(Singleton)
2161 class PortParamDesc(object):
2162 ptype_str = 'Port'
2163 ptype = Port
2164
2165 baseEnums = allEnums.copy()
2166 baseParams = allParams.copy()
2167
2168 def clear():
2169 global allEnums, allParams
2170
2171 allEnums = baseEnums.copy()
2172 allParams = baseParams.copy()
2173
2174 __all__ = ['Param', 'VectorParam',
2175 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2176 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2177 'Int32', 'UInt32', 'Int64', 'UInt64',
2178 'Counter', 'Addr', 'Tick', 'Percent',
2179 'TcpPort', 'UdpPort', 'EthernetAddr',
2180 'IpAddress', 'IpNetmask', 'IpWithPort',
2181 'MemorySize', 'MemorySize32',
2182 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2183 'NetworkBandwidth', 'MemoryBandwidth',
2184 'AddrRange',
2185 'MaxAddr', 'MaxTick', 'AllMemory',
2186 'Time',
2187 'NextEthernetAddr', 'NULL',
2188 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2189 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2190 'VectorMasterPort', 'VectorSlavePort']