bitfield.hh revision 4262
12SN/A/*
21762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292665Ssaidi@eecs.umich.edu *          Nathan Binkert
302SN/A */
312SN/A
321112SN/A#ifndef __BASE_BITFIELD_HH__
331112SN/A#define __BASE_BITFIELD_HH__
342SN/A
353386Sgblack@eecs.umich.edu#include <inttypes.h>
362SN/A
372SN/A/**
382SN/A * Generate a 64-bit mask of 'nbits' 1s, right justified.
392SN/A */
402SN/Ainline uint64_t
412SN/Amask(int nbits)
422SN/A{
432SN/A    return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1;
442SN/A}
452SN/A
462SN/A
474070Ssaidi@eecs.umich.edu
482SN/A/**
492SN/A * Extract the bitfield from position 'first' to 'last' (inclusive)
502SN/A * from 'val' and right justify it.  MSB is numbered 63, LSB is 0.
512SN/A */
522SN/Atemplate <class T>
532SN/Ainline
542SN/AT
552SN/Abits(T val, int first, int last)
562SN/A{
572SN/A    int nbits = first - last + 1;
582SN/A    return (val >> last) & mask(nbits);
592SN/A}
602SN/A
612SN/A/**
623814Ssaidi@eecs.umich.edu * Mask off the given bits in place like bits() but without shifting.
633814Ssaidi@eecs.umich.edu * msb = 63, lsb = 0
643814Ssaidi@eecs.umich.edu */
653814Ssaidi@eecs.umich.edutemplate <class T>
663814Ssaidi@eecs.umich.eduinline
673814Ssaidi@eecs.umich.eduT
683814Ssaidi@eecs.umich.edumbits(T val, int first, int last)
693814Ssaidi@eecs.umich.edu{
703814Ssaidi@eecs.umich.edu    return val & (mask(first+1) & ~mask(last));
713814Ssaidi@eecs.umich.edu}
723814Ssaidi@eecs.umich.edu
734070Ssaidi@eecs.umich.eduinline uint64_t
744070Ssaidi@eecs.umich.edumask(int first, int last)
754070Ssaidi@eecs.umich.edu{
764070Ssaidi@eecs.umich.edu    return mbits((uint64_t)-1LL, first, last);
774070Ssaidi@eecs.umich.edu}
784070Ssaidi@eecs.umich.edu
793814Ssaidi@eecs.umich.edu/**
802SN/A * Sign-extend an N-bit value to 64 bits.
812SN/A */
822SN/Atemplate <int N>
832SN/Ainline
842SN/Aint64_t
852SN/Asext(uint64_t val)
862SN/A{
872SN/A    int sign_bit = bits(val, N-1, N-1);
882SN/A    return sign_bit ? (val | ~mask(N)) : val;
892SN/A}
902SN/A
913422Sgblack@eecs.umich.edu/**
923422Sgblack@eecs.umich.edu * Return val with bits first to last set to bit_val
933422Sgblack@eecs.umich.edu */
943422Sgblack@eecs.umich.edutemplate <class T, class B>
953422Sgblack@eecs.umich.eduinline
963422Sgblack@eecs.umich.eduT
973422Sgblack@eecs.umich.eduinsertBits(T val, int first, int last, B bit_val)
983422Sgblack@eecs.umich.edu{
993422Sgblack@eecs.umich.edu    T bmask = mask(first - last + 1) << last;
1003422Sgblack@eecs.umich.edu    return ((bit_val << last) & bmask) | (val & ~bmask);
1013422Sgblack@eecs.umich.edu}
1023422Sgblack@eecs.umich.edu
1033422Sgblack@eecs.umich.edu/**
1043422Sgblack@eecs.umich.edu * A convenience function to replace bits first to last of val with bit_val
1053422Sgblack@eecs.umich.edu * in place.
1063422Sgblack@eecs.umich.edu */
1073422Sgblack@eecs.umich.edutemplate <class T, class B>
1083422Sgblack@eecs.umich.eduinline
1093422Sgblack@eecs.umich.eduvoid
1103422Sgblack@eecs.umich.edureplaceBits(T& val, int first, int last, B bit_val)
1113422Sgblack@eecs.umich.edu{
1123422Sgblack@eecs.umich.edu    val = insertBits(val, first, last, bit_val);
1133422Sgblack@eecs.umich.edu}
1143422Sgblack@eecs.umich.edu
1154103Ssaidi@eecs.umich.edu/**
1164103Ssaidi@eecs.umich.edu * Returns the bit position of the MSB that is set in the input
1174103Ssaidi@eecs.umich.edu */
1184103Ssaidi@eecs.umich.eduinline
1194103Ssaidi@eecs.umich.eduint
1204103Ssaidi@eecs.umich.edufindMsbSet(uint64_t val) {
1214103Ssaidi@eecs.umich.edu    int msb = 0;
1224103Ssaidi@eecs.umich.edu    if (!val)
1234103Ssaidi@eecs.umich.edu        return 0;
1244244Ssaidi@eecs.umich.edu    if (bits(val, 63,32)) { msb += 32; val >>= 32; }
1254244Ssaidi@eecs.umich.edu    if (bits(val, 31,16)) { msb += 16; val >>= 16; }
1264244Ssaidi@eecs.umich.edu    if (bits(val, 15,8))  { msb += 8;  val >>= 8;  }
1274244Ssaidi@eecs.umich.edu    if (bits(val, 7,4))   { msb += 4;  val >>= 4;  }
1284244Ssaidi@eecs.umich.edu    if (bits(val, 3,2))   { msb += 2;  val >>= 2;  }
1294244Ssaidi@eecs.umich.edu    if (bits(val, 1,1))   { msb += 1; }
1304103Ssaidi@eecs.umich.edu    return msb;
1314103Ssaidi@eecs.umich.edu}
1324103Ssaidi@eecs.umich.edu
1334259Sgblack@eecs.umich.edu//	The following implements the BitUnion system of defining bitfields
1344262Sgblack@eecs.umich.edu//on top of an underlying class. This is done through the pervasive use of
1354259Sgblack@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage.
1364259Sgblack@eecs.umich.edu//Since they're unioned with each other, all of these storage locations
1374259Sgblack@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data
1384262Sgblack@eecs.umich.edu//without having to have access to each other. More details are provided with the
1394259Sgblack@eecs.umich.edu//individual components.
1404259Sgblack@eecs.umich.edu
1414259Sgblack@eecs.umich.edu//This namespace is for classes which implement the backend of the BitUnion
1424262Sgblack@eecs.umich.edu//stuff. Don't use any of these directly, except for the Bitfield classes in
1434262Sgblack@eecs.umich.edu//the *BitfieldTypes class(es).
1444258Sgblack@eecs.umich.edunamespace BitfieldBackend
1454257Sgblack@eecs.umich.edu{
1464259Sgblack@eecs.umich.edu    //A base class for all bitfields. It instantiates the actual storage,
1474259Sgblack@eecs.umich.edu    //and provides getBits and setBits functions for manipulating it. The
1484259Sgblack@eecs.umich.edu    //Data template parameter is type of the underlying storage.
1494258Sgblack@eecs.umich.edu    template<class Data>
1504258Sgblack@eecs.umich.edu    class BitfieldBase
1514258Sgblack@eecs.umich.edu    {
1524258Sgblack@eecs.umich.edu      protected:
1534258Sgblack@eecs.umich.edu        Data __data;
1544103Ssaidi@eecs.umich.edu
1554259Sgblack@eecs.umich.edu        //This function returns a range of bits from the underlying storage.
1564259Sgblack@eecs.umich.edu        //It relies on the "bits" function above. It's the user's
1574259Sgblack@eecs.umich.edu        //responsibility to make sure that there is a properly overloaded
1584259Sgblack@eecs.umich.edu        //version of this function for whatever type they want to overlay.
1594258Sgblack@eecs.umich.edu        inline uint64_t
1604258Sgblack@eecs.umich.edu        getBits(int first, int last)
1614258Sgblack@eecs.umich.edu        {
1624258Sgblack@eecs.umich.edu            return bits(__data, first, last);
1634258Sgblack@eecs.umich.edu        }
1644258Sgblack@eecs.umich.edu
1654259Sgblack@eecs.umich.edu        //Similar to the above, but for settings bits with replaceBits.
1664258Sgblack@eecs.umich.edu        inline void
1674258Sgblack@eecs.umich.edu        setBits(int first, int last, uint64_t val)
1684258Sgblack@eecs.umich.edu        {
1694258Sgblack@eecs.umich.edu            replaceBits(__data, first, last, val);
1704258Sgblack@eecs.umich.edu        }
1714258Sgblack@eecs.umich.edu    };
1724258Sgblack@eecs.umich.edu
1734262Sgblack@eecs.umich.edu    //This class contains all the "regular" bitfield classes. It is inherited
1744262Sgblack@eecs.umich.edu    //by all BitUnions which give them access to those types.
1754262Sgblack@eecs.umich.edu    template<class Type>
1764262Sgblack@eecs.umich.edu    class RegularBitfieldTypes
1774257Sgblack@eecs.umich.edu    {
1784262Sgblack@eecs.umich.edu      protected:
1794262Sgblack@eecs.umich.edu        //This class implements ordinary bitfields, that is a span of bits
1804262Sgblack@eecs.umich.edu        //who's msb is "first", and who's lsb is "last".
1814262Sgblack@eecs.umich.edu        template<int first, int last=first>
1824262Sgblack@eecs.umich.edu        class Bitfield : public BitfieldBase<Type>
1834262Sgblack@eecs.umich.edu        {
1844262Sgblack@eecs.umich.edu          public:
1854262Sgblack@eecs.umich.edu            operator const Type ()
1864262Sgblack@eecs.umich.edu            {
1874262Sgblack@eecs.umich.edu                return this->getBits(first, last);
1884262Sgblack@eecs.umich.edu            }
1894261Sgblack@eecs.umich.edu
1904262Sgblack@eecs.umich.edu            const Type
1914262Sgblack@eecs.umich.edu            operator=(const Type & _data)
1924262Sgblack@eecs.umich.edu            {
1934262Sgblack@eecs.umich.edu                this->setBits(first, last, _data);
1944262Sgblack@eecs.umich.edu                return _data;
1954262Sgblack@eecs.umich.edu            }
1964262Sgblack@eecs.umich.edu        };
1974262Sgblack@eecs.umich.edu
1984262Sgblack@eecs.umich.edu        //A class which specializes the above so that it can only be read
1994262Sgblack@eecs.umich.edu        //from. This is accomplished explicitly making sure the assignment
2004262Sgblack@eecs.umich.edu        //operator is blocked. The conversion operator is carried through
2014262Sgblack@eecs.umich.edu        //inheritance. This will unfortunately need to be copied into each
2024262Sgblack@eecs.umich.edu        //bitfield type due to limitations with how templates work
2034262Sgblack@eecs.umich.edu        template<int first, int last=first>
2044262Sgblack@eecs.umich.edu        class BitfieldRO : public Bitfield<first, last>
2054258Sgblack@eecs.umich.edu        {
2064262Sgblack@eecs.umich.edu          private:
2074262Sgblack@eecs.umich.edu            const Type
2084262Sgblack@eecs.umich.edu            operator=(const Type & _data);
2094262Sgblack@eecs.umich.edu        };
2104262Sgblack@eecs.umich.edu
2114262Sgblack@eecs.umich.edu        //Similar to the above, but only allows writing.
2124262Sgblack@eecs.umich.edu        template<int first, int last=first>
2134262Sgblack@eecs.umich.edu        class BitfieldWO : public Bitfield<first, last>
2144262Sgblack@eecs.umich.edu        {
2154262Sgblack@eecs.umich.edu          private:
2164262Sgblack@eecs.umich.edu            operator const Type ();
2174262Sgblack@eecs.umich.edu
2184262Sgblack@eecs.umich.edu          public:
2194262Sgblack@eecs.umich.edu            const Type operator=(const Type & _data)
2204262Sgblack@eecs.umich.edu            {
2214262Sgblack@eecs.umich.edu                *((Bitfield<first, last> *)this) = _data;
2224262Sgblack@eecs.umich.edu                return _data;
2234262Sgblack@eecs.umich.edu            }
2244262Sgblack@eecs.umich.edu        };
2254258Sgblack@eecs.umich.edu    };
2264257Sgblack@eecs.umich.edu
2274262Sgblack@eecs.umich.edu    template<class Type>
2284262Sgblack@eecs.umich.edu    class BitfieldTypes : public RegularBitfieldTypes<Type>
2294262Sgblack@eecs.umich.edu    {};
2304258Sgblack@eecs.umich.edu
2314259Sgblack@eecs.umich.edu    //When a BitUnion is set up, an underlying class is created which holds
2324259Sgblack@eecs.umich.edu    //the actual union. This class then inherits from it, and provids the
2334259Sgblack@eecs.umich.edu    //implementations for various operators. Setting things up this way
2344259Sgblack@eecs.umich.edu    //prevents having to redefine these functions in every different BitUnion
2354259Sgblack@eecs.umich.edu    //type. More operators could be implemented in the future, as the need
2364259Sgblack@eecs.umich.edu    //arises.
2374258Sgblack@eecs.umich.edu    template <class Type, class Base>
2384258Sgblack@eecs.umich.edu    class BitUnionOperators : public Base
2394257Sgblack@eecs.umich.edu    {
2404258Sgblack@eecs.umich.edu      public:
2414258Sgblack@eecs.umich.edu        operator const Type ()
2424258Sgblack@eecs.umich.edu        {
2434258Sgblack@eecs.umich.edu            return Base::__data;
2444258Sgblack@eecs.umich.edu        }
2454257Sgblack@eecs.umich.edu
2464258Sgblack@eecs.umich.edu        const Type
2474260Sgblack@eecs.umich.edu        operator=(const Type & _data)
2484258Sgblack@eecs.umich.edu        {
2494258Sgblack@eecs.umich.edu            Base::__data = _data;
2504258Sgblack@eecs.umich.edu        }
2514257Sgblack@eecs.umich.edu
2524258Sgblack@eecs.umich.edu        bool
2534260Sgblack@eecs.umich.edu        operator<(const Base & base)
2544258Sgblack@eecs.umich.edu        {
2554258Sgblack@eecs.umich.edu            return Base::__data < base.__data;
2564258Sgblack@eecs.umich.edu        }
2574257Sgblack@eecs.umich.edu
2584258Sgblack@eecs.umich.edu        bool
2594260Sgblack@eecs.umich.edu        operator==(const Base & base)
2604258Sgblack@eecs.umich.edu        {
2614258Sgblack@eecs.umich.edu            return Base::__data == base.__data;
2624258Sgblack@eecs.umich.edu        }
2634258Sgblack@eecs.umich.edu    };
2644258Sgblack@eecs.umich.edu}
2654257Sgblack@eecs.umich.edu
2664259Sgblack@eecs.umich.edu//This macro is a backend for other macros that specialize it slightly.
2674259Sgblack@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
2684259Sgblack@eecs.umich.edu//sticks the class which has the actual union in it, which
2694259Sgblack@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special
2704259Sgblack@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long
2714259Sgblack@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses
2724259Sgblack@eecs.umich.edu//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
2734259Sgblack@eecs.umich.edu//creates a typedef of the "type" parameter called __DataType. This allows
2744259Sgblack@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way.
2754259Sgblack@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to
2764259Sgblack@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by
2774259Sgblack@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained
2784259Sgblack@eecs.umich.edu//above, these is overlayed the __data member in its entirety by each of the
2794259Sgblack@eecs.umich.edu//bitfields which are defined in the union, creating shared storage with no
2804259Sgblack@eecs.umich.edu//overhead.
2814257Sgblack@eecs.umich.edu#define __BitUnion(type, name) \
2824258Sgblack@eecs.umich.edu    namespace BitfieldUnderlyingClasses \
2834258Sgblack@eecs.umich.edu    { \
2844258Sgblack@eecs.umich.edu        class name; \
2854258Sgblack@eecs.umich.edu    } \
2864262Sgblack@eecs.umich.edu    class BitfieldUnderlyingClasses::name : \
2874262Sgblack@eecs.umich.edu        public BitfieldBackend::BitfieldTypes<type> \
2884262Sgblack@eecs.umich.edu    { \
2894257Sgblack@eecs.umich.edu      public: \
2904257Sgblack@eecs.umich.edu        typedef type __DataType; \
2914257Sgblack@eecs.umich.edu        union { \
2924257Sgblack@eecs.umich.edu            type __data;\
2934257Sgblack@eecs.umich.edu
2944259Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is
2954259Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator
2964259Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes
2974259Sgblack@eecs.umich.edu//building up the type for the user.
2984257Sgblack@eecs.umich.edu#define EndBitUnion(name) \
2994257Sgblack@eecs.umich.edu        }; \
3004257Sgblack@eecs.umich.edu    }; \
3014258Sgblack@eecs.umich.edu    typedef BitfieldBackend::BitUnionOperators< \
3024258Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses::name::__DataType, \
3034258Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses::name> name;
3044257Sgblack@eecs.umich.edu
3054259Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The
3064259Sgblack@eecs.umich.edu//__data member functions like the "underlying storage" of the top level
3074259Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so
3084259Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a
3094262Sgblack@eecs.umich.edu//regular bitfield when referred to by itself.
3104262Sgblack@eecs.umich.edu#define __SubBitUnion(fieldType, first, last, name) \
3114262Sgblack@eecs.umich.edu    class : public BitfieldBackend::BitfieldTypes<__DataType> \
3124262Sgblack@eecs.umich.edu    { \
3134262Sgblack@eecs.umich.edu      public: \
3144257Sgblack@eecs.umich.edu        union { \
3154262Sgblack@eecs.umich.edu            fieldType<first, last> __data;
3164257Sgblack@eecs.umich.edu
3174259Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top
3184259Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type.
3194262Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for
3204262Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please
3214262Sgblack@eecs.umich.edu//do so.
3224262Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \
3234262Sgblack@eecs.umich.edu        }; \
3244262Sgblack@eecs.umich.edu        inline operator const __DataType () \
3254262Sgblack@eecs.umich.edu        { return __data; } \
3264262Sgblack@eecs.umich.edu        \
3274262Sgblack@eecs.umich.edu        inline const __DataType operator = (const __DataType & _data) \
3284262Sgblack@eecs.umich.edu        { __data = _data; } \
3294262Sgblack@eecs.umich.edu    } name;
3304258Sgblack@eecs.umich.edu
3314258Sgblack@eecs.umich.edu//Regular bitfields
3324262Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3334258Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \
3344262Sgblack@eecs.umich.edu    __SubBitUnion(Bitfield, first, last, name)
3354257Sgblack@eecs.umich.edu
3364259Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields.
3374257Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name)
3384257Sgblack@eecs.umich.edu
3394259Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields.
3404257Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name)
3414257Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name)
3424257Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name)
3434257Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name)
3444103Ssaidi@eecs.umich.edu
3451112SN/A#endif // __BASE_BITFIELD_HH__
346