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