f16cabaffb33a987b6c6fead6d809bac620fa451
1 # Copyright (c) 2012-2014 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 # default for printing to .json file is regular string conversion.
118 # will be overridden in some cases, mostly to use native Python
119 # types where there are similar JSON types
120 def config_value(self
):
123 # allows us to blithely call unproxy() on things without checking
124 # if they're really proxies or not
125 def unproxy(self
, base
):
128 # Produce a human readable version of the stored value
129 def pretty_print(self
, value
):
132 # Regular parameter description.
133 class ParamDesc(object):
134 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
135 self
.ptype_str
= ptype_str
136 # remember ptype only if it is provided
144 self
.default
= args
[0]
147 raise TypeError, 'too many arguments'
149 if kwargs
.has_key('desc'):
150 assert(not hasattr(self
, 'desc'))
151 self
.desc
= kwargs
['desc']
154 if kwargs
.has_key('default'):
155 assert(not hasattr(self
, 'default'))
156 self
.default
= kwargs
['default']
157 del kwargs
['default']
160 raise TypeError, 'extra unknown kwargs %s' % kwargs
162 if not hasattr(self
, 'desc'):
163 raise TypeError, 'desc attribute missing'
165 def __getattr__(self
, attr
):
167 ptype
= SimObject
.allClasses
[self
.ptype_str
]
168 assert isSimObjectClass(ptype
)
172 raise AttributeError, "'%s' object has no attribute '%s'" % \
173 (type(self
).__name
__, attr
)
175 def example_str(self
):
176 if hasattr(self
.ptype
, "ex_str"):
177 return self
.ptype
.ex_str
179 return self
.ptype_str
181 # Is the param available to be exposed on the command line
182 def isCmdLineSettable(self
):
183 if hasattr(self
.ptype
, "cmd_line_settable"):
184 return self
.ptype
.cmd_line_settable
188 def convert(self
, value
):
189 if isinstance(value
, proxy
.BaseProxy
):
190 value
.set_param_desc(self
)
192 if not hasattr(self
, 'ptype') and isNullPointer(value
):
193 # deferred evaluation of SimObject; continue to defer if
194 # we're just assigning a null pointer
196 if isinstance(value
, self
.ptype
):
198 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
200 return self
.ptype(value
)
202 def pretty_print(self
, value
):
203 if isinstance(value
, proxy
.BaseProxy
):
205 if isNullPointer(value
):
207 return self
.ptype(value
).pretty_print(value
)
209 def cxx_predecls(self
, code
):
210 code('#include <cstddef>')
211 self
.ptype
.cxx_predecls(code
)
213 def swig_predecls(self
, code
):
214 self
.ptype
.swig_predecls(code
)
216 def cxx_decl(self
, code
):
217 code('${{self.ptype.cxx_type}} ${{self.name}};')
219 # Vector-valued parameter description. Just like ParamDesc, except
220 # that the value is a vector (list) of the specified type instead of a
223 class VectorParamValue(list):
224 __metaclass__
= MetaParamValue
225 def __setattr__(self
, attr
, value
):
226 raise AttributeError, \
227 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
229 def config_value(self
):
230 return [v
.config_value() for v
in self
]
233 return ' '.join([v
.ini_str() for v
in self
])
236 return [ v
.getValue() for v
in self
]
238 def unproxy(self
, base
):
239 if len(self
) == 1 and isinstance(self
[0], proxy
.AllProxy
):
240 return self
[0].unproxy(base
)
242 return [v
.unproxy(base
) for v
in self
]
244 class SimObjectVector(VectorParamValue
):
245 # support clone operation
246 def __call__(self
, **kwargs
):
247 return SimObjectVector([v(**kwargs
) for v
in self
])
249 def clear_parent(self
, old_parent
):
251 v
.clear_parent(old_parent
)
253 def set_parent(self
, parent
, name
):
255 self
[0].set_parent(parent
, name
)
257 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
258 for i
,v
in enumerate(self
):
259 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
261 def has_parent(self
):
262 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
264 # return 'cpu0 cpu1' etc. for print_ini()
266 return ' '.join([v
._name
for v
in self
])
268 # By iterating through the constituent members of the vector here
269 # we can nicely handle iterating over all a SimObject's children
270 # without having to provide lots of special functions on
271 # SimObjectVector directly.
272 def descendants(self
):
274 for obj
in v
.descendants():
277 def get_config_as_dict(self
):
280 a
.append(v
.get_config_as_dict())
283 # If we are replacing an item in the vector, make sure to set the
284 # parent reference of the new SimObject to be the same as the parent
285 # of the SimObject being replaced. Useful to have if we created
286 # a SimObjectVector of temporary objects that will be modified later in
287 # configuration scripts.
288 def __setitem__(self
, key
, value
):
290 if value
.has_parent():
291 warn("SimObject %s already has a parent" % value
.get_name() +\
292 " that is being overwritten by a SimObjectVector")
293 value
.set_parent(val
.get_parent(), val
._name
)
294 super(SimObjectVector
, self
).__setitem
__(key
, value
)
296 # Enumerate the params of each member of the SimObject vector. Creates
297 # strings that will allow indexing into the vector by the python code and
298 # allow it to be specified on the command line.
299 def enumerateParams(self
, flags_dict
= {},
302 if hasattr(self
, "_paramEnumed"):
303 print "Cycle detected enumerating params at %s?!" % (cmd_line_str
)
307 # Each entry in the SimObjectVector should be an
308 # instance of a SimObject
309 flags_dict
= vals
.enumerateParams(flags_dict
,
310 cmd_line_str
+ "%d." % x
,
311 access_str
+ "[%d]." % x
)
316 class VectorParamDesc(ParamDesc
):
317 # Convert assigned value to appropriate type. If the RHS is not a
318 # list or tuple, it generates a single-element list.
319 def convert(self
, value
):
320 if isinstance(value
, (list, tuple)):
321 # list: coerce each element into new list
322 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
323 elif isinstance(value
, str):
324 # If input is a csv string
325 tmp_list
= [ ParamDesc
.convert(self
, v
) \
326 for v
in value
.strip('[').strip(']').split(',') ]
328 # singleton: coerce to a single-element list
329 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
331 if isSimObjectSequence(tmp_list
):
332 return SimObjectVector(tmp_list
)
334 return VectorParamValue(tmp_list
)
336 # Produce a human readable example string that describes
337 # how to set this vector parameter in the absence of a default
339 def example_str(self
):
340 s
= super(VectorParamDesc
, self
).example_str()
341 help_str
= "[" + s
+ "," + s
+ ", ...]"
344 # Produce a human readable representation of the value of this vector param.
345 def pretty_print(self
, value
):
346 if isinstance(value
, (list, tuple)):
347 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
348 elif isinstance(value
, str):
349 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
351 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
355 # This is a helper function for the new config system
356 def __call__(self
, value
):
357 if isinstance(value
, (list, tuple)):
358 # list: coerce each element into new list
359 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
360 elif isinstance(value
, str):
361 # If input is a csv string
362 tmp_list
= [ ParamDesc
.convert(self
, v
) \
363 for v
in value
.strip('[').strip(']').split(',') ]
365 # singleton: coerce to a single-element list
366 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
368 return VectorParamValue(tmp_list
)
370 def swig_module_name(self
):
371 return "%s_vector" % self
.ptype_str
373 def swig_predecls(self
, code
):
374 code('%import "${{self.swig_module_name()}}.i"')
376 def swig_decl(self
, code
):
377 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
379 self
.ptype
.cxx_predecls(code
)
382 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
383 code('%include "std_container.i"')
385 self
.ptype
.swig_predecls(code
)
387 code('%include "std_vector.i"')
390 ptype
= self
.ptype_str
391 cxx_type
= self
.ptype
.cxx_type
393 code('%template(vector_$ptype) std::vector< $cxx_type >;')
395 def cxx_predecls(self
, code
):
396 code('#include <vector>')
397 self
.ptype
.cxx_predecls(code
)
399 def cxx_decl(self
, code
):
400 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
402 class ParamFactory(object):
403 def __init__(self
, param_desc_class
, ptype_str
= None):
404 self
.param_desc_class
= param_desc_class
405 self
.ptype_str
= ptype_str
407 def __getattr__(self
, attr
):
409 attr
= self
.ptype_str
+ '.' + attr
410 return ParamFactory(self
.param_desc_class
, attr
)
412 # E.g., Param.Int(5, "number of widgets")
413 def __call__(self
, *args
, **kwargs
):
416 ptype
= allParams
[self
.ptype_str
]
418 # if name isn't defined yet, assume it's a SimObject, and
419 # try to resolve it later
421 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
423 Param
= ParamFactory(ParamDesc
)
424 VectorParam
= ParamFactory(VectorParamDesc
)
426 #####################################################################
430 # Though native Python types could be used to specify parameter types
431 # (the 'ptype' field of the Param and VectorParam classes), it's more
432 # flexible to define our own set of types. This gives us more control
433 # over how Python expressions are converted to values (via the
434 # __init__() constructor) and how these values are printed out (via
435 # the __str__() conversion method).
437 #####################################################################
439 # String-valued parameter. Just mixin the ParamValue class with the
440 # built-in str class.
441 class String(ParamValue
,str):
442 cxx_type
= 'std::string'
443 cmd_line_settable
= True
446 def cxx_predecls(self
, code
):
447 code('#include <string>')
450 def swig_predecls(cls
, code
):
451 code('%include "std_string.i"')
453 def __call__(self
, value
):
460 # superclass for "numeric" parameter values, to emulate math
461 # operations in a type-safe way. e.g., a Latency times an int returns
462 # a new Latency object.
463 class NumericParamValue(ParamValue
):
465 return str(self
.value
)
468 return float(self
.value
)
471 return long(self
.value
)
474 return int(self
.value
)
476 # hook for bounds checking
480 def __mul__(self
, other
):
481 newobj
= self
.__class
__(self
)
482 newobj
.value
*= other
488 def __div__(self
, other
):
489 newobj
= self
.__class
__(self
)
490 newobj
.value
/= other
494 def __sub__(self
, other
):
495 newobj
= self
.__class
__(self
)
496 newobj
.value
-= other
500 def config_value(self
):
503 # Metaclass for bounds-checked integer parameters. See CheckedInt.
504 class CheckedIntType(MetaParamValue
):
505 def __init__(cls
, name
, bases
, dict):
506 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
508 # CheckedInt is an abstract base class, so we actually don't
509 # want to do any processing on it... the rest of this code is
510 # just for classes that derive from CheckedInt.
511 if name
== 'CheckedInt':
514 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
515 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
516 panic("CheckedInt subclass %s must define either\n" \
517 " 'min' and 'max' or 'size' and 'unsigned'\n",
521 cls
.max = 2 ** cls
.size
- 1
523 cls
.min = -(2 ** (cls
.size
- 1))
524 cls
.max = (2 ** (cls
.size
- 1)) - 1
526 # Abstract superclass for bounds-checked integer parameters. This
527 # class is subclassed to generate parameter classes with specific
528 # bounds. Initialization of the min and max bounds is done in the
529 # metaclass CheckedIntType.__init__.
530 class CheckedInt(NumericParamValue
):
531 __metaclass__
= CheckedIntType
532 cmd_line_settable
= True
535 if not self
.min <= self
.value
<= self
.max:
536 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
537 (self
.min, self
.value
, self
.max)
539 def __init__(self
, value
):
540 if isinstance(value
, str):
541 self
.value
= convert
.toInteger(value
)
542 elif isinstance(value
, (int, long, float, NumericParamValue
)):
543 self
.value
= long(value
)
545 raise TypeError, "Can't convert object of type %s to CheckedInt" \
546 % type(value
).__name
__
549 def __call__(self
, value
):
554 def cxx_predecls(cls
, code
):
555 # most derived types require this, so we just do it here once
556 code('#include "base/types.hh"')
559 def swig_predecls(cls
, code
):
560 # most derived types require this, so we just do it here once
561 code('%import "stdint.i"')
562 code('%import "base/types.hh"')
565 return long(self
.value
)
567 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
568 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
570 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
571 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
572 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
573 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
574 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
575 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
576 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
577 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
579 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
580 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
581 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
582 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
584 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
586 class Cycles(CheckedInt
):
592 from m5
.internal
.core
import Cycles
593 return Cycles(self
.value
)
595 class Float(ParamValue
, float):
597 cmdLineSettable
= True
599 def __init__(self
, value
):
600 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
601 self
.value
= float(value
)
603 raise TypeError, "Can't convert object of type %s to Float" \
604 % type(value
).__name
__
606 def __call__(self
, value
):
611 return float(self
.value
)
613 def config_value(self
):
616 class MemorySize(CheckedInt
):
617 cxx_type
= 'uint64_t'
621 def __init__(self
, value
):
622 if isinstance(value
, MemorySize
):
623 self
.value
= value
.value
625 self
.value
= convert
.toMemorySize(value
)
628 class MemorySize32(CheckedInt
):
629 cxx_type
= 'uint32_t'
633 def __init__(self
, value
):
634 if isinstance(value
, MemorySize
):
635 self
.value
= value
.value
637 self
.value
= convert
.toMemorySize(value
)
640 class Addr(CheckedInt
):
644 def __init__(self
, value
):
645 if isinstance(value
, Addr
):
646 self
.value
= value
.value
649 # Often addresses are referred to with sizes. Ex: A device
650 # base address is at "512MB". Use toMemorySize() to convert
651 # these into addresses. If the address is not specified with a
652 # "size", an exception will occur and numeric translation will
654 self
.value
= convert
.toMemorySize(value
)
655 except (TypeError, ValueError):
656 # Convert number to string and use long() to do automatic
657 # base conversion (requires base=0 for auto-conversion)
658 self
.value
= long(str(value
), base
=0)
661 def __add__(self
, other
):
662 if isinstance(other
, Addr
):
663 return self
.value
+ other
.value
665 return self
.value
+ other
666 def pretty_print(self
, value
):
668 val
= convert
.toMemorySize(value
)
671 return "0x%x" % long(val
)
673 class AddrRange(ParamValue
):
674 cxx_type
= 'AddrRange'
676 def __init__(self
, *args
, **kwargs
):
677 # Disable interleaving by default
678 self
.intlvHighBit
= 0
682 def handle_kwargs(self
, kwargs
):
683 # An address range needs to have an upper limit, specified
684 # either explicitly with an end, or as an offset using the
687 self
.end
= Addr(kwargs
.pop('end'))
688 elif 'size' in kwargs
:
689 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
691 raise TypeError, "Either end or size must be specified"
693 # Now on to the optional bit
694 if 'intlvHighBit' in kwargs
:
695 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
696 if 'intlvBits' in kwargs
:
697 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
698 if 'intlvMatch' in kwargs
:
699 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
702 self
.start
= Addr(kwargs
.pop('start'))
703 handle_kwargs(self
, kwargs
)
707 self
.start
= Addr(args
[0])
708 handle_kwargs(self
, kwargs
)
709 elif isinstance(args
[0], (list, tuple)):
710 self
.start
= Addr(args
[0][0])
711 self
.end
= Addr(args
[0][1])
714 self
.end
= Addr(args
[0]) - 1
717 self
.start
= Addr(args
[0])
718 self
.end
= Addr(args
[1])
720 raise TypeError, "Too many arguments specified"
723 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
726 return '%s:%s' % (self
.start
, self
.end
)
729 # Divide the size by the size of the interleaving slice
730 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
733 def cxx_predecls(cls
, code
):
734 Addr
.cxx_predecls(code
)
735 code('#include "base/addr_range.hh"')
738 def swig_predecls(cls
, code
):
739 Addr
.swig_predecls(code
)
742 # Go from the Python class to the wrapped C++ class generated
744 from m5
.internal
.range import AddrRange
746 return AddrRange(long(self
.start
), long(self
.end
),
747 int(self
.intlvHighBit
), int(self
.intlvBits
),
748 int(self
.intlvMatch
))
750 # Boolean parameter type. Python doesn't let you subclass bool, since
751 # it doesn't want to let you create multiple instances of True and
752 # False. Thus this is a little more complicated than String.
753 class Bool(ParamValue
):
755 cmd_line_settable
= True
757 def __init__(self
, value
):
759 self
.value
= convert
.toBool(value
)
761 self
.value
= bool(value
)
763 def __call__(self
, value
):
768 return bool(self
.value
)
771 return str(self
.value
)
773 # implement truth value testing for Bool parameters so that these params
774 # evaluate correctly during the python configuration phase
775 def __nonzero__(self
):
776 return bool(self
.value
)
783 def config_value(self
):
786 def IncEthernetAddr(addr
, val
= 1):
787 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
789 for i
in (5, 4, 3, 2, 1):
790 val
,rem
= divmod(bytes
[i
], 256)
795 assert(bytes
[0] <= 255)
796 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
798 _NextEthernetAddr
= "00:90:00:00:00:01"
799 def NextEthernetAddr():
800 global _NextEthernetAddr
802 value
= _NextEthernetAddr
803 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
806 class EthernetAddr(ParamValue
):
807 cxx_type
= 'Net::EthAddr'
808 ex_str
= "00:90:00:00:00:01"
809 cmd_line_settable
= True
812 def cxx_predecls(cls
, code
):
813 code('#include "base/inet.hh"')
816 def swig_predecls(cls
, code
):
817 code('%include "python/swig/inet.i"')
819 def __init__(self
, value
):
820 if value
== NextEthernetAddr
:
824 if not isinstance(value
, str):
825 raise TypeError, "expected an ethernet address and didn't get one"
827 bytes
= value
.split(':')
829 raise TypeError, 'invalid ethernet address %s' % value
832 if not 0 <= int(byte
, base
=16) <= 0xff:
833 raise TypeError, 'invalid ethernet address %s' % value
837 def __call__(self
, value
):
841 def unproxy(self
, base
):
842 if self
.value
== NextEthernetAddr
:
843 return EthernetAddr(self
.value())
847 from m5
.internal
.params
import EthAddr
848 return EthAddr(self
.value
)
853 # When initializing an IpAddress, pass in an existing IpAddress, a string of
854 # the form "a.b.c.d", or an integer representing an IP.
855 class IpAddress(ParamValue
):
856 cxx_type
= 'Net::IpAddress'
858 cmd_line_settable
= True
861 def cxx_predecls(cls
, code
):
862 code('#include "base/inet.hh"')
865 def swig_predecls(cls
, code
):
866 code('%include "python/swig/inet.i"')
868 def __init__(self
, value
):
869 if isinstance(value
, IpAddress
):
873 self
.ip
= convert
.toIpAddress(value
)
875 self
.ip
= long(value
)
878 def __call__(self
, value
):
883 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
884 return '%d.%d.%d.%d' % tuple(tup
)
886 def __eq__(self
, other
):
887 if isinstance(other
, IpAddress
):
888 return self
.ip
== other
.ip
889 elif isinstance(other
, str):
891 return self
.ip
== convert
.toIpAddress(other
)
895 return self
.ip
== other
897 def __ne__(self
, other
):
898 return not (self
== other
)
901 if self
.ip
< 0 or self
.ip
>= (1 << 32):
902 raise TypeError, "invalid ip address %#08x" % self
.ip
905 from m5
.internal
.params
import IpAddress
906 return IpAddress(self
.ip
)
908 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
909 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
910 # positional or keyword arguments.
911 class IpNetmask(IpAddress
):
912 cxx_type
= 'Net::IpNetmask'
913 ex_str
= "127.0.0.0/24"
914 cmd_line_settable
= True
917 def cxx_predecls(cls
, code
):
918 code('#include "base/inet.hh"')
921 def swig_predecls(cls
, code
):
922 code('%include "python/swig/inet.i"')
924 def __init__(self
, *args
, **kwargs
):
925 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
927 setattr(self
, key
, kwargs
.pop(key
))
929 setattr(self
, key
, elseVal
)
931 raise TypeError, "No value set for %s" % key
934 handle_kwarg(self
, kwargs
, 'ip')
935 handle_kwarg(self
, kwargs
, 'netmask')
939 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
940 raise TypeError, "Invalid arguments"
941 handle_kwarg(self
, kwargs
, 'ip', args
[0])
942 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
943 elif isinstance(args
[0], IpNetmask
):
945 self
.netmask
= args
[0].netmask
947 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
951 self
.netmask
= args
[1]
953 raise TypeError, "Too many arguments specified"
956 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
960 def __call__(self
, value
):
965 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
967 def __eq__(self
, other
):
968 if isinstance(other
, IpNetmask
):
969 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
970 elif isinstance(other
, str):
972 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
980 if self
.netmask
< 0 or self
.netmask
> 32:
981 raise TypeError, "invalid netmask %d" % netmask
984 from m5
.internal
.params
import IpNetmask
985 return IpNetmask(self
.ip
, self
.netmask
)
987 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
988 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
989 class IpWithPort(IpAddress
):
990 cxx_type
= 'Net::IpWithPort'
991 ex_str
= "127.0.0.1:80"
992 cmd_line_settable
= True
995 def cxx_predecls(cls
, code
):
996 code('#include "base/inet.hh"')
999 def swig_predecls(cls
, code
):
1000 code('%include "python/swig/inet.i"')
1002 def __init__(self
, *args
, **kwargs
):
1003 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1005 setattr(self
, key
, kwargs
.pop(key
))
1007 setattr(self
, key
, elseVal
)
1009 raise TypeError, "No value set for %s" % key
1012 handle_kwarg(self
, kwargs
, 'ip')
1013 handle_kwarg(self
, kwargs
, 'port')
1015 elif len(args
) == 1:
1017 if not 'ip' in kwargs
and not 'port' in kwargs
:
1018 raise TypeError, "Invalid arguments"
1019 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1020 handle_kwarg(self
, kwargs
, 'port', args
[0])
1021 elif isinstance(args
[0], IpWithPort
):
1022 self
.ip
= args
[0].ip
1023 self
.port
= args
[0].port
1025 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1027 elif len(args
) == 2:
1031 raise TypeError, "Too many arguments specified"
1034 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1038 def __call__(self
, value
):
1039 self
.__init
__(value
)
1043 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1045 def __eq__(self
, other
):
1046 if isinstance(other
, IpWithPort
):
1047 return self
.ip
== other
.ip
and self
.port
== other
.port
1048 elif isinstance(other
, str):
1050 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1058 if self
.port
< 0 or self
.port
> 0xffff:
1059 raise TypeError, "invalid port %d" % self
.port
1062 from m5
.internal
.params
import IpWithPort
1063 return IpWithPort(self
.ip
, self
.port
)
1065 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1066 "%a %b %d %H:%M:%S %Y",
1067 "%Y/%m/%d %H:%M:%S",
1070 "%m/%d/%Y %H:%M:%S",
1073 "%m/%d/%y %H:%M:%S",
1078 def parse_time(value
):
1079 from time
import gmtime
, strptime
, struct_time
, time
1080 from datetime
import datetime
, date
1082 if isinstance(value
, struct_time
):
1085 if isinstance(value
, (int, long)):
1086 return gmtime(value
)
1088 if isinstance(value
, (datetime
, date
)):
1089 return value
.timetuple()
1091 if isinstance(value
, str):
1092 if value
in ('Now', 'Today'):
1093 return time
.gmtime(time
.time())
1095 for format
in time_formats
:
1097 return strptime(value
, format
)
1101 raise ValueError, "Could not parse '%s' as a time" % value
1103 class Time(ParamValue
):
1107 def cxx_predecls(cls
, code
):
1108 code('#include <time.h>')
1111 def swig_predecls(cls
, code
):
1112 code('%include "python/swig/time.i"')
1114 def __init__(self
, value
):
1115 self
.value
= parse_time(value
)
1117 def __call__(self
, value
):
1118 self
.__init
__(value
)
1122 from m5
.internal
.params
import tm
1125 py_time
= self
.value
1127 # UNIX is years since 1900
1128 c_time
.tm_year
= py_time
.tm_year
- 1900;
1130 # Python starts at 1, UNIX starts at 0
1131 c_time
.tm_mon
= py_time
.tm_mon
- 1;
1132 c_time
.tm_mday
= py_time
.tm_mday
;
1133 c_time
.tm_hour
= py_time
.tm_hour
;
1134 c_time
.tm_min
= py_time
.tm_min
;
1135 c_time
.tm_sec
= py_time
.tm_sec
;
1137 # Python has 0 as Monday, UNIX is 0 as sunday
1138 c_time
.tm_wday
= py_time
.tm_wday
+ 1
1139 if c_time
.tm_wday
> 6:
1140 c_time
.tm_wday
-= 7;
1142 # Python starts at 1, Unix starts at 0
1143 c_time
.tm_yday
= py_time
.tm_yday
- 1;
1148 return time
.asctime(self
.value
)
1153 def get_config_as_dict(self
):
1157 # Enumerated types are a little more complex. The user specifies the
1158 # type as Enum(foo) where foo is either a list or dictionary of
1159 # alternatives (typically strings, but not necessarily so). (In the
1160 # long run, the integer value of the parameter will be the list index
1161 # or the corresponding dictionary value. For now, since we only check
1162 # that the alternative is valid and then spit it into a .ini file,
1163 # there's not much point in using the dictionary.)
1165 # What Enum() must do is generate a new type encapsulating the
1166 # provided list/dictionary so that specific values of the parameter
1167 # can be instances of that type. We define two hidden internal
1168 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1169 # derive the new type from the appropriate base class on the fly.
1172 # Metaclass for Enum types
1173 class MetaEnum(MetaParamValue
):
1174 def __new__(mcls
, name
, bases
, dict):
1175 assert name
not in allEnums
1177 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1178 allEnums
[name
] = cls
1181 def __init__(cls
, name
, bases
, init_dict
):
1182 if init_dict
.has_key('map'):
1183 if not isinstance(cls
.map, dict):
1184 raise TypeError, "Enum-derived class attribute 'map' " \
1185 "must be of type dict"
1186 # build list of value strings from map
1187 cls
.vals
= cls
.map.keys()
1189 elif init_dict
.has_key('vals'):
1190 if not isinstance(cls
.vals
, list):
1191 raise TypeError, "Enum-derived class attribute 'vals' " \
1192 "must be of type list"
1193 # build string->value map from vals sequence
1195 for idx
,val
in enumerate(cls
.vals
):
1198 raise TypeError, "Enum-derived class must define "\
1199 "attribute 'map' or 'vals'"
1201 cls
.cxx_type
= 'Enums::%s' % name
1203 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1205 # Generate C++ class declaration for this enum type.
1206 # Note that we wrap the enum in a class/struct to act as a namespace,
1207 # so that the enum strings can be brief w/o worrying about collisions.
1208 def cxx_decl(cls
, code
):
1209 wrapper_name
= cls
.wrapper_name
1210 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1211 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1212 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1218 $wrapper $wrapper_name {
1222 for val
in cls
.vals
:
1223 code('$val = ${{cls.map[val]}},')
1224 code('Num_$name = ${{len(cls.vals)}}')
1228 if cls
.wrapper_is_struct
:
1229 code(' static const char *${name}Strings[Num_${name}];')
1232 code('extern const char *${name}Strings[Num_${name}];')
1236 code('#endif // $idem_macro')
1238 def cxx_def(cls
, code
):
1239 wrapper_name
= cls
.wrapper_name
1240 file_name
= cls
.__name
__
1241 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1243 code('#include "enums/$file_name.hh"')
1244 if cls
.wrapper_is_struct
:
1245 code('const char *${wrapper_name}::${name}Strings'
1248 code('namespace Enums {')
1250 code(' const char *${name}Strings[Num_${name}] =')
1254 for val
in cls
.vals
:
1259 if not cls
.wrapper_is_struct
:
1260 code('} // namespace $wrapper_name')
1263 def swig_decl(cls
, code
):
1266 %module(package="m5.internal") enum_$name
1269 #include "enums/$name.hh"
1272 %include "enums/$name.hh"
1276 # Base class for enum types.
1277 class Enum(ParamValue
):
1278 __metaclass__
= MetaEnum
1280 cmd_line_settable
= True
1282 # The name of the wrapping namespace or struct
1283 wrapper_name
= 'Enums'
1285 # If true, the enum is wrapped in a struct rather than a namespace
1286 wrapper_is_struct
= False
1288 # If not None, use this as the enum name rather than this class name
1291 def __init__(self
, value
):
1292 if value
not in self
.map:
1293 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1294 % (value
, self
.vals
)
1297 def __call__(self
, value
):
1298 self
.__init
__(value
)
1302 def cxx_predecls(cls
, code
):
1303 code('#include "enums/$0.hh"', cls
.__name
__)
1306 def swig_predecls(cls
, code
):
1307 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1310 return int(self
.map[self
.value
])
1315 # how big does a rounding error need to be before we warn about it?
1316 frequency_tolerance
= 0.001 # 0.1%
1318 class TickParamValue(NumericParamValue
):
1321 cmd_line_settable
= True
1324 def cxx_predecls(cls
, code
):
1325 code('#include "base/types.hh"')
1328 def swig_predecls(cls
, code
):
1329 code('%import "stdint.i"')
1330 code('%import "base/types.hh"')
1332 def __call__(self
, value
):
1333 self
.__init
__(value
)
1337 return long(self
.value
)
1339 class Latency(TickParamValue
):
1342 def __init__(self
, value
):
1343 if isinstance(value
, (Latency
, Clock
)):
1344 self
.ticks
= value
.ticks
1345 self
.value
= value
.value
1346 elif isinstance(value
, Frequency
):
1347 self
.ticks
= value
.ticks
1348 self
.value
= 1.0 / value
.value
1349 elif value
.endswith('t'):
1351 self
.value
= int(value
[:-1])
1354 self
.value
= convert
.toLatency(value
)
1356 def __call__(self
, value
):
1357 self
.__init
__(value
)
1360 def __getattr__(self
, attr
):
1361 if attr
in ('latency', 'period'):
1363 if attr
== 'frequency':
1364 return Frequency(self
)
1365 raise AttributeError, "Latency object has no attribute '%s'" % attr
1368 if self
.ticks
or self
.value
== 0:
1371 value
= ticks
.fromSeconds(self
.value
)
1374 def config_value(self
):
1375 return self
.getValue()
1377 # convert latency to ticks
1379 return '%d' % self
.getValue()
1381 class Frequency(TickParamValue
):
1384 def __init__(self
, value
):
1385 if isinstance(value
, (Latency
, Clock
)):
1386 if value
.value
== 0:
1389 self
.value
= 1.0 / value
.value
1390 self
.ticks
= value
.ticks
1391 elif isinstance(value
, Frequency
):
1392 self
.value
= value
.value
1393 self
.ticks
= value
.ticks
1396 self
.value
= convert
.toFrequency(value
)
1398 def __call__(self
, value
):
1399 self
.__init
__(value
)
1402 def __getattr__(self
, attr
):
1403 if attr
== 'frequency':
1405 if attr
in ('latency', 'period'):
1406 return Latency(self
)
1407 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1409 # convert latency to ticks
1411 if self
.ticks
or self
.value
== 0:
1414 value
= ticks
.fromSeconds(1.0 / self
.value
)
1417 def config_value(self
):
1418 return self
.getValue()
1421 return '%d' % self
.getValue()
1423 # A generic Frequency and/or Latency value. Value is stored as a
1424 # latency, just like Latency and Frequency.
1425 class Clock(TickParamValue
):
1426 def __init__(self
, value
):
1427 if isinstance(value
, (Latency
, Clock
)):
1428 self
.ticks
= value
.ticks
1429 self
.value
= value
.value
1430 elif isinstance(value
, Frequency
):
1431 self
.ticks
= value
.ticks
1432 self
.value
= 1.0 / value
.value
1433 elif value
.endswith('t'):
1435 self
.value
= int(value
[:-1])
1438 self
.value
= convert
.anyToLatency(value
)
1440 def __call__(self
, value
):
1441 self
.__init
__(value
)
1445 return "%s" % Latency(self
)
1447 def __getattr__(self
, attr
):
1448 if attr
== 'frequency':
1449 return Frequency(self
)
1450 if attr
in ('latency', 'period'):
1451 return Latency(self
)
1452 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1455 return self
.period
.getValue()
1457 def config_value(self
):
1458 return self
.period
.config_value()
1461 return self
.period
.ini_str()
1463 class Voltage(float,ParamValue
):
1466 cmd_line_settable
= False
1468 def __new__(cls
, value
):
1469 # convert to voltage
1470 val
= convert
.toVoltage(value
)
1471 return super(cls
, Voltage
).__new
__(cls
, val
)
1473 def __call__(self
, value
):
1474 val
= convert
.toVoltage(value
)
1479 return str(self
.getValue())
1486 return '%f' % self
.getValue()
1488 class Current(float, ParamValue
):
1491 cmd_line_settable
= False
1493 def __new__(cls
, value
):
1494 # convert to current
1495 val
= convert
.toCurrent(value
)
1496 return super(cls
, Current
).__new
__(cls
, val
)
1498 def __call__(self
, value
):
1499 val
= convert
.toCurrent(value
)
1504 return str(self
.getValue())
1511 return '%f' % self
.getValue()
1513 class NetworkBandwidth(float,ParamValue
):
1516 cmd_line_settable
= True
1518 def __new__(cls
, value
):
1519 # convert to bits per second
1520 val
= convert
.toNetworkBandwidth(value
)
1521 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1524 return str(self
.val
)
1526 def __call__(self
, value
):
1527 val
= convert
.toNetworkBandwidth(value
)
1532 # convert to seconds per byte
1533 value
= 8.0 / float(self
)
1534 # convert to ticks per byte
1535 value
= ticks
.fromSeconds(value
)
1539 return '%f' % self
.getValue()
1541 def config_value(self
):
1542 return '%f' % self
.getValue()
1544 class MemoryBandwidth(float,ParamValue
):
1547 cmd_line_settable
= True
1549 def __new__(cls
, value
):
1550 # convert to bytes per second
1551 val
= convert
.toMemoryBandwidth(value
)
1552 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1554 def __call__(self
, value
):
1555 val
= convert
.toMemoryBandwidth(value
)
1560 # convert to seconds per byte
1563 value
= 1.0 / float(self
)
1564 # convert to ticks per byte
1565 value
= ticks
.fromSeconds(value
)
1569 return '%f' % self
.getValue()
1571 def config_value(self
):
1572 return '%f' % self
.getValue()
1575 # "Constants"... handy aliases for various values.
1578 # Special class for NULL pointers. Note the special check in
1579 # make_param_value() above that lets these be assigned where a
1580 # SimObject is required.
1581 # only one copy of a particular node
1582 class NullSimObject(object):
1583 __metaclass__
= Singleton
1588 def _instantiate(self
, parent
= None, path
= ''):
1594 def unproxy(self
, base
):
1597 def set_path(self
, parent
, name
):
1603 def config_value(self
):
1609 # The only instance you'll ever need...
1610 NULL
= NullSimObject()
1612 def isNullPointer(value
):
1613 return isinstance(value
, NullSimObject
)
1615 # Some memory range specifications use this as a default upper bound.
1618 AllMemory
= AddrRange(0, MaxAddr
)
1621 #####################################################################
1625 # Ports are used to interconnect objects in the memory system.
1627 #####################################################################
1629 # Port reference: encapsulates a reference to a particular port on a
1630 # particular SimObject.
1631 class PortRef(object):
1632 def __init__(self
, simobj
, name
, role
):
1633 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1634 self
.simobj
= simobj
1637 self
.peer
= None # not associated with another port yet
1638 self
.ccConnected
= False # C++ port connection done?
1639 self
.index
= -1 # always -1 for non-vector ports
1642 return '%s.%s' % (self
.simobj
, self
.name
)
1645 # Return the number of connected ports, i.e. 0 is we have no
1646 # peer and 1 if we do.
1647 return int(self
.peer
!= None)
1649 # for config.ini, print peer's name (not ours)
1651 return str(self
.peer
)
1654 def get_config_as_dict(self
):
1655 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1657 def __getattr__(self
, attr
):
1658 if attr
== 'peerObj':
1659 # shorthand for proxies
1660 return self
.peer
.simobj
1661 raise AttributeError, "'%s' object has no attribute '%s'" % \
1662 (self
.__class
__.__name
__, attr
)
1664 # Full connection is symmetric (both ways). Called via
1665 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1666 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1667 # e.g., "obj1.portA[3] = obj2.portB".
1668 def connect(self
, other
):
1669 if isinstance(other
, VectorPortRef
):
1670 # reference to plain VectorPort is implicit append
1671 other
= other
._get
_next
()
1672 if self
.peer
and not proxy
.isproxy(self
.peer
):
1673 fatal("Port %s is already connected to %s, cannot connect %s\n",
1674 self
, self
.peer
, other
);
1676 if proxy
.isproxy(other
):
1677 other
.set_param_desc(PortParamDesc())
1678 elif isinstance(other
, PortRef
):
1679 if other
.peer
is not self
:
1683 "assigning non-port reference '%s' to port '%s'" \
1686 # Allow a master/slave port pair to be spliced between
1687 # a port and its connected peer. Useful operation for connecting
1688 # instrumentation structures into a system when it is necessary
1689 # to connect the instrumentation after the full system has been
1691 def splice(self
, new_master_peer
, new_slave_peer
):
1692 if self
.peer
and not proxy
.isproxy(self
.peer
):
1693 if isinstance(new_master_peer
, PortRef
) and \
1694 isinstance(new_slave_peer
, PortRef
):
1695 old_peer
= self
.peer
1696 if self
.role
== 'SLAVE':
1697 self
.peer
= new_master_peer
1698 old_peer
.peer
= new_slave_peer
1699 new_master_peer
.connect(self
)
1700 new_slave_peer
.connect(old_peer
)
1701 elif self
.role
== 'MASTER':
1702 self
.peer
= new_slave_peer
1703 old_peer
.peer
= new_master_peer
1704 new_slave_peer
.connect(self
)
1705 new_master_peer
.connect(old_peer
)
1707 panic("Port %s has unknown role, "+\
1708 "cannot splice in new peers\n", self
)
1711 "Splicing non-port references '%s','%s' to port '%s'"\
1712 % (new_peer
, peers_new_peer
, self
)
1714 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1716 def clone(self
, simobj
, memo
):
1717 if memo
.has_key(self
):
1719 newRef
= copy
.copy(self
)
1721 newRef
.simobj
= simobj
1722 assert(isSimObject(newRef
.simobj
))
1723 if self
.peer
and not proxy
.isproxy(self
.peer
):
1724 peerObj
= self
.peer
.simobj(_memo
=memo
)
1725 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1726 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1729 def unproxy(self
, simobj
):
1730 assert(simobj
is self
.simobj
)
1731 if proxy
.isproxy(self
.peer
):
1733 realPeer
= self
.peer
.unproxy(self
.simobj
)
1735 print "Error in unproxying port '%s' of %s" % \
1736 (self
.name
, self
.simobj
.path())
1738 self
.connect(realPeer
)
1740 # Call C++ to create corresponding port connection between C++ objects
1741 def ccConnect(self
):
1742 from m5
.internal
.pyobject
import connectPorts
1744 if self
.role
== 'SLAVE':
1745 # do nothing and let the master take care of it
1748 if self
.ccConnected
: # already done this
1751 if not self
.peer
: # nothing to connect to
1754 # check that we connect a master to a slave
1755 if self
.role
== peer
.role
:
1757 "cannot connect '%s' and '%s' due to identical role '%s'" \
1758 % (peer
, self
, self
.role
)
1761 # self is always the master and peer the slave
1762 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1763 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1765 print "Error connecting port %s.%s to %s.%s" % \
1766 (self
.simobj
.path(), self
.name
,
1767 peer
.simobj
.path(), peer
.name
)
1769 self
.ccConnected
= True
1770 peer
.ccConnected
= True
1772 # A reference to an individual element of a VectorPort... much like a
1773 # PortRef, but has an index.
1774 class VectorPortElementRef(PortRef
):
1775 def __init__(self
, simobj
, name
, role
, index
):
1776 PortRef
.__init
__(self
, simobj
, name
, role
)
1780 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1782 # A reference to a complete vector-valued port (not just a single element).
1783 # Can be indexed to retrieve individual VectorPortElementRef instances.
1784 class VectorPortRef(object):
1785 def __init__(self
, simobj
, name
, role
):
1786 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1787 self
.simobj
= simobj
1793 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1796 # Return the number of connected peers, corresponding the the
1797 # length of the elements.
1798 return len(self
.elements
)
1800 # for config.ini, print peer's name (not ours)
1802 return ' '.join([el
.ini_str() for el
in self
.elements
])
1805 def get_config_as_dict(self
):
1806 return {'role' : self
.role
,
1807 'peer' : [el
.ini_str() for el
in self
.elements
]}
1809 def __getitem__(self
, key
):
1810 if not isinstance(key
, int):
1811 raise TypeError, "VectorPort index must be integer"
1812 if key
>= len(self
.elements
):
1813 # need to extend list
1814 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1815 for i
in range(len(self
.elements
), key
+1)]
1816 self
.elements
.extend(ext
)
1817 return self
.elements
[key
]
1819 def _get_next(self
):
1820 return self
[len(self
.elements
)]
1822 def __setitem__(self
, key
, value
):
1823 if not isinstance(key
, int):
1824 raise TypeError, "VectorPort index must be integer"
1825 self
[key
].connect(value
)
1827 def connect(self
, other
):
1828 if isinstance(other
, (list, tuple)):
1829 # Assign list of port refs to vector port.
1830 # For now, append them... not sure if that's the right semantics
1831 # or if it should replace the current vector.
1833 self
._get
_next
().connect(ref
)
1835 # scalar assignment to plain VectorPort is implicit append
1836 self
._get
_next
().connect(other
)
1838 def clone(self
, simobj
, memo
):
1839 if memo
.has_key(self
):
1841 newRef
= copy
.copy(self
)
1843 newRef
.simobj
= simobj
1844 assert(isSimObject(newRef
.simobj
))
1845 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1848 def unproxy(self
, simobj
):
1849 [el
.unproxy(simobj
) for el
in self
.elements
]
1851 def ccConnect(self
):
1852 [el
.ccConnect() for el
in self
.elements
]
1854 # Port description object. Like a ParamDesc object, this represents a
1855 # logical port in the SimObject class, not a particular port on a
1856 # SimObject instance. The latter are represented by PortRef objects.
1858 # Generate a PortRef for this port on the given SimObject with the
1860 def makeRef(self
, simobj
):
1861 return PortRef(simobj
, self
.name
, self
.role
)
1863 # Connect an instance of this port (on the given SimObject with
1864 # the given name) with the port described by the supplied PortRef
1865 def connect(self
, simobj
, ref
):
1866 self
.makeRef(simobj
).connect(ref
)
1868 # No need for any pre-declarations at the moment as we merely rely
1869 # on an unsigned int.
1870 def cxx_predecls(self
, code
):
1873 # Declare an unsigned int with the same name as the port, that
1874 # will eventually hold the number of connected ports (and thus the
1875 # number of elements for a VectorPort).
1876 def cxx_decl(self
, code
):
1877 code('unsigned int port_${{self.name}}_connection_count;')
1879 class MasterPort(Port
):
1880 # MasterPort("description")
1881 def __init__(self
, *args
):
1884 self
.role
= 'MASTER'
1886 raise TypeError, 'wrong number of arguments'
1888 class SlavePort(Port
):
1889 # SlavePort("description")
1890 def __init__(self
, *args
):
1895 raise TypeError, 'wrong number of arguments'
1897 # VectorPort description object. Like Port, but represents a vector
1898 # of connections (e.g., as on a XBar).
1899 class VectorPort(Port
):
1900 def __init__(self
, *args
):
1903 def makeRef(self
, simobj
):
1904 return VectorPortRef(simobj
, self
.name
, self
.role
)
1906 class VectorMasterPort(VectorPort
):
1907 # VectorMasterPort("description")
1908 def __init__(self
, *args
):
1911 self
.role
= 'MASTER'
1912 VectorPort
.__init
__(self
, *args
)
1914 raise TypeError, 'wrong number of arguments'
1916 class VectorSlavePort(VectorPort
):
1917 # VectorSlavePort("description")
1918 def __init__(self
, *args
):
1922 VectorPort
.__init
__(self
, *args
)
1924 raise TypeError, 'wrong number of arguments'
1926 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1927 # proxy objects (via set_param_desc()) so that proxy error messages
1929 class PortParamDesc(object):
1930 __metaclass__
= Singleton
1935 baseEnums
= allEnums
.copy()
1936 baseParams
= allParams
.copy()
1939 global allEnums
, allParams
1941 allEnums
= baseEnums
.copy()
1942 allParams
= baseParams
.copy()
1944 __all__
= ['Param', 'VectorParam',
1945 'Enum', 'Bool', 'String', 'Float',
1946 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1947 'Int32', 'UInt32', 'Int64', 'UInt64',
1948 'Counter', 'Addr', 'Tick', 'Percent',
1949 'TcpPort', 'UdpPort', 'EthernetAddr',
1950 'IpAddress', 'IpNetmask', 'IpWithPort',
1951 'MemorySize', 'MemorySize32',
1952 'Latency', 'Frequency', 'Clock', 'Voltage',
1953 'NetworkBandwidth', 'MemoryBandwidth',
1955 'MaxAddr', 'MaxTick', 'AllMemory',
1957 'NextEthernetAddr', 'NULL',
1958 'MasterPort', 'SlavePort',
1959 'VectorMasterPort', 'VectorSlavePort']