mardi 28 février 2023

How to properly design register class in C++ accessing register bits by reference

I need to design a class which manages the CPU internal registers like CR0, CR2, the MSRs etc. in object oriented manner. The requirements are:

  • particular bits are declared as bitfields representing the register values. For instance:

     struct cr0 : public cpu_register<...> {
         using raw_type = uint32_t;
    
         uint8_t pe      : 1     { 0 };      /* bit0 - Protected Mode Enable */
         uint8_t mp      : 1     { 0 };      /* bit1 - Monitor co-processor */
         uint8_t em      : 1     { 0 };      /* bit2 - Emulation */
         uint8_t ts      : 1     { 0 };      /* bit3 - Task Switched */
         uint8_t et      : 1     { 0 };      /* bit4 - Extension Type */
         uint8_t ne      : 1     { 0 };      /* bit5 - Numeric Error */
         uint16_t        : 10;               /* Reserved */
         uint8_t wp      : 1     { 0 };      /* bit16 - Write Protect */
         uint8_t         : 1;                /* Reserved */
         uint8_t am      : 1     { 0 };      /* bit18 - Alignment Mask */
         uint16_t        : 10;               /* Reserved */
         uint8_t nw      : 1     { 0 };      /* bit29 - Not-write Through */
         uint8_t cd      : 1     { 0 };      /* bit30 - Cache Disable */
         uint8_t pg      : 1     { 0 };      /* bit30 - Paging */
    
         inline raw_type load( void ) noexcept {
             raw_type raw;
             asm volatile ( "movl %%cr0, %0\n" : "=r" ( raw ) );
             return raw;
         }
    
         inline void store( raw_type raw ) noexcept {
             asm volatile ( "movl %[v], %%cr0\n" :: [v] "r" ( raw ) );
         }
    
     } __attribute__((packed));
    

For each and every register there are specific write/store and read/load functions.

The goal is to implement a base class cpu_register<> from which each and every register class analogical to cr0 shall derive, eg.

class cr2 : public cpu_register<...> { ... };
class cr3 : public cpu_register<...> { ... };

to share the common functionalities like writing to the register and reading from it. The problem is, it is not possible to return by reference to particular bit representations (the bitfield) in order to uniformly read and write the bit values in within the register using the defined load() and store() functions.

I was thinking about to implement the proxy class somehow to perform the load and stores of particular bits but I was not successfull to do so. The goal is to have simple and uniform interface to read and write the registers:

cr0.pe = 1;                 // writes 1 into PE bit using the store() function
int value = cr0.pg;         // reads the value of PG bit using the load() function
if( cr0.pg == 0 ) { ... };  // same as above

I am focused on clean OOP design. Any kind of advice, help, design pattern recommendation, code snippet would be warmly welcomed... thanks in advance.

Aucun commentaire:

Enregistrer un commentaire