dimanche 29 juillet 2018

C++ Embedded Control Register Template

My current job has had me doing research into creating classes for arbitrary embedded device registers. Currently I am working with a number of targets with varying register sizes and I would like to standardize (or at least come up with some logical way) of enumerating objects for memory-mapped io, registers, etc. The current company standard is to place a variable at the register location.

volatile uint16_t &register_obj = *reinterpret_cast<volatile uint16_t *>(0x01A02);

I read a few papers and discussions on the subject of embedded C++, most notably this blog post by Niklas Hauser and this overview providing a comparison and extension of a few other papers. These posts contain further references to a great paper on representing and manipulating hardware with C and C++ as well as some mock examples and alternative ideas in Ken Smith's C++ Hardware Register Redux.

I further defined a type alias to represent the register width with:

/* These define an alias for the largest register that can exist in a 
* sub-module. Where a module (IE: UART) contains an arbitrary number of 
* sub-modules (IE UART_CTL0, UART_CTL1, UART_INTERRUPTS...) as defined in the 
* vendor's datasheet.
*/
#if defined(__MSP430__)
using reg16_t = volatile uint16_t;
#elif defined(__ARM__)
using reg32_t = volatile uint32_t;
#endif

The first code snippet then becomes:

reg16_t &register_obj = *reinterpret_cast<reg16_t *>(0x01A02);

This didn't satisfy me. I realized that "placement new" might be a good fit for my applications as registers and memory-mapped IO are effectively pre-allocated memory sections that I could overlay objects over.

I read up on variadic templates and spent hours trying to design a template that created and placed an arbitrary type at a specified address, the closest was the following:

template <typename T>
T* placeObject(uintptr_t address) {
   return new (reinterpret_cast<uintptr_t*>(address)) T;
}

but the implementation is effectively a worse version of what I started with. example:

reg16_t& control_register = *submodule_new<reg16_t>(0x0160);

I tried a struct template and came up with:

template<typename T, uintptr_t address>
struct submodule
{
    T &location = *reinterpret_cast<T *>(address);
    // Also needs to implement mutability (access policy)
};

this looked promising as it's declaration is exactly what I'm looking for:

submodule<reg16_t, 0x0160> control_register_0;

but the struct-interfacing is rather awkward:

uint8_t ENABLE = 0x4;
control_register_0.location &= ~ENABLE; // this probably doesn't work

My actual questions

  • Are there any good examples of "pure C++" class-based register templates?
  • If not, how should I structure the inheritance and construction notation so that it provides a clear intention of my goals?

The end goal for this project is to have sub-modules contain access-policies and the location of data to read and write. These sub-modules would ideally be constructed in a variadic class generator to allow for arbitrarily-many, arbitrarily-sized, interfaces to memory that provide type-safety and access policies (read-only, write-only). Something of the form:

// pseudo-code
template<typename base_type, class ...submodules>
class module
{
    // somehow assign submodules to this class
};

module<submodule<reg16_t> UARTControl0, submodule<reg16_t> UARTStatus> UART();

UART.UARTControl0.Write(0x0001);
bool uart_enabled = UART.UARTStatus.read(0x);

Aucun commentaire:

Enregistrer un commentaire