Bit-Banding Updated
Last time, I wrote about bit-banding with ARM Cortex-Mx microcontrollers. Although I am not using my BitWord class in my current project, here is an improved, better documented and slightly better tested version of it:
// Copyright Software Integrity Ltd., 2013
#ifndef SWI_BIT_WORD_H
#define SWI_BIT_WORD_H
#include <limits>
namespace SOFTWARE_INTEGRITY
{
// These constants should really be declared as static members of BitWord,
// but then I would have to publish the .cpp file as well, to show the
// definitions.
static unsigned int * const pBase
= reinterpret_cast<unsigned int *>(0x20000000U);
static unsigned int * const pAlias
= reinterpret_cast<unsigned int *>(0x22000000U);
// The following assumes that the number of bits in an unsigned int is a
// power of 2. Actually, we know it is because it's definitely 32 for the
// Cortex Mx!
static unsigned int const mask
= std::numeric_limits<unsigned int>::digits - 1;
// class BitWord...
// Allows bit-banded variables of type BitWord to be defined.
// The individual bits of a BitWord can be read, set and cleared atomically.
// Implicit Bitword<->unsigned int conversions are supported.
// The user must ensure that all BitWord objects are actually located in the
// valid memory bit-band area (0x200xxxxx).
// This class does not work for the peripheral bit-band area (0x400xxxxx)!
class BitWord
{
public:
// Constructor, which sets an initial value for the BitWord variable.
// Also converts from unsigned int to BitWord type.
BitWord(unsigned int value = 0):
m_value(value),
m_pBit(pAlias + ((&m_value - pBase) << 5))
{
}
// Copy constructor.
BitWord(const BitWord& orig):
m_value(orig.m_value),
m_pBit(pAlias + ((&m_value - pBase) << 5))
{
}
// Converts from BitWord to unsigned int.
operator unsigned int() const volatile
{
return m_value;
}
// Assignment from BitWord.
volatile BitWord& operator=(const BitWord& rhs) volatile
{
m_value = rhs.m_value;
return *this;
}
// Assignment from unsigned int.
volatile BitWord& operator=(unsigned int rhs) volatile
{
m_value = rhs;
return *this;
}
// Given a bit index, sets that bit in the BitWord.
// Forces index into valid range first.
void setBit(unsigned int index) volatile
{
index &= mask;
m_pBit[index] = 1;
}
// Given a bit index, clears that bit in the BitWord.
// Forces index into valid range first.
void clearBit(unsigned int index) volatile
{
index &= mask;
m_pBit[index] = 0;
}
// Given a bit index, reads that bit from the BitWord.
// Forces index into valid range first.
unsigned int readBit(unsigned int index) const volatile
{
index &= mask;
return m_pBit[index];
}
#ifdef NO_PORTABILITY_ISSUES
// Beware! Bit-indexing is not easy to re-implement on
// microcontrollers without bit-banding.
// Allows indexing of a BitWord object, e.g...
// BitWord x, y = 0x5a5a5a5aU;
// x[8] = y[3];
// Forces index into valid range first.
volatile unsigned int& operator[](unsigned int index) volatile
{
index &= mask;
return m_pBit[index];
}
#endif
private:
// Storage for the word-sized operand.
volatile unsigned int m_value;
// The aliased base address of m_value.
volatile unsigned int * const m_pBit;
};
}
#endif // SWI_BIT_WORD