bitfield.hh revision 4258:a84b8cce90ce
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 *          Nathan Binkert
30 */
31
32#ifndef __BASE_BITFIELD_HH__
33#define __BASE_BITFIELD_HH__
34
35#include <inttypes.h>
36
37/**
38 * Generate a 64-bit mask of 'nbits' 1s, right justified.
39 */
40inline uint64_t
41mask(int nbits)
42{
43    return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1;
44}
45
46
47
48/**
49 * Extract the bitfield from position 'first' to 'last' (inclusive)
50 * from 'val' and right justify it.  MSB is numbered 63, LSB is 0.
51 */
52template <class T>
53inline
54T
55bits(T val, int first, int last)
56{
57    int nbits = first - last + 1;
58    return (val >> last) & mask(nbits);
59}
60
61/**
62 * Mask off the given bits in place like bits() but without shifting.
63 * msb = 63, lsb = 0
64 */
65template <class T>
66inline
67T
68mbits(T val, int first, int last)
69{
70    return val & (mask(first+1) & ~mask(last));
71}
72
73inline uint64_t
74mask(int first, int last)
75{
76    return mbits((uint64_t)-1LL, first, last);
77}
78
79/**
80 * Sign-extend an N-bit value to 64 bits.
81 */
82template <int N>
83inline
84int64_t
85sext(uint64_t val)
86{
87    int sign_bit = bits(val, N-1, N-1);
88    return sign_bit ? (val | ~mask(N)) : val;
89}
90
91/**
92 * Return val with bits first to last set to bit_val
93 */
94template <class T, class B>
95inline
96T
97insertBits(T val, int first, int last, B bit_val)
98{
99    T bmask = mask(first - last + 1) << last;
100    return ((bit_val << last) & bmask) | (val & ~bmask);
101}
102
103/**
104 * A convenience function to replace bits first to last of val with bit_val
105 * in place.
106 */
107template <class T, class B>
108inline
109void
110replaceBits(T& val, int first, int last, B bit_val)
111{
112    val = insertBits(val, first, last, bit_val);
113}
114
115/**
116 * Returns the bit position of the MSB that is set in the input
117 */
118inline
119int
120findMsbSet(uint64_t val) {
121    int msb = 0;
122    if (!val)
123        return 0;
124    if (bits(val, 63,32)) { msb += 32; val >>= 32; }
125    if (bits(val, 31,16)) { msb += 16; val >>= 16; }
126    if (bits(val, 15,8))  { msb += 8;  val >>= 8;  }
127    if (bits(val, 7,4))   { msb += 4;  val >>= 4;  }
128    if (bits(val, 3,2))   { msb += 2;  val >>= 2;  }
129    if (bits(val, 1,1))   { msb += 1; }
130    return msb;
131}
132
133namespace BitfieldBackend
134{
135    template<class Data>
136    class BitfieldBase
137    {
138      protected:
139        Data __data;
140
141        inline uint64_t
142        getBits(int first, int last)
143        {
144            return bits(__data, first, last);
145        }
146
147        inline void
148        setBits(int first, int last, uint64_t val)
149        {
150            replaceBits(__data, first, last, val);
151        }
152    };
153
154    template<class Type, class Base>
155    class _BitfieldRO : public Base
156    {
157      public:
158        operator const Type ()
159        {
160            return *((Base *)this);
161        }
162    };
163
164    template<class Type, class Base>
165    class _BitfieldWO : public Base
166    {
167      public:
168        const Type operator = (const Type & _data)
169        {
170            *((Base *)this) = _data;
171            return _data;
172        }
173    };
174
175    template<class Data, int first, int last=first>
176    class _Bitfield : public BitfieldBase<Data>
177    {
178      public:
179        operator const Data ()
180        {
181            return this->getBits(first, last);
182        }
183
184        const Data
185        operator = (const Data & _data)
186        {
187            this->setBits(first, last, _data);
188            return _data;
189        }
190    };
191
192    template <class Type, class Base>
193    class BitUnionOperators : public Base
194    {
195      public:
196        operator const Type ()
197        {
198            return Base::__data;
199        }
200
201        const Type
202        operator = (const Type & _data)
203        {
204            Base::__data = _data;
205        }
206
207        bool
208        operator < (const Base & base)
209        {
210            return Base::__data < base.__data;
211        }
212
213        bool
214        operator == (const Base & base)
215        {
216            return Base::__data == base.__data;
217        }
218    };
219}
220
221#define __BitUnion(type, name) \
222    namespace BitfieldUnderlyingClasses \
223    { \
224        class name; \
225    } \
226    class BitfieldUnderlyingClasses::name { \
227      public: \
228        typedef type __DataType; \
229        union { \
230            type __data;\
231
232#define EndBitUnion(name) \
233        }; \
234    }; \
235    typedef BitfieldBackend::BitUnionOperators< \
236        BitfieldUnderlyingClasses::name::__DataType, \
237        BitfieldUnderlyingClasses::name> name;
238
239#define __SubBitUnion(type, name) \
240        union { \
241            type __data; \
242            inline operator const __DataType () \
243            { return __data; } \
244            \
245            inline const __DataType operator = (const __DataType & _data) \
246            { __data = _data; }
247
248#define EndSubBitUnion(name) } name;
249
250//This is so we can send in parameters with commas
251#define wrap(guts) guts
252
253//Read only bitfields
254#define __BitfieldRO(base) \
255    BitfieldBackend::_BitfieldRO<__DataType, base>
256#define __SubBitUnionRO(name, base) \
257    __SubBitUnion(wrap(_BitfieldRO<__DataType, base>), name)
258
259//Write only bitfields
260#define __BitfieldWO(base) \
261    BitfieldBackend::_BitfieldWO<__DataType, base>
262#define __SubBitUnionWO(name, base) \
263    __SubBitUnion(wrap(_BitfieldWO<__DataType, base>), name)
264
265//Regular bitfields
266#define Bitfield(first, last) \
267    BitfieldBackend::_Bitfield<__DataType, first, last>
268#define SubBitUnion(name, first, last) \
269    __SubBitUnion(Bitfield(first, last), name)
270#define BitfieldRO(first, last) __BitfieldRO(Bitfield(first, last))
271#define SubBitUnionRO(name, first, last) \
272    __SubBitUnionRO(Bitfield(first, last), name)
273#define BitfieldWO(first, last) __BitfieldWO(Bitfield(first, last))
274#define SubBitUnionWO(name, first, last) \
275    __SubBitUnionWO(Bitfield(first, last), name)
276
277#define BitUnion(type, name) __BitUnion(type, name)
278
279#define BitUnion64(name) __BitUnion(uint64_t, name)
280#define BitUnion32(name) __BitUnion(uint32_t, name)
281#define BitUnion16(name) __BitUnion(uint16_t, name)
282#define BitUnion8(name) __BitUnion(uint8_t, name)
283
284#endif // __BASE_BITFIELD_HH__
285