sparc,sim: Remove special handling of SPARC in the clone system call.
[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 with_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 class ParamValue(with_metaclass(MetaParamValue, object)):
101 cmd_line_settable = False
102
103 # Generate the code needed as a prerequisite for declaring a C++
104 # object of this type. Typically generates one or more #include
105 # statements. Used when declaring parameters of this type.
106 @classmethod
107 def cxx_predecls(cls, code):
108 pass
109
110 @classmethod
111 def pybind_predecls(cls, code):
112 cls.cxx_predecls(code)
113
114 # default for printing to .ini file is regular string conversion.
115 # will be overridden in some cases
116 def ini_str(self):
117 return str(self)
118
119 # default for printing to .json file is regular string conversion.
120 # will be overridden in some cases, mostly to use native Python
121 # types where there are similar JSON types
122 def config_value(self):
123 return str(self)
124
125 # Prerequisites for .ini parsing with cxx_ini_parse
126 @classmethod
127 def cxx_ini_predecls(cls, code):
128 pass
129
130 # parse a .ini file entry for this param from string expression
131 # src into lvalue dest (of the param's C++ type)
132 @classmethod
133 def cxx_ini_parse(cls, code, src, dest, ret):
134 code('// Unhandled param type: %s' % cls.__name__)
135 code('%s false;' % ret)
136
137 # allows us to blithely call unproxy() on things without checking
138 # if they're really proxies or not
139 def unproxy(self, base):
140 return self
141
142 # Produce a human readable version of the stored value
143 def pretty_print(self, value):
144 return str(value)
145
146 # Regular parameter description.
147 class ParamDesc(object):
148 def __init__(self, ptype_str, ptype, *args, **kwargs):
149 self.ptype_str = ptype_str
150 # remember ptype only if it is provided
151 if ptype != None:
152 self.ptype = ptype
153
154 if args:
155 if len(args) == 1:
156 self.desc = args[0]
157 elif len(args) == 2:
158 self.default = args[0]
159 self.desc = args[1]
160 else:
161 raise TypeError('too many arguments')
162
163 if 'desc' in kwargs:
164 assert(not hasattr(self, 'desc'))
165 self.desc = kwargs['desc']
166 del kwargs['desc']
167
168 if 'default' in kwargs:
169 assert(not hasattr(self, 'default'))
170 self.default = kwargs['default']
171 del kwargs['default']
172
173 if kwargs:
174 raise TypeError('extra unknown kwargs %s' % kwargs)
175
176 if not hasattr(self, 'desc'):
177 raise TypeError('desc attribute missing')
178
179 def __getattr__(self, attr):
180 if attr == 'ptype':
181 from . import SimObject
182 ptype = SimObject.allClasses[self.ptype_str]
183 assert isSimObjectClass(ptype)
184 self.ptype = ptype
185 return ptype
186
187 raise AttributeError("'%s' object has no attribute '%s'" % \
188 (type(self).__name__, attr))
189
190 def example_str(self):
191 if hasattr(self.ptype, "ex_str"):
192 return self.ptype.ex_str
193 else:
194 return self.ptype_str
195
196 # Is the param available to be exposed on the command line
197 def isCmdLineSettable(self):
198 if hasattr(self.ptype, "cmd_line_settable"):
199 return self.ptype.cmd_line_settable
200 else:
201 return False
202
203 def convert(self, value):
204 if isinstance(value, proxy.BaseProxy):
205 value.set_param_desc(self)
206 return value
207 if 'ptype' not in self.__dict__ and isNullPointer(value):
208 # deferred evaluation of SimObject; continue to defer if
209 # we're just assigning a null pointer
210 return value
211 if isinstance(value, self.ptype):
212 return value
213 if isNullPointer(value) and isSimObjectClass(self.ptype):
214 return value
215 return self.ptype(value)
216
217 def pretty_print(self, value):
218 if isinstance(value, proxy.BaseProxy):
219 return str(value)
220 if isNullPointer(value):
221 return NULL
222 return self.ptype(value).pretty_print(value)
223
224 def cxx_predecls(self, code):
225 code('#include <cstddef>')
226 self.ptype.cxx_predecls(code)
227
228 def pybind_predecls(self, code):
229 self.ptype.pybind_predecls(code)
230
231 def cxx_decl(self, code):
232 code('${{self.ptype.cxx_type}} ${{self.name}};')
233
234 # Vector-valued parameter description. Just like ParamDesc, except
235 # that the value is a vector (list) of the specified type instead of a
236 # single value.
237
238 class VectorParamValue(with_metaclass(MetaParamValue, list)):
239 def __setattr__(self, attr, value):
240 raise AttributeError("Not allowed to set %s on '%s'" % \
241 (attr, type(self).__name__))
242
243 def config_value(self):
244 return [v.config_value() for v in self]
245
246 def ini_str(self):
247 return ' '.join([v.ini_str() for v in self])
248
249 def getValue(self):
250 return [ v.getValue() for v in self ]
251
252 def unproxy(self, base):
253 if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
254 # The value is a proxy (e.g. Parent.any, Parent.all or
255 # Parent.x) therefore try resolve it
256 return self[0].unproxy(base)
257 else:
258 return [v.unproxy(base) for v in self]
259
260 class SimObjectVector(VectorParamValue):
261 # support clone operation
262 def __call__(self, **kwargs):
263 return SimObjectVector([v(**kwargs) for v in self])
264
265 def clear_parent(self, old_parent):
266 for v in self:
267 v.clear_parent(old_parent)
268
269 def set_parent(self, parent, name):
270 if len(self) == 1:
271 self[0].set_parent(parent, name)
272 else:
273 width = int(math.ceil(math.log(len(self))/math.log(10)))
274 for i,v in enumerate(self):
275 v.set_parent(parent, "%s%0*d" % (name, width, i))
276
277 def has_parent(self):
278 return any([e.has_parent() for e in self if not isNullPointer(e)])
279
280 # return 'cpu0 cpu1' etc. for print_ini()
281 def get_name(self):
282 return ' '.join([v._name for v in self])
283
284 # By iterating through the constituent members of the vector here
285 # we can nicely handle iterating over all a SimObject's children
286 # without having to provide lots of special functions on
287 # SimObjectVector directly.
288 def descendants(self):
289 for v in self:
290 for obj in v.descendants():
291 yield obj
292
293 def get_config_as_dict(self):
294 a = []
295 for v in self:
296 a.append(v.get_config_as_dict())
297 return a
298
299 # If we are replacing an item in the vector, make sure to set the
300 # parent reference of the new SimObject to be the same as the parent
301 # of the SimObject being replaced. Useful to have if we created
302 # a SimObjectVector of temporary objects that will be modified later in
303 # configuration scripts.
304 def __setitem__(self, key, value):
305 val = self[key]
306 if value.has_parent():
307 warn("SimObject %s already has a parent" % value.get_name() +\
308 " that is being overwritten by a SimObjectVector")
309 value.set_parent(val.get_parent(), val._name)
310 super(SimObjectVector, self).__setitem__(key, value)
311
312 # Enumerate the params of each member of the SimObject vector. Creates
313 # strings that will allow indexing into the vector by the python code and
314 # allow it to be specified on the command line.
315 def enumerateParams(self, flags_dict = {},
316 cmd_line_str = "",
317 access_str = ""):
318 if hasattr(self, "_paramEnumed"):
319 print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
320 else:
321 x = 0
322 for vals in self:
323 # Each entry in the SimObjectVector should be an
324 # instance of a SimObject
325 flags_dict = vals.enumerateParams(flags_dict,
326 cmd_line_str + "%d." % x,
327 access_str + "[%d]." % x)
328 x = x + 1
329
330 return flags_dict
331
332 class VectorParamDesc(ParamDesc):
333 # Convert assigned value to appropriate type. If the RHS is not a
334 # list or tuple, it generates a single-element list.
335 def convert(self, value):
336 if isinstance(value, (list, tuple)):
337 # list: coerce each element into new list
338 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
339 elif isinstance(value, str):
340 # If input is a csv string
341 tmp_list = [ ParamDesc.convert(self, v) \
342 for v in value.strip('[').strip(']').split(',') ]
343 else:
344 # singleton: coerce to a single-element list
345 tmp_list = [ ParamDesc.convert(self, value) ]
346
347 if isSimObjectSequence(tmp_list):
348 return SimObjectVector(tmp_list)
349 else:
350 return VectorParamValue(tmp_list)
351
352 # Produce a human readable example string that describes
353 # how to set this vector parameter in the absence of a default
354 # value.
355 def example_str(self):
356 s = super(VectorParamDesc, self).example_str()
357 help_str = "[" + s + "," + s + ", ...]"
358 return help_str
359
360 # Produce a human readable representation of the value of this vector param.
361 def pretty_print(self, value):
362 if isinstance(value, (list, tuple)):
363 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
364 elif isinstance(value, str):
365 tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
366 else:
367 tmp_list = [ ParamDesc.pretty_print(self, value) ]
368
369 return tmp_list
370
371 # This is a helper function for the new config system
372 def __call__(self, value):
373 if isinstance(value, (list, tuple)):
374 # list: coerce each element into new list
375 tmp_list = [ ParamDesc.convert(self, v) for v in value ]
376 elif isinstance(value, str):
377 # If input is a csv string
378 tmp_list = [ ParamDesc.convert(self, v) \
379 for v in value.strip('[').strip(']').split(',') ]
380 else:
381 # singleton: coerce to a single-element list
382 tmp_list = [ ParamDesc.convert(self, value) ]
383
384 return VectorParamValue(tmp_list)
385
386 def cxx_predecls(self, code):
387 code('#include <vector>')
388 self.ptype.cxx_predecls(code)
389
390 def pybind_predecls(self, code):
391 code('#include <vector>')
392 self.ptype.pybind_predecls(code)
393
394 def cxx_decl(self, code):
395 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
396
397 class ParamFactory(object):
398 def __init__(self, param_desc_class, ptype_str = None):
399 self.param_desc_class = param_desc_class
400 self.ptype_str = ptype_str
401
402 def __getattr__(self, attr):
403 if self.ptype_str:
404 attr = self.ptype_str + '.' + attr
405 return ParamFactory(self.param_desc_class, attr)
406
407 # E.g., Param.Int(5, "number of widgets")
408 def __call__(self, *args, **kwargs):
409 ptype = None
410 try:
411 ptype = allParams[self.ptype_str]
412 except KeyError:
413 # if name isn't defined yet, assume it's a SimObject, and
414 # try to resolve it later
415 pass
416 return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
417
418 Param = ParamFactory(ParamDesc)
419 VectorParam = ParamFactory(VectorParamDesc)
420
421 #####################################################################
422 #
423 # Parameter Types
424 #
425 # Though native Python types could be used to specify parameter types
426 # (the 'ptype' field of the Param and VectorParam classes), it's more
427 # flexible to define our own set of types. This gives us more control
428 # over how Python expressions are converted to values (via the
429 # __init__() constructor) and how these values are printed out (via
430 # the __str__() conversion method).
431 #
432 #####################################################################
433
434 # String-valued parameter. Just mixin the ParamValue class with the
435 # built-in str class.
436 class String(ParamValue,str):
437 cxx_type = 'std::string'
438 cmd_line_settable = True
439
440 @classmethod
441 def cxx_predecls(self, code):
442 code('#include <string>')
443
444 def __call__(self, value):
445 self = value
446 return value
447
448 @classmethod
449 def cxx_ini_parse(self, code, src, dest, ret):
450 code('%s = %s;' % (dest, src))
451 code('%s true;' % ret)
452
453 def getValue(self):
454 return self
455
456 # superclass for "numeric" parameter values, to emulate math
457 # operations in a type-safe way. e.g., a Latency times an int returns
458 # a new Latency object.
459 class NumericParamValue(ParamValue):
460 @staticmethod
461 def unwrap(v):
462 return v.value if isinstance(v, NumericParamValue) else v
463
464 def __str__(self):
465 return str(self.value)
466
467 def __float__(self):
468 return float(self.value)
469
470 def __long__(self):
471 return long(self.value)
472
473 def __int__(self):
474 return int(self.value)
475
476 # hook for bounds checking
477 def _check(self):
478 return
479
480 def __mul__(self, other):
481 newobj = self.__class__(self)
482 newobj.value *= NumericParamValue.unwrap(other)
483 newobj._check()
484 return newobj
485
486 __rmul__ = __mul__
487
488 def __truediv__(self, other):
489 newobj = self.__class__(self)
490 newobj.value /= NumericParamValue.unwrap(other)
491 newobj._check()
492 return newobj
493
494 def __floordiv__(self, other):
495 newobj = self.__class__(self)
496 newobj.value //= NumericParamValue.unwrap(other)
497 newobj._check()
498 return newobj
499
500
501 def __add__(self, other):
502 newobj = self.__class__(self)
503 newobj.value += NumericParamValue.unwrap(other)
504 newobj._check()
505 return newobj
506
507 def __sub__(self, other):
508 newobj = self.__class__(self)
509 newobj.value -= NumericParamValue.unwrap(other)
510 newobj._check()
511 return newobj
512
513 def __iadd__(self, other):
514 self.value += NumericParamValue.unwrap(other)
515 self._check()
516 return self
517
518 def __isub__(self, other):
519 self.value -= NumericParamValue.unwrap(other)
520 self._check()
521 return self
522
523 def __imul__(self, other):
524 self.value *= NumericParamValue.unwrap(other)
525 self._check()
526 return self
527
528 def __itruediv__(self, other):
529 self.value /= NumericParamValue.unwrap(other)
530 self._check()
531 return self
532
533 def __ifloordiv__(self, other):
534 self.value //= NumericParamValue.unwrap(other)
535 self._check()
536 return self
537
538 def __lt__(self, other):
539 return self.value < NumericParamValue.unwrap(other)
540
541 # Python 2.7 pre __future__.division operators
542 # TODO: Remove these when after "import division from __future__"
543 __div__ = __truediv__
544 __idiv__ = __itruediv__
545
546 def config_value(self):
547 return self.value
548
549 @classmethod
550 def cxx_ini_predecls(cls, code):
551 # Assume that base/str.hh will be included anyway
552 # code('#include "base/str.hh"')
553 pass
554
555 # The default for parsing PODs from an .ini entry is to extract from an
556 # istringstream and let overloading choose the right type according to
557 # the dest type.
558 @classmethod
559 def cxx_ini_parse(self, code, src, dest, ret):
560 code('%s to_number(%s, %s);' % (ret, src, dest))
561
562 # Metaclass for bounds-checked integer parameters. See CheckedInt.
563 class CheckedIntType(MetaParamValue):
564 def __init__(cls, name, bases, dict):
565 super(CheckedIntType, cls).__init__(name, bases, dict)
566
567 # CheckedInt is an abstract base class, so we actually don't
568 # want to do any processing on it... the rest of this code is
569 # just for classes that derive from CheckedInt.
570 if name == 'CheckedInt':
571 return
572
573 if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
574 if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
575 panic("CheckedInt subclass %s must define either\n" \
576 " 'min' and 'max' or 'size' and 'unsigned'\n",
577 name);
578 if cls.unsigned:
579 cls.min = 0
580 cls.max = 2 ** cls.size - 1
581 else:
582 cls.min = -(2 ** (cls.size - 1))
583 cls.max = (2 ** (cls.size - 1)) - 1
584
585 # Abstract superclass for bounds-checked integer parameters. This
586 # class is subclassed to generate parameter classes with specific
587 # bounds. Initialization of the min and max bounds is done in the
588 # metaclass CheckedIntType.__init__.
589 class CheckedInt(with_metaclass(CheckedIntType, NumericParamValue)):
590 cmd_line_settable = True
591
592 def _check(self):
593 if not self.min <= self.value <= self.max:
594 raise TypeError('Integer param out of bounds %d < %d < %d' % \
595 (self.min, self.value, self.max))
596
597 def __init__(self, value):
598 if isinstance(value, str):
599 self.value = convert.toInteger(value)
600 elif isinstance(value, (int, long, float, NumericParamValue)):
601 self.value = long(value)
602 else:
603 raise TypeError("Can't convert object of type %s to CheckedInt" \
604 % type(value).__name__)
605 self._check()
606
607 def __call__(self, value):
608 self.__init__(value)
609 return value
610
611 def __index__(self):
612 return int(self.value)
613
614 @classmethod
615 def cxx_predecls(cls, code):
616 # most derived types require this, so we just do it here once
617 code('#include "base/types.hh"')
618
619 def getValue(self):
620 return long(self.value)
621
622 class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False
623 class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
624
625 class Int8(CheckedInt): cxx_type = 'int8_t'; size = 8; unsigned = False
626 class UInt8(CheckedInt): cxx_type = 'uint8_t'; size = 8; unsigned = True
627 class Int16(CheckedInt): cxx_type = 'int16_t'; size = 16; unsigned = False
628 class UInt16(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
629 class Int32(CheckedInt): cxx_type = 'int32_t'; size = 32; unsigned = False
630 class UInt32(CheckedInt): cxx_type = 'uint32_t'; size = 32; unsigned = True
631 class Int64(CheckedInt): cxx_type = 'int64_t'; size = 64; unsigned = False
632 class UInt64(CheckedInt): cxx_type = 'uint64_t'; size = 64; unsigned = True
633
634 class Counter(CheckedInt): cxx_type = 'Counter'; size = 64; unsigned = True
635 class Tick(CheckedInt): cxx_type = 'Tick'; size = 64; unsigned = True
636 class TcpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
637 class UdpPort(CheckedInt): cxx_type = 'uint16_t'; size = 16; unsigned = True
638
639 class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
640
641 class Cycles(CheckedInt):
642 cxx_type = 'Cycles'
643 size = 64
644 unsigned = True
645
646 def getValue(self):
647 from _m5.core import Cycles
648 return Cycles(self.value)
649
650 @classmethod
651 def cxx_ini_predecls(cls, code):
652 # Assume that base/str.hh will be included anyway
653 # code('#include "base/str.hh"')
654 pass
655
656 @classmethod
657 def cxx_ini_parse(cls, code, src, dest, ret):
658 code('uint64_t _temp;')
659 code('bool _ret = to_number(%s, _temp);' % src)
660 code('if (_ret)')
661 code(' %s = Cycles(_temp);' % dest)
662 code('%s _ret;' % ret)
663
664 class Float(ParamValue, float):
665 cxx_type = 'double'
666 cmd_line_settable = True
667
668 def __init__(self, value):
669 if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
670 self.value = float(value)
671 else:
672 raise TypeError("Can't convert object of type %s to Float" \
673 % type(value).__name__)
674
675 def __call__(self, value):
676 self.__init__(value)
677 return value
678
679 def getValue(self):
680 return float(self.value)
681
682 def config_value(self):
683 return self
684
685 @classmethod
686 def cxx_ini_predecls(cls, code):
687 code('#include <sstream>')
688
689 @classmethod
690 def cxx_ini_parse(self, code, src, dest, ret):
691 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
692
693 class MemorySize(CheckedInt):
694 cxx_type = 'uint64_t'
695 ex_str = '512MB'
696 size = 64
697 unsigned = True
698 def __init__(self, value):
699 if isinstance(value, MemorySize):
700 self.value = value.value
701 else:
702 self.value = convert.toMemorySize(value)
703 self._check()
704
705 class MemorySize32(CheckedInt):
706 cxx_type = 'uint32_t'
707 ex_str = '512MB'
708 size = 32
709 unsigned = True
710 def __init__(self, value):
711 if isinstance(value, MemorySize):
712 self.value = value.value
713 else:
714 self.value = convert.toMemorySize(value)
715 self._check()
716
717 class Addr(CheckedInt):
718 cxx_type = 'Addr'
719 size = 64
720 unsigned = True
721 def __init__(self, value):
722 if isinstance(value, Addr):
723 self.value = value.value
724 else:
725 try:
726 # Often addresses are referred to with sizes. Ex: A device
727 # base address is at "512MB". Use toMemorySize() to convert
728 # these into addresses. If the address is not specified with a
729 # "size", an exception will occur and numeric translation will
730 # proceed below.
731 self.value = convert.toMemorySize(value)
732 except (TypeError, ValueError):
733 # Convert number to string and use long() to do automatic
734 # base conversion (requires base=0 for auto-conversion)
735 self.value = long(str(value), base=0)
736
737 self._check()
738 def __add__(self, other):
739 if isinstance(other, Addr):
740 return self.value + other.value
741 else:
742 return self.value + other
743 def pretty_print(self, value):
744 try:
745 val = convert.toMemorySize(value)
746 except TypeError:
747 val = long(value)
748 return "0x%x" % long(val)
749
750 class AddrRange(ParamValue):
751 cxx_type = 'AddrRange'
752
753 def __init__(self, *args, **kwargs):
754 # Disable interleaving and hashing by default
755 self.intlvBits = 0
756 self.intlvMatch = 0
757 self.masks = []
758
759 def handle_kwargs(self, kwargs):
760 # An address range needs to have an upper limit, specified
761 # either explicitly with an end, or as an offset using the
762 # size keyword.
763 if 'end' in kwargs:
764 self.end = Addr(kwargs.pop('end'))
765 elif 'size' in kwargs:
766 self.end = self.start + Addr(kwargs.pop('size'))
767 else:
768 raise TypeError("Either end or size must be specified")
769
770 # Now on to the optional bit
771 if 'intlvMatch' in kwargs:
772 self.intlvMatch = int(kwargs.pop('intlvMatch'))
773
774 if 'masks' in kwargs:
775 self.masks = [ long(x) for x in list(kwargs.pop('masks')) ]
776 self.intlvBits = len(self.masks)
777 else:
778 if 'intlvBits' in kwargs:
779 self.intlvBits = int(kwargs.pop('intlvBits'))
780 self.masks = [0] * self.intlvBits
781 if 'intlvHighBit' not in kwargs:
782 raise TypeError("No interleave bits specified")
783 intlv_high_bit = int(kwargs.pop('intlvHighBit'))
784 xor_high_bit = 0
785 if 'xorHighBit' in kwargs:
786 xor_high_bit = int(kwargs.pop('xorHighBit'))
787 for i in range(0, self.intlvBits):
788 bit1 = intlv_high_bit - i
789 mask = 1 << bit1
790 if xor_high_bit != 0:
791 bit2 = xor_high_bit - i
792 mask |= 1 << bit2
793 self.masks[self.intlvBits - i - 1] = mask
794
795 if len(args) == 0:
796 self.start = Addr(kwargs.pop('start'))
797 handle_kwargs(self, kwargs)
798
799 elif len(args) == 1:
800 if kwargs:
801 self.start = Addr(args[0])
802 handle_kwargs(self, kwargs)
803 elif isinstance(args[0], (list, tuple)):
804 self.start = Addr(args[0][0])
805 self.end = Addr(args[0][1])
806 else:
807 self.start = Addr(0)
808 self.end = Addr(args[0])
809
810 elif len(args) == 2:
811 self.start = Addr(args[0])
812 self.end = Addr(args[1])
813 else:
814 raise TypeError("Too many arguments specified")
815
816 if kwargs:
817 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
818
819 def __str__(self):
820 if len(self.masks) == 0:
821 return '%s:%s' % (self.start, self.end)
822 else:
823 return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch,
824 ':'.join(str(m) for m in self.masks))
825
826 def size(self):
827 # Divide the size by the size of the interleaving slice
828 return (long(self.end) - long(self.start)) >> self.intlvBits
829
830 @classmethod
831 def cxx_predecls(cls, code):
832 Addr.cxx_predecls(code)
833 code('#include "base/addr_range.hh"')
834
835 @classmethod
836 def pybind_predecls(cls, code):
837 Addr.pybind_predecls(code)
838 code('#include "base/addr_range.hh"')
839
840 @classmethod
841 def cxx_ini_predecls(cls, code):
842 code('#include <sstream>')
843 code('#include <vector>')
844 code('#include "base/types.hh"')
845
846 @classmethod
847 def cxx_ini_parse(cls, code, src, dest, ret):
848 code('bool _ret = true;')
849 code('uint64_t _start, _end, _intlvMatch = 0;')
850 code('std::vector<Addr> _masks;')
851 code('char _sep;')
852 code('std::istringstream _stream(${src});')
853 code('_stream >> _start;')
854 code('_stream.get(_sep);')
855 code('_ret = _sep == \':\';')
856 code('_stream >> _end;')
857 code('if (!_stream.fail() && !_stream.eof()) {')
858 code(' _stream.get(_sep);')
859 code(' _ret = ret && _sep == \':\';')
860 code(' _stream >> _intlvMatch;')
861 code(' while (!_stream.fail() && !_stream.eof()) {')
862 code(' _stream.get(_sep);')
863 code(' _ret = ret && _sep == \':\';')
864 code(' Addr mask;')
865 code(' _stream >> mask;')
866 code(' _masks.push_back(mask);')
867 code(' }')
868 code('}')
869 code('_ret = _ret && !_stream.fail() && _stream.eof();')
870 code('if (_ret)')
871 code(' ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
872 code('${ret} _ret;')
873
874 def getValue(self):
875 # Go from the Python class to the wrapped C++ class
876 from _m5.range import AddrRange
877
878 return AddrRange(long(self.start), long(self.end),
879 self.masks, int(self.intlvMatch))
880
881 # Boolean parameter type. Python doesn't let you subclass bool, since
882 # it doesn't want to let you create multiple instances of True and
883 # False. Thus this is a little more complicated than String.
884 class Bool(ParamValue):
885 cxx_type = 'bool'
886 cmd_line_settable = True
887
888 def __init__(self, value):
889 try:
890 self.value = convert.toBool(value)
891 except TypeError:
892 self.value = bool(value)
893
894 def __call__(self, value):
895 self.__init__(value)
896 return value
897
898 def getValue(self):
899 return bool(self.value)
900
901 def __str__(self):
902 return str(self.value)
903
904 # implement truth value testing for Bool parameters so that these params
905 # evaluate correctly during the python configuration phase
906 def __bool__(self):
907 return bool(self.value)
908
909 # Python 2.7 uses __nonzero__ instead of __bool__
910 __nonzero__ = __bool__
911
912 def ini_str(self):
913 if self.value:
914 return 'true'
915 return 'false'
916
917 def config_value(self):
918 return self.value
919
920 @classmethod
921 def cxx_ini_predecls(cls, code):
922 # Assume that base/str.hh will be included anyway
923 # code('#include "base/str.hh"')
924 pass
925
926 @classmethod
927 def cxx_ini_parse(cls, code, src, dest, ret):
928 code('%s to_bool(%s, %s);' % (ret, src, dest))
929
930 def IncEthernetAddr(addr, val = 1):
931 bytes = [ int(x, 16) for x in addr.split(':') ]
932 bytes[5] += val
933 for i in (5, 4, 3, 2, 1):
934 val,rem = divmod(bytes[i], 256)
935 bytes[i] = rem
936 if val == 0:
937 break
938 bytes[i - 1] += val
939 assert(bytes[0] <= 255)
940 return ':'.join(map(lambda x: '%02x' % x, bytes))
941
942 _NextEthernetAddr = "00:90:00:00:00:01"
943 def NextEthernetAddr():
944 global _NextEthernetAddr
945
946 value = _NextEthernetAddr
947 _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
948 return value
949
950 class EthernetAddr(ParamValue):
951 cxx_type = 'Net::EthAddr'
952 ex_str = "00:90:00:00:00:01"
953 cmd_line_settable = True
954
955 @classmethod
956 def cxx_predecls(cls, code):
957 code('#include "base/inet.hh"')
958
959 def __init__(self, value):
960 if value == NextEthernetAddr:
961 self.value = value
962 return
963
964 if not isinstance(value, str):
965 raise TypeError("expected an ethernet address and didn't get one")
966
967 bytes = value.split(':')
968 if len(bytes) != 6:
969 raise TypeError('invalid ethernet address %s' % value)
970
971 for byte in bytes:
972 if not 0 <= int(byte, base=16) <= 0xff:
973 raise TypeError('invalid ethernet address %s' % value)
974
975 self.value = value
976
977 def __call__(self, value):
978 self.__init__(value)
979 return value
980
981 def unproxy(self, base):
982 if self.value == NextEthernetAddr:
983 return EthernetAddr(self.value())
984 return self
985
986 def getValue(self):
987 from _m5.net import EthAddr
988 return EthAddr(self.value)
989
990 def __str__(self):
991 return self.value
992
993 def ini_str(self):
994 return self.value
995
996 @classmethod
997 def cxx_ini_parse(self, code, src, dest, ret):
998 code('%s = Net::EthAddr(%s);' % (dest, src))
999 code('%s true;' % ret)
1000
1001 # When initializing an IpAddress, pass in an existing IpAddress, a string of
1002 # the form "a.b.c.d", or an integer representing an IP.
1003 class IpAddress(ParamValue):
1004 cxx_type = 'Net::IpAddress'
1005 ex_str = "127.0.0.1"
1006 cmd_line_settable = True
1007
1008 @classmethod
1009 def cxx_predecls(cls, code):
1010 code('#include "base/inet.hh"')
1011
1012 def __init__(self, value):
1013 if isinstance(value, IpAddress):
1014 self.ip = value.ip
1015 else:
1016 try:
1017 self.ip = convert.toIpAddress(value)
1018 except TypeError:
1019 self.ip = long(value)
1020 self.verifyIp()
1021
1022 def __call__(self, value):
1023 self.__init__(value)
1024 return value
1025
1026 def __str__(self):
1027 tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
1028 return '%d.%d.%d.%d' % tuple(tup)
1029
1030 def __eq__(self, other):
1031 if isinstance(other, IpAddress):
1032 return self.ip == other.ip
1033 elif isinstance(other, str):
1034 try:
1035 return self.ip == convert.toIpAddress(other)
1036 except:
1037 return False
1038 else:
1039 return self.ip == other
1040
1041 def __ne__(self, other):
1042 return not (self == other)
1043
1044 def verifyIp(self):
1045 if self.ip < 0 or self.ip >= (1 << 32):
1046 raise TypeError("invalid ip address %#08x" % self.ip)
1047
1048 def getValue(self):
1049 from _m5.net import IpAddress
1050 return IpAddress(self.ip)
1051
1052 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
1053 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
1054 # positional or keyword arguments.
1055 class IpNetmask(IpAddress):
1056 cxx_type = 'Net::IpNetmask'
1057 ex_str = "127.0.0.0/24"
1058 cmd_line_settable = True
1059
1060 @classmethod
1061 def cxx_predecls(cls, code):
1062 code('#include "base/inet.hh"')
1063
1064 def __init__(self, *args, **kwargs):
1065 def handle_kwarg(self, kwargs, key, elseVal = None):
1066 if key in kwargs:
1067 setattr(self, key, kwargs.pop(key))
1068 elif elseVal:
1069 setattr(self, key, elseVal)
1070 else:
1071 raise TypeError("No value set for %s" % key)
1072
1073 if len(args) == 0:
1074 handle_kwarg(self, kwargs, 'ip')
1075 handle_kwarg(self, kwargs, 'netmask')
1076
1077 elif len(args) == 1:
1078 if kwargs:
1079 if not 'ip' in kwargs and not 'netmask' in kwargs:
1080 raise TypeError("Invalid arguments")
1081 handle_kwarg(self, kwargs, 'ip', args[0])
1082 handle_kwarg(self, kwargs, 'netmask', args[0])
1083 elif isinstance(args[0], IpNetmask):
1084 self.ip = args[0].ip
1085 self.netmask = args[0].netmask
1086 else:
1087 (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1088
1089 elif len(args) == 2:
1090 self.ip = args[0]
1091 self.netmask = args[1]
1092 else:
1093 raise TypeError("Too many arguments specified")
1094
1095 if kwargs:
1096 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1097
1098 self.verify()
1099
1100 def __call__(self, value):
1101 self.__init__(value)
1102 return value
1103
1104 def __str__(self):
1105 return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1106
1107 def __eq__(self, other):
1108 if isinstance(other, IpNetmask):
1109 return self.ip == other.ip and self.netmask == other.netmask
1110 elif isinstance(other, str):
1111 try:
1112 return (self.ip, self.netmask) == convert.toIpNetmask(other)
1113 except:
1114 return False
1115 else:
1116 return False
1117
1118 def verify(self):
1119 self.verifyIp()
1120 if self.netmask < 0 or self.netmask > 32:
1121 raise TypeError("invalid netmask %d" % netmask)
1122
1123 def getValue(self):
1124 from _m5.net import IpNetmask
1125 return IpNetmask(self.ip, self.netmask)
1126
1127 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1128 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1129 class IpWithPort(IpAddress):
1130 cxx_type = 'Net::IpWithPort'
1131 ex_str = "127.0.0.1:80"
1132 cmd_line_settable = True
1133
1134 @classmethod
1135 def cxx_predecls(cls, code):
1136 code('#include "base/inet.hh"')
1137
1138 def __init__(self, *args, **kwargs):
1139 def handle_kwarg(self, kwargs, key, elseVal = None):
1140 if key in kwargs:
1141 setattr(self, key, kwargs.pop(key))
1142 elif elseVal:
1143 setattr(self, key, elseVal)
1144 else:
1145 raise TypeError("No value set for %s" % key)
1146
1147 if len(args) == 0:
1148 handle_kwarg(self, kwargs, 'ip')
1149 handle_kwarg(self, kwargs, 'port')
1150
1151 elif len(args) == 1:
1152 if kwargs:
1153 if not 'ip' in kwargs and not 'port' in kwargs:
1154 raise TypeError("Invalid arguments")
1155 handle_kwarg(self, kwargs, 'ip', args[0])
1156 handle_kwarg(self, kwargs, 'port', args[0])
1157 elif isinstance(args[0], IpWithPort):
1158 self.ip = args[0].ip
1159 self.port = args[0].port
1160 else:
1161 (self.ip, self.port) = convert.toIpWithPort(args[0])
1162
1163 elif len(args) == 2:
1164 self.ip = args[0]
1165 self.port = args[1]
1166 else:
1167 raise TypeError("Too many arguments specified")
1168
1169 if kwargs:
1170 raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1171
1172 self.verify()
1173
1174 def __call__(self, value):
1175 self.__init__(value)
1176 return value
1177
1178 def __str__(self):
1179 return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1180
1181 def __eq__(self, other):
1182 if isinstance(other, IpWithPort):
1183 return self.ip == other.ip and self.port == other.port
1184 elif isinstance(other, str):
1185 try:
1186 return (self.ip, self.port) == convert.toIpWithPort(other)
1187 except:
1188 return False
1189 else:
1190 return False
1191
1192 def verify(self):
1193 self.verifyIp()
1194 if self.port < 0 or self.port > 0xffff:
1195 raise TypeError("invalid port %d" % self.port)
1196
1197 def getValue(self):
1198 from _m5.net import IpWithPort
1199 return IpWithPort(self.ip, self.port)
1200
1201 time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1202 "%a %b %d %H:%M:%S %Y",
1203 "%Y/%m/%d %H:%M:%S",
1204 "%Y/%m/%d %H:%M",
1205 "%Y/%m/%d",
1206 "%m/%d/%Y %H:%M:%S",
1207 "%m/%d/%Y %H:%M",
1208 "%m/%d/%Y",
1209 "%m/%d/%y %H:%M:%S",
1210 "%m/%d/%y %H:%M",
1211 "%m/%d/%y"]
1212
1213
1214 def parse_time(value):
1215 from time import gmtime, strptime, struct_time, time
1216 from datetime import datetime, date
1217
1218 if isinstance(value, struct_time):
1219 return value
1220
1221 if isinstance(value, (int, long)):
1222 return gmtime(value)
1223
1224 if isinstance(value, (datetime, date)):
1225 return value.timetuple()
1226
1227 if isinstance(value, str):
1228 if value in ('Now', 'Today'):
1229 return time.gmtime(time.time())
1230
1231 for format in time_formats:
1232 try:
1233 return strptime(value, format)
1234 except ValueError:
1235 pass
1236
1237 raise ValueError("Could not parse '%s' as a time" % value)
1238
1239 class Time(ParamValue):
1240 cxx_type = 'tm'
1241
1242 @classmethod
1243 def cxx_predecls(cls, code):
1244 code('#include <time.h>')
1245
1246 def __init__(self, value):
1247 self.value = parse_time(value)
1248
1249 def __call__(self, value):
1250 self.__init__(value)
1251 return value
1252
1253 def getValue(self):
1254 from _m5.core import tm
1255 import calendar
1256
1257 return tm.gmtime(calendar.timegm(self.value))
1258
1259 def __str__(self):
1260 return time.asctime(self.value)
1261
1262 def ini_str(self):
1263 return str(self)
1264
1265 def get_config_as_dict(self):
1266 assert false
1267 return str(self)
1268
1269 @classmethod
1270 def cxx_ini_predecls(cls, code):
1271 code('#include <time.h>')
1272
1273 @classmethod
1274 def cxx_ini_parse(cls, code, src, dest, ret):
1275 code('char *_parse_ret = strptime((${src}).c_str(),')
1276 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1277 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1278
1279 # Enumerated types are a little more complex. The user specifies the
1280 # type as Enum(foo) where foo is either a list or dictionary of
1281 # alternatives (typically strings, but not necessarily so). (In the
1282 # long run, the integer value of the parameter will be the list index
1283 # or the corresponding dictionary value. For now, since we only check
1284 # that the alternative is valid and then spit it into a .ini file,
1285 # there's not much point in using the dictionary.)
1286
1287 # What Enum() must do is generate a new type encapsulating the
1288 # provided list/dictionary so that specific values of the parameter
1289 # can be instances of that type. We define two hidden internal
1290 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1291 # derive the new type from the appropriate base class on the fly.
1292
1293 allEnums = {}
1294 # Metaclass for Enum types
1295 class MetaEnum(MetaParamValue):
1296 def __new__(mcls, name, bases, dict):
1297
1298 cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1299 allEnums[name] = cls
1300 return cls
1301
1302 def __init__(cls, name, bases, init_dict):
1303 if 'map' in init_dict:
1304 if not isinstance(cls.map, dict):
1305 raise TypeError("Enum-derived class attribute 'map' " \
1306 "must be of type dict")
1307 # build list of value strings from map
1308 cls.vals = list(cls.map.keys())
1309 cls.vals.sort()
1310 elif 'vals' in init_dict:
1311 if not isinstance(cls.vals, list):
1312 raise TypeError("Enum-derived class attribute 'vals' " \
1313 "must be of type list")
1314 # build string->value map from vals sequence
1315 cls.map = {}
1316 for idx,val in enumerate(cls.vals):
1317 cls.map[val] = idx
1318 else:
1319 raise TypeError("Enum-derived class must define "\
1320 "attribute 'map' or 'vals'")
1321
1322 if cls.is_class:
1323 cls.cxx_type = '%s' % name
1324 else:
1325 cls.cxx_type = 'Enums::%s' % name
1326
1327 super(MetaEnum, cls).__init__(name, bases, init_dict)
1328
1329 # Generate C++ class declaration for this enum type.
1330 # Note that we wrap the enum in a class/struct to act as a namespace,
1331 # so that the enum strings can be brief w/o worrying about collisions.
1332 def cxx_decl(cls, code):
1333 wrapper_name = cls.wrapper_name
1334 wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1335 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1336 idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1337
1338 code('''\
1339 #ifndef $idem_macro
1340 #define $idem_macro
1341
1342 ''')
1343 if cls.is_class:
1344 code('''\
1345 enum class $name {
1346 ''')
1347 else:
1348 code('''\
1349 $wrapper $wrapper_name {
1350 enum $name {
1351 ''')
1352 code.indent(1)
1353 code.indent(1)
1354 for val in cls.vals:
1355 code('$val = ${{cls.map[val]}},')
1356 code('Num_$name = ${{len(cls.vals)}}')
1357 code.dedent(1)
1358 code('};')
1359
1360 if cls.is_class:
1361 code('''\
1362 extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1363 ''')
1364 elif cls.wrapper_is_struct:
1365 code('static const char *${name}Strings[Num_${name}];')
1366 else:
1367 code('extern const char *${name}Strings[Num_${name}];')
1368
1369 if not cls.is_class:
1370 code.dedent(1)
1371 code('};')
1372
1373 code()
1374 code('#endif // $idem_macro')
1375
1376 def cxx_def(cls, code):
1377 wrapper_name = cls.wrapper_name
1378 file_name = cls.__name__
1379 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1380
1381 code('#include "enums/$file_name.hh"')
1382 if cls.wrapper_is_struct:
1383 code('const char *${wrapper_name}::${name}Strings'
1384 '[Num_${name}] =')
1385 else:
1386 if cls.is_class:
1387 code('''\
1388 const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1389 ''')
1390 else:
1391 code('namespace Enums {')
1392 code.indent(1)
1393 code('const char *${name}Strings[Num_${name}] =')
1394
1395 code('{')
1396 code.indent(1)
1397 for val in cls.vals:
1398 code('"$val",')
1399 code.dedent(1)
1400 code('};')
1401
1402 if not cls.wrapper_is_struct and not cls.is_class:
1403 code.dedent(1)
1404 code('} // namespace $wrapper_name')
1405
1406
1407 def pybind_def(cls, code):
1408 name = cls.__name__
1409 enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1410 wrapper_name = enum_name if cls.is_class else cls.wrapper_name
1411
1412 code('''#include "pybind11/pybind11.h"
1413 #include "pybind11/stl.h"
1414
1415 #include <sim/init.hh>
1416
1417 namespace py = pybind11;
1418
1419 static void
1420 module_init(py::module &m_internal)
1421 {
1422 py::module m = m_internal.def_submodule("enum_${name}");
1423
1424 ''')
1425 if cls.is_class:
1426 code('py::enum_<${enum_name}>(m, "enum_${name}")')
1427 else:
1428 code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1429
1430 code.indent()
1431 code.indent()
1432 for val in cls.vals:
1433 code('.value("${val}", ${wrapper_name}::${val})')
1434 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1435 if not cls.is_class:
1436 code('.export_values()')
1437 code(';')
1438 code.dedent()
1439
1440 code('}')
1441 code.dedent()
1442 code()
1443 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1444
1445
1446 # Base class for enum types.
1447 class Enum(with_metaclass(MetaEnum, ParamValue)):
1448 vals = []
1449 cmd_line_settable = True
1450
1451 # The name of the wrapping namespace or struct
1452 wrapper_name = 'Enums'
1453
1454 # If true, the enum is wrapped in a struct rather than a namespace
1455 wrapper_is_struct = False
1456
1457 is_class = False
1458
1459 # If not None, use this as the enum name rather than this class name
1460 enum_name = None
1461
1462 def __init__(self, value):
1463 if value not in self.map:
1464 raise TypeError("Enum param got bad value '%s' (not in %s)" \
1465 % (value, self.vals))
1466 self.value = value
1467
1468 def __call__(self, value):
1469 self.__init__(value)
1470 return value
1471
1472 @classmethod
1473 def cxx_predecls(cls, code):
1474 code('#include "enums/$0.hh"', cls.__name__)
1475
1476 @classmethod
1477 def cxx_ini_parse(cls, code, src, dest, ret):
1478 code('if (false) {')
1479 for elem_name in cls.map.keys():
1480 code('} else if (%s == "%s") {' % (src, elem_name))
1481 code.indent()
1482 name = cls.__name__ if cls.enum_name is None else cls.enum_name
1483 code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums',
1484 elem_name))
1485 code('%s true;' % ret)
1486 code.dedent()
1487 code('} else {')
1488 code(' %s false;' % ret)
1489 code('}')
1490
1491 def getValue(self):
1492 import m5.internal.params
1493 e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1494 return e(self.map[self.value])
1495
1496 def __str__(self):
1497 return self.value
1498
1499 # This param will generate a scoped c++ enum and its python bindings.
1500 class ScopedEnum(Enum):
1501 vals = []
1502 cmd_line_settable = True
1503
1504 # The name of the wrapping namespace or struct
1505 wrapper_name = None
1506
1507 # If true, the enum is wrapped in a struct rather than a namespace
1508 wrapper_is_struct = False
1509
1510 # If true, the generated enum is a scoped enum
1511 is_class = True
1512
1513 # If not None, use this as the enum name rather than this class name
1514 enum_name = None
1515
1516 class ByteOrder(ScopedEnum):
1517 """Enum representing component's byte order (endianness)"""
1518
1519 vals = [
1520 'big',
1521 'little',
1522 ]
1523
1524 # how big does a rounding error need to be before we warn about it?
1525 frequency_tolerance = 0.001 # 0.1%
1526
1527 class TickParamValue(NumericParamValue):
1528 cxx_type = 'Tick'
1529 ex_str = "1MHz"
1530 cmd_line_settable = True
1531
1532 @classmethod
1533 def cxx_predecls(cls, code):
1534 code('#include "base/types.hh"')
1535
1536 def __call__(self, value):
1537 self.__init__(value)
1538 return value
1539
1540 def getValue(self):
1541 return long(self.value)
1542
1543 @classmethod
1544 def cxx_ini_predecls(cls, code):
1545 code('#include <sstream>')
1546
1547 # Ticks are expressed in seconds in JSON files and in plain
1548 # Ticks in .ini files. Switch based on a config flag
1549 @classmethod
1550 def cxx_ini_parse(self, code, src, dest, ret):
1551 code('${ret} to_number(${src}, ${dest});')
1552
1553 class Latency(TickParamValue):
1554 ex_str = "100ns"
1555
1556 def __init__(self, value):
1557 if isinstance(value, (Latency, Clock)):
1558 self.ticks = value.ticks
1559 self.value = value.value
1560 elif isinstance(value, Frequency):
1561 self.ticks = value.ticks
1562 self.value = 1.0 / value.value
1563 elif value.endswith('t'):
1564 self.ticks = True
1565 self.value = int(value[:-1])
1566 else:
1567 self.ticks = False
1568 self.value = convert.toLatency(value)
1569
1570 def __call__(self, value):
1571 self.__init__(value)
1572 return value
1573
1574 def __getattr__(self, attr):
1575 if attr in ('latency', 'period'):
1576 return self
1577 if attr == 'frequency':
1578 return Frequency(self)
1579 raise AttributeError("Latency object has no attribute '%s'" % attr)
1580
1581 def getValue(self):
1582 if self.ticks or self.value == 0:
1583 value = self.value
1584 else:
1585 value = ticks.fromSeconds(self.value)
1586 return long(value)
1587
1588 def config_value(self):
1589 return self.getValue()
1590
1591 # convert latency to ticks
1592 def ini_str(self):
1593 return '%d' % self.getValue()
1594
1595 class Frequency(TickParamValue):
1596 ex_str = "1GHz"
1597
1598 def __init__(self, value):
1599 if isinstance(value, (Latency, Clock)):
1600 if value.value == 0:
1601 self.value = 0
1602 else:
1603 self.value = 1.0 / value.value
1604 self.ticks = value.ticks
1605 elif isinstance(value, Frequency):
1606 self.value = value.value
1607 self.ticks = value.ticks
1608 else:
1609 self.ticks = False
1610 self.value = convert.toFrequency(value)
1611
1612 def __call__(self, value):
1613 self.__init__(value)
1614 return value
1615
1616 def __getattr__(self, attr):
1617 if attr == 'frequency':
1618 return self
1619 if attr in ('latency', 'period'):
1620 return Latency(self)
1621 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1622
1623 # convert latency to ticks
1624 def getValue(self):
1625 if self.ticks or self.value == 0:
1626 value = self.value
1627 else:
1628 value = ticks.fromSeconds(1.0 / self.value)
1629 return long(value)
1630
1631 def config_value(self):
1632 return self.getValue()
1633
1634 def ini_str(self):
1635 return '%d' % self.getValue()
1636
1637 # A generic Frequency and/or Latency value. Value is stored as a
1638 # latency, just like Latency and Frequency.
1639 class Clock(TickParamValue):
1640 def __init__(self, value):
1641 if isinstance(value, (Latency, Clock)):
1642 self.ticks = value.ticks
1643 self.value = value.value
1644 elif isinstance(value, Frequency):
1645 self.ticks = value.ticks
1646 self.value = 1.0 / value.value
1647 elif value.endswith('t'):
1648 self.ticks = True
1649 self.value = int(value[:-1])
1650 else:
1651 self.ticks = False
1652 self.value = convert.anyToLatency(value)
1653
1654 def __call__(self, value):
1655 self.__init__(value)
1656 return value
1657
1658 def __str__(self):
1659 return "%s" % Latency(self)
1660
1661 def __getattr__(self, attr):
1662 if attr == 'frequency':
1663 return Frequency(self)
1664 if attr in ('latency', 'period'):
1665 return Latency(self)
1666 raise AttributeError("Frequency object has no attribute '%s'" % attr)
1667
1668 def getValue(self):
1669 return self.period.getValue()
1670
1671 def config_value(self):
1672 return self.period.config_value()
1673
1674 def ini_str(self):
1675 return self.period.ini_str()
1676
1677 class Voltage(Float):
1678 ex_str = "1V"
1679
1680 def __new__(cls, value):
1681 value = convert.toVoltage(value)
1682 return super(cls, Voltage).__new__(cls, value)
1683
1684 def __init__(self, value):
1685 value = convert.toVoltage(value)
1686 super(Voltage, self).__init__(value)
1687
1688 class Current(Float):
1689 ex_str = "1mA"
1690
1691 def __new__(cls, value):
1692 value = convert.toCurrent(value)
1693 return super(cls, Current).__new__(cls, value)
1694
1695 def __init__(self, value):
1696 value = convert.toCurrent(value)
1697 super(Current, self).__init__(value)
1698
1699 class Energy(Float):
1700 ex_str = "1pJ"
1701
1702 def __new__(cls, value):
1703 value = convert.toEnergy(value)
1704 return super(cls, Energy).__new__(cls, value)
1705
1706 def __init__(self, value):
1707 value = convert.toEnergy(value)
1708 super(Energy, self).__init__(value)
1709
1710 class NetworkBandwidth(float,ParamValue):
1711 cxx_type = 'float'
1712 ex_str = "1Gbps"
1713 cmd_line_settable = True
1714
1715 def __new__(cls, value):
1716 # convert to bits per second
1717 val = convert.toNetworkBandwidth(value)
1718 return super(cls, NetworkBandwidth).__new__(cls, val)
1719
1720 def __str__(self):
1721 return str(self.val)
1722
1723 def __call__(self, value):
1724 val = convert.toNetworkBandwidth(value)
1725 self.__init__(val)
1726 return value
1727
1728 def getValue(self):
1729 # convert to seconds per byte
1730 value = 8.0 / float(self)
1731 # convert to ticks per byte
1732 value = ticks.fromSeconds(value)
1733 return float(value)
1734
1735 def ini_str(self):
1736 return '%f' % self.getValue()
1737
1738 def config_value(self):
1739 return '%f' % self.getValue()
1740
1741 @classmethod
1742 def cxx_ini_predecls(cls, code):
1743 code('#include <sstream>')
1744
1745 @classmethod
1746 def cxx_ini_parse(self, code, src, dest, ret):
1747 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1748
1749 class MemoryBandwidth(float,ParamValue):
1750 cxx_type = 'float'
1751 ex_str = "1GB/s"
1752 cmd_line_settable = True
1753
1754 def __new__(cls, value):
1755 # convert to bytes per second
1756 val = convert.toMemoryBandwidth(value)
1757 return super(cls, MemoryBandwidth).__new__(cls, val)
1758
1759 def __call__(self, value):
1760 val = convert.toMemoryBandwidth(value)
1761 self.__init__(val)
1762 return value
1763
1764 def getValue(self):
1765 # convert to seconds per byte
1766 value = float(self)
1767 if value:
1768 value = 1.0 / float(self)
1769 # convert to ticks per byte
1770 value = ticks.fromSeconds(value)
1771 return float(value)
1772
1773 def ini_str(self):
1774 return '%f' % self.getValue()
1775
1776 def config_value(self):
1777 return '%f' % self.getValue()
1778
1779 @classmethod
1780 def cxx_ini_predecls(cls, code):
1781 code('#include <sstream>')
1782
1783 @classmethod
1784 def cxx_ini_parse(self, code, src, dest, ret):
1785 code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1786
1787 #
1788 # "Constants"... handy aliases for various values.
1789 #
1790
1791 # Special class for NULL pointers. Note the special check in
1792 # make_param_value() above that lets these be assigned where a
1793 # SimObject is required.
1794 # only one copy of a particular node
1795 class NullSimObject(with_metaclass(Singleton, object)):
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 REQUESTOR', 'GEM5 RESPONDER')
2124
2125 class RequestPort(Port):
2126 # RequestPort("description")
2127 def __init__(self, desc):
2128 super(RequestPort, self).__init__(
2129 'GEM5 REQUESTOR', 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 REQUESTOR', 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(with_metaclass(Singleton, object)):
2163 ptype_str = 'Port'
2164 ptype = Port
2165
2166 class DeprecatedParam(object):
2167 """A special type for deprecated parameter variable names.
2168
2169 There are times when we need to change the name of parameter, but this
2170 breaks the external-facing python API used in configuration files. Using
2171 this "type" for a parameter will warn users that they are using the old
2172 name, but allow for backwards compatibility.
2173
2174 Usage example:
2175 In the following example, the `time` parameter is changed to `delay`.
2176
2177 ```
2178 class SomeDevice(SimObject):
2179 delay = Param.Latency('1ns', 'The time to wait before something')
2180 time = DeprecatedParam(delay, '`time` is now called `delay`')
2181 ```
2182 """
2183
2184 def __init__(self, new_param, message=''):
2185 """new_param: the new parameter variable that users should be using
2186 instead of this parameter variable.
2187 message: an optional message to print when warning the user
2188 """
2189 self.message = message
2190 self.newParam = new_param
2191 # Note: We won't know the string variable names until later in the
2192 # SimObject initialization process. Note: we expect that the setters
2193 # will be called when the SimObject type (class) is initialized so
2194 # these variables should be filled in before the instance of the
2195 # SimObject with this parameter is constructed
2196 self._oldName = ''
2197 self._newName = ''
2198
2199 @property
2200 def oldName(self):
2201 assert(self._oldName != '') # should already be set
2202 return self._oldName
2203
2204 @oldName.setter
2205 def oldName(self, name):
2206 assert(self._oldName == '') # Cannot "re-set" this value
2207 self._oldName = name
2208
2209 @property
2210 def newName(self):
2211 assert(self._newName != '') # should already be set
2212 return self._newName
2213
2214 @newName.setter
2215 def newName(self, name):
2216 assert(self._newName == '') # Cannot "re-set" this value
2217 self._newName = name
2218
2219 def printWarning(self, instance_name, simobj_name):
2220 """Issue a warning that this variable name should not be used.
2221
2222 instance_name: str, the name of the instance used in python
2223 simobj_name: str, the name of the SimObject type
2224 """
2225 if not self.message:
2226 self.message = "See {} for more information".format(simobj_name)
2227 warn('{}.{} is deprecated. {}'.format(
2228 instance_name, self._oldName, self.message))
2229
2230 baseEnums = allEnums.copy()
2231 baseParams = allParams.copy()
2232
2233 def clear():
2234 global allEnums, allParams
2235
2236 allEnums = baseEnums.copy()
2237 allParams = baseParams.copy()
2238
2239 __all__ = ['Param', 'VectorParam',
2240 'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2241 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2242 'Int32', 'UInt32', 'Int64', 'UInt64',
2243 'Counter', 'Addr', 'Tick', 'Percent',
2244 'TcpPort', 'UdpPort', 'EthernetAddr',
2245 'IpAddress', 'IpNetmask', 'IpWithPort',
2246 'MemorySize', 'MemorySize32',
2247 'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2248 'NetworkBandwidth', 'MemoryBandwidth',
2249 'AddrRange',
2250 'MaxAddr', 'MaxTick', 'AllMemory',
2251 'Time',
2252 'NextEthernetAddr', 'NULL',
2253 'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2254 'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2255 'VectorMasterPort', 'VectorSlavePort',
2256 'DeprecatedParam',
2257 ]