Previous - Up - Next

2.5   Configuration Attributes

A Simics configuration consists of a machine description and a few other parts, and it is divided into a number of configuration objects. Each device instance in the configuration is represented by such an object. Any Simics configuration object has a number of attributes. An attribute is a named property that can be read or written using the Simics API. The value of an attribute can be an integer, a floating-point number, a string, an object reference, a boolean value, a list of values, or a mapping from values to other values.

Attributes are used for several related purposes, but the most important uses are for configuration and checkpointing. All the internal state of a device object must be available through the attributes, so that a checkpoint of the current state can be saved by reading all the attributes and storing the values to disk. By reloading a configuration and setting all attributes from the previously saved checkpoint, the states of all devices can be restored to the checkpointed state and simulation can continue as if it had never been interrupted. When creating a new configuration, some of the state must be given an explicit initial assignment, which makes those attributes also part of the configuration. There may also be attributes that are not part of the state, in the sense that they don't change during simulation. Instead, they control the behavior of the model, such as buffer sizes, timing parameters etc. Those configuration attributes can generally not be modified once the object has been created.

Attributes can also be used as a simple interface to an object, e.g., for inspecting or manipulating the state for debugging purposes.

A DML device model usually defines a number of attributes. By default, each register defines a corresponding attribute that can be used to get or set the register value, but more attributes can be defined by explicitly declaring them in the DML source. In our example above, for the register r0 of bank b there will be a device attribute named b_r0 (note the underscore).

2.5.1   Using Register Attributes

The get and set methods of a register are different from its read and write methods in that they do not simulate a hardware access (which often triggers side-effects in devices). Instead, they offer a direct way of reading or modifying the value of the register.

We can access the attribute from the Simics command line. Continuing our example from the previous sections, enter:

  simics> dev1->b_r0 = 17
and then enter
  simics> dev1->b_r0
which should print the value 17.

However, if we make a new memory access, as before:

  simics> phys_mem.get 0x1000
we still get the message "Hello, bus!" and the value 42. But entering dev1->b_r0 once again still returns 17. What is going on?

The answer is of course that we had hard-coded the read method to always return 42, no matter what. But this does not affect the behavior of get and set, or the write method. Let's try to make a write access:

  simics> phys_mem.set 0x1000 0xff
Entering conf->dev1.b_r0 now prints the value 255 as expected. You can change the line
    result = 42;
in the program to:
    result = $this;
(note the $ character), recompile, and try the same accesses again to check how a normal register would behave. Then change the code back to return 42 for the rest of this section.

It is in fact often useful to create registers which either return a constant (usually zero), or return a value that is computed on the fly. For such registers, it is unnecessary to allocate memory for storing the value inbetween calls. The allocation can be turned off by adding the following line to the body of the register:

    parameter allocate = false;
note, however, that doing so makes it necessary to implement your own versions of the get, set, read and write methods. (Try adding the above line to your code, recompile, and run the example again. Note the messages you get when you try to access the register in the various ways we have shown.)

A full implementation of such a "synthetic" constant register could contain method definitions like the following:

    method write(value) {
        /* do nothing */
    }
    method get -> (value) {
        value = 42;
    }
    method set(value) {
        if (value != 42)
            throw;
    }
Try adding them (to the body of the register), recompile, and run the example again.

The standard library file utility.dml contains several pre-defined templates for common implementations such as this. To use it, add the declaration "import "utility.dml";" to your source file. The constant register can now simply be implemented as follows:

      register r0 size 4 @0x0000 is (constant) {
          parameter value = 42;
      }
or, if you still want to get a log message for each read access:
      register r0 size 4 @0x0000 is (constant) {
          parameter value = 42;
          method read() -> (result) {
              log "info", 1, 0: "Hello, bus!";
              result = $value;
          }
      }

2.5.2   User-defined Attributes

It is sometimes useful to have device attributes that are not associated with any register. If we just want the attribute to behave as a data field, which stores a value of a simple data type such as int32 or bool, we only have to specify the parameter allocate_type, as follows:

    attribute foo "an integer attribute" {
        parameter allocate_type = "int32";
    }
(note that the data type must be specified as a string). Try adding this code to your device (either before or after the bank), recompile and rerun the example. Enter the following command:
  simics> help attribute:dev1.foo
This prints some information about the attribute. Note that the descriptive string you specified in the program is included in the online documentation.

You can now experiment with setting and getting the value of the attribute; e.g., entering

  simics> dev1->foo = 4711
  simics> dev1->foo
should print 4711.

If it is important that other parts of the device are updated whenever the value of the attribute is modified, the method after_set can be overridden to perform such updates. (By default, it does nothing.) For example:

    method after_set {
        log "info": "Someone updated the attribute!";
    }
Add this method to the body of the attribute, recompile and restart Simics, then try setting and getting the value of the attribute.

If you want the attribute to do things differently, such as not store the value between calls, or use a more complex data type, you need to do more work on your own, instead of using the allocate_type parameter; see the DML Reference Manual for details.

Previous - Up - Next