Skip to content

Instantly share code, notes, and snippets.

@Crspy
Last active July 26, 2020 13:13
Show Gist options
  • Select an option

  • Save Crspy/afadfeafd588ce055a63154ad3ce923c to your computer and use it in GitHub Desktop.

Select an option

Save Crspy/afadfeafd588ce055a63154ad3ce923c to your computer and use it in GitHub Desktop.
C++11 templatized constexpr register wrapper class
#include <stddef.h> // this is all we need
namespace reg_wrapper
{
namespace detail
{
template <class T, T v>
struct integral_constant
{
static constexpr T value = v;
using value_type = T;
using type = integral_constant; // using injected-class-name
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; } //since c++14
};
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
template <class T, class U>
struct is_same : false_type
{
};
template <class T>
struct is_same<T, T> : true_type
{
};
template <class T>
struct remove_volatile
{
typedef T type;
};
template <class T>
struct remove_volatile<volatile T>
{
typedef T type;
};
} // namespace detail
template <typename T>
class TReg
{
template <bool...>
struct bool_pack;
template <bool... bs>
using all_true = detail::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
using folding_dummy = int[];
template <size_t... nbits>
constexpr void AssertIndices() const
{
static_assert(all_true<(nbits < (sizeof(T) * 8))...>::value,
"Bit index out of range");
};
public:
// make a range of bits set to 1 and the rest is 0
template <size_t start_nbit, size_t end_nbit>
inline typename detail::remove_volatile<T>::type make_range()
{
AssertIndices<start_nbit, end_nbit>();
return (((1 << start_nbit) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
template <size_t start_nbit, size_t end_nbit>
constexpr void set_range(T &reg)
{
AssertIndices<start_nbit, end_nbit>();
reg |= (((1 << start_nbit) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
template <size_t start_nbit, size_t end_nbit>
constexpr void clear_range(T &reg)
{
AssertIndices<start_nbit, end_nbit>();
reg &= ~(((1 << start_nbit) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
template <size_t start_nbit, size_t end_nbit>
constexpr void toggle_range(T &reg)
{
AssertIndices<start_nbit, end_nbit>();
reg ^= (((1 << start_nbit) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
// make a variable with the specified bits set to 1 and the rest is zero
template <size_t... nbits>
inline typename detail::remove_volatile<T>::type make_bits()
{
AssertIndices<nbits...>();
typename detail::remove_volatile<T>::type res{0};
(void)folding_dummy{0, ((res |= (1 << nbits)), 0)...};
return res;
}
template <size_t... nbits>
constexpr void bit_config(T& reg,bool value)
{
AssertIndices<nbits...>();
(void)folding_dummy{((reg = (reg & ~(1 << nbits)) | (value << nbits)), 0)...};
}
template <size_t... nbits>
constexpr void set_bits(T &reg)
{
AssertIndices<nbits...>();
(void)folding_dummy{((reg |= (1 << nbits)), 0)...};
}
template <size_t... nbits>
constexpr void clear_bits(T &reg)
{
AssertIndices<nbits...>();
(void)folding_dummy{(reg &= ~(1 << nbits), 0)...};
}
template <size_t... nbits>
constexpr void toggle_bits(T &reg)
{
AssertIndices<nbits...>();
(void)folding_dummy{(reg ^= (1 << nbits), 0)...};
}
template <size_t nbit>
constexpr T get_bit(T &reg) const
{
AssertIndices<nbit>();
return (reg & (1 << nbit)) >> nbit;
}
constexpr void set_bits(T &reg) { reg = ~static_cast<T>(0); }
constexpr void clear_bits(T &reg) { reg = 0; }
constexpr void toggle_bits(T &reg) { reg ^= ~(reg); }
// (for non-const arguments) make a range of bits set to 1 and the rest is 0
inline typename detail::remove_volatile<T>::type make_range(size_t start_nbit, size_t end_nbit)
{
return (((1 << start_nbit) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
// for non-const arguments
constexpr void set_range(T &reg, size_t start_nbit, size_t end_nbit)
{
reg |= (((1 << (start_nbit)) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
// for non-const arguments
constexpr void clear_range(T &reg, size_t start_nbit, size_t end_nbit)
{
reg &= ~(((1 << (start_nbit)) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
// for non-const arguments
constexpr void toggle_range(T &reg, size_t start_nbit, size_t end_nbit)
{
reg ^= (((1 << (start_nbit)) - 1) ^ ((1 << (end_nbit + 1)) - 1));
}
// (for non-const arguments) make a variable with the specified bits set to 1 and the rest is zero
template <typename... Ts>
inline typename detail::remove_volatile<T>::type make_bits(Ts... nbits)
{
typename detail::remove_volatile<T>::type res{0};
(void)folding_dummy{((res |= (1 << nbits)), 0)...};
return res;
}
// for non-const arguments
template <typename... Ts>
constexpr void bit_config(T& reg,bool value,Ts... nbits)
{
(void)folding_dummy{((reg = (reg & ~(1 << nbits)) | (value << nbits)), 0)...};
}
// for non-const arguments
template <typename... Ts>
constexpr void set_bits(T &reg, Ts... nbits)
{
(void)folding_dummy{((reg |= (1 << nbits)), 0)...};
}
// for non-const arguments
template <typename... Ts>
constexpr void clear_bits(T &reg, Ts... nbits)
{
(void)folding_dummy{((reg &= ~(1 << nbits)), 0)...};
}
// for non-const arguments
template <typename... Ts>
constexpr void toggle_bits(T &reg, Ts... nbits)
{
(void)folding_dummy{((reg ^= (1 << nbits)), 0)...};
}
// for non-const arguments
constexpr T get_bit(T &reg, size_t nbit) const { return (reg & (1 << nbit)) >> nbit; }
};
template <typename T>
inline constexpr auto make_wrapper(__attribute__((unused)) const T &reg) -> TReg<T>
{
return TReg<T>{};
}
} // namespace reg_wrapper
// example on atmega16 microcontroller
// here we can pass any PORT/REG just so we can just deduce the type we are dealing with
auto myreg = reg_wrapper::make_wrapper(PORTA);
int main()
{
// setup
myreg.set_bits<DDB0, DDB1>(DDRB); // make PORTB P0 , P1 OUTPUT
// DDRB = myreg.make_bits<DDB0,DDB1>(); // initialize the register with DDB0 and DDB1 set to 1
for (;;)
{
// toggling P0,P1 of PORTB every 1 second
myreg.set_bits<PB0, PB1>(PORTB);
_delay_ms(1000);
myreg.clear_bits<PB0, PB1>(PORTB);
_delay_ms(1000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment