I'm looking for a way to pass embedded device registers to C++ templates, using gcc 4.8.4. In data sheets describing the embedded devices, the addresses of the registers are usually given as raw memory locations (0x40008000 for example).
When I test the software, I want to use static integers as registers to see if register values are set correctly.
So basically a wrapper around some device peripheral boils down to a class with it's register addresses given as template parameter:
template < volatile std::uint32_t* Reg >
struct peripheral {};
Testing works fine:
std::uint32_t reg;
peripheral< ® > mocked;
But when I want to instantiate the template with a fixed, data sheet given address:
peripheral< reinterpret_cast< std::uint32_t* >( 0x40008000 ) > mocked;
gcc complains: could not convert template argument '1073774592u' to 'volatile uint32_t* {aka volatile long unsigned int*}. clang doesn't complain about this.
If I use the address given as integer as template parameter, I have problems to instantiate the template during my tests with the address of the mocked registers:
template < std::intptr_t Reg >
struct peripheral {};
std::uint32_t reg;
peripheral< reinterpret_cast< std::intptr_t >( ® ) > mocked;
This results in error: conversion from pointer type 'uint32_t* {aka long unsigned int*}' to arithmetic type 'intptr_t {aka int}' in a constant-expression.
I can think of two solutions to this:
1) Use pointers as template parameters, use global variables as registers and fix the address of the registers with some linker script magic.
2) Use special register types that have a common interface to the peripheral template but two very different implementations for testing and for the real application.
But I'm looking for an easier way to accomplish this. Any ideas, pointers or comments?