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