Minor enhancements to Python config stuff:

- Add support for assigning NULL to SimObject pointers.  In Python,
this is a special value, distinct from None.
- Initial, incomplete pass at regenerating C++ parameter code (declarations
and INIT_PARAM macros) from .odesc files.

util/config/m5config.py:
    - Add support for assigning NULL to SimObject pointers.  In Python,
    this is a special value, distinct from None.
    - Initial, incomplete pass at regenerating C++ parameter code (declarations
    and INIT_PARAM macros) from .odesc files.

--HG--
extra : convert_revision : d7ae8f32e30b3c0829fd1a60589dd998e2e0d0d7
This commit is contained in:
Steve Reinhardt 2004-04-28 16:28:37 -07:00
parent 05f29b8d8d
commit d85b26d65a

View file

@ -99,7 +99,7 @@ import sys
#
#####################################################################
# The metaclass for ConfigNode (and thus for everything that dervies
# The metaclass for ConfigNode (and thus for everything that derives
# from ConfigNode, including SimObject). This class controls how new
# classes that derive from ConfigNode are instantiated, and provides
# inherited class behavior (just like a class controls how instances
@ -278,8 +278,8 @@ class ConfigNode(object):
self._children[new_child._name] = new_child
# operator overload for '+='. You can say "node += child" to add
# # a child that was created with parent=None. An early attempt
# at # playing with syntax; turns out not to be that useful.
# a child that was created with parent=None. An early attempt
# at playing with syntax; turns out not to be that useful.
def __iadd__(self, new_child):
if new_child._parent != None:
raise AttributeError, \
@ -335,6 +335,23 @@ class SimObject(ConfigNode):
if value != None:
print pname, '=', value
def _sim_code(cls):
name = cls.__name__
param_names = cls._param_dict.keys()
param_names.sort()
code = "BEGIN_DECLARE_SIM_OBJECT_PARAMS(%s)\n" % name
decls = [" " + cls._param_dict[pname].sim_decl(pname) \
for pname in param_names]
code += "\n".join(decls) + "\n"
code += "END_DECLARE_SIM_OBJECT_PARAMS(%s)\n\n" % name
code += "BEGIN_INIT_SIM_OBJECT_PARAMS(%s)\n" % name
inits = [" " + cls._param_dict[pname].sim_init(pname) \
for pname in param_names]
code += ",\n".join(inits) + "\n"
code += "END_INIT_SIM_OBJECT_PARAMS(%s)\n\n" % name
return code
_sim_code = classmethod(_sim_code)
#####################################################################
#
# Parameter description classes
@ -353,26 +370,41 @@ class SimObject(ConfigNode):
#
#####################################################################
# Force parameter value (rhs of '=') to ptype (or None, which means
# not set).
def make_param_value(ptype, value):
# nothing to do if None or already correct type
if value == None or isinstance(value, ptype):
return value
# this type conversion will raise an exception if it's illegal
return ptype(value)
def isNullPointer(value):
return isinstance(value, NullSimObject)
def isSimObjectType(ptype):
return issubclass(ptype, SimObject)
# Regular parameter.
class Param(object):
# Constructor. E.g., Param(Int, "number of widgets", 5)
def __init__(self, ptype, desc, default=None):
self.ptype = ptype
self.ptype_name = self.ptype.__name__
self.desc = desc
self.default = default
# Convert assigned value to appropriate type.
# Convert assigned value to appropriate type. Force parameter
# value (rhs of '=') to ptype (or None, which means not set).
def make_value(self, value):
return make_param_value(self.ptype, value)
# nothing to do if None or already correct type. Also allow NULL
# pointer to be assigned where a SimObject is expected.
if value == None or isinstance(value, self.ptype) or \
isNullPointer(value) and isSimObjectType(self.ptype):
return value
# this type conversion will raise an exception if it's illegal
return self.ptype(value)
def sim_decl(self, name):
return 'Param<%s> %s;' % (self.ptype_name, name)
def sim_init(self, name):
if self.default == None:
return 'INIT_PARAM(%s, "%s")' % (name, self.desc)
else:
return 'INIT_PARAM_DFLT(%s, "%s", %s)' % \
(name, self.desc, str(self.default))
# The _VectorParamValue class is a wrapper for vector-valued
# parameters. The leading underscore indicates that users shouldn't
@ -391,12 +423,12 @@ class _VectorParamValue(object):
# Vector-valued parameter description. Just like Param, except that
# the value is a vector (list) of the specified type instead of a
# single value.
class VectorParam(object):
# Constructor. The resulting parameter will be a list of ptype.
class VectorParam(Param):
# Inherit Param constructor. However, the resulting parameter
# will be a list of ptype rather than a single element of ptype.
def __init__(self, ptype, desc, default=None):
self.ptype = ptype
self.desc = desc
self.default = default
Param.__init__(self, ptype, desc, default)
# Convert assigned value to appropriate type. If the RHS is not a
# list or tuple, it generates a single-element list.
@ -404,14 +436,18 @@ class VectorParam(object):
if value == None: return value
if isinstance(value, list) or isinstance(value, tuple):
# list: coerce each element into new list
val_list = [make_param_value(self.ptype, v) for v in
iter(value)]
val_list = [Param.make_value(self, v) for v in iter(value)]
else:
# singleton: coerce & wrap in a list
val_list = [ make_param_value(self.ptype, value) ]
val_list = [Param.make_value(self, value)]
# wrap list in _VectorParamValue (see above)
return _VectorParamValue(val_list)
def sim_decl(self, name):
return 'VectorParam<%s> %s;' % (self.ptype_name, name)
# sim_init inherited from Param
#####################################################################
#
# Parameter Types
@ -498,6 +534,19 @@ class String(object):
def __str__(self):
return self.value
# Special class for NULL pointers. Note the special check in
# make_param_value() above that lets these be assigned where a
# SimObject is required.
class NullSimObject(object):
# Constructor. No parameters, nothing to do.
def __init__(self):
pass
def __str__(self):
return "NULL"
# The only instance you'll ever need...
NULL = NullSimObject()
# Enumerated types are a little more complex. The user specifies the
# type as Enum(foo) where foo is either a list or dictionary of
@ -673,7 +722,9 @@ def def_class(path):
sys.exit(1)
if not odesc_loaded[parent]:
def_class(odesc_file[parent])
# define the class.
# define the class. The _name attribute of the class lets us
# track the actual SimObject class name even when we derive new
# subclasses in scripts (to provide new parameter value settings).
s = "class %s(%s): _name = '%s'" % (obj, parent, obj)
try:
# execute in global namespace, so new class will be globally
@ -730,14 +781,24 @@ for objname, path in odesc_file.iteritems():
if not odesc_loaded[objname]:
def_class(path)
sim_object_list = odesc_loaded.keys()
sim_object_list.sort()
# Iterate through files again and load parameters.
for path in odesc_file.itervalues():
def_params(path)
#####################################################################
# Hook to generate C++ parameter code.
def gen_sim_code(file):
for objname in sim_object_list:
print >> file, eval("%s._sim_code()" % objname)
# The final hook to generate .ini files. Called from configuration
# script once config is built.
def instantiate(*objs):
for obj in objs:
obj._instantiate()