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