Home > ARM Cortex-M3, C/C++ > ARM Cortex Bit-Banding in C++

ARM Cortex Bit-Banding in C++

It has been a long time since I posted, so I’m posting this very technical article just to get into the swing of it again.

On LinkedIn (Cortex-M Programmers’s group) I started a discussion about accessing the bit-banding features present in many ARM Cortex-M3 chips, using C++. If you don’t know what I’m talking about, look away now!

Bit-banding gives each bit in a 32-bit word its own address in memory, allowing single-access atomic writes to each bit, instead of necessitating an explicitly protected read-modify-write operation on the word. It is quite easy to write a C++ class for this, and here is mine – less the documenting comments it ought eventually to have:

// Copyright Software Integrity Ltd., 2013
#ifndef SWI_BIT_WORD
#define SWI_BIT_WORD

namespace
{
    // Using this namespace in a header file is bad, but it
    // serves the purpose for illustration only!
    unsigned int * const pBase =  reinterpret_cast<unsigned int *>(0x20000000U);
    unsigned int * const pAlias = reinterpret_cast<unsigned int *>(0x22000000U);}
}
namespace SOFTWARE_INTEGRITY
{
    class BitWord
    {
    public:
        BitWord():
            m_value(0),
            m_pBit(pAlias + ((&m_value - pBase) << 5))
        {
        }

        BitWord(unsigned int value):
            m_value(value),
            m_pBit(pAlias + ((&m_value - pBase) << 5))
        {
        }

        BitWord(const BitWord& orig):
            m_value(orig.m_value),
            m_pBit(pAlias + ((&m_value - pBase) << 5))
        {
        }

        operator unsigned int()
        {
            return m_value;
        }

        BitWord& operator=(const BitWord& rhs)
        {
            m_value = rhs.m_value;
            return *this;
        }

        BitWord& operator=(unsigned int rhs)
        {
            m_value = rhs;
            return *this;
        }

        void setBit(unsigned int index)
        {
            index &= (32U - 1U);
            m_pBit[index] = 1;
        }

        void clearBit(unsigned int index)
        {
            index &= (32U - 1U);
            m_pBit[index] = 0;
        }

        unsigned int readBit(unsigned int index)
        {
            index &= (32U - 1U);
            return m_pBit[index];
        }

#ifdef  NO_PORTABILITY_ISSUES
        // Beware! Bit-indexing is not easy to re-implement on
        // microcotrollers without bit-banding.
        unsigned int& operator[](unsigned int index)
        {
            return m_pBit[index];
        }
#endif

    private:
        unsigned int m_value;
        unsigned int * const m_pBit;
    };
}

#endif // SWI_BIT_WORD

The harder part is actually locating the BitWord variables in the bit-banded area of memory. OK, it’s not so hard, technically. You just use whatever means the compiler provides to put the variables in their own memory section, then edit the linker script to put the section in the right place, which begins at 0x20000000. However, I’m writing library code (a real-time kernel), not an application. It’s bad enough having to tailor the code to the processor and compiler (such is life, though), but having to tell an application or system programmer I will probably never meet how to patch the provided linker script, in its own proprietary language, is a step too far – both for me and for the client.

At first, I looked at the memory map in the ARM documentation and found that the area defined for bit-banded variables was 1MB long. All the M3 chips I’ve looked at have less static RAM than this, so I naïvely thought that all chip manufacturers would put all of it in the bit-band area, thus rendering the above machinations unnecessary. But they don’t!

I found one way to solve the problem, with the ARM compiler, without the need to alter the linker script:

Kernel::ReadyList::BitWords     Kernel::ReadyList::readyPriorities 
  __attribute__((at(afterBitBand - sizeof(BitWords)))) = {0, 0};

where afterBitBand is the address just after the bit-band area. In short, I got a linker conflict if I tried to locate my stuff at the beginning of the area, so I put it at the end, instead. However, this then requires the user to supply configuration information to let me know where the end is. So much for keeping things simple!

I’ve now decided that the whole bit-banding thing is not worth the hassle, in this particular project. The performance cost of reverting to protected read-modify-write will be trivial and in one of the three circumstances where I use these variables I cannot avoid it (and already do it) in any case.

If you want to implement bit-banding in C++, for processors which support it, you are welcome to use my ideas, but I shall be rewriting my BitWord class to use more orthodox techniques.

Advertisements
Categories: ARM Cortex-M3, C/C++ Tags: ,
  1. Peter Bushell
    Tuesday, March 12, 2013 at 10:54

    I’ve just edited the BitWord class, above, to put a comment about my header-file wrongdoing in the illustrative code!

    If you want to use the class, the constants need to be defined in a better place.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: