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