Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/tl/include/bitfield
2025-09-12 15:55:45 +02:00

309 lines
11 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2012 Alexander Warg <warg@os.inf.tu-dresden.de>,
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "type_list"
/** Our C++ library. */
namespace cxx {
/**
* Definition for a member (part) of a bit field.
*
* \param T The underlying type of the bit field.
* \param LSB The least significant bit of our bits.
* \param MSB The most significant bit of our bits.
*/
template<typename T, unsigned LSB, unsigned MSB>
class Bitfield
{
private:
typedef remove_reference_t<T> Base_type;
static_assert(MSB >= LSB, "boundary mismatch in bit-field definition");
static_assert(MSB < sizeof(Base_type) * 8, "MSB outside of bit-field type");
static_assert(LSB < sizeof(Base_type) * 8, "LSB outside of bit-field type");
/**
* Get the best unsigned type for `bits`.
*
* \param BITS Number of bits to cover.
*/
template<unsigned BITS> struct Best_type
{
template< typename TY > struct Cmp { enum { value = (BITS <= sizeof(TY)*8) }; };
typedef cxx::type_list<
unsigned char,
unsigned short,
unsigned int,
unsigned long,
unsigned long long
> Unsigned_types;
typedef cxx::find_type_t<Unsigned_types, Cmp> Type;
};
public:
enum
{
Bits = MSB + 1 - LSB, ///< Number of bits
Lsb = LSB, ///< index of the LSB
Msb = MSB, ///< index of the MSB
};
/// Masks for bitswise operation on internal parts of a bitfield
enum Masks : Base_type
{
/** Mask value to get #Bits bits. */
Low_mask = static_cast<Base_type>(~0ULL) >> (sizeof(Base_type)*8 - Bits),
/** Mask value to the bits out of a `T`. */
Mask = Low_mask << Lsb,
};
/**
* Type to hold at least #Bits bits.
*
* This type can handle all values that can be stored in this part of the bit
* field.
*/
typedef typename Best_type<Bits>::Type Bits_type;
/**
* Type to hold at least #Bits + #Lsb bits.
*
* This type can handle all values that can be stored in this part of the bit
* field when they are at the target location (#Lsb bits shifted to the left).
*/
typedef typename Best_type<Bits + Lsb>::Type Shift_type;
private:
static_assert(sizeof(Bits_type)*8 >= Bits, "error finding the type to store the bits");
static_assert(sizeof(Shift_type)*8 >= Bits + Lsb, "error finding the type to keep the shifted bits");
static_assert(sizeof(Bits_type) <= sizeof(Base_type), "size mismatch for Bits_type");
static_assert(sizeof(Shift_type) <= sizeof(Base_type), "size mismatch for Shift_type");
static_assert(sizeof(Bits_type) <= sizeof(Shift_type), "size mismatch for Shift_type and Bits_type");
public:
/**
* Get the bits out of `val`.
*
* \param val The raw value of the whole bit field.
*
* \return The bits form #Lsb to #Msb shifted to the right.
*/
static constexpr Bits_type get(Shift_type val)
{ return (val >> Lsb) & Low_mask; }
/**
* Get the bits in place out of `val`.
*
* \param val The raw value of the whole bit field.
*
* \return The bits from #Lsb to #Msb (unshifted).
*
* This means other bits are masked out, however the result is not shifted to
* the right.
*/
static constexpr Base_type get_unshifted(Shift_type val)
{ return val & Mask; }
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value to set into the bits.
*
* \return The new value of the whole bit field.
*
* \pre `val` must not contain more than #Bits bits.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type set_dirty(Base_type dest, Shift_type val)
{
//assert (!(val & ~Low_mask));
return (dest & ~Mask) | (val << Lsb);
}
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bits.
*
* \return The new value of the whole bit field.
*
* \pre `val` must not contain more than #Bits bits shifted #Lsb bits to the
* left.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type set_unshifted_dirty(Base_type dest, Shift_type val)
{
//assert (!(val & ~Mask));
return (dest & ~Mask) | val;
}
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value to set into the bits.
*
* \return The new value of the whole bit field.
*/
static Base_type set(Base_type dest, Bits_type val)
{ return set_dirty(dest, val & Low_mask); }
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bit field.
*
* \return the new value of the whole bit field.
*/
static Base_type set_unshifted(Base_type dest, Shift_type val)
{ return set_unshifted_dirty(dest, val & Mask); }
/**
* Get the shifted bits for `val`.
*
* \param val The value to set into the bits.
*
* \return The raw bit field value.
*
* \pre `val` must not contain more than #Bits bits.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type val_dirty(Shift_type val) { return val << Lsb; }
/**
* Get the shifted bits for `val`.
*
* \param val The value to set into the bits.
*
* \return The raw bit field value.
*/
static constexpr Base_type val(Bits_type val) { return val_dirty(val & Low_mask); }
/**
* Get the shifted bits for `val`.
*
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bits.
*
* \return The raw bit field value.
*/
static constexpr Base_type val_unshifted(Shift_type val) { return val & Mask; }
/** Internal helper type */
template< typename TT >
class Value_base
{
private:
TT v;
public:
constexpr Value_base(TT t) : v(t) {}
constexpr Bits_type get() const { return Bitfield::get(v); }
constexpr Base_type get_unshifted() const { return Bitfield::get_unshifted(v); }
void set(Bits_type val) { v = Bitfield::set(v, val); }
void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); }
void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); }
void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); }
};
/** Internal helper type */
template< typename TT >
class Value : public Value_base<TT>
{
public:
constexpr Value(TT t) : Value_base<TT>(t) {}
constexpr operator Bits_type () const { return this->get(); }
constexpr Value &operator = (Bits_type val) { this->set(val); return *this; }
constexpr Value &operator = (Value const &val)
{ this->set(val.get()); return *this; }
Value(Value const &) = default;
};
/** Internal helper type */
template< typename TT >
class Value_unshifted : public Value_base<TT>
{
public:
constexpr Value_unshifted(TT t) : Value_base<TT>(t) {}
constexpr operator Shift_type () const { return this->get_unshifted(); }
constexpr Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; }
constexpr Value_unshifted &operator = (Value_unshifted const &val)
{ this->set_unshifted(val.get_unshifted()); return *this; }
Value_unshifted(Value_unshifted const &) = default;
};
/** Reference type to access the bits inside a raw bit field. */
typedef Value<Base_type &> Ref;
/** Volatile reference type to access the bits inside a raw bit field. */
typedef Value<Base_type volatile &> Ref_volatile;
/** Value type to access the bits inside a raw bit field. */
typedef Value<Base_type const> Val;
/** Reference type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type &> Ref_unshifted;
/** Volatile reference type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type volatile &> Ref_unshifted_volatile;
/** Value type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type const> Val_unshifted;
};
#define CXX_BITFIELD_MEMBER(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val name() const { return data_member; } \
typename name ## _bfm_t::Val name() const volatile { return data_member; } \
/** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Ref name() { return data_member; } \
typename name ## _bfm_t::Ref_volatile name() volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val name() const { return data_member; } \
typename name ## _bfm_t::Val name() const volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
typename name ## _bfm_t::Val_unshifted name() const volatile { return data_member; } \
/** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Ref_unshifted name() { return data_member; } \
typename name ## _bfm_t::Ref_unshifted_volatile name() volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
typename name ## _bfm_t::Val_unshifted name() const volatile { return data_member; } \
/** @} */
}