gem5  v22.1.0.0
bitunion.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007-2008 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifndef __BASE_BITUNION_HH__
30 #define __BASE_BITUNION_HH__
31 
32 #include <functional>
33 #include <iostream>
34 #include <type_traits>
35 #include <typeinfo>
36 
37 #include "base/bitfield.hh"
38 #include "base/compiler.hh"
40 
41 namespace gem5
42 {
43 
44 // The following implements the BitUnion system of defining bitfields
45 //on top of an underlying class. This is done through the pervasive use of
46 //both named and unnamed unions which all contain the same actual storage.
47 //Since they're unioned with each other, all of these storage locations
48 //overlap. This allows all of the bitfields to manipulate the same data
49 //without having to have access to each other. More details are provided with
50 //the individual components.
51 
52 //This class wraps around another which defines getter/setter functions which
53 //manipulate the underlying data. The type of the underlying data and the type
54 //of the bitfield itself are inferred from the argument types of the setter
55 //function.
56 template<class Base>
57 class BitfieldTypeImpl : public Base
58 {
59  static_assert(std::is_empty_v<Base>, "Bitfield base class must be empty.");
60 
61  private:
62 
63  struct TypeDeducer
64  {
65  template<typename>
66  struct T;
67 
68  template<typename C, typename Type1, typename Type2>
69  struct T<void (C::*)(Type1 &, Type2)>
70  {
71  typedef Type1 Storage;
72  typedef Type2 Type;
73  };
74 
75  struct Wrapper : public Base
76  {
77  using Base::setter;
78  };
79 
80  typedef typename T<decltype(&Wrapper::setter)>::Storage Storage;
81  typedef typename T<decltype(&Wrapper::setter)>::Type Type;
82  };
83 
84  protected:
85  typedef typename TypeDeducer::Storage Storage;
86  typedef typename TypeDeducer::Type Type;
87 
88  Type getter(const Storage &storage) const = delete;
89  void setter(Storage &storage, Type val) = delete;
90 
91  BitfieldTypeImpl() = default;
92  BitfieldTypeImpl(const BitfieldTypeImpl &) = default;
93 
95 
96  operator Type () const
97  {
98  return Base::getter(__storage);
99  }
100 
101  Type
103  {
104  Base::setter(__storage, val);
105  return val;
106  }
107 
108  Type
110  {
111  return *this = (Type)other;
112  }
113 };
114 
115 //A wrapper for the above class which allows setting and getting.
116 template<class Base>
117 class BitfieldType : public BitfieldTypeImpl<Base>
118 {
119  protected:
121  using typename Impl::Type;
122 
123  public:
124  BitfieldType() = default;
125  BitfieldType(const BitfieldType &) = default;
126 
127  operator Type () const { return Impl::operator Type(); }
128 
129  Type operator=(const Type val) { return Impl::operator=(val); }
130  Type
132  {
133  return Impl::operator=(other);
134  }
135 };
136 
137 //A wrapper which only supports getting.
138 template<class Base>
139 class BitfieldROType : public BitfieldTypeImpl<Base>
140 {
141  public:
143  using typename Impl::Type;
144 
145  BitfieldROType() = default;
146  BitfieldROType(const BitfieldROType &) = default;
147 
148  Type operator=(BitfieldROType<Base> const &other) = delete;
149  operator Type () const { return Impl::operator Type(); }
150 };
151 
152 //A wrapper which only supports setting.
153 template <class Base>
154 class BitfieldWOType : public BitfieldTypeImpl<Base>
155 {
156  protected:
158  using typename Impl::Type;
159 
160  public:
161  BitfieldWOType() = default;
162  BitfieldWOType(const BitfieldWOType &) = default;
163 
164  Type operator=(const Type val) { return Impl::operator=(val); }
165  Type
167  {
168  return Impl::operator=(other);
169  }
170 };
171 
172 //This namespace is for classes which implement the backend of the BitUnion
173 //stuff. Don't use any of these directly.
174 namespace bitfield_backend
175 {
176  template<class Storage, int first, int last>
177  class Unsigned
178  {
179  static_assert(first >= last,
180  "Bitfield ranges must be specified as <msb, lsb>");
181 
182  protected:
183  uint64_t
184  getter(const Storage &storage) const
185  {
186  return bits(storage, first, last);
187  }
188 
189  void
190  setter(Storage &storage, uint64_t val)
191  {
192  replaceBits(storage, first, last, val);
193  }
194  };
195 
196  template<class Storage, int first, int last>
197  class Signed
198  {
199  static_assert(first >= last,
200  "Bitfield ranges must be specified as <msb, lsb>");
201 
202  protected:
203  int64_t
204  getter(const Storage &storage) const
205  {
206  return sext<first - last + 1>(bits(storage, first, last));
207  }
208 
209  void
210  setter(Storage &storage, int64_t val)
211  {
212  replaceBits(storage, first, last, val);
213  }
214  };
215 
216  //This class contains the basic bitfield types which are automatically
217  //available within a BitUnion. They inherit their Storage type from the
218  //containing BitUnion.
219  template<class Storage>
221  {
222  protected:
223 
224  template<int first, int last=first>
226  template<int first, int last=first>
227  using BitfieldRO =
229  template<int first, int last=first>
230  using BitfieldWO =
232 
233  template<int first, int last=first>
236  template<int first, int last=first>
239  template<int first, int last=first>
242  };
243 
244  //When a BitUnion is set up, an underlying class is created which holds
245  //the actual union. This class then inherits from it, and provids the
246  //implementations for various operators. Setting things up this way
247  //prevents having to redefine these functions in every different BitUnion
248  //type. More operators could be implemented in the future, as the need
249  //arises.
250  template <class Base>
251  class BitUnionOperators : public Base
252  {
253  static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
254  "BitUnion larger than its storage type.");
255 
256  public:
257  BitUnionOperators(typename Base::__StorageType const &val)
258  {
259  Base::__storage = val;
260  }
261 
263 
264  BitUnionOperators() = default;
265 
266  //Conversion operators.
267  operator const typename Base::__StorageType () const
268  {
269  return Base::__storage;
270  }
271 
272  //Basic assignment operators.
274  operator=(typename Base::__StorageType const &val)
275  {
276  Base::__storage = val;
277  return *this;
278  }
279 
282  {
283  return operator=(other.__storage);
284  }
285 
286  //Increment and decrement operators.
289  {
290  Base::__storage++;
291  return *this;
292  }
293 
296  {
297  BitUnionOperators ret = *this;
298  operator++();
299  return ret;
300  }
301 
304  {
305  Base::__storage--;
306  return *this;
307  }
308 
311  {
312  BitUnionOperators ret = *this;
313  operator--();
314  return ret;
315  }
316 
317  //Operation and assignment operators
319  operator+=(typename Base::__StorageType const &val)
320  {
321  Base::__storage += val;
322  return *this;
323  }
324 
326  operator-=(typename Base::__StorageType const &val)
327  {
328  Base::__storage -= val;
329  return *this;
330  }
331 
333  operator*=(typename Base::__StorageType const &val)
334  {
335  Base::__storage *= val;
336  return *this;
337  }
338 
340  operator/=(typename Base::__StorageType const &val)
341  {
342  Base::__storage /= val;
343  return *this;
344  }
345 
347  operator%=(typename Base::__StorageType const &val)
348  {
349  Base::__storage %= val;
350  return *this;
351  }
352 
354  operator&=(typename Base::__StorageType const &val)
355  {
356  Base::__storage &= val;
357  return *this;
358  }
359 
361  operator|=(typename Base::__StorageType const &val)
362  {
363  Base::__storage |= val;
364  return *this;
365  }
366 
368  operator^=(typename Base::__StorageType const &val)
369  {
370  Base::__storage ^= val;
371  return *this;
372  }
373 
375  operator<<=(typename Base::__StorageType const &val)
376  {
377  Base::__storage <<= val;
378  return *this;
379  }
380 
382  operator>>=(typename Base::__StorageType const &val)
383  {
384  Base::__storage >>= val;
385  return *this;
386  }
387  };
388 } // namespace bitfield_backend
389 
390 //This macro is a backend for other macros that specialize it slightly.
391 //First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
392 //sticks the class which has the actual union in it, which
393 //BitfieldOperators above inherits from. Putting these classes in a special
394 //namespace ensures that there will be no collisions with other names as long
395 //as the BitUnion names themselves are all distinct and nothing else uses
396 //the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
397 //creates a typedef of the "type" parameter called __StorageType. This allows
398 //the type to propagate outside of the macro itself in a controlled way.
399 //Finally, the base storage is defined which BitfieldOperators will refer to
400 //in the operators it defines. This macro is intended to be followed by
401 //bitfield definitions which will end up inside it's union. As explained
402 //above, these is overlayed the __storage member in its entirety by each of the
403 //bitfields which are defined in the union, creating shared storage with no
404 //overhead.
405 #define __BitUnion(type, name) \
406  class BitfieldUnderlyingClasses##name : \
407  public gem5::bitfield_backend::BitfieldTypes<type> \
408  { \
409  protected: \
410  typedef type __StorageType; \
411  friend gem5::bitfield_backend::BitUnionBaseType< \
412  gem5::bitfield_backend::BitUnionOperators< \
413  BitfieldUnderlyingClasses##name> >; \
414  friend gem5::bitfield_backend::BitUnionBaseType< \
415  BitfieldUnderlyingClasses##name>; \
416  public: \
417  union { \
418  type __storage;
419 
428 #define EndBitUnion(name) \
429  }; \
430  }; \
431  typedef gem5::bitfield_backend::BitUnionOperators< \
432  BitfieldUnderlyingClasses##name> name;
433 
434 //This sets up a bitfield which has other bitfields nested inside of it. The
435 //__storage member functions like the "underlying storage" of the top level
436 //BitUnion. Like everything else, it overlays with the top level storage, so
437 //making it a regular bitfield type makes the entire thing function as a
438 //regular bitfield when referred to by itself.
439 #define __SubBitUnion(name, fieldType, ...) \
440  class \
441  { \
442  public: \
443  union { \
444  fieldType<__VA_ARGS__> __storage;
445 
455 #define EndSubBitUnion(name) \
456  }; \
457  inline operator __StorageType () const \
458  { return __storage; } \
459  \
460  inline __StorageType operator = (const __StorageType & _storage) \
461  { return __storage = _storage;} \
462  } name;
463 
470 #define SubBitUnion(name, first, last) \
471  __SubBitUnion(name, Bitfield, first, last)
472 
479 #define SignedSubBitUnion(name, first, last) \
480  __SubBitUnion(name, SignedBitfield, first, last)
481 
487 #define BitUnion(type, name) __BitUnion(type, name)
488 
494 #define BitUnion64(name) __BitUnion(uint64_t, name)
495 #define BitUnion32(name) __BitUnion(uint32_t, name)
496 #define BitUnion16(name) __BitUnion(uint16_t, name)
497 #define BitUnion8(name) __BitUnion(uint8_t, name)
498 
499 
500 //These templates make it possible to define other templates related to
501 //BitUnions without having to refer to internal typedefs or the
502 // bitfield_backend namespace.
503 
504 //To build a template specialization which works for all BitUnions, accept a
505 //template argument T, and then use BitUnionType<T> as an argument in the
506 //template. To refer to the basic type the BitUnion wraps, use
507 //BitUnionBaseType<T>.
508 
509 //For example:
510 //template <typename T>
511 //void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
512 
513 //Also, BitUnionBaseType can be used on a BitUnion type directly.
514 
518 template <typename T>
520 
521 namespace bitfield_backend
522 {
523  template<typename T>
525  {
527  };
528 
529  template<typename T>
531  {
533  };
534 } // namespace bitfield_backend
535 
539 template <typename T>
541 
542 namespace bitfield_backend
543 {
544  template<typename T>
545  static inline std::ostream &
546  bitfieldBackendPrinter(std::ostream &os, const T &t)
547  {
548  os << t;
549  return os;
550  }
551 
552  //Since BitUnions are generally numerical values and not character codes,
553  //these specializations attempt to ensure that they get cast to integers
554  //of the appropriate type before printing.
555  template <>
556  inline std::ostream &
557  bitfieldBackendPrinter(std::ostream &os, const char &t)
558  {
559  os << (int)t;
560  return os;
561  }
562 
563  template <>
564  inline std::ostream &
565  bitfieldBackendPrinter(std::ostream &os, const unsigned char &t)
566  {
567  os << (unsigned int)t;
568  return os;
569  }
570 } // namespace bitfield_backend
571 
578 template <typename T>
579 std::ostream &
580 operator << (std::ostream &os, const BitUnionType<T> &bu)
581 {
583  os, (BitUnionBaseType<T>)bu);
584 }
585 
586 // Specialization for BitUnion types.
587 template <class T>
589 {
590  static bool
591  parse(const std::string &s, BitUnionType<T> &value)
592  {
593  // Zero initialize storage to avoid leaking an uninitialized value
595  auto res = to_number(s, storage);
596  value = storage;
597  return res;
598  }
599 };
600 
601 template <class T>
603 {
604  static void
605  show(std::ostream &os, const BitUnionType<T> &value)
606  {
608  os, static_cast<const BitUnionBaseType<T> &>(value));
609  }
610 };
611 
612 } // namespace gem5
613 
614 //An STL style hash structure for hashing BitUnions based on their base type.
615 namespace std
616 {
617  template <typename T>
618  struct hash<gem5::BitUnionType<T>> : public hash<gem5::BitUnionBaseType<T>>
619  {
620  size_t
621  operator() (const gem5::BitUnionType<T> &val) const
622  {
623  return hash<gem5::BitUnionBaseType<T> >::operator()(val);
624  }
625  };
626 } // namespace std
627 
628 #endif // __BASE_BITUNION_HH__
Type operator=(BitfieldROType< Base > const &other)=delete
BitfieldROType()=default
BitfieldROType(const BitfieldROType &)=default
TypeDeducer::Type Type
Definition: bitunion.hh:86
TypeDeducer::Storage Storage
Definition: bitunion.hh:85
Type operator=(const Type val)
Definition: bitunion.hh:102
BitfieldTypeImpl(const BitfieldTypeImpl &)=default
TypeDeducer::Type Type
Definition: bitunion.hh:86
Type operator=(BitfieldTypeImpl< Base > const &other)
Definition: bitunion.hh:109
void setter(Storage &storage, Type val)=delete
Type getter(const Storage &storage) const =delete
Type operator=(const Type val)
Definition: bitunion.hh:129
Type operator=(BitfieldType< Base > const &other)
Definition: bitunion.hh:131
TypeDeducer::Type Type
Definition: bitunion.hh:86
BitfieldType()=default
BitfieldType(const BitfieldType &)=default
BitfieldWOType()=default
Type operator=(const Type val)
Definition: bitunion.hh:164
Type operator=(BitfieldWOType< Base > const &other)
Definition: bitunion.hh:166
BitfieldWOType(const BitfieldWOType &)=default
TypeDeducer::Type Type
Definition: bitunion.hh:86
BitUnionOperators & operator&=(typename Base::__StorageType const &val)
Definition: bitunion.hh:354
BitUnionOperators & operator-=(typename Base::__StorageType const &val)
Definition: bitunion.hh:326
BitUnionOperators(typename Base::__StorageType const &val)
Definition: bitunion.hh:257
BitUnionOperators & operator+=(typename Base::__StorageType const &val)
Definition: bitunion.hh:319
BitUnionOperators & operator=(typename Base::__StorageType const &val)
Definition: bitunion.hh:274
BitUnionOperators & operator<<=(typename Base::__StorageType const &val)
Definition: bitunion.hh:375
BitUnionOperators & operator=(BitUnionOperators const &other)
Definition: bitunion.hh:281
BitUnionOperators & operator*=(typename Base::__StorageType const &val)
Definition: bitunion.hh:333
BitUnionOperators & operator^=(typename Base::__StorageType const &val)
Definition: bitunion.hh:368
BitUnionOperators(const BitUnionOperators &)=default
BitUnionOperators & operator/=(typename Base::__StorageType const &val)
Definition: bitunion.hh:340
BitUnionOperators & operator|=(typename Base::__StorageType const &val)
Definition: bitunion.hh:361
BitUnionOperators & operator>>=(typename Base::__StorageType const &val)
Definition: bitunion.hh:382
BitUnionOperators & operator%=(typename Base::__StorageType const &val)
Definition: bitunion.hh:347
int64_t getter(const Storage &storage) const
Definition: bitunion.hh:204
void setter(Storage &storage, int64_t val)
Definition: bitunion.hh:210
uint64_t getter(const Storage &storage) const
Definition: bitunion.hh:184
void setter(Storage &storage, uint64_t val)
Definition: bitunion.hh:190
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:76
constexpr uint64_t sext(uint64_t val)
Sign-extend an N-bit value to 64 bits.
Definition: bitfield.hh:126
constexpr void replaceBits(T &val, unsigned first, unsigned last, B bit_val)
A convenience function to replace bits first to last of val with bit_val in place.
Definition: bitfield.hh:197
bitfield_backend::BitUnionOperators< T > BitUnionType
Definition: bitunion.hh:519
typename bitfield_backend::BitUnionBaseType< T >::Type BitUnionBaseType
Definition: bitunion.hh:540
constexpr RegId C
Definition: cc.hh:74
Bitfield< 1 > s
Definition: pagetable.hh:64
Bitfield< 51 > t
Definition: pagetable.hh:56
Bitfield< 17 > os
Definition: misc.hh:810
Bitfield< 63 > val
Definition: misc.hh:776
static std::ostream & bitfieldBackendPrinter(std::ostream &os, const T &t)
Definition: bitunion.hh:546
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
bool to_number(const std::string &value, Pixel &retval)
Definition: pixel.hh:217
std::ostream & operator<<(std::ostream &os, const ArmSemihosting::InPlaceArg &ipa)
Overload hash function for BasicBlockRange type.
Definition: misc.hh:2826
T< decltype(&Wrapper::setter)>::Storage Storage
Definition: bitunion.hh:80
T< decltype(&Wrapper::setter)>::Type Type
Definition: bitunion.hh:81
static bool parse(const std::string &s, BitUnionType< T > &value)
Definition: bitunion.hh:591
static void show(std::ostream &os, const BitUnionType< T > &value)
Definition: bitunion.hh:605
static void show(std::ostream &os, const T &value)
BitUnionType< T >::__StorageType Type
Definition: bitunion.hh:526

Generated on Wed Dec 21 2022 10:22:28 for gem5 by doxygen 1.9.1