4e646d3f5faf0f4ae64b23b4594823df8aa61197
1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
2 # Copyright (c) 2010 Advanced Micro Devices, Inc.
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.
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.
28 # Authors: Steve Reinhardt
31 #####################################################################
33 # Parameter description classes
35 # The _params dictionary in each class maps parameter names to either
36 # a Param or a VectorParam object. These objects contain the
37 # parameter description string, the parameter type, and the default
38 # value (if any). The convert() method on these objects is used to
39 # force whatever value is assigned to the parameter to the appropriate
42 # Note that the default values are loaded into the class's attribute
43 # space when the parameter dictionary is initialized (in
44 # MetaSimObject._new_param()); after that point they aren't used.
46 #####################################################################
59 def isSimObject(*args
, **kwargs
):
60 return SimObject
.isSimObject(*args
, **kwargs
)
62 def isSimObjectSequence(*args
, **kwargs
):
63 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
65 def isSimObjectClass(*args
, **kwargs
):
66 return SimObject
.isSimObjectClass(*args
, **kwargs
)
70 class MetaParamValue(type):
71 def __new__(mcls
, name
, bases
, dct
):
72 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
73 assert name
not in allParams
78 # Dummy base class to identify types that are legitimate for SimObject
80 class ParamValue(object):
81 __metaclass__
= MetaParamValue
84 def cxx_predecls(cls
, code
):
88 def swig_predecls(cls
, code
):
91 # default for printing to .ini file is regular string conversion.
92 # will be overridden in some cases
96 # allows us to blithely call unproxy() on things without checking
97 # if they're really proxies or not
98 def unproxy(self
, base
):
101 # Regular parameter description.
102 class ParamDesc(object):
105 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
106 self
.ptype_str
= ptype_str
107 # remember ptype only if it is provided
115 self
.default
= args
[0]
118 raise TypeError, 'too many arguments'
120 if kwargs
.has_key('desc'):
121 assert(not hasattr(self
, 'desc'))
122 self
.desc
= kwargs
['desc']
125 if kwargs
.has_key('default'):
126 assert(not hasattr(self
, 'default'))
127 self
.default
= kwargs
['default']
128 del kwargs
['default']
131 raise TypeError, 'extra unknown kwargs %s' % kwargs
133 if not hasattr(self
, 'desc'):
134 raise TypeError, 'desc attribute missing'
136 def __getattr__(self
, attr
):
138 ptype
= SimObject
.allClasses
[self
.ptype_str
]
139 assert isSimObjectClass(ptype
)
143 raise AttributeError, "'%s' object has no attribute '%s'" % \
144 (type(self
).__name
__, attr
)
146 def convert(self
, value
):
147 if isinstance(value
, proxy
.BaseProxy
):
148 value
.set_param_desc(self
)
150 if not hasattr(self
, 'ptype') and isNullPointer(value
):
151 # deferred evaluation of SimObject; continue to defer if
152 # we're just assigning a null pointer
154 if isinstance(value
, self
.ptype
):
156 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
158 return self
.ptype(value
)
160 def cxx_predecls(self
, code
):
161 self
.ptype
.cxx_predecls(code
)
163 def swig_predecls(self
, code
):
164 self
.ptype
.swig_predecls(code
)
166 def cxx_decl(self
, code
):
167 code('${{self.ptype.cxx_type}} ${{self.name}};')
169 # Vector-valued parameter description. Just like ParamDesc, except
170 # that the value is a vector (list) of the specified type instead of a
173 class VectorParamValue(list):
174 __metaclass__
= MetaParamValue
175 def __setattr__(self
, attr
, value
):
176 raise AttributeError, \
177 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
180 return ' '.join([v
.ini_str() for v
in self
])
183 return [ v
.getValue() for v
in self
]
185 def unproxy(self
, base
):
186 return [v
.unproxy(base
) for v
in self
]
188 class SimObjectVector(VectorParamValue
):
189 # support clone operation
190 def __call__(self
, **kwargs
):
191 return SimObjectVector([v(**kwargs
) for v
in self
])
193 def clear_parent(self
, old_parent
):
195 v
.clear_parent(old_parent
)
197 def set_parent(self
, parent
, name
):
199 self
[0].set_parent(parent
, name
)
201 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
202 for i
,v
in enumerate(self
):
203 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
205 def get_parent(self
):
206 parent_set
= set(v
._parent
for v
in self
)
207 if len(parent_set
) != 1:
208 raise RuntimeError, \
209 "SimObjectVector elements have inconsistent parent value."
210 return parent_set
.pop()
212 # return 'cpu0 cpu1' etc. for print_ini()
214 return ' '.join([v
._name
for v
in self
])
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
):
222 for obj
in v
.descendants():
225 class VectorParamDesc(ParamDesc
):
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
]
235 # singleton: coerce to a single-element list
236 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
238 if isSimObjectSequence(tmp_list
):
239 return SimObjectVector(tmp_list
)
241 return VectorParamValue(tmp_list
)
243 def swig_predecls(self
, code
):
244 code('%import "vptype_${{self.ptype_str}}.i"')
246 def swig_decl(self
, code
):
248 self
.ptype
.cxx_predecls(code
)
251 self
.ptype
.swig_predecls(code
)
253 code('%include "std_vector.i"')
256 ptype
= self
.ptype_str
257 cxx_type
= self
.ptype
.cxx_type
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) {
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) {
279 code('%template(vector_$ptype) std::vector< $cxx_type >;')
281 def cxx_predecls(self
, code
):
282 code('#include <vector>')
283 self
.ptype
.cxx_predecls(code
)
285 def cxx_decl(self
, code
):
286 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
288 class 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
293 def __getattr__(self
, attr
):
295 attr
= self
.ptype_str
+ '.' + attr
296 return ParamFactory(self
.param_desc_class
, attr
)
298 # E.g., Param.Int(5, "number of widgets")
299 def __call__(self
, *args
, **kwargs
):
302 ptype
= allParams
[self
.ptype_str
]
304 # if name isn't defined yet, assume it's a SimObject, and
305 # try to resolve it later
307 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
309 Param
= ParamFactory(ParamDesc
)
310 VectorParam
= ParamFactory(VectorParamDesc
)
312 #####################################################################
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).
323 #####################################################################
325 # String-valued parameter. Just mixin the ParamValue class with the
326 # built-in str class.
327 class String(ParamValue
,str):
328 cxx_type
= 'std::string'
331 def cxx_predecls(self
, code
):
332 code('#include <string>')
335 def swig_predecls(cls
, code
):
336 code('%include "std_string.i"')
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.
344 class NumericParamValue(ParamValue
):
346 return str(self
.value
)
349 return float(self
.value
)
352 return long(self
.value
)
355 return int(self
.value
)
357 # hook for bounds checking
361 def __mul__(self
, other
):
362 newobj
= self
.__class
__(self
)
363 newobj
.value
*= other
369 def __div__(self
, other
):
370 newobj
= self
.__class
__(self
)
371 newobj
.value
/= other
375 def __sub__(self
, other
):
376 newobj
= self
.__class
__(self
)
377 newobj
.value
-= other
381 # Metaclass for bounds-checked integer parameters. See CheckedInt.
382 class CheckedIntType(MetaParamValue
):
383 def __init__(cls
, name
, bases
, dict):
384 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
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':
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",
399 cls
.max = 2 ** cls
.size
- 1
401 cls
.min = -(2 ** (cls
.size
- 1))
402 cls
.max = (2 ** (cls
.size
- 1)) - 1
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__.
408 class CheckedInt(NumericParamValue
):
409 __metaclass__
= CheckedIntType
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)
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
)
422 raise TypeError, "Can't convert object of type %s to CheckedInt" \
423 % type(value
).__name
__
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"')
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"')
438 return long(self
.value
)
440 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
441 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
443 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
444 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
445 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
446 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
447 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
448 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
449 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
450 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
452 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
453 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
454 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
455 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
457 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
459 class Float(ParamValue
, float):
462 def __init__(self
, value
):
463 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
464 self
.value
= float(value
)
466 raise TypeError, "Can't convert object of type %s to Float" \
467 % type(value
).__name
__
470 return float(self
.value
)
472 class MemorySize(CheckedInt
):
473 cxx_type
= 'uint64_t'
476 def __init__(self
, value
):
477 if isinstance(value
, MemorySize
):
478 self
.value
= value
.value
480 self
.value
= convert
.toMemorySize(value
)
483 class MemorySize32(CheckedInt
):
484 cxx_type
= 'uint32_t'
487 def __init__(self
, value
):
488 if isinstance(value
, MemorySize
):
489 self
.value
= value
.value
491 self
.value
= convert
.toMemorySize(value
)
494 class Addr(CheckedInt
):
498 def __init__(self
, value
):
499 if isinstance(value
, Addr
):
500 self
.value
= value
.value
503 self
.value
= convert
.toMemorySize(value
)
505 self
.value
= long(value
)
507 def __add__(self
, other
):
508 if isinstance(other
, Addr
):
509 return self
.value
+ other
.value
511 return self
.value
+ other
514 class MetaRange(MetaParamValue
):
515 def __init__(cls
, name
, bases
, dict):
516 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
519 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
521 class 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
):
527 self
.second
= self
.type(kwargs
.pop('end'))
528 elif 'size' in kwargs
:
529 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
531 raise TypeError, "Either end or size must be specified"
534 self
.first
= self
.type(kwargs
.pop('start'))
535 handle_kwargs(self
, 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])
548 self
.first
= self
.type(0)
549 self
.second
= self
.type(args
[0]) - 1
552 self
.first
= self
.type(args
[0])
553 self
.second
= self
.type(args
[1])
555 raise TypeError, "Too many arguments specified"
558 raise TypeError, "too many keywords: %s" % kwargs
.keys()
561 return '%s:%s' % (self
.first
, self
.second
)
564 def cxx_predecls(cls
, code
):
565 cls
.type.cxx_predecls(code
)
566 code('#include "base/range.hh"')
569 def swig_predecls(cls
, code
):
570 cls
.type.swig_predecls(code
)
571 code('%import "python/swig/range.i"')
573 class AddrRange(Range
):
577 from m5
.internal
.range import AddrRange
580 value
.start
= long(self
.first
)
581 value
.end
= long(self
.second
)
584 class TickRange(Range
):
588 from m5
.internal
.range import TickRange
591 value
.start
= long(self
.first
)
592 value
.end
= long(self
.second
)
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.
598 class Bool(ParamValue
):
600 def __init__(self
, value
):
602 self
.value
= convert
.toBool(value
)
604 self
.value
= bool(value
)
607 return bool(self
.value
)
610 return str(self
.value
)
617 def IncEthernetAddr(addr
, val
= 1):
618 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
620 for i
in (5, 4, 3, 2, 1):
621 val
,rem
= divmod(bytes
[i
], 256)
626 assert(bytes
[0] <= 255)
627 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
629 _NextEthernetAddr
= "00:90:00:00:00:01"
630 def NextEthernetAddr():
631 global _NextEthernetAddr
633 value
= _NextEthernetAddr
634 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
637 class EthernetAddr(ParamValue
):
638 cxx_type
= 'Net::EthAddr'
641 def cxx_predecls(cls
, code
):
642 code('#include "base/inet.hh"')
645 def swig_predecls(cls
, code
):
646 code('%include "python/swig/inet.i"')
648 def __init__(self
, value
):
649 if value
== NextEthernetAddr
:
653 if not isinstance(value
, str):
654 raise TypeError, "expected an ethernet address and didn't get one"
656 bytes
= value
.split(':')
658 raise TypeError, 'invalid ethernet address %s' % value
661 if not 0 <= int(byte
) <= 0xff:
662 raise TypeError, 'invalid ethernet address %s' % value
666 def unproxy(self
, base
):
667 if self
.value
== NextEthernetAddr
:
668 return EthernetAddr(self
.value())
672 from m5
.internal
.params
import EthAddr
673 return EthAddr(self
.value
)
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.
680 class IpAddress(ParamValue
):
681 cxx_type
= 'Net::IpAddress'
684 def cxx_predecls(cls
, code
):
685 code('#include "base/inet.hh"')
688 def swig_predecls(cls
, code
):
689 code('%include "python/swig/inet.i"')
691 def __init__(self
, value
):
692 if isinstance(value
, IpAddress
):
696 self
.ip
= convert
.toIpAddress(value
)
698 self
.ip
= long(value
)
702 if self
.ip
< 0 or self
.ip
>= (1 << 32):
703 raise TypeError, "invalid ip address %#08x" % ip
706 from m5
.internal
.params
import IpAddress
707 return IpAddress(self
.ip
)
712 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
713 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
714 # positional or keyword arguments.
715 class IpNetmask(IpAddress
):
716 cxx_type
= 'Net::IpNetmask'
719 def cxx_predecls(cls
, code
):
720 code('#include "base/inet.hh"')
723 def swig_predecls(cls
, code
):
724 code('%include "python/swig/inet.i"')
726 def __init__(self
, *args
, **kwargs
):
727 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
729 setattr(self
, key
, kwargs
.pop(key
))
731 setattr(self
, key
, elseVal
)
733 raise TypeError, "No value set for %s" % key
736 handle_kwarg(self
, kwargs
, 'ip')
737 handle_kwarg(self
, kwargs
, 'netmask')
741 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
742 raise TypeError, "Invalid arguments"
743 handle_kwarg(self
, kwargs
, 'ip', args
[0])
744 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
745 elif isinstance(args
[0], IpNetmask
):
747 self
.netmask
= args
[0].netmask
749 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
753 self
.netmask
= args
[1]
755 raise TypeError, "Too many arguments specified"
758 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
764 if self
.netmask
< 0 or self
.netmask
> 32:
765 raise TypeError, "invalid netmask %d" % netmask
768 from m5
.internal
.params
import IpNetmask
769 return IpNetmask(self
.ip
, self
.netmask
)
772 return "%08x/%d" % (self
.ip
, self
.netmask
)
774 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
775 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
776 class IpWithPort(IpAddress
):
777 cxx_type
= 'Net::IpWithPort'
780 def cxx_predecls(cls
, code
):
781 code('#include "base/inet.hh"')
784 def swig_predecls(cls
, code
):
785 code('%include "python/swig/inet.i"')
787 def __init__(self
, *args
, **kwargs
):
788 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
790 setattr(self
, key
, kwargs
.pop(key
))
792 setattr(self
, key
, elseVal
)
794 raise TypeError, "No value set for %s" % key
797 handle_kwarg(self
, kwargs
, 'ip')
798 handle_kwarg(self
, kwargs
, 'port')
802 if not 'ip' in kwargs
and not 'port' in kwargs
:
803 raise TypeError, "Invalid arguments"
804 handle_kwarg(self
, kwargs
, 'ip', args
[0])
805 handle_kwarg(self
, kwargs
, 'port', args
[0])
806 elif isinstance(args
[0], IpWithPort
):
808 self
.port
= args
[0].port
810 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
816 raise TypeError, "Too many arguments specified"
819 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
825 if self
.port
< 0 or self
.port
> 0xffff:
826 raise TypeError, "invalid port %d" % self
.port
829 from m5
.internal
.params
import IpWithPort
830 return IpWithPort(self
.ip
, self
.port
)
833 return "%08x:%d" % (self
.ip
, self
.port
)
835 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
836 "%a %b %d %H:%M:%S %Z %Y",
848 def parse_time(value
):
849 from time
import gmtime
, strptime
, struct_time
, time
850 from datetime
import datetime
, date
852 if isinstance(value
, struct_time
):
855 if isinstance(value
, (int, long)):
858 if isinstance(value
, (datetime
, date
)):
859 return value
.timetuple()
861 if isinstance(value
, str):
862 if value
in ('Now', 'Today'):
863 return time
.gmtime(time
.time())
865 for format
in time_formats
:
867 return strptime(value
, format
)
871 raise ValueError, "Could not parse '%s' as a time" % value
873 class Time(ParamValue
):
877 def cxx_predecls(cls
, code
):
878 code('#include <time.h>')
881 def swig_predecls(cls
, code
):
882 code('%include "python/swig/time.i"')
884 def __init__(self
, value
):
885 self
.value
= parse_time(value
)
888 from m5
.internal
.params
import tm
893 # UNIX is years since 1900
894 c_time
.tm_year
= py_time
.tm_year
- 1900;
896 # Python starts at 1, UNIX starts at 0
897 c_time
.tm_mon
= py_time
.tm_mon
- 1;
898 c_time
.tm_mday
= py_time
.tm_mday
;
899 c_time
.tm_hour
= py_time
.tm_hour
;
900 c_time
.tm_min
= py_time
.tm_min
;
901 c_time
.tm_sec
= py_time
.tm_sec
;
903 # Python has 0 as Monday, UNIX is 0 as sunday
904 c_time
.tm_wday
= py_time
.tm_wday
+ 1
905 if c_time
.tm_wday
> 6:
908 # Python starts at 1, Unix starts at 0
909 c_time
.tm_yday
= py_time
.tm_yday
- 1;
914 return time
.asctime(self
.value
)
919 # Enumerated types are a little more complex. The user specifies the
920 # type as Enum(foo) where foo is either a list or dictionary of
921 # alternatives (typically strings, but not necessarily so). (In the
922 # long run, the integer value of the parameter will be the list index
923 # or the corresponding dictionary value. For now, since we only check
924 # that the alternative is valid and then spit it into a .ini file,
925 # there's not much point in using the dictionary.)
927 # What Enum() must do is generate a new type encapsulating the
928 # provided list/dictionary so that specific values of the parameter
929 # can be instances of that type. We define two hidden internal
930 # classes (_ListEnum and _DictEnum) to serve as base classes, then
931 # derive the new type from the appropriate base class on the fly.
934 # Metaclass for Enum types
935 class MetaEnum(MetaParamValue
):
936 def __new__(mcls
, name
, bases
, dict):
937 assert name
not in allEnums
939 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
943 def __init__(cls
, name
, bases
, init_dict
):
944 if init_dict
.has_key('map'):
945 if not isinstance(cls
.map, dict):
946 raise TypeError, "Enum-derived class attribute 'map' " \
947 "must be of type dict"
948 # build list of value strings from map
949 cls
.vals
= cls
.map.keys()
951 elif init_dict
.has_key('vals'):
952 if not isinstance(cls
.vals
, list):
953 raise TypeError, "Enum-derived class attribute 'vals' " \
954 "must be of type list"
955 # build string->value map from vals sequence
957 for idx
,val
in enumerate(cls
.vals
):
960 raise TypeError, "Enum-derived class must define "\
961 "attribute 'map' or 'vals'"
963 cls
.cxx_type
= 'Enums::%s' % name
965 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
967 # Generate C++ class declaration for this enum type.
968 # Note that we wrap the enum in a class/struct to act as a namespace,
969 # so that the enum strings can be brief w/o worrying about collisions.
970 def cxx_decl(cls
, code
):
973 #ifndef __ENUM__${name}__
974 #define __ENUM__${name}__
981 code('$val = ${{cls.map[val]}},')
982 code('Num_$name = ${{len(cls.vals)}},')
986 extern const char *${name}Strings[Num_${name}];
989 #endif // __ENUM__${name}__
992 def cxx_def(cls
, code
):
995 #include "enums/$name.hh"
997 const char *${name}Strings[Num_${name}] =
1001 for val
in cls
.vals
:
1006 /* namespace Enums */ }
1009 # Base class for enum types.
1010 class Enum(ParamValue
):
1011 __metaclass__
= MetaEnum
1014 def __init__(self
, value
):
1015 if value
not in self
.map:
1016 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1017 % (value
, self
.vals
)
1021 def cxx_predecls(cls
, code
):
1022 code('#include "enums/$0.hh"', cls
.__name
__)
1025 def swig_predecls(cls
, code
):
1026 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1029 return int(self
.map[self
.value
])
1034 # how big does a rounding error need to be before we warn about it?
1035 frequency_tolerance
= 0.001 # 0.1%
1037 class TickParamValue(NumericParamValue
):
1041 def cxx_predecls(cls
, code
):
1042 code('#include "base/types.hh"')
1045 def swig_predecls(cls
, code
):
1046 code('%import "stdint.i"')
1047 code('%import "base/types.hh"')
1050 return long(self
.value
)
1052 class Latency(TickParamValue
):
1053 def __init__(self
, value
):
1054 if isinstance(value
, (Latency
, Clock
)):
1055 self
.ticks
= value
.ticks
1056 self
.value
= value
.value
1057 elif isinstance(value
, Frequency
):
1058 self
.ticks
= value
.ticks
1059 self
.value
= 1.0 / value
.value
1060 elif value
.endswith('t'):
1062 self
.value
= int(value
[:-1])
1065 self
.value
= convert
.toLatency(value
)
1067 def __getattr__(self
, attr
):
1068 if attr
in ('latency', 'period'):
1070 if attr
== 'frequency':
1071 return Frequency(self
)
1072 raise AttributeError, "Latency object has no attribute '%s'" % attr
1075 if self
.ticks
or self
.value
== 0:
1078 value
= ticks
.fromSeconds(self
.value
)
1081 # convert latency to ticks
1083 return '%d' % self
.getValue()
1085 class Frequency(TickParamValue
):
1086 def __init__(self
, value
):
1087 if isinstance(value
, (Latency
, Clock
)):
1088 if value
.value
== 0:
1091 self
.value
= 1.0 / value
.value
1092 self
.ticks
= value
.ticks
1093 elif isinstance(value
, Frequency
):
1094 self
.value
= value
.value
1095 self
.ticks
= value
.ticks
1098 self
.value
= convert
.toFrequency(value
)
1100 def __getattr__(self
, attr
):
1101 if attr
== 'frequency':
1103 if attr
in ('latency', 'period'):
1104 return Latency(self
)
1105 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1107 # convert latency to ticks
1109 if self
.ticks
or self
.value
== 0:
1112 value
= ticks
.fromSeconds(1.0 / self
.value
)
1116 return '%d' % self
.getValue()
1118 # A generic frequency and/or Latency value. Value is stored as a latency,
1119 # but to avoid ambiguity this object does not support numeric ops (* or /).
1120 # An explicit conversion to a Latency or Frequency must be made first.
1121 class Clock(ParamValue
):
1125 def cxx_predecls(cls
, code
):
1126 code('#include "base/types.hh"')
1129 def swig_predecls(cls
, code
):
1130 code('%import "stdint.i"')
1131 code('%import "base/types.hh"')
1133 def __init__(self
, value
):
1134 if isinstance(value
, (Latency
, Clock
)):
1135 self
.ticks
= value
.ticks
1136 self
.value
= value
.value
1137 elif isinstance(value
, Frequency
):
1138 self
.ticks
= value
.ticks
1139 self
.value
= 1.0 / value
.value
1140 elif value
.endswith('t'):
1142 self
.value
= int(value
[:-1])
1145 self
.value
= convert
.anyToLatency(value
)
1147 def __getattr__(self
, attr
):
1148 if attr
== 'frequency':
1149 return Frequency(self
)
1150 if attr
in ('latency', 'period'):
1151 return Latency(self
)
1152 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1155 return self
.period
.getValue()
1158 return self
.period
.ini_str()
1160 class NetworkBandwidth(float,ParamValue
):
1162 def __new__(cls
, value
):
1163 # convert to bits per second
1164 val
= convert
.toNetworkBandwidth(value
)
1165 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1168 return str(self
.val
)
1171 # convert to seconds per byte
1172 value
= 8.0 / float(self
)
1173 # convert to ticks per byte
1174 value
= ticks
.fromSeconds(value
)
1178 return '%f' % self
.getValue()
1180 class MemoryBandwidth(float,ParamValue
):
1182 def __new__(cls
, value
):
1183 # convert to bytes per second
1184 val
= convert
.toMemoryBandwidth(value
)
1185 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1188 return str(self
.val
)
1191 # convert to seconds per byte
1194 value
= 1.0 / float(self
)
1195 # convert to ticks per byte
1196 value
= ticks
.fromSeconds(value
)
1200 return '%f' % self
.getValue()
1203 # "Constants"... handy aliases for various values.
1206 # Special class for NULL pointers. Note the special check in
1207 # make_param_value() above that lets these be assigned where a
1208 # SimObject is required.
1209 # only one copy of a particular node
1210 class NullSimObject(object):
1211 __metaclass__
= Singleton
1216 def _instantiate(self
, parent
= None, path
= ''):
1222 def unproxy(self
, base
):
1225 def set_path(self
, parent
, name
):
1234 # The only instance you'll ever need...
1235 NULL
= NullSimObject()
1237 def isNullPointer(value
):
1238 return isinstance(value
, NullSimObject
)
1240 # Some memory range specifications use this as a default upper bound.
1243 AllMemory
= AddrRange(0, MaxAddr
)
1246 #####################################################################
1250 # Ports are used to interconnect objects in the memory system.
1252 #####################################################################
1254 # Port reference: encapsulates a reference to a particular port on a
1255 # particular SimObject.
1256 class PortRef(object):
1257 def __init__(self
, simobj
, name
):
1258 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1259 self
.simobj
= simobj
1261 self
.peer
= None # not associated with another port yet
1262 self
.ccConnected
= False # C++ port connection done?
1263 self
.index
= -1 # always -1 for non-vector ports
1266 return '%s.%s' % (self
.simobj
, self
.name
)
1268 # for config.ini, print peer's name (not ours)
1270 return str(self
.peer
)
1272 def __getattr__(self
, attr
):
1273 if attr
== 'peerObj':
1274 # shorthand for proxies
1275 return self
.peer
.simobj
1276 raise AttributeError, "'%s' object has no attribute '%s'" % \
1277 (self
.__class
__.__name
__, attr
)
1279 # Full connection is symmetric (both ways). Called via
1280 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1281 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1282 # e.g., "obj1.portA[3] = obj2.portB".
1283 def connect(self
, other
):
1284 if isinstance(other
, VectorPortRef
):
1285 # reference to plain VectorPort is implicit append
1286 other
= other
._get
_next
()
1287 if self
.peer
and not proxy
.isproxy(self
.peer
):
1288 print "warning: overwriting port", self
, \
1289 "value", self
.peer
, "with", other
1290 self
.peer
.peer
= None
1292 if proxy
.isproxy(other
):
1293 other
.set_param_desc(PortParamDesc())
1294 elif isinstance(other
, PortRef
):
1295 if other
.peer
is not self
:
1299 "assigning non-port reference '%s' to port '%s'" \
1302 def clone(self
, simobj
, memo
):
1303 if memo
.has_key(self
):
1305 newRef
= copy
.copy(self
)
1307 newRef
.simobj
= simobj
1308 assert(isSimObject(newRef
.simobj
))
1309 if self
.peer
and not proxy
.isproxy(self
.peer
):
1310 peerObj
= self
.peer
.simobj(_memo
=memo
)
1311 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1312 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1315 def unproxy(self
, simobj
):
1316 assert(simobj
is self
.simobj
)
1317 if proxy
.isproxy(self
.peer
):
1319 realPeer
= self
.peer
.unproxy(self
.simobj
)
1321 print "Error in unproxying port '%s' of %s" % \
1322 (self
.name
, self
.simobj
.path())
1324 self
.connect(realPeer
)
1326 # Call C++ to create corresponding port connection between C++ objects
1327 def ccConnect(self
):
1328 from m5
.internal
.params
import connectPorts
1330 if self
.ccConnected
: # already done this
1333 if not self
.peer
: # nothing to connect to
1336 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1337 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1339 print "Error connecting port %s.%s to %s.%s" % \
1340 (self
.simobj
.path(), self
.name
,
1341 peer
.simobj
.path(), peer
.name
)
1343 self
.ccConnected
= True
1344 peer
.ccConnected
= True
1346 # A reference to an individual element of a VectorPort... much like a
1347 # PortRef, but has an index.
1348 class VectorPortElementRef(PortRef
):
1349 def __init__(self
, simobj
, name
, index
):
1350 PortRef
.__init
__(self
, simobj
, name
)
1354 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1356 # A reference to a complete vector-valued port (not just a single element).
1357 # Can be indexed to retrieve individual VectorPortElementRef instances.
1358 class VectorPortRef(object):
1359 def __init__(self
, simobj
, name
):
1360 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1361 self
.simobj
= simobj
1366 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1368 # for config.ini, print peer's name (not ours)
1370 return ' '.join([el
.ini_str() for el
in self
.elements
])
1372 def __getitem__(self
, key
):
1373 if not isinstance(key
, int):
1374 raise TypeError, "VectorPort index must be integer"
1375 if key
>= len(self
.elements
):
1376 # need to extend list
1377 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1378 for i
in range(len(self
.elements
), key
+1)]
1379 self
.elements
.extend(ext
)
1380 return self
.elements
[key
]
1382 def _get_next(self
):
1383 return self
[len(self
.elements
)]
1385 def __setitem__(self
, key
, value
):
1386 if not isinstance(key
, int):
1387 raise TypeError, "VectorPort index must be integer"
1388 self
[key
].connect(value
)
1390 def connect(self
, other
):
1391 if isinstance(other
, (list, tuple)):
1392 # Assign list of port refs to vector port.
1393 # For now, append them... not sure if that's the right semantics
1394 # or if it should replace the current vector.
1396 self
._get
_next
().connect(ref
)
1398 # scalar assignment to plain VectorPort is implicit append
1399 self
._get
_next
().connect(other
)
1401 def clone(self
, simobj
, memo
):
1402 if memo
.has_key(self
):
1404 newRef
= copy
.copy(self
)
1406 newRef
.simobj
= simobj
1407 assert(isSimObject(newRef
.simobj
))
1408 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1411 def unproxy(self
, simobj
):
1412 [el
.unproxy(simobj
) for el
in self
.elements
]
1414 def ccConnect(self
):
1415 [el
.ccConnect() for el
in self
.elements
]
1417 # Port description object. Like a ParamDesc object, this represents a
1418 # logical port in the SimObject class, not a particular port on a
1419 # SimObject instance. The latter are represented by PortRef objects.
1421 # Port("description") or Port(default, "description")
1422 def __init__(self
, *args
):
1425 elif len(args
) == 2:
1426 self
.default
= args
[0]
1429 raise TypeError, 'wrong number of arguments'
1430 # self.name is set by SimObject class on assignment
1431 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1433 # Generate a PortRef for this port on the given SimObject with the
1435 def makeRef(self
, simobj
):
1436 return PortRef(simobj
, self
.name
)
1438 # Connect an instance of this port (on the given SimObject with
1439 # the given name) with the port described by the supplied PortRef
1440 def connect(self
, simobj
, ref
):
1441 self
.makeRef(simobj
).connect(ref
)
1443 # VectorPort description object. Like Port, but represents a vector
1444 # of connections (e.g., as on a Bus).
1445 class VectorPort(Port
):
1446 def __init__(self
, *args
):
1447 Port
.__init
__(self
, *args
)
1450 def makeRef(self
, simobj
):
1451 return VectorPortRef(simobj
, self
.name
)
1453 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1454 # proxy objects (via set_param_desc()) so that proxy error messages
1456 class PortParamDesc(object):
1457 __metaclass__
= Singleton
1462 baseEnums
= allEnums
.copy()
1463 baseParams
= allParams
.copy()
1466 global allEnums
, allParams
1468 allEnums
= baseEnums
.copy()
1469 allParams
= baseParams
.copy()
1471 __all__
= ['Param', 'VectorParam',
1472 'Enum', 'Bool', 'String', 'Float',
1473 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1474 'Int32', 'UInt32', 'Int64', 'UInt64',
1475 'Counter', 'Addr', 'Tick', 'Percent',
1476 'TcpPort', 'UdpPort', 'EthernetAddr',
1477 'IpAddress', 'IpNetmask', 'IpWithPort',
1478 'MemorySize', 'MemorySize32',
1479 'Latency', 'Frequency', 'Clock',
1480 'NetworkBandwidth', 'MemoryBandwidth',
1481 'Range', 'AddrRange', 'TickRange',
1482 'MaxAddr', 'MaxTick', 'AllMemory',
1484 'NextEthernetAddr', 'NULL',
1485 'Port', 'VectorPort']