A Simics class can register attributes that will act as data members for all objects instantiated from this class. For Simics, an attribute is an abstraction, defined by its type and a pair of get()/set() functions. When an attribute is read (i.e., when the SIM_get_attribute() function is used on the object), the corresponding get() function is called. Likewise, when an attribute is written to, the set() function is executed. These functions can perform any kind of operation provided they return a value (for get()) or accept a value to be written (for set()).
Attributes have different types and properties. The Simics User Guide presents a high level description of attributes. Let us here have a closer look at their definition.
The C and DML definition of the structures representing an attribute are the following:
typedef enum { Sim_Val_Invalid = 0, Sim_Val_String = 1, Sim_Val_Integer = 2, Sim_Val_Floating = 3, Sim_Val_List = 4, Sim_Val_Data = 5, Sim_Val_Nil = 6, Sim_Val_Object = 7, Sim_Val_Dict = 8, Sim_Val_Boolean = 9 } attr_kind_t; typedef struct { integer_t size; struct attr_value *vector; } attr_list_t; typedef struct { integer_t size; uint8 *data; } attr_data_t; typedef struct { struct attr_value key; struct attr_value value; } attr_dict_pair_t; typedef struct { integer_t size; attr_dict_pair_t *vector; } attr_dict_t; typedef struct attr_value { attr_kind_t kind; union { const char *string; integer_t integer; integer_t boolean; double floating; attr_list_t list; attr_dict_t data; attr_data_t data; conf_object_t *object; } u; } attr_value_t;
When using an attribute in C or DML, one should take care of only using the union member that corresponds to the attribute type in the attr_value_t structure. Here are some example of attribute manipulation in C and DML:
// create an integer attribute attr_value_t a; a.kind = Sim_Val_Integer; a.u.integer = 4711; // or better, using help functions attr_value_t a; a = SIM_make_attr_integer(4711); // create a list attribute attr_value_t l; l = SIM_alloc_attr_list(2); // writing to the first element l.u.list.vector[0] = SIM_make_attr_integer(1) // reading the second element of the list integer_t other = l.u.list.vector[1].u.integer;
A complete documentation of attributes related functions is provided in the Simics Reference Manual.
In Python, attributes are automatically converted to or from the corresponding Python type, so manipulating attributes is completely transparent:
Attribute Type | Python Equivalent |
Invalid | Cast a SimExc_Attribute exception. |
String | str (a Python string) |
Integer | int or long |
Floating | float |
List | list |
Data | tuple |
Nil | None |
Object | An object from the conf namespace. |
Dict | dict |
Boolean | bool |
When registering an attribute, a type definition should be provided for Simics to check that the attribute is always set properly. This type definition is a string defined by to the following rules:
When you specify a size, the list definition can have only one element.
As an example, the type for sim.simics_path is "s|[s*]", which means that it can either match a string or a (possibly empty) list of strings.
When writing complex attributes, you may notice that the type description strings don't cover all the possibilities offered by the attribute structure definition. If you need to register attributes that can not be described in a type string (like complex variable size lists), you will need to use the a type and perform the type checking by yourself in the set() function. You may also want to review your attribute and change its definition to match a possible type description, or divide your attribute into several simpler attributes.
For example, an attribute accepting a list composed of one object and one or more integers can not be described in a type string (list definition with variable size can only have one element). You may want to rewrite your attribute to use a sub-list for the integers: [o[i+]], or you can perform type checking yourself.
To learn more about attributes in DML, refer to section 5.2. For C and Python, refer to section 6.4.
When the attr_value_t type is used for function arguments, it is the caller that owns the data, and that is responsible for freeing it after the call. If the called function wants to keep a reference to the attribute value, it should make a copy of it.
When a function returns an attr_value_t, it may return a reference to a static data area, that will be reused in future calls. The caller has to use the returned data, or create a copy of it, before calling any other functions. If an attribute get function allocates new memory every time the attribute is read, it will leak memory.
When an attr_value_t is returned, the attribute structure used for lists and dictionaries should be freed by the caller using SIM_free_attribute(). This function will only free the attribute structure, not any string or data memory.