// regbits: C++ templates for type-safe bit manipulation // Copyright (C) 2019,2020 Mark R. Rubin // // This file is part of regbits. // // The regbits program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // The regbits program is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // (LICENSE.txt) along with the regbits program. If not, see // #ifndef regbits_hxx #define regbits_hxx #define REGBITS_MAJOR_VERSION 1 #define REGBITS_MINOR_VERSION 1 #define REGBITS_MICRO_VERSION 0 namespace regbits { // forward refs template class Mskd; template class Copy ; template class Reg ; template class Pos { public: // friends template friend class Bits; template friend class Mskd; template friend class Shft; template friend class Copy; template friend class Reg ; // constructors // explicit constexpr Pos() : _pos(static_cast(0)) {} explicit constexpr Pos( const WORD pos) : _pos(pos) {} #ifdef REGBITS_COPY_CTOR // implementing this impacts object passing performance constexpr Pos( const Pos &other) : _pos(other._pos) {} #else Pos(const Pos &other) = default; #endif // for passing constexpr instance by value without requiring storage Pos operator+() const { return *this; // don't need: return Pos(_pos); } // resettter Pos &operator()( const WORD pos) { _pos = pos; return *this; } // assignments // Pos operator=( const Pos &other) { _pos = other._pos; return *this; } Pos operator=( const WORD word) { _pos = word; return *this; } // accessor constexpr WORD pos() const { return _pos; } // comparisons // constexpr bool operator==( const Pos other) const { return other._pos == _pos; } constexpr bool operator!=( const Pos other) const { return other._pos != _pos; } private: // do not implement this, even as private // operator WORD() {} protected: WORD _pos; }; // template class Pos template class Bits { public: // friends template friend class Mskd; template friend class Copy; template friend class Reg ; // constructors // explicit constexpr Bits() : _bits(static_cast(0)) {} explicit constexpr Bits( const WORD bits) : _bits(bits) {} constexpr Bits( const WORD bits, const Pos pos ) : _bits(bits << pos._pos) {} Bits( const Mskd mskd) : _bits(mskd._bits) {} Bits( const Reg ®) : _bits(reg._word) {} Bits( volatile const Reg ®) : _bits(reg._word) {} #ifdef REGBITS_COPY_CTOR // implementing this impacts object passing performance constexpr Bits( const Bits &other) : _bits(other._bits) {} #else Bits(const Bits &other) = default; #endif // for passing constexpr instance by value without requiring storage Bits operator+() const { return *this; // don't need: return Bits(_bits) } // resettter Bits &operator()( const WORD bits) { _bits = bits; return *this; } // assignments // Bits operator=( const Bits &other) { _bits = other._bits; return *this; } Bits operator=( const WORD bits) { _bits = bits; return *this; } Bits operator=( const Mskd mskd) { _bits = mskd._bits; return *this; } Bits operator=( const Reg ®) { _bits = reg._word; return *this; } Bits operator=( volatile const Reg ®) { _bits = reg._word; return *this; } // accessor constexpr WORD bits() const { return _bits; } // bitwise operators // constexpr Bits operator|( const Bits other) const { return Bits(_bits | other._bits); } constexpr Bits operator|( const Mskd &mskd) const { return Bits(_bits | mskd._bits); } Bits operator|=( const Bits other) { _bits |= other._bits; return *this; } constexpr Bits operator|=( const Mskd &mskd) { _bits |= mskd._bits; return *this; } constexpr Bits operator-( const Bits other) const { return Bits(_bits & ~other._bits); } constexpr Bits operator-( const Mskd &mskd) const { return Bits(_bits &~ mskd._bits); } Bits operator-=( const Bits other) { _bits = bits & ~other._bits; return *this; } constexpr Bits operator-=( const Mskd &mskd) { _bits = bits & ~mskd._bits; return *this; } // comparisons // constexpr bool operator==( const Bits other) const { return other._bits == _bits; } constexpr bool operator!=( const Bits other) const { return other._bits != _bits; } private: // do not implement this, even as private // operator WORD() {} protected: WORD _bits; }; // template class Bits template class Mskd { public: // friends template friend class Bits; template friend class Copy; template friend class Reg ; // constructors // explicit constexpr Mskd() : _mask(static_cast(0)), _bits(static_cast(0)) {} constexpr Mskd( const WORD mask, const WORD bits, const Pos pos ) : _mask(mask << pos._pos), _bits(bits << pos._pos) {} constexpr Mskd( const WORD mask, const WORD bits) : _mask(mask), _bits(bits) {} constexpr Mskd( const Bits bits) : _mask(bits._bits), _bits(bits._bits) {} #ifdef REGBITS_COPY_CTOR // implementing this impacts object passing performance constexpr Mskd( const Mskd &other) : _mask(other._mask), _bits(other._bits) {} #else Mskd(const Mskd &other) = default; #endif // for passing constexpr instance by value without requiring storage Mskd operator+() const { return Mskd(_mask, _bits); // can't have: return *this } // resettter Mskd &operator()( const WORD mask, const WORD bits) { _mask = mask; _bits = bits; return *this; } // assignments // Mskd &operator=( const Mskd &other) { _mask = other._mask; _bits = other._bits; return *this; } Mskd &operator=( const Bits &bits) { _mask = bits._bits; _bits = bits._bits; return *this; } Mskd &operator=( const Reg ®) { _bits = reg._word; // do not modify _mask return *this; } Mskd &operator=( volatile const Reg ®) { _bits = reg._word; // do not modify _mask return *this; } // accessors constexpr WORD mask() const { return _mask; } constexpr WORD bits() const { return _bits; } // bitwise operators // constexpr Mskd operator|( const Mskd other) const { return Mskd(_mask | other._mask, _bits | other._bits); } constexpr Mskd operator|( const Bits bits) const { return Mskd(_mask | bits._bits, _bits | bits._bits); } Mskd operator|=( const Mskd other) { _mask |= other._mask; _bits |= other._bits; return *this; } Mskd operator|=( const Bits bits) { _mask |= bits._bits; _bits |= bits._bits; return *this; } constexpr Mskd operator-( const Mskd other) const { return Mskd(_mask & ~other._mask, _bits & ~other._bits); } constexpr Mskd operator-( const Bits bits) const { return Mskd(_mask & ~bits._bits, _bits & ~bits._bits); } Mskd operator-=( const Mskd other) { _mask = _mask & ~other._mask; _bits = bits & ~other._bits; return *this; } Mskd operator-=( const Bits bits) { _mask = _mask & ~bits._bits; _bits = _mask & ~bits._bits; return *this; } // comparisons // constexpr bool operator==( const Mskd other) const { return other._mask == _mask && other._bits == _bits; } constexpr bool operator!=( const Mskd other) const { return other._mask != _mask || other._bits != _bits; } constexpr bool operator<( const Mskd other) const { return _bits < other._bits; } constexpr bool operator<=( const Mskd other) const { return _bits <= other._bits; } constexpr bool operator>( const Mskd other) const { return _bits > other._bits; } constexpr bool operator>=( const Mskd other) const { return _bits >= other._bits; } private: // do not implement this, even as private // operator WORD() {} protected: WORD _mask, _bits; }; // template class Mskd template class Shft { public: // friends template friend class Copy; template friend class Reg ; // constructors // explicit constexpr Shft() : _mask(static_cast(0)), _pos (static_cast(0)) {} constexpr Shft( const WORD mask, const Pos pos ) : _mask(mask << pos._pos), _pos(pos ) {} #ifdef REGBITS_COPY_CTOR // implementing this impacts object passing performance constexpr Shft( const Shft &other) : _mask(other._mask), _pos (other._pos ) {} #else Shft(const Shft &other) = default; #endif // for passing constexpr instance by value without requiring storage constexpr Shft operator+() const { return *this; } // resettter Shft &operator()( const WORD mask, const WORD pos ) { _mask = mask; _pos = pos ; return *this; } // assignments // Shft &operator=( const Shft &other) { _mask = other._mask; _pos = other._pos ; return *this; } // accessors uint32_t mask() const { return _mask; } Pos pos () const { return _pos ; } protected: uint32_t _mask; Pos _pos; }; // template class Shft template class Reg { public: // friends template friend class Bits; template friend class Mskd; template friend class Copy; // constructors // Reg() {} explicit constexpr Reg( const WORD word) : _word(word) {} constexpr Reg( const Bits bits) : _word(bits.bits()) {} constexpr Reg( const Mskd mskd) : _word(mskd.bits()) {} #ifdef REGBITS_COPY_CTOR // implementing this impacts object passing performance constexpr Reg( const Reg &other) : _word(other._word) {} #else Reg(const Reg &other) = default; #endif // for passing constexpr instance by value without requiring storage Reg operator+() volatile const { return Reg(_word); } Reg operator+() const { return Reg(_word); } // for passing all bits off static constexpr Bits zero() { return Bits(0); } // assignments // void operator=(const WORD word) volatile { _word = word; } void operator=(const WORD word) { _word = word; } void operator=(const Bits bits) volatile { _word = bits._bits; } void operator=(const Bits bits) { _word = bits._bits; } void wrt(const Bits bits) volatile { _word = bits._bits; } void wrt(const Bits bits) { _word = bits._bits; } void operator=(const Mskd &mskd) volatile { _word = mskd._bits; } void operator=(const Mskd &mskd) { _word = mskd._bits; } void wrt(const Mskd &mskd) volatile { _word = mskd._bits; } void wrt(const Mskd &mskd) { _word = mskd._bits; } void operator=(volatile const Reg ®) volatile { _word = reg._word; } void operator=(const Reg ®) { _word = reg._word; } // accessor WORD word() volatile const { return _word; } WORD word() const { return _word; } // bitwise operators // void operator|=(const Bits bits) volatile { _word |= bits._bits; } void operator|=(const Bits bits) { _word |= bits._bits; } void set(const Bits bits) volatile { _word |= bits._bits; } void set(const Bits bits) { _word |= bits._bits; } void operator|=(const Mskd &mskd) volatile { _word |= mskd._bits; } void operator|=(const Mskd &mskd) { _word |= mskd._bits; } void set(const Mskd &mskd) volatile { _word |= mskd._bits; } void set(const Mskd &mskd) { _word |= mskd._bits; } void operator-=(const Bits bits) volatile { _word &= ~bits._bits; } void operator-=(const Bits bits) { _word &= ~bits._bits; } void clr(const Bits bits) volatile { _word &= ~bits._bits; } void clr(const Bits bits) { _word &= ~bits._bits; } void operator-=(const Mskd &mskd) volatile { _word &= ~mskd._bits; } void operator-=(const Mskd &mskd) { _word &= ~mskd._bits; } void clr(const Mskd &mskd) volatile { _word &= ~mskd._bits; } void clr(const Mskd &mskd) { _word &= ~mskd._bits; } void operator^=(const Bits bits) volatile { _word ^= bits._bits; } void operator^=(const Bits bits) { _word ^= bits._bits; } void flp(const Bits bits) volatile { _word ^= bits._bits; } void flp(const Bits bits) { _word ^= bits._bits; } void operator^=(const Mskd &mskd) volatile { _word ^= mskd._bits; } void operator^=(const Mskd &mskd) { _word ^= mskd._bits; } void flp(const Mskd &mskd) volatile { _word ^= mskd._bits; } void flp(const Mskd &mskd) { _word ^= mskd._bits; } void operator/=(const Mskd &mskd) volatile { _word = (_word & ~mskd._mask) | mskd._bits; } void operator/=(const Mskd &mskd) { _word = (_word & ~mskd._mask) | mskd._bits; } void ins(const Mskd &mskd) volatile { _word = (_word & ~mskd._mask) | mskd._bits; } void ins(const Mskd &mskd) { _word = (_word & ~mskd._mask) | mskd._bits; } // extractors // Bits operator&(Bits bits) volatile const { return Bits(_word & bits._bits); } Bits operator&(Bits bits) const { return Bits(_word & bits._bits); } Mskd operator&(Mskd mskd) volatile const { return Mskd(_word & mskd._mask, mskd._mask); } Mskd operator&(Mskd mskd) const { return Mskd(_word & mskd._mask, mskd._mask); } WORD operator>>(const Shft shft) volatile const { return (_word & shft._mask) >> shft._pos._pos; } WORD operator>>(const Shft shft) const { return (_word & shft._mask) >> shft._pos._pos; } WORD shifted(const Shft shft) volatile const { return (_word & shft._mask) >> shft._pos._pos; } WORD shifted(const Shft shft) const { return (_word & shft._mask) >> shft._pos._pos; } // comparisons // bool is(const WORD word) volatile const { return word == _word; } bool is(const WORD word) const { return word == _word; } bool is(const Bits bits) volatile const { return _word == bits._bits; } bool is(const Bits bits) const { return _word == bits._bits; } bool is(const Mskd mskd) volatile const { return _word == mskd._bits; } bool is(const Mskd mskd) const { return _word == mskd._bits; } bool all(const WORD word) volatile const { return word & _word == _word; } bool all(const WORD word) const { return word & _word == _word; } bool all(const Bits bits) volatile const { return (_word & bits._bits) == bits._bits; } bool all(const Bits bits) const { return (_word & bits._bits) == bits._bits; } bool all( const Bits mask, const Bits bits) volatile const { return (_word & mask._bits) == bits._bits; } bool all( const Bits mask, const Bits bits) const { return (_word & mask._bits) == bits._bits; } bool all(const Mskd mskd) volatile const { return (_word & mskd._mask) == mskd._bits; } bool all(const Mskd mskd) const { return (_word & mskd._mask) == mskd._bits; } bool any(const WORD word) volatile const { return static_cast(word & _word); } bool any(const WORD word) const { return static_cast(word & _word); } bool any(const Bits bits) volatile const { return static_cast(_word & bits._bits); } bool any(const Bits bits) const { return static_cast(_word & bits._bits); } bool operator<(const Mskd &mskd) volatile const { return (_word & mskd._mask) < mskd._bits; } bool operator<(const Mskd &mskd) const { return (_word & mskd._mask) < mskd._bits; } bool operator<=(const Mskd &mskd) volatile const { return (_word & mskd._mask) <= mskd._bits; } bool operator<=(const Mskd &mskd) const { return (_word & mskd._mask) <= mskd._bits; } bool operator>(const Mskd &mskd) volatile const { return (_word & mskd._mask) > mskd._bits; } bool operator>(const Mskd &mskd) const { return (_word & mskd._mask) > mskd._bits; } bool operator>=(const Mskd &mskd) volatile const { return (_word & mskd._mask) >= mskd._bits; } bool operator>=(const Mskd &mskd) const { return (_word & mskd._mask) >= mskd._bits; } protected: WORD _word; private: // do not implement this, even as private // operator WORD() {} }; // template class Reg // macro for generating functions returning Bits (constexpr and non-) // assumes pos_t and bits_ have been typedef'd/using'd // #define REGBITS_BITS_RANGE(CLASS, CONSTEXPR_NAME, RUNTIME_NAME, WORD) \ template static constexpr bits_t CONSTEXPR_NAME() \ { \ static_assert(BIT_NUM < sizeof(WORD) * 8, \ CLASS "::" #CONSTEXPR_NAME " out of range"); \ return bits_t(1, pos_t(BIT_NUM)); \ } \ \ static const bits_t RUNTIME_NAME( \ const unsigned bit_num) \ { \ return bits_t(1, pos_t(bit_num)); \ } \ \ static bool RUNTIME_NAME##_valid( \ const unsigned bit_num) \ { \ return bit_num < sizeof(WORD) * 4; \ } // macro for generating functions returning Mskd (constexpr and non-) // assumes shft_t and mskd_t have been typedef'd/using'd // #define REGBITS_MSKD_RANGE(CLASS, CONSTEXPR_NAME, RUNTIME_NAME, MASK, POS, LIMIT) \ static constexpr shft_t CONSTEXPR_NAME##_SHFT = shft_t(MASK, POS); \ \ template static constexpr mskd_t CONSTEXPR_NAME() \ { \ static_assert(BITS <= (LIMIT), \ CLASS "::" #CONSTEXPR_NAME " out of range"); \ return mskd_t(MASK, BITS, POS); \ } \ \ static const mskd_t RUNTIME_NAME( \ const unsigned bits) \ { \ return mskd_t(MASK << POS.pos(), bits << POS.pos()); \ } \ \ static bool RUNTIME_NAME##_valid( \ const unsigned bits) \ { \ return bits <= (LIMIT); \ } // same as REGBITS_MSKD_RANGE but with explicit type for RUNTIME_NAME // argument if mskd_t WORD size is wider than unsigned // // #define REGBITS_MSKD_UNSGN(CLASS, UNSIGNED_TYPE, CONSTEXPR_NAME, RUNTIME_NAME, MASK, POS, LIMIT) \ static constexpr shft_t CONSTEXPR_NAME##_SHFT = shft_t(MASK, POS); \ \ template static constexpr mskd_t CONSTEXPR_NAME() \ { \ static_assert(BITS <= (LIMIT), \ CLASS "::" #CONSTEXPR_NAME " out of range"); \ return mskd_t(MASK, BITS, POS); \ } \ \ static const mskd_t RUNTIME_NAME( \ const UNSIGNED_TYPE bits) \ { \ return mskd_t(MASK << POS.pos(), bits << POS.pos()); \ } \ \ static bool RUNTIME_NAME##_valid( \ const unsigned bits) \ { \ return bits <= (LIMIT); \ } // macro for generating functions returning array member (constexpr and non-) #define REGBITS_ARRAY_RANGE(CLASS, CONSTEXPR_NAME, RUNTIME_NAME, DATATYPE, ARRAY, LIMIT) \ template volatile DATATYPE& CONSTEXPR_NAME() \ volatile { \ static_assert(INDEX <= (LIMIT), \ #CLASS "::" #CONSTEXPR_NAME " out of range"); \ return ARRAY[INDEX]; \ } \ \ volatile DATATYPE& RUNTIME_NAME( \ const unsigned index) \ volatile { \ return ARRAY[index]; \ } \ \ static bool RUNTIME_NAME##_valid( \ const unsigned index) \ { \ return index <= (LIMIT); \ } } // namespace regbits #endif // ifndef regbits_hxx