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