1 # Copyright (c) 2012-2014, 2017 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
):
106 def pybind_predecls(cls
, code
):
107 cls
.cxx_predecls(code
)
109 # default for printing to .ini file is regular string conversion.
110 # will be overridden in some cases
114 # default for printing to .json file is regular string conversion.
115 # will be overridden in some cases, mostly to use native Python
116 # types where there are similar JSON types
117 def config_value(self
):
120 # Prerequisites for .ini parsing with cxx_ini_parse
122 def cxx_ini_predecls(cls
, code
):
125 # parse a .ini file entry for this param from string expression
126 # src into lvalue dest (of the param's C++ type)
128 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
129 code('// Unhandled param type: %s' % cls
.__name
__)
130 code('%s false;' % ret
)
132 # allows us to blithely call unproxy() on things without checking
133 # if they're really proxies or not
134 def unproxy(self
, base
):
137 # Produce a human readable version of the stored value
138 def pretty_print(self
, value
):
141 # Regular parameter description.
142 class ParamDesc(object):
143 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
144 self
.ptype_str
= ptype_str
145 # remember ptype only if it is provided
153 self
.default
= args
[0]
156 raise TypeError, 'too many arguments'
158 if kwargs
.has_key('desc'):
159 assert(not hasattr(self
, 'desc'))
160 self
.desc
= kwargs
['desc']
163 if kwargs
.has_key('default'):
164 assert(not hasattr(self
, 'default'))
165 self
.default
= kwargs
['default']
166 del kwargs
['default']
169 raise TypeError, 'extra unknown kwargs %s' % kwargs
171 if not hasattr(self
, 'desc'):
172 raise TypeError, 'desc attribute missing'
174 def __getattr__(self
, attr
):
176 ptype
= SimObject
.allClasses
[self
.ptype_str
]
177 assert isSimObjectClass(ptype
)
181 raise AttributeError, "'%s' object has no attribute '%s'" % \
182 (type(self
).__name
__, attr
)
184 def example_str(self
):
185 if hasattr(self
.ptype
, "ex_str"):
186 return self
.ptype
.ex_str
188 return self
.ptype_str
190 # Is the param available to be exposed on the command line
191 def isCmdLineSettable(self
):
192 if hasattr(self
.ptype
, "cmd_line_settable"):
193 return self
.ptype
.cmd_line_settable
197 def convert(self
, value
):
198 if isinstance(value
, proxy
.BaseProxy
):
199 value
.set_param_desc(self
)
201 if not hasattr(self
, 'ptype') and isNullPointer(value
):
202 # deferred evaluation of SimObject; continue to defer if
203 # we're just assigning a null pointer
205 if isinstance(value
, self
.ptype
):
207 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
209 return self
.ptype(value
)
211 def pretty_print(self
, value
):
212 if isinstance(value
, proxy
.BaseProxy
):
214 if isNullPointer(value
):
216 return self
.ptype(value
).pretty_print(value
)
218 def cxx_predecls(self
, code
):
219 code('#include <cstddef>')
220 self
.ptype
.cxx_predecls(code
)
222 def pybind_predecls(self
, code
):
223 self
.ptype
.pybind_predecls(code
)
225 def cxx_decl(self
, code
):
226 code('${{self.ptype.cxx_type}} ${{self.name}};')
228 # Vector-valued parameter description. Just like ParamDesc, except
229 # that the value is a vector (list) of the specified type instead of a
232 class VectorParamValue(list):
233 __metaclass__
= MetaParamValue
234 def __setattr__(self
, attr
, value
):
235 raise AttributeError, \
236 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
238 def config_value(self
):
239 return [v
.config_value() for v
in self
]
242 return ' '.join([v
.ini_str() for v
in self
])
245 return [ v
.getValue() for v
in self
]
247 def unproxy(self
, base
):
248 if len(self
) == 1 and isinstance(self
[0], proxy
.BaseProxy
):
249 # The value is a proxy (e.g. Parent.any, Parent.all or
250 # Parent.x) therefore try resolve it
251 return self
[0].unproxy(base
)
253 return [v
.unproxy(base
) for v
in self
]
255 class SimObjectVector(VectorParamValue
):
256 # support clone operation
257 def __call__(self
, **kwargs
):
258 return SimObjectVector([v(**kwargs
) for v
in self
])
260 def clear_parent(self
, old_parent
):
262 v
.clear_parent(old_parent
)
264 def set_parent(self
, parent
, name
):
266 self
[0].set_parent(parent
, name
)
268 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
269 for i
,v
in enumerate(self
):
270 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
272 def has_parent(self
):
273 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
275 # return 'cpu0 cpu1' etc. for print_ini()
277 return ' '.join([v
._name
for v
in self
])
279 # By iterating through the constituent members of the vector here
280 # we can nicely handle iterating over all a SimObject's children
281 # without having to provide lots of special functions on
282 # SimObjectVector directly.
283 def descendants(self
):
285 for obj
in v
.descendants():
288 def get_config_as_dict(self
):
291 a
.append(v
.get_config_as_dict())
294 # If we are replacing an item in the vector, make sure to set the
295 # parent reference of the new SimObject to be the same as the parent
296 # of the SimObject being replaced. Useful to have if we created
297 # a SimObjectVector of temporary objects that will be modified later in
298 # configuration scripts.
299 def __setitem__(self
, key
, value
):
301 if value
.has_parent():
302 warn("SimObject %s already has a parent" % value
.get_name() +\
303 " that is being overwritten by a SimObjectVector")
304 value
.set_parent(val
.get_parent(), val
._name
)
305 super(SimObjectVector
, self
).__setitem
__(key
, value
)
307 # Enumerate the params of each member of the SimObject vector. Creates
308 # strings that will allow indexing into the vector by the python code and
309 # allow it to be specified on the command line.
310 def enumerateParams(self
, flags_dict
= {},
313 if hasattr(self
, "_paramEnumed"):
314 print "Cycle detected enumerating params at %s?!" % (cmd_line_str
)
318 # Each entry in the SimObjectVector should be an
319 # instance of a SimObject
320 flags_dict
= vals
.enumerateParams(flags_dict
,
321 cmd_line_str
+ "%d." % x
,
322 access_str
+ "[%d]." % x
)
327 class VectorParamDesc(ParamDesc
):
328 # Convert assigned value to appropriate type. If the RHS is not a
329 # list or tuple, it generates a single-element list.
330 def convert(self
, value
):
331 if isinstance(value
, (list, tuple)):
332 # list: coerce each element into new list
333 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
334 elif isinstance(value
, str):
335 # If input is a csv string
336 tmp_list
= [ ParamDesc
.convert(self
, v
) \
337 for v
in value
.strip('[').strip(']').split(',') ]
339 # singleton: coerce to a single-element list
340 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
342 if isSimObjectSequence(tmp_list
):
343 return SimObjectVector(tmp_list
)
345 return VectorParamValue(tmp_list
)
347 # Produce a human readable example string that describes
348 # how to set this vector parameter in the absence of a default
350 def example_str(self
):
351 s
= super(VectorParamDesc
, self
).example_str()
352 help_str
= "[" + s
+ "," + s
+ ", ...]"
355 # Produce a human readable representation of the value of this vector param.
356 def pretty_print(self
, value
):
357 if isinstance(value
, (list, tuple)):
358 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
359 elif isinstance(value
, str):
360 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
362 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
366 # This is a helper function for the new config system
367 def __call__(self
, value
):
368 if isinstance(value
, (list, tuple)):
369 # list: coerce each element into new list
370 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
371 elif isinstance(value
, str):
372 # If input is a csv string
373 tmp_list
= [ ParamDesc
.convert(self
, v
) \
374 for v
in value
.strip('[').strip(']').split(',') ]
376 # singleton: coerce to a single-element list
377 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
379 return VectorParamValue(tmp_list
)
381 def cxx_predecls(self
, code
):
382 code('#include <vector>')
383 self
.ptype
.cxx_predecls(code
)
385 def pybind_predecls(self
, code
):
386 code('#include <vector>')
387 self
.ptype
.pybind_predecls(code
)
389 def cxx_decl(self
, code
):
390 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
392 class ParamFactory(object):
393 def __init__(self
, param_desc_class
, ptype_str
= None):
394 self
.param_desc_class
= param_desc_class
395 self
.ptype_str
= ptype_str
397 def __getattr__(self
, attr
):
399 attr
= self
.ptype_str
+ '.' + attr
400 return ParamFactory(self
.param_desc_class
, attr
)
402 # E.g., Param.Int(5, "number of widgets")
403 def __call__(self
, *args
, **kwargs
):
406 ptype
= allParams
[self
.ptype_str
]
408 # if name isn't defined yet, assume it's a SimObject, and
409 # try to resolve it later
411 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
413 Param
= ParamFactory(ParamDesc
)
414 VectorParam
= ParamFactory(VectorParamDesc
)
416 #####################################################################
420 # Though native Python types could be used to specify parameter types
421 # (the 'ptype' field of the Param and VectorParam classes), it's more
422 # flexible to define our own set of types. This gives us more control
423 # over how Python expressions are converted to values (via the
424 # __init__() constructor) and how these values are printed out (via
425 # the __str__() conversion method).
427 #####################################################################
429 # String-valued parameter. Just mixin the ParamValue class with the
430 # built-in str class.
431 class String(ParamValue
,str):
432 cxx_type
= 'std::string'
433 cmd_line_settable
= True
436 def cxx_predecls(self
, code
):
437 code('#include <string>')
439 def __call__(self
, value
):
444 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
445 code('%s = %s;' % (dest
, src
))
446 code('%s true;' % ret
)
451 # superclass for "numeric" parameter values, to emulate math
452 # operations in a type-safe way. e.g., a Latency times an int returns
453 # a new Latency object.
454 class NumericParamValue(ParamValue
):
456 return str(self
.value
)
459 return float(self
.value
)
462 return long(self
.value
)
465 return int(self
.value
)
467 # hook for bounds checking
471 def __mul__(self
, other
):
472 newobj
= self
.__class
__(self
)
473 newobj
.value
*= other
479 def __div__(self
, other
):
480 newobj
= self
.__class
__(self
)
481 newobj
.value
/= other
485 def __sub__(self
, other
):
486 newobj
= self
.__class
__(self
)
487 newobj
.value
-= other
491 def config_value(self
):
495 def cxx_ini_predecls(cls
, code
):
496 # Assume that base/str.hh will be included anyway
497 # code('#include "base/str.hh"')
500 # The default for parsing PODs from an .ini entry is to extract from an
501 # istringstream and let overloading choose the right type according to
504 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
505 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
507 # Metaclass for bounds-checked integer parameters. See CheckedInt.
508 class CheckedIntType(MetaParamValue
):
509 def __init__(cls
, name
, bases
, dict):
510 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
512 # CheckedInt is an abstract base class, so we actually don't
513 # want to do any processing on it... the rest of this code is
514 # just for classes that derive from CheckedInt.
515 if name
== 'CheckedInt':
518 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
519 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
520 panic("CheckedInt subclass %s must define either\n" \
521 " 'min' and 'max' or 'size' and 'unsigned'\n",
525 cls
.max = 2 ** cls
.size
- 1
527 cls
.min = -(2 ** (cls
.size
- 1))
528 cls
.max = (2 ** (cls
.size
- 1)) - 1
530 # Abstract superclass for bounds-checked integer parameters. This
531 # class is subclassed to generate parameter classes with specific
532 # bounds. Initialization of the min and max bounds is done in the
533 # metaclass CheckedIntType.__init__.
534 class CheckedInt(NumericParamValue
):
535 __metaclass__
= CheckedIntType
536 cmd_line_settable
= True
539 if not self
.min <= self
.value
<= self
.max:
540 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
541 (self
.min, self
.value
, self
.max)
543 def __init__(self
, value
):
544 if isinstance(value
, str):
545 self
.value
= convert
.toInteger(value
)
546 elif isinstance(value
, (int, long, float, NumericParamValue
)):
547 self
.value
= long(value
)
549 raise TypeError, "Can't convert object of type %s to CheckedInt" \
550 % type(value
).__name
__
553 def __call__(self
, value
):
558 def cxx_predecls(cls
, code
):
559 # most derived types require this, so we just do it here once
560 code('#include "base/types.hh"')
563 return long(self
.value
)
565 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
566 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
568 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
569 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
570 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
571 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
572 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
573 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
574 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
575 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
577 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
578 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
579 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
580 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
582 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
584 class Cycles(CheckedInt
):
590 from _m5
.core
import Cycles
591 return Cycles(self
.value
)
594 def cxx_ini_predecls(cls
, code
):
595 # Assume that base/str.hh will be included anyway
596 # code('#include "base/str.hh"')
600 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
601 code('uint64_t _temp;')
602 code('bool _ret = to_number(%s, _temp);' % src
)
604 code(' %s = Cycles(_temp);' % dest
)
605 code('%s _ret;' % ret
)
607 class Float(ParamValue
, float):
609 cmd_line_settable
= True
611 def __init__(self
, value
):
612 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
613 self
.value
= float(value
)
615 raise TypeError, "Can't convert object of type %s to Float" \
616 % type(value
).__name
__
618 def __call__(self
, value
):
623 return float(self
.value
)
625 def config_value(self
):
629 def cxx_ini_predecls(cls
, code
):
630 code('#include <sstream>')
633 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
634 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
636 class MemorySize(CheckedInt
):
637 cxx_type
= 'uint64_t'
641 def __init__(self
, value
):
642 if isinstance(value
, MemorySize
):
643 self
.value
= value
.value
645 self
.value
= convert
.toMemorySize(value
)
648 class MemorySize32(CheckedInt
):
649 cxx_type
= 'uint32_t'
653 def __init__(self
, value
):
654 if isinstance(value
, MemorySize
):
655 self
.value
= value
.value
657 self
.value
= convert
.toMemorySize(value
)
660 class Addr(CheckedInt
):
664 def __init__(self
, value
):
665 if isinstance(value
, Addr
):
666 self
.value
= value
.value
669 # Often addresses are referred to with sizes. Ex: A device
670 # base address is at "512MB". Use toMemorySize() to convert
671 # these into addresses. If the address is not specified with a
672 # "size", an exception will occur and numeric translation will
674 self
.value
= convert
.toMemorySize(value
)
675 except (TypeError, ValueError):
676 # Convert number to string and use long() to do automatic
677 # base conversion (requires base=0 for auto-conversion)
678 self
.value
= long(str(value
), base
=0)
681 def __add__(self
, other
):
682 if isinstance(other
, Addr
):
683 return self
.value
+ other
.value
685 return self
.value
+ other
686 def pretty_print(self
, value
):
688 val
= convert
.toMemorySize(value
)
691 return "0x%x" % long(val
)
693 class AddrRange(ParamValue
):
694 cxx_type
= 'AddrRange'
696 def __init__(self
, *args
, **kwargs
):
697 # Disable interleaving and hashing by default
698 self
.intlvHighBit
= 0
703 def handle_kwargs(self
, kwargs
):
704 # An address range needs to have an upper limit, specified
705 # either explicitly with an end, or as an offset using the
708 self
.end
= Addr(kwargs
.pop('end'))
709 elif 'size' in kwargs
:
710 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
712 raise TypeError, "Either end or size must be specified"
714 # Now on to the optional bit
715 if 'intlvHighBit' in kwargs
:
716 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
717 if 'xorHighBit' in kwargs
:
718 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
719 if 'intlvBits' in kwargs
:
720 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
721 if 'intlvMatch' in kwargs
:
722 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
725 self
.start
= Addr(kwargs
.pop('start'))
726 handle_kwargs(self
, kwargs
)
730 self
.start
= Addr(args
[0])
731 handle_kwargs(self
, kwargs
)
732 elif isinstance(args
[0], (list, tuple)):
733 self
.start
= Addr(args
[0][0])
734 self
.end
= Addr(args
[0][1])
737 self
.end
= Addr(args
[0]) - 1
740 self
.start
= Addr(args
[0])
741 self
.end
= Addr(args
[1])
743 raise TypeError, "Too many arguments specified"
746 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
749 return '%s:%s:%s:%s:%s:%s' \
750 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
751 self
.intlvBits
, self
.intlvMatch
)
754 # Divide the size by the size of the interleaving slice
755 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
758 def cxx_predecls(cls
, code
):
759 Addr
.cxx_predecls(code
)
760 code('#include "base/addr_range.hh"')
763 def pybind_predecls(cls
, code
):
764 Addr
.pybind_predecls(code
)
765 code('#include "base/addr_range.hh"')
768 def cxx_ini_predecls(cls
, code
):
769 code('#include <sstream>')
772 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
773 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
774 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
776 code('std::istringstream _stream(${src});')
777 code('_stream >> _start;')
778 code('_stream.get(_sep);')
779 code('_stream >> _end;')
780 code('if (!_stream.fail() && !_stream.eof()) {')
781 code(' _stream.get(_sep);')
782 code(' _stream >> _intlvHighBit;')
783 code(' _stream.get(_sep);')
784 code(' _stream >> _xorHighBit;')
785 code(' _stream.get(_sep);')
786 code(' _stream >> _intlvBits;')
787 code(' _stream.get(_sep);')
788 code(' _stream >> _intlvMatch;')
790 code('bool _ret = !_stream.fail() &&'
791 '_stream.eof() && _sep == \':\';')
793 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
794 _xorHighBit, _intlvBits, _intlvMatch);')
798 # Go from the Python class to the wrapped C++ class
799 from _m5
.range import AddrRange
801 return AddrRange(long(self
.start
), long(self
.end
),
802 int(self
.intlvHighBit
), int(self
.xorHighBit
),
803 int(self
.intlvBits
), int(self
.intlvMatch
))
805 # Boolean parameter type. Python doesn't let you subclass bool, since
806 # it doesn't want to let you create multiple instances of True and
807 # False. Thus this is a little more complicated than String.
808 class Bool(ParamValue
):
810 cmd_line_settable
= True
812 def __init__(self
, value
):
814 self
.value
= convert
.toBool(value
)
816 self
.value
= bool(value
)
818 def __call__(self
, value
):
823 return bool(self
.value
)
826 return str(self
.value
)
828 # implement truth value testing for Bool parameters so that these params
829 # evaluate correctly during the python configuration phase
830 def __nonzero__(self
):
831 return bool(self
.value
)
838 def config_value(self
):
842 def cxx_ini_predecls(cls
, code
):
843 # Assume that base/str.hh will be included anyway
844 # code('#include "base/str.hh"')
848 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
849 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
851 def IncEthernetAddr(addr
, val
= 1):
852 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
854 for i
in (5, 4, 3, 2, 1):
855 val
,rem
= divmod(bytes
[i
], 256)
860 assert(bytes
[0] <= 255)
861 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
863 _NextEthernetAddr
= "00:90:00:00:00:01"
864 def NextEthernetAddr():
865 global _NextEthernetAddr
867 value
= _NextEthernetAddr
868 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
871 class EthernetAddr(ParamValue
):
872 cxx_type
= 'Net::EthAddr'
873 ex_str
= "00:90:00:00:00:01"
874 cmd_line_settable
= True
877 def cxx_predecls(cls
, code
):
878 code('#include "base/inet.hh"')
880 def __init__(self
, value
):
881 if value
== NextEthernetAddr
:
885 if not isinstance(value
, str):
886 raise TypeError, "expected an ethernet address and didn't get one"
888 bytes
= value
.split(':')
890 raise TypeError, 'invalid ethernet address %s' % value
893 if not 0 <= int(byte
, base
=16) <= 0xff:
894 raise TypeError, 'invalid ethernet address %s' % value
898 def __call__(self
, value
):
902 def unproxy(self
, base
):
903 if self
.value
== NextEthernetAddr
:
904 return EthernetAddr(self
.value())
908 from _m5
.net
import EthAddr
909 return EthAddr(self
.value
)
918 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
919 code('%s = Net::EthAddr(%s);' % (dest
, src
))
920 code('%s true;' % ret
)
922 # When initializing an IpAddress, pass in an existing IpAddress, a string of
923 # the form "a.b.c.d", or an integer representing an IP.
924 class IpAddress(ParamValue
):
925 cxx_type
= 'Net::IpAddress'
927 cmd_line_settable
= True
930 def cxx_predecls(cls
, code
):
931 code('#include "base/inet.hh"')
933 def __init__(self
, value
):
934 if isinstance(value
, IpAddress
):
938 self
.ip
= convert
.toIpAddress(value
)
940 self
.ip
= long(value
)
943 def __call__(self
, value
):
948 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
949 return '%d.%d.%d.%d' % tuple(tup
)
951 def __eq__(self
, other
):
952 if isinstance(other
, IpAddress
):
953 return self
.ip
== other
.ip
954 elif isinstance(other
, str):
956 return self
.ip
== convert
.toIpAddress(other
)
960 return self
.ip
== other
962 def __ne__(self
, other
):
963 return not (self
== other
)
966 if self
.ip
< 0 or self
.ip
>= (1 << 32):
967 raise TypeError, "invalid ip address %#08x" % self
.ip
970 from _m5
.net
import IpAddress
971 return IpAddress(self
.ip
)
973 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
974 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
975 # positional or keyword arguments.
976 class IpNetmask(IpAddress
):
977 cxx_type
= 'Net::IpNetmask'
978 ex_str
= "127.0.0.0/24"
979 cmd_line_settable
= True
982 def cxx_predecls(cls
, code
):
983 code('#include "base/inet.hh"')
985 def __init__(self
, *args
, **kwargs
):
986 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
988 setattr(self
, key
, kwargs
.pop(key
))
990 setattr(self
, key
, elseVal
)
992 raise TypeError, "No value set for %s" % key
995 handle_kwarg(self
, kwargs
, 'ip')
996 handle_kwarg(self
, kwargs
, 'netmask')
1000 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1001 raise TypeError, "Invalid arguments"
1002 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1003 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1004 elif isinstance(args
[0], IpNetmask
):
1005 self
.ip
= args
[0].ip
1006 self
.netmask
= args
[0].netmask
1008 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1010 elif len(args
) == 2:
1012 self
.netmask
= args
[1]
1014 raise TypeError, "Too many arguments specified"
1017 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1021 def __call__(self
, value
):
1022 self
.__init
__(value
)
1026 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1028 def __eq__(self
, other
):
1029 if isinstance(other
, IpNetmask
):
1030 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1031 elif isinstance(other
, str):
1033 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1041 if self
.netmask
< 0 or self
.netmask
> 32:
1042 raise TypeError, "invalid netmask %d" % netmask
1045 from _m5
.net
import IpNetmask
1046 return IpNetmask(self
.ip
, self
.netmask
)
1048 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1049 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1050 class IpWithPort(IpAddress
):
1051 cxx_type
= 'Net::IpWithPort'
1052 ex_str
= "127.0.0.1:80"
1053 cmd_line_settable
= True
1056 def cxx_predecls(cls
, code
):
1057 code('#include "base/inet.hh"')
1059 def __init__(self
, *args
, **kwargs
):
1060 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1062 setattr(self
, key
, kwargs
.pop(key
))
1064 setattr(self
, key
, elseVal
)
1066 raise TypeError, "No value set for %s" % key
1069 handle_kwarg(self
, kwargs
, 'ip')
1070 handle_kwarg(self
, kwargs
, 'port')
1072 elif len(args
) == 1:
1074 if not 'ip' in kwargs
and not 'port' in kwargs
:
1075 raise TypeError, "Invalid arguments"
1076 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1077 handle_kwarg(self
, kwargs
, 'port', args
[0])
1078 elif isinstance(args
[0], IpWithPort
):
1079 self
.ip
= args
[0].ip
1080 self
.port
= args
[0].port
1082 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1084 elif len(args
) == 2:
1088 raise TypeError, "Too many arguments specified"
1091 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1095 def __call__(self
, value
):
1096 self
.__init
__(value
)
1100 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1102 def __eq__(self
, other
):
1103 if isinstance(other
, IpWithPort
):
1104 return self
.ip
== other
.ip
and self
.port
== other
.port
1105 elif isinstance(other
, str):
1107 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1115 if self
.port
< 0 or self
.port
> 0xffff:
1116 raise TypeError, "invalid port %d" % self
.port
1119 from _m5
.net
import IpWithPort
1120 return IpWithPort(self
.ip
, self
.port
)
1122 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1123 "%a %b %d %H:%M:%S %Y",
1124 "%Y/%m/%d %H:%M:%S",
1127 "%m/%d/%Y %H:%M:%S",
1130 "%m/%d/%y %H:%M:%S",
1135 def parse_time(value
):
1136 from time
import gmtime
, strptime
, struct_time
, time
1137 from datetime
import datetime
, date
1139 if isinstance(value
, struct_time
):
1142 if isinstance(value
, (int, long)):
1143 return gmtime(value
)
1145 if isinstance(value
, (datetime
, date
)):
1146 return value
.timetuple()
1148 if isinstance(value
, str):
1149 if value
in ('Now', 'Today'):
1150 return time
.gmtime(time
.time())
1152 for format
in time_formats
:
1154 return strptime(value
, format
)
1158 raise ValueError, "Could not parse '%s' as a time" % value
1160 class Time(ParamValue
):
1164 def cxx_predecls(cls
, code
):
1165 code('#include <time.h>')
1167 def __init__(self
, value
):
1168 self
.value
= parse_time(value
)
1170 def __call__(self
, value
):
1171 self
.__init
__(value
)
1175 from _m5
.core
import tm
1178 return tm
.gmtime(calendar
.timegm(self
.value
))
1181 return time
.asctime(self
.value
)
1186 def get_config_as_dict(self
):
1191 def cxx_ini_predecls(cls
, code
):
1192 code('#include <time.h>')
1195 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1196 code('char *_parse_ret = strptime((${src}).c_str(),')
1197 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1198 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1200 # Enumerated types are a little more complex. The user specifies the
1201 # type as Enum(foo) where foo is either a list or dictionary of
1202 # alternatives (typically strings, but not necessarily so). (In the
1203 # long run, the integer value of the parameter will be the list index
1204 # or the corresponding dictionary value. For now, since we only check
1205 # that the alternative is valid and then spit it into a .ini file,
1206 # there's not much point in using the dictionary.)
1208 # What Enum() must do is generate a new type encapsulating the
1209 # provided list/dictionary so that specific values of the parameter
1210 # can be instances of that type. We define two hidden internal
1211 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1212 # derive the new type from the appropriate base class on the fly.
1215 # Metaclass for Enum types
1216 class MetaEnum(MetaParamValue
):
1217 def __new__(mcls
, name
, bases
, dict):
1218 assert name
not in allEnums
1220 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1221 allEnums
[name
] = cls
1224 def __init__(cls
, name
, bases
, init_dict
):
1225 if init_dict
.has_key('map'):
1226 if not isinstance(cls
.map, dict):
1227 raise TypeError, "Enum-derived class attribute 'map' " \
1228 "must be of type dict"
1229 # build list of value strings from map
1230 cls
.vals
= cls
.map.keys()
1232 elif init_dict
.has_key('vals'):
1233 if not isinstance(cls
.vals
, list):
1234 raise TypeError, "Enum-derived class attribute 'vals' " \
1235 "must be of type list"
1236 # build string->value map from vals sequence
1238 for idx
,val
in enumerate(cls
.vals
):
1241 raise TypeError, "Enum-derived class must define "\
1242 "attribute 'map' or 'vals'"
1244 cls
.cxx_type
= 'Enums::%s' % name
1246 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1248 # Generate C++ class declaration for this enum type.
1249 # Note that we wrap the enum in a class/struct to act as a namespace,
1250 # so that the enum strings can be brief w/o worrying about collisions.
1251 def cxx_decl(cls
, code
):
1252 wrapper_name
= cls
.wrapper_name
1253 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1254 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1255 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1261 $wrapper $wrapper_name {
1265 for val
in cls
.vals
:
1266 code('$val = ${{cls.map[val]}},')
1267 code('Num_$name = ${{len(cls.vals)}}')
1271 if cls
.wrapper_is_struct
:
1272 code(' static const char *${name}Strings[Num_${name}];')
1275 code('extern const char *${name}Strings[Num_${name}];')
1279 code('#endif // $idem_macro')
1281 def cxx_def(cls
, code
):
1282 wrapper_name
= cls
.wrapper_name
1283 file_name
= cls
.__name
__
1284 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1286 code('#include "enums/$file_name.hh"')
1287 if cls
.wrapper_is_struct
:
1288 code('const char *${wrapper_name}::${name}Strings'
1291 code('namespace Enums {')
1293 code(' const char *${name}Strings[Num_${name}] =')
1297 for val
in cls
.vals
:
1302 if not cls
.wrapper_is_struct
:
1303 code('} // namespace $wrapper_name')
1306 def pybind_def(cls
, code
):
1308 wrapper_name
= cls
.wrapper_name
1309 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1311 code('''#include "pybind11/pybind11.h"
1312 #include "pybind11/stl.h"
1314 #include <sim/init.hh>
1316 namespace py = pybind11;
1319 module_init(py::module &m_internal)
1321 py::module m = m_internal.def_submodule("enum_${name}");
1323 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
1328 for val
in cls
.vals
:
1329 code('.value("${val}", ${wrapper_name}::${val})')
1330 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1331 code('.export_values()')
1338 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1341 # Base class for enum types.
1342 class Enum(ParamValue
):
1343 __metaclass__
= MetaEnum
1345 cmd_line_settable
= True
1347 # The name of the wrapping namespace or struct
1348 wrapper_name
= 'Enums'
1350 # If true, the enum is wrapped in a struct rather than a namespace
1351 wrapper_is_struct
= False
1353 # If not None, use this as the enum name rather than this class name
1356 def __init__(self
, value
):
1357 if value
not in self
.map:
1358 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1359 % (value
, self
.vals
)
1362 def __call__(self
, value
):
1363 self
.__init
__(value
)
1367 def cxx_predecls(cls
, code
):
1368 code('#include "enums/$0.hh"', cls
.__name
__)
1371 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1372 code('if (false) {')
1373 for elem_name
in cls
.map.iterkeys():
1374 code('} else if (%s == "%s") {' % (src
, elem_name
))
1376 code('%s = Enums::%s;' % (dest
, elem_name
))
1377 code('%s true;' % ret
)
1380 code(' %s false;' % ret
)
1384 import m5
.internal
.params
1385 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1386 return e(self
.map[self
.value
])
1391 # how big does a rounding error need to be before we warn about it?
1392 frequency_tolerance
= 0.001 # 0.1%
1394 class TickParamValue(NumericParamValue
):
1397 cmd_line_settable
= True
1400 def cxx_predecls(cls
, code
):
1401 code('#include "base/types.hh"')
1403 def __call__(self
, value
):
1404 self
.__init
__(value
)
1408 return long(self
.value
)
1411 def cxx_ini_predecls(cls
, code
):
1412 code('#include <sstream>')
1414 # Ticks are expressed in seconds in JSON files and in plain
1415 # Ticks in .ini files. Switch based on a config flag
1417 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1418 code('${ret} to_number(${src}, ${dest});')
1420 class Latency(TickParamValue
):
1423 def __init__(self
, value
):
1424 if isinstance(value
, (Latency
, Clock
)):
1425 self
.ticks
= value
.ticks
1426 self
.value
= value
.value
1427 elif isinstance(value
, Frequency
):
1428 self
.ticks
= value
.ticks
1429 self
.value
= 1.0 / value
.value
1430 elif value
.endswith('t'):
1432 self
.value
= int(value
[:-1])
1435 self
.value
= convert
.toLatency(value
)
1437 def __call__(self
, value
):
1438 self
.__init
__(value
)
1441 def __getattr__(self
, attr
):
1442 if attr
in ('latency', 'period'):
1444 if attr
== 'frequency':
1445 return Frequency(self
)
1446 raise AttributeError, "Latency object has no attribute '%s'" % attr
1449 if self
.ticks
or self
.value
== 0:
1452 value
= ticks
.fromSeconds(self
.value
)
1455 def config_value(self
):
1456 return self
.getValue()
1458 # convert latency to ticks
1460 return '%d' % self
.getValue()
1462 class Frequency(TickParamValue
):
1465 def __init__(self
, value
):
1466 if isinstance(value
, (Latency
, Clock
)):
1467 if value
.value
== 0:
1470 self
.value
= 1.0 / value
.value
1471 self
.ticks
= value
.ticks
1472 elif isinstance(value
, Frequency
):
1473 self
.value
= value
.value
1474 self
.ticks
= value
.ticks
1477 self
.value
= convert
.toFrequency(value
)
1479 def __call__(self
, value
):
1480 self
.__init
__(value
)
1483 def __getattr__(self
, attr
):
1484 if attr
== 'frequency':
1486 if attr
in ('latency', 'period'):
1487 return Latency(self
)
1488 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1490 # convert latency to ticks
1492 if self
.ticks
or self
.value
== 0:
1495 value
= ticks
.fromSeconds(1.0 / self
.value
)
1498 def config_value(self
):
1499 return self
.getValue()
1502 return '%d' % self
.getValue()
1504 # A generic Frequency and/or Latency value. Value is stored as a
1505 # latency, just like Latency and Frequency.
1506 class Clock(TickParamValue
):
1507 def __init__(self
, value
):
1508 if isinstance(value
, (Latency
, Clock
)):
1509 self
.ticks
= value
.ticks
1510 self
.value
= value
.value
1511 elif isinstance(value
, Frequency
):
1512 self
.ticks
= value
.ticks
1513 self
.value
= 1.0 / value
.value
1514 elif value
.endswith('t'):
1516 self
.value
= int(value
[:-1])
1519 self
.value
= convert
.anyToLatency(value
)
1521 def __call__(self
, value
):
1522 self
.__init
__(value
)
1526 return "%s" % Latency(self
)
1528 def __getattr__(self
, attr
):
1529 if attr
== 'frequency':
1530 return Frequency(self
)
1531 if attr
in ('latency', 'period'):
1532 return Latency(self
)
1533 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1536 return self
.period
.getValue()
1538 def config_value(self
):
1539 return self
.period
.config_value()
1542 return self
.period
.ini_str()
1544 class Voltage(float,ParamValue
):
1547 cmd_line_settable
= True
1549 def __new__(cls
, value
):
1550 # convert to voltage
1551 val
= convert
.toVoltage(value
)
1552 return super(cls
, Voltage
).__new
__(cls
, val
)
1554 def __call__(self
, value
):
1555 val
= convert
.toVoltage(value
)
1560 return str(self
.getValue())
1567 return '%f' % self
.getValue()
1570 def cxx_ini_predecls(cls
, code
):
1571 code('#include <sstream>')
1574 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1575 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1577 class Current(float, ParamValue
):
1580 cmd_line_settable
= False
1582 def __new__(cls
, value
):
1583 # convert to current
1584 val
= convert
.toCurrent(value
)
1585 return super(cls
, Current
).__new
__(cls
, val
)
1587 def __call__(self
, value
):
1588 val
= convert
.toCurrent(value
)
1593 return str(self
.getValue())
1600 return '%f' % self
.getValue()
1603 def cxx_ini_predecls(cls
, code
):
1604 code('#include <sstream>')
1607 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1608 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1610 class NetworkBandwidth(float,ParamValue
):
1613 cmd_line_settable
= True
1615 def __new__(cls
, value
):
1616 # convert to bits per second
1617 val
= convert
.toNetworkBandwidth(value
)
1618 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1621 return str(self
.val
)
1623 def __call__(self
, value
):
1624 val
= convert
.toNetworkBandwidth(value
)
1629 # convert to seconds per byte
1630 value
= 8.0 / float(self
)
1631 # convert to ticks per byte
1632 value
= ticks
.fromSeconds(value
)
1636 return '%f' % self
.getValue()
1638 def config_value(self
):
1639 return '%f' % self
.getValue()
1642 def cxx_ini_predecls(cls
, code
):
1643 code('#include <sstream>')
1646 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1647 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1649 class MemoryBandwidth(float,ParamValue
):
1652 cmd_line_settable
= True
1654 def __new__(cls
, value
):
1655 # convert to bytes per second
1656 val
= convert
.toMemoryBandwidth(value
)
1657 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1659 def __call__(self
, value
):
1660 val
= convert
.toMemoryBandwidth(value
)
1665 # convert to seconds per byte
1668 value
= 1.0 / float(self
)
1669 # convert to ticks per byte
1670 value
= ticks
.fromSeconds(value
)
1674 return '%f' % self
.getValue()
1676 def config_value(self
):
1677 return '%f' % self
.getValue()
1680 def cxx_ini_predecls(cls
, code
):
1681 code('#include <sstream>')
1684 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1685 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1688 # "Constants"... handy aliases for various values.
1691 # Special class for NULL pointers. Note the special check in
1692 # make_param_value() above that lets these be assigned where a
1693 # SimObject is required.
1694 # only one copy of a particular node
1695 class NullSimObject(object):
1696 __metaclass__
= Singleton
1701 def _instantiate(self
, parent
= None, path
= ''):
1707 def unproxy(self
, base
):
1710 def set_path(self
, parent
, name
):
1716 def config_value(self
):
1722 # The only instance you'll ever need...
1723 NULL
= NullSimObject()
1725 def isNullPointer(value
):
1726 return isinstance(value
, NullSimObject
)
1728 # Some memory range specifications use this as a default upper bound.
1731 AllMemory
= AddrRange(0, MaxAddr
)
1734 #####################################################################
1738 # Ports are used to interconnect objects in the memory system.
1740 #####################################################################
1742 # Port reference: encapsulates a reference to a particular port on a
1743 # particular SimObject.
1744 class PortRef(object):
1745 def __init__(self
, simobj
, name
, role
):
1746 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1747 self
.simobj
= simobj
1750 self
.peer
= None # not associated with another port yet
1751 self
.ccConnected
= False # C++ port connection done?
1752 self
.index
= -1 # always -1 for non-vector ports
1755 return '%s.%s' % (self
.simobj
, self
.name
)
1758 # Return the number of connected ports, i.e. 0 is we have no
1759 # peer and 1 if we do.
1760 return int(self
.peer
!= None)
1762 # for config.ini, print peer's name (not ours)
1764 return str(self
.peer
)
1767 def get_config_as_dict(self
):
1768 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1770 def __getattr__(self
, attr
):
1771 if attr
== 'peerObj':
1772 # shorthand for proxies
1773 return self
.peer
.simobj
1774 raise AttributeError, "'%s' object has no attribute '%s'" % \
1775 (self
.__class
__.__name
__, attr
)
1777 # Full connection is symmetric (both ways). Called via
1778 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1779 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1780 # e.g., "obj1.portA[3] = obj2.portB".
1781 def connect(self
, other
):
1782 if isinstance(other
, VectorPortRef
):
1783 # reference to plain VectorPort is implicit append
1784 other
= other
._get
_next
()
1785 if self
.peer
and not proxy
.isproxy(self
.peer
):
1786 fatal("Port %s is already connected to %s, cannot connect %s\n",
1787 self
, self
.peer
, other
);
1789 if proxy
.isproxy(other
):
1790 other
.set_param_desc(PortParamDesc())
1791 elif isinstance(other
, PortRef
):
1792 if other
.peer
is not self
:
1796 "assigning non-port reference '%s' to port '%s'" \
1799 # Allow a master/slave port pair to be spliced between
1800 # a port and its connected peer. Useful operation for connecting
1801 # instrumentation structures into a system when it is necessary
1802 # to connect the instrumentation after the full system has been
1804 def splice(self
, new_master_peer
, new_slave_peer
):
1805 if self
.peer
and not proxy
.isproxy(self
.peer
):
1806 if isinstance(new_master_peer
, PortRef
) and \
1807 isinstance(new_slave_peer
, PortRef
):
1808 old_peer
= self
.peer
1809 if self
.role
== 'SLAVE':
1810 self
.peer
= new_master_peer
1811 old_peer
.peer
= new_slave_peer
1812 new_master_peer
.connect(self
)
1813 new_slave_peer
.connect(old_peer
)
1814 elif self
.role
== 'MASTER':
1815 self
.peer
= new_slave_peer
1816 old_peer
.peer
= new_master_peer
1817 new_slave_peer
.connect(self
)
1818 new_master_peer
.connect(old_peer
)
1820 panic("Port %s has unknown role, "+\
1821 "cannot splice in new peers\n", self
)
1824 "Splicing non-port references '%s','%s' to port '%s'"\
1825 % (new_peer
, peers_new_peer
, self
)
1827 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1829 def clone(self
, simobj
, memo
):
1830 if memo
.has_key(self
):
1832 newRef
= copy
.copy(self
)
1834 newRef
.simobj
= simobj
1835 assert(isSimObject(newRef
.simobj
))
1836 if self
.peer
and not proxy
.isproxy(self
.peer
):
1837 peerObj
= self
.peer
.simobj(_memo
=memo
)
1838 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1839 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1842 def unproxy(self
, simobj
):
1843 assert(simobj
is self
.simobj
)
1844 if proxy
.isproxy(self
.peer
):
1846 realPeer
= self
.peer
.unproxy(self
.simobj
)
1848 print "Error in unproxying port '%s' of %s" % \
1849 (self
.name
, self
.simobj
.path())
1851 self
.connect(realPeer
)
1853 # Call C++ to create corresponding port connection between C++ objects
1854 def ccConnect(self
):
1855 from _m5
.pyobject
import connectPorts
1857 if self
.role
== 'SLAVE':
1858 # do nothing and let the master take care of it
1861 if self
.ccConnected
: # already done this
1864 if not self
.peer
: # nothing to connect to
1867 # check that we connect a master to a slave
1868 if self
.role
== peer
.role
:
1870 "cannot connect '%s' and '%s' due to identical role '%s'" \
1871 % (peer
, self
, self
.role
)
1874 # self is always the master and peer the slave
1875 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1876 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1878 print "Error connecting port %s.%s to %s.%s" % \
1879 (self
.simobj
.path(), self
.name
,
1880 peer
.simobj
.path(), peer
.name
)
1882 self
.ccConnected
= True
1883 peer
.ccConnected
= True
1885 # A reference to an individual element of a VectorPort... much like a
1886 # PortRef, but has an index.
1887 class VectorPortElementRef(PortRef
):
1888 def __init__(self
, simobj
, name
, role
, index
):
1889 PortRef
.__init
__(self
, simobj
, name
, role
)
1893 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1895 # A reference to a complete vector-valued port (not just a single element).
1896 # Can be indexed to retrieve individual VectorPortElementRef instances.
1897 class VectorPortRef(object):
1898 def __init__(self
, simobj
, name
, role
):
1899 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1900 self
.simobj
= simobj
1906 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1909 # Return the number of connected peers, corresponding the the
1910 # length of the elements.
1911 return len(self
.elements
)
1913 # for config.ini, print peer's name (not ours)
1915 return ' '.join([el
.ini_str() for el
in self
.elements
])
1918 def get_config_as_dict(self
):
1919 return {'role' : self
.role
,
1920 'peer' : [el
.ini_str() for el
in self
.elements
]}
1922 def __getitem__(self
, key
):
1923 if not isinstance(key
, int):
1924 raise TypeError, "VectorPort index must be integer"
1925 if key
>= len(self
.elements
):
1926 # need to extend list
1927 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1928 for i
in range(len(self
.elements
), key
+1)]
1929 self
.elements
.extend(ext
)
1930 return self
.elements
[key
]
1932 def _get_next(self
):
1933 return self
[len(self
.elements
)]
1935 def __setitem__(self
, key
, value
):
1936 if not isinstance(key
, int):
1937 raise TypeError, "VectorPort index must be integer"
1938 self
[key
].connect(value
)
1940 def connect(self
, other
):
1941 if isinstance(other
, (list, tuple)):
1942 # Assign list of port refs to vector port.
1943 # For now, append them... not sure if that's the right semantics
1944 # or if it should replace the current vector.
1946 self
._get
_next
().connect(ref
)
1948 # scalar assignment to plain VectorPort is implicit append
1949 self
._get
_next
().connect(other
)
1951 def clone(self
, simobj
, memo
):
1952 if memo
.has_key(self
):
1954 newRef
= copy
.copy(self
)
1956 newRef
.simobj
= simobj
1957 assert(isSimObject(newRef
.simobj
))
1958 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1961 def unproxy(self
, simobj
):
1962 [el
.unproxy(simobj
) for el
in self
.elements
]
1964 def ccConnect(self
):
1965 [el
.ccConnect() for el
in self
.elements
]
1967 # Port description object. Like a ParamDesc object, this represents a
1968 # logical port in the SimObject class, not a particular port on a
1969 # SimObject instance. The latter are represented by PortRef objects.
1971 # Generate a PortRef for this port on the given SimObject with the
1973 def makeRef(self
, simobj
):
1974 return PortRef(simobj
, self
.name
, self
.role
)
1976 # Connect an instance of this port (on the given SimObject with
1977 # the given name) with the port described by the supplied PortRef
1978 def connect(self
, simobj
, ref
):
1979 self
.makeRef(simobj
).connect(ref
)
1981 # No need for any pre-declarations at the moment as we merely rely
1982 # on an unsigned int.
1983 def cxx_predecls(self
, code
):
1986 def pybind_predecls(self
, code
):
1987 cls
.cxx_predecls(self
, code
)
1989 # Declare an unsigned int with the same name as the port, that
1990 # will eventually hold the number of connected ports (and thus the
1991 # number of elements for a VectorPort).
1992 def cxx_decl(self
, code
):
1993 code('unsigned int port_${{self.name}}_connection_count;')
1995 class MasterPort(Port
):
1996 # MasterPort("description")
1997 def __init__(self
, *args
):
2000 self
.role
= 'MASTER'
2002 raise TypeError, 'wrong number of arguments'
2004 class SlavePort(Port
):
2005 # SlavePort("description")
2006 def __init__(self
, *args
):
2011 raise TypeError, 'wrong number of arguments'
2013 # VectorPort description object. Like Port, but represents a vector
2014 # of connections (e.g., as on a XBar).
2015 class VectorPort(Port
):
2016 def __init__(self
, *args
):
2019 def makeRef(self
, simobj
):
2020 return VectorPortRef(simobj
, self
.name
, self
.role
)
2022 class VectorMasterPort(VectorPort
):
2023 # VectorMasterPort("description")
2024 def __init__(self
, *args
):
2027 self
.role
= 'MASTER'
2028 VectorPort
.__init
__(self
, *args
)
2030 raise TypeError, 'wrong number of arguments'
2032 class VectorSlavePort(VectorPort
):
2033 # VectorSlavePort("description")
2034 def __init__(self
, *args
):
2038 VectorPort
.__init
__(self
, *args
)
2040 raise TypeError, 'wrong number of arguments'
2042 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2043 # proxy objects (via set_param_desc()) so that proxy error messages
2045 class PortParamDesc(object):
2046 __metaclass__
= Singleton
2051 baseEnums
= allEnums
.copy()
2052 baseParams
= allParams
.copy()
2055 global allEnums
, allParams
2057 allEnums
= baseEnums
.copy()
2058 allParams
= baseParams
.copy()
2060 __all__
= ['Param', 'VectorParam',
2061 'Enum', 'Bool', 'String', 'Float',
2062 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2063 'Int32', 'UInt32', 'Int64', 'UInt64',
2064 'Counter', 'Addr', 'Tick', 'Percent',
2065 'TcpPort', 'UdpPort', 'EthernetAddr',
2066 'IpAddress', 'IpNetmask', 'IpWithPort',
2067 'MemorySize', 'MemorySize32',
2068 'Latency', 'Frequency', 'Clock', 'Voltage',
2069 'NetworkBandwidth', 'MemoryBandwidth',
2071 'MaxAddr', 'MaxTick', 'AllMemory',
2073 'NextEthernetAddr', 'NULL',
2074 'MasterPort', 'SlavePort',
2075 'VectorMasterPort', 'VectorSlavePort']