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