1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Steve Reinhardt
30 #####################################################################
32 # Parameter description classes
34 # The _params dictionary in each class maps parameter names to either
35 # a Param or a VectorParam object. These objects contain the
36 # parameter description string, the parameter type, and the default
37 # value (if any). The convert() method on these objects is used to
38 # force whatever value is assigned to the parameter to the appropriate
41 # Note that the default values are loaded into the class's attribute
42 # space when the parameter dictionary is initialized (in
43 # MetaSimObject._new_param()); after that point they aren't used.
45 #####################################################################
47 import sys
, inspect
, copy
51 # Dummy base class to identify types that are legitimate for SimObject
53 class ParamValue(object):
58 # default for printing to .ini file is regular string conversion.
59 # will be overridden in some cases
63 # allows us to blithely call unproxy() on things without checking
64 # if they're really proxies or not
65 def unproxy(self
, base
):
68 # Regular parameter description.
69 class ParamDesc(object):
70 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
71 self
.ptype_str
= ptype_str
72 # remember ptype only if it is provided
80 self
.default
= args
[0]
83 raise TypeError, 'too many arguments'
85 if kwargs
.has_key('desc'):
86 assert(not hasattr(self
, 'desc'))
87 self
.desc
= kwargs
['desc']
90 if kwargs
.has_key('default'):
91 assert(not hasattr(self
, 'default'))
92 self
.default
= kwargs
['default']
96 raise TypeError, 'extra unknown kwargs %s' % kwargs
98 if not hasattr(self
, 'desc'):
99 raise TypeError, 'desc attribute missing'
101 def __getattr__(self
, attr
):
104 ptype
= eval(self
.ptype_str
, objects
.__dict
__)
105 if not isinstance(ptype
, type):
111 "Param qualifier '%s' is not a type" % self
.ptype_str
112 raise AttributeError, "'%s' object has no attribute '%s'" % \
113 (type(self
).__name
__, attr
)
115 def convert(self
, value
):
116 if isinstance(value
, proxy
.BaseProxy
):
117 value
.set_param_desc(self
)
119 if not hasattr(self
, 'ptype') and isNullPointer(value
):
120 # deferred evaluation of SimObject; continue to defer if
121 # we're just assigning a null pointer
123 if isinstance(value
, self
.ptype
):
125 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
127 return self
.ptype(value
)
129 def cxx_predecls(self
):
130 return self
.ptype
.cxx_predecls
132 def swig_predecls(self
):
133 return self
.ptype
.swig_predecls
136 return '%s %s;' % (self
.ptype
.cxx_type
, self
.name
)
138 # Vector-valued parameter description. Just like ParamDesc, except
139 # that the value is a vector (list) of the specified type instead of a
142 class VectorParamValue(list):
144 return ' '.join([v
.ini_str() for v
in self
])
146 def unproxy(self
, base
):
147 return [v
.unproxy(base
) for v
in self
]
149 class SimObjVector(VectorParamValue
):
154 class VectorParamDesc(ParamDesc
):
155 # Convert assigned value to appropriate type. If the RHS is not a
156 # list or tuple, it generates a single-element list.
157 def convert(self
, value
):
158 if isinstance(value
, (list, tuple)):
159 # list: coerce each element into new list
160 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
161 if isSimObjectSequence(tmp_list
):
162 return SimObjVector(tmp_list
)
164 return VectorParamValue(tmp_list
)
166 # singleton: leave it be (could coerce to a single-element
167 # list here, but for some historical reason we don't...
168 return ParamDesc
.convert(self
, value
)
170 def cxx_predecls(self
):
171 return ['#include <vector>'] + self
.ptype
.cxx_predecls
173 def swig_predecls(self
):
174 return ['%include "std_vector.i"'] + self
.ptype
.swig_predecls
177 return 'std::vector< %s > %s;' % (self
.ptype
.cxx_type
, self
.name
)
179 class ParamFactory(object):
180 def __init__(self
, param_desc_class
, ptype_str
= None):
181 self
.param_desc_class
= param_desc_class
182 self
.ptype_str
= ptype_str
184 def __getattr__(self
, attr
):
186 attr
= self
.ptype_str
+ '.' + attr
187 return ParamFactory(self
.param_desc_class
, attr
)
189 # E.g., Param.Int(5, "number of widgets")
190 def __call__(self
, *args
, **kwargs
):
191 caller_frame
= inspect
.currentframe().f_back
194 ptype
= eval(self
.ptype_str
,
195 caller_frame
.f_globals
, caller_frame
.f_locals
)
196 if not isinstance(ptype
, type):
198 "Param qualifier is not a type: %s" % ptype
200 # if name isn't defined yet, assume it's a SimObject, and
201 # try to resolve it later
203 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
205 Param
= ParamFactory(ParamDesc
)
206 VectorParam
= ParamFactory(VectorParamDesc
)
208 #####################################################################
212 # Though native Python types could be used to specify parameter types
213 # (the 'ptype' field of the Param and VectorParam classes), it's more
214 # flexible to define our own set of types. This gives us more control
215 # over how Python expressions are converted to values (via the
216 # __init__() constructor) and how these values are printed out (via
217 # the __str__() conversion method).
219 #####################################################################
221 # String-valued parameter. Just mixin the ParamValue class with the
222 # built-in str class.
223 class String(ParamValue
,str):
224 cxx_type
= 'std::string'
225 cxx_predecls
= ['#include <string>']
226 swig_predecls
= ['%include "std_string.i"\n' +
227 '%apply const std::string& {std::string *};']
230 # superclass for "numeric" parameter values, to emulate math
231 # operations in a type-safe way. e.g., a Latency times an int returns
232 # a new Latency object.
233 class NumericParamValue(ParamValue
):
235 return str(self
.value
)
238 return float(self
.value
)
240 # hook for bounds checking
244 def __mul__(self
, other
):
245 newobj
= self
.__class
__(self
)
246 newobj
.value
*= other
252 def __div__(self
, other
):
253 newobj
= self
.__class
__(self
)
254 newobj
.value
/= other
258 def __sub__(self
, other
):
259 newobj
= self
.__class
__(self
)
260 newobj
.value
-= other
264 # Metaclass for bounds-checked integer parameters. See CheckedInt.
265 class CheckedIntType(type):
266 def __init__(cls
, name
, bases
, dict):
267 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
269 # CheckedInt is an abstract base class, so we actually don't
270 # want to do any processing on it... the rest of this code is
271 # just for classes that derive from CheckedInt.
272 if name
== 'CheckedInt':
275 if not cls
.cxx_predecls
:
276 # most derived types require this, so we just do it here once
277 cls
.cxx_predecls
= ['#include "sim/host.hh"']
279 if not cls
.swig_predecls
:
280 # most derived types require this, so we just do it here once
281 cls
.swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
282 '%import "sim/host.hh"']
284 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
285 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
286 panic("CheckedInt subclass %s must define either\n" \
287 " 'min' and 'max' or 'size' and 'unsigned'\n" \
291 cls
.max = 2 ** cls
.size
- 1
293 cls
.min = -(2 ** (cls
.size
- 1))
294 cls
.max = (2 ** (cls
.size
- 1)) - 1
296 # Abstract superclass for bounds-checked integer parameters. This
297 # class is subclassed to generate parameter classes with specific
298 # bounds. Initialization of the min and max bounds is done in the
299 # metaclass CheckedIntType.__init__.
300 class CheckedInt(NumericParamValue
):
301 __metaclass__
= CheckedIntType
304 if not self
.min <= self
.value
<= self
.max:
305 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
306 (self
.min, self
.value
, self
.max)
308 def __init__(self
, value
):
309 if isinstance(value
, str):
310 self
.value
= convert
.toInteger(value
)
311 elif isinstance(value
, (int, long, float)):
312 self
.value
= long(value
)
315 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
316 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
318 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
319 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
320 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
321 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
322 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
323 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
324 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
325 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
327 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
328 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
329 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
330 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
332 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
334 class Float(ParamValue
, float):
337 class MemorySize(CheckedInt
):
338 cxx_type
= 'uint64_t'
341 def __init__(self
, value
):
342 if isinstance(value
, MemorySize
):
343 self
.value
= value
.value
345 self
.value
= convert
.toMemorySize(value
)
348 class MemorySize32(CheckedInt
):
351 def __init__(self
, value
):
352 if isinstance(value
, MemorySize
):
353 self
.value
= value
.value
355 self
.value
= convert
.toMemorySize(value
)
358 class Addr(CheckedInt
):
360 cxx_predecls
= ['#include "targetarch/isa_traits.hh"']
363 def __init__(self
, value
):
364 if isinstance(value
, Addr
):
365 self
.value
= value
.value
368 self
.value
= convert
.toMemorySize(value
)
370 self
.value
= long(value
)
372 def __add__(self
, other
):
373 if isinstance(other
, Addr
):
374 return self
.value
+ other
.value
376 return self
.value
+ other
379 class MetaRange(type):
380 def __init__(cls
, name
, bases
, dict):
381 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
384 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
386 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
388 class Range(ParamValue
):
389 __metaclass__
= MetaRange
390 type = Int
# default; can be overridden in subclasses
391 def __init__(self
, *args
, **kwargs
):
392 def handle_kwargs(self
, kwargs
):
394 self
.second
= self
.type(kwargs
.pop('end'))
395 elif 'size' in kwargs
:
396 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
398 raise TypeError, "Either end or size must be specified"
401 self
.first
= self
.type(kwargs
.pop('start'))
402 handle_kwargs(self
, kwargs
)
406 self
.first
= self
.type(args
[0])
407 handle_kwargs(self
, kwargs
)
408 elif isinstance(args
[0], Range
):
409 self
.first
= self
.type(args
[0].first
)
410 self
.second
= self
.type(args
[0].second
)
412 self
.first
= self
.type(0)
413 self
.second
= self
.type(args
[0]) - 1
416 self
.first
= self
.type(args
[0])
417 self
.second
= self
.type(args
[1])
419 raise TypeError, "Too many arguments specified"
422 raise TypeError, "too many keywords: %s" % kwargs
.keys()
425 return '%s:%s' % (self
.first
, self
.second
)
427 class AddrRange(Range
):
430 class TickRange(Range
):
433 # Boolean parameter type. Python doesn't let you subclass bool, since
434 # it doesn't want to let you create multiple instances of True and
435 # False. Thus this is a little more complicated than String.
436 class Bool(ParamValue
):
438 def __init__(self
, value
):
440 self
.value
= convert
.toBool(value
)
442 self
.value
= bool(value
)
445 return str(self
.value
)
452 def IncEthernetAddr(addr
, val
= 1):
453 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
455 for i
in (5, 4, 3, 2, 1):
456 val
,rem
= divmod(bytes
[i
], 256)
461 assert(bytes
[0] <= 255)
462 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
464 class NextEthernetAddr(object):
465 addr
= "00:90:00:00:00:01"
467 def __init__(self
, inc
= 1):
468 self
.value
= NextEthernetAddr
.addr
469 NextEthernetAddr
.addr
= IncEthernetAddr(NextEthernetAddr
.addr
, inc
)
471 class EthernetAddr(ParamValue
):
472 cxx_type
= 'Net::EthAddr'
473 cxx_predecls
= ['#include "base/inet.hh"']
474 swig_predecls
= ['class Net::EthAddr;']
475 def __init__(self
, value
):
476 if value
== NextEthernetAddr
:
480 if not isinstance(value
, str):
481 raise TypeError, "expected an ethernet address and didn't get one"
483 bytes
= value
.split(':')
485 raise TypeError, 'invalid ethernet address %s' % value
488 if not 0 <= int(byte
) <= 256:
489 raise TypeError, 'invalid ethernet address %s' % value
493 def unproxy(self
, base
):
494 if self
.value
== NextEthernetAddr
:
495 self
.addr
= self
.value().value
499 if self
.value
== NextEthernetAddr
:
500 if hasattr(self
, 'addr'):
503 return "NextEthernetAddr (unresolved)"
507 # Enumerated types are a little more complex. The user specifies the
508 # type as Enum(foo) where foo is either a list or dictionary of
509 # alternatives (typically strings, but not necessarily so). (In the
510 # long run, the integer value of the parameter will be the list index
511 # or the corresponding dictionary value. For now, since we only check
512 # that the alternative is valid and then spit it into a .ini file,
513 # there's not much point in using the dictionary.)
515 # What Enum() must do is generate a new type encapsulating the
516 # provided list/dictionary so that specific values of the parameter
517 # can be instances of that type. We define two hidden internal
518 # classes (_ListEnum and _DictEnum) to serve as base classes, then
519 # derive the new type from the appropriate base class on the fly.
522 # Metaclass for Enum types
523 class MetaEnum(type):
524 def __init__(cls
, name
, bases
, init_dict
):
525 if init_dict
.has_key('map'):
526 if not isinstance(cls
.map, dict):
527 raise TypeError, "Enum-derived class attribute 'map' " \
528 "must be of type dict"
529 # build list of value strings from map
530 cls
.vals
= cls
.map.keys()
532 elif init_dict
.has_key('vals'):
533 if not isinstance(cls
.vals
, list):
534 raise TypeError, "Enum-derived class attribute 'vals' " \
535 "must be of type list"
536 # build string->value map from vals sequence
538 for idx
,val
in enumerate(cls
.vals
):
541 raise TypeError, "Enum-derived class must define "\
542 "attribute 'map' or 'vals'"
544 cls
.cxx_type
= name
+ '::Enum'
546 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
548 # Generate C++ class declaration for this enum type.
549 # Note that we wrap the enum in a class/struct to act as a namespace,
550 # so that the enum strings can be brief w/o worrying about collisions.
552 s
= 'struct %s {\n enum Enum {\n ' % cls
.__name
__
553 s
+= ',\n '.join(['%s = %d' % (v
,cls
.map[v
]) for v
in cls
.vals
])
557 # Base class for enum types.
558 class Enum(ParamValue
):
559 __metaclass__
= MetaEnum
562 def __init__(self
, value
):
563 if value
not in self
.map:
564 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
573 # how big does a rounding error need to be before we warn about it?
574 frequency_tolerance
= 0.001 # 0.1%
576 # convert a floting-point # of ticks to integer, and warn if rounding
577 # discards too much precision
578 def tick_check(float_ticks
):
581 int_ticks
= int(round(float_ticks
))
582 err
= (float_ticks
- int_ticks
) / float_ticks
583 if err
> frequency_tolerance
:
584 print >> sys
.stderr
, "Warning: rounding error > tolerance"
585 print >> sys
.stderr
, " %f rounded to %d" % (float_ticks
, int_ticks
)
589 def getLatency(value
):
590 if isinstance(value
, Latency
) or isinstance(value
, Clock
):
592 elif isinstance(value
, Frequency
) or isinstance(value
, RootClock
):
593 return 1 / value
.value
594 elif isinstance(value
, str):
596 return convert
.toLatency(value
)
599 return 1 / convert
.toFrequency(value
)
602 raise ValueError, "Invalid Frequency/Latency value '%s'" % value
605 class Latency(NumericParamValue
):
607 cxx_predecls
= ['#include "sim/host.hh"']
608 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
609 '%import "sim/host.hh"']
610 def __init__(self
, value
):
611 self
.value
= getLatency(value
)
613 def __getattr__(self
, attr
):
614 if attr
in ('latency', 'period'):
616 if attr
== 'frequency':
617 return Frequency(self
)
618 raise AttributeError, "Latency object has no attribute '%s'" % attr
620 # convert latency to ticks
622 return str(tick_check(self
.value
* ticks_per_sec
))
624 class Frequency(NumericParamValue
):
626 cxx_predecls
= ['#include "sim/host.hh"']
627 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
628 '%import "sim/host.hh"']
629 def __init__(self
, value
):
630 self
.value
= 1 / getLatency(value
)
632 def __getattr__(self
, attr
):
633 if attr
== 'frequency':
635 if attr
in ('latency', 'period'):
637 raise AttributeError, "Frequency object has no attribute '%s'" % attr
639 # convert frequency to ticks per period
641 return self
.period
.ini_str()
643 # Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
644 # We can't inherit from Frequency because we don't want it to be directly
645 # assignable to a regular Frequency parameter.
646 class RootClock(ParamValue
):
648 cxx_predecls
= ['#include "sim/host.hh"']
649 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
650 '%import "sim/host.hh"']
651 def __init__(self
, value
):
652 self
.value
= 1 / getLatency(value
)
654 def __getattr__(self
, attr
):
655 if attr
== 'frequency':
656 return Frequency(self
)
657 if attr
in ('latency', 'period'):
659 raise AttributeError, "Frequency object has no attribute '%s'" % attr
662 return str(tick_check(self
.value
))
664 # A generic frequency and/or Latency value. Value is stored as a latency,
665 # but to avoid ambiguity this object does not support numeric ops (* or /).
666 # An explicit conversion to a Latency or Frequency must be made first.
667 class Clock(ParamValue
):
669 cxx_predecls
= ['#include "sim/host.hh"']
670 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
671 '%import "sim/host.hh"']
672 def __init__(self
, value
):
673 self
.value
= getLatency(value
)
675 def __getattr__(self
, attr
):
676 if attr
== 'frequency':
677 return Frequency(self
)
678 if attr
in ('latency', 'period'):
680 raise AttributeError, "Frequency object has no attribute '%s'" % attr
683 return self
.period
.ini_str()
685 class NetworkBandwidth(float,ParamValue
):
687 def __new__(cls
, value
):
688 val
= convert
.toNetworkBandwidth(value
) / 8.0
689 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
695 return '%f' % (ticks_per_sec
/ float(self
))
697 class MemoryBandwidth(float,ParamValue
):
699 def __new__(self
, value
):
700 val
= convert
.toMemoryBandwidth(value
)
701 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
707 return '%f' % (ticks_per_sec
/ float(self
))
710 # "Constants"... handy aliases for various values.
713 # Special class for NULL pointers. Note the special check in
714 # make_param_value() above that lets these be assigned where a
715 # SimObject is required.
716 # only one copy of a particular node
717 class NullSimObject(object):
718 __metaclass__
= Singleton
723 def _instantiate(self
, parent
= None, path
= ''):
729 def unproxy(self
, base
):
732 def set_path(self
, parent
, name
):
737 # The only instance you'll ever need...
738 NULL
= NullSimObject()
740 def isNullPointer(value
):
741 return isinstance(value
, NullSimObject
)
743 # Some memory range specifications use this as a default upper bound.
746 AllMemory
= AddrRange(0, MaxAddr
)
749 #####################################################################
753 # Ports are used to interconnect objects in the memory system.
755 #####################################################################
757 # Port reference: encapsulates a reference to a particular port on a
758 # particular SimObject.
759 class PortRef(object):
760 def __init__(self
, simobj
, name
):
761 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
764 self
.peer
= None # not associated with another port yet
765 self
.ccConnected
= False # C++ port connection done?
766 self
.index
= -1 # always -1 for non-vector ports
769 return '%s.%s' % (self
.simobj
, self
.name
)
771 # for config.ini, print peer's name (not ours)
773 return str(self
.peer
)
775 def __getattr__(self
, attr
):
776 if attr
== 'peerObj':
777 # shorthand for proxies
778 return self
.peer
.simobj
779 raise AttributeError, "'%s' object has no attribute '%s'" % \
780 (self
.__class
__.__name
__, attr
)
782 # Full connection is symmetric (both ways). Called via
783 # SimObject.__setattr__ as a result of a port assignment, e.g.,
784 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
785 # e.g., "obj1.portA[3] = obj2.portB".
786 def connect(self
, other
):
787 if isinstance(other
, VectorPortRef
):
788 # reference to plain VectorPort is implicit append
789 other
= other
._get
_next
()
790 if self
.peer
and not proxy
.isproxy(self
.peer
):
791 print "warning: overwriting port", self
, \
792 "value", self
.peer
, "with", other
794 if proxy
.isproxy(other
):
795 other
.set_param_desc(PortParamDesc())
796 elif isinstance(other
, PortRef
):
797 if other
.peer
is not self
:
801 "assigning non-port reference '%s' to port '%s'" \
804 def clone(self
, simobj
, memo
):
805 if memo
.has_key(self
):
807 newRef
= copy
.copy(self
)
809 newRef
.simobj
= simobj
810 assert(isSimObject(newRef
.simobj
))
811 if self
.peer
and not proxy
.isproxy(self
.peer
):
812 peerObj
= self
.peer
.simobj(_memo
=memo
)
813 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
814 assert(not isinstance(newRef
.peer
, VectorPortRef
))
817 def unproxy(self
, simobj
):
818 assert(simobj
is self
.simobj
)
819 if proxy
.isproxy(self
.peer
):
821 realPeer
= self
.peer
.unproxy(self
.simobj
)
823 print "Error in unproxying port '%s' of %s" % \
824 (self
.name
, self
.simobj
.path())
826 self
.connect(realPeer
)
828 # Call C++ to create corresponding port connection between C++ objects
830 if self
.ccConnected
: # already done this
833 internal
.main
.connectPorts(self
.simobj
.getCCObject(), self
.name
,
834 self
.index
, peer
.simobj
.getCCObject(),
835 peer
.name
, peer
.index
)
836 self
.ccConnected
= True
837 peer
.ccConnected
= True
839 # A reference to an individual element of a VectorPort... much like a
840 # PortRef, but has an index.
841 class VectorPortElementRef(PortRef
):
842 def __init__(self
, simobj
, name
, index
):
843 PortRef
.__init
__(self
, simobj
, name
)
847 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
849 # A reference to a complete vector-valued port (not just a single element).
850 # Can be indexed to retrieve individual VectorPortElementRef instances.
851 class VectorPortRef(object):
852 def __init__(self
, simobj
, name
):
853 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
859 return '%s.%s[:]' % (self
.simobj
, self
.name
)
861 # for config.ini, print peer's name (not ours)
863 return ' '.join([el
.ini_str() for el
in self
.elements
])
865 def __getitem__(self
, key
):
866 if not isinstance(key
, int):
867 raise TypeError, "VectorPort index must be integer"
868 if key
>= len(self
.elements
):
869 # need to extend list
870 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
871 for i
in range(len(self
.elements
), key
+1)]
872 self
.elements
.extend(ext
)
873 return self
.elements
[key
]
876 return self
[len(self
.elements
)]
878 def __setitem__(self
, key
, value
):
879 if not isinstance(key
, int):
880 raise TypeError, "VectorPort index must be integer"
881 self
[key
].connect(value
)
883 def connect(self
, other
):
884 if isinstance(other
, (list, tuple)):
885 # Assign list of port refs to vector port.
886 # For now, append them... not sure if that's the right semantics
887 # or if it should replace the current vector.
889 self
._get
_next
().connect(ref
)
891 # scalar assignment to plain VectorPort is implicit append
892 self
._get
_next
().connect(other
)
894 def clone(self
, simobj
, memo
):
895 if memo
.has_key(self
):
897 newRef
= copy
.copy(self
)
899 newRef
.simobj
= simobj
900 assert(isSimObject(newRef
.simobj
))
901 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
904 def unproxy(self
, simobj
):
905 [el
.unproxy(simobj
) for el
in self
.elements
]
908 [el
.ccConnect() for el
in self
.elements
]
910 # Port description object. Like a ParamDesc object, this represents a
911 # logical port in the SimObject class, not a particular port on a
912 # SimObject instance. The latter are represented by PortRef objects.
914 # Port("description") or Port(default, "description")
915 def __init__(self
, *args
):
919 self
.default
= args
[0]
922 raise TypeError, 'wrong number of arguments'
923 # self.name is set by SimObject class on assignment
924 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
926 # Generate a PortRef for this port on the given SimObject with the
928 def makeRef(self
, simobj
):
929 return PortRef(simobj
, self
.name
)
931 # Connect an instance of this port (on the given SimObject with
932 # the given name) with the port described by the supplied PortRef
933 def connect(self
, simobj
, ref
):
934 self
.makeRef(simobj
).connect(ref
)
936 # VectorPort description object. Like Port, but represents a vector
937 # of connections (e.g., as on a Bus).
938 class VectorPort(Port
):
939 def __init__(self
, *args
):
940 Port
.__init
__(self
, *args
)
943 def makeRef(self
, simobj
):
944 return VectorPortRef(simobj
, self
.name
)
946 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
947 # proxy objects (via set_param_desc()) so that proxy error messages
949 class PortParamDesc(object):
950 __metaclass__
= Singleton
956 __all__
= ['Param', 'VectorParam',
957 'Enum', 'Bool', 'String', 'Float',
958 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
959 'Int32', 'UInt32', 'Int64', 'UInt64',
960 'Counter', 'Addr', 'Tick', 'Percent',
961 'TcpPort', 'UdpPort', 'EthernetAddr',
962 'MemorySize', 'MemorySize32',
963 'Latency', 'Frequency', 'RootClock', 'Clock',
964 'NetworkBandwidth', 'MemoryBandwidth',
965 'Range', 'AddrRange', 'TickRange',
966 'MaxAddr', 'MaxTick', 'AllMemory',
967 'NextEthernetAddr', 'NULL',
968 'Port', 'VectorPort']
970 # see comment on imports at end of __init__.py.
971 from SimObject
import isSimObject
, isSimObjectSequence
, isSimObjectClass