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