dfc3ede3bd59cdc2e57c46bffeac1e1495e3cc72
1 # Copyright (c) 2012-2013 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2004-2006 The Regents of The University of Michigan
14 # Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
15 # All rights reserved.
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 # Authors: Steve Reinhardt
45 #####################################################################
47 # Parameter description classes
49 # The _params dictionary in each class maps parameter names to either
50 # a Param or a VectorParam object. These objects contain the
51 # parameter description string, the parameter type, and the default
52 # value (if any). The convert() method on these objects is used to
53 # force whatever value is assigned to the parameter to the appropriate
56 # Note that the default values are loaded into the class's attribute
57 # space when the parameter dictionary is initialized (in
58 # MetaSimObject._new_param()); after that point they aren't used.
60 #####################################################################
73 def isSimObject(*args
, **kwargs
):
74 return SimObject
.isSimObject(*args
, **kwargs
)
76 def isSimObjectSequence(*args
, **kwargs
):
77 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
79 def isSimObjectClass(*args
, **kwargs
):
80 return SimObject
.isSimObjectClass(*args
, **kwargs
)
84 class MetaParamValue(type):
85 def __new__(mcls
, name
, bases
, dct
):
86 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
87 assert name
not in allParams
92 # Dummy base class to identify types that are legitimate for SimObject
94 class ParamValue(object):
95 __metaclass__
= MetaParamValue
96 cmd_line_settable
= False
98 # Generate the code needed as a prerequisite for declaring a C++
99 # object of this type. Typically generates one or more #include
100 # statements. Used when declaring parameters of this type.
102 def cxx_predecls(cls
, code
):
105 # Generate the code needed as a prerequisite for including a
106 # reference to a C++ object of this type in a SWIG .i file.
107 # Typically generates one or more %import or %include statements.
109 def swig_predecls(cls
, code
):
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
117 # allows us to blithely call unproxy() on things without checking
118 # if they're really proxies or not
119 def unproxy(self
, base
):
122 # Produce a human readable version of the stored value
123 def pretty_print(self
, value
):
126 # Regular parameter description.
127 class ParamDesc(object):
128 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
129 self
.ptype_str
= ptype_str
130 # remember ptype only if it is provided
138 self
.default
= args
[0]
141 raise TypeError, 'too many arguments'
143 if kwargs
.has_key('desc'):
144 assert(not hasattr(self
, 'desc'))
145 self
.desc
= kwargs
['desc']
148 if kwargs
.has_key('default'):
149 assert(not hasattr(self
, 'default'))
150 self
.default
= kwargs
['default']
151 del kwargs
['default']
154 raise TypeError, 'extra unknown kwargs %s' % kwargs
156 if not hasattr(self
, 'desc'):
157 raise TypeError, 'desc attribute missing'
159 def __getattr__(self
, attr
):
161 ptype
= SimObject
.allClasses
[self
.ptype_str
]
162 assert isSimObjectClass(ptype
)
166 raise AttributeError, "'%s' object has no attribute '%s'" % \
167 (type(self
).__name
__, attr
)
169 def example_str(self
):
170 if hasattr(self
.ptype
, "ex_str"):
171 return self
.ptype
.ex_str
173 return self
.ptype_str
175 # Is the param available to be exposed on the command line
176 def isCmdLineSettable(self
):
177 if hasattr(self
.ptype
, "cmd_line_settable"):
178 return self
.ptype
.cmd_line_settable
182 def convert(self
, value
):
183 if isinstance(value
, proxy
.BaseProxy
):
184 value
.set_param_desc(self
)
186 if not hasattr(self
, 'ptype') and isNullPointer(value
):
187 # deferred evaluation of SimObject; continue to defer if
188 # we're just assigning a null pointer
190 if isinstance(value
, self
.ptype
):
192 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
194 return self
.ptype(value
)
196 def pretty_print(self
, value
):
197 if isinstance(value
, proxy
.BaseProxy
):
199 if isNullPointer(value
):
201 return self
.ptype(value
).pretty_print(value
)
203 def cxx_predecls(self
, code
):
204 code('#include <cstddef>')
205 self
.ptype
.cxx_predecls(code
)
207 def swig_predecls(self
, code
):
208 self
.ptype
.swig_predecls(code
)
210 def cxx_decl(self
, code
):
211 code('${{self.ptype.cxx_type}} ${{self.name}};')
213 # Vector-valued parameter description. Just like ParamDesc, except
214 # that the value is a vector (list) of the specified type instead of a
217 class VectorParamValue(list):
218 __metaclass__
= MetaParamValue
219 def __setattr__(self
, attr
, value
):
220 raise AttributeError, \
221 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
224 return ' '.join([v
.ini_str() for v
in self
])
227 return [ v
.getValue() for v
in self
]
229 def unproxy(self
, base
):
230 if len(self
) == 1 and isinstance(self
[0], proxy
.AllProxy
):
231 return self
[0].unproxy(base
)
233 return [v
.unproxy(base
) for v
in self
]
235 class SimObjectVector(VectorParamValue
):
236 # support clone operation
237 def __call__(self
, **kwargs
):
238 return SimObjectVector([v(**kwargs
) for v
in self
])
240 def clear_parent(self
, old_parent
):
242 v
.clear_parent(old_parent
)
244 def set_parent(self
, parent
, name
):
246 self
[0].set_parent(parent
, name
)
248 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
249 for i
,v
in enumerate(self
):
250 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
252 def has_parent(self
):
253 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
255 # return 'cpu0 cpu1' etc. for print_ini()
257 return ' '.join([v
._name
for v
in self
])
259 # By iterating through the constituent members of the vector here
260 # we can nicely handle iterating over all a SimObject's children
261 # without having to provide lots of special functions on
262 # SimObjectVector directly.
263 def descendants(self
):
265 for obj
in v
.descendants():
268 def get_config_as_dict(self
):
271 a
.append(v
.get_config_as_dict())
274 # If we are replacing an item in the vector, make sure to set the
275 # parent reference of the new SimObject to be the same as the parent
276 # of the SimObject being replaced. Useful to have if we created
277 # a SimObjectVector of temporary objects that will be modified later in
278 # configuration scripts.
279 def __setitem__(self
, key
, value
):
281 if value
.has_parent():
282 warn("SimObject %s already has a parent" % value
.get_name() +\
283 " that is being overwritten by a SimObjectVector")
284 value
.set_parent(val
.get_parent(), val
._name
)
285 super(SimObjectVector
, self
).__setitem
__(key
, value
)
287 # Enumerate the params of each member of the SimObject vector. Creates
288 # strings that will allow indexing into the vector by the python code and
289 # allow it to be specified on the command line.
290 def enumerateParams(self
, flags_dict
= {},
293 if hasattr(self
, "_paramEnumed"):
294 print "Cycle detected enumerating params at %s?!" % (cmd_line_str
)
298 # Each entry in the SimObjectVector should be an
299 # instance of a SimObject
300 flags_dict
= vals
.enumerateParams(flags_dict
,
301 cmd_line_str
+ "%d." % x
,
302 access_str
+ "[%d]." % x
)
307 class VectorParamDesc(ParamDesc
):
308 # Convert assigned value to appropriate type. If the RHS is not a
309 # list or tuple, it generates a single-element list.
310 def convert(self
, value
):
311 if isinstance(value
, (list, tuple)):
312 # list: coerce each element into new list
313 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
315 # singleton: coerce to a single-element list
316 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
318 if isSimObjectSequence(tmp_list
):
319 return SimObjectVector(tmp_list
)
321 return VectorParamValue(tmp_list
)
323 # Produce a human readable example string that describes
324 # how to set this vector parameter in the absence of a default
326 def example_str(self
):
327 s
= super(VectorParamDesc
, self
).example_str()
328 help_str
= "[" + s
+ "," + s
+ ", ...]"
331 # Produce a human readable representation of the value of this vector param.
332 def pretty_print(self
, value
):
333 if isinstance(value
, (list, tuple)):
334 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
335 elif isinstance(value
, str):
336 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
338 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
342 # This is a helper function for the new config system
343 def __call__(self
, value
):
344 if isinstance(value
, (list, tuple)):
345 # list: coerce each element into new list
346 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
347 elif isinstance(value
, str):
348 # If input is a csv string
349 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
.split(',') ]
351 # singleton: coerce to a single-element list
352 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
354 return VectorParamValue(tmp_list
)
356 def swig_module_name(self
):
357 return "%s_vector" % self
.ptype_str
359 def swig_predecls(self
, code
):
360 code('%import "${{self.swig_module_name()}}.i"')
362 def swig_decl(self
, code
):
363 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
365 self
.ptype
.cxx_predecls(code
)
368 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
369 code('%include "std_container.i"')
371 self
.ptype
.swig_predecls(code
)
373 code('%include "std_vector.i"')
376 ptype
= self
.ptype_str
377 cxx_type
= self
.ptype
.cxx_type
379 code('%template(vector_$ptype) std::vector< $cxx_type >;')
381 def cxx_predecls(self
, code
):
382 code('#include <vector>')
383 self
.ptype
.cxx_predecls(code
)
385 def cxx_decl(self
, code
):
386 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
388 class ParamFactory(object):
389 def __init__(self
, param_desc_class
, ptype_str
= None):
390 self
.param_desc_class
= param_desc_class
391 self
.ptype_str
= ptype_str
393 def __getattr__(self
, attr
):
395 attr
= self
.ptype_str
+ '.' + attr
396 return ParamFactory(self
.param_desc_class
, attr
)
398 # E.g., Param.Int(5, "number of widgets")
399 def __call__(self
, *args
, **kwargs
):
402 ptype
= allParams
[self
.ptype_str
]
404 # if name isn't defined yet, assume it's a SimObject, and
405 # try to resolve it later
407 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
409 Param
= ParamFactory(ParamDesc
)
410 VectorParam
= ParamFactory(VectorParamDesc
)
412 #####################################################################
416 # Though native Python types could be used to specify parameter types
417 # (the 'ptype' field of the Param and VectorParam classes), it's more
418 # flexible to define our own set of types. This gives us more control
419 # over how Python expressions are converted to values (via the
420 # __init__() constructor) and how these values are printed out (via
421 # the __str__() conversion method).
423 #####################################################################
425 # String-valued parameter. Just mixin the ParamValue class with the
426 # built-in str class.
427 class String(ParamValue
,str):
428 cxx_type
= 'std::string'
429 cmd_line_settable
= True
432 def cxx_predecls(self
, code
):
433 code('#include <string>')
436 def swig_predecls(cls
, code
):
437 code('%include "std_string.i"')
439 def __call__(self
, value
):
446 # superclass for "numeric" parameter values, to emulate math
447 # operations in a type-safe way. e.g., a Latency times an int returns
448 # a new Latency object.
449 class NumericParamValue(ParamValue
):
451 return str(self
.value
)
454 return float(self
.value
)
457 return long(self
.value
)
460 return int(self
.value
)
462 # hook for bounds checking
466 def __mul__(self
, other
):
467 newobj
= self
.__class
__(self
)
468 newobj
.value
*= other
474 def __div__(self
, other
):
475 newobj
= self
.__class
__(self
)
476 newobj
.value
/= other
480 def __sub__(self
, other
):
481 newobj
= self
.__class
__(self
)
482 newobj
.value
-= other
486 # Metaclass for bounds-checked integer parameters. See CheckedInt.
487 class CheckedIntType(MetaParamValue
):
488 def __init__(cls
, name
, bases
, dict):
489 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
491 # CheckedInt is an abstract base class, so we actually don't
492 # want to do any processing on it... the rest of this code is
493 # just for classes that derive from CheckedInt.
494 if name
== 'CheckedInt':
497 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
498 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
499 panic("CheckedInt subclass %s must define either\n" \
500 " 'min' and 'max' or 'size' and 'unsigned'\n",
504 cls
.max = 2 ** cls
.size
- 1
506 cls
.min = -(2 ** (cls
.size
- 1))
507 cls
.max = (2 ** (cls
.size
- 1)) - 1
509 # Abstract superclass for bounds-checked integer parameters. This
510 # class is subclassed to generate parameter classes with specific
511 # bounds. Initialization of the min and max bounds is done in the
512 # metaclass CheckedIntType.__init__.
513 class CheckedInt(NumericParamValue
):
514 __metaclass__
= CheckedIntType
515 cmd_line_settable
= True
518 if not self
.min <= self
.value
<= self
.max:
519 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
520 (self
.min, self
.value
, self
.max)
522 def __init__(self
, value
):
523 if isinstance(value
, str):
524 self
.value
= convert
.toInteger(value
)
525 elif isinstance(value
, (int, long, float, NumericParamValue
)):
526 self
.value
= long(value
)
528 raise TypeError, "Can't convert object of type %s to CheckedInt" \
529 % type(value
).__name
__
532 def __call__(self
, value
):
537 def cxx_predecls(cls
, code
):
538 # most derived types require this, so we just do it here once
539 code('#include "base/types.hh"')
542 def swig_predecls(cls
, code
):
543 # most derived types require this, so we just do it here once
544 code('%import "stdint.i"')
545 code('%import "base/types.hh"')
548 return long(self
.value
)
550 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
551 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
553 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
554 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
555 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
556 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
557 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
558 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
559 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
560 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
562 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
563 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
564 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
565 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
567 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
569 class Cycles(CheckedInt
):
575 from m5
.internal
.core
import Cycles
576 return Cycles(self
.value
)
578 class Float(ParamValue
, float):
580 cmdLineSettable
= True
582 def __init__(self
, value
):
583 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
584 self
.value
= float(value
)
586 raise TypeError, "Can't convert object of type %s to Float" \
587 % type(value
).__name
__
589 def __call__(self
, value
):
594 return float(self
.value
)
596 class MemorySize(CheckedInt
):
597 cxx_type
= 'uint64_t'
601 def __init__(self
, value
):
602 if isinstance(value
, MemorySize
):
603 self
.value
= value
.value
605 self
.value
= convert
.toMemorySize(value
)
608 class MemorySize32(CheckedInt
):
609 cxx_type
= 'uint32_t'
613 def __init__(self
, value
):
614 if isinstance(value
, MemorySize
):
615 self
.value
= value
.value
617 self
.value
= convert
.toMemorySize(value
)
620 class Addr(CheckedInt
):
624 def __init__(self
, value
):
625 if isinstance(value
, Addr
):
626 self
.value
= value
.value
629 # Often addresses are referred to with sizes. Ex: A device
630 # base address is at "512MB". Use toMemorySize() to convert
631 # these into addresses. If the address is not specified with a
632 # "size", an exception will occur and numeric translation will
634 self
.value
= convert
.toMemorySize(value
)
635 except (TypeError, ValueError):
636 # Convert number to string and use long() to do automatic
637 # base conversion (requires base=0 for auto-conversion)
638 self
.value
= long(str(value
), base
=0)
641 def __add__(self
, other
):
642 if isinstance(other
, Addr
):
643 return self
.value
+ other
.value
645 return self
.value
+ other
646 def pretty_print(self
, value
):
648 val
= convert
.toMemorySize(value
)
651 return "0x%x" % long(val
)
653 class AddrRange(ParamValue
):
654 cxx_type
= 'AddrRange'
656 def __init__(self
, *args
, **kwargs
):
657 # Disable interleaving by default
658 self
.intlvHighBit
= 0
662 def handle_kwargs(self
, kwargs
):
663 # An address range needs to have an upper limit, specified
664 # either explicitly with an end, or as an offset using the
667 self
.end
= Addr(kwargs
.pop('end'))
668 elif 'size' in kwargs
:
669 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
671 raise TypeError, "Either end or size must be specified"
673 # Now on to the optional bit
674 if 'intlvHighBit' in kwargs
:
675 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
676 if 'intlvBits' in kwargs
:
677 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
678 if 'intlvMatch' in kwargs
:
679 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
682 self
.start
= Addr(kwargs
.pop('start'))
683 handle_kwargs(self
, kwargs
)
687 self
.start
= Addr(args
[0])
688 handle_kwargs(self
, kwargs
)
689 elif isinstance(args
[0], (list, tuple)):
690 self
.start
= Addr(args
[0][0])
691 self
.end
= Addr(args
[0][1])
694 self
.end
= Addr(args
[0]) - 1
697 self
.start
= Addr(args
[0])
698 self
.end
= Addr(args
[1])
700 raise TypeError, "Too many arguments specified"
703 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
706 return '%s:%s' % (self
.start
, self
.end
)
709 # Divide the size by the size of the interleaving slice
710 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
713 def cxx_predecls(cls
, code
):
714 Addr
.cxx_predecls(code
)
715 code('#include "base/addr_range.hh"')
718 def swig_predecls(cls
, code
):
719 Addr
.swig_predecls(code
)
722 # Go from the Python class to the wrapped C++ class generated
724 from m5
.internal
.range import AddrRange
726 return AddrRange(long(self
.start
), long(self
.end
),
727 int(self
.intlvHighBit
), int(self
.intlvBits
),
728 int(self
.intlvMatch
))
730 # Boolean parameter type. Python doesn't let you subclass bool, since
731 # it doesn't want to let you create multiple instances of True and
732 # False. Thus this is a little more complicated than String.
733 class Bool(ParamValue
):
735 cmd_line_settable
= True
737 def __init__(self
, value
):
739 self
.value
= convert
.toBool(value
)
741 self
.value
= bool(value
)
743 def __call__(self
, value
):
748 return bool(self
.value
)
751 return str(self
.value
)
753 # implement truth value testing for Bool parameters so that these params
754 # evaluate correctly during the python configuration phase
755 def __nonzero__(self
):
756 return bool(self
.value
)
763 def IncEthernetAddr(addr
, val
= 1):
764 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
766 for i
in (5, 4, 3, 2, 1):
767 val
,rem
= divmod(bytes
[i
], 256)
772 assert(bytes
[0] <= 255)
773 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
775 _NextEthernetAddr
= "00:90:00:00:00:01"
776 def NextEthernetAddr():
777 global _NextEthernetAddr
779 value
= _NextEthernetAddr
780 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
783 class EthernetAddr(ParamValue
):
784 cxx_type
= 'Net::EthAddr'
785 ex_str
= "00:90:00:00:00:01"
786 cmd_line_settable
= True
789 def cxx_predecls(cls
, code
):
790 code('#include "base/inet.hh"')
793 def swig_predecls(cls
, code
):
794 code('%include "python/swig/inet.i"')
796 def __init__(self
, value
):
797 if value
== NextEthernetAddr
:
801 if not isinstance(value
, str):
802 raise TypeError, "expected an ethernet address and didn't get one"
804 bytes
= value
.split(':')
806 raise TypeError, 'invalid ethernet address %s' % value
809 if not 0 <= int(byte
, base
=16) <= 0xff:
810 raise TypeError, 'invalid ethernet address %s' % value
814 def __call__(self
, value
):
818 def unproxy(self
, base
):
819 if self
.value
== NextEthernetAddr
:
820 return EthernetAddr(self
.value())
824 from m5
.internal
.params
import EthAddr
825 return EthAddr(self
.value
)
830 # When initializing an IpAddress, pass in an existing IpAddress, a string of
831 # the form "a.b.c.d", or an integer representing an IP.
832 class IpAddress(ParamValue
):
833 cxx_type
= 'Net::IpAddress'
835 cmd_line_settable
= True
838 def cxx_predecls(cls
, code
):
839 code('#include "base/inet.hh"')
842 def swig_predecls(cls
, code
):
843 code('%include "python/swig/inet.i"')
845 def __init__(self
, value
):
846 if isinstance(value
, IpAddress
):
850 self
.ip
= convert
.toIpAddress(value
)
852 self
.ip
= long(value
)
855 def __call__(self
, value
):
860 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
861 return '%d.%d.%d.%d' % tuple(tup
)
863 def __eq__(self
, other
):
864 if isinstance(other
, IpAddress
):
865 return self
.ip
== other
.ip
866 elif isinstance(other
, str):
868 return self
.ip
== convert
.toIpAddress(other
)
872 return self
.ip
== other
874 def __ne__(self
, other
):
875 return not (self
== other
)
878 if self
.ip
< 0 or self
.ip
>= (1 << 32):
879 raise TypeError, "invalid ip address %#08x" % self
.ip
882 from m5
.internal
.params
import IpAddress
883 return IpAddress(self
.ip
)
885 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
886 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
887 # positional or keyword arguments.
888 class IpNetmask(IpAddress
):
889 cxx_type
= 'Net::IpNetmask'
890 ex_str
= "127.0.0.0/24"
891 cmd_line_settable
= True
894 def cxx_predecls(cls
, code
):
895 code('#include "base/inet.hh"')
898 def swig_predecls(cls
, code
):
899 code('%include "python/swig/inet.i"')
901 def __init__(self
, *args
, **kwargs
):
902 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
904 setattr(self
, key
, kwargs
.pop(key
))
906 setattr(self
, key
, elseVal
)
908 raise TypeError, "No value set for %s" % key
911 handle_kwarg(self
, kwargs
, 'ip')
912 handle_kwarg(self
, kwargs
, 'netmask')
916 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
917 raise TypeError, "Invalid arguments"
918 handle_kwarg(self
, kwargs
, 'ip', args
[0])
919 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
920 elif isinstance(args
[0], IpNetmask
):
922 self
.netmask
= args
[0].netmask
924 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
928 self
.netmask
= args
[1]
930 raise TypeError, "Too many arguments specified"
933 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
937 def __call__(self
, value
):
942 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
944 def __eq__(self
, other
):
945 if isinstance(other
, IpNetmask
):
946 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
947 elif isinstance(other
, str):
949 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
957 if self
.netmask
< 0 or self
.netmask
> 32:
958 raise TypeError, "invalid netmask %d" % netmask
961 from m5
.internal
.params
import IpNetmask
962 return IpNetmask(self
.ip
, self
.netmask
)
964 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
965 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
966 class IpWithPort(IpAddress
):
967 cxx_type
= 'Net::IpWithPort'
968 ex_str
= "127.0.0.1:80"
969 cmd_line_settable
= True
972 def cxx_predecls(cls
, code
):
973 code('#include "base/inet.hh"')
976 def swig_predecls(cls
, code
):
977 code('%include "python/swig/inet.i"')
979 def __init__(self
, *args
, **kwargs
):
980 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
982 setattr(self
, key
, kwargs
.pop(key
))
984 setattr(self
, key
, elseVal
)
986 raise TypeError, "No value set for %s" % key
989 handle_kwarg(self
, kwargs
, 'ip')
990 handle_kwarg(self
, kwargs
, 'port')
994 if not 'ip' in kwargs
and not 'port' in kwargs
:
995 raise TypeError, "Invalid arguments"
996 handle_kwarg(self
, kwargs
, 'ip', args
[0])
997 handle_kwarg(self
, kwargs
, 'port', args
[0])
998 elif isinstance(args
[0], IpWithPort
):
1000 self
.port
= args
[0].port
1002 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1004 elif len(args
) == 2:
1008 raise TypeError, "Too many arguments specified"
1011 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1015 def __call__(self
, value
):
1016 self
.__init
__(value
)
1020 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1022 def __eq__(self
, other
):
1023 if isinstance(other
, IpWithPort
):
1024 return self
.ip
== other
.ip
and self
.port
== other
.port
1025 elif isinstance(other
, str):
1027 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1035 if self
.port
< 0 or self
.port
> 0xffff:
1036 raise TypeError, "invalid port %d" % self
.port
1039 from m5
.internal
.params
import IpWithPort
1040 return IpWithPort(self
.ip
, self
.port
)
1042 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1043 "%a %b %d %H:%M:%S %Z %Y",
1044 "%Y/%m/%d %H:%M:%S",
1047 "%m/%d/%Y %H:%M:%S",
1050 "%m/%d/%y %H:%M:%S",
1055 def parse_time(value
):
1056 from time
import gmtime
, strptime
, struct_time
, time
1057 from datetime
import datetime
, date
1059 if isinstance(value
, struct_time
):
1062 if isinstance(value
, (int, long)):
1063 return gmtime(value
)
1065 if isinstance(value
, (datetime
, date
)):
1066 return value
.timetuple()
1068 if isinstance(value
, str):
1069 if value
in ('Now', 'Today'):
1070 return time
.gmtime(time
.time())
1072 for format
in time_formats
:
1074 return strptime(value
, format
)
1078 raise ValueError, "Could not parse '%s' as a time" % value
1080 class Time(ParamValue
):
1084 def cxx_predecls(cls
, code
):
1085 code('#include <time.h>')
1088 def swig_predecls(cls
, code
):
1089 code('%include "python/swig/time.i"')
1091 def __init__(self
, value
):
1092 self
.value
= parse_time(value
)
1094 def __call__(self
, value
):
1095 self
.__init
__(value
)
1099 from m5
.internal
.params
import tm
1102 py_time
= self
.value
1104 # UNIX is years since 1900
1105 c_time
.tm_year
= py_time
.tm_year
- 1900;
1107 # Python starts at 1, UNIX starts at 0
1108 c_time
.tm_mon
= py_time
.tm_mon
- 1;
1109 c_time
.tm_mday
= py_time
.tm_mday
;
1110 c_time
.tm_hour
= py_time
.tm_hour
;
1111 c_time
.tm_min
= py_time
.tm_min
;
1112 c_time
.tm_sec
= py_time
.tm_sec
;
1114 # Python has 0 as Monday, UNIX is 0 as sunday
1115 c_time
.tm_wday
= py_time
.tm_wday
+ 1
1116 if c_time
.tm_wday
> 6:
1117 c_time
.tm_wday
-= 7;
1119 # Python starts at 1, Unix starts at 0
1120 c_time
.tm_yday
= py_time
.tm_yday
- 1;
1125 return time
.asctime(self
.value
)
1130 def get_config_as_dict(self
):
1133 # Enumerated types are a little more complex. The user specifies the
1134 # type as Enum(foo) where foo is either a list or dictionary of
1135 # alternatives (typically strings, but not necessarily so). (In the
1136 # long run, the integer value of the parameter will be the list index
1137 # or the corresponding dictionary value. For now, since we only check
1138 # that the alternative is valid and then spit it into a .ini file,
1139 # there's not much point in using the dictionary.)
1141 # What Enum() must do is generate a new type encapsulating the
1142 # provided list/dictionary so that specific values of the parameter
1143 # can be instances of that type. We define two hidden internal
1144 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1145 # derive the new type from the appropriate base class on the fly.
1148 # Metaclass for Enum types
1149 class MetaEnum(MetaParamValue
):
1150 def __new__(mcls
, name
, bases
, dict):
1151 assert name
not in allEnums
1153 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1154 allEnums
[name
] = cls
1157 def __init__(cls
, name
, bases
, init_dict
):
1158 if init_dict
.has_key('map'):
1159 if not isinstance(cls
.map, dict):
1160 raise TypeError, "Enum-derived class attribute 'map' " \
1161 "must be of type dict"
1162 # build list of value strings from map
1163 cls
.vals
= cls
.map.keys()
1165 elif init_dict
.has_key('vals'):
1166 if not isinstance(cls
.vals
, list):
1167 raise TypeError, "Enum-derived class attribute 'vals' " \
1168 "must be of type list"
1169 # build string->value map from vals sequence
1171 for idx
,val
in enumerate(cls
.vals
):
1174 raise TypeError, "Enum-derived class must define "\
1175 "attribute 'map' or 'vals'"
1177 cls
.cxx_type
= 'Enums::%s' % name
1179 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1181 # Generate C++ class declaration for this enum type.
1182 # Note that we wrap the enum in a class/struct to act as a namespace,
1183 # so that the enum strings can be brief w/o worrying about collisions.
1184 def cxx_decl(cls
, code
):
1185 wrapper_name
= cls
.wrapper_name
1186 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1187 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1188 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1194 $wrapper $wrapper_name {
1198 for val
in cls
.vals
:
1199 code('$val = ${{cls.map[val]}},')
1200 code('Num_$name = ${{len(cls.vals)}}')
1204 if cls
.wrapper_is_struct
:
1205 code(' static const char *${name}Strings[Num_${name}];')
1208 code('extern const char *${name}Strings[Num_${name}];')
1212 code('#endif // $idem_macro')
1214 def cxx_def(cls
, code
):
1215 wrapper_name
= cls
.wrapper_name
1216 file_name
= cls
.__name
__
1217 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1219 code('#include "enums/$file_name.hh"')
1220 if cls
.wrapper_is_struct
:
1221 code('const char *${wrapper_name}::${name}Strings'
1224 code('namespace Enums {')
1226 code(' const char *${name}Strings[Num_${name}] =')
1230 for val
in cls
.vals
:
1235 if not cls
.wrapper_is_struct
:
1236 code('} // namespace $wrapper_name')
1239 def swig_decl(cls
, code
):
1242 %module(package="m5.internal") enum_$name
1245 #include "enums/$name.hh"
1248 %include "enums/$name.hh"
1252 # Base class for enum types.
1253 class Enum(ParamValue
):
1254 __metaclass__
= MetaEnum
1256 cmd_line_settable
= True
1258 # The name of the wrapping namespace or struct
1259 wrapper_name
= 'Enums'
1261 # If true, the enum is wrapped in a struct rather than a namespace
1262 wrapper_is_struct
= False
1264 # If not None, use this as the enum name rather than this class name
1267 def __init__(self
, value
):
1268 if value
not in self
.map:
1269 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1270 % (value
, self
.vals
)
1273 def __call__(self
, value
):
1274 self
.__init
__(value
)
1278 def cxx_predecls(cls
, code
):
1279 code('#include "enums/$0.hh"', cls
.__name
__)
1282 def swig_predecls(cls
, code
):
1283 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1286 return int(self
.map[self
.value
])
1291 # how big does a rounding error need to be before we warn about it?
1292 frequency_tolerance
= 0.001 # 0.1%
1294 class TickParamValue(NumericParamValue
):
1297 cmd_line_settable
= True
1300 def cxx_predecls(cls
, code
):
1301 code('#include "base/types.hh"')
1304 def swig_predecls(cls
, code
):
1305 code('%import "stdint.i"')
1306 code('%import "base/types.hh"')
1308 def __call__(self
, value
):
1309 self
.__init
__(value
)
1313 return long(self
.value
)
1315 class Latency(TickParamValue
):
1318 def __init__(self
, value
):
1319 if isinstance(value
, (Latency
, Clock
)):
1320 self
.ticks
= value
.ticks
1321 self
.value
= value
.value
1322 elif isinstance(value
, Frequency
):
1323 self
.ticks
= value
.ticks
1324 self
.value
= 1.0 / value
.value
1325 elif value
.endswith('t'):
1327 self
.value
= int(value
[:-1])
1330 self
.value
= convert
.toLatency(value
)
1332 def __call__(self
, value
):
1333 self
.__init
__(value
)
1336 def __getattr__(self
, attr
):
1337 if attr
in ('latency', 'period'):
1339 if attr
== 'frequency':
1340 return Frequency(self
)
1341 raise AttributeError, "Latency object has no attribute '%s'" % attr
1344 if self
.ticks
or self
.value
== 0:
1347 value
= ticks
.fromSeconds(self
.value
)
1350 # convert latency to ticks
1352 return '%d' % self
.getValue()
1354 class Frequency(TickParamValue
):
1357 def __init__(self
, value
):
1358 if isinstance(value
, (Latency
, Clock
)):
1359 if value
.value
== 0:
1362 self
.value
= 1.0 / value
.value
1363 self
.ticks
= value
.ticks
1364 elif isinstance(value
, Frequency
):
1365 self
.value
= value
.value
1366 self
.ticks
= value
.ticks
1369 self
.value
= convert
.toFrequency(value
)
1371 def __call__(self
, value
):
1372 self
.__init
__(value
)
1375 def __getattr__(self
, attr
):
1376 if attr
== 'frequency':
1378 if attr
in ('latency', 'period'):
1379 return Latency(self
)
1380 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1382 # convert latency to ticks
1384 if self
.ticks
or self
.value
== 0:
1387 value
= ticks
.fromSeconds(1.0 / self
.value
)
1391 return '%d' % self
.getValue()
1393 # A generic Frequency and/or Latency value. Value is stored as a
1394 # latency, just like Latency and Frequency.
1395 class Clock(TickParamValue
):
1396 def __init__(self
, value
):
1397 if isinstance(value
, (Latency
, Clock
)):
1398 self
.ticks
= value
.ticks
1399 self
.value
= value
.value
1400 elif isinstance(value
, Frequency
):
1401 self
.ticks
= value
.ticks
1402 self
.value
= 1.0 / value
.value
1403 elif value
.endswith('t'):
1405 self
.value
= int(value
[:-1])
1408 self
.value
= convert
.anyToLatency(value
)
1410 def __call__(self
, value
):
1411 self
.__init
__(value
)
1415 return "%s" % Latency(self
)
1417 def __getattr__(self
, attr
):
1418 if attr
== 'frequency':
1419 return Frequency(self
)
1420 if attr
in ('latency', 'period'):
1421 return Latency(self
)
1422 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1425 return self
.period
.getValue()
1428 return self
.period
.ini_str()
1430 class Voltage(float,ParamValue
):
1433 cmd_line_settable
= False
1435 def __new__(cls
, value
):
1436 # convert to voltage
1437 val
= convert
.toVoltage(value
)
1438 return super(cls
, Voltage
).__new
__(cls
, val
)
1440 def __call__(self
, value
):
1441 val
= convert
.toVoltage(value
)
1446 return str(self
.getValue())
1453 return '%f' % self
.getValue()
1455 class NetworkBandwidth(float,ParamValue
):
1458 cmd_line_settable
= True
1460 def __new__(cls
, value
):
1461 # convert to bits per second
1462 val
= convert
.toNetworkBandwidth(value
)
1463 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1466 return str(self
.val
)
1468 def __call__(self
, value
):
1469 val
= convert
.toNetworkBandwidth(value
)
1474 # convert to seconds per byte
1475 value
= 8.0 / float(self
)
1476 # convert to ticks per byte
1477 value
= ticks
.fromSeconds(value
)
1481 return '%f' % self
.getValue()
1483 class MemoryBandwidth(float,ParamValue
):
1486 cmd_line_settable
= True
1488 def __new__(cls
, value
):
1489 # convert to bytes per second
1490 val
= convert
.toMemoryBandwidth(value
)
1491 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1493 def __call__(self
, value
):
1494 val
= convert
.toMemoryBandwidth(value
)
1499 # convert to seconds per byte
1502 value
= 1.0 / float(self
)
1503 # convert to ticks per byte
1504 value
= ticks
.fromSeconds(value
)
1508 return '%f' % self
.getValue()
1511 # "Constants"... handy aliases for various values.
1514 # Special class for NULL pointers. Note the special check in
1515 # make_param_value() above that lets these be assigned where a
1516 # SimObject is required.
1517 # only one copy of a particular node
1518 class NullSimObject(object):
1519 __metaclass__
= Singleton
1524 def _instantiate(self
, parent
= None, path
= ''):
1530 def unproxy(self
, base
):
1533 def set_path(self
, parent
, name
):
1542 # The only instance you'll ever need...
1543 NULL
= NullSimObject()
1545 def isNullPointer(value
):
1546 return isinstance(value
, NullSimObject
)
1548 # Some memory range specifications use this as a default upper bound.
1551 AllMemory
= AddrRange(0, MaxAddr
)
1554 #####################################################################
1558 # Ports are used to interconnect objects in the memory system.
1560 #####################################################################
1562 # Port reference: encapsulates a reference to a particular port on a
1563 # particular SimObject.
1564 class PortRef(object):
1565 def __init__(self
, simobj
, name
, role
):
1566 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1567 self
.simobj
= simobj
1570 self
.peer
= None # not associated with another port yet
1571 self
.ccConnected
= False # C++ port connection done?
1572 self
.index
= -1 # always -1 for non-vector ports
1575 return '%s.%s' % (self
.simobj
, self
.name
)
1578 # Return the number of connected ports, i.e. 0 is we have no
1579 # peer and 1 if we do.
1580 return int(self
.peer
!= None)
1582 # for config.ini, print peer's name (not ours)
1584 return str(self
.peer
)
1587 def get_config_as_dict(self
):
1588 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1590 def __getattr__(self
, attr
):
1591 if attr
== 'peerObj':
1592 # shorthand for proxies
1593 return self
.peer
.simobj
1594 raise AttributeError, "'%s' object has no attribute '%s'" % \
1595 (self
.__class
__.__name
__, attr
)
1597 # Full connection is symmetric (both ways). Called via
1598 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1599 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1600 # e.g., "obj1.portA[3] = obj2.portB".
1601 def connect(self
, other
):
1602 if isinstance(other
, VectorPortRef
):
1603 # reference to plain VectorPort is implicit append
1604 other
= other
._get
_next
()
1605 if self
.peer
and not proxy
.isproxy(self
.peer
):
1606 fatal("Port %s is already connected to %s, cannot connect %s\n",
1607 self
, self
.peer
, other
);
1609 if proxy
.isproxy(other
):
1610 other
.set_param_desc(PortParamDesc())
1611 elif isinstance(other
, PortRef
):
1612 if other
.peer
is not self
:
1616 "assigning non-port reference '%s' to port '%s'" \
1619 def clone(self
, simobj
, memo
):
1620 if memo
.has_key(self
):
1622 newRef
= copy
.copy(self
)
1624 newRef
.simobj
= simobj
1625 assert(isSimObject(newRef
.simobj
))
1626 if self
.peer
and not proxy
.isproxy(self
.peer
):
1627 peerObj
= self
.peer
.simobj(_memo
=memo
)
1628 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1629 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1632 def unproxy(self
, simobj
):
1633 assert(simobj
is self
.simobj
)
1634 if proxy
.isproxy(self
.peer
):
1636 realPeer
= self
.peer
.unproxy(self
.simobj
)
1638 print "Error in unproxying port '%s' of %s" % \
1639 (self
.name
, self
.simobj
.path())
1641 self
.connect(realPeer
)
1643 # Call C++ to create corresponding port connection between C++ objects
1644 def ccConnect(self
):
1645 from m5
.internal
.pyobject
import connectPorts
1647 if self
.role
== 'SLAVE':
1648 # do nothing and let the master take care of it
1651 if self
.ccConnected
: # already done this
1654 if not self
.peer
: # nothing to connect to
1657 # check that we connect a master to a slave
1658 if self
.role
== peer
.role
:
1660 "cannot connect '%s' and '%s' due to identical role '%s'" \
1661 % (peer
, self
, self
.role
)
1664 # self is always the master and peer the slave
1665 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1666 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1668 print "Error connecting port %s.%s to %s.%s" % \
1669 (self
.simobj
.path(), self
.name
,
1670 peer
.simobj
.path(), peer
.name
)
1672 self
.ccConnected
= True
1673 peer
.ccConnected
= True
1675 # A reference to an individual element of a VectorPort... much like a
1676 # PortRef, but has an index.
1677 class VectorPortElementRef(PortRef
):
1678 def __init__(self
, simobj
, name
, role
, index
):
1679 PortRef
.__init
__(self
, simobj
, name
, role
)
1683 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1685 # A reference to a complete vector-valued port (not just a single element).
1686 # Can be indexed to retrieve individual VectorPortElementRef instances.
1687 class VectorPortRef(object):
1688 def __init__(self
, simobj
, name
, role
):
1689 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1690 self
.simobj
= simobj
1696 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1699 # Return the number of connected peers, corresponding the the
1700 # length of the elements.
1701 return len(self
.elements
)
1703 # for config.ini, print peer's name (not ours)
1705 return ' '.join([el
.ini_str() for el
in self
.elements
])
1708 def get_config_as_dict(self
):
1709 return {'role' : self
.role
,
1710 'peer' : [el
.ini_str() for el
in self
.elements
]}
1712 def __getitem__(self
, key
):
1713 if not isinstance(key
, int):
1714 raise TypeError, "VectorPort index must be integer"
1715 if key
>= len(self
.elements
):
1716 # need to extend list
1717 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1718 for i
in range(len(self
.elements
), key
+1)]
1719 self
.elements
.extend(ext
)
1720 return self
.elements
[key
]
1722 def _get_next(self
):
1723 return self
[len(self
.elements
)]
1725 def __setitem__(self
, key
, value
):
1726 if not isinstance(key
, int):
1727 raise TypeError, "VectorPort index must be integer"
1728 self
[key
].connect(value
)
1730 def connect(self
, other
):
1731 if isinstance(other
, (list, tuple)):
1732 # Assign list of port refs to vector port.
1733 # For now, append them... not sure if that's the right semantics
1734 # or if it should replace the current vector.
1736 self
._get
_next
().connect(ref
)
1738 # scalar assignment to plain VectorPort is implicit append
1739 self
._get
_next
().connect(other
)
1741 def clone(self
, simobj
, memo
):
1742 if memo
.has_key(self
):
1744 newRef
= copy
.copy(self
)
1746 newRef
.simobj
= simobj
1747 assert(isSimObject(newRef
.simobj
))
1748 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1751 def unproxy(self
, simobj
):
1752 [el
.unproxy(simobj
) for el
in self
.elements
]
1754 def ccConnect(self
):
1755 [el
.ccConnect() for el
in self
.elements
]
1757 # Port description object. Like a ParamDesc object, this represents a
1758 # logical port in the SimObject class, not a particular port on a
1759 # SimObject instance. The latter are represented by PortRef objects.
1761 # Generate a PortRef for this port on the given SimObject with the
1763 def makeRef(self
, simobj
):
1764 return PortRef(simobj
, self
.name
, self
.role
)
1766 # Connect an instance of this port (on the given SimObject with
1767 # the given name) with the port described by the supplied PortRef
1768 def connect(self
, simobj
, ref
):
1769 self
.makeRef(simobj
).connect(ref
)
1771 # No need for any pre-declarations at the moment as we merely rely
1772 # on an unsigned int.
1773 def cxx_predecls(self
, code
):
1776 # Declare an unsigned int with the same name as the port, that
1777 # will eventually hold the number of connected ports (and thus the
1778 # number of elements for a VectorPort).
1779 def cxx_decl(self
, code
):
1780 code('unsigned int port_${{self.name}}_connection_count;')
1782 class MasterPort(Port
):
1783 # MasterPort("description")
1784 def __init__(self
, *args
):
1787 self
.role
= 'MASTER'
1789 raise TypeError, 'wrong number of arguments'
1791 class SlavePort(Port
):
1792 # SlavePort("description")
1793 def __init__(self
, *args
):
1798 raise TypeError, 'wrong number of arguments'
1800 # VectorPort description object. Like Port, but represents a vector
1801 # of connections (e.g., as on a Bus).
1802 class VectorPort(Port
):
1803 def __init__(self
, *args
):
1806 def makeRef(self
, simobj
):
1807 return VectorPortRef(simobj
, self
.name
, self
.role
)
1809 class VectorMasterPort(VectorPort
):
1810 # VectorMasterPort("description")
1811 def __init__(self
, *args
):
1814 self
.role
= 'MASTER'
1815 VectorPort
.__init
__(self
, *args
)
1817 raise TypeError, 'wrong number of arguments'
1819 class VectorSlavePort(VectorPort
):
1820 # VectorSlavePort("description")
1821 def __init__(self
, *args
):
1825 VectorPort
.__init
__(self
, *args
)
1827 raise TypeError, 'wrong number of arguments'
1829 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1830 # proxy objects (via set_param_desc()) so that proxy error messages
1832 class PortParamDesc(object):
1833 __metaclass__
= Singleton
1838 baseEnums
= allEnums
.copy()
1839 baseParams
= allParams
.copy()
1842 global allEnums
, allParams
1844 allEnums
= baseEnums
.copy()
1845 allParams
= baseParams
.copy()
1847 __all__
= ['Param', 'VectorParam',
1848 'Enum', 'Bool', 'String', 'Float',
1849 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1850 'Int32', 'UInt32', 'Int64', 'UInt64',
1851 'Counter', 'Addr', 'Tick', 'Percent',
1852 'TcpPort', 'UdpPort', 'EthernetAddr',
1853 'IpAddress', 'IpNetmask', 'IpWithPort',
1854 'MemorySize', 'MemorySize32',
1855 'Latency', 'Frequency', 'Clock', 'Voltage',
1856 'NetworkBandwidth', 'MemoryBandwidth',
1858 'MaxAddr', 'MaxTick', 'AllMemory',
1860 'NextEthernetAddr', 'NULL',
1861 'MasterPort', 'SlavePort',
1862 'VectorMasterPort', 'VectorSlavePort']