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
)
374 class MetaRange(type):
375 def __init__(cls
, name
, bases
, dict):
376 super(MetaRange
, cls
).__init
__(name
, bases
, dict)
379 cls
.cxx_type
= 'Range< %s >' % cls
.type.cxx_type
381 ['#include "base/range.hh"'] + cls
.type.cxx_predecls
383 class Range(ParamValue
):
384 __metaclass__
= MetaRange
385 type = Int
# default; can be overridden in subclasses
386 def __init__(self
, *args
, **kwargs
):
387 def handle_kwargs(self
, kwargs
):
389 self
.second
= self
.type(kwargs
.pop('end'))
390 elif 'size' in kwargs
:
391 self
.second
= self
.first
+ self
.type(kwargs
.pop('size')) - 1
393 raise TypeError, "Either end or size must be specified"
396 self
.first
= self
.type(kwargs
.pop('start'))
397 handle_kwargs(self
, kwargs
)
401 self
.first
= self
.type(args
[0])
402 handle_kwargs(self
, kwargs
)
403 elif isinstance(args
[0], Range
):
404 self
.first
= self
.type(args
[0].first
)
405 self
.second
= self
.type(args
[0].second
)
407 self
.first
= self
.type(0)
408 self
.second
= self
.type(args
[0]) - 1
411 self
.first
= self
.type(args
[0])
412 self
.second
= self
.type(args
[1])
414 raise TypeError, "Too many arguments specified"
417 raise TypeError, "too many keywords: %s" % kwargs
.keys()
420 return '%s:%s' % (self
.first
, self
.second
)
422 class AddrRange(Range
):
425 class TickRange(Range
):
428 # Boolean parameter type. Python doesn't let you subclass bool, since
429 # it doesn't want to let you create multiple instances of True and
430 # False. Thus this is a little more complicated than String.
431 class Bool(ParamValue
):
433 def __init__(self
, value
):
435 self
.value
= convert
.toBool(value
)
437 self
.value
= bool(value
)
440 return str(self
.value
)
447 def IncEthernetAddr(addr
, val
= 1):
448 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
450 for i
in (5, 4, 3, 2, 1):
451 val
,rem
= divmod(bytes
[i
], 256)
456 assert(bytes
[0] <= 255)
457 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
459 class NextEthernetAddr(object):
460 addr
= "00:90:00:00:00:01"
462 def __init__(self
, inc
= 1):
463 self
.value
= NextEthernetAddr
.addr
464 NextEthernetAddr
.addr
= IncEthernetAddr(NextEthernetAddr
.addr
, inc
)
466 class EthernetAddr(ParamValue
):
467 cxx_type
= 'Net::EthAddr'
468 cxx_predecls
= ['#include "base/inet.hh"']
469 swig_predecls
= ['class Net::EthAddr;']
470 def __init__(self
, value
):
471 if value
== NextEthernetAddr
:
475 if not isinstance(value
, str):
476 raise TypeError, "expected an ethernet address and didn't get one"
478 bytes
= value
.split(':')
480 raise TypeError, 'invalid ethernet address %s' % value
483 if not 0 <= int(byte
) <= 256:
484 raise TypeError, 'invalid ethernet address %s' % value
488 def unproxy(self
, base
):
489 if self
.value
== NextEthernetAddr
:
490 self
.addr
= self
.value().value
494 if self
.value
== NextEthernetAddr
:
495 if hasattr(self
, 'addr'):
498 return "NextEthernetAddr (unresolved)"
502 # Enumerated types are a little more complex. The user specifies the
503 # type as Enum(foo) where foo is either a list or dictionary of
504 # alternatives (typically strings, but not necessarily so). (In the
505 # long run, the integer value of the parameter will be the list index
506 # or the corresponding dictionary value. For now, since we only check
507 # that the alternative is valid and then spit it into a .ini file,
508 # there's not much point in using the dictionary.)
510 # What Enum() must do is generate a new type encapsulating the
511 # provided list/dictionary so that specific values of the parameter
512 # can be instances of that type. We define two hidden internal
513 # classes (_ListEnum and _DictEnum) to serve as base classes, then
514 # derive the new type from the appropriate base class on the fly.
517 # Metaclass for Enum types
518 class MetaEnum(type):
519 def __init__(cls
, name
, bases
, init_dict
):
520 if init_dict
.has_key('map'):
521 if not isinstance(cls
.map, dict):
522 raise TypeError, "Enum-derived class attribute 'map' " \
523 "must be of type dict"
524 # build list of value strings from map
525 cls
.vals
= cls
.map.keys()
527 elif init_dict
.has_key('vals'):
528 if not isinstance(cls
.vals
, list):
529 raise TypeError, "Enum-derived class attribute 'vals' " \
530 "must be of type list"
531 # build string->value map from vals sequence
533 for idx
,val
in enumerate(cls
.vals
):
536 raise TypeError, "Enum-derived class must define "\
537 "attribute 'map' or 'vals'"
539 cls
.cxx_type
= name
+ '::Enum'
541 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
543 # Generate C++ class declaration for this enum type.
544 # Note that we wrap the enum in a class/struct to act as a namespace,
545 # so that the enum strings can be brief w/o worrying about collisions.
547 s
= 'struct %s {\n enum Enum {\n ' % cls
.__name
__
548 s
+= ',\n '.join(['%s = %d' % (v
,cls
.map[v
]) for v
in cls
.vals
])
552 # Base class for enum types.
553 class Enum(ParamValue
):
554 __metaclass__
= MetaEnum
557 def __init__(self
, value
):
558 if value
not in self
.map:
559 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
568 # how big does a rounding error need to be before we warn about it?
569 frequency_tolerance
= 0.001 # 0.1%
571 # convert a floting-point # of ticks to integer, and warn if rounding
572 # discards too much precision
573 def tick_check(float_ticks
):
576 int_ticks
= int(round(float_ticks
))
577 err
= (float_ticks
- int_ticks
) / float_ticks
578 if err
> frequency_tolerance
:
579 print >> sys
.stderr
, "Warning: rounding error > tolerance"
580 print >> sys
.stderr
, " %f rounded to %d" % (float_ticks
, int_ticks
)
584 def getLatency(value
):
585 if isinstance(value
, Latency
) or isinstance(value
, Clock
):
587 elif isinstance(value
, Frequency
) or isinstance(value
, RootClock
):
588 return 1 / value
.value
589 elif isinstance(value
, str):
591 return convert
.toLatency(value
)
594 return 1 / convert
.toFrequency(value
)
597 raise ValueError, "Invalid Frequency/Latency value '%s'" % value
600 class Latency(NumericParamValue
):
602 cxx_predecls
= ['#include "sim/host.hh"']
603 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
604 '%import "sim/host.hh"']
605 def __init__(self
, value
):
606 self
.value
= getLatency(value
)
608 def __getattr__(self
, attr
):
609 if attr
in ('latency', 'period'):
611 if attr
== 'frequency':
612 return Frequency(self
)
613 raise AttributeError, "Latency object has no attribute '%s'" % attr
615 # convert latency to ticks
617 return str(tick_check(self
.value
* ticks_per_sec
))
619 class Frequency(NumericParamValue
):
621 cxx_predecls
= ['#include "sim/host.hh"']
622 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
623 '%import "sim/host.hh"']
624 def __init__(self
, value
):
625 self
.value
= 1 / getLatency(value
)
627 def __getattr__(self
, attr
):
628 if attr
== 'frequency':
630 if attr
in ('latency', 'period'):
632 raise AttributeError, "Frequency object has no attribute '%s'" % attr
634 # convert frequency to ticks per period
636 return self
.period
.ini_str()
638 # Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
639 # We can't inherit from Frequency because we don't want it to be directly
640 # assignable to a regular Frequency parameter.
641 class RootClock(ParamValue
):
643 cxx_predecls
= ['#include "sim/host.hh"']
644 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
645 '%import "sim/host.hh"']
646 def __init__(self
, value
):
647 self
.value
= 1 / getLatency(value
)
649 def __getattr__(self
, attr
):
650 if attr
== 'frequency':
651 return Frequency(self
)
652 if attr
in ('latency', 'period'):
654 raise AttributeError, "Frequency object has no attribute '%s'" % attr
657 return str(tick_check(self
.value
))
659 # A generic frequency and/or Latency value. Value is stored as a latency,
660 # but to avoid ambiguity this object does not support numeric ops (* or /).
661 # An explicit conversion to a Latency or Frequency must be made first.
662 class Clock(ParamValue
):
664 cxx_predecls
= ['#include "sim/host.hh"']
665 swig_predecls
= ['%import "python/m5/swig/stdint.i"\n' +
666 '%import "sim/host.hh"']
667 def __init__(self
, value
):
668 self
.value
= getLatency(value
)
670 def __getattr__(self
, attr
):
671 if attr
== 'frequency':
672 return Frequency(self
)
673 if attr
in ('latency', 'period'):
675 raise AttributeError, "Frequency object has no attribute '%s'" % attr
678 return self
.period
.ini_str()
680 class NetworkBandwidth(float,ParamValue
):
682 def __new__(cls
, value
):
683 val
= convert
.toNetworkBandwidth(value
) / 8.0
684 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
690 return '%f' % (ticks_per_sec
/ float(self
))
692 class MemoryBandwidth(float,ParamValue
):
694 def __new__(self
, value
):
695 val
= convert
.toMemoryBandwidth(value
)
696 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
702 return '%f' % (ticks_per_sec
/ float(self
))
705 # "Constants"... handy aliases for various values.
708 # Special class for NULL pointers. Note the special check in
709 # make_param_value() above that lets these be assigned where a
710 # SimObject is required.
711 # only one copy of a particular node
712 class NullSimObject(object):
713 __metaclass__
= Singleton
718 def _instantiate(self
, parent
= None, path
= ''):
724 def unproxy(self
, base
):
727 def set_path(self
, parent
, name
):
732 # The only instance you'll ever need...
733 NULL
= NullSimObject()
735 def isNullPointer(value
):
736 return isinstance(value
, NullSimObject
)
738 # Some memory range specifications use this as a default upper bound.
741 AllMemory
= AddrRange(0, MaxAddr
)
744 #####################################################################
748 # Ports are used to interconnect objects in the memory system.
750 #####################################################################
752 # Port reference: encapsulates a reference to a particular port on a
753 # particular SimObject.
754 class PortRef(object):
755 def __init__(self
, simobj
, name
):
756 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
759 self
.peer
= None # not associated with another port yet
760 self
.ccConnected
= False # C++ port connection done?
761 self
.index
= -1 # always -1 for non-vector ports
764 return '%s.%s' % (self
.simobj
, self
.name
)
766 # for config.ini, print peer's name (not ours)
768 return str(self
.peer
)
770 def __getattr__(self
, attr
):
771 if attr
== 'peerObj':
772 # shorthand for proxies
773 return self
.peer
.simobj
774 raise AttributeError, "'%s' object has no attribute '%s'" % \
775 (self
.__class
__.__name
__, attr
)
777 # Full connection is symmetric (both ways). Called via
778 # SimObject.__setattr__ as a result of a port assignment, e.g.,
779 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
780 # e.g., "obj1.portA[3] = obj2.portB".
781 def connect(self
, other
):
782 if isinstance(other
, VectorPortRef
):
783 # reference to plain VectorPort is implicit append
784 other
= other
._get
_next
()
785 if self
.peer
and not proxy
.isproxy(self
.peer
):
786 print "warning: overwriting port", self
, \
787 "value", self
.peer
, "with", other
789 if proxy
.isproxy(other
):
790 other
.set_param_desc(PortParamDesc())
791 elif isinstance(other
, PortRef
):
792 if other
.peer
is not self
:
796 "assigning non-port reference '%s' to port '%s'" \
799 def clone(self
, simobj
, memo
):
800 if memo
.has_key(self
):
802 newRef
= copy
.copy(self
)
804 newRef
.simobj
= simobj
805 assert(isSimObject(newRef
.simobj
))
806 if self
.peer
and not proxy
.isproxy(self
.peer
):
807 peerObj
= self
.peer
.simobj(_memo
=memo
)
808 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
809 assert(not isinstance(newRef
.peer
, VectorPortRef
))
812 def unproxy(self
, simobj
):
813 assert(simobj
is self
.simobj
)
814 if proxy
.isproxy(self
.peer
):
816 realPeer
= self
.peer
.unproxy(self
.simobj
)
818 print "Error in unproxying port '%s' of %s" % \
819 (self
.name
, self
.simobj
.path())
821 self
.connect(realPeer
)
823 # Call C++ to create corresponding port connection between C++ objects
825 if self
.ccConnected
: # already done this
828 cc_main
.connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
829 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
830 self
.ccConnected
= True
831 peer
.ccConnected
= True
833 # A reference to an individual element of a VectorPort... much like a
834 # PortRef, but has an index.
835 class VectorPortElementRef(PortRef
):
836 def __init__(self
, simobj
, name
, index
):
837 PortRef
.__init
__(self
, simobj
, name
)
841 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
843 # A reference to a complete vector-valued port (not just a single element).
844 # Can be indexed to retrieve individual VectorPortElementRef instances.
845 class VectorPortRef(object):
846 def __init__(self
, simobj
, name
):
847 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
853 return '%s.%s[:]' % (self
.simobj
, self
.name
)
855 # for config.ini, print peer's name (not ours)
857 return ' '.join([el
.ini_str() for el
in self
.elements
])
859 def __getitem__(self
, key
):
860 if not isinstance(key
, int):
861 raise TypeError, "VectorPort index must be integer"
862 if key
>= len(self
.elements
):
863 # need to extend list
864 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, i
)
865 for i
in range(len(self
.elements
), key
+1)]
866 self
.elements
.extend(ext
)
867 return self
.elements
[key
]
870 return self
[len(self
.elements
)]
872 def __setitem__(self
, key
, value
):
873 if not isinstance(key
, int):
874 raise TypeError, "VectorPort index must be integer"
875 self
[key
].connect(value
)
877 def connect(self
, other
):
878 if isinstance(other
, (list, tuple)):
879 # Assign list of port refs to vector port.
880 # For now, append them... not sure if that's the right semantics
881 # or if it should replace the current vector.
883 self
._get
_next
().connect(ref
)
885 # scalar assignment to plain VectorPort is implicit append
886 self
._get
_next
().connect(other
)
888 def clone(self
, simobj
, memo
):
889 if memo
.has_key(self
):
891 newRef
= copy
.copy(self
)
893 newRef
.simobj
= simobj
894 assert(isSimObject(newRef
.simobj
))
895 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
898 def unproxy(self
, simobj
):
899 [el
.unproxy(simobj
) for el
in self
.elements
]
902 [el
.ccConnect() for el
in self
.elements
]
904 # Port description object. Like a ParamDesc object, this represents a
905 # logical port in the SimObject class, not a particular port on a
906 # SimObject instance. The latter are represented by PortRef objects.
908 # Port("description") or Port(default, "description")
909 def __init__(self
, *args
):
913 self
.default
= args
[0]
916 raise TypeError, 'wrong number of arguments'
917 # self.name is set by SimObject class on assignment
918 # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
920 # Generate a PortRef for this port on the given SimObject with the
922 def makeRef(self
, simobj
):
923 return PortRef(simobj
, self
.name
)
925 # Connect an instance of this port (on the given SimObject with
926 # the given name) with the port described by the supplied PortRef
927 def connect(self
, simobj
, ref
):
928 self
.makeRef(simobj
).connect(ref
)
930 # VectorPort description object. Like Port, but represents a vector
931 # of connections (e.g., as on a Bus).
932 class VectorPort(Port
):
933 def __init__(self
, *args
):
934 Port
.__init
__(self
, *args
)
937 def makeRef(self
, simobj
):
938 return VectorPortRef(simobj
, self
.name
)
940 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
941 # proxy objects (via set_param_desc()) so that proxy error messages
943 class PortParamDesc(object):
944 __metaclass__
= Singleton
950 __all__
= ['Param', 'VectorParam',
951 'Enum', 'Bool', 'String', 'Float',
952 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
953 'Int32', 'UInt32', 'Int64', 'UInt64',
954 'Counter', 'Addr', 'Tick', 'Percent',
955 'TcpPort', 'UdpPort', 'EthernetAddr',
956 'MemorySize', 'MemorySize32',
957 'Latency', 'Frequency', 'RootClock', 'Clock',
958 'NetworkBandwidth', 'MemoryBandwidth',
959 'Range', 'AddrRange', 'TickRange',
960 'MaxAddr', 'MaxTick', 'AllMemory',
961 'NextEthernetAddr', 'NULL',
962 'Port', 'VectorPort']
964 # see comment on imports at end of __init__.py.
965 from SimObject
import isSimObject
, isSimObjectSequence
, isSimObjectClass