vendredi 25 septembre 2015

passing reference pointing to struct as template parameter

I would like effectively map structures with registers to a memory. Actually I have working code like this:

Structure with registers for a peripheral:

struct Periph {
    volatile uint32_t REG1;
    volatile uint32_t REG2;
};

In device is this peripheral two times located on two different addresses in memory, so define these addresses:

static constexpr size_t PERIPH1_BASE = 0x40000000;
static constexpr size_t PERIPH2_BASE = 0x40001000;

Then I have a driver which can use any of these registers:

template<size_t Base> struct Driver {
    inline Periph &r() {
        return *reinterpret_cast<Periph *>(base);
    }
    void setFoo(uint32_t x) {
        r().REG1 = x;
    }
    uint32_t getBar() {
        return r().REG2;
    }
};

To use this driver is simple, only need set address of certain peripheral to template:

Driver<PERIPH1_BASE> drv;
uint32_t x = drv.getBar();
drv.setFoo(x);
...

If compiler merge all inline functions after optimization then this method works very effectively with registers and without any overhead.

But this is not very safe, because I can set to Driver any address from different peripheral.

My Idea to improve this is to put reference to a structure as template argument, but without success.

First I defined references to registers:

static Periph &PERIPH1 = *reinterpret_cast<Periph *>(PERIPH1_BASE);
static Periph &PERIPH2 = *reinterpret_cast<Periph *>(PERIPH2_BASE);

This is working, I can directly access these registers like:

PERIPH2.REG1 = 123;

But I have no idea how to pass these references to template argument, my attempt is following:

template<Periph &r> struct Driver {
    void setFoo(uint32_t x) {
        r.REG1 = x;
    }
    uint32_t getBar() {
        return r.REG2;
    }
};

Driver<PERIPH2> drv;
drv.setFoo(x);

From this I get following error:

`error: the value of 'PERIPH2' is not usable in a constant expression`

If I define PERIPH2 as constexpr then I get another error:

`error: reinterpret_cast from integer to pointer`

... So how to put reference to an object as template argument? Or an idea or suggestion to make this better.

Also here exists lot of other solutions (like put reference to a Driver constructor...), but this slow down access to registers.

Thanks for any help.

Aucun commentaire:

Enregistrer un commentaire