1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2012 Alexander Warg <warg@os.inf.tu-dresden.de>, 4 * economic rights: Technische Universität Dresden (Germany) 5 * 6 * This file is part of TUD:OS and distributed under the terms of the 7 * GNU General Public License 2. 8 * Please see the COPYING-GPL-2 file for details. 9 * 10 * As a special exception, you may use this file as part of a free software 11 * library without restriction. Specifically, if other files instantiate 12 * templates or use macros or inline functions from this file, or you compile 13 * this file and link it with other files to produce an executable, this 14 * file does not by itself cause the resulting executable to be covered by 15 * the GNU General Public License. This exception does not however 16 * invalidate any other reasons why the executable file might be covered by 17 * the GNU General Public License. 18 */ 19 20#pragma once 21 22#include "type_list" 23 24/** Our C++ library. */ 25namespace cxx { 26 27/** 28 * Definition for a member (part) of a bit field. 29 * 30 * \param T The underlying type of the bit field. 31 * \param LSB The least significant bit of our bits. 32 * \param MSB The most significant bit of our bits. 33 */ 34template<typename T, unsigned LSB, unsigned MSB> 35class Bitfield 36{ 37private: 38 static_assert(MSB >= LSB, "boundary mismatch in bit-field definition"); 39 static_assert(MSB < sizeof(T) * 8, "MSB outside of bit-field type"); 40 static_assert(LSB < sizeof(T) * 8, "LSB outside of bit-field type"); 41 42 /** 43 * Get the best unsigned type for `bits`. 44 * 45 * \param BITS Number of bits to cover. 46 */ 47 template<unsigned BITS> struct Best_type 48 { 49 template< typename TY > struct Cmp { enum { value = (BITS <= sizeof(TY)*8) }; }; 50 typedef cxx::type_list< 51 unsigned char, 52 unsigned short, 53 unsigned int, 54 unsigned long, 55 unsigned long long 56 > Unsigned_types; 57 typedef typename cxx::find_type<Unsigned_types, Cmp>::type Type; 58 }; 59 60public: 61 enum 62 { 63 Bits = MSB + 1 - LSB, ///< Number of bits 64 Lsb = LSB, ///< index of the LSB 65 Msb = MSB, ///< index of the MSB 66 }; 67 68 enum Masks : T 69 { 70 /** Mask value to get #Bits bits. */ 71 Low_mask = ((T)~0ULL) >> (sizeof(T)*8 - Bits), 72 /** Mask value to the bits out of a `T`. */ 73 Mask = Low_mask << Lsb, 74 }; 75 76 /** 77 * Type to hold at least #Bits bits. 78 * 79 * This type can handle all values that can be stored in this part of the bit 80 * field. 81 */ 82 typedef typename Best_type<Bits>::Type Bits_type; 83 84 /** 85 * Type to hold at least #Bits + #Lsb bits. 86 * 87 * This type can handle all values that can be stored in this part of the bit 88 * field when they are at the target location (#Lsb bits shifted to the left). 89 */ 90 typedef typename Best_type<Bits + Lsb>::Type Shift_type; 91 92private: 93 static_assert(sizeof(Bits_type)*8 >= Bits, "error finding the type to store the bits"); 94 static_assert(sizeof(Shift_type)*8 >= Bits + Lsb, "error finding the type to keep the shifted bits"); 95 static_assert(sizeof(Bits_type) <= sizeof(T), "size mismatch for Bits_type"); 96 static_assert(sizeof(Shift_type) <= sizeof(T), "size mismatch for Shift_type"); 97 static_assert(sizeof(Bits_type) <= sizeof(Shift_type), "size mismacht for Shift_type and Bits_type"); 98 99public: 100 /** 101 * Get the bits out of `val`. 102 * 103 * \param val The raw value of the whole bit field. 104 * 105 * \return The bits form #Lsb to #Msb shifted to the right. 106 */ 107 static Bits_type get(Shift_type val) 108 { return (val >> Lsb) & Low_mask; } 109 110 /** 111 * Get the bits in place out of `val`. 112 * 113 * \param val The raw value of the whole bit field. 114 * 115 * \return The bits from #Lsb to #Msb (unshifted). 116 * 117 * This means other bits are masked out, however the result is not shifted to 118 * the right. 119 */ 120 static T get_unshifted(Shift_type val) 121 { return val & Mask; } 122 123 /** 124 * Set the bits corresponding to `val`. 125 * 126 * \param dest The current value of the whole bit field. 127 * \param val The value to set into the bits. 128 * 129 * \return The new value of the whole bit field. 130 * 131 * \pre `val` must not contain more than #Bits bits. 132 * 133 * \note This function does not mask `val` to the right number of bits. 134 */ 135 static T set_dirty(T dest, Shift_type val) 136 { 137 //assert (!(val & ~Low_mask)); 138 return (dest & ~Mask) | (val << Lsb); 139 } 140 141 /** 142 * Set the bits corresponding to `val`. 143 * 144 * \param dest The current value of the whole bit field. 145 * \param val The value shifted #Lsb bits to the left that shall be set into 146 * the bits. 147 * 148 * \return The new value of the whole bit field. 149 * 150 * \pre `val` must not contain more than #Bits bits shifted #Lsb bits to the 151 * left. 152 * 153 * \note This function does not mask `val` to the right number of bits. 154 */ 155 static T set_unshifted_dirty(T dest, Shift_type val) 156 { 157 //assert (!(val & ~Mask)); 158 return (dest & ~Mask) | val; 159 } 160 161 /** 162 * Set the bits corresponding to `val`. 163 * 164 * \param dest The current value of the whole bit field. 165 * \param val The value to set into the bits. 166 * 167 * \return The new value of the whole bit field. 168 */ 169 static T set(T dest, Bits_type val) 170 { return set_dirty(dest, val & Low_mask); } 171 172 /** 173 * Set the bits corresponding to `val`. 174 * 175 * \param dest The current value of the whole bit field. 176 * \param val The value shifted #Lsb bits to the left that shall be set into 177 * the bit field. 178 * 179 * \return the new value of the whole bit field. 180 */ 181 static T set_unshifted(T dest, Shift_type val) 182 { return set_unshifted_dirty(dest, val & Mask); } 183 184 /** 185 * Get the shifted bits for `val`. 186 * 187 * \param val The value to set into the bits. 188 * 189 * \return The raw bit field value. 190 * 191 * \pre `val` must not contain more than #Bits bits. 192 * 193 * \note This function does not mask `val` to the right number of bits. 194 */ 195 static T val_dirty(Shift_type val) { return val << Lsb; } 196 197 /** 198 * Get the shifted bits for `val`. 199 * 200 * \param val The value to set into the bits. 201 * 202 * \return The raw bit field value. 203 */ 204 static T val(Bits_type val) { return val_dirty(val & Low_mask); } 205 206 /** 207 * Get the shifted bits for `val`. 208 * 209 * \param val The value shifted #Lsb bits to the left that shall be set into 210 * the bits. 211 * 212 * \return The raw bit field value. 213 */ 214 static T val_unshifted(Shift_type val) { return val & Mask; } 215 216 /** Internal helper type */ 217 template< typename TT > 218 class Value_base 219 { 220 private: 221 TT v; 222 223 public: 224 Value_base(TT t) : v(t) {} 225 Bits_type get() const { return Bitfield::get(v); } 226 T get_unshifted() const { return Bitfield::get_unshifted(v); } 227 228 void set(Bits_type val) { v = Bitfield::set(v, val); } 229 void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); } 230 void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); } 231 void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); } 232 }; 233 234 /** Internal helper type */ 235 template< typename TT > 236 class Value : public Value_base<TT> 237 { 238 public: 239 Value(TT t) : Value_base<TT>(t) {} 240 operator Bits_type () const { return this->get(); } 241 Value &operator = (Bits_type val) { this->set(val); return *this; } 242 Value &operator = (Value const &o) { this->set(o.get()); return *this; } 243 }; 244 245 /** Internal helper type */ 246 template< typename TT > 247 class Value_unshifted : public Value_base<TT> 248 { 249 public: 250 Value_unshifted(TT t) : Value_base<TT>(t) {} 251 operator Shift_type () const { return this->get_unshifted(); } 252 Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; } 253 Value_unshifted &operator = (Value_unshifted const &o) 254 { 255 this->set_unshifted(o.get_unshifted()); 256 return *this; 257 } 258 }; 259 260 /** Reference type to access the bits inside a raw bit field. */ 261 typedef Value<T&> Ref; 262 /** Value type to access the bits inside a raw bit field. */ 263 typedef Value<T const> Val; 264 265 /** Reference type to access the bits inside a raw bit field (in place). */ 266 typedef Value_unshifted<T&> Ref_unshifted; 267 /** Value type to access the bits inside a raw bit field (in place). */ 268 typedef Value_unshifted<T const> Val_unshifted; 269}; 270 271#define CXX_BITFIELD_MEMBER(LSB, MSB, name, data_member) \ 272 /** @{ */ \ 273 /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ 274 typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \ 275 /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ 276 typename name ## _bfm_t::Val name() const { return data_member; } \ 277 /** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \ 278 typename name ## _bfm_t::Ref name() { return data_member; } \ 279 /** @} */ 280 281#define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \ 282 /** @{ */ \ 283 /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ 284 typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \ 285 /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ 286 typename name ## _bfm_t::Val name() const { return data_member; } \ 287 /** @} */ 288 289#define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \ 290 /** @{ */ \ 291 /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ 292 typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \ 293 /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ 294 typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \ 295 /** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \ 296 typename name ## _bfm_t::Ref_unshifted name() { return data_member; } \ 297 /** @} */ 298 299#define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \ 300 /** @{ */ \ 301 /** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \ 302 typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \ 303 /** Get the `name` bits (LSB to MSB) of `data_member`. */ \ 304 typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \ 305 /** @} */ 306}