cls._params = multidict() # param descriptions
cls._ports = multidict() # port descriptions
+ # Parameter names that are deprecated. Dict[str, DeprecatedParam]
+ # The key is the "old_name" so that when the old_name is used in
+ # python config files, we will use the DeprecatedParam object to
+ # translate to the new type.
+ cls._deprecated_params = multidict()
+
# class or instance attributes
cls._values = multidict() # param values
cls._hr_values = multidict() # human readable param values
cls._base = base
cls._params.parent = base._params
cls._ports.parent = base._ports
+ cls._deprecated_params.parent = base._deprecated_params
cls._values.parent = base._values
cls._hr_values.parent = base._hr_values
cls._children.parent = base._children
elif isinstance(val, Port):
cls._new_port(key, val)
+ # Deprecated variable names
+ elif isinstance(val, DeprecatedParam):
+ new_name, new_val = cls._get_param_by_value(val.newParam)
+ # Note: We don't know the (string) name of this variable until
+ # here, so now we can finish setting up the dep_param.
+ val.oldName = key
+ val.newName = new_name
+ cls._deprecated_params[key] = val
+
# init-time-only keywords
elif key in cls.init_keywords:
cls._set_keyword(key, val, cls.init_keywords[key])
cls._port_refs[attr] = ref
return ref
+ def _get_param_by_value(cls, value):
+ """Given an object, value, return the name and the value from the
+ internal list of parameter values. If this value can't be found, raise
+ a runtime error. This will search both the current object and its
+ parents.
+ """
+ for k,v in cls._value_dict.items():
+ if v == value:
+ return k,v
+ raise RuntimeError("Cannot find parameter {} in parameter list"
+ .format(value))
+
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
def __setattr__(cls, attr, value):
return ref
def __getattr__(self, attr):
+ if attr in self._deprecated_params:
+ dep_param = self._deprecated_params[attr]
+ dep_param.printWarning(self._name, self.__class__.__name__)
+ return getattr(self, self._deprecated_params[attr].newName)
+
if attr in self._ports:
return self._get_port_ref(attr)
object.__setattr__(self, attr, value)
return
+ if attr in self._deprecated_params:
+ dep_param = self._deprecated_params[attr]
+ dep_param.printWarning(self._name, self.__class__.__name__)
+ return setattr(self, self._deprecated_params[attr].newName, value)
+
if attr in self._ports:
# set up port connection
self._get_port_ref(attr).connect(value)
ptype_str = 'Port'
ptype = Port
+class DeprecatedParam(object):
+ """A special type for deprecated parameter variable names.
+
+ There are times when we need to change the name of parameter, but this
+ breaks the external-facing python API used in configuration files. Using
+ this "type" for a parameter will warn users that they are using the old
+ name, but allow for backwards compatibility.
+
+ Usage example:
+ In the following example, the `time` parameter is changed to `delay`.
+
+ ```
+ class SomeDevice(SimObject):
+ delay = Param.Latency('1ns', 'The time to wait before something')
+ time = DeprecatedParam(delay, '`time` is now called `delay`')
+ ```
+ """
+
+ def __init__(self, new_param, message=''):
+ """new_param: the new parameter variable that users should be using
+ instead of this parameter variable.
+ message: an optional message to print when warning the user
+ """
+ self.message = message
+ self.newParam = new_param
+ # Note: We won't know the string variable names until later in the
+ # SimObject initialization process. Note: we expect that the setters
+ # will be called when the SimObject type (class) is initialized so
+ # these variables should be filled in before the instance of the
+ # SimObject with this parameter is constructed
+ self._oldName = ''
+ self._newName = ''
+
+ @property
+ def oldName(self):
+ assert(self._oldName != '') # should already be set
+ return self._oldName
+
+ @oldName.setter
+ def oldName(self, name):
+ assert(self._oldName == '') # Cannot "re-set" this value
+ self._oldName = name
+
+ @property
+ def newName(self):
+ assert(self._newName != '') # should already be set
+ return self._newName
+
+ @newName.setter
+ def newName(self, name):
+ assert(self._newName == '') # Cannot "re-set" this value
+ self._newName = name
+
+ def printWarning(self, instance_name, simobj_name):
+ """Issue a warning that this variable name should not be used.
+
+ instance_name: str, the name of the instance used in python
+ simobj_name: str, the name of the SimObject type
+ """
+ if not self.message:
+ self.message = "See {} for more information".format(simobj_name)
+ warn('{}.{} is deprecated. {}'.format(
+ instance_name, self._oldName, self.message))
+
baseEnums = allEnums.copy()
baseParams = allParams.copy()
'NextEthernetAddr', 'NULL',
'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
- 'VectorMasterPort', 'VectorSlavePort']
+ 'VectorMasterPort', 'VectorSlavePort',
+ 'DeprecatedParam',
+ ]