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