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}