ab0c3954310273ac4bbbeff830f4dc5758955dc9
1 # Copyright (c) 2004-2006 The Regents of The University of Michigan
2 # Copyright (c) 2010 Advanced Micro Devices, Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # Authors: Steve Reinhardt
32 from types
import FunctionType
42 # Have to import params up top since Param is referenced on initial
43 # load (when SimObject class references Param to create a class
44 # variable, the 'name' param)...
45 from m5
.params
import *
46 # There are a few things we need that aren't in params.__all__ since
47 # normal users don't need them
48 from m5
.params
import ParamDesc
, VectorParamDesc
, \
49 isNullPointer
, SimObjectVector
51 from m5
.proxy
import *
52 from m5
.proxy
import isproxy
54 #####################################################################
56 # M5 Python Configuration Utility
58 # The basic idea is to write simple Python programs that build Python
59 # objects corresponding to M5 SimObjects for the desired simulation
60 # configuration. For now, the Python emits a .ini file that can be
61 # parsed by M5. In the future, some tighter integration between M5
62 # and the Python interpreter may allow bypassing the .ini file.
64 # Each SimObject class in M5 is represented by a Python class with the
65 # same name. The Python inheritance tree mirrors the M5 C++ tree
66 # (e.g., SimpleCPU derives from BaseCPU in both cases, and all
67 # SimObjects inherit from a single SimObject base class). To specify
68 # an instance of an M5 SimObject in a configuration, the user simply
69 # instantiates the corresponding Python object. The parameters for
70 # that SimObject are given by assigning to attributes of the Python
71 # object, either using keyword assignment in the constructor or in
72 # separate assignment statements. For example:
74 # cache = BaseCache(size='64KB')
75 # cache.hit_latency = 3
78 # The magic lies in the mapping of the Python attributes for SimObject
79 # classes to the actual SimObject parameter specifications. This
80 # allows parameter validity checking in the Python code. Continuing
81 # the example above, the statements "cache.blurfl=3" or
82 # "cache.assoc='hello'" would both result in runtime errors in Python,
83 # since the BaseCache object has no 'blurfl' parameter and the 'assoc'
84 # parameter requires an integer, respectively. This magic is done
85 # primarily by overriding the special __setattr__ method that controls
86 # assignment to object attributes.
88 # Once a set of Python objects have been instantiated in a hierarchy,
89 # calling 'instantiate(obj)' (where obj is the root of the hierarchy)
90 # will generate a .ini file.
92 #####################################################################
94 # list of all SimObject classes
97 # dict to look up SimObjects based on path
100 # The metaclass for SimObject. This class controls how new classes
101 # that derive from SimObject are instantiated, and provides inherited
102 # class behavior (just like a class controls how instances of that
103 # class are instantiated, and provides inherited instance behavior).
104 class MetaSimObject(type):
105 # Attributes that can be set only at initialization time
106 init_keywords
= { 'abstract' : bool,
109 'cxx_predecls' : list,
110 'swig_objdecls' : list,
111 'swig_predecls' : list,
113 # Attributes that can be set any time
114 keywords
= { 'check' : FunctionType
}
116 # __new__ is called before __init__, and is where the statements
117 # in the body of the class definition get loaded into the class's
118 # __dict__. We intercept this to filter out parameter & port assignments
119 # and only allow "private" attributes to be passed to the base
120 # __new__ (starting with underscore).
121 def __new__(mcls
, name
, bases
, dict):
122 assert name
not in allClasses
, "SimObject %s already present" % name
124 # Copy "private" attributes, functions, and classes to the
125 # official dict. Everything else goes in _init_dict to be
126 # filtered in __init__.
129 for key
,val
in dict.items():
130 if key
.startswith('_') or isinstance(val
, (FunctionType
,
135 # must be a param/port setting
136 value_dict
[key
] = val
137 if 'abstract' not in value_dict
:
138 value_dict
['abstract'] = False
139 cls_dict
['_value_dict'] = value_dict
140 cls
= super(MetaSimObject
, mcls
).__new
__(mcls
, name
, bases
, cls_dict
)
141 if 'type' in value_dict
:
142 allClasses
[name
] = cls
145 # subclass initialization
146 def __init__(cls
, name
, bases
, dict):
147 # calls type.__init__()... I think that's a no-op, but leave
148 # it here just in case it's not.
149 super(MetaSimObject
, cls
).__init
__(name
, bases
, dict)
151 # initialize required attributes
153 # class-only attributes
154 cls
._params
= multidict() # param descriptions
155 cls
._ports
= multidict() # port descriptions
157 # class or instance attributes
158 cls
._values
= multidict() # param values
159 cls
._children
= multidict() # SimObject children
160 cls
._port
_refs
= multidict() # port ref objects
161 cls
._instantiated
= False # really instantiated, cloned, or subclassed
163 # We don't support multiple inheritance. If you want to, you
164 # must fix multidict to deal with it properly.
166 raise TypeError, "SimObjects do not support multiple inheritance"
170 # Set up general inheritance via multidicts. A subclass will
171 # inherit all its settings from the base class. The only time
172 # the following is not true is when we define the SimObject
173 # class itself (in which case the multidicts have no parent).
174 if isinstance(base
, MetaSimObject
):
176 cls
._params
.parent
= base
._params
177 cls
._ports
.parent
= base
._ports
178 cls
._values
.parent
= base
._values
179 cls
._children
.parent
= base
._children
180 cls
._port
_refs
.parent
= base
._port
_refs
181 # mark base as having been subclassed
182 base
._instantiated
= True
186 # default keyword values
187 if 'type' in cls
._value
_dict
:
188 if 'cxx_class' not in cls
._value
_dict
:
189 cls
._value
_dict
['cxx_class'] = cls
._value
_dict
['type']
191 cls
._value
_dict
['cxx_type'] = '%s *' % cls
._value
_dict
['cxx_class']
193 if 'cxx_predecls' not in cls
._value
_dict
:
194 # A forward class declaration is sufficient since we are
195 # just declaring a pointer.
196 class_path
= cls
._value
_dict
['cxx_class'].split('::')
198 decl
= 'class %s;' % class_path
[0]
199 for ns
in class_path
[1:]:
200 decl
= 'namespace %s { %s }' % (ns
, decl
)
201 cls
._value
_dict
['cxx_predecls'] = [decl
]
203 if 'swig_predecls' not in cls
._value
_dict
:
204 # A forward class declaration is sufficient since we are
205 # just declaring a pointer.
206 cls
._value
_dict
['swig_predecls'] = \
207 cls
._value
_dict
['cxx_predecls']
209 if 'swig_objdecls' not in cls
._value
_dict
:
210 cls
._value
_dict
['swig_objdecls'] = []
212 # Now process the _value_dict items. They could be defining
213 # new (or overriding existing) parameters or ports, setting
214 # class keywords (e.g., 'abstract'), or setting parameter
215 # values or port bindings. The first 3 can only be set when
216 # the class is defined, so we handle them here. The others
217 # can be set later too, so just emulate that by calling
219 for key
,val
in cls
._value
_dict
.items():
221 if isinstance(val
, ParamDesc
):
222 cls
._new
_param
(key
, val
)
225 elif isinstance(val
, Port
):
226 cls
._new
_port
(key
, val
)
228 # init-time-only keywords
229 elif cls
.init_keywords
.has_key(key
):
230 cls
._set
_keyword
(key
, val
, cls
.init_keywords
[key
])
232 # default: use normal path (ends up in __setattr__)
234 setattr(cls
, key
, val
)
236 def _set_keyword(cls
, keyword
, val
, kwtype
):
237 if not isinstance(val
, kwtype
):
238 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
239 (keyword
, type(val
), kwtype
)
240 if isinstance(val
, FunctionType
):
241 val
= classmethod(val
)
242 type.__setattr
__(cls
, keyword
, val
)
244 def _new_param(cls
, name
, pdesc
):
245 # each param desc should be uniquely assigned to one variable
246 assert(not hasattr(pdesc
, 'name'))
248 cls
._params
[name
] = pdesc
249 if hasattr(pdesc
, 'default'):
250 cls
._set
_param
(name
, pdesc
.default
, pdesc
)
252 def _set_param(cls
, name
, value
, param
):
253 assert(param
.name
== name
)
255 cls
._values
[name
] = param
.convert(value
)
257 msg
= "%s\nError setting param %s.%s to %s\n" % \
258 (e
, cls
.__name
__, name
, value
)
262 def _new_port(cls
, name
, port
):
263 # each port should be uniquely assigned to one variable
264 assert(not hasattr(port
, 'name'))
266 cls
._ports
[name
] = port
267 if hasattr(port
, 'default'):
268 cls
._cls
_get
_port
_ref
(name
).connect(port
.default
)
270 # same as _get_port_ref, effectively, but for classes
271 def _cls_get_port_ref(cls
, attr
):
272 # Return reference that can be assigned to another port
273 # via __setattr__. There is only ever one reference
274 # object per port, but we create them lazily here.
275 ref
= cls
._port
_refs
.get(attr
)
277 ref
= cls
._ports
[attr
].makeRef(cls
)
278 cls
._port
_refs
[attr
] = ref
281 # Set attribute (called on foo.attr = value when foo is an
282 # instance of class cls).
283 def __setattr__(cls
, attr
, value
):
284 # normal processing for private attributes
285 if attr
.startswith('_'):
286 type.__setattr
__(cls
, attr
, value
)
289 if cls
.keywords
.has_key(attr
):
290 cls
._set
_keyword
(attr
, value
, cls
.keywords
[attr
])
293 if cls
._ports
.has_key(attr
):
294 cls
._cls
_get
_port
_ref
(attr
).connect(value
)
297 if isSimObjectOrSequence(value
) and cls
._instantiated
:
298 raise RuntimeError, \
299 "cannot set SimObject parameter '%s' after\n" \
300 " class %s has been instantiated or subclassed" \
301 % (attr
, cls
.__name
__)
304 param
= cls
._params
.get(attr
)
306 cls
._set
_param
(attr
, value
, param
)
309 if isSimObjectOrSequence(value
):
310 # If RHS is a SimObject, it's an implicit child assignment.
311 cls
._children
[attr
] = coerceSimObjectOrVector(value
)
314 # no valid assignment... raise exception
315 raise AttributeError, \
316 "Class %s has no parameter \'%s\'" % (cls
.__name
__, attr
)
318 def __getattr__(cls
, attr
):
319 if cls
._values
.has_key(attr
):
320 return cls
._values
[attr
]
322 if cls
._children
.has_key(attr
):
323 return cls
._children
[attr
]
325 raise AttributeError, \
326 "object '%s' has no attribute '%s'" % (cls
.__name
__, attr
)
332 code
= "#ifndef __PARAMS__%s\n" % cls
333 code
+= "#define __PARAMS__%s\n\n" % cls
335 # The 'dict' attribute restricts us to the params declared in
336 # the object itself, not including inherited params (which
337 # will also be inherited from the base class's param struct
339 params
= cls
._params
.local
.values()
341 ptypes
= [p
.ptype
for p
in params
]
343 print cls
, p
, p
.ptype_str
347 # get a list of lists of predeclaration lines
349 predecls
.extend(cls
.cxx_predecls
)
351 predecls
.extend(p
.cxx_predecls())
352 # remove redundant lines
355 if pd
not in predecls2
:
358 code
+= "\n".join(predecls2
)
362 code
+= '#include "params/%s.hh"\n\n' % cls
._base
.type
365 if issubclass(ptype
, Enum
):
366 code
+= '#include "enums/%s.hh"\n' % ptype
.__name
__
369 code
+= cls
.cxx_struct(cls
._base
, params
)
371 # close #ifndef __PARAMS__* guard
375 def cxx_struct(cls
, base
, params
):
377 return '#include "sim/sim_object_params.hh"\n'
379 # now generate the actual param struct
380 code
= "struct %sParams" % cls
382 code
+= " : public %sParams" % base
.type
384 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
385 if 'type' in cls
.__dict
__:
386 code
+= " %s create();\n" % cls
.cxx_type
387 decls
= [p
.cxx_decl() for p
in params
]
389 code
+= "".join([" %s\n" % d
for d
in decls
])
395 code
= '%%module %s\n' % cls
398 code
+= '#include "params/%s.hh"\n' % cls
401 # The 'dict' attribute restricts us to the params declared in
402 # the object itself, not including inherited params (which
403 # will also be inherited from the base class's param struct
405 params
= cls
._params
.local
.values()
406 ptypes
= [p
.ptype
for p
in params
]
408 # get a list of lists of predeclaration lines
410 predecls
.extend([ p
.swig_predecls() for p
in params
])
412 predecls
= reduce(lambda x
,y
:x
+y
, predecls
, [])
413 # remove redundant lines
416 if pd
not in predecls2
:
419 code
+= "\n".join(predecls2
)
423 code
+= '%%import "params/%s.i"\n\n' % cls
._base
.type
426 if issubclass(ptype
, Enum
):
427 code
+= '%%import "enums/%s.hh"\n' % ptype
.__name
__
430 code
+= '%%import "params/%s_type.hh"\n\n' % cls
431 code
+= '%%include "params/%s.hh"\n\n' % cls
435 # The SimObject class is the root of the special hierarchy. Most of
436 # the code in this class deals with the configuration hierarchy itself
437 # (parent/child node relationships).
438 class SimObject(object):
439 # Specify metaclass. Any class inheriting from SimObject will
440 # get this metaclass.
441 __metaclass__
= MetaSimObject
445 swig_objdecls
= [ '%include "python/swig/sim_object.i"' ]
447 # Initialize new instance. For objects with SimObject-valued
448 # children, we need to recursively clone the classes represented
449 # by those param values as well in a consistent "deep copy"-style
450 # fashion. That is, we want to make sure that each instance is
451 # cloned only once, and that if there are multiple references to
452 # the same original object, we end up with the corresponding
453 # cloned references all pointing to the same cloned instance.
454 def __init__(self
, **kwargs
):
455 ancestor
= kwargs
.get('_ancestor')
456 memo_dict
= kwargs
.get('_memo')
457 if memo_dict
is None:
458 # prepare to memoize any recursively instantiated objects
461 # memoize me now to avoid problems with recursive calls
462 memo_dict
[ancestor
] = self
465 ancestor
= self
.__class
__
466 ancestor
._instantiated
= True
468 # initialize required attributes
471 self
._ccObject
= None # pointer to C++ object
472 self
._ccParams
= None
473 self
._instantiated
= False # really "cloned"
475 # Inherit parameter values from class using multidict so
476 # individual value settings can be overridden but we still
477 # inherit late changes to non-overridden class values.
478 self
._values
= multidict(ancestor
._values
)
479 # clone SimObject-valued parameters
480 for key
,val
in ancestor
._values
.iteritems():
481 val
= tryAsSimObjectOrVector(val
)
483 self
._values
[key
] = val(_memo
=memo_dict
)
485 # Clone children specified at class level. No need for a
486 # multidict here since we will be cloning everything.
488 for key
,val
in ancestor
._children
.iteritems():
489 self
.add_child(key
, val(_memo
=memo_dict
))
491 # clone port references. no need to use a multidict here
492 # since we will be creating new references for all ports.
494 for key
,val
in ancestor
._port
_refs
.iteritems():
495 self
._port
_refs
[key
] = val
.clone(self
, memo_dict
)
496 # apply attribute assignments from keyword args, if any
497 for key
,val
in kwargs
.iteritems():
498 setattr(self
, key
, val
)
500 # "Clone" the current instance by creating another instance of
501 # this instance's class, but that inherits its parameter values
502 # and port mappings from the current instance. If we're in a
503 # "deep copy" recursive clone, check the _memo dict to see if
504 # we've already cloned this instance.
505 def __call__(self
, **kwargs
):
506 memo_dict
= kwargs
.get('_memo')
507 if memo_dict
is None:
508 # no memo_dict: must be top-level clone operation.
509 # this is only allowed at the root of a hierarchy
511 raise RuntimeError, "attempt to clone object %s " \
512 "not at the root of a tree (parent = %s)" \
513 % (self
, self
._parent
)
514 # create a new dict and use that.
516 kwargs
['_memo'] = memo_dict
517 elif memo_dict
.has_key(self
):
518 # clone already done & memoized
519 return memo_dict
[self
]
520 return self
.__class
__(_ancestor
= self
, **kwargs
)
522 def _get_port_ref(self
, attr
):
523 # Return reference that can be assigned to another port
524 # via __setattr__. There is only ever one reference
525 # object per port, but we create them lazily here.
526 ref
= self
._port
_refs
.get(attr
)
528 ref
= self
._ports
[attr
].makeRef(self
)
529 self
._port
_refs
[attr
] = ref
532 def __getattr__(self
, attr
):
533 if self
._ports
.has_key(attr
):
534 return self
._get
_port
_ref
(attr
)
536 if self
._values
.has_key(attr
):
537 return self
._values
[attr
]
539 if self
._children
.has_key(attr
):
540 return self
._children
[attr
]
542 # If the attribute exists on the C++ object, transparently
543 # forward the reference there. This is typically used for
544 # SWIG-wrapped methods such as init(), regStats(),
545 # regFormulas(), resetStats(), startup(), drain(), and
547 if self
._ccObject
and hasattr(self
._ccObject
, attr
):
548 return getattr(self
._ccObject
, attr
)
550 raise AttributeError, "object '%s' has no attribute '%s'" \
551 % (self
.__class
__.__name
__, attr
)
553 # Set attribute (called on foo.attr = value when foo is an
554 # instance of class cls).
555 def __setattr__(self
, attr
, value
):
556 # normal processing for private attributes
557 if attr
.startswith('_'):
558 object.__setattr
__(self
, attr
, value
)
561 if self
._ports
.has_key(attr
):
562 # set up port connection
563 self
._get
_port
_ref
(attr
).connect(value
)
566 if isSimObjectOrSequence(value
) and self
._instantiated
:
567 raise RuntimeError, \
568 "cannot set SimObject parameter '%s' after\n" \
569 " instance been cloned %s" % (attr
, `self`
)
571 param
= self
._params
.get(attr
)
574 value
= param
.convert(value
)
576 msg
= "%s\nError setting param %s.%s to %s\n" % \
577 (e
, self
.__class
__.__name
__, attr
, value
)
580 self
._values
[attr
] = value
583 # if RHS is a SimObject, it's an implicit child assignment
584 if isSimObjectOrSequence(value
):
585 self
.add_child(attr
, value
)
588 # no valid assignment... raise exception
589 raise AttributeError, "Class %s has no parameter %s" \
590 % (self
.__class
__.__name
__, attr
)
593 # this hack allows tacking a '[0]' onto parameters that may or may
594 # not be vectors, and always getting the first element (e.g. cpus)
595 def __getitem__(self
, key
):
598 raise TypeError, "Non-zero index '%s' to SimObject" % key
600 # Also implemented by SimObjectVector
601 def clear_parent(self
, old_parent
):
602 assert self
._parent
is old_parent
605 # Also implemented by SimObjectVector
606 def set_parent(self
, parent
, name
):
607 self
._parent
= parent
610 # Also implemented by SimObjectVector
614 # use this rather than directly accessing _parent for symmetry
615 # with SimObjectVector
616 def get_parent(self
):
619 # clear out child with given name
620 def clear_child(self
, name
):
621 child
= self
._children
[name
]
622 child
.clear_parent(self
)
623 del self
._children
[name
]
625 # Add a new child to this object.
626 def add_child(self
, name
, child
):
627 child
= coerceSimObjectOrVector(child
)
628 if child
.get_parent():
629 raise RuntimeError, \
630 "add_child('%s'): child '%s' already has parent '%s'" % \
631 (name
, child
._name
, child
._parent
)
632 if self
._children
.has_key(name
):
634 child
.set_parent(self
, name
)
635 self
._children
[name
] = child
637 # Take SimObject-valued parameters that haven't been explicitly
638 # assigned as children and make them children of the object that
639 # they were assigned to as a parameter value. This guarantees
640 # that when we instantiate all the parameter objects we're still
641 # inside the configuration hierarchy.
642 def adoptOrphanParams(self
):
643 for key
,val
in self
._values
.iteritems():
644 if not isSimObjectVector(val
) and isSimObjectSequence(val
):
645 # need to convert raw SimObject sequences to
646 # SimObjectVector class so we can call get_parent()
647 val
= SimObjectVector(val
)
648 self
._values
[key
] = val
649 if isSimObjectOrVector(val
) and not val
.get_parent():
650 self
.add_child(key
, val
)
655 ppath
= self
._parent
.path()
658 return ppath
+ "." + self
._name
666 def find_any(self
, ptype
):
667 if isinstance(self
, ptype
):
671 for child
in self
._children
.itervalues():
672 if isinstance(child
, ptype
):
673 if found_obj
!= None and child
!= found_obj
:
674 raise AttributeError, \
675 'parent.any matched more than one: %s %s' % \
676 (found_obj
.path
, child
.path
)
679 for pname
,pdesc
in self
._params
.iteritems():
680 if issubclass(pdesc
.ptype
, ptype
):
681 match_obj
= self
._values
[pname
]
682 if found_obj
!= None and found_obj
!= match_obj
:
683 raise AttributeError, \
684 'parent.any matched more than one: %s and %s' % (found_obj
.path
, match_obj
.path
)
685 found_obj
= match_obj
686 return found_obj
, found_obj
!= None
688 def unproxy(self
, base
):
691 def unproxyParams(self
):
692 for param
in self
._params
.iterkeys():
693 value
= self
._values
.get(param
)
694 if value
!= None and isproxy(value
):
696 value
= value
.unproxy(self
)
698 print "Error in unproxying param '%s' of %s" % \
701 setattr(self
, param
, value
)
703 # Unproxy ports in sorted order so that 'append' operations on
704 # vector ports are done in a deterministic fashion.
705 port_names
= self
._ports
.keys()
707 for port_name
in port_names
:
708 port
= self
._port
_refs
.get(port_name
)
712 def print_ini(self
, ini_file
):
713 print >>ini_file
, '[' + self
.path() + ']' # .ini section header
715 instanceDict
[self
.path()] = self
717 if hasattr(self
, 'type'):
718 print >>ini_file
, 'type=%s' % self
.type
720 child_names
= self
._children
.keys()
723 print >>ini_file
, 'children=%s' % \
724 ' '.join(self
._children
[n
].get_name() for n
in child_names
)
726 param_names
= self
._params
.keys()
728 for param
in param_names
:
729 value
= self
._values
.get(param
)
731 print >>ini_file
, '%s=%s' % (param
,
732 self
._values
[param
].ini_str())
734 port_names
= self
._ports
.keys()
736 for port_name
in port_names
:
737 port
= self
._port
_refs
.get(port_name
, None)
739 print >>ini_file
, '%s=%s' % (port_name
, port
.ini_str())
741 print >>ini_file
# blank line between objects
743 def getCCParams(self
):
745 return self
._ccParams
747 cc_params_struct
= getattr(m5
.objects
.params
, '%sParams' % self
.type)
748 cc_params
= cc_params_struct()
749 cc_params
.pyobj
= self
750 cc_params
.name
= str(self
)
752 param_names
= self
._params
.keys()
754 for param
in param_names
:
755 value
= self
._values
.get(param
)
757 fatal("%s.%s without default or user set value",
760 value
= value
.getValue()
761 if isinstance(self
._params
[param
], VectorParamDesc
):
762 assert isinstance(value
, list)
763 vec
= getattr(cc_params
, param
)
768 setattr(cc_params
, param
, value
)
770 port_names
= self
._ports
.keys()
772 for port_name
in port_names
:
773 port
= self
._port
_refs
.get(port_name
, None)
775 setattr(cc_params
, port_name
, port
)
776 self
._ccParams
= cc_params
777 return self
._ccParams
779 # Get C++ object corresponding to this object, calling C++ if
780 # necessary to construct it. Does *not* recursively create
782 def getCCObject(self
):
783 if not self
._ccObject
:
784 # Make sure this object is in the configuration hierarchy
785 if not self
._parent
and not isRoot(self
):
786 raise RuntimeError, "Attempt to instantiate orphan node"
787 # Cycles in the configuration hierarchy are not supported. This
788 # will catch the resulting recursion and stop.
790 params
= self
.getCCParams()
791 self
._ccObject
= params
.create()
792 elif self
._ccObject
== -1:
793 raise RuntimeError, "%s: Cycle found in configuration hierarchy." \
795 return self
._ccObject
797 def descendants(self
):
799 for child
in self
._children
.itervalues():
800 for obj
in child
.descendants():
803 # Call C++ to create C++ object corresponding to this object
804 def createCCObject(self
):
806 self
.getCCObject() # force creation
809 return self
.getCCObject()
811 # Create C++ port connections corresponding to the connections in
813 def connectPorts(self
):
814 for portRef
in self
._port
_refs
.itervalues():
817 def getMemoryMode(self
):
818 if not isinstance(self
, m5
.objects
.System
):
821 return self
._ccObject
.getMemoryMode()
823 def changeTiming(self
, mode
):
824 if isinstance(self
, m5
.objects
.System
):
825 # i don't know if there's a better way to do this - calling
826 # setMemoryMode directly from self._ccObject results in calling
827 # SimObject::setMemoryMode, not the System::setMemoryMode
828 self
._ccObject
.setMemoryMode(mode
)
830 def takeOverFrom(self
, old_cpu
):
831 self
._ccObject
.takeOverFrom(old_cpu
._ccObject
)
833 # generate output file for 'dot' to display as a pretty graph.
834 # this code is currently broken.
835 def outputDot(self
, dot
):
836 label
= "{%s|" % self
.path
837 if isSimObject(self
.realtype
):
838 label
+= '%s|' % self
.type
841 # instantiate children in same order they were added for
842 # backward compatibility (else we can end up with cpu1
844 for c
in self
.children
:
845 dot
.add_edge(pydot
.Edge(self
.path
,c
.path
, style
="bold"))
848 for param
in self
.params
:
850 if param
.value
is None:
851 raise AttributeError, 'Parameter with no value'
854 string
= param
.string(value
)
856 msg
= 'exception in %s:%s\n%s' % (self
.name
, param
.name
, e
)
860 if isSimObject(param
.ptype
) and string
!= "Null":
861 simobjs
.append(string
)
863 label
+= '%s = %s\\n' % (param
.name
, string
)
866 label
+= "|<%s> %s" % (so
, so
)
867 dot
.add_edge(pydot
.Edge("%s:%s" % (self
.path
, so
), so
,
870 dot
.add_node(pydot
.Node(self
.path
,shape
="Mrecord",label
=label
))
872 # recursively dump out children
873 for c
in self
.children
:
876 # Function to provide to C++ so it can look up instances based on paths
877 def resolveSimObject(name
):
878 obj
= instanceDict
[name
]
879 return obj
.getCCObject()
881 def isSimObject(value
):
882 return isinstance(value
, SimObject
)
884 def isSimObjectClass(value
):
885 return issubclass(value
, SimObject
)
887 def isSimObjectVector(value
):
888 return isinstance(value
, SimObjectVector
)
890 def isSimObjectSequence(value
):
891 if not isinstance(value
, (list, tuple)) or len(value
) == 0:
895 if not isNullPointer(val
) and not isSimObject(val
):
900 def isSimObjectOrSequence(value
):
901 return isSimObject(value
) or isSimObjectSequence(value
)
904 from m5
.objects
import Root
905 return obj
and obj
is Root
.getInstance()
907 def isSimObjectOrVector(value
):
908 return isSimObject(value
) or isSimObjectVector(value
)
910 def tryAsSimObjectOrVector(value
):
911 if isSimObjectOrVector(value
):
913 if isSimObjectSequence(value
):
914 return SimObjectVector(value
)
917 def coerceSimObjectOrVector(value
):
918 value
= tryAsSimObjectOrVector(value
)
920 raise TypeError, "SimObject or SimObjectVector expected"
923 baseClasses
= allClasses
.copy()
924 baseInstances
= instanceDict
.copy()
927 global allClasses
, instanceDict
929 allClasses
= baseClasses
.copy()
930 instanceDict
= baseInstances
.copy()
932 # __all__ defines the list of symbols that get exported when
933 # 'from config import *' is invoked. Try to keep this reasonably
934 # short to avoid polluting other namespaces.
935 __all__
= [ 'SimObject' ]