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