bitunion.hh revision 12454:277c1f58ab6d
12740SN/A/*
27534Ssteve.reinhardt@amd.com * Copyright (c) 2007-2008 The Regents of The University of Michigan
31046SN/A * All rights reserved.
41046SN/A *
51046SN/A * Redistribution and use in source and binary forms, with or without
61046SN/A * modification, are permitted provided that the following conditions are
71046SN/A * met: redistributions of source code must retain the above copyright
81046SN/A * notice, this list of conditions and the following disclaimer;
91046SN/A * redistributions in binary form must reproduce the above copyright
101046SN/A * notice, this list of conditions and the following disclaimer in the
111046SN/A * documentation and/or other materials provided with the distribution;
121046SN/A * neither the name of the copyright holders nor the names of its
131046SN/A * contributors may be used to endorse or promote products derived from
141046SN/A * this software without specific prior written permission.
151046SN/A *
161046SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171046SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181046SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191046SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201046SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211046SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221046SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231046SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241046SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251046SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261046SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282665SN/A * Authors: Gabe Black
292665SN/A */
301046SN/A
315766Snate@binkert.org#ifndef __BASE_BITUNION_HH__
327673Snate@binkert.org#define __BASE_BITUNION_HH__
331438SN/A
346654Snate@binkert.org#include <iostream>
356654Snate@binkert.org#include <type_traits>
366654Snate@binkert.org
376654Snate@binkert.org#include "base/bitfield.hh"
386654Snate@binkert.org
394762Snate@binkert.org//      The following implements the BitUnion system of defining bitfields
406654Snate@binkert.org//on top of an underlying class. This is done through the pervasive use of
413102Sstever@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage.
423102Sstever@eecs.umich.edu//Since they're unioned with each other, all of these storage locations
433102Sstever@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data
443102Sstever@eecs.umich.edu//without having to have access to each other. More details are provided with
456654Snate@binkert.org//the individual components.
463102Sstever@eecs.umich.edu
473102Sstever@eecs.umich.edu//This class wraps around another which defines getter/setter functions which
487528Ssteve.reinhardt@amd.com//manipulate the underlying data. The type of the underlying data and the type
497528Ssteve.reinhardt@amd.com//of the bitfield itself are inferred from the argument types of the setter
503102Sstever@eecs.umich.edu//function.
516654Snate@binkert.orgtemplate<class Base>
526654Snate@binkert.orgclass BitfieldTypeImpl : public Base
53679SN/A{
54679SN/A    static_assert(std::is_empty<Base>::value,
55679SN/A                  "Bitfield base class must be empty.");
56679SN/A
57679SN/A  private:
58679SN/A    using Base::setter;
591692SN/A
60679SN/A    template<typename T>
61679SN/A    struct TypeDeducer;
62679SN/A
63679SN/A    template<typename T>
64679SN/A    friend class TypeDeducer;
65679SN/A
66679SN/A    template<typename Type1, typename Type2>
67679SN/A    struct TypeDeducer<void (Base::*)(Type1 &, Type2)>
68679SN/A    {
69679SN/A        typedef Type1 Storage;
70679SN/A        typedef Type2 Type;
71679SN/A    };
72679SN/A
73679SN/A  protected:
741692SN/A    typedef typename TypeDeducer<
75679SN/A            decltype(&BitfieldTypeImpl<Base>::setter)>::Storage Storage;
76679SN/A    typedef typename TypeDeducer<
77679SN/A            decltype(&BitfieldTypeImpl<Base>::setter)>::Type Type;
78679SN/A
79679SN/A    Type getter(const Storage &storage) const = delete;
80679SN/A    void setter(Storage &storage, Type val) = delete;
81679SN/A
82679SN/A    Storage __storage;
83679SN/A
84679SN/A    operator Type () const
85679SN/A    {
86679SN/A        return Base::getter(__storage);
87679SN/A    }
88679SN/A
89679SN/A    Type
902740SN/A    operator=(const Type val)
91679SN/A    {
92679SN/A        Base::setter(__storage, val);
93679SN/A        return val;
944762Snate@binkert.org    }
954762Snate@binkert.org
964762Snate@binkert.org    Type
972738SN/A    operator=(BitfieldTypeImpl<Base> const & other)
982738SN/A    {
992738SN/A        return *this = (Type)other;
1007673Snate@binkert.org    }
1017675Snate@binkert.org};
1027673Snate@binkert.org
1037675Snate@binkert.org//A wrapper for the above class which allows setting and getting.
1047677Snate@binkert.orgtemplate<class Base>
1057673Snate@binkert.orgclass BitfieldType : public BitfieldTypeImpl<Base>
1067673Snate@binkert.org{
1077673Snate@binkert.org  protected:
1087673Snate@binkert.org    using Impl = BitfieldTypeImpl<Base>;
1097673Snate@binkert.org    using typename Impl::Type;
1107673Snate@binkert.org
1117673Snate@binkert.org  public:
1127673Snate@binkert.org    operator Type () const { return Impl::operator Type(); }
1137673Snate@binkert.org    Type operator=(const Type val) { return Impl::operator=(val); }
1147673Snate@binkert.org    Type
1157673Snate@binkert.org    operator=(BitfieldType<Base> const & other)
1167673Snate@binkert.org    {
1177673Snate@binkert.org        return Impl::operator=(other);
1187673Snate@binkert.org    }
1197673Snate@binkert.org};
1207673Snate@binkert.org
1217673Snate@binkert.org//A wrapper which only supports getting.
1227673Snate@binkert.orgtemplate<class Base>
1237673Snate@binkert.orgclass BitfieldROType : public BitfieldTypeImpl<Base>
1247673Snate@binkert.org{
1257673Snate@binkert.org  public:
1267673Snate@binkert.org    using Impl = BitfieldTypeImpl<Base>;
1277673Snate@binkert.org    using typename Impl::Type;
1287673Snate@binkert.org
1297811Ssteve.reinhardt@amd.com    Type operator=(BitfieldROType<Base> const &other) = delete;
1307673Snate@binkert.org    operator Type () const { return Impl::operator Type(); }
1317673Snate@binkert.org};
1327673Snate@binkert.org
1337673Snate@binkert.org//A wrapper which only supports setting.
1347673Snate@binkert.orgtemplate <class Base>
1352740SN/Aclass BitfieldWOType : public BitfieldTypeImpl<Base>
1362740SN/A{
1372740SN/A  protected:
1382740SN/A    using Impl = BitfieldTypeImpl<Base>;
1391692SN/A    using typename Impl::Type;
1401427SN/A
1417493Ssteve.reinhardt@amd.com  public:
1427493Ssteve.reinhardt@amd.com    Type operator=(const Type val) { return Impl::operator=(val); }
1437493Ssteve.reinhardt@amd.com    Type
1447673Snate@binkert.org    operator=(BitfieldWOType<Base> const & other)
1457673Snate@binkert.org    {
1467673Snate@binkert.org        return Impl::operator=(other);
1477493Ssteve.reinhardt@amd.com    }
1481427SN/A};
1497493Ssteve.reinhardt@amd.com
150679SN/A//This namespace is for classes which implement the backend of the BitUnion
151679SN/A//stuff. Don't use any of these directly.
152679SN/Anamespace BitfieldBackend
1532740SN/A{
154679SN/A    template<class Storage, int first, int last>
155679SN/A    class Unsigned
1561310SN/A    {
1576654Snate@binkert.org        static_assert(first >= last,
1584762Snate@binkert.org                      "Bitfield ranges must be specified as <msb, lsb>");
1592740SN/A
1602740SN/A      protected:
1612740SN/A        uint64_t
1622740SN/A        getter(const Storage &storage) const
1632740SN/A        {
1642740SN/A            return bits(storage, first, last);
1657673Snate@binkert.org        }
1662740SN/A
1672740SN/A        void
1682740SN/A        setter(Storage &storage, uint64_t val)
1692740SN/A        {
1704762Snate@binkert.org            replaceBits(storage, first, last, val);
1714762Snate@binkert.org        }
1722740SN/A    };
1734762Snate@binkert.org
1744762Snate@binkert.org    template<class Storage, int first, int last>
1754762Snate@binkert.org    class Signed
1764762Snate@binkert.org    {
177679SN/A        static_assert(first >= last,
1782711SN/A                      "Bitfield ranges must be specified as <msb, lsb>");
179679SN/A
1802711SN/A      protected:
1812711SN/A        int64_t
1821692SN/A        getter(const Storage &storage) const
1831310SN/A        {
1841427SN/A            return sext<first - last + 1>(bits(storage, first, last));
1852740SN/A        }
1862740SN/A
1872740SN/A        void
1882740SN/A        setter(Storage &storage, int64_t val)
1892740SN/A        {
1902740SN/A            replaceBits(storage, first, last, val);
1912740SN/A        }
1927528Ssteve.reinhardt@amd.com    };
1933105Sstever@eecs.umich.edu
1942740SN/A    //This class contains the basic bitfield types which are automatically
1951310SN/A    //available within a BitUnion. They inherit their Storage type from the
1961692SN/A    //containing BitUnion.
1971585SN/A    template<class Storage>
1981692SN/A    class BitfieldTypes
1991692SN/A    {
2001692SN/A      protected:
2011692SN/A
2021692SN/A        template<int first, int last=first>
2032740SN/A        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
2042740SN/A        template<int first, int last=first>
2052740SN/A        using BitfieldRO =
2062740SN/A                BitfieldROType<Unsigned<Storage, first, last> >;
2071692SN/A        template<int first, int last=first>
2085610Snate@binkert.org        using BitfieldWO =
2091692SN/A                BitfieldWOType<Unsigned<Storage, first, last> >;
2102740SN/A
2111692SN/A        template<int first, int last=first>
2127528Ssteve.reinhardt@amd.com        using SignedBitfield =
2133105Sstever@eecs.umich.edu                BitfieldType<Signed<Storage, first, last> >;
2142740SN/A        template<int first, int last=first>
2152712SN/A        using SignedBitfieldRO =
2165610Snate@binkert.org                BitfieldROType<Signed<Storage, first, last> >;
2175610Snate@binkert.org        template<int first, int last=first>
2181692SN/A        using SignedBitfieldWO =
2194762Snate@binkert.org                BitfieldWOType<Signed<Storage, first, last> >;
2204762Snate@binkert.org    };
2214762Snate@binkert.org
2225610Snate@binkert.org    //When a BitUnion is set up, an underlying class is created which holds
2234762Snate@binkert.org    //the actual union. This class then inherits from it, and provids the
2245610Snate@binkert.org    //implementations for various operators. Setting things up this way
2255610Snate@binkert.org    //prevents having to redefine these functions in every different BitUnion
2267673Snate@binkert.org    //type. More operators could be implemented in the future, as the need
2277673Snate@binkert.org    //arises.
2287673Snate@binkert.org    template <class Base>
2294762Snate@binkert.org    class BitUnionOperators : public Base
2307673Snate@binkert.org    {
2317675Snate@binkert.org        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
2327675Snate@binkert.org                      "BitUnion larger than its storage type.");
2334762Snate@binkert.org
2347673Snate@binkert.org      public:
2357673Snate@binkert.org        BitUnionOperators(typename Base::__StorageType const &val)
2367673Snate@binkert.org        {
2374859Snate@binkert.org            Base::__storage = val;
2382740SN/A        }
2392740SN/A
2402740SN/A        BitUnionOperators() {}
2412740SN/A
2422740SN/A        operator const typename Base::__StorageType () const
2432740SN/A        {
2442740SN/A            return Base::__storage;
2452740SN/A        }
2461527SN/A
2472740SN/A        typename Base::__StorageType
2481585SN/A        operator=(typename Base::__StorageType const &val)
2491427SN/A        {
2502738SN/A            Base::__storage = val;
2512738SN/A            return val;
2523105Sstever@eecs.umich.edu        }
2532738SN/A
2541427SN/A        typename Base::__StorageType
2551427SN/A        operator=(BitUnionOperators const &other)
2561427SN/A        {
2571427SN/A            Base::__storage = other;
2581427SN/A            return Base::__storage;
2591427SN/A        }
2601427SN/A
2611427SN/A        bool
2621427SN/A        operator<(Base const &base) const
2631427SN/A        {
2641427SN/A            return Base::__storage < base.__storage;
2651427SN/A        }
2667493Ssteve.reinhardt@amd.com
2671427SN/A        bool
2681427SN/A        operator==(Base const &base) const
2691427SN/A        {
2703100SN/A            return Base::__storage == base.__storage;
2713100SN/A        }
2723100SN/A    };
2733100SN/A}
2743100SN/A
2753100SN/A//This macro is a backend for other macros that specialize it slightly.
2763105Sstever@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
2773105Sstever@eecs.umich.edu//sticks the class which has the actual union in it, which
2783105Sstever@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special
2793105Sstever@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long
2803105Sstever@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses
2818321Ssteve.reinhardt@amd.com//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
2823105Sstever@eecs.umich.edu//creates a typedef of the "type" parameter called __StorageType. This allows
2833105Sstever@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way.
2843105Sstever@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to
2853105Sstever@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by
2863105Sstever@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained
2878321Ssteve.reinhardt@amd.com//above, these is overlayed the __storage member in its entirety by each of the
2888321Ssteve.reinhardt@amd.com//bitfields which are defined in the union, creating shared storage with no
2898321Ssteve.reinhardt@amd.com//overhead.
2908321Ssteve.reinhardt@amd.com#define __BitUnion(type, name) \
2918321Ssteve.reinhardt@amd.com    class BitfieldUnderlyingClasses##name : \
2928321Ssteve.reinhardt@amd.com        public BitfieldBackend::BitfieldTypes<type> \
2938321Ssteve.reinhardt@amd.com    { \
2948321Ssteve.reinhardt@amd.com      protected: \
2958321Ssteve.reinhardt@amd.com        typedef type __StorageType; \
2968321Ssteve.reinhardt@amd.com        friend BitfieldBackend::BitUnionBaseType< \
2978321Ssteve.reinhardt@amd.com            BitfieldBackend::BitUnionOperators< \
2988321Ssteve.reinhardt@amd.com                BitfieldUnderlyingClasses##name> >; \
2998321Ssteve.reinhardt@amd.com        friend BitfieldBackend::BitUnionBaseType< \
3008321Ssteve.reinhardt@amd.com                BitfieldUnderlyingClasses##name>; \
3013105Sstever@eecs.umich.edu      public: \
3023105Sstever@eecs.umich.edu        union { \
3033105Sstever@eecs.umich.edu            type __storage;
3043105Sstever@eecs.umich.edu
3053105Sstever@eecs.umich.edu//This closes off the class and union started by the above macro. It is
3063105Sstever@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator
3073105Sstever@eecs.umich.edu//class inheriting from the class and union just defined, which completes
3083105Sstever@eecs.umich.edu//building up the type for the user.
3093105Sstever@eecs.umich.edu#define EndBitUnion(name) \
3103105Sstever@eecs.umich.edu        }; \
3113105Sstever@eecs.umich.edu    }; \
3123105Sstever@eecs.umich.edu    typedef BitfieldBackend::BitUnionOperators< \
3133105Sstever@eecs.umich.edu        BitfieldUnderlyingClasses##name> name;
3143105Sstever@eecs.umich.edu
3153105Sstever@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The
3163105Sstever@eecs.umich.edu//__storage member functions like the "underlying storage" of the top level
3173105Sstever@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so
3183105Sstever@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a
3193105Sstever@eecs.umich.edu//regular bitfield when referred to by itself.
3201585SN/A#define __SubBitUnion(name, fieldType, ...) \
3211310SN/A    class \
3221310SN/A    { \
3231310SN/A      public: \
3241310SN/A        union { \
3257673Snate@binkert.org            fieldType<__VA_ARGS__> __storage;
3261310SN/A
3271310SN/A//This closes off the union created above and gives it a name. Unlike the top
3281310SN/A//level BitUnion, we're interested in creating an object instead of a type.
3291310SN/A//The operators are defined in the macro itself instead of a class for
3301427SN/A//technical reasons. If someone determines a way to move them to one, please
3311310SN/A//do so.
3321310SN/A#define EndSubBitUnion(name) \
3332738SN/A        }; \
3343105Sstever@eecs.umich.edu        inline operator __StorageType () const \
3352738SN/A        { return __storage; } \
3362738SN/A        \
3372740SN/A        inline __StorageType operator = (const __StorageType & _storage) \
3382740SN/A        { return __storage = _storage;} \
3392740SN/A    } name;
3402740SN/A
3412740SN/A//Regular bitfields
3422740SN/A//These define macros for read/write regular bitfield based subbitfields.
3432740SN/A#define SubBitUnion(name, first, last) \
3443105Sstever@eecs.umich.edu    __SubBitUnion(name, Bitfield, first, last)
3451310SN/A
3463105Sstever@eecs.umich.edu//Regular bitfields
3473105Sstever@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3483105Sstever@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \
3493105Sstever@eecs.umich.edu    __SubBitUnion(name, SignedBitfield, first, last)
3503105Sstever@eecs.umich.edu
3518321Ssteve.reinhardt@amd.com//Use this to define an arbitrary type overlayed with bitfields.
3523105Sstever@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name)
3533105Sstever@eecs.umich.edu
3543105Sstever@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields.
3553105Sstever@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name)
3563105Sstever@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name)
3571310SN/A#define BitUnion16(name) __BitUnion(uint16_t, name)
3581585SN/A#define BitUnion8(name) __BitUnion(uint8_t, name)
3597675Snate@binkert.org
3607675Snate@binkert.org
3617675Snate@binkert.org//These templates make it possible to define other templates related to
3627675Snate@binkert.org//BitUnions without having to refer to internal typedefs or the BitfieldBackend
3637675Snate@binkert.org//namespace.
3647675Snate@binkert.org
3657675Snate@binkert.org//To build a template specialization which works for all BitUnions, accept a
3667675Snate@binkert.org//template argument T, and then use BitUnionType<T> as an argument in the
3677675Snate@binkert.org//template. To refer to the basic type the BitUnion wraps, use
3681692SN/A//BitUnionBaseType<T>.
3691692SN/A
3701585SN/A//For example:
3717528Ssteve.reinhardt@amd.com//template <typename T>
3727528Ssteve.reinhardt@amd.com//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
3737528Ssteve.reinhardt@amd.com
3741585SN/A//Also, BitUnionBaseType can be used on a BitUnion type directly.
3751585SN/A
3761585SN/Atemplate <typename T>
3773100SN/Ausing BitUnionType = BitfieldBackend::BitUnionOperators<T>;
3783100SN/A
3793100SN/Anamespace BitfieldBackend
3807673Snate@binkert.org{
3813100SN/A    template<typename T>
3823100SN/A    struct BitUnionBaseType
3833100SN/A    {
3843100SN/A        typedef typename BitUnionType<T>::__StorageType Type;
3854762Snate@binkert.org    };
3863100SN/A
3873100SN/A    template<typename T>
3883100SN/A    struct BitUnionBaseType<BitUnionType<T> >
3893100SN/A    {
3903100SN/A        typedef typename BitUnionType<T>::__StorageType Type;
3913100SN/A    };
3923100SN/A}
3937675Snate@binkert.org
3947675Snate@binkert.orgtemplate <typename T>
3957675Snate@binkert.orgusing BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
3967675Snate@binkert.org
3977675Snate@binkert.org
3987675Snate@binkert.org//An STL style hash structure for hashing BitUnions based on their base type.
3997675Snate@binkert.orgnamespace std
4007675Snate@binkert.org{
4017675Snate@binkert.org    template <typename T>
4027675Snate@binkert.org    struct hash;
4037675Snate@binkert.org
4047675Snate@binkert.org    template <typename T>
4057675Snate@binkert.org    struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
4067675Snate@binkert.org    {
4077811Ssteve.reinhardt@amd.com        size_t
4087675Snate@binkert.org        operator() (const BitUnionType<T> &val) const
4097675Snate@binkert.org        {
4107673Snate@binkert.org            return hash<BitUnionBaseType<T> >::operator()(val);
4117673Snate@binkert.org        }
4127673Snate@binkert.org    };
4134762Snate@binkert.org}
4145610Snate@binkert.org
4157673Snate@binkert.org#endif // __BASE_BITUNION_HH__
4167673Snate@binkert.org