Previous - Up - Next

3   Using C code and the Simics API

Since data types and method bodies in DML are written in an extended subset of C, you can easily call C functions from DML by using normal function call syntax, as in f(x) (rather than using the call or inline keywords to call DML methods). For example, the following is a legal DML program, based on the example in Section 2.1:

    dml 1.0;
    device simple_device;
    import "io-memory.dml";

    extern int fib(int x);

    bank b {
        parameter function = 0;
        register r0 size 4 @0x0000 {
            parameter allocate = false;
            method write(val) {
                log "info": "Fibonacci(%d) = %d.", val, fib(val);

    header %{
    int fib(int x);

    footer %{
    int fib(int x) {
        if (x < 2) return 1;
        else return fib(x-1) + fib(x-2);

Writing to the (pseudo-) register r0 has the effect of printing a log message with the computed Fibonacci number:

  simics> phys_mem.set 0x1000 6
  [dev1 info] Fibonacci(6) = 13.

Notable points are:

The Simics API (a set of C functions and data types) is defined in DML in the library file simics-api.dml, which is automatically included by dmlc. The corresponding C declarations are defined in header files which are also automatically included by the generated code for a device. Hence, the DML programmer has direct access to the entire Simics API.

For example, this is how the method set_read_value() is implemented in the standard library. It updates a generic_transaction_t structure (a "memop") at the end of a read access to a memory bank has finished, depending on the endianism of the bank:

    method set_read_value(generic_transaction_t *memop,
                          uint64 value) default
        if (!defined $byte_order)
        else if ($byte_order == "little-endian")
            SIM_set_mem_op_value_le(memop, value);
            SIM_set_mem_op_value_be(memop, value);

Previous - Up - Next