7a1eec84bd36e2e9711a88b36d8571779e4c0f60
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
.AllProxy
):
249 return self
[0].unproxy(base
)
251 return [v
.unproxy(base
) for v
in self
]
253 class SimObjectVector(VectorParamValue
):
254 # support clone operation
255 def __call__(self
, **kwargs
):
256 return SimObjectVector([v(**kwargs
) for v
in self
])
258 def clear_parent(self
, old_parent
):
260 v
.clear_parent(old_parent
)
262 def set_parent(self
, parent
, name
):
264 self
[0].set_parent(parent
, name
)
266 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
267 for i
,v
in enumerate(self
):
268 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
270 def has_parent(self
):
271 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
273 # return 'cpu0 cpu1' etc. for print_ini()
275 return ' '.join([v
._name
for v
in self
])
277 # By iterating through the constituent members of the vector here
278 # we can nicely handle iterating over all a SimObject's children
279 # without having to provide lots of special functions on
280 # SimObjectVector directly.
281 def descendants(self
):
283 for obj
in v
.descendants():
286 def get_config_as_dict(self
):
289 a
.append(v
.get_config_as_dict())
292 # If we are replacing an item in the vector, make sure to set the
293 # parent reference of the new SimObject to be the same as the parent
294 # of the SimObject being replaced. Useful to have if we created
295 # a SimObjectVector of temporary objects that will be modified later in
296 # configuration scripts.
297 def __setitem__(self
, key
, value
):
299 if value
.has_parent():
300 warn("SimObject %s already has a parent" % value
.get_name() +\
301 " that is being overwritten by a SimObjectVector")
302 value
.set_parent(val
.get_parent(), val
._name
)
303 super(SimObjectVector
, self
).__setitem
__(key
, value
)
305 # Enumerate the params of each member of the SimObject vector. Creates
306 # strings that will allow indexing into the vector by the python code and
307 # allow it to be specified on the command line.
308 def enumerateParams(self
, flags_dict
= {},
311 if hasattr(self
, "_paramEnumed"):
312 print "Cycle detected enumerating params at %s?!" % (cmd_line_str
)
316 # Each entry in the SimObjectVector should be an
317 # instance of a SimObject
318 flags_dict
= vals
.enumerateParams(flags_dict
,
319 cmd_line_str
+ "%d." % x
,
320 access_str
+ "[%d]." % x
)
325 class VectorParamDesc(ParamDesc
):
326 # Convert assigned value to appropriate type. If the RHS is not a
327 # list or tuple, it generates a single-element list.
328 def convert(self
, value
):
329 if isinstance(value
, (list, tuple)):
330 # list: coerce each element into new list
331 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
332 elif isinstance(value
, str):
333 # If input is a csv string
334 tmp_list
= [ ParamDesc
.convert(self
, v
) \
335 for v
in value
.strip('[').strip(']').split(',') ]
337 # singleton: coerce to a single-element list
338 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
340 if isSimObjectSequence(tmp_list
):
341 return SimObjectVector(tmp_list
)
343 return VectorParamValue(tmp_list
)
345 # Produce a human readable example string that describes
346 # how to set this vector parameter in the absence of a default
348 def example_str(self
):
349 s
= super(VectorParamDesc
, self
).example_str()
350 help_str
= "[" + s
+ "," + s
+ ", ...]"
353 # Produce a human readable representation of the value of this vector param.
354 def pretty_print(self
, value
):
355 if isinstance(value
, (list, tuple)):
356 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
]
357 elif isinstance(value
, str):
358 tmp_list
= [ ParamDesc
.pretty_print(self
, v
) for v
in value
.split(',') ]
360 tmp_list
= [ ParamDesc
.pretty_print(self
, value
) ]
364 # This is a helper function for the new config system
365 def __call__(self
, value
):
366 if isinstance(value
, (list, tuple)):
367 # list: coerce each element into new list
368 tmp_list
= [ ParamDesc
.convert(self
, v
) for v
in value
]
369 elif isinstance(value
, str):
370 # If input is a csv string
371 tmp_list
= [ ParamDesc
.convert(self
, v
) \
372 for v
in value
.strip('[').strip(']').split(',') ]
374 # singleton: coerce to a single-element list
375 tmp_list
= [ ParamDesc
.convert(self
, value
) ]
377 return VectorParamValue(tmp_list
)
379 def cxx_predecls(self
, code
):
380 code('#include <vector>')
381 self
.ptype
.cxx_predecls(code
)
383 def pybind_predecls(self
, code
):
384 code('#include <vector>')
385 self
.ptype
.pybind_predecls(code
)
387 def cxx_decl(self
, code
):
388 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
390 class ParamFactory(object):
391 def __init__(self
, param_desc_class
, ptype_str
= None):
392 self
.param_desc_class
= param_desc_class
393 self
.ptype_str
= ptype_str
395 def __getattr__(self
, attr
):
397 attr
= self
.ptype_str
+ '.' + attr
398 return ParamFactory(self
.param_desc_class
, attr
)
400 # E.g., Param.Int(5, "number of widgets")
401 def __call__(self
, *args
, **kwargs
):
404 ptype
= allParams
[self
.ptype_str
]
406 # if name isn't defined yet, assume it's a SimObject, and
407 # try to resolve it later
409 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
411 Param
= ParamFactory(ParamDesc
)
412 VectorParam
= ParamFactory(VectorParamDesc
)
414 #####################################################################
418 # Though native Python types could be used to specify parameter types
419 # (the 'ptype' field of the Param and VectorParam classes), it's more
420 # flexible to define our own set of types. This gives us more control
421 # over how Python expressions are converted to values (via the
422 # __init__() constructor) and how these values are printed out (via
423 # the __str__() conversion method).
425 #####################################################################
427 # String-valued parameter. Just mixin the ParamValue class with the
428 # built-in str class.
429 class String(ParamValue
,str):
430 cxx_type
= 'std::string'
431 cmd_line_settable
= True
434 def cxx_predecls(self
, code
):
435 code('#include <string>')
437 def __call__(self
, value
):
442 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
443 code('%s = %s;' % (dest
, src
))
444 code('%s true;' % ret
)
449 # superclass for "numeric" parameter values, to emulate math
450 # operations in a type-safe way. e.g., a Latency times an int returns
451 # a new Latency object.
452 class NumericParamValue(ParamValue
):
454 return str(self
.value
)
457 return float(self
.value
)
460 return long(self
.value
)
463 return int(self
.value
)
465 # hook for bounds checking
469 def __mul__(self
, other
):
470 newobj
= self
.__class
__(self
)
471 newobj
.value
*= other
477 def __div__(self
, other
):
478 newobj
= self
.__class
__(self
)
479 newobj
.value
/= other
483 def __sub__(self
, other
):
484 newobj
= self
.__class
__(self
)
485 newobj
.value
-= other
489 def config_value(self
):
493 def cxx_ini_predecls(cls
, code
):
494 # Assume that base/str.hh will be included anyway
495 # code('#include "base/str.hh"')
498 # The default for parsing PODs from an .ini entry is to extract from an
499 # istringstream and let overloading choose the right type according to
502 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
503 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
505 # Metaclass for bounds-checked integer parameters. See CheckedInt.
506 class CheckedIntType(MetaParamValue
):
507 def __init__(cls
, name
, bases
, dict):
508 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
510 # CheckedInt is an abstract base class, so we actually don't
511 # want to do any processing on it... the rest of this code is
512 # just for classes that derive from CheckedInt.
513 if name
== 'CheckedInt':
516 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
517 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
518 panic("CheckedInt subclass %s must define either\n" \
519 " 'min' and 'max' or 'size' and 'unsigned'\n",
523 cls
.max = 2 ** cls
.size
- 1
525 cls
.min = -(2 ** (cls
.size
- 1))
526 cls
.max = (2 ** (cls
.size
- 1)) - 1
528 # Abstract superclass for bounds-checked integer parameters. This
529 # class is subclassed to generate parameter classes with specific
530 # bounds. Initialization of the min and max bounds is done in the
531 # metaclass CheckedIntType.__init__.
532 class CheckedInt(NumericParamValue
):
533 __metaclass__
= CheckedIntType
534 cmd_line_settable
= True
537 if not self
.min <= self
.value
<= self
.max:
538 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
539 (self
.min, self
.value
, self
.max)
541 def __init__(self
, value
):
542 if isinstance(value
, str):
543 self
.value
= convert
.toInteger(value
)
544 elif isinstance(value
, (int, long, float, NumericParamValue
)):
545 self
.value
= long(value
)
547 raise TypeError, "Can't convert object of type %s to CheckedInt" \
548 % type(value
).__name
__
551 def __call__(self
, value
):
556 def cxx_predecls(cls
, code
):
557 # most derived types require this, so we just do it here once
558 code('#include "base/types.hh"')
561 return long(self
.value
)
563 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
564 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
566 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
567 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
568 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
569 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
570 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
571 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
572 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
573 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
575 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
576 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
577 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
578 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
580 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
582 class Cycles(CheckedInt
):
588 from _m5
.core
import Cycles
589 return Cycles(self
.value
)
592 def cxx_ini_predecls(cls
, code
):
593 # Assume that base/str.hh will be included anyway
594 # code('#include "base/str.hh"')
598 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
599 code('uint64_t _temp;')
600 code('bool _ret = to_number(%s, _temp);' % src
)
602 code(' %s = Cycles(_temp);' % dest
)
603 code('%s _ret;' % ret
)
605 class Float(ParamValue
, float):
607 cmd_line_settable
= True
609 def __init__(self
, value
):
610 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
611 self
.value
= float(value
)
613 raise TypeError, "Can't convert object of type %s to Float" \
614 % type(value
).__name
__
616 def __call__(self
, value
):
621 return float(self
.value
)
623 def config_value(self
):
627 def cxx_ini_predecls(cls
, code
):
628 code('#include <sstream>')
631 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
632 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
634 class MemorySize(CheckedInt
):
635 cxx_type
= 'uint64_t'
639 def __init__(self
, value
):
640 if isinstance(value
, MemorySize
):
641 self
.value
= value
.value
643 self
.value
= convert
.toMemorySize(value
)
646 class MemorySize32(CheckedInt
):
647 cxx_type
= 'uint32_t'
651 def __init__(self
, value
):
652 if isinstance(value
, MemorySize
):
653 self
.value
= value
.value
655 self
.value
= convert
.toMemorySize(value
)
658 class Addr(CheckedInt
):
662 def __init__(self
, value
):
663 if isinstance(value
, Addr
):
664 self
.value
= value
.value
667 # Often addresses are referred to with sizes. Ex: A device
668 # base address is at "512MB". Use toMemorySize() to convert
669 # these into addresses. If the address is not specified with a
670 # "size", an exception will occur and numeric translation will
672 self
.value
= convert
.toMemorySize(value
)
673 except (TypeError, ValueError):
674 # Convert number to string and use long() to do automatic
675 # base conversion (requires base=0 for auto-conversion)
676 self
.value
= long(str(value
), base
=0)
679 def __add__(self
, other
):
680 if isinstance(other
, Addr
):
681 return self
.value
+ other
.value
683 return self
.value
+ other
684 def pretty_print(self
, value
):
686 val
= convert
.toMemorySize(value
)
689 return "0x%x" % long(val
)
691 class AddrRange(ParamValue
):
692 cxx_type
= 'AddrRange'
694 def __init__(self
, *args
, **kwargs
):
695 # Disable interleaving and hashing by default
696 self
.intlvHighBit
= 0
701 def handle_kwargs(self
, kwargs
):
702 # An address range needs to have an upper limit, specified
703 # either explicitly with an end, or as an offset using the
706 self
.end
= Addr(kwargs
.pop('end'))
707 elif 'size' in kwargs
:
708 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
710 raise TypeError, "Either end or size must be specified"
712 # Now on to the optional bit
713 if 'intlvHighBit' in kwargs
:
714 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
715 if 'xorHighBit' in kwargs
:
716 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
717 if 'intlvBits' in kwargs
:
718 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
719 if 'intlvMatch' in kwargs
:
720 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
723 self
.start
= Addr(kwargs
.pop('start'))
724 handle_kwargs(self
, kwargs
)
728 self
.start
= Addr(args
[0])
729 handle_kwargs(self
, kwargs
)
730 elif isinstance(args
[0], (list, tuple)):
731 self
.start
= Addr(args
[0][0])
732 self
.end
= Addr(args
[0][1])
735 self
.end
= Addr(args
[0]) - 1
738 self
.start
= Addr(args
[0])
739 self
.end
= Addr(args
[1])
741 raise TypeError, "Too many arguments specified"
744 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
747 return '%s:%s:%s:%s:%s:%s' \
748 % (self
.start
, self
.end
, self
.intlvHighBit
, self
.xorHighBit
,\
749 self
.intlvBits
, self
.intlvMatch
)
752 # Divide the size by the size of the interleaving slice
753 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
756 def cxx_predecls(cls
, code
):
757 Addr
.cxx_predecls(code
)
758 code('#include "base/addr_range.hh"')
761 def pybind_predecls(cls
, code
):
762 Addr
.pybind_predecls(code
)
763 code('#include "base/addr_range.hh"')
766 def cxx_ini_predecls(cls
, code
):
767 code('#include <sstream>')
770 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
771 code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
772 code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
774 code('std::istringstream _stream(${src});')
775 code('_stream >> _start;')
776 code('_stream.get(_sep);')
777 code('_stream >> _end;')
778 code('if (!_stream.fail() && !_stream.eof()) {')
779 code(' _stream.get(_sep);')
780 code(' _stream >> _intlvHighBit;')
781 code(' _stream.get(_sep);')
782 code(' _stream >> _xorHighBit;')
783 code(' _stream.get(_sep);')
784 code(' _stream >> _intlvBits;')
785 code(' _stream.get(_sep);')
786 code(' _stream >> _intlvMatch;')
788 code('bool _ret = !_stream.fail() &&'
789 '_stream.eof() && _sep == \':\';')
791 code(' ${dest} = AddrRange(_start, _end, _intlvHighBit, \
792 _xorHighBit, _intlvBits, _intlvMatch);')
796 # Go from the Python class to the wrapped C++ class
797 from _m5
.range import AddrRange
799 return AddrRange(long(self
.start
), long(self
.end
),
800 int(self
.intlvHighBit
), int(self
.xorHighBit
),
801 int(self
.intlvBits
), int(self
.intlvMatch
))
803 # Boolean parameter type. Python doesn't let you subclass bool, since
804 # it doesn't want to let you create multiple instances of True and
805 # False. Thus this is a little more complicated than String.
806 class Bool(ParamValue
):
808 cmd_line_settable
= True
810 def __init__(self
, value
):
812 self
.value
= convert
.toBool(value
)
814 self
.value
= bool(value
)
816 def __call__(self
, value
):
821 return bool(self
.value
)
824 return str(self
.value
)
826 # implement truth value testing for Bool parameters so that these params
827 # evaluate correctly during the python configuration phase
828 def __nonzero__(self
):
829 return bool(self
.value
)
836 def config_value(self
):
840 def cxx_ini_predecls(cls
, code
):
841 # Assume that base/str.hh will be included anyway
842 # code('#include "base/str.hh"')
846 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
847 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
849 def IncEthernetAddr(addr
, val
= 1):
850 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
852 for i
in (5, 4, 3, 2, 1):
853 val
,rem
= divmod(bytes
[i
], 256)
858 assert(bytes
[0] <= 255)
859 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
861 _NextEthernetAddr
= "00:90:00:00:00:01"
862 def NextEthernetAddr():
863 global _NextEthernetAddr
865 value
= _NextEthernetAddr
866 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
869 class EthernetAddr(ParamValue
):
870 cxx_type
= 'Net::EthAddr'
871 ex_str
= "00:90:00:00:00:01"
872 cmd_line_settable
= True
875 def cxx_predecls(cls
, code
):
876 code('#include "base/inet.hh"')
878 def __init__(self
, value
):
879 if value
== NextEthernetAddr
:
883 if not isinstance(value
, str):
884 raise TypeError, "expected an ethernet address and didn't get one"
886 bytes
= value
.split(':')
888 raise TypeError, 'invalid ethernet address %s' % value
891 if not 0 <= int(byte
, base
=16) <= 0xff:
892 raise TypeError, 'invalid ethernet address %s' % value
896 def __call__(self
, value
):
900 def unproxy(self
, base
):
901 if self
.value
== NextEthernetAddr
:
902 return EthernetAddr(self
.value())
906 from _m5
.net
import EthAddr
907 return EthAddr(self
.value
)
916 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
917 code('%s = Net::EthAddr(%s);' % (dest
, src
))
918 code('%s true;' % ret
)
920 # When initializing an IpAddress, pass in an existing IpAddress, a string of
921 # the form "a.b.c.d", or an integer representing an IP.
922 class IpAddress(ParamValue
):
923 cxx_type
= 'Net::IpAddress'
925 cmd_line_settable
= True
928 def cxx_predecls(cls
, code
):
929 code('#include "base/inet.hh"')
931 def __init__(self
, value
):
932 if isinstance(value
, IpAddress
):
936 self
.ip
= convert
.toIpAddress(value
)
938 self
.ip
= long(value
)
941 def __call__(self
, value
):
946 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
947 return '%d.%d.%d.%d' % tuple(tup
)
949 def __eq__(self
, other
):
950 if isinstance(other
, IpAddress
):
951 return self
.ip
== other
.ip
952 elif isinstance(other
, str):
954 return self
.ip
== convert
.toIpAddress(other
)
958 return self
.ip
== other
960 def __ne__(self
, other
):
961 return not (self
== other
)
964 if self
.ip
< 0 or self
.ip
>= (1 << 32):
965 raise TypeError, "invalid ip address %#08x" % self
.ip
968 from _m5
.net
import IpAddress
969 return IpAddress(self
.ip
)
971 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
972 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
973 # positional or keyword arguments.
974 class IpNetmask(IpAddress
):
975 cxx_type
= 'Net::IpNetmask'
976 ex_str
= "127.0.0.0/24"
977 cmd_line_settable
= True
980 def cxx_predecls(cls
, code
):
981 code('#include "base/inet.hh"')
983 def __init__(self
, *args
, **kwargs
):
984 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
986 setattr(self
, key
, kwargs
.pop(key
))
988 setattr(self
, key
, elseVal
)
990 raise TypeError, "No value set for %s" % key
993 handle_kwarg(self
, kwargs
, 'ip')
994 handle_kwarg(self
, kwargs
, 'netmask')
998 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
999 raise TypeError, "Invalid arguments"
1000 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1001 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1002 elif isinstance(args
[0], IpNetmask
):
1003 self
.ip
= args
[0].ip
1004 self
.netmask
= args
[0].netmask
1006 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1008 elif len(args
) == 2:
1010 self
.netmask
= args
[1]
1012 raise TypeError, "Too many arguments specified"
1015 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1019 def __call__(self
, value
):
1020 self
.__init
__(value
)
1024 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1026 def __eq__(self
, other
):
1027 if isinstance(other
, IpNetmask
):
1028 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1029 elif isinstance(other
, str):
1031 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1039 if self
.netmask
< 0 or self
.netmask
> 32:
1040 raise TypeError, "invalid netmask %d" % netmask
1043 from _m5
.net
import IpNetmask
1044 return IpNetmask(self
.ip
, self
.netmask
)
1046 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1047 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1048 class IpWithPort(IpAddress
):
1049 cxx_type
= 'Net::IpWithPort'
1050 ex_str
= "127.0.0.1:80"
1051 cmd_line_settable
= True
1054 def cxx_predecls(cls
, code
):
1055 code('#include "base/inet.hh"')
1057 def __init__(self
, *args
, **kwargs
):
1058 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1060 setattr(self
, key
, kwargs
.pop(key
))
1062 setattr(self
, key
, elseVal
)
1064 raise TypeError, "No value set for %s" % key
1067 handle_kwarg(self
, kwargs
, 'ip')
1068 handle_kwarg(self
, kwargs
, 'port')
1070 elif len(args
) == 1:
1072 if not 'ip' in kwargs
and not 'port' in kwargs
:
1073 raise TypeError, "Invalid arguments"
1074 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1075 handle_kwarg(self
, kwargs
, 'port', args
[0])
1076 elif isinstance(args
[0], IpWithPort
):
1077 self
.ip
= args
[0].ip
1078 self
.port
= args
[0].port
1080 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1082 elif len(args
) == 2:
1086 raise TypeError, "Too many arguments specified"
1089 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1093 def __call__(self
, value
):
1094 self
.__init
__(value
)
1098 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1100 def __eq__(self
, other
):
1101 if isinstance(other
, IpWithPort
):
1102 return self
.ip
== other
.ip
and self
.port
== other
.port
1103 elif isinstance(other
, str):
1105 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1113 if self
.port
< 0 or self
.port
> 0xffff:
1114 raise TypeError, "invalid port %d" % self
.port
1117 from _m5
.net
import IpWithPort
1118 return IpWithPort(self
.ip
, self
.port
)
1120 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1121 "%a %b %d %H:%M:%S %Y",
1122 "%Y/%m/%d %H:%M:%S",
1125 "%m/%d/%Y %H:%M:%S",
1128 "%m/%d/%y %H:%M:%S",
1133 def parse_time(value
):
1134 from time
import gmtime
, strptime
, struct_time
, time
1135 from datetime
import datetime
, date
1137 if isinstance(value
, struct_time
):
1140 if isinstance(value
, (int, long)):
1141 return gmtime(value
)
1143 if isinstance(value
, (datetime
, date
)):
1144 return value
.timetuple()
1146 if isinstance(value
, str):
1147 if value
in ('Now', 'Today'):
1148 return time
.gmtime(time
.time())
1150 for format
in time_formats
:
1152 return strptime(value
, format
)
1156 raise ValueError, "Could not parse '%s' as a time" % value
1158 class Time(ParamValue
):
1162 def cxx_predecls(cls
, code
):
1163 code('#include <time.h>')
1165 def __init__(self
, value
):
1166 self
.value
= parse_time(value
)
1168 def __call__(self
, value
):
1169 self
.__init
__(value
)
1173 from _m5
.core
import tm
1176 return tm
.gmtime(calendar
.timegm(self
.value
))
1179 return time
.asctime(self
.value
)
1184 def get_config_as_dict(self
):
1189 def cxx_ini_predecls(cls
, code
):
1190 code('#include <time.h>')
1193 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1194 code('char *_parse_ret = strptime((${src}).c_str(),')
1195 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1196 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1198 # Enumerated types are a little more complex. The user specifies the
1199 # type as Enum(foo) where foo is either a list or dictionary of
1200 # alternatives (typically strings, but not necessarily so). (In the
1201 # long run, the integer value of the parameter will be the list index
1202 # or the corresponding dictionary value. For now, since we only check
1203 # that the alternative is valid and then spit it into a .ini file,
1204 # there's not much point in using the dictionary.)
1206 # What Enum() must do is generate a new type encapsulating the
1207 # provided list/dictionary so that specific values of the parameter
1208 # can be instances of that type. We define two hidden internal
1209 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1210 # derive the new type from the appropriate base class on the fly.
1213 # Metaclass for Enum types
1214 class MetaEnum(MetaParamValue
):
1215 def __new__(mcls
, name
, bases
, dict):
1216 assert name
not in allEnums
1218 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1219 allEnums
[name
] = cls
1222 def __init__(cls
, name
, bases
, init_dict
):
1223 if init_dict
.has_key('map'):
1224 if not isinstance(cls
.map, dict):
1225 raise TypeError, "Enum-derived class attribute 'map' " \
1226 "must be of type dict"
1227 # build list of value strings from map
1228 cls
.vals
= cls
.map.keys()
1230 elif init_dict
.has_key('vals'):
1231 if not isinstance(cls
.vals
, list):
1232 raise TypeError, "Enum-derived class attribute 'vals' " \
1233 "must be of type list"
1234 # build string->value map from vals sequence
1236 for idx
,val
in enumerate(cls
.vals
):
1239 raise TypeError, "Enum-derived class must define "\
1240 "attribute 'map' or 'vals'"
1242 cls
.cxx_type
= 'Enums::%s' % name
1244 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1246 # Generate C++ class declaration for this enum type.
1247 # Note that we wrap the enum in a class/struct to act as a namespace,
1248 # so that the enum strings can be brief w/o worrying about collisions.
1249 def cxx_decl(cls
, code
):
1250 wrapper_name
= cls
.wrapper_name
1251 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1252 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1253 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1259 $wrapper $wrapper_name {
1263 for val
in cls
.vals
:
1264 code('$val = ${{cls.map[val]}},')
1265 code('Num_$name = ${{len(cls.vals)}}')
1269 if cls
.wrapper_is_struct
:
1270 code(' static const char *${name}Strings[Num_${name}];')
1273 code('extern const char *${name}Strings[Num_${name}];')
1277 code('#endif // $idem_macro')
1279 def cxx_def(cls
, code
):
1280 wrapper_name
= cls
.wrapper_name
1281 file_name
= cls
.__name
__
1282 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1284 code('#include "enums/$file_name.hh"')
1285 if cls
.wrapper_is_struct
:
1286 code('const char *${wrapper_name}::${name}Strings'
1289 code('namespace Enums {')
1291 code(' const char *${name}Strings[Num_${name}] =')
1295 for val
in cls
.vals
:
1300 if not cls
.wrapper_is_struct
:
1301 code('} // namespace $wrapper_name')
1304 def pybind_def(cls
, code
):
1306 wrapper_name
= cls
.wrapper_name
1307 enum_name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1309 code('''#include "pybind11/pybind11.h"
1310 #include "pybind11/stl.h"
1312 #include <sim/init.hh>
1314 namespace py = pybind11;
1317 module_init(py::module &m_internal)
1319 py::module m = m_internal.def_submodule("enum_${name}");
1321 py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
1326 for val
in cls
.vals
:
1327 code('.value("${val}", ${wrapper_name}::${val})')
1328 code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1329 code('.export_values()')
1336 code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1339 # Base class for enum types.
1340 class Enum(ParamValue
):
1341 __metaclass__
= MetaEnum
1343 cmd_line_settable
= True
1345 # The name of the wrapping namespace or struct
1346 wrapper_name
= 'Enums'
1348 # If true, the enum is wrapped in a struct rather than a namespace
1349 wrapper_is_struct
= False
1351 # If not None, use this as the enum name rather than this class name
1354 def __init__(self
, value
):
1355 if value
not in self
.map:
1356 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1357 % (value
, self
.vals
)
1360 def __call__(self
, value
):
1361 self
.__init
__(value
)
1365 def cxx_predecls(cls
, code
):
1366 code('#include "enums/$0.hh"', cls
.__name
__)
1369 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1370 code('if (false) {')
1371 for elem_name
in cls
.map.iterkeys():
1372 code('} else if (%s == "%s") {' % (src
, elem_name
))
1374 code('%s = Enums::%s;' % (dest
, elem_name
))
1375 code('%s true;' % ret
)
1378 code(' %s false;' % ret
)
1382 import m5
.internal
.params
1383 e
= getattr(m5
.internal
.params
, "enum_%s" % self
.__class
__.__name
__)
1384 return e(self
.map[self
.value
])
1389 # how big does a rounding error need to be before we warn about it?
1390 frequency_tolerance
= 0.001 # 0.1%
1392 class TickParamValue(NumericParamValue
):
1395 cmd_line_settable
= True
1398 def cxx_predecls(cls
, code
):
1399 code('#include "base/types.hh"')
1401 def __call__(self
, value
):
1402 self
.__init
__(value
)
1406 return long(self
.value
)
1409 def cxx_ini_predecls(cls
, code
):
1410 code('#include <sstream>')
1412 # Ticks are expressed in seconds in JSON files and in plain
1413 # Ticks in .ini files. Switch based on a config flag
1415 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1416 code('${ret} to_number(${src}, ${dest});')
1418 class Latency(TickParamValue
):
1421 def __init__(self
, value
):
1422 if isinstance(value
, (Latency
, Clock
)):
1423 self
.ticks
= value
.ticks
1424 self
.value
= value
.value
1425 elif isinstance(value
, Frequency
):
1426 self
.ticks
= value
.ticks
1427 self
.value
= 1.0 / value
.value
1428 elif value
.endswith('t'):
1430 self
.value
= int(value
[:-1])
1433 self
.value
= convert
.toLatency(value
)
1435 def __call__(self
, value
):
1436 self
.__init
__(value
)
1439 def __getattr__(self
, attr
):
1440 if attr
in ('latency', 'period'):
1442 if attr
== 'frequency':
1443 return Frequency(self
)
1444 raise AttributeError, "Latency object has no attribute '%s'" % attr
1447 if self
.ticks
or self
.value
== 0:
1450 value
= ticks
.fromSeconds(self
.value
)
1453 def config_value(self
):
1454 return self
.getValue()
1456 # convert latency to ticks
1458 return '%d' % self
.getValue()
1460 class Frequency(TickParamValue
):
1463 def __init__(self
, value
):
1464 if isinstance(value
, (Latency
, Clock
)):
1465 if value
.value
== 0:
1468 self
.value
= 1.0 / value
.value
1469 self
.ticks
= value
.ticks
1470 elif isinstance(value
, Frequency
):
1471 self
.value
= value
.value
1472 self
.ticks
= value
.ticks
1475 self
.value
= convert
.toFrequency(value
)
1477 def __call__(self
, value
):
1478 self
.__init
__(value
)
1481 def __getattr__(self
, attr
):
1482 if attr
== 'frequency':
1484 if attr
in ('latency', 'period'):
1485 return Latency(self
)
1486 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1488 # convert latency to ticks
1490 if self
.ticks
or self
.value
== 0:
1493 value
= ticks
.fromSeconds(1.0 / self
.value
)
1496 def config_value(self
):
1497 return self
.getValue()
1500 return '%d' % self
.getValue()
1502 # A generic Frequency and/or Latency value. Value is stored as a
1503 # latency, just like Latency and Frequency.
1504 class Clock(TickParamValue
):
1505 def __init__(self
, value
):
1506 if isinstance(value
, (Latency
, Clock
)):
1507 self
.ticks
= value
.ticks
1508 self
.value
= value
.value
1509 elif isinstance(value
, Frequency
):
1510 self
.ticks
= value
.ticks
1511 self
.value
= 1.0 / value
.value
1512 elif value
.endswith('t'):
1514 self
.value
= int(value
[:-1])
1517 self
.value
= convert
.anyToLatency(value
)
1519 def __call__(self
, value
):
1520 self
.__init
__(value
)
1524 return "%s" % Latency(self
)
1526 def __getattr__(self
, attr
):
1527 if attr
== 'frequency':
1528 return Frequency(self
)
1529 if attr
in ('latency', 'period'):
1530 return Latency(self
)
1531 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1534 return self
.period
.getValue()
1536 def config_value(self
):
1537 return self
.period
.config_value()
1540 return self
.period
.ini_str()
1542 class Voltage(float,ParamValue
):
1545 cmd_line_settable
= True
1547 def __new__(cls
, value
):
1548 # convert to voltage
1549 val
= convert
.toVoltage(value
)
1550 return super(cls
, Voltage
).__new
__(cls
, val
)
1552 def __call__(self
, value
):
1553 val
= convert
.toVoltage(value
)
1558 return str(self
.getValue())
1565 return '%f' % self
.getValue()
1568 def cxx_ini_predecls(cls
, code
):
1569 code('#include <sstream>')
1572 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1573 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1575 class Current(float, ParamValue
):
1578 cmd_line_settable
= False
1580 def __new__(cls
, value
):
1581 # convert to current
1582 val
= convert
.toCurrent(value
)
1583 return super(cls
, Current
).__new
__(cls
, val
)
1585 def __call__(self
, value
):
1586 val
= convert
.toCurrent(value
)
1591 return str(self
.getValue())
1598 return '%f' % self
.getValue()
1601 def cxx_ini_predecls(cls
, code
):
1602 code('#include <sstream>')
1605 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1606 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1608 class NetworkBandwidth(float,ParamValue
):
1611 cmd_line_settable
= True
1613 def __new__(cls
, value
):
1614 # convert to bits per second
1615 val
= convert
.toNetworkBandwidth(value
)
1616 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1619 return str(self
.val
)
1621 def __call__(self
, value
):
1622 val
= convert
.toNetworkBandwidth(value
)
1627 # convert to seconds per byte
1628 value
= 8.0 / float(self
)
1629 # convert to ticks per byte
1630 value
= ticks
.fromSeconds(value
)
1634 return '%f' % self
.getValue()
1636 def config_value(self
):
1637 return '%f' % self
.getValue()
1640 def cxx_ini_predecls(cls
, code
):
1641 code('#include <sstream>')
1644 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1645 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1647 class MemoryBandwidth(float,ParamValue
):
1650 cmd_line_settable
= True
1652 def __new__(cls
, value
):
1653 # convert to bytes per second
1654 val
= convert
.toMemoryBandwidth(value
)
1655 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1657 def __call__(self
, value
):
1658 val
= convert
.toMemoryBandwidth(value
)
1663 # convert to seconds per byte
1666 value
= 1.0 / float(self
)
1667 # convert to ticks per byte
1668 value
= ticks
.fromSeconds(value
)
1672 return '%f' % self
.getValue()
1674 def config_value(self
):
1675 return '%f' % self
.getValue()
1678 def cxx_ini_predecls(cls
, code
):
1679 code('#include <sstream>')
1682 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1683 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1686 # "Constants"... handy aliases for various values.
1689 # Special class for NULL pointers. Note the special check in
1690 # make_param_value() above that lets these be assigned where a
1691 # SimObject is required.
1692 # only one copy of a particular node
1693 class NullSimObject(object):
1694 __metaclass__
= Singleton
1699 def _instantiate(self
, parent
= None, path
= ''):
1705 def unproxy(self
, base
):
1708 def set_path(self
, parent
, name
):
1714 def config_value(self
):
1720 # The only instance you'll ever need...
1721 NULL
= NullSimObject()
1723 def isNullPointer(value
):
1724 return isinstance(value
, NullSimObject
)
1726 # Some memory range specifications use this as a default upper bound.
1729 AllMemory
= AddrRange(0, MaxAddr
)
1732 #####################################################################
1736 # Ports are used to interconnect objects in the memory system.
1738 #####################################################################
1740 # Port reference: encapsulates a reference to a particular port on a
1741 # particular SimObject.
1742 class PortRef(object):
1743 def __init__(self
, simobj
, name
, role
):
1744 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1745 self
.simobj
= simobj
1748 self
.peer
= None # not associated with another port yet
1749 self
.ccConnected
= False # C++ port connection done?
1750 self
.index
= -1 # always -1 for non-vector ports
1753 return '%s.%s' % (self
.simobj
, self
.name
)
1756 # Return the number of connected ports, i.e. 0 is we have no
1757 # peer and 1 if we do.
1758 return int(self
.peer
!= None)
1760 # for config.ini, print peer's name (not ours)
1762 return str(self
.peer
)
1765 def get_config_as_dict(self
):
1766 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1768 def __getattr__(self
, attr
):
1769 if attr
== 'peerObj':
1770 # shorthand for proxies
1771 return self
.peer
.simobj
1772 raise AttributeError, "'%s' object has no attribute '%s'" % \
1773 (self
.__class
__.__name
__, attr
)
1775 # Full connection is symmetric (both ways). Called via
1776 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1777 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1778 # e.g., "obj1.portA[3] = obj2.portB".
1779 def connect(self
, other
):
1780 if isinstance(other
, VectorPortRef
):
1781 # reference to plain VectorPort is implicit append
1782 other
= other
._get
_next
()
1783 if self
.peer
and not proxy
.isproxy(self
.peer
):
1784 fatal("Port %s is already connected to %s, cannot connect %s\n",
1785 self
, self
.peer
, other
);
1787 if proxy
.isproxy(other
):
1788 other
.set_param_desc(PortParamDesc())
1789 elif isinstance(other
, PortRef
):
1790 if other
.peer
is not self
:
1794 "assigning non-port reference '%s' to port '%s'" \
1797 # Allow a master/slave port pair to be spliced between
1798 # a port and its connected peer. Useful operation for connecting
1799 # instrumentation structures into a system when it is necessary
1800 # to connect the instrumentation after the full system has been
1802 def splice(self
, new_master_peer
, new_slave_peer
):
1803 if self
.peer
and not proxy
.isproxy(self
.peer
):
1804 if isinstance(new_master_peer
, PortRef
) and \
1805 isinstance(new_slave_peer
, PortRef
):
1806 old_peer
= self
.peer
1807 if self
.role
== 'SLAVE':
1808 self
.peer
= new_master_peer
1809 old_peer
.peer
= new_slave_peer
1810 new_master_peer
.connect(self
)
1811 new_slave_peer
.connect(old_peer
)
1812 elif self
.role
== 'MASTER':
1813 self
.peer
= new_slave_peer
1814 old_peer
.peer
= new_master_peer
1815 new_slave_peer
.connect(self
)
1816 new_master_peer
.connect(old_peer
)
1818 panic("Port %s has unknown role, "+\
1819 "cannot splice in new peers\n", self
)
1822 "Splicing non-port references '%s','%s' to port '%s'"\
1823 % (new_peer
, peers_new_peer
, self
)
1825 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1827 def clone(self
, simobj
, memo
):
1828 if memo
.has_key(self
):
1830 newRef
= copy
.copy(self
)
1832 newRef
.simobj
= simobj
1833 assert(isSimObject(newRef
.simobj
))
1834 if self
.peer
and not proxy
.isproxy(self
.peer
):
1835 peerObj
= self
.peer
.simobj(_memo
=memo
)
1836 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1837 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1840 def unproxy(self
, simobj
):
1841 assert(simobj
is self
.simobj
)
1842 if proxy
.isproxy(self
.peer
):
1844 realPeer
= self
.peer
.unproxy(self
.simobj
)
1846 print "Error in unproxying port '%s' of %s" % \
1847 (self
.name
, self
.simobj
.path())
1849 self
.connect(realPeer
)
1851 # Call C++ to create corresponding port connection between C++ objects
1852 def ccConnect(self
):
1853 from _m5
.pyobject
import connectPorts
1855 if self
.role
== 'SLAVE':
1856 # do nothing and let the master take care of it
1859 if self
.ccConnected
: # already done this
1862 if not self
.peer
: # nothing to connect to
1865 # check that we connect a master to a slave
1866 if self
.role
== peer
.role
:
1868 "cannot connect '%s' and '%s' due to identical role '%s'" \
1869 % (peer
, self
, self
.role
)
1872 # self is always the master and peer the slave
1873 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1874 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1876 print "Error connecting port %s.%s to %s.%s" % \
1877 (self
.simobj
.path(), self
.name
,
1878 peer
.simobj
.path(), peer
.name
)
1880 self
.ccConnected
= True
1881 peer
.ccConnected
= True
1883 # A reference to an individual element of a VectorPort... much like a
1884 # PortRef, but has an index.
1885 class VectorPortElementRef(PortRef
):
1886 def __init__(self
, simobj
, name
, role
, index
):
1887 PortRef
.__init
__(self
, simobj
, name
, role
)
1891 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1893 # A reference to a complete vector-valued port (not just a single element).
1894 # Can be indexed to retrieve individual VectorPortElementRef instances.
1895 class VectorPortRef(object):
1896 def __init__(self
, simobj
, name
, role
):
1897 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1898 self
.simobj
= simobj
1904 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1907 # Return the number of connected peers, corresponding the the
1908 # length of the elements.
1909 return len(self
.elements
)
1911 # for config.ini, print peer's name (not ours)
1913 return ' '.join([el
.ini_str() for el
in self
.elements
])
1916 def get_config_as_dict(self
):
1917 return {'role' : self
.role
,
1918 'peer' : [el
.ini_str() for el
in self
.elements
]}
1920 def __getitem__(self
, key
):
1921 if not isinstance(key
, int):
1922 raise TypeError, "VectorPort index must be integer"
1923 if key
>= len(self
.elements
):
1924 # need to extend list
1925 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1926 for i
in range(len(self
.elements
), key
+1)]
1927 self
.elements
.extend(ext
)
1928 return self
.elements
[key
]
1930 def _get_next(self
):
1931 return self
[len(self
.elements
)]
1933 def __setitem__(self
, key
, value
):
1934 if not isinstance(key
, int):
1935 raise TypeError, "VectorPort index must be integer"
1936 self
[key
].connect(value
)
1938 def connect(self
, other
):
1939 if isinstance(other
, (list, tuple)):
1940 # Assign list of port refs to vector port.
1941 # For now, append them... not sure if that's the right semantics
1942 # or if it should replace the current vector.
1944 self
._get
_next
().connect(ref
)
1946 # scalar assignment to plain VectorPort is implicit append
1947 self
._get
_next
().connect(other
)
1949 def clone(self
, simobj
, memo
):
1950 if memo
.has_key(self
):
1952 newRef
= copy
.copy(self
)
1954 newRef
.simobj
= simobj
1955 assert(isSimObject(newRef
.simobj
))
1956 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
1959 def unproxy(self
, simobj
):
1960 [el
.unproxy(simobj
) for el
in self
.elements
]
1962 def ccConnect(self
):
1963 [el
.ccConnect() for el
in self
.elements
]
1965 # Port description object. Like a ParamDesc object, this represents a
1966 # logical port in the SimObject class, not a particular port on a
1967 # SimObject instance. The latter are represented by PortRef objects.
1969 # Generate a PortRef for this port on the given SimObject with the
1971 def makeRef(self
, simobj
):
1972 return PortRef(simobj
, self
.name
, self
.role
)
1974 # Connect an instance of this port (on the given SimObject with
1975 # the given name) with the port described by the supplied PortRef
1976 def connect(self
, simobj
, ref
):
1977 self
.makeRef(simobj
).connect(ref
)
1979 # No need for any pre-declarations at the moment as we merely rely
1980 # on an unsigned int.
1981 def cxx_predecls(self
, code
):
1984 def pybind_predecls(self
, code
):
1985 cls
.cxx_predecls(self
, code
)
1987 # Declare an unsigned int with the same name as the port, that
1988 # will eventually hold the number of connected ports (and thus the
1989 # number of elements for a VectorPort).
1990 def cxx_decl(self
, code
):
1991 code('unsigned int port_${{self.name}}_connection_count;')
1993 class MasterPort(Port
):
1994 # MasterPort("description")
1995 def __init__(self
, *args
):
1998 self
.role
= 'MASTER'
2000 raise TypeError, 'wrong number of arguments'
2002 class SlavePort(Port
):
2003 # SlavePort("description")
2004 def __init__(self
, *args
):
2009 raise TypeError, 'wrong number of arguments'
2011 # VectorPort description object. Like Port, but represents a vector
2012 # of connections (e.g., as on a XBar).
2013 class VectorPort(Port
):
2014 def __init__(self
, *args
):
2017 def makeRef(self
, simobj
):
2018 return VectorPortRef(simobj
, self
.name
, self
.role
)
2020 class VectorMasterPort(VectorPort
):
2021 # VectorMasterPort("description")
2022 def __init__(self
, *args
):
2025 self
.role
= 'MASTER'
2026 VectorPort
.__init
__(self
, *args
)
2028 raise TypeError, 'wrong number of arguments'
2030 class VectorSlavePort(VectorPort
):
2031 # VectorSlavePort("description")
2032 def __init__(self
, *args
):
2036 VectorPort
.__init
__(self
, *args
)
2038 raise TypeError, 'wrong number of arguments'
2040 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2041 # proxy objects (via set_param_desc()) so that proxy error messages
2043 class PortParamDesc(object):
2044 __metaclass__
= Singleton
2049 baseEnums
= allEnums
.copy()
2050 baseParams
= allParams
.copy()
2053 global allEnums
, allParams
2055 allEnums
= baseEnums
.copy()
2056 allParams
= baseParams
.copy()
2058 __all__
= ['Param', 'VectorParam',
2059 'Enum', 'Bool', 'String', 'Float',
2060 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2061 'Int32', 'UInt32', 'Int64', 'UInt64',
2062 'Counter', 'Addr', 'Tick', 'Percent',
2063 'TcpPort', 'UdpPort', 'EthernetAddr',
2064 'IpAddress', 'IpNetmask', 'IpWithPort',
2065 'MemorySize', 'MemorySize32',
2066 'Latency', 'Frequency', 'Clock', 'Voltage',
2067 'NetworkBandwidth', 'MemoryBandwidth',
2069 'MaxAddr', 'MaxTick', 'AllMemory',
2071 'NextEthernetAddr', 'NULL',
2072 'MasterPort', 'SlavePort',
2073 'VectorMasterPort', 'VectorSlavePort']