846c5416e21076c7616be9f2c319db4c36f15974
1 # Copyright (c) 2012-2014 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2004-2006 The Regents of The University of Michigan
14 # Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
15 # All rights reserved.
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 # Authors: Steve Reinhardt
45 #####################################################################
47 # Parameter description classes
49 # The _params dictionary in each class maps parameter names to either
50 # a Param or a VectorParam object. These objects contain the
51 # parameter description string, the parameter type, and the default
52 # value (if any). The convert() method on these objects is used to
53 # force whatever value is assigned to the parameter to the appropriate
56 # Note that the default values are loaded into the class's attribute
57 # space when the parameter dictionary is initialized (in
58 # MetaSimObject._new_param()); after that point they aren't used.
60 #####################################################################
73 def isSimObject(*args
, **kwargs
):
74 return SimObject
.isSimObject(*args
, **kwargs
)
76 def isSimObjectSequence(*args
, **kwargs
):
77 return SimObject
.isSimObjectSequence(*args
, **kwargs
)
79 def isSimObjectClass(*args
, **kwargs
):
80 return SimObject
.isSimObjectClass(*args
, **kwargs
)
84 class MetaParamValue(type):
85 def __new__(mcls
, name
, bases
, dct
):
86 cls
= super(MetaParamValue
, mcls
).__new
__(mcls
, name
, bases
, dct
)
87 assert name
not in allParams
92 # Dummy base class to identify types that are legitimate for SimObject
94 class ParamValue(object):
95 __metaclass__
= MetaParamValue
96 cmd_line_settable
= False
98 # Generate the code needed as a prerequisite for declaring a C++
99 # object of this type. Typically generates one or more #include
100 # statements. Used when declaring parameters of this type.
102 def cxx_predecls(cls
, code
):
105 # Generate the code needed as a prerequisite for including a
106 # reference to a C++ object of this type in a SWIG .i file.
107 # Typically generates one or more %import or %include statements.
109 def swig_predecls(cls
, code
):
112 # default for printing to .ini file is regular string conversion.
113 # will be overridden in some cases
117 # default for printing to .json file is regular string conversion.
118 # will be overridden in some cases, mostly to use native Python
119 # types where there are similar JSON types
120 def config_value(self
):
123 # Prerequisites for .ini parsing with cxx_ini_parse
125 def cxx_ini_predecls(cls
, code
):
128 # parse a .ini file entry for this param from string expression
129 # src into lvalue dest (of the param's C++ type)
131 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
132 code('// Unhandled param type: %s' % cls
.__name
__)
133 code('%s false;' % ret
)
135 # allows us to blithely call unproxy() on things without checking
136 # if they're really proxies or not
137 def unproxy(self
, base
):
140 # Produce a human readable version of the stored value
141 def pretty_print(self
, value
):
144 # Regular parameter description.
145 class ParamDesc(object):
146 def __init__(self
, ptype_str
, ptype
, *args
, **kwargs
):
147 self
.ptype_str
= ptype_str
148 # remember ptype only if it is provided
156 self
.default
= args
[0]
159 raise TypeError, 'too many arguments'
161 if kwargs
.has_key('desc'):
162 assert(not hasattr(self
, 'desc'))
163 self
.desc
= kwargs
['desc']
166 if kwargs
.has_key('default'):
167 assert(not hasattr(self
, 'default'))
168 self
.default
= kwargs
['default']
169 del kwargs
['default']
172 raise TypeError, 'extra unknown kwargs %s' % kwargs
174 if not hasattr(self
, 'desc'):
175 raise TypeError, 'desc attribute missing'
177 def __getattr__(self
, attr
):
179 ptype
= SimObject
.allClasses
[self
.ptype_str
]
180 assert isSimObjectClass(ptype
)
184 raise AttributeError, "'%s' object has no attribute '%s'" % \
185 (type(self
).__name
__, attr
)
187 def example_str(self
):
188 if hasattr(self
.ptype
, "ex_str"):
189 return self
.ptype
.ex_str
191 return self
.ptype_str
193 # Is the param available to be exposed on the command line
194 def isCmdLineSettable(self
):
195 if hasattr(self
.ptype
, "cmd_line_settable"):
196 return self
.ptype
.cmd_line_settable
200 def convert(self
, value
):
201 if isinstance(value
, proxy
.BaseProxy
):
202 value
.set_param_desc(self
)
204 if not hasattr(self
, 'ptype') and isNullPointer(value
):
205 # deferred evaluation of SimObject; continue to defer if
206 # we're just assigning a null pointer
208 if isinstance(value
, self
.ptype
):
210 if isNullPointer(value
) and isSimObjectClass(self
.ptype
):
212 return self
.ptype(value
)
214 def pretty_print(self
, value
):
215 if isinstance(value
, proxy
.BaseProxy
):
217 if isNullPointer(value
):
219 return self
.ptype(value
).pretty_print(value
)
221 def cxx_predecls(self
, code
):
222 code('#include <cstddef>')
223 self
.ptype
.cxx_predecls(code
)
225 def swig_predecls(self
, code
):
226 self
.ptype
.swig_predecls(code
)
228 def cxx_decl(self
, code
):
229 code('${{self.ptype.cxx_type}} ${{self.name}};')
231 # Vector-valued parameter description. Just like ParamDesc, except
232 # that the value is a vector (list) of the specified type instead of a
235 class VectorParamValue(list):
236 __metaclass__
= MetaParamValue
237 def __setattr__(self
, attr
, value
):
238 raise AttributeError, \
239 "Not allowed to set %s on '%s'" % (attr
, type(self
).__name
__)
241 def config_value(self
):
242 return [v
.config_value() for v
in self
]
245 return ' '.join([v
.ini_str() for v
in self
])
248 return [ v
.getValue() for v
in self
]
250 def unproxy(self
, base
):
251 if len(self
) == 1 and isinstance(self
[0], proxy
.AllProxy
):
252 return self
[0].unproxy(base
)
254 return [v
.unproxy(base
) for v
in self
]
256 class SimObjectVector(VectorParamValue
):
257 # support clone operation
258 def __call__(self
, **kwargs
):
259 return SimObjectVector([v(**kwargs
) for v
in self
])
261 def clear_parent(self
, old_parent
):
263 v
.clear_parent(old_parent
)
265 def set_parent(self
, parent
, name
):
267 self
[0].set_parent(parent
, name
)
269 width
= int(math
.ceil(math
.log(len(self
))/math
.log(10)))
270 for i
,v
in enumerate(self
):
271 v
.set_parent(parent
, "%s%0*d" % (name
, width
, i
))
273 def has_parent(self
):
274 return reduce(lambda x
,y
: x
and y
, [v
.has_parent() for v
in self
])
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 swig_module_name(self
):
383 return "%s_vector" % self
.ptype_str
385 def swig_predecls(self
, code
):
386 code('%import "${{self.swig_module_name()}}.i"')
388 def swig_decl(self
, code
):
389 code('%module(package="m5.internal") ${{self.swig_module_name()}}')
391 self
.ptype
.cxx_predecls(code
)
394 # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
395 code('%include "std_container.i"')
397 self
.ptype
.swig_predecls(code
)
399 code('%include "std_vector.i"')
402 ptype
= self
.ptype_str
403 cxx_type
= self
.ptype
.cxx_type
405 code('%template(vector_$ptype) std::vector< $cxx_type >;')
407 def cxx_predecls(self
, code
):
408 code('#include <vector>')
409 self
.ptype
.cxx_predecls(code
)
411 def cxx_decl(self
, code
):
412 code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
414 class ParamFactory(object):
415 def __init__(self
, param_desc_class
, ptype_str
= None):
416 self
.param_desc_class
= param_desc_class
417 self
.ptype_str
= ptype_str
419 def __getattr__(self
, attr
):
421 attr
= self
.ptype_str
+ '.' + attr
422 return ParamFactory(self
.param_desc_class
, attr
)
424 # E.g., Param.Int(5, "number of widgets")
425 def __call__(self
, *args
, **kwargs
):
428 ptype
= allParams
[self
.ptype_str
]
430 # if name isn't defined yet, assume it's a SimObject, and
431 # try to resolve it later
433 return self
.param_desc_class(self
.ptype_str
, ptype
, *args
, **kwargs
)
435 Param
= ParamFactory(ParamDesc
)
436 VectorParam
= ParamFactory(VectorParamDesc
)
438 #####################################################################
442 # Though native Python types could be used to specify parameter types
443 # (the 'ptype' field of the Param and VectorParam classes), it's more
444 # flexible to define our own set of types. This gives us more control
445 # over how Python expressions are converted to values (via the
446 # __init__() constructor) and how these values are printed out (via
447 # the __str__() conversion method).
449 #####################################################################
451 # String-valued parameter. Just mixin the ParamValue class with the
452 # built-in str class.
453 class String(ParamValue
,str):
454 cxx_type
= 'std::string'
455 cmd_line_settable
= True
458 def cxx_predecls(self
, code
):
459 code('#include <string>')
462 def swig_predecls(cls
, code
):
463 code('%include "std_string.i"')
465 def __call__(self
, value
):
470 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
471 code('%s = %s;' % (dest
, src
))
472 code('%s true;' % ret
)
477 # superclass for "numeric" parameter values, to emulate math
478 # operations in a type-safe way. e.g., a Latency times an int returns
479 # a new Latency object.
480 class NumericParamValue(ParamValue
):
482 return str(self
.value
)
485 return float(self
.value
)
488 return long(self
.value
)
491 return int(self
.value
)
493 # hook for bounds checking
497 def __mul__(self
, other
):
498 newobj
= self
.__class
__(self
)
499 newobj
.value
*= other
505 def __div__(self
, other
):
506 newobj
= self
.__class
__(self
)
507 newobj
.value
/= other
511 def __sub__(self
, other
):
512 newobj
= self
.__class
__(self
)
513 newobj
.value
-= other
517 def config_value(self
):
521 def cxx_ini_predecls(cls
, code
):
522 # Assume that base/str.hh will be included anyway
523 # code('#include "base/str.hh"')
526 # The default for parsing PODs from an .ini entry is to extract from an
527 # istringstream and let overloading choose the right type according to
530 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
531 code('%s to_number(%s, %s);' % (ret
, src
, dest
))
533 # Metaclass for bounds-checked integer parameters. See CheckedInt.
534 class CheckedIntType(MetaParamValue
):
535 def __init__(cls
, name
, bases
, dict):
536 super(CheckedIntType
, cls
).__init
__(name
, bases
, dict)
538 # CheckedInt is an abstract base class, so we actually don't
539 # want to do any processing on it... the rest of this code is
540 # just for classes that derive from CheckedInt.
541 if name
== 'CheckedInt':
544 if not (hasattr(cls
, 'min') and hasattr(cls
, 'max')):
545 if not (hasattr(cls
, 'size') and hasattr(cls
, 'unsigned')):
546 panic("CheckedInt subclass %s must define either\n" \
547 " 'min' and 'max' or 'size' and 'unsigned'\n",
551 cls
.max = 2 ** cls
.size
- 1
553 cls
.min = -(2 ** (cls
.size
- 1))
554 cls
.max = (2 ** (cls
.size
- 1)) - 1
556 # Abstract superclass for bounds-checked integer parameters. This
557 # class is subclassed to generate parameter classes with specific
558 # bounds. Initialization of the min and max bounds is done in the
559 # metaclass CheckedIntType.__init__.
560 class CheckedInt(NumericParamValue
):
561 __metaclass__
= CheckedIntType
562 cmd_line_settable
= True
565 if not self
.min <= self
.value
<= self
.max:
566 raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
567 (self
.min, self
.value
, self
.max)
569 def __init__(self
, value
):
570 if isinstance(value
, str):
571 self
.value
= convert
.toInteger(value
)
572 elif isinstance(value
, (int, long, float, NumericParamValue
)):
573 self
.value
= long(value
)
575 raise TypeError, "Can't convert object of type %s to CheckedInt" \
576 % type(value
).__name
__
579 def __call__(self
, value
):
584 def cxx_predecls(cls
, code
):
585 # most derived types require this, so we just do it here once
586 code('#include "base/types.hh"')
589 def swig_predecls(cls
, code
):
590 # most derived types require this, so we just do it here once
591 code('%import "stdint.i"')
592 code('%import "base/types.hh"')
595 return long(self
.value
)
597 class Int(CheckedInt
): cxx_type
= 'int'; size
= 32; unsigned
= False
598 class Unsigned(CheckedInt
): cxx_type
= 'unsigned'; size
= 32; unsigned
= True
600 class Int8(CheckedInt
): cxx_type
= 'int8_t'; size
= 8; unsigned
= False
601 class UInt8(CheckedInt
): cxx_type
= 'uint8_t'; size
= 8; unsigned
= True
602 class Int16(CheckedInt
): cxx_type
= 'int16_t'; size
= 16; unsigned
= False
603 class UInt16(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
604 class Int32(CheckedInt
): cxx_type
= 'int32_t'; size
= 32; unsigned
= False
605 class UInt32(CheckedInt
): cxx_type
= 'uint32_t'; size
= 32; unsigned
= True
606 class Int64(CheckedInt
): cxx_type
= 'int64_t'; size
= 64; unsigned
= False
607 class UInt64(CheckedInt
): cxx_type
= 'uint64_t'; size
= 64; unsigned
= True
609 class Counter(CheckedInt
): cxx_type
= 'Counter'; size
= 64; unsigned
= True
610 class Tick(CheckedInt
): cxx_type
= 'Tick'; size
= 64; unsigned
= True
611 class TcpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
612 class UdpPort(CheckedInt
): cxx_type
= 'uint16_t'; size
= 16; unsigned
= True
614 class Percent(CheckedInt
): cxx_type
= 'int'; min = 0; max = 100
616 class Cycles(CheckedInt
):
622 from m5
.internal
.core
import Cycles
623 return Cycles(self
.value
)
626 def cxx_ini_predecls(cls
, code
):
627 # Assume that base/str.hh will be included anyway
628 # code('#include "base/str.hh"')
632 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
633 code('uint64_t _temp;')
634 code('bool _ret = to_number(%s, _temp);' % src
)
636 code(' %s = Cycles(_temp);' % dest
)
637 code('%s _ret;' % ret
)
639 class Float(ParamValue
, float):
641 cmd_line_settable
= True
643 def __init__(self
, value
):
644 if isinstance(value
, (int, long, float, NumericParamValue
, Float
, str)):
645 self
.value
= float(value
)
647 raise TypeError, "Can't convert object of type %s to Float" \
648 % type(value
).__name
__
650 def __call__(self
, value
):
655 return float(self
.value
)
657 def config_value(self
):
661 def cxx_ini_predecls(cls
, code
):
662 code('#include <sstream>')
665 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
666 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
668 class MemorySize(CheckedInt
):
669 cxx_type
= 'uint64_t'
673 def __init__(self
, value
):
674 if isinstance(value
, MemorySize
):
675 self
.value
= value
.value
677 self
.value
= convert
.toMemorySize(value
)
680 class MemorySize32(CheckedInt
):
681 cxx_type
= 'uint32_t'
685 def __init__(self
, value
):
686 if isinstance(value
, MemorySize
):
687 self
.value
= value
.value
689 self
.value
= convert
.toMemorySize(value
)
692 class Addr(CheckedInt
):
696 def __init__(self
, value
):
697 if isinstance(value
, Addr
):
698 self
.value
= value
.value
701 # Often addresses are referred to with sizes. Ex: A device
702 # base address is at "512MB". Use toMemorySize() to convert
703 # these into addresses. If the address is not specified with a
704 # "size", an exception will occur and numeric translation will
706 self
.value
= convert
.toMemorySize(value
)
707 except (TypeError, ValueError):
708 # Convert number to string and use long() to do automatic
709 # base conversion (requires base=0 for auto-conversion)
710 self
.value
= long(str(value
), base
=0)
713 def __add__(self
, other
):
714 if isinstance(other
, Addr
):
715 return self
.value
+ other
.value
717 return self
.value
+ other
718 def pretty_print(self
, value
):
720 val
= convert
.toMemorySize(value
)
723 return "0x%x" % long(val
)
725 class AddrRange(ParamValue
):
726 cxx_type
= 'AddrRange'
728 def __init__(self
, *args
, **kwargs
):
729 # Disable interleaving and hashing by default
730 self
.intlvHighBit
= 0
735 def handle_kwargs(self
, kwargs
):
736 # An address range needs to have an upper limit, specified
737 # either explicitly with an end, or as an offset using the
740 self
.end
= Addr(kwargs
.pop('end'))
741 elif 'size' in kwargs
:
742 self
.end
= self
.start
+ Addr(kwargs
.pop('size')) - 1
744 raise TypeError, "Either end or size must be specified"
746 # Now on to the optional bit
747 if 'intlvHighBit' in kwargs
:
748 self
.intlvHighBit
= int(kwargs
.pop('intlvHighBit'))
749 if 'xorHighBit' in kwargs
:
750 self
.xorHighBit
= int(kwargs
.pop('xorHighBit'))
751 if 'intlvBits' in kwargs
:
752 self
.intlvBits
= int(kwargs
.pop('intlvBits'))
753 if 'intlvMatch' in kwargs
:
754 self
.intlvMatch
= int(kwargs
.pop('intlvMatch'))
757 self
.start
= Addr(kwargs
.pop('start'))
758 handle_kwargs(self
, kwargs
)
762 self
.start
= Addr(args
[0])
763 handle_kwargs(self
, kwargs
)
764 elif isinstance(args
[0], (list, tuple)):
765 self
.start
= Addr(args
[0][0])
766 self
.end
= Addr(args
[0][1])
769 self
.end
= Addr(args
[0]) - 1
772 self
.start
= Addr(args
[0])
773 self
.end
= Addr(args
[1])
775 raise TypeError, "Too many arguments specified"
778 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
781 return '%s:%s' % (self
.start
, self
.end
)
784 # Divide the size by the size of the interleaving slice
785 return (long(self
.end
) - long(self
.start
) + 1) >> self
.intlvBits
788 def cxx_predecls(cls
, code
):
789 Addr
.cxx_predecls(code
)
790 code('#include "base/addr_range.hh"')
793 def swig_predecls(cls
, code
):
794 Addr
.swig_predecls(code
)
797 def cxx_ini_predecls(cls
, code
):
798 code('#include <sstream>')
801 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
802 code('uint64_t _start, _end;')
804 code('std::istringstream _stream(${src});')
805 code('_stream >> _start;')
806 code('_stream.get(_sep);')
807 code('_stream >> _end;')
808 code('bool _ret = !_stream.fail() &&'
809 '_stream.eof() && _sep == \':\';')
811 code(' ${dest} = AddrRange(_start, _end);')
815 # Go from the Python class to the wrapped C++ class generated
817 from m5
.internal
.range import AddrRange
819 return AddrRange(long(self
.start
), long(self
.end
),
820 int(self
.intlvHighBit
), int(self
.xorHighBit
),
821 int(self
.intlvBits
), int(self
.intlvMatch
))
823 # Boolean parameter type. Python doesn't let you subclass bool, since
824 # it doesn't want to let you create multiple instances of True and
825 # False. Thus this is a little more complicated than String.
826 class Bool(ParamValue
):
828 cmd_line_settable
= True
830 def __init__(self
, value
):
832 self
.value
= convert
.toBool(value
)
834 self
.value
= bool(value
)
836 def __call__(self
, value
):
841 return bool(self
.value
)
844 return str(self
.value
)
846 # implement truth value testing for Bool parameters so that these params
847 # evaluate correctly during the python configuration phase
848 def __nonzero__(self
):
849 return bool(self
.value
)
856 def config_value(self
):
860 def cxx_ini_predecls(cls
, code
):
861 # Assume that base/str.hh will be included anyway
862 # code('#include "base/str.hh"')
866 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
867 code('%s to_bool(%s, %s);' % (ret
, src
, dest
))
869 def IncEthernetAddr(addr
, val
= 1):
870 bytes
= map(lambda x
: int(x
, 16), addr
.split(':'))
872 for i
in (5, 4, 3, 2, 1):
873 val
,rem
= divmod(bytes
[i
], 256)
878 assert(bytes
[0] <= 255)
879 return ':'.join(map(lambda x
: '%02x' % x
, bytes
))
881 _NextEthernetAddr
= "00:90:00:00:00:01"
882 def NextEthernetAddr():
883 global _NextEthernetAddr
885 value
= _NextEthernetAddr
886 _NextEthernetAddr
= IncEthernetAddr(_NextEthernetAddr
, 1)
889 class EthernetAddr(ParamValue
):
890 cxx_type
= 'Net::EthAddr'
891 ex_str
= "00:90:00:00:00:01"
892 cmd_line_settable
= True
895 def cxx_predecls(cls
, code
):
896 code('#include "base/inet.hh"')
899 def swig_predecls(cls
, code
):
900 code('%include "python/swig/inet.i"')
902 def __init__(self
, value
):
903 if value
== NextEthernetAddr
:
907 if not isinstance(value
, str):
908 raise TypeError, "expected an ethernet address and didn't get one"
910 bytes
= value
.split(':')
912 raise TypeError, 'invalid ethernet address %s' % value
915 if not 0 <= int(byte
, base
=16) <= 0xff:
916 raise TypeError, 'invalid ethernet address %s' % value
920 def __call__(self
, value
):
924 def unproxy(self
, base
):
925 if self
.value
== NextEthernetAddr
:
926 return EthernetAddr(self
.value())
930 from m5
.internal
.params
import EthAddr
931 return EthAddr(self
.value
)
937 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
938 code('%s = Net::EthAddr(%s);' % (dest
, src
))
939 code('%s true;' % ret
)
941 # When initializing an IpAddress, pass in an existing IpAddress, a string of
942 # the form "a.b.c.d", or an integer representing an IP.
943 class IpAddress(ParamValue
):
944 cxx_type
= 'Net::IpAddress'
946 cmd_line_settable
= True
949 def cxx_predecls(cls
, code
):
950 code('#include "base/inet.hh"')
953 def swig_predecls(cls
, code
):
954 code('%include "python/swig/inet.i"')
956 def __init__(self
, value
):
957 if isinstance(value
, IpAddress
):
961 self
.ip
= convert
.toIpAddress(value
)
963 self
.ip
= long(value
)
966 def __call__(self
, value
):
971 tup
= [(self
.ip
>> i
) & 0xff for i
in (24, 16, 8, 0)]
972 return '%d.%d.%d.%d' % tuple(tup
)
974 def __eq__(self
, other
):
975 if isinstance(other
, IpAddress
):
976 return self
.ip
== other
.ip
977 elif isinstance(other
, str):
979 return self
.ip
== convert
.toIpAddress(other
)
983 return self
.ip
== other
985 def __ne__(self
, other
):
986 return not (self
== other
)
989 if self
.ip
< 0 or self
.ip
>= (1 << 32):
990 raise TypeError, "invalid ip address %#08x" % self
.ip
993 from m5
.internal
.params
import IpAddress
994 return IpAddress(self
.ip
)
996 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
997 # the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
998 # positional or keyword arguments.
999 class IpNetmask(IpAddress
):
1000 cxx_type
= 'Net::IpNetmask'
1001 ex_str
= "127.0.0.0/24"
1002 cmd_line_settable
= True
1005 def cxx_predecls(cls
, code
):
1006 code('#include "base/inet.hh"')
1009 def swig_predecls(cls
, code
):
1010 code('%include "python/swig/inet.i"')
1012 def __init__(self
, *args
, **kwargs
):
1013 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1015 setattr(self
, key
, kwargs
.pop(key
))
1017 setattr(self
, key
, elseVal
)
1019 raise TypeError, "No value set for %s" % key
1022 handle_kwarg(self
, kwargs
, 'ip')
1023 handle_kwarg(self
, kwargs
, 'netmask')
1025 elif len(args
) == 1:
1027 if not 'ip' in kwargs
and not 'netmask' in kwargs
:
1028 raise TypeError, "Invalid arguments"
1029 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1030 handle_kwarg(self
, kwargs
, 'netmask', args
[0])
1031 elif isinstance(args
[0], IpNetmask
):
1032 self
.ip
= args
[0].ip
1033 self
.netmask
= args
[0].netmask
1035 (self
.ip
, self
.netmask
) = convert
.toIpNetmask(args
[0])
1037 elif len(args
) == 2:
1039 self
.netmask
= args
[1]
1041 raise TypeError, "Too many arguments specified"
1044 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1048 def __call__(self
, value
):
1049 self
.__init
__(value
)
1053 return "%s/%d" % (super(IpNetmask
, self
).__str
__(), self
.netmask
)
1055 def __eq__(self
, other
):
1056 if isinstance(other
, IpNetmask
):
1057 return self
.ip
== other
.ip
and self
.netmask
== other
.netmask
1058 elif isinstance(other
, str):
1060 return (self
.ip
, self
.netmask
) == convert
.toIpNetmask(other
)
1068 if self
.netmask
< 0 or self
.netmask
> 32:
1069 raise TypeError, "invalid netmask %d" % netmask
1072 from m5
.internal
.params
import IpNetmask
1073 return IpNetmask(self
.ip
, self
.netmask
)
1075 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1076 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1077 class IpWithPort(IpAddress
):
1078 cxx_type
= 'Net::IpWithPort'
1079 ex_str
= "127.0.0.1:80"
1080 cmd_line_settable
= True
1083 def cxx_predecls(cls
, code
):
1084 code('#include "base/inet.hh"')
1087 def swig_predecls(cls
, code
):
1088 code('%include "python/swig/inet.i"')
1090 def __init__(self
, *args
, **kwargs
):
1091 def handle_kwarg(self
, kwargs
, key
, elseVal
= None):
1093 setattr(self
, key
, kwargs
.pop(key
))
1095 setattr(self
, key
, elseVal
)
1097 raise TypeError, "No value set for %s" % key
1100 handle_kwarg(self
, kwargs
, 'ip')
1101 handle_kwarg(self
, kwargs
, 'port')
1103 elif len(args
) == 1:
1105 if not 'ip' in kwargs
and not 'port' in kwargs
:
1106 raise TypeError, "Invalid arguments"
1107 handle_kwarg(self
, kwargs
, 'ip', args
[0])
1108 handle_kwarg(self
, kwargs
, 'port', args
[0])
1109 elif isinstance(args
[0], IpWithPort
):
1110 self
.ip
= args
[0].ip
1111 self
.port
= args
[0].port
1113 (self
.ip
, self
.port
) = convert
.toIpWithPort(args
[0])
1115 elif len(args
) == 2:
1119 raise TypeError, "Too many arguments specified"
1122 raise TypeError, "Too many keywords: %s" % kwargs
.keys()
1126 def __call__(self
, value
):
1127 self
.__init
__(value
)
1131 return "%s:%d" % (super(IpWithPort
, self
).__str
__(), self
.port
)
1133 def __eq__(self
, other
):
1134 if isinstance(other
, IpWithPort
):
1135 return self
.ip
== other
.ip
and self
.port
== other
.port
1136 elif isinstance(other
, str):
1138 return (self
.ip
, self
.port
) == convert
.toIpWithPort(other
)
1146 if self
.port
< 0 or self
.port
> 0xffff:
1147 raise TypeError, "invalid port %d" % self
.port
1150 from m5
.internal
.params
import IpWithPort
1151 return IpWithPort(self
.ip
, self
.port
)
1153 time_formats
= [ "%a %b %d %H:%M:%S %Z %Y",
1154 "%a %b %d %H:%M:%S %Y",
1155 "%Y/%m/%d %H:%M:%S",
1158 "%m/%d/%Y %H:%M:%S",
1161 "%m/%d/%y %H:%M:%S",
1166 def parse_time(value
):
1167 from time
import gmtime
, strptime
, struct_time
, time
1168 from datetime
import datetime
, date
1170 if isinstance(value
, struct_time
):
1173 if isinstance(value
, (int, long)):
1174 return gmtime(value
)
1176 if isinstance(value
, (datetime
, date
)):
1177 return value
.timetuple()
1179 if isinstance(value
, str):
1180 if value
in ('Now', 'Today'):
1181 return time
.gmtime(time
.time())
1183 for format
in time_formats
:
1185 return strptime(value
, format
)
1189 raise ValueError, "Could not parse '%s' as a time" % value
1191 class Time(ParamValue
):
1195 def cxx_predecls(cls
, code
):
1196 code('#include <time.h>')
1199 def swig_predecls(cls
, code
):
1200 code('%include "python/swig/time.i"')
1202 def __init__(self
, value
):
1203 self
.value
= parse_time(value
)
1205 def __call__(self
, value
):
1206 self
.__init
__(value
)
1210 from m5
.internal
.params
import tm
1213 py_time
= self
.value
1215 # UNIX is years since 1900
1216 c_time
.tm_year
= py_time
.tm_year
- 1900;
1218 # Python starts at 1, UNIX starts at 0
1219 c_time
.tm_mon
= py_time
.tm_mon
- 1;
1220 c_time
.tm_mday
= py_time
.tm_mday
;
1221 c_time
.tm_hour
= py_time
.tm_hour
;
1222 c_time
.tm_min
= py_time
.tm_min
;
1223 c_time
.tm_sec
= py_time
.tm_sec
;
1225 # Python has 0 as Monday, UNIX is 0 as sunday
1226 c_time
.tm_wday
= py_time
.tm_wday
+ 1
1227 if c_time
.tm_wday
> 6:
1228 c_time
.tm_wday
-= 7;
1230 # Python starts at 1, Unix starts at 0
1231 c_time
.tm_yday
= py_time
.tm_yday
- 1;
1236 return time
.asctime(self
.value
)
1241 def get_config_as_dict(self
):
1246 def cxx_ini_predecls(cls
, code
):
1247 code('#include <time.h>')
1250 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1251 code('char *_parse_ret = strptime((${src}).c_str(),')
1252 code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
1253 code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1255 # Enumerated types are a little more complex. The user specifies the
1256 # type as Enum(foo) where foo is either a list or dictionary of
1257 # alternatives (typically strings, but not necessarily so). (In the
1258 # long run, the integer value of the parameter will be the list index
1259 # or the corresponding dictionary value. For now, since we only check
1260 # that the alternative is valid and then spit it into a .ini file,
1261 # there's not much point in using the dictionary.)
1263 # What Enum() must do is generate a new type encapsulating the
1264 # provided list/dictionary so that specific values of the parameter
1265 # can be instances of that type. We define two hidden internal
1266 # classes (_ListEnum and _DictEnum) to serve as base classes, then
1267 # derive the new type from the appropriate base class on the fly.
1270 # Metaclass for Enum types
1271 class MetaEnum(MetaParamValue
):
1272 def __new__(mcls
, name
, bases
, dict):
1273 assert name
not in allEnums
1275 cls
= super(MetaEnum
, mcls
).__new
__(mcls
, name
, bases
, dict)
1276 allEnums
[name
] = cls
1279 def __init__(cls
, name
, bases
, init_dict
):
1280 if init_dict
.has_key('map'):
1281 if not isinstance(cls
.map, dict):
1282 raise TypeError, "Enum-derived class attribute 'map' " \
1283 "must be of type dict"
1284 # build list of value strings from map
1285 cls
.vals
= cls
.map.keys()
1287 elif init_dict
.has_key('vals'):
1288 if not isinstance(cls
.vals
, list):
1289 raise TypeError, "Enum-derived class attribute 'vals' " \
1290 "must be of type list"
1291 # build string->value map from vals sequence
1293 for idx
,val
in enumerate(cls
.vals
):
1296 raise TypeError, "Enum-derived class must define "\
1297 "attribute 'map' or 'vals'"
1299 cls
.cxx_type
= 'Enums::%s' % name
1301 super(MetaEnum
, cls
).__init
__(name
, bases
, init_dict
)
1303 # Generate C++ class declaration for this enum type.
1304 # Note that we wrap the enum in a class/struct to act as a namespace,
1305 # so that the enum strings can be brief w/o worrying about collisions.
1306 def cxx_decl(cls
, code
):
1307 wrapper_name
= cls
.wrapper_name
1308 wrapper
= 'struct' if cls
.wrapper_is_struct
else 'namespace'
1309 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1310 idem_macro
= '__ENUM__%s__%s__' % (wrapper_name
, name
)
1316 $wrapper $wrapper_name {
1320 for val
in cls
.vals
:
1321 code('$val = ${{cls.map[val]}},')
1322 code('Num_$name = ${{len(cls.vals)}}')
1326 if cls
.wrapper_is_struct
:
1327 code(' static const char *${name}Strings[Num_${name}];')
1330 code('extern const char *${name}Strings[Num_${name}];')
1334 code('#endif // $idem_macro')
1336 def cxx_def(cls
, code
):
1337 wrapper_name
= cls
.wrapper_name
1338 file_name
= cls
.__name
__
1339 name
= cls
.__name
__ if cls
.enum_name
is None else cls
.enum_name
1341 code('#include "enums/$file_name.hh"')
1342 if cls
.wrapper_is_struct
:
1343 code('const char *${wrapper_name}::${name}Strings'
1346 code('namespace Enums {')
1348 code(' const char *${name}Strings[Num_${name}] =')
1352 for val
in cls
.vals
:
1357 if not cls
.wrapper_is_struct
:
1358 code('} // namespace $wrapper_name')
1361 def swig_decl(cls
, code
):
1364 %module(package="m5.internal") enum_$name
1367 #include "enums/$name.hh"
1370 %include "enums/$name.hh"
1374 # Base class for enum types.
1375 class Enum(ParamValue
):
1376 __metaclass__
= MetaEnum
1378 cmd_line_settable
= True
1380 # The name of the wrapping namespace or struct
1381 wrapper_name
= 'Enums'
1383 # If true, the enum is wrapped in a struct rather than a namespace
1384 wrapper_is_struct
= False
1386 # If not None, use this as the enum name rather than this class name
1389 def __init__(self
, value
):
1390 if value
not in self
.map:
1391 raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1392 % (value
, self
.vals
)
1395 def __call__(self
, value
):
1396 self
.__init
__(value
)
1400 def cxx_predecls(cls
, code
):
1401 code('#include "enums/$0.hh"', cls
.__name
__)
1404 def swig_predecls(cls
, code
):
1405 code('%import "python/m5/internal/enum_$0.i"', cls
.__name
__)
1408 def cxx_ini_parse(cls
, code
, src
, dest
, ret
):
1409 code('if (false) {')
1410 for elem_name
in cls
.map.iterkeys():
1411 code('} else if (%s == "%s") {' % (src
, elem_name
))
1413 code('%s = Enums::%s;' % (dest
, elem_name
))
1414 code('%s true;' % ret
)
1417 code(' %s false;' % ret
)
1421 return int(self
.map[self
.value
])
1426 # how big does a rounding error need to be before we warn about it?
1427 frequency_tolerance
= 0.001 # 0.1%
1429 class TickParamValue(NumericParamValue
):
1432 cmd_line_settable
= True
1435 def cxx_predecls(cls
, code
):
1436 code('#include "base/types.hh"')
1439 def swig_predecls(cls
, code
):
1440 code('%import "stdint.i"')
1441 code('%import "base/types.hh"')
1443 def __call__(self
, value
):
1444 self
.__init
__(value
)
1448 return long(self
.value
)
1451 def cxx_ini_predecls(cls
, code
):
1452 code('#include <sstream>')
1454 # Ticks are expressed in seconds in JSON files and in plain
1455 # Ticks in .ini files. Switch based on a config flag
1457 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1458 code('${ret} to_number(${src}, ${dest});')
1460 class Latency(TickParamValue
):
1463 def __init__(self
, value
):
1464 if isinstance(value
, (Latency
, Clock
)):
1465 self
.ticks
= value
.ticks
1466 self
.value
= value
.value
1467 elif isinstance(value
, Frequency
):
1468 self
.ticks
= value
.ticks
1469 self
.value
= 1.0 / value
.value
1470 elif value
.endswith('t'):
1472 self
.value
= int(value
[:-1])
1475 self
.value
= convert
.toLatency(value
)
1477 def __call__(self
, value
):
1478 self
.__init
__(value
)
1481 def __getattr__(self
, attr
):
1482 if attr
in ('latency', 'period'):
1484 if attr
== 'frequency':
1485 return Frequency(self
)
1486 raise AttributeError, "Latency object has no attribute '%s'" % attr
1489 if self
.ticks
or self
.value
== 0:
1492 value
= ticks
.fromSeconds(self
.value
)
1495 def config_value(self
):
1496 return self
.getValue()
1498 # convert latency to ticks
1500 return '%d' % self
.getValue()
1502 class Frequency(TickParamValue
):
1505 def __init__(self
, value
):
1506 if isinstance(value
, (Latency
, Clock
)):
1507 if value
.value
== 0:
1510 self
.value
= 1.0 / value
.value
1511 self
.ticks
= value
.ticks
1512 elif isinstance(value
, Frequency
):
1513 self
.value
= value
.value
1514 self
.ticks
= value
.ticks
1517 self
.value
= convert
.toFrequency(value
)
1519 def __call__(self
, value
):
1520 self
.__init
__(value
)
1523 def __getattr__(self
, attr
):
1524 if attr
== 'frequency':
1526 if attr
in ('latency', 'period'):
1527 return Latency(self
)
1528 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1530 # convert latency to ticks
1532 if self
.ticks
or self
.value
== 0:
1535 value
= ticks
.fromSeconds(1.0 / self
.value
)
1538 def config_value(self
):
1539 return self
.getValue()
1542 return '%d' % self
.getValue()
1544 # A generic Frequency and/or Latency value. Value is stored as a
1545 # latency, just like Latency and Frequency.
1546 class Clock(TickParamValue
):
1547 def __init__(self
, value
):
1548 if isinstance(value
, (Latency
, Clock
)):
1549 self
.ticks
= value
.ticks
1550 self
.value
= value
.value
1551 elif isinstance(value
, Frequency
):
1552 self
.ticks
= value
.ticks
1553 self
.value
= 1.0 / value
.value
1554 elif value
.endswith('t'):
1556 self
.value
= int(value
[:-1])
1559 self
.value
= convert
.anyToLatency(value
)
1561 def __call__(self
, value
):
1562 self
.__init
__(value
)
1566 return "%s" % Latency(self
)
1568 def __getattr__(self
, attr
):
1569 if attr
== 'frequency':
1570 return Frequency(self
)
1571 if attr
in ('latency', 'period'):
1572 return Latency(self
)
1573 raise AttributeError, "Frequency object has no attribute '%s'" % attr
1576 return self
.period
.getValue()
1578 def config_value(self
):
1579 return self
.period
.config_value()
1582 return self
.period
.ini_str()
1584 class Voltage(float,ParamValue
):
1587 cmd_line_settable
= False
1589 def __new__(cls
, value
):
1590 # convert to voltage
1591 val
= convert
.toVoltage(value
)
1592 return super(cls
, Voltage
).__new
__(cls
, val
)
1594 def __call__(self
, value
):
1595 val
= convert
.toVoltage(value
)
1600 return str(self
.getValue())
1607 return '%f' % self
.getValue()
1610 def cxx_ini_predecls(cls
, code
):
1611 code('#include <sstream>')
1614 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1615 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1617 class Current(float, ParamValue
):
1620 cmd_line_settable
= False
1622 def __new__(cls
, value
):
1623 # convert to current
1624 val
= convert
.toCurrent(value
)
1625 return super(cls
, Current
).__new
__(cls
, val
)
1627 def __call__(self
, value
):
1628 val
= convert
.toCurrent(value
)
1633 return str(self
.getValue())
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 NetworkBandwidth(float,ParamValue
):
1653 cmd_line_settable
= True
1655 def __new__(cls
, value
):
1656 # convert to bits per second
1657 val
= convert
.toNetworkBandwidth(value
)
1658 return super(cls
, NetworkBandwidth
).__new
__(cls
, val
)
1661 return str(self
.val
)
1663 def __call__(self
, value
):
1664 val
= convert
.toNetworkBandwidth(value
)
1669 # convert to seconds per byte
1670 value
= 8.0 / float(self
)
1671 # convert to ticks per byte
1672 value
= ticks
.fromSeconds(value
)
1676 return '%f' % self
.getValue()
1678 def config_value(self
):
1679 return '%f' % self
.getValue()
1682 def cxx_ini_predecls(cls
, code
):
1683 code('#include <sstream>')
1686 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1687 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1689 class MemoryBandwidth(float,ParamValue
):
1692 cmd_line_settable
= True
1694 def __new__(cls
, value
):
1695 # convert to bytes per second
1696 val
= convert
.toMemoryBandwidth(value
)
1697 return super(cls
, MemoryBandwidth
).__new
__(cls
, val
)
1699 def __call__(self
, value
):
1700 val
= convert
.toMemoryBandwidth(value
)
1705 # convert to seconds per byte
1708 value
= 1.0 / float(self
)
1709 # convert to ticks per byte
1710 value
= ticks
.fromSeconds(value
)
1714 return '%f' % self
.getValue()
1716 def config_value(self
):
1717 return '%f' % self
.getValue()
1720 def cxx_ini_predecls(cls
, code
):
1721 code('#include <sstream>')
1724 def cxx_ini_parse(self
, code
, src
, dest
, ret
):
1725 code('%s (std::istringstream(%s) >> %s).eof();' % (ret
, src
, dest
))
1728 # "Constants"... handy aliases for various values.
1731 # Special class for NULL pointers. Note the special check in
1732 # make_param_value() above that lets these be assigned where a
1733 # SimObject is required.
1734 # only one copy of a particular node
1735 class NullSimObject(object):
1736 __metaclass__
= Singleton
1741 def _instantiate(self
, parent
= None, path
= ''):
1747 def unproxy(self
, base
):
1750 def set_path(self
, parent
, name
):
1756 def config_value(self
):
1762 # The only instance you'll ever need...
1763 NULL
= NullSimObject()
1765 def isNullPointer(value
):
1766 return isinstance(value
, NullSimObject
)
1768 # Some memory range specifications use this as a default upper bound.
1771 AllMemory
= AddrRange(0, MaxAddr
)
1774 #####################################################################
1778 # Ports are used to interconnect objects in the memory system.
1780 #####################################################################
1782 # Port reference: encapsulates a reference to a particular port on a
1783 # particular SimObject.
1784 class PortRef(object):
1785 def __init__(self
, simobj
, name
, role
):
1786 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1787 self
.simobj
= simobj
1790 self
.peer
= None # not associated with another port yet
1791 self
.ccConnected
= False # C++ port connection done?
1792 self
.index
= -1 # always -1 for non-vector ports
1795 return '%s.%s' % (self
.simobj
, self
.name
)
1798 # Return the number of connected ports, i.e. 0 is we have no
1799 # peer and 1 if we do.
1800 return int(self
.peer
!= None)
1802 # for config.ini, print peer's name (not ours)
1804 return str(self
.peer
)
1807 def get_config_as_dict(self
):
1808 return {'role' : self
.role
, 'peer' : str(self
.peer
)}
1810 def __getattr__(self
, attr
):
1811 if attr
== 'peerObj':
1812 # shorthand for proxies
1813 return self
.peer
.simobj
1814 raise AttributeError, "'%s' object has no attribute '%s'" % \
1815 (self
.__class
__.__name
__, attr
)
1817 # Full connection is symmetric (both ways). Called via
1818 # SimObject.__setattr__ as a result of a port assignment, e.g.,
1819 # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1820 # e.g., "obj1.portA[3] = obj2.portB".
1821 def connect(self
, other
):
1822 if isinstance(other
, VectorPortRef
):
1823 # reference to plain VectorPort is implicit append
1824 other
= other
._get
_next
()
1825 if self
.peer
and not proxy
.isproxy(self
.peer
):
1826 fatal("Port %s is already connected to %s, cannot connect %s\n",
1827 self
, self
.peer
, other
);
1829 if proxy
.isproxy(other
):
1830 other
.set_param_desc(PortParamDesc())
1831 elif isinstance(other
, PortRef
):
1832 if other
.peer
is not self
:
1836 "assigning non-port reference '%s' to port '%s'" \
1839 # Allow a master/slave port pair to be spliced between
1840 # a port and its connected peer. Useful operation for connecting
1841 # instrumentation structures into a system when it is necessary
1842 # to connect the instrumentation after the full system has been
1844 def splice(self
, new_master_peer
, new_slave_peer
):
1845 if self
.peer
and not proxy
.isproxy(self
.peer
):
1846 if isinstance(new_master_peer
, PortRef
) and \
1847 isinstance(new_slave_peer
, PortRef
):
1848 old_peer
= self
.peer
1849 if self
.role
== 'SLAVE':
1850 self
.peer
= new_master_peer
1851 old_peer
.peer
= new_slave_peer
1852 new_master_peer
.connect(self
)
1853 new_slave_peer
.connect(old_peer
)
1854 elif self
.role
== 'MASTER':
1855 self
.peer
= new_slave_peer
1856 old_peer
.peer
= new_master_peer
1857 new_slave_peer
.connect(self
)
1858 new_master_peer
.connect(old_peer
)
1860 panic("Port %s has unknown role, "+\
1861 "cannot splice in new peers\n", self
)
1864 "Splicing non-port references '%s','%s' to port '%s'"\
1865 % (new_peer
, peers_new_peer
, self
)
1867 fatal("Port %s not connected, cannot splice in new peers\n", self
)
1869 def clone(self
, simobj
, memo
):
1870 if memo
.has_key(self
):
1872 newRef
= copy
.copy(self
)
1874 newRef
.simobj
= simobj
1875 assert(isSimObject(newRef
.simobj
))
1876 if self
.peer
and not proxy
.isproxy(self
.peer
):
1877 peerObj
= self
.peer
.simobj(_memo
=memo
)
1878 newRef
.peer
= self
.peer
.clone(peerObj
, memo
)
1879 assert(not isinstance(newRef
.peer
, VectorPortRef
))
1882 def unproxy(self
, simobj
):
1883 assert(simobj
is self
.simobj
)
1884 if proxy
.isproxy(self
.peer
):
1886 realPeer
= self
.peer
.unproxy(self
.simobj
)
1888 print "Error in unproxying port '%s' of %s" % \
1889 (self
.name
, self
.simobj
.path())
1891 self
.connect(realPeer
)
1893 # Call C++ to create corresponding port connection between C++ objects
1894 def ccConnect(self
):
1895 from m5
.internal
.pyobject
import connectPorts
1897 if self
.role
== 'SLAVE':
1898 # do nothing and let the master take care of it
1901 if self
.ccConnected
: # already done this
1904 if not self
.peer
: # nothing to connect to
1907 # check that we connect a master to a slave
1908 if self
.role
== peer
.role
:
1910 "cannot connect '%s' and '%s' due to identical role '%s'" \
1911 % (peer
, self
, self
.role
)
1914 # self is always the master and peer the slave
1915 connectPorts(self
.simobj
.getCCObject(), self
.name
, self
.index
,
1916 peer
.simobj
.getCCObject(), peer
.name
, peer
.index
)
1918 print "Error connecting port %s.%s to %s.%s" % \
1919 (self
.simobj
.path(), self
.name
,
1920 peer
.simobj
.path(), peer
.name
)
1922 self
.ccConnected
= True
1923 peer
.ccConnected
= True
1925 # A reference to an individual element of a VectorPort... much like a
1926 # PortRef, but has an index.
1927 class VectorPortElementRef(PortRef
):
1928 def __init__(self
, simobj
, name
, role
, index
):
1929 PortRef
.__init
__(self
, simobj
, name
, role
)
1933 return '%s.%s[%d]' % (self
.simobj
, self
.name
, self
.index
)
1935 # A reference to a complete vector-valued port (not just a single element).
1936 # Can be indexed to retrieve individual VectorPortElementRef instances.
1937 class VectorPortRef(object):
1938 def __init__(self
, simobj
, name
, role
):
1939 assert(isSimObject(simobj
) or isSimObjectClass(simobj
))
1940 self
.simobj
= simobj
1946 return '%s.%s[:]' % (self
.simobj
, self
.name
)
1949 # Return the number of connected peers, corresponding the the
1950 # length of the elements.
1951 return len(self
.elements
)
1953 # for config.ini, print peer's name (not ours)
1955 return ' '.join([el
.ini_str() for el
in self
.elements
])
1958 def get_config_as_dict(self
):
1959 return {'role' : self
.role
,
1960 'peer' : [el
.ini_str() for el
in self
.elements
]}
1962 def __getitem__(self
, key
):
1963 if not isinstance(key
, int):
1964 raise TypeError, "VectorPort index must be integer"
1965 if key
>= len(self
.elements
):
1966 # need to extend list
1967 ext
= [VectorPortElementRef(self
.simobj
, self
.name
, self
.role
, i
)
1968 for i
in range(len(self
.elements
), key
+1)]
1969 self
.elements
.extend(ext
)
1970 return self
.elements
[key
]
1972 def _get_next(self
):
1973 return self
[len(self
.elements
)]
1975 def __setitem__(self
, key
, value
):
1976 if not isinstance(key
, int):
1977 raise TypeError, "VectorPort index must be integer"
1978 self
[key
].connect(value
)
1980 def connect(self
, other
):
1981 if isinstance(other
, (list, tuple)):
1982 # Assign list of port refs to vector port.
1983 # For now, append them... not sure if that's the right semantics
1984 # or if it should replace the current vector.
1986 self
._get
_next
().connect(ref
)
1988 # scalar assignment to plain VectorPort is implicit append
1989 self
._get
_next
().connect(other
)
1991 def clone(self
, simobj
, memo
):
1992 if memo
.has_key(self
):
1994 newRef
= copy
.copy(self
)
1996 newRef
.simobj
= simobj
1997 assert(isSimObject(newRef
.simobj
))
1998 newRef
.elements
= [el
.clone(simobj
, memo
) for el
in self
.elements
]
2001 def unproxy(self
, simobj
):
2002 [el
.unproxy(simobj
) for el
in self
.elements
]
2004 def ccConnect(self
):
2005 [el
.ccConnect() for el
in self
.elements
]
2007 # Port description object. Like a ParamDesc object, this represents a
2008 # logical port in the SimObject class, not a particular port on a
2009 # SimObject instance. The latter are represented by PortRef objects.
2011 # Generate a PortRef for this port on the given SimObject with the
2013 def makeRef(self
, simobj
):
2014 return PortRef(simobj
, self
.name
, self
.role
)
2016 # Connect an instance of this port (on the given SimObject with
2017 # the given name) with the port described by the supplied PortRef
2018 def connect(self
, simobj
, ref
):
2019 self
.makeRef(simobj
).connect(ref
)
2021 # No need for any pre-declarations at the moment as we merely rely
2022 # on an unsigned int.
2023 def cxx_predecls(self
, code
):
2026 # Declare an unsigned int with the same name as the port, that
2027 # will eventually hold the number of connected ports (and thus the
2028 # number of elements for a VectorPort).
2029 def cxx_decl(self
, code
):
2030 code('unsigned int port_${{self.name}}_connection_count;')
2032 class MasterPort(Port
):
2033 # MasterPort("description")
2034 def __init__(self
, *args
):
2037 self
.role
= 'MASTER'
2039 raise TypeError, 'wrong number of arguments'
2041 class SlavePort(Port
):
2042 # SlavePort("description")
2043 def __init__(self
, *args
):
2048 raise TypeError, 'wrong number of arguments'
2050 # VectorPort description object. Like Port, but represents a vector
2051 # of connections (e.g., as on a XBar).
2052 class VectorPort(Port
):
2053 def __init__(self
, *args
):
2056 def makeRef(self
, simobj
):
2057 return VectorPortRef(simobj
, self
.name
, self
.role
)
2059 class VectorMasterPort(VectorPort
):
2060 # VectorMasterPort("description")
2061 def __init__(self
, *args
):
2064 self
.role
= 'MASTER'
2065 VectorPort
.__init
__(self
, *args
)
2067 raise TypeError, 'wrong number of arguments'
2069 class VectorSlavePort(VectorPort
):
2070 # VectorSlavePort("description")
2071 def __init__(self
, *args
):
2075 VectorPort
.__init
__(self
, *args
)
2077 raise TypeError, 'wrong number of arguments'
2079 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2080 # proxy objects (via set_param_desc()) so that proxy error messages
2082 class PortParamDesc(object):
2083 __metaclass__
= Singleton
2088 baseEnums
= allEnums
.copy()
2089 baseParams
= allParams
.copy()
2092 global allEnums
, allParams
2094 allEnums
= baseEnums
.copy()
2095 allParams
= baseParams
.copy()
2097 __all__
= ['Param', 'VectorParam',
2098 'Enum', 'Bool', 'String', 'Float',
2099 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2100 'Int32', 'UInt32', 'Int64', 'UInt64',
2101 'Counter', 'Addr', 'Tick', 'Percent',
2102 'TcpPort', 'UdpPort', 'EthernetAddr',
2103 'IpAddress', 'IpNetmask', 'IpWithPort',
2104 'MemorySize', 'MemorySize32',
2105 'Latency', 'Frequency', 'Clock', 'Voltage',
2106 'NetworkBandwidth', 'MemoryBandwidth',
2108 'MaxAddr', 'MaxTick', 'AllMemory',
2110 'NextEthernetAddr', 'NULL',
2111 'MasterPort', 'SlavePort',
2112 'VectorMasterPort', 'VectorSlavePort']