]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/cxx/lib/tl/include/bitfield
Update
[l4.git] / l4 / pkg / l4re-core / cxx / lib / tl / include / bitfield
1 // vi: ft=cpp
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 }