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