Search code examples
dml-lang

Create a register alias template that produces an error when aliased to itself


Question about "Alias Registers" concept from Model Builder guide. Would like to produce an error (ideally, a compile time error) when a register alias is accidentally aliased to itself :) Alias registers could be arrays.

Comparing alias parameter to "this" doesn't work :)

This is the register alias example from Model Builder guide:

bank regs {
    register X size 4 @ 0x00 is (read_write) "the X register";
    register Y size 4 @ 0x04 is (alias) { parameter alias_reg = $X; }
}

template alias {
    parameter alias_reg;
    parameter allocate = false;
    parameter configuration = "none";
    parameter desc = "alias of " + $alias_reg.name;

    method read_access(generic_transaction_t *mop, msb1, lsb) -> (value) {
        log "info", 4: "Redirecting read access to %s", $alias_reg.qname;
        inline $alias_reg.read_access(mop, msb1, lsb) -> (value);
    }

    method write_access(generic_transaction_t *mop, msb1, lsb, value) {
        log "info", 4: "Redirecting write access to %s", $alias_reg.qname;
        inline $alias_reg.write_access(mop, msb1, lsb, value);
    }
}

Solution

  • First, rephrasing your question in terms of DML 1.4 where a direct translation of the alias template would be:

    dml 1.4;
    template alias is register {
        param alias_reg;
        param configuration = "none";
        param desc = "alias of " + alias_reg.name;
    
        method read_register(uint64 enabled_bits, void *aux) -> (uint64) {
            log info, 4: "Redirecting read access to %s", alias_reg.qname;
            return alias_reg.read_register(enabled_bits, aux);
        }
    
        method write_register(uint64 value, uint64 enabled_bits, void *aux) {
            log info, 4: "Redirecting write access to %s", alias_reg.qname;
            alias_reg.write_register(value, enabled_bits, aux);
        }
    }
    

    And you want the following to give an error:

    bank regs {
        register Y size 4 @ 0x04 is alias { param alias_reg = Y; }
    }
    

    In fact, GCC detects the infinite recursion in generated C code if I use GCC 12.1.0:

    sample-device-dml-dml.c:3548:14: error: infinite recursion detected [-Werror=infinite-recursion]
    

    If that's not enough, then you can compare object identities by casting references to object, something like:

        method read_register(uint64 enabled_bits, void *aux) -> (uint64) {
            assert cast(alias_reg, object) != cast(this, object);
            log info, 4: "Redirecting read access to %s", alias_reg.qname;
            return alias_reg.read_register(enabled_bits, aux);
        }
    

    This will however silence the GCC warning (GCC understands that the assertion will fail and thus break the infinite recursion)

    A third alternative is a compile-time assertion:

        method read_register(uint64 enabled_bits, void *aux) -> (uint64) {
            #if (cast(alias_reg, object) == cast(this, object)) { error; }
            log info, 4: "Redirecting read access to %s", alias_reg.qname;
            return alias_reg.read_register(enabled_bits, aux);
        }
    

    This approach is nice in some ways, but does not work if you want to declare the methods as shared.

    This could have been resolved by moving the #if outside the method; however, when I tried this I ran into a compiler bug that caused DMLC to crash; this is now reported as SIMICS-20411.