86b4b050455cfc1958c2d8e4f40bffe19b7d47c7
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
32 #####################################################################
34 # Parameter description classes
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
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.
47 #####################################################################
60 def isSimObject(*args
, **kwargs
):
61 return SimObject
.isSimObject(*args
, **kwargs
)
63 def isSimObjectSequence(*args
, **kwargs
):
64 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
66 def isSimObjectClass(*args
, **kwargs
):
67 return SimObject
.isSimObjectClass(*args
, **kwargs
)
71 class 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
79 # Dummy base class to identify types that are legitimate for SimObject
81 class ParamValue(object):
82 __metaclass__
= MetaParamValue
85 def cxx_predecls(cls
, code
):
89 def swig_predecls(cls
, code
):
92 # default for printing to .ini file is regular string conversion.
93 # will be overridden in some cases
97 # allows us to blithely call unproxy() on things without checking
98 # if they're really proxies or not
99 def unproxy(self
, base
):
102 # Regular parameter description.
103 class ParamDesc(object):
106 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
107 self
.ptype_str
= ptype_str
108 # remember ptype only if it is provided
116 self
.default
= args
[0]
119 raise TypeError, 'too many arguments'
121 if kwargs
.has_key('desc'):
122 assert(not hasattr(self
, 'desc'))
123 self
.desc
= kwargs
['desc']
126 if kwargs
.has_key('default'):
127 assert(not hasattr(self
, 'default'))
128 self
.default
= kwargs
['default']
129 del kwargs
['default']
132 raise TypeError, 'extra unknown kwargs %s' % kwargs
134 if not hasattr(self
, 'desc'):
135 raise TypeError, 'desc attribute missing'
137 def __getattr__(self
, attr
):
139 ptype
= SimObject
.allClasses
[self
.ptype_str
]
140 assert isSimObjectClass(ptype
)
144 raise AttributeError, "'%s' object has no attribute '%s'" % \
145 (type(self
).__name
__, attr
)
147 def convert(self
, value
):
148 if isinstance(value
, proxy
.BaseProxy
):
149 value
.set_param_desc(self
)
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
155 if isinstance(value
, self
.ptype
):
157 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
159 return self
.ptype(value
)
161 def cxx_predecls(self
, code
):
162 self
.ptype
.cxx_predecls(code
)
164 def swig_predecls(self
, code
):
165 self
.ptype
.swig_predecls(code
)
167 def cxx_decl(self
, code
):
168 code('${{self.ptype.cxx_type}} ${{self.name}};')
170 # Vector-valued parameter description. Just like ParamDesc, except
171 # that the value is a vector (list) of the specified type instead of a
174 class 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
__)
181 return ' '.join([v
.ini_str() for v
in self
])
184 return [ v
.getValue() for v
in self
]
186 def unproxy(self
, base
):
187 return [v
.unproxy(base
) for v
in self
]
189 class SimObjectVector(VectorParamValue
):
190 # support clone operation
191 def __call__(self
, **kwargs
):
192 return SimObjectVector([v(**kwargs
) for v
in self
])
194 def clear_parent(self
, old_parent
):
196 v
.clear_parent(old_parent
)
198 def set_parent(self
, parent
, name
):
200 self
[0].set_parent(parent
, name
)
202 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
203 for i
,v
in enumerate(self
):
204 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
206 def has_parent(self
):
207 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
209 # return 'cpu0 cpu1' etc. for print_ini()
211 return ' '.join([v
._name
for v
in self
])
213 # By iterating through the constituent members of the vector here
214 # we can nicely handle iterating over all a SimObject's children
215 # without having to provide lots of special functions on
216 # SimObjectVector directly.
217 def descendants(self
):
219 for obj
in v
.descendants():
222 class VectorParamDesc(ParamDesc
):
225 # Convert assigned value to appropriate type. If the RHS is not a
226 # list or tuple, it generates a single-element list.
227 def convert(self
, value
):
228 if isinstance(value
, (list, tuple)):
229 # list: coerce each element into new list
230 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
232 # singleton: coerce to a single-element list
233 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
235 if isSimObjectSequence(tmp_list
):
236 return SimObjectVector(tmp_list
)
238 return VectorParamValue(tmp_list
)
240 def swig_predecls(self
, code
):
241 code('%import "vptype_${{self.ptype_str}}.i"')
243 def swig_decl(self
, code
):
245 self
.ptype
.cxx_predecls(code
)
248 self
.ptype
.swig_predecls(code
)
250 code('%include "std_vector.i"')
253 ptype
= self
.ptype_str
254 cxx_type
= self
.ptype
.cxx_type
257 %typemap(in) std::vector< $cxx_type >::value_type {
258 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
259 if (SWIG_ConvertPtr($$input, (void **)&$$1,
260 $$descriptor($cxx_type), 0) == -1) {
266 %typemap(in) std::vector< $cxx_type >::value_type * {
267 if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
268 if (SWIG_ConvertPtr($$input, (void **)&$$1,
269 $$descriptor($cxx_type *), 0) == -1) {
276 code('%template(vector_$ptype) std::vector< $cxx_type >;')
278 def cxx_predecls(self
, code
):
279 code('#include <vector>')
280 self
.ptype
.cxx_predecls(code
)
282 def cxx_decl(self
, code
):
283 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
285 class ParamFactory(object):
286 def __init__(self
, param_desc_class
, ptype_str
= None):
287 self
.param_desc_class
= param_desc_class
288 self
.ptype_str
= ptype_str
290 def __getattr__(self
, attr
):
292 attr
= self
.ptype_str
+ '.' + attr
293 return ParamFactory(self
.param_desc_class
, attr
)
295 # E.g., Param.Int(5, "number of widgets")
296 def __call__(self
, *args
, **kwargs
):
299 ptype
= allParams
[self
.ptype_str
]
301 # if name isn't defined yet, assume it's a SimObject, and
302 # try to resolve it later
304 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
306 Param
= ParamFactory(ParamDesc
)
307 VectorParam
= ParamFactory(VectorParamDesc
)
309 #####################################################################
313 # Though native Python types could be used to specify parameter types
314 # (the 'ptype' field of the Param and VectorParam classes), it's more
315 # flexible to define our own set of types. This gives us more control
316 # over how Python expressions are converted to values (via the
317 # __init__() constructor) and how these values are printed out (via
318 # the __str__() conversion method).
320 #####################################################################
322 # String-valued parameter. Just mixin the ParamValue class with the
323 # built-in str class.
324 class String(ParamValue
,str):
325 cxx_type
= 'std::string'
328 def cxx_predecls(self
, code
):
329 code('#include <string>')
332 def swig_predecls(cls
, code
):
333 code('%include "std_string.i"')
338 # superclass for "numeric" parameter values, to emulate math
339 # operations in a type-safe way. e.g., a Latency times an int returns
340 # a new Latency object.
341 class NumericParamValue(ParamValue
):
343 return str(self
.value
)
346 return float(self
.value
)
349 return long(self
.value
)
352 return int(self
.value
)
354 # hook for bounds checking
358 def __mul__(self
, other
):
359 newobj
= self
.__class
__(self
)
360 newobj
.value
*= other
366 def __div__(self
, other
):
367 newobj
= self
.__class
__(self
)
368 newobj
.value
/= other
372 def __sub__(self
, other
):
373 newobj
= self
.__class
__(self
)
374 newobj
.value
-= other
378 # Metaclass for bounds-checked integer parameters. See CheckedInt.
379 class CheckedIntType(MetaParamValue
):
380 def __init__(cls
, name
, bases
, dict):
381 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
383 # CheckedInt is an abstract base class, so we actually don't
384 # want to do any processing on it... the rest of this code is
385 # just for classes that derive from CheckedInt.
386 if name
== 'CheckedInt':
389 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
390 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
391 panic("CheckedInt subclass %s must define either\n" \
392 " 'min' and 'max' or 'size' and 'unsigned'\n",
396 cls
.max = 2 ** cls
.size
- 1
398 cls
.min = -(2 ** (cls
.size
- 1))
399 cls
.max = (2 ** (cls
.size
- 1)) - 1
401 # Abstract superclass for bounds-checked integer parameters. This
402 # class is subclassed to generate parameter classes with specific
403 # bounds. Initialization of the min and max bounds is done in the
404 # metaclass CheckedIntType.__init__.
405 class CheckedInt(NumericParamValue
):
406 __metaclass__
= CheckedIntType
409 if not self
.min <= self
.value
<= self
.max:
410 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
411 (self
.min, self
.value
, self
.max)
413 def __init__(self
, value
):
414 if isinstance(value
, str):
415 self
.value
= convert
.toInteger(value
)
416 elif isinstance(value
, (int, long, float, NumericParamValue
)):
417 self
.value
= long(value
)
419 raise TypeError, "Can't convert object of type %s to CheckedInt" \
420 % type(value
).__name
__
424 def cxx_predecls(cls
, code
):
425 # most derived types require this, so we just do it here once
426 code('#include "base/types.hh"')
429 def swig_predecls(cls
, code
):
430 # most derived types require this, so we just do it here once
431 code('%import "stdint.i"')
432 code('%import "base/types.hh"')
435 return long(self
.value
)
437 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
438 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
440 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
441 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
442 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
443 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
444 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
445 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
446 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
447 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
449 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
450 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
451 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
452 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
454 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
456 class Float(ParamValue
, float):
459 def __init__(self
, value
):
460 if isinstance(value
, (int, long, float, NumericParamValue
, Float
)):
461 self
.value
= float(value
)
463 raise TypeError, "Can't convert object of type %s to Float" \
464 % type(value
).__name
__
467 return float(self
.value
)
469 class MemorySize(CheckedInt
):
470 cxx_type
= 'uint64_t'
473 def __init__(self
, value
):
474 if isinstance(value
, MemorySize
):
475 self
.value
= value
.value
477 self
.value
= convert
.toMemorySize(value
)
480 class MemorySize32(CheckedInt
):
481 cxx_type
= 'uint32_t'
484 def __init__(self
, value
):
485 if isinstance(value
, MemorySize
):
486 self
.value
= value
.value
488 self
.value
= convert
.toMemorySize(value
)
491 class Addr(CheckedInt
):
495 def __init__(self
, value
):
496 if isinstance(value
, Addr
):
497 self
.value
= value
.value
500 self
.value
= convert
.toMemorySize(value
)
502 self
.value
= long(value
)
504 def __add__(self
, other
):
505 if isinstance(other
, Addr
):
506 return self
.value
+ other
.value
508 return self
.value
+ other
511 class MetaRange(MetaParamValue
):
512 def __init__(cls
, name
, bases
, dict):
513 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
516 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
518 class Range(ParamValue
):
519 __metaclass__
= MetaRange
520 type = Int
# default; can be overridden in subclasses
521 def __init__(self
, *args
, **kwargs
):
522 def handle_kwargs(self
, kwargs
):
524 self
.second
= self
.type(kwargs
.pop('end'))
525 elif 'size' in kwargs
:
526 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
528 raise TypeError, "Either end or size must be specified"
531 self
.first
= self
.type(kwargs
.pop('start'))
532 handle_kwargs(self
, kwargs
)
536 self
.first
= self
.type(args
[0])
537 handle_kwargs(self
, kwargs
)
538 elif isinstance(args
[0], Range
):
539 self
.first
= self
.type(args
[0].first
)
540 self
.second
= self
.type(args
[0].second
)
541 elif isinstance(args
[0], (list, tuple)):
542 self
.first
= self
.type(args
[0][0])
543 self
.second
= self
.type(args
[0][1])
545 self
.first
= self
.type(0)
546 self
.second
= self
.type(args
[0]) - 1
549 self
.first
= self
.type(args
[0])
550 self
.second
= self
.type(args
[1])
552 raise TypeError, "Too many arguments specified"
555 raise TypeError, "too many keywords: %s" % kwargs
.keys()
558 return '%s:%s' % (self
.first
, self
.second
)
561 def cxx_predecls(cls
, code
):
562 cls
.type.cxx_predecls(code
)
563 code('#include "base/range.hh"')
566 def swig_predecls(cls
, code
):
567 cls
.type.swig_predecls(code
)
568 code('%import "python/swig/range.i"')
570 class AddrRange(Range
):
574 from m5
.internal
.range import AddrRange
577 value
.start
= long(self
.first
)
578 value
.end
= long(self
.second
)
581 class TickRange(Range
):
585 from m5
.internal
.range import TickRange
588 value
.start
= long(self
.first
)
589 value
.end
= long(self
.second
)
592 # Boolean parameter type. Python doesn't let you subclass bool, since
593 # it doesn't want to let you create multiple instances of True and
594 # False. Thus this is a little more complicated than String.
595 class Bool(ParamValue
):
597 def __init__(self
, value
):
599 self
.value
= convert
.toBool(value
)
601 self
.value
= bool(value
)
604 return bool(self
.value
)
607 return str(self
.value
)
614 def IncEthernetAddr(addr
, val
= 1):
615 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
617 for i
in (5, 4, 3, 2, 1):
618 val
,rem
= divmod(bytes
[i
], 256)
623 assert(bytes
[0] <= 255)
624 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
626 _NextEthernetAddr
= "00:90:00:00:00:01"
627 def NextEthernetAddr():
628 global _NextEthernetAddr
630 value
= _NextEthernetAddr
631 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
634 class EthernetAddr(ParamValue
):
635 cxx_type
= 'Net::EthAddr'
638 def cxx_predecls(cls
, code
):
639 code('#include "base/inet.hh"')
642 def swig_predecls(cls
, code
):
643 code('%include "python/swig/inet.i"')
645 def __init__(self
, value
):
646 if value
== NextEthernetAddr
:
650 if not isinstance(value
, str):
651 raise TypeError, "expected an ethernet address and didn't get one"
653 bytes
= value
.split(':')
655 raise TypeError, 'invalid ethernet address %s' % value
658 if not 0 <= int(byte
) <= 0xff:
659 raise TypeError, 'invalid ethernet address %s' % value
663 def unproxy(self
, base
):
664 if self
.value
== NextEthernetAddr
:
665 return EthernetAddr(self
.value())
669 from m5
.internal
.params
import EthAddr
670 return EthAddr(self
.value
)
675 # When initializing an IpAddress, pass in an existing IpAddress, a string of
676 # the form "a.b.c.d", or an integer representing an IP.
677 class IpAddress(ParamValue
):
678 cxx_type
= 'Net::IpAddress'
681 def cxx_predecls(cls
, code
):
682 code('#include "base/inet.hh"')
685 def swig_predecls(cls
, code
):
686 code('%include "python/swig/inet.i"')
688 def __init__(self
, value
):
689 if isinstance(value
, IpAddress
):
693 self
.ip
= convert
.toIpAddress(value
)
695 self
.ip
= long(value
)
699 if self
.ip
< 0 or self
.ip
>= (1 << 32):
700 raise TypeError, "invalid ip address %#08x" % self
.ip
703 from m5
.internal
.params
import IpAddress
704 return IpAddress(self
.ip
)
709 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
710 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
711 # positional or keyword arguments.
712 class IpNetmask(IpAddress
):
713 cxx_type
= 'Net::IpNetmask'
716 def cxx_predecls(cls
, code
):
717 code('#include "base/inet.hh"')
720 def swig_predecls(cls
, code
):
721 code('%include "python/swig/inet.i"')
723 def __init__(self
, *args
, **kwargs
):
724 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
726 setattr(self
, key
, kwargs
.pop(key
))
728 setattr(self
, key
, elseVal
)
730 raise TypeError, "No value set for %s" % key
733 handle_kwarg(self
, kwargs
, 'ip')
734 handle_kwarg(self
, kwargs
, 'netmask')
738 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
739 raise TypeError, "Invalid arguments"
740 handle_kwarg(self
, kwargs
, 'ip', args
[0])
741 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
742 elif isinstance(args
[0], IpNetmask
):
744 self
.netmask
= args
[0].netmask
746 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
750 self
.netmask
= args
[1]
752 raise TypeError, "Too many arguments specified"
755 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
761 if self
.netmask
< 0 or self
.netmask
> 32:
762 raise TypeError, "invalid netmask %d" % netmask
765 from m5
.internal
.params
import IpNetmask
766 return IpNetmask(self
.ip
, self
.netmask
)
769 return "%08x/%d" % (self
.ip
, self
.netmask
)
771 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
772 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
773 class IpWithPort(IpAddress
):
774 cxx_type
= 'Net::IpWithPort'
777 def cxx_predecls(cls
, code
):
778 code('#include "base/inet.hh"')
781 def swig_predecls(cls
, code
):
782 code('%include "python/swig/inet.i"')
784 def __init__(self
, *args
, **kwargs
):
785 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
787 setattr(self
, key
, kwargs
.pop(key
))
789 setattr(self
, key
, elseVal
)
791 raise TypeError, "No value set for %s" % key
794 handle_kwarg(self
, kwargs
, 'ip')
795 handle_kwarg(self
, kwargs
, 'port')
799 if not 'ip' in kwargs
and not 'port' in kwargs
:
800 raise TypeError, "Invalid arguments"
801 handle_kwarg(self
, kwargs
, 'ip', args
[0])
802 handle_kwarg(self
, kwargs
, 'port', args
[0])
803 elif isinstance(args
[0], IpWithPort
):
805 self
.port
= args
[0].port
807 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
813 raise TypeError, "Too many arguments specified"
816 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
822 if self
.port
< 0 or self
.port
> 0xffff:
823 raise TypeError, "invalid port %d" % self
.port
826 from m5
.internal
.params
import IpWithPort
827 return IpWithPort(self
.ip
, self
.port
)
830 return "%08x:%d" % (self
.ip
, self
.port
)
832 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
833 "%a %b %d %H:%M:%S %Z %Y",
845 def parse_time(value
):
846 from time
import gmtime
, strptime
, struct_time
, time
847 from datetime
import datetime
, date
849 if isinstance(value
, struct_time
):
852 if isinstance(value
, (int, long)):
855 if isinstance(value
, (datetime
, date
)):
856 return value
.timetuple()
858 if isinstance(value
, str):
859 if value
in ('Now', 'Today'):
860 return time
.gmtime(time
.time())
862 for format
in time_formats
:
864 return strptime(value
, format
)
868 raise ValueError, "Could not parse '%s' as a time" % value
870 class Time(ParamValue
):
874 def cxx_predecls(cls
, code
):
875 code('#include <time.h>')
878 def swig_predecls(cls
, code
):
879 code('%include "python/swig/time.i"')
881 def __init__(self
, value
):
882 self
.value
= parse_time(value
)
885 from m5
.internal
.params
import tm
890 # UNIX is years since 1900
891 c_time
.tm_year
= py_time
.tm_year
- 1900;
893 # Python starts at 1, UNIX starts at 0
894 c_time
.tm_mon
= py_time
.tm_mon
- 1;
895 c_time
.tm_mday
= py_time
.tm_mday
;
896 c_time
.tm_hour
= py_time
.tm_hour
;
897 c_time
.tm_min
= py_time
.tm_min
;
898 c_time
.tm_sec
= py_time
.tm_sec
;
900 # Python has 0 as Monday, UNIX is 0 as sunday
901 c_time
.tm_wday
= py_time
.tm_wday
+ 1
902 if c_time
.tm_wday
> 6:
905 # Python starts at 1, Unix starts at 0
906 c_time
.tm_yday
= py_time
.tm_yday
- 1;
911 return time
.asctime(self
.value
)
916 # Enumerated types are a little more complex. The user specifies the
917 # type as Enum(foo) where foo is either a list or dictionary of
918 # alternatives (typically strings, but not necessarily so). (In the
919 # long run, the integer value of the parameter will be the list index
920 # or the corresponding dictionary value. For now, since we only check
921 # that the alternative is valid and then spit it into a .ini file,
922 # there's not much point in using the dictionary.)
924 # What Enum() must do is generate a new type encapsulating the
925 # provided list/dictionary so that specific values of the parameter
926 # can be instances of that type. We define two hidden internal
927 # classes (_ListEnum and _DictEnum) to serve as base classes, then
928 # derive the new type from the appropriate base class on the fly.
931 # Metaclass for Enum types
932 class MetaEnum(MetaParamValue
):
933 def __new__(mcls
, name
, bases
, dict):
934 assert name
not in allEnums
936 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
940 def __init__(cls
, name
, bases
, init_dict
):
941 if init_dict
.has_key('map'):
942 if not isinstance(cls
.map, dict):
943 raise TypeError, "Enum-derived class attribute 'map' " \
944 "must be of type dict"
945 # build list of value strings from map
946 cls
.vals
= cls
.map.keys()
948 elif init_dict
.has_key('vals'):
949 if not isinstance(cls
.vals
, list):
950 raise TypeError, "Enum-derived class attribute 'vals' " \
951 "must be of type list"
952 # build string->value map from vals sequence
954 for idx
,val
in enumerate(cls
.vals
):
957 raise TypeError, "Enum-derived class must define "\
958 "attribute 'map' or 'vals'"
960 cls
.cxx_type
= 'Enums::%s' % name
962 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
964 # Generate C++ class declaration for this enum type.
965 # Note that we wrap the enum in a class/struct to act as a namespace,
966 # so that the enum strings can be brief w/o worrying about collisions.
967 def cxx_decl(cls
, code
):
970 #ifndef __ENUM__${name}__
971 #define __ENUM__${name}__
978 code('$val = ${{cls.map[val]}},')
979 code('Num_$name = ${{len(cls.vals)}},')
983 extern const char *${name}Strings[Num_${name}];
986 #endif // __ENUM__${name}__
989 def cxx_def(cls
, code
):
992 #include "enums/$name.hh"
994 const char *${name}Strings[Num_${name}] =
1003 } // namespace Enums
1006 # Base class for enum types.
1007 class Enum(ParamValue
):
1008 __metaclass__
= MetaEnum
1011 def __init__(self
, value
):
1012 if value
not in self
.map:
1013 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1014 % (value
, self
.vals
)
1018 def cxx_predecls(cls
, code
):
1019 code('#include "enums/$0.hh"', cls
.__name
__)
1022 def swig_predecls(cls
, code
):
1023 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1026 return int(self
.map[self
.value
])
1031 # how big does a rounding error need to be before we warn about it?
1032 frequency_tolerance
= 0.001 # 0.1%
1034 class TickParamValue(NumericParamValue
):
1038 def cxx_predecls(cls
, code
):
1039 code('#include "base/types.hh"')
1042 def swig_predecls(cls
, code
):
1043 code('%import "stdint.i"')
1044 code('%import "base/types.hh"')
1047 return long(self
.value
)
1049 class Latency(TickParamValue
):
1050 def __init__(self
, value
):
1051 if isinstance(value
, (Latency
, Clock
)):
1052 self
.ticks
= value
.ticks
1053 self
.value
= value
.value
1054 elif isinstance(value
, Frequency
):
1055 self
.ticks
= value
.ticks
1056 self
.value
= 1.0 / value
.value
1057 elif value
.endswith('t'):
1059 self
.value
= int(value
[:-1])
1062 self
.value
= convert
.toLatency(value
)
1064 def __getattr__(self
, attr
):
1065 if attr
in ('latency', 'period'):
1067 if attr
== 'frequency':
1068 return Frequency(self
)
1069 raise AttributeError, "Latency object has no attribute '%s'" % attr
1072 if self
.ticks
or self
.value
== 0:
1075 value
= ticks
.fromSeconds(self
.value
)
1078 # convert latency to ticks
1080 return '%d' % self
.getValue()
1082 class Frequency(TickParamValue
):
1083 def __init__(self
, value
):
1084 if isinstance(value
, (Latency
, Clock
)):
1085 if value
.value
== 0:
1088 self
.value
= 1.0 / value
.value
1089 self
.ticks
= value
.ticks
1090 elif isinstance(value
, Frequency
):
1091 self
.value
= value
.value
1092 self
.ticks
= value
.ticks
1095 self
.value
= convert
.toFrequency(value
)
1097 def __getattr__(self
, attr
):
1098 if attr
== 'frequency':
1100 if attr
in ('latency', 'period'):
1101 return Latency(self
)
1102 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1104 # convert latency to ticks
1106 if self
.ticks
or self
.value
== 0:
1109 value
= ticks
.fromSeconds(1.0 / self
.value
)
1113 return '%d' % self
.getValue()
1115 # A generic frequency and/or Latency value. Value is stored as a latency,
1116 # but to avoid ambiguity this object does not support numeric ops (* or /).
1117 # An explicit conversion to a Latency or Frequency must be made first.
1118 class Clock(ParamValue
):
1122 def cxx_predecls(cls
, code
):
1123 code('#include "base/types.hh"')
1126 def swig_predecls(cls
, code
):
1127 code('%import "stdint.i"')
1128 code('%import "base/types.hh"')
1130 def __init__(self
, value
):
1131 if isinstance(value
, (Latency
, Clock
)):
1132 self
.ticks
= value
.ticks
1133 self
.value
= value
.value
1134 elif isinstance(value
, Frequency
):
1135 self
.ticks
= value
.ticks
1136 self
.value
= 1.0 / value
.value
1137 elif value
.endswith('t'):
1139 self
.value
= int(value
[:-1])
1142 self
.value
= convert
.anyToLatency(value
)
1144 def __getattr__(self
, attr
):
1145 if attr
== 'frequency':
1146 return Frequency(self
)
1147 if attr
in ('latency', 'period'):
1148 return Latency(self
)
1149 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1152 return self
.period
.getValue()
1155 return self
.period
.ini_str()
1157 class NetworkBandwidth(float,ParamValue
):
1159 def __new__(cls
, value
):
1160 # convert to bits per second
1161 val
= convert
.toNetworkBandwidth(value
)
1162 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1165 return str(self
.val
)
1168 # convert to seconds per byte
1169 value
= 8.0 / float(self
)
1170 # convert to ticks per byte
1171 value
= ticks
.fromSeconds(value
)
1175 return '%f' % self
.getValue()
1177 class MemoryBandwidth(float,ParamValue
):
1179 def __new__(cls
, value
):
1180 # convert to bytes per second
1181 val
= convert
.toMemoryBandwidth(value
)
1182 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1185 return str(self
.val
)
1188 # convert to seconds per byte
1191 value
= 1.0 / float(self
)
1192 # convert to ticks per byte
1193 value
= ticks
.fromSeconds(value
)
1197 return '%f' % self
.getValue()
1200 # "Constants"... handy aliases for various values.
1203 # Special class for NULL pointers. Note the special check in
1204 # make_param_value() above that lets these be assigned where a
1205 # SimObject is required.
1206 # only one copy of a particular node
1207 class NullSimObject(object):
1208 __metaclass__
= Singleton
1213 def _instantiate(self
, parent
= None, path
= ''):
1219 def unproxy(self
, base
):
1222 def set_path(self
, parent
, name
):
1231 # The only instance you'll ever need...
1232 NULL
= NullSimObject()
1234 def isNullPointer(value
):
1235 return isinstance(value
, NullSimObject
)
1237 # Some memory range specifications use this as a default upper bound.
1240 AllMemory
= AddrRange(0, MaxAddr
)
1243 #####################################################################
1247 # Ports are used to interconnect objects in the memory system.
1249 #####################################################################
1251 # Port reference: encapsulates a reference to a particular port on a
1252 # particular SimObject.
1253 class PortRef(object):
1254 def __init__(self
, simobj
, name
):
1255 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1256 self
.simobj
= simobj
1258 self
.peer
= None # not associated with another port yet
1259 self
.ccConnected
= False # C++ port connection done?
1260 self
.index
= -1 # always -1 for non-vector ports
1263 return '%s.%s' % (self
.simobj
, self
.name
)
1265 # for config.ini, print peer's name (not ours)
1267 return str(self
.peer
)
1269 def __getattr__(self
, attr
):
1270 if attr
== 'peerObj':
1271 # shorthand for proxies
1272 return self
.peer
.simobj
1273 raise AttributeError, "'%s' object has no attribute '%s'" % \
1274 (self
.__class
__.__name
__, attr
)
1276 # Full connection is symmetric (both ways). Called via
1277 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1278 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1279 # e.g., "obj1.portA[3] = obj2.portB".
1280 def connect(self
, other
):
1281 if isinstance(other
, VectorPortRef
):
1282 # reference to plain VectorPort is implicit append
1283 other
= other
._get
_next
()
1284 if self
.peer
and not proxy
.isproxy(self
.peer
):
1285 print "warning: overwriting port", self
, \
1286 "value", self
.peer
, "with", other
1287 self
.peer
.peer
= None
1289 if proxy
.isproxy(other
):
1290 other
.set_param_desc(PortParamDesc())
1291 elif isinstance(other
, PortRef
):
1292 if other
.peer
is not self
:
1296 "assigning non-port reference '%s' to port '%s'" \
1299 def clone(self
, simobj
, memo
):
1300 if memo
.has_key(self
):
1302 newRef
= copy
.copy(self
)
1304 newRef
.simobj
= simobj
1305 assert(isSimObject(newRef
.simobj
))
1306 if self
.peer
and not proxy
.isproxy(self
.peer
):
1307 peerObj
= self
.peer
.simobj(_memo
=memo
)
1308 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1309 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1312 def unproxy(self
, simobj
):
1313 assert(simobj
is self
.simobj
)
1314 if proxy
.isproxy(self
.peer
):
1316 realPeer
= self
.peer
.unproxy(self
.simobj
)
1318 print "Error in unproxying port '%s' of %s" % \
1319 (self
.name
, self
.simobj
.path())
1321 self
.connect(realPeer
)
1323 # Call C++ to create corresponding port connection between C++ objects
1324 def ccConnect(self
):
1325 from m5
.internal
.params
import connectPorts
1327 if self
.ccConnected
: # already done this
1330 if not self
.peer
: # nothing to connect to
1333 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1334 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1336 print "Error connecting port %s.%s to %s.%s" % \
1337 (self
.simobj
.path(), self
.name
,
1338 peer
.simobj
.path(), peer
.name
)
1340 self
.ccConnected
= True
1341 peer
.ccConnected
= True
1343 # A reference to an individual element of a VectorPort... much like a
1344 # PortRef, but has an index.
1345 class VectorPortElementRef(PortRef
):
1346 def __init__(self
, simobj
, name
, index
):
1347 PortRef
.__init
__(self
, simobj
, name
)
1351 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1353 # A reference to a complete vector-valued port (not just a single element).
1354 # Can be indexed to retrieve individual VectorPortElementRef instances.
1355 class VectorPortRef(object):
1356 def __init__(self
, simobj
, name
):
1357 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1358 self
.simobj
= simobj
1363 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1365 # for config.ini, print peer's name (not ours)
1367 return ' '.join([el
.ini_str() for el
in self
.elements
])
1369 def __getitem__(self
, key
):
1370 if not isinstance(key
, int):
1371 raise TypeError, "VectorPort index must be integer"
1372 if key
>= len(self
.elements
):
1373 # need to extend list
1374 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
1375 for i
in range(len(self
.elements
), key
+1)]
1376 self
.elements
.extend(ext
)
1377 return self
.elements
[key
]
1379 def _get_next(self
):
1380 return self
[len(self
.elements
)]
1382 def __setitem__(self
, key
, value
):
1383 if not isinstance(key
, int):
1384 raise TypeError, "VectorPort index must be integer"
1385 self
[key
].connect(value
)
1387 def connect(self
, other
):
1388 if isinstance(other
, (list, tuple)):
1389 # Assign list of port refs to vector port.
1390 # For now, append them... not sure if that's the right semantics
1391 # or if it should replace the current vector.
1393 self
._get
_next
().connect(ref
)
1395 # scalar assignment to plain VectorPort is implicit append
1396 self
._get
_next
().connect(other
)
1398 def clone(self
, simobj
, memo
):
1399 if memo
.has_key(self
):
1401 newRef
= copy
.copy(self
)
1403 newRef
.simobj
= simobj
1404 assert(isSimObject(newRef
.simobj
))
1405 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1408 def unproxy(self
, simobj
):
1409 [el
.unproxy(simobj
) for el
in self
.elements
]
1411 def ccConnect(self
):
1412 [el
.ccConnect() for el
in self
.elements
]
1414 # Port description object. Like a ParamDesc object, this represents a
1415 # logical port in the SimObject class, not a particular port on a
1416 # SimObject instance. The latter are represented by PortRef objects.
1418 # Port("description") or Port(default, "description")
1419 def __init__(self
, *args
):
1422 elif len(args
) == 2:
1423 self
.default
= args
[0]
1426 raise TypeError, 'wrong number of arguments'
1427 # self.name is set by SimObject class on assignment
1428 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1430 # Generate a PortRef for this port on the given SimObject with the
1432 def makeRef(self
, simobj
):
1433 return PortRef(simobj
, self
.name
)
1435 # Connect an instance of this port (on the given SimObject with
1436 # the given name) with the port described by the supplied PortRef
1437 def connect(self
, simobj
, ref
):
1438 self
.makeRef(simobj
).connect(ref
)
1440 # VectorPort description object. Like Port, but represents a vector
1441 # of connections (e.g., as on a Bus).
1442 class VectorPort(Port
):
1443 def __init__(self
, *args
):
1444 Port
.__init
__(self
, *args
)
1447 def makeRef(self
, simobj
):
1448 return VectorPortRef(simobj
, self
.name
)
1450 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1451 # proxy objects (via set_param_desc()) so that proxy error messages
1453 class PortParamDesc(object):
1454 __metaclass__
= Singleton
1459 baseEnums
= allEnums
.copy()
1460 baseParams
= allParams
.copy()
1463 global allEnums
, allParams
1465 allEnums
= baseEnums
.copy()
1466 allParams
= baseParams
.copy()
1468 __all__
= ['Param', 'VectorParam',
1469 'Enum', 'Bool', 'String', 'Float',
1470 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1471 'Int32', 'UInt32', 'Int64', 'UInt64',
1472 'Counter', 'Addr', 'Tick', 'Percent',
1473 'TcpPort', 'UdpPort', 'EthernetAddr',
1474 'IpAddress', 'IpNetmask', 'IpWithPort',
1475 'MemorySize', 'MemorySize32',
1476 'Latency', 'Frequency', 'Clock',
1477 'NetworkBandwidth', 'MemoryBandwidth',
1478 'Range', 'AddrRange', 'TickRange',
1479 'MaxAddr', 'MaxTick', 'AllMemory',
1481 'NextEthernetAddr', 'NULL',
1482 'Port', 'VectorPort']