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