L4Re - L4 Runtime Environment
bitfield
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 /** \brief Our C++ library. */
25 namespace cxx {
26 
27 /** \brief Definition for a member (part) of a bit field.
28  *
29  * \param T the underlying type of the bit field.
30  * \param LSB the least significant bit of our bits.
31  * \param MSB the mos significant bit if our bits.
32  */
33 template<typename T, unsigned LSB, unsigned MSB>
34 class Bitfield
35 {
36 private:
37  static_assert(MSB >= LSB, "boundary mismatch in bit-field definition");
38  static_assert(MSB < sizeof(T) * 8, "MSB outside of bit-field type");
39  static_assert(LSB < sizeof(T) * 8, "LSB outside of bit-field type");
40 
41  /** \brief Get the best unsigned type for \a bits.
42  * \param BITS number of bits to cover
43  */
44  template<unsigned BITS> struct Best_type
45  {
46  template< typename TY > struct Cmp { enum { value = (BITS <= sizeof(TY)*8) }; };
47  typedef cxx::type_list<
48  unsigned char,
49  unsigned short,
50  unsigned int,
51  unsigned long,
52  unsigned long long
53  > Unsigned_types;
54  typedef typename cxx::find_type<Unsigned_types, Cmp>::type Type;
55  };
56 
57 public:
58  enum
59  {
60  Bits = MSB + 1 - LSB, ///< Number of bits
61  Lsb = LSB, ///< index of the LSB
62  Msb = MSB, ///< index of the MSB
63  };
64 
65  enum Masks : T
66  {
67  /** Mask value to get #Bits bits. */
68  Low_mask = ((T)~0ULL) >> (sizeof(T)*8 - Bits),
69  /** Mask value to the bits out of a \a T. */
70  Mask = Low_mask << Lsb,
71  };
72 
73  /** \brief Type to hold at least #Bits bits.
74  *
75  * This type can handle all values that can be stored in this part of the bit
76  * field.
77  */
78  typedef typename Best_type<Bits>::Type Bits_type;
79 
80  /** \brief Type to hold at least #Bits + #Lsb bits.
81  *
82  * This type can handle all values that can be stored in this part of the bit
83  * field when they are at the target location (#Lsb bits shifted to the
84  * left).
85  */
86  typedef typename Best_type<Bits + Lsb>::Type Shift_type;
87 
88 private:
89  static_assert(sizeof(Bits_type)*8 >= Bits, "error finding the type to store the bits");
90  static_assert(sizeof(Shift_type)*8 >= Bits + Lsb, "error finding the type to keep the shifted bits");
91  static_assert(sizeof(Bits_type) <= sizeof(T), "size mismatch for Bits_type");
92  static_assert(sizeof(Shift_type) <= sizeof(T), "size mismatch for Shift_type");
93  static_assert(sizeof(Bits_type) <= sizeof(Shift_type), "size mismacht for Shift_type and Bits_type");
94 
95 public:
96  /** \brief Get the bits out of \a val.
97  * \param val the raw value of the whole bit field.
98  * \return the bits form #Lsb to #Msb shifted to the right.
99  */
100  static Bits_type get(Shift_type val)
101  { return (val >> Lsb) & Low_mask; }
102 
103  /** \brief Get the bits in place out of \a val.
104  * \param val the raw value of the whole bit field.
105  * \return the bits from #Lsb to #Msb (unshifted).
106  *
107  * This means other bits are masked out, however the result is not shifted to
108  * the right,
109  */
110  static T get_unshifted(Shift_type val)
111  { return val & Mask; }
112 
113  /** \brief Set the bits corresponding to \a val.
114  * \param dest the current value of the whole bit field.
115  * \param val the value to set into the bits.
116  * \return the new value of the whole bit field.
117  * \pre \a val must contain not more than bits than #Bits.
118  * \note This function does not mask \a val to the right number of bits.
119  */
120  static T set_dirty(T dest, Shift_type val)
121  {
122  //assert (!(val & ~Low_mask));
123  return (dest & ~Mask) | (val << Lsb);
124  }
125 
126  /** \brief Set the bits corresponding to \a val.
127  * \param dest the current value of the whole bit field.
128  * \param val the value shifted #Lsb bits to the left that shall be set into
129  * the bits.
130  * \return the new value of the whole bit field.
131  * \pre \a val must contain not more than bits than #Bits shifted #Lsb bits
132  * to the left.
133  * \note This function does not mask \a val to the right number of bits.
134  */
135  static T set_unshifted_dirty(T dest, Shift_type val)
136  {
137  //assert (!(val & ~Mask));
138  return (dest & ~Mask) | val;
139  }
140 
141  /** \brief Set the bits corresponding to \a val.
142  * \param dest the current value of the whole bit field.
143  * \param val the value to set into the bits.
144  * \return the new value of the whole bit field.
145  */
146  static T set(T dest, Bits_type val)
147  { return set_dirty(dest, val & Low_mask); }
148 
149  /** \brief Set the bits corresponding to \a val.
150  * \param dest the current value of the whole bit field.
151  * \param val the value shifted #Lsb bits to the left that shall be set into
152  * the bits.
153  * \return the new value of the whole bit field.
154  */
155  static T set_unshifted(T dest, Shift_type val)
156  { return set_unshifted_dirty(dest, val & Mask); }
157 
158  /** \brief Get the shifted bits for \a val.
159  * \param val the value to set into the bits.
160  * \return the raw bit field value containing.
161  * \pre \a val must contain not more than bits than #Bits.
162  * \note This function does not mask \a val to the right number of bits.
163  */
164  static T val_dirty(Shift_type val) { return val << Lsb; }
165 
166  /** \brief Get the shifted bits for \a val.
167  * \param val the value to set into the bits.
168  * \return the raw bit field value containing.
169  */
170  static T val(Bits_type val) { return val_dirty(val & Low_mask); }
171 
172  /** \brief Get the shifted bits for \a val.
173  * \param val the value shifted #Lsb bits to the left that shall be set into
174  * the bits.
175  * \return the raw bit field value containing.
176  */
177  static T val_unshifted(Shift_type val) { return val & Mask; }
178 
179  /** Internal helper type */
180  template< typename TT >
181  class Value_base
182  {
183  private:
184  TT v;
185 
186  public:
187  Value_base(TT t) : v(t) {}
188  Bits_type get() const { return Bitfield::get(v); }
189  T get_unshifted() const { return Bitfield::get_unshifted(v); }
190 
191  void set(Bits_type val) { v = Bitfield::set(v, val); }
192  void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); }
193  void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); }
194  void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); }
195  };
196 
197  /** Internal helper type */
198  template< typename TT >
199  class Value : public Value_base<TT>
200  {
201  public:
202  Value(TT t) : Value_base<TT>(t) {}
203  operator Bits_type () const { return this->get(); }
204  Value &operator = (Bits_type val) { this->set(val); return *this; }
205  };
206 
207  /** Internal helper type */
208  template< typename TT >
209  class Value_unshifted : public Value_base<TT>
210  {
211  public:
212  Value_unshifted(TT t) : Value_base<TT>(t) {}
213  operator Shift_type () const { return this->get_unshifted(); }
214  Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; }
215  };
216 
217  /** Reference type to access the bits inside a raw bit field. */
218  typedef Value<T&> Ref;
219  /** Value type to access the bits inside a raw bit field. */
220  typedef Value<T const> Val;
221 
222  /** Reference type to access the bits inside a raw bit field (in place). */
223  typedef Value_unshifted<T&> Ref_unshifted;
224  /** Value type to access the bits inside a raw bit field (in place). */
225  typedef Value_unshifted<T const> Val_unshifted;
226 };
227 
228 #define CXX_BITFIELD_MEMBER(LSB, MSB, name, data_member) \
229  /** @{ */ \
230  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
231  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
232  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
233  typename name ## _bfm_t::Val name() const { return data_member; } \
234  /** \brief Get a reference to the \a name bits (LSB to MSB) of \a data_member. */ \
235  typename name ## _bfm_t::Ref name() { return data_member; } \
236  /** @} */
237 
238 #define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \
239  /** @{ */ \
240  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
241  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
242  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
243  typename name ## _bfm_t::Val name() const { return data_member; } \
244  /** @} */
245 
246 #define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \
247  /** @{ */ \
248  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
249  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
250  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
251  typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
252  /** \brief Get a reference to the \a name bits (LSB to MSB) of \a data_member. */ \
253  typename name ## _bfm_t::Ref_unshifted name() { return data_member; } \
254  /** @} */
255 
256 #define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \
257  /** @{ */ \
258  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
259  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
260  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
261  typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
262  /** @} */
263 }