1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Authors: Steve Reinhardt
35 from multidict
import multidict
37 # These utility functions have to come first because they're
38 # referenced in params.py... otherwise they won't be defined when we
39 # import params below, and the recursive import of this file from
40 # params.py will not find these names.
41 def isSimObject(value
):
42 return isinstance(value
, SimObject
)
44 def isSimObjectClass(value
):
45 return issubclass(value
, SimObject
)
47 def isSimObjectSequence(value
):
48 if not isinstance(value
, (list, tuple)) or len(value
) == 0:
52 if not isNullPointer(val
) and not isSimObject(val
):
57 def isSimObjectOrSequence(value
):
58 return isSimObject(value
) or isSimObjectSequence(value
)
60 # Have to import params up top since Param is referenced on initial
61 # load (when SimObject class references Param to create a class
62 # variable, the 'name' param)...
64 # There are a few things we need that aren't in params.__all__ since
65 # normal users don't need them
66 from params
import ParamDesc
, VectorParamDesc
, isNullPointer
, SimObjVector
74 #####################################################################
76 # M5 Python Configuration Utility
78 # The basic idea is to write simple Python programs that build Python
79 # objects corresponding to M5 SimObjects for the desired simulation
80 # configuration. For now, the Python emits a .ini file that can be
81 # parsed by M5. In the future, some tighter integration between M5
82 # and the Python interpreter may allow bypassing the .ini file.
84 # Each SimObject class in M5 is represented by a Python class with the
85 # same name. The Python inheritance tree mirrors the M5 C++ tree
86 # (e.g., SimpleCPU derives from BaseCPU in both cases, and all
87 # SimObjects inherit from a single SimObject base class). To specify
88 # an instance of an M5 SimObject in a configuration, the user simply
89 # instantiates the corresponding Python object. The parameters for
90 # that SimObject are given by assigning to attributes of the Python
91 # object, either using keyword assignment in the constructor or in
92 # separate assignment statements. For example:
94 # cache = BaseCache(size='64KB')
95 # cache.hit_latency = 3
98 # The magic lies in the mapping of the Python attributes for SimObject
99 # classes to the actual SimObject parameter specifications. This
100 # allows parameter validity checking in the Python code. Continuing
101 # the example above, the statements "cache.blurfl=3" or
102 # "cache.assoc='hello'" would both result in runtime errors in Python,
103 # since the BaseCache object has no 'blurfl' parameter and the 'assoc'
104 # parameter requires an integer, respectively. This magic is done
105 # primarily by overriding the special __setattr__ method that controls
106 # assignment to object attributes.
108 # Once a set of Python objects have been instantiated in a hierarchy,
109 # calling 'instantiate(obj)' (where obj is the root of the hierarchy)
110 # will generate a .ini file.
112 #####################################################################
114 # list of all SimObject classes
117 # dict to look up SimObjects based on path
120 # The metaclass for SimObject. This class controls how new classes
121 # that derive from SimObject are instantiated, and provides inherited
122 # class behavior (just like a class controls how instances of that
123 # class are instantiated, and provides inherited instance behavior).
124 class MetaSimObject(type):
125 # Attributes that can be set only at initialization time
126 init_keywords
= { 'abstract' : types
.BooleanType
,
127 'cxx_namespace' : types
.StringType
,
128 'cxx_class' : types
.StringType
,
129 'cxx_type' : types
.StringType
,
130 'cxx_predecls' : types
.ListType
,
131 'swig_objdecls' : types
.ListType
,
132 'swig_predecls' : types
.ListType
,
133 'type' : types
.StringType
}
134 # Attributes that can be set any time
135 keywords
= { 'check' : types
.FunctionType
}
137 # __new__ is called before __init__, and is where the statements
138 # in the body of the class definition get loaded into the class's
139 # __dict__. We intercept this to filter out parameter & port assignments
140 # and only allow "private" attributes to be passed to the base
141 # __new__ (starting with underscore).
142 def __new__(mcls
, name
, bases
, dict):
143 assert name
not in allClasses
145 # Copy "private" attributes, functions, and classes to the
146 # official dict. Everything else goes in _init_dict to be
147 # filtered in __init__.
150 for key
,val
in dict.items():
151 if key
.startswith('_') or isinstance(val
, (types
.FunctionType
,
155 # must be a param/port setting
156 value_dict
[key
] = val
157 if 'abstract' not in value_dict
:
158 value_dict
['abstract'] = False
159 cls_dict
['_value_dict'] = value_dict
160 cls
= super(MetaSimObject
, mcls
).__new
__(mcls
, name
, bases
, cls_dict
)
161 if 'type' in value_dict
:
162 allClasses
[name
] = cls
165 # subclass initialization
166 def __init__(cls
, name
, bases
, dict):
167 # calls type.__init__()... I think that's a no-op, but leave
168 # it here just in case it's not.
169 super(MetaSimObject
, cls
).__init
__(name
, bases
, dict)
171 # initialize required attributes
173 # class-only attributes
174 cls
._params
= multidict() # param descriptions
175 cls
._ports
= multidict() # port descriptions
177 # class or instance attributes
178 cls
._values
= multidict() # param values
179 cls
._port
_refs
= multidict() # port ref objects
180 cls
._instantiated
= False # really instantiated, cloned, or subclassed
182 # We don't support multiple inheritance. If you want to, you
183 # must fix multidict to deal with it properly.
185 raise TypeError, "SimObjects do not support multiple inheritance"
189 # Set up general inheritance via multidicts. A subclass will
190 # inherit all its settings from the base class. The only time
191 # the following is not true is when we define the SimObject
192 # class itself (in which case the multidicts have no parent).
193 if isinstance(base
, MetaSimObject
):
194 cls
._params
.parent
= base
._params
195 cls
._ports
.parent
= base
._ports
196 cls
._values
.parent
= base
._values
197 cls
._port
_refs
.parent
= base
._port
_refs
198 # mark base as having been subclassed
199 base
._instantiated
= True
201 # default keyword values
202 if 'type' in cls
._value
_dict
:
203 _type
= cls
._value
_dict
['type']
204 if 'cxx_class' not in cls
._value
_dict
:
205 cls
._value
_dict
['cxx_class'] = _type
207 namespace
= cls
._value
_dict
.get('cxx_namespace', None)
209 _cxx_class
= cls
._value
_dict
['cxx_class']
210 if 'cxx_type' not in cls
._value
_dict
:
213 t
= '%s::%s' % (namespace
, t
)
214 cls
._value
_dict
['cxx_type'] = t
215 if 'cxx_predecls' not in cls
._value
_dict
:
216 # A forward class declaration is sufficient since we are
217 # just declaring a pointer.
218 decl
= 'class %s;' % _cxx_class
220 decl
= 'namespace %s { %s }' % (namespace
, decl
)
221 cls
._value
_dict
['cxx_predecls'] = [decl
]
223 if 'swig_predecls' not in cls
._value
_dict
:
224 # A forward class declaration is sufficient since we are
225 # just declaring a pointer.
226 cls
._value
_dict
['swig_predecls'] = \
227 cls
._value
_dict
['cxx_predecls']
229 if 'swig_objdecls' not in cls
._value
_dict
:
230 cls
._value
_dict
['swig_objdecls'] = []
232 # Now process the _value_dict items. They could be defining
233 # new (or overriding existing) parameters or ports, setting
234 # class keywords (e.g., 'abstract'), or setting parameter
235 # values or port bindings. The first 3 can only be set when
236 # the class is defined, so we handle them here. The others
237 # can be set later too, so just emulate that by calling
239 for key
,val
in cls
._value
_dict
.items():
241 if isinstance(val
, ParamDesc
):
242 cls
._new
_param
(key
, val
)
245 elif isinstance(val
, Port
):
246 cls
._new
_port
(key
, val
)
248 # init-time-only keywords
249 elif cls
.init_keywords
.has_key(key
):
250 cls
._set
_keyword
(key
, val
, cls
.init_keywords
[key
])
252 # default: use normal path (ends up in __setattr__)
254 setattr(cls
, key
, val
)
256 def _set_keyword(cls
, keyword
, val
, kwtype
):
257 if not isinstance(val
, kwtype
):
258 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
259 (keyword
, type(val
), kwtype
)
260 if isinstance(val
, types
.FunctionType
):
261 val
= classmethod(val
)
262 type.__setattr
__(cls
, keyword
, val
)
264 def _new_param(cls
, name
, pdesc
):
265 # each param desc should be uniquely assigned to one variable
266 assert(not hasattr(pdesc
, 'name'))
268 cls
._params
[name
] = pdesc
269 if hasattr(pdesc
, 'default'):
270 cls
._set
_param
(name
, pdesc
.default
, pdesc
)
272 def _set_param(cls
, name
, value
, param
):
273 assert(param
.name
== name
)
275 cls
._values
[name
] = param
.convert(value
)
277 msg
= "%s\nError setting param %s.%s to %s\n" % \
278 (e
, cls
.__name
__, name
, value
)
282 def _new_port(cls
, name
, port
):
283 # each port should be uniquely assigned to one variable
284 assert(not hasattr(port
, 'name'))
286 cls
._ports
[name
] = port
287 if hasattr(port
, 'default'):
288 cls
._cls
_get
_port
_ref
(name
).connect(port
.default
)
290 # same as _get_port_ref, effectively, but for classes
291 def _cls_get_port_ref(cls
, attr
):
292 # Return reference that can be assigned to another port
293 # via __setattr__. There is only ever one reference
294 # object per port, but we create them lazily here.
295 ref
= cls
._port
_refs
.get(attr
)
297 ref
= cls
._ports
[attr
].makeRef(cls
)
298 cls
._port
_refs
[attr
] = ref
301 # Set attribute (called on foo.attr = value when foo is an
302 # instance of class cls).
303 def __setattr__(cls
, attr
, value
):
304 # normal processing for private attributes
305 if attr
.startswith('_'):
306 type.__setattr
__(cls
, attr
, value
)
309 if cls
.keywords
.has_key(attr
):
310 cls
._set
_keyword
(attr
, value
, cls
.keywords
[attr
])
313 if cls
._ports
.has_key(attr
):
314 cls
._cls
_get
_port
_ref
(attr
).connect(value
)
317 if isSimObjectOrSequence(value
) and cls
._instantiated
:
318 raise RuntimeError, \
319 "cannot set SimObject parameter '%s' after\n" \
320 " class %s has been instantiated or subclassed" \
321 % (attr
, cls
.__name
__)
324 param
= cls
._params
.get(attr
)
326 cls
._set
_param
(attr
, value
, param
)
329 if isSimObjectOrSequence(value
):
330 # If RHS is a SimObject, it's an implicit child assignment.
331 # Classes don't have children, so we just put this object
332 # in _values; later, each instance will do a 'setattr(self,
333 # attr, _values[attr])' in SimObject.__init__ which will
334 # add this object as a child.
335 cls
._values
[attr
] = value
338 # no valid assignment... raise exception
339 raise AttributeError, \
340 "Class %s has no parameter \'%s\'" % (cls
.__name
__, attr
)
342 def __getattr__(cls
, attr
):
343 if cls
._values
.has_key(attr
):
344 return cls
._values
[attr
]
346 raise AttributeError, \
347 "object '%s' has no attribute '%s'" % (cls
.__name
__, attr
)
353 if str(cls
) == 'SimObject':
356 return cls
.__bases
__[0].type
359 code
= "#ifndef __PARAMS__%s\n" % cls
360 code
+= "#define __PARAMS__%s\n\n" % cls
362 # The 'dict' attribute restricts us to the params declared in
363 # the object itself, not including inherited params (which
364 # will also be inherited from the base class's param struct
366 params
= cls
._params
.local
.values()
368 ptypes
= [p
.ptype
for p
in params
]
370 print cls
, p
, p
.ptype_str
374 # get a list of lists of predeclaration lines
376 predecls
.extend(cls
.cxx_predecls
)
378 predecls
.extend(p
.cxx_predecls())
379 # remove redundant lines
382 if pd
not in predecls2
:
385 code
+= "\n".join(predecls2
)
388 base
= cls
.get_base()
390 code
+= '#include "params/%s.hh"\n\n' % base
393 if issubclass(ptype
, Enum
):
394 code
+= '#include "enums/%s.hh"\n' % ptype
.__name
__
397 # now generate the actual param struct
398 code
+= "struct %sParams" % cls
400 code
+= " : public %sParams" % base
403 code
+= " virtual ~%sParams() {}\n" % cls
404 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
405 if 'type' in cls
.__dict
__:
406 code
+= " %s create();\n" % cls
.cxx_type
407 decls
= [p
.cxx_decl() for p
in params
]
409 code
+= "".join([" %s\n" % d
for d
in decls
])
412 # close #ifndef __PARAMS__* guard
416 def cxx_type_decl(cls
):
417 base
= cls
.get_base()
421 code
+= '#include "%s_type.h"\n' % base
423 # now generate dummy code for inheritance
424 code
+= "struct %s" % cls
.cxx_class
426 code
+= " : public %s" % base
.cxx_class
432 base
= cls
.get_base()
434 code
= '%%module %s\n' % cls
437 code
+= '#include "params/%s.hh"\n' % cls
440 # The 'dict' attribute restricts us to the params declared in
441 # the object itself, not including inherited params (which
442 # will also be inherited from the base class's param struct
444 params
= cls
._params
.local
.values()
445 ptypes
= [p
.ptype
for p
in params
]
447 # get a list of lists of predeclaration lines
449 predecls
.extend([ p
.swig_predecls() for p
in params
])
451 predecls
= reduce(lambda x
,y
:x
+y
, predecls
, [])
452 # remove redundant lines
455 if pd
not in predecls2
:
458 code
+= "\n".join(predecls2
)
462 code
+= '%%import "params/%s.i"\n\n' % base
465 if issubclass(ptype
, Enum
):
466 code
+= '%%import "enums/%s.hh"\n' % ptype
.__name
__
469 code
+= '%%import "params/%s_type.hh"\n\n' % cls
470 code
+= '%%include "params/%s.hh"\n\n' % cls
474 # The SimObject class is the root of the special hierarchy. Most of
475 # the code in this class deals with the configuration hierarchy itself
476 # (parent/child node relationships).
477 class SimObject(object):
478 # Specify metaclass. Any class inheriting from SimObject will
479 # get this metaclass.
480 __metaclass__
= MetaSimObject
484 name
= Param
.String("Object name")
485 swig_objdecls
= [ '%include "python/swig/sim_object.i"' ]
487 # Initialize new instance. For objects with SimObject-valued
488 # children, we need to recursively clone the classes represented
489 # by those param values as well in a consistent "deep copy"-style
490 # fashion. That is, we want to make sure that each instance is
491 # cloned only once, and that if there are multiple references to
492 # the same original object, we end up with the corresponding
493 # cloned references all pointing to the same cloned instance.
494 def __init__(self
, **kwargs
):
495 ancestor
= kwargs
.get('_ancestor')
496 memo_dict
= kwargs
.get('_memo')
497 if memo_dict
is None:
498 # prepare to memoize any recursively instantiated objects
501 # memoize me now to avoid problems with recursive calls
502 memo_dict
[ancestor
] = self
505 ancestor
= self
.__class
__
506 ancestor
._instantiated
= True
508 # initialize required attributes
511 self
._ccObject
= None # pointer to C++ object
512 self
._ccParams
= None
513 self
._instantiated
= False # really "cloned"
515 # Inherit parameter values from class using multidict so
516 # individual value settings can be overridden.
517 self
._values
= multidict(ancestor
._values
)
518 # clone SimObject-valued parameters
519 for key
,val
in ancestor
._values
.iteritems():
521 setattr(self
, key
, val(_memo
=memo_dict
))
522 elif isSimObjectSequence(val
) and len(val
):
523 setattr(self
, key
, [ v(_memo
=memo_dict
) for v
in val
])
524 # clone port references. no need to use a multidict here
525 # since we will be creating new references for all ports.
527 for key
,val
in ancestor
._port
_refs
.iteritems():
528 self
._port
_refs
[key
] = val
.clone(self
, memo_dict
)
529 # apply attribute assignments from keyword args, if any
530 for key
,val
in kwargs
.iteritems():
531 setattr(self
, key
, val
)
533 # "Clone" the current instance by creating another instance of
534 # this instance's class, but that inherits its parameter values
535 # and port mappings from the current instance. If we're in a
536 # "deep copy" recursive clone, check the _memo dict to see if
537 # we've already cloned this instance.
538 def __call__(self
, **kwargs
):
539 memo_dict
= kwargs
.get('_memo')
540 if memo_dict
is None:
541 # no memo_dict: must be top-level clone operation.
542 # this is only allowed at the root of a hierarchy
544 raise RuntimeError, "attempt to clone object %s " \
545 "not at the root of a tree (parent = %s)" \
546 % (self
, self
._parent
)
547 # create a new dict and use that.
549 kwargs
['_memo'] = memo_dict
550 elif memo_dict
.has_key(self
):
551 # clone already done & memoized
552 return memo_dict
[self
]
553 return self
.__class
__(_ancestor
= self
, **kwargs
)
555 def _get_port_ref(self
, attr
):
556 # Return reference that can be assigned to another port
557 # via __setattr__. There is only ever one reference
558 # object per port, but we create them lazily here.
559 ref
= self
._port
_refs
.get(attr
)
561 ref
= self
._ports
[attr
].makeRef(self
)
562 self
._port
_refs
[attr
] = ref
565 def __getattr__(self
, attr
):
566 if self
._ports
.has_key(attr
):
567 return self
._get
_port
_ref
(attr
)
569 if self
._values
.has_key(attr
):
570 return self
._values
[attr
]
572 raise AttributeError, "object '%s' has no attribute '%s'" \
573 % (self
.__class
__.__name
__, attr
)
575 # Set attribute (called on foo.attr = value when foo is an
576 # instance of class cls).
577 def __setattr__(self
, attr
, value
):
578 # normal processing for private attributes
579 if attr
.startswith('_'):
580 object.__setattr
__(self
, attr
, value
)
583 if self
._ports
.has_key(attr
):
584 # set up port connection
585 self
._get
_port
_ref
(attr
).connect(value
)
588 if isSimObjectOrSequence(value
) and self
._instantiated
:
589 raise RuntimeError, \
590 "cannot set SimObject parameter '%s' after\n" \
591 " instance been cloned %s" % (attr
, `self`
)
593 # must be SimObject param
594 param
= self
._params
.get(attr
)
597 value
= param
.convert(value
)
599 msg
= "%s\nError setting param %s.%s to %s\n" % \
600 (e
, self
.__class
__.__name
__, attr
, value
)
603 self
._set
_child
(attr
, value
)
606 if isSimObjectOrSequence(value
):
607 self
._set
_child
(attr
, value
)
610 # no valid assignment... raise exception
611 raise AttributeError, "Class %s has no parameter %s" \
612 % (self
.__class
__.__name
__, attr
)
615 # this hack allows tacking a '[0]' onto parameters that may or may
616 # not be vectors, and always getting the first element (e.g. cpus)
617 def __getitem__(self
, key
):
620 raise TypeError, "Non-zero index '%s' to SimObject" % key
622 # clear out children with given name, even if it's a vector
623 def clear_child(self
, name
):
624 if not self
._children
.has_key(name
):
626 child
= self
._children
[name
]
627 if isinstance(child
, SimObjVector
):
628 for i
in xrange(len(child
)):
629 del self
._children
["s%d" % (name
, i
)]
630 del self
._children
[name
]
632 def add_child(self
, name
, value
):
633 self
._children
[name
] = value
635 def _maybe_set_parent(self
, parent
, name
):
637 self
._parent
= parent
639 parent
.add_child(name
, self
)
641 def _set_child(self
, attr
, value
):
642 # if RHS is a SimObject, it's an implicit child assignment
643 # clear out old child with this name, if any
644 self
.clear_child(attr
)
646 if isSimObject(value
):
647 value
._maybe
_set
_parent
(self
, attr
)
648 elif isSimObjectSequence(value
):
649 value
= SimObjVector(value
)
651 value
[0]._maybe
_set
_parent
(self
, attr
)
653 for i
,v
in enumerate(value
):
654 v
._maybe
_set
_parent
(self
, "%s%d" % (attr
, i
))
656 self
._values
[attr
] = value
661 ppath
= self
._parent
.path()
664 return ppath
+ "." + self
._name
672 def find_any(self
, ptype
):
673 if isinstance(self
, ptype
):
677 for child
in self
._children
.itervalues():
678 if isinstance(child
, ptype
):
679 if found_obj
!= None and child
!= found_obj
:
680 raise AttributeError, \
681 'parent.any matched more than one: %s %s' % \
682 (found_obj
.path
, child
.path
)
685 for pname
,pdesc
in self
._params
.iteritems():
686 if issubclass(pdesc
.ptype
, ptype
):
687 match_obj
= self
._values
[pname
]
688 if found_obj
!= None and found_obj
!= match_obj
:
689 raise AttributeError, \
690 'parent.any matched more than one: %s' % obj
.path
691 found_obj
= match_obj
692 return found_obj
, found_obj
!= None
694 def unproxy(self
, base
):
697 def unproxy_all(self
):
698 for param
in self
._params
.iterkeys():
699 value
= self
._values
.get(param
)
700 if value
!= None and proxy
.isproxy(value
):
702 value
= value
.unproxy(self
)
704 print "Error in unproxying param '%s' of %s" % \
707 setattr(self
, param
, value
)
709 # Unproxy ports in sorted order so that 'append' operations on
710 # vector ports are done in a deterministic fashion.
711 port_names
= self
._ports
.keys()
713 for port_name
in port_names
:
714 port
= self
._port
_refs
.get(port_name
)
718 # Unproxy children in sorted order for determinism also.
719 child_names
= self
._children
.keys()
721 for child
in child_names
:
722 self
._children
[child
].unproxy_all()
724 def print_ini(self
, ini_file
):
725 print >>ini_file
, '[' + self
.path() + ']' # .ini section header
727 instanceDict
[self
.path()] = self
729 if hasattr(self
, 'type'):
730 print >>ini_file
, 'type=%s' % self
.type
732 child_names
= self
._children
.keys()
735 print >>ini_file
, 'children=%s' % ' '.join(child_names
)
737 param_names
= self
._params
.keys()
739 for param
in param_names
:
740 value
= self
._values
.get(param
)
742 print >>ini_file
, '%s=%s' % (param
,
743 self
._values
[param
].ini_str())
745 port_names
= self
._ports
.keys()
747 for port_name
in port_names
:
748 port
= self
._port
_refs
.get(port_name
, None)
750 print >>ini_file
, '%s=%s' % (port_name
, port
.ini_str())
752 print >>ini_file
# blank line between objects
754 for child
in child_names
:
755 self
._children
[child
].print_ini(ini_file
)
757 def getCCParams(self
):
759 return self
._ccParams
761 cc_params_struct
= getattr(m5
.objects
.params
, '%sParams' % self
.type)
762 cc_params
= cc_params_struct()
763 cc_params
.object = self
764 cc_params
.name
= str(self
)
766 param_names
= self
._params
.keys()
768 for param
in param_names
:
769 value
= self
._values
.get(param
)
773 value
= value
.getValue()
774 if isinstance(self
._params
[param
], VectorParamDesc
):
775 assert isinstance(value
, list)
776 vec
= getattr(cc_params
, param
)
781 setattr(cc_params
, param
, value
)
783 port_names
= self
._ports
.keys()
785 for port_name
in port_names
:
786 port
= self
._port
_refs
.get(port_name
, None)
788 setattr(cc_params
, port_name
, port
)
789 self
._ccParams
= cc_params
790 return self
._ccParams
792 # Get C++ object corresponding to this object, calling C++ if
793 # necessary to construct it. Does *not* recursively create
795 def getCCObject(self
):
796 if not self
._ccObject
:
797 # Cycles in the configuration heirarchy are not supported. This
798 # will catch the resulting recursion and stop.
800 params
= self
.getCCParams()
801 self
._ccObject
= params
.create()
802 elif self
._ccObject
== -1:
803 raise RuntimeError, "%s: Cycle found in configuration heirarchy." \
805 return self
._ccObject
807 # Call C++ to create C++ object corresponding to this object and
808 # (recursively) all its children
809 def createCCObject(self
):
811 self
.getCCObject() # force creation
812 for child
in self
._children
.itervalues():
813 child
.createCCObject()
816 return self
.getCCObject()
818 # Create C++ port connections corresponding to the connections in
819 # _port_refs (& recursively for all children)
820 def connectPorts(self
):
821 for portRef
in self
._port
_refs
.itervalues():
823 for child
in self
._children
.itervalues():
826 def startDrain(self
, drain_event
, recursive
):
828 if isinstance(self
, SimObject
):
829 count
+= self
._ccObject
.drain(drain_event
)
831 for child
in self
._children
.itervalues():
832 count
+= child
.startDrain(drain_event
, True)
836 if isinstance(self
, SimObject
):
837 self
._ccObject
.resume()
838 for child
in self
._children
.itervalues():
841 def getMemoryMode(self
):
842 if not isinstance(self
, m5
.objects
.System
):
845 return self
._ccObject
.getMemoryMode()
847 def changeTiming(self
, mode
):
848 if isinstance(self
, m5
.objects
.System
):
849 # i don't know if there's a better way to do this - calling
850 # setMemoryMode directly from self._ccObject results in calling
851 # SimObject::setMemoryMode, not the System::setMemoryMode
852 self
._ccObject
.setMemoryMode(mode
)
853 for child
in self
._children
.itervalues():
854 child
.changeTiming(mode
)
856 def takeOverFrom(self
, old_cpu
):
857 self
._ccObject
.takeOverFrom(old_cpu
._ccObject
)
859 # generate output file for 'dot' to display as a pretty graph.
860 # this code is currently broken.
861 def outputDot(self
, dot
):
862 label
= "{%s|" % self
.path
863 if isSimObject(self
.realtype
):
864 label
+= '%s|' % self
.type
867 # instantiate children in same order they were added for
868 # backward compatibility (else we can end up with cpu1
870 for c
in self
.children
:
871 dot
.add_edge(pydot
.Edge(self
.path
,c
.path
, style
="bold"))
874 for param
in self
.params
:
876 if param
.value
is None:
877 raise AttributeError, 'Parameter with no value'
880 string
= param
.string(value
)
882 msg
= 'exception in %s:%s\n%s' % (self
.name
, param
.name
, e
)
886 if isSimObject(param
.ptype
) and string
!= "Null":
887 simobjs
.append(string
)
889 label
+= '%s = %s\\n' % (param
.name
, string
)
892 label
+= "|<%s> %s" % (so
, so
)
893 dot
.add_edge(pydot
.Edge("%s:%s" % (self
.path
, so
), so
,
896 dot
.add_node(pydot
.Node(self
.path
,shape
="Mrecord",label
=label
))
898 # recursively dump out children
899 for c
in self
.children
:
902 # Function to provide to C++ so it can look up instances based on paths
903 def resolveSimObject(name
):
904 obj
= instanceDict
[name
]
905 return obj
.getCCObject()
907 # __all__ defines the list of symbols that get exported when
908 # 'from config import *' is invoked. Try to keep this reasonably
909 # short to avoid polluting other namespaces.
910 __all__
= [ 'SimObject' ]