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