Listing 10

// A macro that defines enumeration values for a bitset
// You supply the start and end bit positions
#define REG_BIT_DEFN(start, end) ((start<<16)|(end-start+1))
enum STATUS_bits
{
    TX_BUFFER_EMPTY = REG_BIT_DEFN(0, 0),
    RX_BUFFER_EMPTY = REG_BIT_DEFN(1, 1), 
    TX_UNDERRUN     = REG_BIT_DEFN(2, 2), 
    RX_OVERFLOW     = REG_BIT_DEFN(3, 3)
};
 ... similarly for other bitsets ...
#undef REG_BIT_DEFN

inline uint32_t bitRead(Registers32 reg, uint32_t bits)
{
    uint32_t       regval = *regAddress(reg);
    const uint32_t width  = bits & 0xff;
    const uint32_t bitno  = bits >> 16;
    regval >>= bitno;
    regval  &= ((1<<width)-1);
    return regval;
}
inline void bitWrite(Registers32 reg, uint32_t bits, uint32_t value)
{
    uint32_t           regval = *regAddress(reg);
    const uint32_t     width  = bits & 0xff;
    const uint32_t     bitno  = bits >> 16;
    regval &= ~(((1<<width)-1) << bitno);
    regval |=  value << bitno;
    *regAddress(reg) = regval;
}