e5f47e6946b8372a93828e88cbaa87f646482e6d
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 elements
= [e
for e
in self
if not isNullPointer(e
)]
274 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in elements
])
276 # return 'cpu0 cpu1' etc. for print_ini()
278 return ' '.join([v
._name
for v
in self
])
280 # By iterating through the constituent members of the vector here
281 # we can nicely handle iterating over all a SimObject's children
282 # without having to provide lots of special functions on
283 # SimObjectVector directly.
284 def descendants(self
):
286 for obj
in v
.descendants():
289 def get_config_as_dict(self
):
292 a
.append(v
.get_config_as_dict())
295 # If we are replacing an item in the vector, make sure to set the
296 # parent reference of the new SimObject to be the same as the parent
297 # of the SimObject being replaced. Useful to have if we created
298 # a SimObjectVector of temporary objects that will be modified later in
299 # configuration scripts.
300 def __setitem__(self
, key
, value
):
302 if value
.has_parent():
303 warn("SimObject %s already has a parent" % value
.get_name() +\
304 " that is being overwritten by a SimObjectVector")
305 value
.set_parent(val
.get_parent(), val
._name
)
306 super(SimObjectVector
, self
).__setitem
__(key
, value
)
308 # Enumerate the params of each member of the SimObject vector. Creates
309 # strings that will allow indexing into the vector by the python code and
310 # allow it to be specified on the command line.
311 def enumerateParams(self
, flags_dict
= {},
314 if hasattr(self
, "_paramEnumed"):
315 print "Cycle detected enumerating params at %s?!" % (cmd_line_str
)
319 # Each entry in the SimObjectVector should be an
320 # instance of a SimObject
321 flags_dict
= vals
.enumerateParams(flags_dict
,
322 cmd_line_str
+ "%d." % x
,
323 access_str
+ "[%d]." % x
)
328 class VectorParamDesc(ParamDesc
):
329 # Convert assigned value to appropriate type. If the RHS is not a
330 # list or tuple, it generates a single-element list.
331 def convert(self
, value
):
332 if isinstance(value
, (list, tuple)):
333 # list: coerce each element into new list
334 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
335 elif isinstance(value
, str):
336 # If input is a csv string
337 tmp_list
= [ ParamDesc
.convert(self
, v
) \
338 for v
in value
.strip('[').strip(']').split(',') ]
340 # singleton: coerce to a single-element list
341 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
343 if isSimObjectSequence(tmp_list
):
344 return SimObjectVector(tmp_list
)
346 return VectorParamValue(tmp_list
)
348 # Produce a human readable example string that describes
349 # how to set this vector parameter in the absence of a default
351 def example_str(self
):
352 s
= super(VectorParamDesc
, self
).example_str()
353 help_str
= "[" + s
+ "," + s
+ ", ...]"
356 # Produce a human readable representation of the value of this vector param.
357 def pretty_print(self
, value
):
358 if isinstance(value
, (list, tuple)):
359 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
360 elif isinstance(value
, str):
361 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
363 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
367 # This is a helper function for the new config system
368 def __call__(self
, value
):
369 if isinstance(value
, (list, tuple)):
370 # list: coerce each element into new list
371 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
372 elif isinstance(value
, str):
373 # If input is a csv string
374 tmp_list
= [ ParamDesc
.convert(self
, v
) \
375 for v
in value
.strip('[').strip(']').split(',') ]
377 # singleton: coerce to a single-element list
378 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
380 return VectorParamValue(tmp_list
)
382 def cxx_predecls(self
, code
):
383 code('#include <vector>')
384 self
.ptype
.cxx_predecls(code
)
386 def pybind_predecls(self
, code
):
387 code('#include <vector>')
388 self
.ptype
.pybind_predecls(code
)
390 def cxx_decl(self
, code
):
391 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
393 class ParamFactory(object):
394 def __init__(self
, param_desc_class
, ptype_str
= None):
395 self
.param_desc_class
= param_desc_class
396 self
.ptype_str
= ptype_str
398 def __getattr__(self
, attr
):
400 attr
= self
.ptype_str
+ '.' + attr
401 return ParamFactory(self
.param_desc_class
, attr
)
403 # E.g., Param.Int(5, "number of widgets")
404 def __call__(self
, *args
, **kwargs
):
407 ptype
= allParams
[self
.ptype_str
]
409 # if name isn't defined yet, assume it's a SimObject, and
410 # try to resolve it later
412 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
414 Param
= ParamFactory(ParamDesc
)
415 VectorParam
= ParamFactory(VectorParamDesc
)
417 #####################################################################
421 # Though native Python types could be used to specify parameter types
422 # (the 'ptype' field of the Param and VectorParam classes), it's more
423 # flexible to define our own set of types. This gives us more control
424 # over how Python expressions are converted to values (via the
425 # __init__() constructor) and how these values are printed out (via
426 # the __str__() conversion method).
428 #####################################################################
430 # String-valued parameter. Just mixin the ParamValue class with the
431 # built-in str class.
432 class String(ParamValue
,str):
433 cxx_type
= 'std::string'
434 cmd_line_settable
= True
437 def cxx_predecls(self
, code
):
438 code('#include <string>')
440 def __call__(self
, value
):
445 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
446 code('%s = %s;' % (dest
, src
))
447 code('%s true;' % ret
)
452 # superclass for "numeric" parameter values, to emulate math
453 # operations in a type-safe way. e.g., a Latency times an int returns
454 # a new Latency object.
455 class NumericParamValue(ParamValue
):
457 return str(self
.value
)
460 return float(self
.value
)
463 return long(self
.value
)
466 return int(self
.value
)
468 # hook for bounds checking
472 def __mul__(self
, other
):
473 newobj
= self
.__class
__(self
)
474 newobj
.value
*= other
480 def __div__(self
, other
):
481 newobj
= self
.__class
__(self
)
482 newobj
.value
/= other
486 def __sub__(self
, other
):
487 newobj
= self
.__class
__(self
)
488 newobj
.value
-= other
492 def config_value(self
):
496 def cxx_ini_predecls(cls
, code
):
497 # Assume that base/str.hh will be included anyway
498 # code('#include "base/str.hh"')
501 # The default for parsing PODs from an .ini entry is to extract from an
502 # istringstream and let overloading choose the right type according to
505 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
506 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
508 # Metaclass for bounds-checked integer parameters. See CheckedInt.
509 class CheckedIntType(MetaParamValue
):
510 def __init__(cls
, name
, bases
, dict):
511 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
513 # CheckedInt is an abstract base class, so we actually don't
514 # want to do any processing on it... the rest of this code is
515 # just for classes that derive from CheckedInt.
516 if name
== 'CheckedInt':
519 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
520 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
521 panic("CheckedInt subclass %s must define either\n" \
522 " 'min' and 'max' or 'size' and 'unsigned'\n",
526 cls
.max = 2 ** cls
.size
- 1
528 cls
.min = -(2 ** (cls
.size
- 1))
529 cls
.max = (2 ** (cls
.size
- 1)) - 1
531 # Abstract superclass for bounds-checked integer parameters. This
532 # class is subclassed to generate parameter classes with specific
533 # bounds. Initialization of the min and max bounds is done in the
534 # metaclass CheckedIntType.__init__.
535 class CheckedInt(NumericParamValue
):
536 __metaclass__
= CheckedIntType
537 cmd_line_settable
= True
540 if not self
.min <= self
.value
<= self
.max:
541 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
542 (self
.min, self
.value
, self
.max)
544 def __init__(self
, value
):
545 if isinstance(value
, str):
546 self
.value
= convert
.toInteger(value
)
547 elif isinstance(value
, (int, long, float, NumericParamValue
)):
548 self
.value
= long(value
)
550 raise TypeError, "Can't convert object of type %s to CheckedInt" \
551 % type(value
).__name
__
554 def __call__(self
, value
):
559 def cxx_predecls(cls
, code
):
560 # most derived types require this, so we just do it here once
561 code('#include "base/types.hh"')
564 return long(self
.value
)
566 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
567 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
569 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
570 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
571 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
572 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
573 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
574 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
575 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
576 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
578 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
579 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
580 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
581 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
583 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
585 class Cycles(CheckedInt
):
591 from _m5
.core
import Cycles
592 return Cycles(self
.value
)
595 def cxx_ini_predecls(cls
, code
):
596 # Assume that base/str.hh will be included anyway
597 # code('#include "base/str.hh"')
601 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
602 code('uint64_t _temp;')
603 code('bool _ret = to_number(%s, _temp);' % src
)
605 code(' %s = Cycles(_temp);' % dest
)
606 code('%s _ret;' % ret
)
608 class Float(ParamValue
, float):
610 cmd_line_settable
= True
612 def __init__(self
, value
):
613 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
614 self
.value
= float(value
)
616 raise TypeError, "Can't convert object of type %s to Float" \
617 % type(value
).__name
__
619 def __call__(self
, value
):
624 return float(self
.value
)
626 def config_value(self
):
630 def cxx_ini_predecls(cls
, code
):
631 code('#include <sstream>')
634 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
635 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
637 class MemorySize(CheckedInt
):
638 cxx_type
= 'uint64_t'
642 def __init__(self
, value
):
643 if isinstance(value
, MemorySize
):
644 self
.value
= value
.value
646 self
.value
= convert
.toMemorySize(value
)
649 class MemorySize32(CheckedInt
):
650 cxx_type
= 'uint32_t'
654 def __init__(self
, value
):
655 if isinstance(value
, MemorySize
):
656 self
.value
= value
.value
658 self
.value
= convert
.toMemorySize(value
)
661 class Addr(CheckedInt
):
665 def __init__(self
, value
):
666 if isinstance(value
, Addr
):
667 self
.value
= value
.value
670 # Often addresses are referred to with sizes. Ex: A device
671 # base address is at "512MB". Use toMemorySize() to convert
672 # these into addresses. If the address is not specified with a
673 # "size", an exception will occur and numeric translation will
675 self
.value
= convert
.toMemorySize(value
)
676 except (TypeError, ValueError):
677 # Convert number to string and use long() to do automatic
678 # base conversion (requires base=0 for auto-conversion)
679 self
.value
= long(str(value
), base
=0)
682 def __add__(self
, other
):
683 if isinstance(other
, Addr
):
684 return self
.value
+ other
.value
686 return self
.value
+ other
687 def pretty_print(self
, value
):
689 val
= convert
.toMemorySize(value
)
692 return "0x%x" % long(val
)
694 class AddrRange(ParamValue
):
695 cxx_type
= 'AddrRange'
697 def __init__(self
, *args
, **kwargs
):
698 # Disable interleaving and hashing by default
699 self
.intlvHighBit
= 0
704 def handle_kwargs(self
, kwargs
):
705 # An address range needs to have an upper limit, specified
706 # either explicitly with an end, or as an offset using the
709 self
.end
= Addr(kwargs
.pop('end'))
710 elif 'size' in kwargs
:
711 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
713 raise TypeError, "Either end or size must be specified"
715 # Now on to the optional bit
716 if 'intlvHighBit' in kwargs
:
717 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
718 if 'xorHighBit' in kwargs
:
719 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
720 if 'intlvBits' in kwargs
:
721 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
722 if 'intlvMatch' in kwargs
:
723 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
726 self
.start
= Addr(kwargs
.pop('start'))
727 handle_kwargs(self
, kwargs
)
731 self
.start
= Addr(args
[0])
732 handle_kwargs(self
, kwargs
)
733 elif isinstance(args
[0], (list, tuple)):
734 self
.start
= Addr(args
[0][0])
735 self
.end
= Addr(args
[0][1])
738 self
.end
= Addr(args
[0]) - 1
741 self
.start
= Addr(args
[0])
742 self
.end
= Addr(args
[1])
744 raise TypeError, "Too many arguments specified"
747 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
750 return '%s:%s:%s:%s:%s:%s' \
751 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
752 self
.intlvBits
, self
.intlvMatch
)
755 # Divide the size by the size of the interleaving slice
756 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
759 def cxx_predecls(cls
, code
):
760 Addr
.cxx_predecls(code
)
761 code('#include "base/addr_range.hh"')
764 def pybind_predecls(cls
, code
):
765 Addr
.pybind_predecls(code
)
766 code('#include "base/addr_range.hh"')
769 def cxx_ini_predecls(cls
, code
):
770 code('#include <sstream>')
773 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
774 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
775 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
777 code('std::istringstream _stream(${src});')
778 code('_stream >> _start;')
779 code('_stream.get(_sep);')
780 code('_stream >> _end;')
781 code('if (!_stream.fail() && !_stream.eof()) {')
782 code(' _stream.get(_sep);')
783 code(' _stream >> _intlvHighBit;')
784 code(' _stream.get(_sep);')
785 code(' _stream >> _xorHighBit;')
786 code(' _stream.get(_sep);')
787 code(' _stream >> _intlvBits;')
788 code(' _stream.get(_sep);')
789 code(' _stream >> _intlvMatch;')
791 code('bool _ret = !_stream.fail() &&'
792 '_stream.eof() && _sep == \':\';')
794 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
795 _xorHighBit, _intlvBits, _intlvMatch);')
799 # Go from the Python class to the wrapped C++ class
800 from _m5
.range import AddrRange
802 return AddrRange(long(self
.start
), long(self
.end
),
803 int(self
.intlvHighBit
), int(self
.xorHighBit
),
804 int(self
.intlvBits
), int(self
.intlvMatch
))
806 # Boolean parameter type. Python doesn't let you subclass bool, since
807 # it doesn't want to let you create multiple instances of True and
808 # False. Thus this is a little more complicated than String.
809 class Bool(ParamValue
):
811 cmd_line_settable
= True
813 def __init__(self
, value
):
815 self
.value
= convert
.toBool(value
)
817 self
.value
= bool(value
)
819 def __call__(self
, value
):
824 return bool(self
.value
)
827 return str(self
.value
)
829 # implement truth value testing for Bool parameters so that these params
830 # evaluate correctly during the python configuration phase
831 def __nonzero__(self
):
832 return bool(self
.value
)
839 def config_value(self
):
843 def cxx_ini_predecls(cls
, code
):
844 # Assume that base/str.hh will be included anyway
845 # code('#include "base/str.hh"')
849 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
850 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
852 def IncEthernetAddr(addr
, val
= 1):
853 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
855 for i
in (5, 4, 3, 2, 1):
856 val
,rem
= divmod(bytes
[i
], 256)
861 assert(bytes
[0] <= 255)
862 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
864 _NextEthernetAddr
= "00:90:00:00:00:01"
865 def NextEthernetAddr():
866 global _NextEthernetAddr
868 value
= _NextEthernetAddr
869 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
872 class EthernetAddr(ParamValue
):
873 cxx_type
= 'Net::EthAddr'
874 ex_str
= "00:90:00:00:00:01"
875 cmd_line_settable
= True
878 def cxx_predecls(cls
, code
):
879 code('#include "base/inet.hh"')
881 def __init__(self
, value
):
882 if value
== NextEthernetAddr
:
886 if not isinstance(value
, str):
887 raise TypeError, "expected an ethernet address and didn't get one"
889 bytes
= value
.split(':')
891 raise TypeError, 'invalid ethernet address %s' % value
894 if not 0 <= int(byte
, base
=16) <= 0xff:
895 raise TypeError, 'invalid ethernet address %s' % value
899 def __call__(self
, value
):
903 def unproxy(self
, base
):
904 if self
.value
== NextEthernetAddr
:
905 return EthernetAddr(self
.value())
909 from _m5
.net
import EthAddr
910 return EthAddr(self
.value
)
919 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
920 code('%s = Net::EthAddr(%s);' % (dest
, src
))
921 code('%s true;' % ret
)
923 # When initializing an IpAddress, pass in an existing IpAddress, a string of
924 # the form "a.b.c.d", or an integer representing an IP.
925 class IpAddress(ParamValue
):
926 cxx_type
= 'Net::IpAddress'
928 cmd_line_settable
= True
931 def cxx_predecls(cls
, code
):
932 code('#include "base/inet.hh"')
934 def __init__(self
, value
):
935 if isinstance(value
, IpAddress
):
939 self
.ip
= convert
.toIpAddress(value
)
941 self
.ip
= long(value
)
944 def __call__(self
, value
):
949 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
950 return '%d.%d.%d.%d' % tuple(tup
)
952 def __eq__(self
, other
):
953 if isinstance(other
, IpAddress
):
954 return self
.ip
== other
.ip
955 elif isinstance(other
, str):
957 return self
.ip
== convert
.toIpAddress(other
)
961 return self
.ip
== other
963 def __ne__(self
, other
):
964 return not (self
== other
)
967 if self
.ip
< 0 or self
.ip
>= (1 << 32):
968 raise TypeError, "invalid ip address %#08x" % self
.ip
971 from _m5
.net
import IpAddress
972 return IpAddress(self
.ip
)
974 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
975 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
976 # positional or keyword arguments.
977 class IpNetmask(IpAddress
):
978 cxx_type
= 'Net::IpNetmask'
979 ex_str
= "127.0.0.0/24"
980 cmd_line_settable
= True
983 def cxx_predecls(cls
, code
):
984 code('#include "base/inet.hh"')
986 def __init__(self
, *args
, **kwargs
):
987 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
989 setattr(self
, key
, kwargs
.pop(key
))
991 setattr(self
, key
, elseVal
)
993 raise TypeError, "No value set for %s" % key
996 handle_kwarg(self
, kwargs
, 'ip')
997 handle_kwarg(self
, kwargs
, 'netmask')
1001 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1002 raise TypeError, "Invalid arguments"
1003 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1004 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1005 elif isinstance(args
[0], IpNetmask
):
1006 self
.ip
= args
[0].ip
1007 self
.netmask
= args
[0].netmask
1009 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1011 elif len(args
) == 2:
1013 self
.netmask
= args
[1]
1015 raise TypeError, "Too many arguments specified"
1018 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1022 def __call__(self
, value
):
1023 self
.__init
__(value
)
1027 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1029 def __eq__(self
, other
):
1030 if isinstance(other
, IpNetmask
):
1031 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1032 elif isinstance(other
, str):
1034 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1042 if self
.netmask
< 0 or self
.netmask
> 32:
1043 raise TypeError, "invalid netmask %d" % netmask
1046 from _m5
.net
import IpNetmask
1047 return IpNetmask(self
.ip
, self
.netmask
)
1049 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1050 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1051 class IpWithPort(IpAddress
):
1052 cxx_type
= 'Net::IpWithPort'
1053 ex_str
= "127.0.0.1:80"
1054 cmd_line_settable
= True
1057 def cxx_predecls(cls
, code
):
1058 code('#include "base/inet.hh"')
1060 def __init__(self
, *args
, **kwargs
):
1061 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1063 setattr(self
, key
, kwargs
.pop(key
))
1065 setattr(self
, key
, elseVal
)
1067 raise TypeError, "No value set for %s" % key
1070 handle_kwarg(self
, kwargs
, 'ip')
1071 handle_kwarg(self
, kwargs
, 'port')
1073 elif len(args
) == 1:
1075 if not 'ip' in kwargs
and not 'port' in kwargs
:
1076 raise TypeError, "Invalid arguments"
1077 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1078 handle_kwarg(self
, kwargs
, 'port', args
[0])
1079 elif isinstance(args
[0], IpWithPort
):
1080 self
.ip
= args
[0].ip
1081 self
.port
= args
[0].port
1083 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1085 elif len(args
) == 2:
1089 raise TypeError, "Too many arguments specified"
1092 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1096 def __call__(self
, value
):
1097 self
.__init
__(value
)
1101 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1103 def __eq__(self
, other
):
1104 if isinstance(other
, IpWithPort
):
1105 return self
.ip
== other
.ip
and self
.port
== other
.port
1106 elif isinstance(other
, str):
1108 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1116 if self
.port
< 0 or self
.port
> 0xffff:
1117 raise TypeError, "invalid port %d" % self
.port
1120 from _m5
.net
import IpWithPort
1121 return IpWithPort(self
.ip
, self
.port
)
1123 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1124 "%a %b %d %H:%M:%S %Y",
1125 "%Y/%m/%d %H:%M:%S",
1128 "%m/%d/%Y %H:%M:%S",
1131 "%m/%d/%y %H:%M:%S",
1136 def parse_time(value
):
1137 from time
import gmtime
, strptime
, struct_time
, time
1138 from datetime
import datetime
, date
1140 if isinstance(value
, struct_time
):
1143 if isinstance(value
, (int, long)):
1144 return gmtime(value
)
1146 if isinstance(value
, (datetime
, date
)):
1147 return value
.timetuple()
1149 if isinstance(value
, str):
1150 if value
in ('Now', 'Today'):
1151 return time
.gmtime(time
.time())
1153 for format
in time_formats
:
1155 return strptime(value
, format
)
1159 raise ValueError, "Could not parse '%s' as a time" % value
1161 class Time(ParamValue
):
1165 def cxx_predecls(cls
, code
):
1166 code('#include <time.h>')
1168 def __init__(self
, value
):
1169 self
.value
= parse_time(value
)
1171 def __call__(self
, value
):
1172 self
.__init
__(value
)
1176 from _m5
.core
import tm
1179 return tm
.gmtime(calendar
.timegm(self
.value
))
1182 return time
.asctime(self
.value
)
1187 def get_config_as_dict(self
):
1192 def cxx_ini_predecls(cls
, code
):
1193 code('#include <time.h>')
1196 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1197 code('char *_parse_ret = strptime((${src}).c_str(),')
1198 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1199 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1201 # Enumerated types are a little more complex. The user specifies the
1202 # type as Enum(foo) where foo is either a list or dictionary of
1203 # alternatives (typically strings, but not necessarily so). (In the
1204 # long run, the integer value of the parameter will be the list index
1205 # or the corresponding dictionary value. For now, since we only check
1206 # that the alternative is valid and then spit it into a .ini file,
1207 # there's not much point in using the dictionary.)
1209 # What Enum() must do is generate a new type encapsulating the
1210 # provided list/dictionary so that specific values of the parameter
1211 # can be instances of that type. We define two hidden internal
1212 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1213 # derive the new type from the appropriate base class on the fly.
1216 # Metaclass for Enum types
1217 class MetaEnum(MetaParamValue
):
1218 def __new__(mcls
, name
, bases
, dict):
1219 assert name
not in allEnums
1221 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1222 allEnums
[name
] = cls
1225 def __init__(cls
, name
, bases
, init_dict
):
1226 if init_dict
.has_key('map'):
1227 if not isinstance(cls
.map, dict):
1228 raise TypeError, "Enum-derived class attribute 'map' " \
1229 "must be of type dict"
1230 # build list of value strings from map
1231 cls
.vals
= cls
.map.keys()
1233 elif init_dict
.has_key('vals'):
1234 if not isinstance(cls
.vals
, list):
1235 raise TypeError, "Enum-derived class attribute 'vals' " \
1236 "must be of type list"
1237 # build string->value map from vals sequence
1239 for idx
,val
in enumerate(cls
.vals
):
1242 raise TypeError, "Enum-derived class must define "\
1243 "attribute 'map' or 'vals'"
1245 cls
.cxx_type
= 'Enums::%s' % name
1247 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1249 # Generate C++ class declaration for this enum type.
1250 # Note that we wrap the enum in a class/struct to act as a namespace,
1251 # so that the enum strings can be brief w/o worrying about collisions.
1252 def cxx_decl(cls
, code
):
1253 wrapper_name
= cls
.wrapper_name
1254 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1255 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1256 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1262 $wrapper $wrapper_name {
1266 for val
in cls
.vals
:
1267 code('$val = ${{cls.map[val]}},')
1268 code('Num_$name = ${{len(cls.vals)}}')
1272 if cls
.wrapper_is_struct
:
1273 code(' static const char *${name}Strings[Num_${name}];')
1276 code('extern const char *${name}Strings[Num_${name}];')
1280 code('#endif // $idem_macro')
1282 def cxx_def(cls
, code
):
1283 wrapper_name
= cls
.wrapper_name
1284 file_name
= cls
.__name
__
1285 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1287 code('#include "enums/$file_name.hh"')
1288 if cls
.wrapper_is_struct
:
1289 code('const char *${wrapper_name}::${name}Strings'
1292 code('namespace Enums {')
1294 code(' const char *${name}Strings[Num_${name}] =')
1298 for val
in cls
.vals
:
1303 if not cls
.wrapper_is_struct
:
1304 code('} // namespace $wrapper_name')
1307 def pybind_def(cls
, code
):
1309 wrapper_name
= cls
.wrapper_name
1310 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1312 code('''#include "pybind11/pybind11.h"
1313 #include "pybind11/stl.h"
1315 #include <sim/init.hh>
1317 namespace py = pybind11;
1320 module_init(py::module &m_internal)
1322 py::module m = m_internal.def_submodule("enum_${name}");
1324 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
1329 for val
in cls
.vals
:
1330 code('.value("${val}", ${wrapper_name}::${val})')
1331 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1332 code('.export_values()')
1339 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1342 # Base class for enum types.
1343 class Enum(ParamValue
):
1344 __metaclass__
= MetaEnum
1346 cmd_line_settable
= True
1348 # The name of the wrapping namespace or struct
1349 wrapper_name
= 'Enums'
1351 # If true, the enum is wrapped in a struct rather than a namespace
1352 wrapper_is_struct
= False
1354 # If not None, use this as the enum name rather than this class name
1357 def __init__(self
, value
):
1358 if value
not in self
.map:
1359 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1360 % (value
, self
.vals
)
1363 def __call__(self
, value
):
1364 self
.__init
__(value
)
1368 def cxx_predecls(cls
, code
):
1369 code('#include "enums/$0.hh"', cls
.__name
__)
1372 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1373 code('if (false) {')
1374 for elem_name
in cls
.map.iterkeys():
1375 code('} else if (%s == "%s") {' % (src
, elem_name
))
1377 code('%s = Enums::%s;' % (dest
, elem_name
))
1378 code('%s true;' % ret
)
1381 code(' %s false;' % ret
)
1385 import m5
.internal
.params
1386 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1387 return e(self
.map[self
.value
])
1392 # how big does a rounding error need to be before we warn about it?
1393 frequency_tolerance
= 0.001 # 0.1%
1395 class TickParamValue(NumericParamValue
):
1398 cmd_line_settable
= True
1401 def cxx_predecls(cls
, code
):
1402 code('#include "base/types.hh"')
1404 def __call__(self
, value
):
1405 self
.__init
__(value
)
1409 return long(self
.value
)
1412 def cxx_ini_predecls(cls
, code
):
1413 code('#include <sstream>')
1415 # Ticks are expressed in seconds in JSON files and in plain
1416 # Ticks in .ini files. Switch based on a config flag
1418 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1419 code('${ret} to_number(${src}, ${dest});')
1421 class Latency(TickParamValue
):
1424 def __init__(self
, value
):
1425 if isinstance(value
, (Latency
, Clock
)):
1426 self
.ticks
= value
.ticks
1427 self
.value
= value
.value
1428 elif isinstance(value
, Frequency
):
1429 self
.ticks
= value
.ticks
1430 self
.value
= 1.0 / value
.value
1431 elif value
.endswith('t'):
1433 self
.value
= int(value
[:-1])
1436 self
.value
= convert
.toLatency(value
)
1438 def __call__(self
, value
):
1439 self
.__init
__(value
)
1442 def __getattr__(self
, attr
):
1443 if attr
in ('latency', 'period'):
1445 if attr
== 'frequency':
1446 return Frequency(self
)
1447 raise AttributeError, "Latency object has no attribute '%s'" % attr
1450 if self
.ticks
or self
.value
== 0:
1453 value
= ticks
.fromSeconds(self
.value
)
1456 def config_value(self
):
1457 return self
.getValue()
1459 # convert latency to ticks
1461 return '%d' % self
.getValue()
1463 class Frequency(TickParamValue
):
1466 def __init__(self
, value
):
1467 if isinstance(value
, (Latency
, Clock
)):
1468 if value
.value
== 0:
1471 self
.value
= 1.0 / value
.value
1472 self
.ticks
= value
.ticks
1473 elif isinstance(value
, Frequency
):
1474 self
.value
= value
.value
1475 self
.ticks
= value
.ticks
1478 self
.value
= convert
.toFrequency(value
)
1480 def __call__(self
, value
):
1481 self
.__init
__(value
)
1484 def __getattr__(self
, attr
):
1485 if attr
== 'frequency':
1487 if attr
in ('latency', 'period'):
1488 return Latency(self
)
1489 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1491 # convert latency to ticks
1493 if self
.ticks
or self
.value
== 0:
1496 value
= ticks
.fromSeconds(1.0 / self
.value
)
1499 def config_value(self
):
1500 return self
.getValue()
1503 return '%d' % self
.getValue()
1505 # A generic Frequency and/or Latency value. Value is stored as a
1506 # latency, just like Latency and Frequency.
1507 class Clock(TickParamValue
):
1508 def __init__(self
, value
):
1509 if isinstance(value
, (Latency
, Clock
)):
1510 self
.ticks
= value
.ticks
1511 self
.value
= value
.value
1512 elif isinstance(value
, Frequency
):
1513 self
.ticks
= value
.ticks
1514 self
.value
= 1.0 / value
.value
1515 elif value
.endswith('t'):
1517 self
.value
= int(value
[:-1])
1520 self
.value
= convert
.anyToLatency(value
)
1522 def __call__(self
, value
):
1523 self
.__init
__(value
)
1527 return "%s" % Latency(self
)
1529 def __getattr__(self
, attr
):
1530 if attr
== 'frequency':
1531 return Frequency(self
)
1532 if attr
in ('latency', 'period'):
1533 return Latency(self
)
1534 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1537 return self
.period
.getValue()
1539 def config_value(self
):
1540 return self
.period
.config_value()
1543 return self
.period
.ini_str()
1545 class Voltage(float,ParamValue
):
1548 cmd_line_settable
= True
1550 def __new__(cls
, value
):
1551 # convert to voltage
1552 val
= convert
.toVoltage(value
)
1553 return super(cls
, Voltage
).__new
__(cls
, val
)
1555 def __call__(self
, value
):
1556 val
= convert
.toVoltage(value
)
1561 return str(self
.getValue())
1568 return '%f' % self
.getValue()
1571 def cxx_ini_predecls(cls
, code
):
1572 code('#include <sstream>')
1575 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1576 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1578 class Current(float, ParamValue
):
1581 cmd_line_settable
= False
1583 def __new__(cls
, value
):
1584 # convert to current
1585 val
= convert
.toCurrent(value
)
1586 return super(cls
, Current
).__new
__(cls
, val
)
1588 def __call__(self
, value
):
1589 val
= convert
.toCurrent(value
)
1594 return str(self
.getValue())
1601 return '%f' % self
.getValue()
1604 def cxx_ini_predecls(cls
, code
):
1605 code('#include <sstream>')
1608 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1609 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1611 class NetworkBandwidth(float,ParamValue
):
1614 cmd_line_settable
= True
1616 def __new__(cls
, value
):
1617 # convert to bits per second
1618 val
= convert
.toNetworkBandwidth(value
)
1619 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1622 return str(self
.val
)
1624 def __call__(self
, value
):
1625 val
= convert
.toNetworkBandwidth(value
)
1630 # convert to seconds per byte
1631 value
= 8.0 / float(self
)
1632 # convert to ticks per byte
1633 value
= ticks
.fromSeconds(value
)
1637 return '%f' % self
.getValue()
1639 def config_value(self
):
1640 return '%f' % self
.getValue()
1643 def cxx_ini_predecls(cls
, code
):
1644 code('#include <sstream>')
1647 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1648 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1650 class MemoryBandwidth(float,ParamValue
):
1653 cmd_line_settable
= True
1655 def __new__(cls
, value
):
1656 # convert to bytes per second
1657 val
= convert
.toMemoryBandwidth(value
)
1658 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1660 def __call__(self
, value
):
1661 val
= convert
.toMemoryBandwidth(value
)
1666 # convert to seconds per byte
1669 value
= 1.0 / float(self
)
1670 # convert to ticks per byte
1671 value
= ticks
.fromSeconds(value
)
1675 return '%f' % self
.getValue()
1677 def config_value(self
):
1678 return '%f' % self
.getValue()
1681 def cxx_ini_predecls(cls
, code
):
1682 code('#include <sstream>')
1685 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1686 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1689 # "Constants"... handy aliases for various values.
1692 # Special class for NULL pointers. Note the special check in
1693 # make_param_value() above that lets these be assigned where a
1694 # SimObject is required.
1695 # only one copy of a particular node
1696 class NullSimObject(object):
1697 __metaclass__
= Singleton
1702 def _instantiate(self
, parent
= None, path
= ''):
1708 def unproxy(self
, base
):
1711 def set_path(self
, parent
, name
):
1714 def set_parent(self
, parent
, name
):
1720 def config_value(self
):
1726 # The only instance you'll ever need...
1727 NULL
= NullSimObject()
1729 def isNullPointer(value
):
1730 return isinstance(value
, NullSimObject
)
1732 # Some memory range specifications use this as a default upper bound.
1735 AllMemory
= AddrRange(0, MaxAddr
)
1738 #####################################################################
1742 # Ports are used to interconnect objects in the memory system.
1744 #####################################################################
1746 # Port reference: encapsulates a reference to a particular port on a
1747 # particular SimObject.
1748 class PortRef(object):
1749 def __init__(self
, simobj
, name
, role
):
1750 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1751 self
.simobj
= simobj
1754 self
.peer
= None # not associated with another port yet
1755 self
.ccConnected
= False # C++ port connection done?
1756 self
.index
= -1 # always -1 for non-vector ports
1759 return '%s.%s' % (self
.simobj
, self
.name
)
1762 # Return the number of connected ports, i.e. 0 is we have no
1763 # peer and 1 if we do.
1764 return int(self
.peer
!= None)
1766 # for config.ini, print peer's name (not ours)
1768 return str(self
.peer
)
1771 def get_config_as_dict(self
):
1772 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1774 def __getattr__(self
, attr
):
1775 if attr
== 'peerObj':
1776 # shorthand for proxies
1777 return self
.peer
.simobj
1778 raise AttributeError, "'%s' object has no attribute '%s'" % \
1779 (self
.__class
__.__name
__, attr
)
1781 # Full connection is symmetric (both ways). Called via
1782 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1783 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1784 # e.g., "obj1.portA[3] = obj2.portB".
1785 def connect(self
, other
):
1786 if isinstance(other
, VectorPortRef
):
1787 # reference to plain VectorPort is implicit append
1788 other
= other
._get
_next
()
1789 if self
.peer
and not proxy
.isproxy(self
.peer
):
1790 fatal("Port %s is already connected to %s, cannot connect %s\n",
1791 self
, self
.peer
, other
);
1793 if proxy
.isproxy(other
):
1794 other
.set_param_desc(PortParamDesc())
1795 elif isinstance(other
, PortRef
):
1796 if other
.peer
is not self
:
1800 "assigning non-port reference '%s' to port '%s'" \
1803 # Allow a master/slave port pair to be spliced between
1804 # a port and its connected peer. Useful operation for connecting
1805 # instrumentation structures into a system when it is necessary
1806 # to connect the instrumentation after the full system has been
1808 def splice(self
, new_master_peer
, new_slave_peer
):
1809 if self
.peer
and not proxy
.isproxy(self
.peer
):
1810 if isinstance(new_master_peer
, PortRef
) and \
1811 isinstance(new_slave_peer
, PortRef
):
1812 old_peer
= self
.peer
1813 if self
.role
== 'SLAVE':
1814 self
.peer
= new_master_peer
1815 old_peer
.peer
= new_slave_peer
1816 new_master_peer
.connect(self
)
1817 new_slave_peer
.connect(old_peer
)
1818 elif self
.role
== 'MASTER':
1819 self
.peer
= new_slave_peer
1820 old_peer
.peer
= new_master_peer
1821 new_slave_peer
.connect(self
)
1822 new_master_peer
.connect(old_peer
)
1824 panic("Port %s has unknown role, "+\
1825 "cannot splice in new peers\n", self
)
1828 "Splicing non-port references '%s','%s' to port '%s'"\
1829 % (new_peer
, peers_new_peer
, self
)
1831 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1833 def clone(self
, simobj
, memo
):
1834 if memo
.has_key(self
):
1836 newRef
= copy
.copy(self
)
1838 newRef
.simobj
= simobj
1839 assert(isSimObject(newRef
.simobj
))
1840 if self
.peer
and not proxy
.isproxy(self
.peer
):
1841 peerObj
= self
.peer
.simobj(_memo
=memo
)
1842 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1843 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1846 def unproxy(self
, simobj
):
1847 assert(simobj
is self
.simobj
)
1848 if proxy
.isproxy(self
.peer
):
1850 realPeer
= self
.peer
.unproxy(self
.simobj
)
1852 print "Error in unproxying port '%s' of %s" % \
1853 (self
.name
, self
.simobj
.path())
1855 self
.connect(realPeer
)
1857 # Call C++ to create corresponding port connection between C++ objects
1858 def ccConnect(self
):
1859 from _m5
.pyobject
import connectPorts
1861 if self
.role
== 'SLAVE':
1862 # do nothing and let the master take care of it
1865 if self
.ccConnected
: # already done this
1868 if not self
.peer
: # nothing to connect to
1871 # check that we connect a master to a slave
1872 if self
.role
== peer
.role
:
1874 "cannot connect '%s' and '%s' due to identical role '%s'" \
1875 % (peer
, self
, self
.role
)
1878 # self is always the master and peer the slave
1879 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1880 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1882 print "Error connecting port %s.%s to %s.%s" % \
1883 (self
.simobj
.path(), self
.name
,
1884 peer
.simobj
.path(), peer
.name
)
1886 self
.ccConnected
= True
1887 peer
.ccConnected
= True
1889 # A reference to an individual element of a VectorPort... much like a
1890 # PortRef, but has an index.
1891 class VectorPortElementRef(PortRef
):
1892 def __init__(self
, simobj
, name
, role
, index
):
1893 PortRef
.__init
__(self
, simobj
, name
, role
)
1897 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1899 # A reference to a complete vector-valued port (not just a single element).
1900 # Can be indexed to retrieve individual VectorPortElementRef instances.
1901 class VectorPortRef(object):
1902 def __init__(self
, simobj
, name
, role
):
1903 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1904 self
.simobj
= simobj
1910 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1913 # Return the number of connected peers, corresponding the the
1914 # length of the elements.
1915 return len(self
.elements
)
1917 # for config.ini, print peer's name (not ours)
1919 return ' '.join([el
.ini_str() for el
in self
.elements
])
1922 def get_config_as_dict(self
):
1923 return {'role' : self
.role
,
1924 'peer' : [el
.ini_str() for el
in self
.elements
]}
1926 def __getitem__(self
, key
):
1927 if not isinstance(key
, int):
1928 raise TypeError, "VectorPort index must be integer"
1929 if key
>= len(self
.elements
):
1930 # need to extend list
1931 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1932 for i
in range(len(self
.elements
), key
+1)]
1933 self
.elements
.extend(ext
)
1934 return self
.elements
[key
]
1936 def _get_next(self
):
1937 return self
[len(self
.elements
)]
1939 def __setitem__(self
, key
, value
):
1940 if not isinstance(key
, int):
1941 raise TypeError, "VectorPort index must be integer"
1942 self
[key
].connect(value
)
1944 def connect(self
, other
):
1945 if isinstance(other
, (list, tuple)):
1946 # Assign list of port refs to vector port.
1947 # For now, append them... not sure if that's the right semantics
1948 # or if it should replace the current vector.
1950 self
._get
_next
().connect(ref
)
1952 # scalar assignment to plain VectorPort is implicit append
1953 self
._get
_next
().connect(other
)
1955 def clone(self
, simobj
, memo
):
1956 if memo
.has_key(self
):
1958 newRef
= copy
.copy(self
)
1960 newRef
.simobj
= simobj
1961 assert(isSimObject(newRef
.simobj
))
1962 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1965 def unproxy(self
, simobj
):
1966 [el
.unproxy(simobj
) for el
in self
.elements
]
1968 def ccConnect(self
):
1969 [el
.ccConnect() for el
in self
.elements
]
1971 # Port description object. Like a ParamDesc object, this represents a
1972 # logical port in the SimObject class, not a particular port on a
1973 # SimObject instance. The latter are represented by PortRef objects.
1975 # Generate a PortRef for this port on the given SimObject with the
1977 def makeRef(self
, simobj
):
1978 return PortRef(simobj
, self
.name
, self
.role
)
1980 # Connect an instance of this port (on the given SimObject with
1981 # the given name) with the port described by the supplied PortRef
1982 def connect(self
, simobj
, ref
):
1983 self
.makeRef(simobj
).connect(ref
)
1985 # No need for any pre-declarations at the moment as we merely rely
1986 # on an unsigned int.
1987 def cxx_predecls(self
, code
):
1990 def pybind_predecls(self
, code
):
1991 cls
.cxx_predecls(self
, code
)
1993 # Declare an unsigned int with the same name as the port, that
1994 # will eventually hold the number of connected ports (and thus the
1995 # number of elements for a VectorPort).
1996 def cxx_decl(self
, code
):
1997 code('unsigned int port_${{self.name}}_connection_count;')
1999 class MasterPort(Port
):
2000 # MasterPort("description")
2001 def __init__(self
, *args
):
2004 self
.role
= 'MASTER'
2006 raise TypeError, 'wrong number of arguments'
2008 class SlavePort(Port
):
2009 # SlavePort("description")
2010 def __init__(self
, *args
):
2015 raise TypeError, 'wrong number of arguments'
2017 # VectorPort description object. Like Port, but represents a vector
2018 # of connections (e.g., as on a XBar).
2019 class VectorPort(Port
):
2020 def __init__(self
, *args
):
2023 def makeRef(self
, simobj
):
2024 return VectorPortRef(simobj
, self
.name
, self
.role
)
2026 class VectorMasterPort(VectorPort
):
2027 # VectorMasterPort("description")
2028 def __init__(self
, *args
):
2031 self
.role
= 'MASTER'
2032 VectorPort
.__init
__(self
, *args
)
2034 raise TypeError, 'wrong number of arguments'
2036 class VectorSlavePort(VectorPort
):
2037 # VectorSlavePort("description")
2038 def __init__(self
, *args
):
2042 VectorPort
.__init
__(self
, *args
)
2044 raise TypeError, 'wrong number of arguments'
2046 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2047 # proxy objects (via set_param_desc()) so that proxy error messages
2049 class PortParamDesc(object):
2050 __metaclass__
= Singleton
2055 baseEnums
= allEnums
.copy()
2056 baseParams
= allParams
.copy()
2059 global allEnums
, allParams
2061 allEnums
= baseEnums
.copy()
2062 allParams
= baseParams
.copy()
2064 __all__
= ['Param', 'VectorParam',
2065 'Enum', 'Bool', 'String', 'Float',
2066 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2067 'Int32', 'UInt32', 'Int64', 'UInt64',
2068 'Counter', 'Addr', 'Tick', 'Percent',
2069 'TcpPort', 'UdpPort', 'EthernetAddr',
2070 'IpAddress', 'IpNetmask', 'IpWithPort',
2071 'MemorySize', 'MemorySize32',
2072 'Latency', 'Frequency', 'Clock', 'Voltage',
2073 'NetworkBandwidth', 'MemoryBandwidth',
2075 'MaxAddr', 'MaxTick', 'AllMemory',
2077 'NextEthernetAddr', 'NULL',
2078 'MasterPort', 'SlavePort',
2079 'VectorMasterPort', 'VectorSlavePort']