bitunion.hh revision 12451
113559Snikos.nikoleris@arm.com/*
212109SRekai.GonzalezAlberquilla@arm.com * Copyright (c) 2007-2008 The Regents of The University of Michigan
312109SRekai.GonzalezAlberquilla@arm.com * All rights reserved.
412109SRekai.GonzalezAlberquilla@arm.com *
512109SRekai.GonzalezAlberquilla@arm.com * Redistribution and use in source and binary forms, with or without
612109SRekai.GonzalezAlberquilla@arm.com * modification, are permitted provided that the following conditions are
712109SRekai.GonzalezAlberquilla@arm.com * met: redistributions of source code must retain the above copyright
812109SRekai.GonzalezAlberquilla@arm.com * notice, this list of conditions and the following disclaimer;
912109SRekai.GonzalezAlberquilla@arm.com * redistributions in binary form must reproduce the above copyright
1012109SRekai.GonzalezAlberquilla@arm.com * notice, this list of conditions and the following disclaimer in the
1112109SRekai.GonzalezAlberquilla@arm.com * documentation and/or other materials provided with the distribution;
1212109SRekai.GonzalezAlberquilla@arm.com * neither the name of the copyright holders nor the names of its
134486Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
144486Sbinkertn@umich.edu * this software without specific prior written permission.
154486Sbinkertn@umich.edu *
164486Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174486Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184486Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194486Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204486Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214486Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224486Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234486Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244486Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254486Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264486Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274486Sbinkertn@umich.edu *
284486Sbinkertn@umich.edu * Authors: Gabe Black
294486Sbinkertn@umich.edu */
304486Sbinkertn@umich.edu
314486Sbinkertn@umich.edu#ifndef __BASE_BITUNION_HH__
324486Sbinkertn@umich.edu#define __BASE_BITUNION_HH__
334486Sbinkertn@umich.edu
344486Sbinkertn@umich.edu#include <iostream>
354486Sbinkertn@umich.edu#include <type_traits>
364486Sbinkertn@umich.edu
374486Sbinkertn@umich.edu#include "base/bitfield.hh"
384486Sbinkertn@umich.edu
394486Sbinkertn@umich.edu//      The following implements the BitUnion system of defining bitfields
404486Sbinkertn@umich.edu//on top of an underlying class. This is done through the pervasive use of
4112563Sgabeblack@google.com//both named and unnamed unions which all contain the same actual storage.
4212563Sgabeblack@google.com//Since they're unioned with each other, all of these storage locations
436654Snate@binkert.org//overlap. This allows all of the bitfields to manipulate the same data
443102SN/A//without having to have access to each other. More details are provided with
453102SN/A//the individual components.
461681SN/A
473223SN/A//This class wraps around another which defines getter/setter functions which
488887Sgeoffrey.blake@arm.com//manipulate the underlying data. The type of the underlying data and the type
4910785Sgope@wisc.edu//of the bitfield itself are inferred from the argument types of the setter
504486Sbinkertn@umich.edu//function.
5113559Snikos.nikoleris@arm.comtemplate<class Base>
5213559Snikos.nikoleris@arm.comclass BitfieldTypeImpl : public Base
5313559Snikos.nikoleris@arm.com{
542817SN/A    static_assert(std::is_empty<Base>::value,
552817SN/A                  "Bitfield base class must be empty.");
569341SAndreas.Sandberg@arm.com
579341SAndreas.Sandberg@arm.com  private:
589518SAndreas.Sandberg@ARM.com    using Base::setter;
599518SAndreas.Sandberg@ARM.com
609518SAndreas.Sandberg@ARM.com    template<typename T>
619518SAndreas.Sandberg@ARM.com    struct TypeDeducer;
629518SAndreas.Sandberg@ARM.com
639518SAndreas.Sandberg@ARM.com    template<typename T>
649518SAndreas.Sandberg@ARM.com    friend class TypeDeducer;
659518SAndreas.Sandberg@ARM.com
669518SAndreas.Sandberg@ARM.com    template<typename Type1, typename Type2>
679518SAndreas.Sandberg@ARM.com    struct TypeDeducer<void (Base::*)(Type1 &, Type2)>
689518SAndreas.Sandberg@ARM.com    {
699518SAndreas.Sandberg@ARM.com        typedef Type1 Storage;
702932SN/A        typedef Type2 Type;
711681SN/A    };
7211780Sarthur.perais@inria.fr
7311780Sarthur.perais@inria.fr  protected:
741681SN/A    typedef typename TypeDeducer<
759184Sandreas.hansson@arm.com            decltype(&BitfieldTypeImpl<Base>::setter)>::Storage Storage;
769184Sandreas.hansson@arm.com    typedef typename TypeDeducer<
779184Sandreas.hansson@arm.com            decltype(&BitfieldTypeImpl<Base>::setter)>::Type Type;
789184Sandreas.hansson@arm.com
799184Sandreas.hansson@arm.com    Type getter(const Storage &storage) const = delete;
802932SN/A    void setter(Storage &storage, Type val) = delete;
819982Satgutier@umich.edu
8210331Smitch.hayenga@arm.com    Storage __storage;
8310331Smitch.hayenga@arm.com
842932SN/A    operator Type () const
859184Sandreas.hansson@arm.com    {
869184Sandreas.hansson@arm.com        return Base::getter(__storage);
879184Sandreas.hansson@arm.com    }
889184Sandreas.hansson@arm.com
899184Sandreas.hansson@arm.com    Type
902932SN/A    operator=(const Type val)
911681SN/A    {
929184Sandreas.hansson@arm.com        Base::setter(__storage, val);
939184Sandreas.hansson@arm.com        return val;
949184Sandreas.hansson@arm.com    }
959184Sandreas.hansson@arm.com
962932SN/A    Type
971681SN/A    operator=(BitfieldTypeImpl<Base> const & other)
989184Sandreas.hansson@arm.com    {
992932SN/A        return *this = (Type)other;
1009184Sandreas.hansson@arm.com    }
1012932SN/A};
1029184Sandreas.hansson@arm.com
1032932SN/A//A wrapper for the above class which allows setting and getting.
1042932SN/Atemplate<class Base>
1052932SN/Aclass BitfieldType : public BitfieldTypeImpl<Base>
1062932SN/A{
1073223SN/A  protected:
1082932SN/A    using Impl = BitfieldTypeImpl<Base>;
1099184Sandreas.hansson@arm.com    using typename Impl::Type;
1101681SN/A
1119184Sandreas.hansson@arm.com  public:
1122932SN/A    operator Type () const { return Impl::operator Type(); }
1132932SN/A    Type operator=(const Type val) { return Impl::operator=(val); }
1149184Sandreas.hansson@arm.com    Type
1159184Sandreas.hansson@arm.com    operator=(BitfieldType<Base> const & other)
1161681SN/A    {
1172932SN/A        return Impl::operator=(other);
1182932SN/A    }
1191681SN/A};
1202932SN/A
1212932SN/A//A wrapper which only supports getting.
1228199SAli.Saidi@ARM.comtemplate<class Base>
1238199SAli.Saidi@ARM.comclass BitfieldROType : public BitfieldTypeImpl<Base>
1248199SAli.Saidi@ARM.com{
1258519SAli.Saidi@ARM.com  public:
1268519SAli.Saidi@ARM.com    using Impl = BitfieldTypeImpl<Base>;
1272932SN/A    using typename Impl::Type;
1282932SN/A
1291681SN/A    Type operator=(BitfieldROType<Base> const &other) = delete;
1302932SN/A    operator Type () const { return Impl::operator Type(); }
1311681SN/A};
1322932SN/A
1332932SN/A//A wrapper which only supports setting.
1342932SN/Atemplate <class Base>
1359921Syasuko.eckert@amd.comclass BitfieldWOType : public BitfieldTypeImpl<Base>
1369921Syasuko.eckert@amd.com{
13710338SCurtis.Dunham@arm.com  protected:
1389921Syasuko.eckert@amd.com    using Impl = BitfieldTypeImpl<Base>;
1399921Syasuko.eckert@amd.com    using typename Impl::Type;
1409921Syasuko.eckert@amd.com
1419921Syasuko.eckert@amd.com  public:
1429921Syasuko.eckert@amd.com    Type operator=(const Type val) { return Impl::operator=(val); }
1439921Syasuko.eckert@amd.com    Type
1449921Syasuko.eckert@amd.com    operator=(BitfieldWOType<Base> const & other)
14512109SRekai.GonzalezAlberquilla@arm.com    {
14612109SRekai.GonzalezAlberquilla@arm.com        return Impl::operator=(other);
1479921Syasuko.eckert@amd.com    }
1489921Syasuko.eckert@amd.com};
1492932SN/A
1502932SN/A//This namespace is for classes which implement the backend of the BitUnion
1511681SN/A//stuff. Don't use any of these directly.
1524597Sbinkertn@umich.edunamespace BitfieldBackend
15313559Snikos.nikoleris@arm.com{
1544597Sbinkertn@umich.edu    template<class Storage, int first, int last>
1554597Sbinkertn@umich.edu    class Unsigned
1564597Sbinkertn@umich.edu    {
1574597Sbinkertn@umich.edu        static_assert(first >= last,
1584597Sbinkertn@umich.edu                      "Bitfield ranges must be specified as <msb, lsb>");
1594597Sbinkertn@umich.edu
1604597Sbinkertn@umich.edu      protected:
1614303SN/A        uint64_t
16210785Sgope@wisc.edu        getter(const Storage &storage) const
1639849Sandreas.hansson@arm.com        {
1649849Sandreas.hansson@arm.com            return bits(storage, first, last);
1658727Snilay@cs.wisc.edu        }
1668727Snilay@cs.wisc.edu
1678887Sgeoffrey.blake@arm.com        void
1688887Sgeoffrey.blake@arm.com        setter(Storage &storage, uint64_t val)
1698887Sgeoffrey.blake@arm.com        {
1708887Sgeoffrey.blake@arm.com            replaceBits(storage, first, last, val);
1718887Sgeoffrey.blake@arm.com        }
1728887Sgeoffrey.blake@arm.com    };
1738887Sgeoffrey.blake@arm.com
1748887Sgeoffrey.blake@arm.com    template<class Storage, int first, int last>
1758887Sgeoffrey.blake@arm.com    class Signed
1768887Sgeoffrey.blake@arm.com    {
1778887Sgeoffrey.blake@arm.com        static_assert(first >= last,
1789132Satgutier@umich.edu                      "Bitfield ranges must be specified as <msb, lsb>");
1798887Sgeoffrey.blake@arm.com
1808887Sgeoffrey.blake@arm.com      protected:
18112563Sgabeblack@google.com        int64_t
1828887Sgeoffrey.blake@arm.com        getter(const Storage &storage) const
183        {
184            return sext<first - last + 1>(bits(storage, first, last));
185        }
186
187        void
188        setter(Storage &storage, int64_t val)
189        {
190            replaceBits(storage, first, last, val);
191        }
192    };
193
194    //This class contains the basic bitfield types which are automatically
195    //available within a BitUnion. They inherit their Storage type from the
196    //containing BitUnion.
197    template<class Storage>
198    class BitfieldTypes
199    {
200      protected:
201
202        template<int first, int last=first>
203        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
204        template<int first, int last=first>
205        using BitfieldRO =
206                BitfieldROType<Unsigned<Storage, first, last> >;
207        template<int first, int last=first>
208        using BitfieldWO =
209                BitfieldWOType<Unsigned<Storage, first, last> >;
210
211        template<int first, int last=first>
212        using SignedBitfield =
213                BitfieldType<Signed<Storage, first, last> >;
214        template<int first, int last=first>
215        using SignedBitfieldRO =
216                BitfieldROType<Signed<Storage, first, last> >;
217        template<int first, int last=first>
218        using SignedBitfieldWO =
219                BitfieldWOType<Signed<Storage, first, last> >;
220    };
221
222    //When a BitUnion is set up, an underlying class is created which holds
223    //the actual union. This class then inherits from it, and provids the
224    //implementations for various operators. Setting things up this way
225    //prevents having to redefine these functions in every different BitUnion
226    //type. More operators could be implemented in the future, as the need
227    //arises.
228    template <class Base>
229    class BitUnionOperators : public Base
230    {
231        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
232                      "BitUnion larger than its storage type.");
233
234      public:
235        BitUnionOperators(typename Base::__StorageType const &val)
236        {
237            Base::__storage = val;
238        }
239
240        BitUnionOperators() {}
241
242        operator const typename Base::__StorageType () const
243        {
244            return Base::__storage;
245        }
246
247        typename Base::__StorageType
248        operator=(typename Base::__StorageType const &val)
249        {
250            Base::__storage = val;
251            return val;
252        }
253
254        typename Base::__StorageType
255        operator=(BitUnionOperators const &other)
256        {
257            Base::__storage = other;
258            return Base::__storage;
259        }
260
261        bool
262        operator<(Base const &base) const
263        {
264            return Base::__storage < base.__storage;
265        }
266
267        bool
268        operator==(Base const &base) const
269        {
270            return Base::__storage == base.__storage;
271        }
272    };
273}
274
275//This macro is a backend for other macros that specialize it slightly.
276//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
277//sticks the class which has the actual union in it, which
278//BitfieldOperators above inherits from. Putting these classes in a special
279//namespace ensures that there will be no collisions with other names as long
280//as the BitUnion names themselves are all distinct and nothing else uses
281//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
282//creates a typedef of the "type" parameter called __StorageType. This allows
283//the type to propagate outside of the macro itself in a controlled way.
284//Finally, the base storage is defined which BitfieldOperators will refer to
285//in the operators it defines. This macro is intended to be followed by
286//bitfield definitions which will end up inside it's union. As explained
287//above, these is overlayed the __storage member in its entirety by each of the
288//bitfields which are defined in the union, creating shared storage with no
289//overhead.
290#define __BitUnion(type, name) \
291    class BitfieldUnderlyingClasses##name : \
292        public BitfieldBackend::BitfieldTypes<type> \
293    { \
294      public: \
295        typedef type __StorageType; \
296        union { \
297            type __storage;
298
299//This closes off the class and union started by the above macro. It is
300//followed by a typedef which makes "name" refer to a BitfieldOperator
301//class inheriting from the class and union just defined, which completes
302//building up the type for the user.
303#define EndBitUnion(name) \
304        }; \
305    }; \
306    typedef BitfieldBackend::BitUnionOperators< \
307        BitfieldUnderlyingClasses##name> name;
308
309//This sets up a bitfield which has other bitfields nested inside of it. The
310//__storage member functions like the "underlying storage" of the top level
311//BitUnion. Like everything else, it overlays with the top level storage, so
312//making it a regular bitfield type makes the entire thing function as a
313//regular bitfield when referred to by itself.
314#define __SubBitUnion(name, fieldType, ...) \
315    class \
316    { \
317      public: \
318        union { \
319            fieldType<__VA_ARGS__> __storage;
320
321//This closes off the union created above and gives it a name. Unlike the top
322//level BitUnion, we're interested in creating an object instead of a type.
323//The operators are defined in the macro itself instead of a class for
324//technical reasons. If someone determines a way to move them to one, please
325//do so.
326#define EndSubBitUnion(name) \
327        }; \
328        inline operator __StorageType () const \
329        { return __storage; } \
330        \
331        inline __StorageType operator = (const __StorageType & _storage) \
332        { return __storage = _storage;} \
333    } name;
334
335//Regular bitfields
336//These define macros for read/write regular bitfield based subbitfields.
337#define SubBitUnion(name, first, last) \
338    __SubBitUnion(name, Bitfield, first, last)
339
340//Regular bitfields
341//These define macros for read/write regular bitfield based subbitfields.
342#define SignedSubBitUnion(name, first, last) \
343    __SubBitUnion(name, SignedBitfield, first, last)
344
345//Use this to define an arbitrary type overlayed with bitfields.
346#define BitUnion(type, name) __BitUnion(type, name)
347
348//Use this to define conveniently sized values overlayed with bitfields.
349#define BitUnion64(name) __BitUnion(uint64_t, name)
350#define BitUnion32(name) __BitUnion(uint32_t, name)
351#define BitUnion16(name) __BitUnion(uint16_t, name)
352#define BitUnion8(name) __BitUnion(uint8_t, name)
353
354
355//These templates make it possible to define other templates related to
356//BitUnions without having to refer to internal typedefs or the BitfieldBackend
357//namespace.
358
359//To build a template specialization which works for all BitUnions, accept a
360//template argument T, and then use BitUnionType<T> as an argument in the
361//template. To refer to the basic type the BitUnion wraps, use
362//BitUnionBaseType<T>.
363
364//For example:
365//template <typename T>
366//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
367
368//Also, BitUnionBaseType can be used on a BitUnion type directly.
369
370template <typename T>
371using BitUnionType = BitfieldBackend::BitUnionOperators<T>;
372
373namespace BitfieldBackend
374{
375    template<typename T>
376    struct BitUnionBaseType
377    {
378        typedef typename BitUnionType<T>::__StorageType Type;
379    };
380
381    template<typename T>
382    struct BitUnionBaseType<BitUnionType<T> >
383    {
384        typedef typename BitUnionType<T>::__StorageType Type;
385    };
386}
387
388template <typename T>
389using BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
390
391#endif // __BASE_BITUNION_HH__
392