// vi:set ft=cpp: -*- Mode: C++ -*- /* * (c) 2012 Alexander Warg , * economic rights: Technische Universität Dresden (Germany) * * This file is part of TUD:OS and distributed under the terms of the * GNU General Public License 2. * Please see the COPYING-GPL-2 file for details. * * As a special exception, you may use this file as part of a free software * library without restriction. Specifically, if other files instantiate * templates or use macros or inline functions from this file, or you compile * this file and link it with other files to produce an executable, this * file does not by itself cause the resulting executable to be covered by * the GNU General Public License. This exception does not however * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. */ #pragma once #include "type_list" /** Our C++ library. */ namespace cxx { /** * Definition for a member (part) of a bit field. * * \param T The underlying type of the bit field. * \param LSB The least significant bit of our bits. * \param MSB The most significant bit of our bits. */ template class Bitfield { private: static_assert(MSB >= LSB, "boundary mismatch in bit-field definition"); static_assert(MSB < sizeof(T) * 8, "MSB outside of bit-field type"); static_assert(LSB < sizeof(T) * 8, "LSB outside of bit-field type"); /** * Get the best unsigned type for `bits`. * * \param BITS Number of bits to cover. */ template struct Best_type { template< typename TY > struct Cmp { enum { value = (BITS <= sizeof(TY)*8) }; }; typedef cxx::type_list< unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long > Unsigned_types; typedef typename cxx::find_type::type Type; }; public: enum { Bits = MSB + 1 - LSB, ///< Number of bits Lsb = LSB, ///< index of the LSB Msb = MSB, ///< index of the MSB }; enum Masks : T { /** Mask value to get #Bits bits. */ Low_mask = ((T)~0ULL) >> (sizeof(T)*8 - Bits), /** Mask value to the bits out of a `T`. */ Mask = Low_mask << Lsb, }; /** * Type to hold at least #Bits bits. * * This type can handle all values that can be stored in this part of the bit * field. */ typedef typename Best_type::Type Bits_type; /** * Type to hold at least #Bits + #Lsb bits. * * This type can handle all values that can be stored in this part of the bit * field when they are at the target location (#Lsb bits shifted to the left). */ typedef typename Best_type::Type Shift_type; private: static_assert(sizeof(Bits_type)*8 >= Bits, "error finding the type to store the bits"); static_assert(sizeof(Shift_type)*8 >= Bits + Lsb, "error finding the type to keep the shifted bits"); static_assert(sizeof(Bits_type) <= sizeof(T), "size mismatch for Bits_type"); static_assert(sizeof(Shift_type) <= sizeof(T), "size mismatch for Shift_type"); static_assert(sizeof(Bits_type) <= sizeof(Shift_type), "size mismacht for Shift_type and Bits_type"); public: /** * Get the bits out of `val`. * * \param val The raw value of the whole bit field. * * \return The bits form #Lsb to #Msb shifted to the right. */ static Bits_type get(Shift_type val) { return (val >> Lsb) & Low_mask; } /** * Get the bits in place out of `val`. * * \param val The raw value of the whole bit field. * * \return The bits from #Lsb to #Msb (unshifted). * * This means other bits are masked out, however the result is not shifted to * the right. */ static T get_unshifted(Shift_type val) { return val & Mask; } /** * Set the bits corresponding to `val`. * * \param dest The current value of the whole bit field. * \param val The value to set into the bits. * * \return The new value of the whole bit field. * * \pre `val` must not contain more than #Bits bits. * * \note This function does not mask `val` to the right number of bits. */ static T set_dirty(T dest, Shift_type val) { //assert (!(val & ~Low_mask)); return (dest & ~Mask) | (val << Lsb); } /** * Set the bits corresponding to `val`. * * \param dest The current value of the whole bit field. * \param val The value shifted #Lsb bits to the left that shall be set into * the bits. * * \return The new value of the whole bit field. * * \pre `val` must not contain more than #Bits bits shifted #Lsb bits to the * left. * * \note This function does not mask `val` to the right number of bits. */ static T set_unshifted_dirty(T dest, Shift_type val) { //assert (!(val & ~Mask)); return (dest & ~Mask) | val; } /** * Set the bits corresponding to `val`. * * \param dest The current value of the whole bit field. * \param val The value to set into the bits. * * \return The new value of the whole bit field. */ static T set(T dest, Bits_type val) { return set_dirty(dest, val & Low_mask); } /** * Set the bits corresponding to `val`. * * \param dest The current value of the whole bit field. * \param val The value shifted #Lsb bits to the left that shall be set into * the bit field. * * \return the new value of the whole bit field. */ static T set_unshifted(T dest, Shift_type val) { return set_unshifted_dirty(dest, val & Mask); } /** * Get the shifted bits for `val`. * * \param val The value to set into the bits. * * \return The raw bit field value. * * \pre `val` must not contain more than #Bits bits. * * \note This function does not mask `val` to the right number of bits. */ static T val_dirty(Shift_type val) { return val << Lsb; } /** * Get the shifted bits for `val`. * * \param val The value to set into the bits. * * \return The raw bit field value. */ static T val(Bits_type val) { return val_dirty(val & Low_mask); } /** * Get the shifted bits for `val`. * * \param val The value shifted #Lsb bits to the left that shall be set into * the bits. * * \return The raw bit field value. */ static T val_unshifted(Shift_type val) { return val & Mask; } /** Internal helper type */ template< typename TT > class Value_base { private: TT v; public: Value_base(TT t) : v(t) {} Bits_type get() const { return Bitfield::get(v); } T get_unshifted() const { return Bitfield::get_unshifted(v); } void set(Bits_type val) { v = Bitfield::set(v, val); } void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); } void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); } void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); } }; /** Internal helper type */ template< typename TT > class Value : public Value_base { public: Value(TT t) : Value_base(t) {} operator Bits_type () const { return this->get(); } Value &operator = (Bits_type val) { this->set(val); return *this; } Value &operator = (Value const &o) { this->set(o.get()); return *this; } }; /** Internal helper type */ template< typename TT > class Value_unshifted : public Value_base { public: Value_unshifted(TT t) : Value_base(t) {} operator Shift_type () const { return this->get_unshifted(); } Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; } Value_unshifted &operator = (Value_unshifted const &o) { this->set_unshifted(o.get_unshifted()); return *this; } }; /** Reference type to access the bits inside a raw bit field. */ typedef Value Ref; /** Value type to access the bits inside a raw bit field. */ typedef Value Val; /** Reference type to access the bits inside a raw bit field (in place). */ typedef Value_unshifted Ref_unshifted; /** Value type to access the bits inside a raw bit field (in place). */ typedef Value_unshifted Val_unshifted; }; #define CXX_BITFIELD_MEMBER(LSB, MSB, name, data_member) \ /** @{ */ \ /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ typedef cxx::Bitfield name ## _bfm_t; \ /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Val name() const { return data_member; } \ /** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Ref name() { return data_member; } \ /** @} */ #define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \ /** @{ */ \ /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ typedef cxx::Bitfield name ## _bfm_t; \ /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Val name() const { return data_member; } \ /** @} */ #define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \ /** @{ */ \ /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ typedef cxx::Bitfield name ## _bfm_t; \ /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \ /** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Ref_unshifted name() { return data_member; } \ /** @} */ #define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \ /** @{ */ \ /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ typedef cxx::Bitfield name ## _bfm_t; \ /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \ /** @} */ }