Verify register and mask parameters

error-checking
Clyne 2 years ago
parent 922489447f
commit 2e6001946f

@ -86,20 +86,18 @@ requires IsAccess<Access>
struct Register;
template<typename T>
concept IsRegister = requires {
requires IsAccess<typename T::access>;
requires std::same_as<T, Register<typename T::access>>;
};
concept IsRegister =
IsAccess<typename T::access> &&
std::same_as<T, Register<typename T::access>>;
#else
template<typename T, uintptr_t Addr>
requires(std::unsigned_integral<T>)
class Register;
template<typename T>
concept IsRegister = requires {
requires std::unsigned_integral<typename T::type>;
requires IsAccess<typename T::Access>;
};
concept IsRegister =
std::unsigned_integral<typename T::type> &&
IsAccess<typename T::Access>;
#endif
template<typename Reg, typename Reg::type Mask>
@ -107,10 +105,21 @@ requires IsRegister<Reg>
struct RegisterMask;
template<typename T>
concept IsRegisterMask = requires {
requires IsRegister<typename T::reg>;
requires std::same_as<T, RegisterMask<typename T::reg, T::mask>>;
};
concept IsRegisterMask =
IsRegister<typename T::reg> &&
std::same_as<T, RegisterMask<typename T::reg, T::mask>>;
template<typename M, typename R>
concept UsesRegister =
IsRegisterMask<M> &&
IsRegister<R> &&
std::same_as<typename M::reg, R>;
template<typename M, typename... Rs>
concept UsesSomeRegister =
IsRegisterMask<M> &&
(IsRegister<Rs>, ...) &&
(std::same_as<typename M::reg, Rs> || ...);
/**
* @struct Register
@ -156,7 +165,8 @@ public:
* Sets register bits to '1' according to the given RegisterMasks.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesRegister<Masks, Register<Access>>, ...))
static void set() {
apply<Masks...>([](auto r, auto m) { return r | m; });
}
@ -172,7 +182,8 @@ public:
* Clears register bits to '0' according to the given RegisterMasks.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesRegister<Masks, Register<Access>>, ...))
static void clear() {
apply<Masks...>([](auto r, auto m) { return r & ~m; });
}
@ -188,7 +199,8 @@ public:
* Toggles bits in the register according to the given RegisterMasks.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesRegister<Masks, Register<Access>>, ...))
static void toggle() {
apply<Masks...>([](auto r, auto m) { return r ^m; });
}
@ -206,7 +218,8 @@ public:
* If no masks are given, all register bits are returned.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesRegister<Masks, Register<Access>>, ...))
static auto read() {
if constexpr (sizeof...(Masks) > 0)
return read() & mergeMasks<Masks...>();
@ -219,7 +232,8 @@ public:
* If no masks are given, tests if the register has a non-zero value.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesRegister<Masks, Register<Access>>, ...))
static bool test() {
if constexpr (sizeof...(Masks) > 0) {
auto mask = mergeMasks<Masks...>();
@ -248,16 +262,16 @@ public:
}
}
private:
// Internal use only.
// Applies bit-masks to the register through the provided function.
// The provided function receives a pointer to the register's data and a
// bit-mask created by merging all provided bit-masks.
// All masks meant for this register are merged together; then, `fn`
// will receive the register's current value and the mask to carry out
// the operation. The result is written back to the register.
// If no masks are given, a mask selecting all bits is used.
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
static void apply(auto fn) {
constexpr static void apply(auto fn) {
if constexpr (sizeof...(Masks) > 0) {
auto mask = mergeMasks<Masks...>();
constexpr auto mask = mergeMasks<Masks...>();
if constexpr (mask)
write(fn(read(), mask));
} else {
@ -265,11 +279,11 @@ private:
}
}
private:
// Takes a list of bit-masks, and returns a merged mask of those which are
// meant for this register.
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
static auto mergeMasks() {
constexpr static auto mergeMasks() {
if constexpr (sizeof...(Masks) > 0) {
if constexpr ((isThis<typename Masks::reg> | ...)) {
auto mask =
@ -482,7 +496,8 @@ public:
* only written once.
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesSomeRegister<Masks, Registers...>, ...))
static void set() {
apply<Masks...>([](auto r, auto m) { return r | m; });
}
@ -493,7 +508,8 @@ public:
* Only reads and writes each register once; see set().
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesSomeRegister<Masks, Registers...>, ...))
static void clear() {
apply<Masks...>([](auto r, auto m) { return r & ~m; });
}
@ -504,7 +520,8 @@ public:
* Only reads and writes each register once; see set().
*/
template<typename... Masks>
requires(IsRegisterMask<Masks>, ...)
requires((IsRegisterMask<Masks>, ...) &&
(UsesSomeRegister<Masks, Registers...>, ...))
static void toggle() {
apply<Masks...>([](auto r, auto m) { return r ^ m; });
}
@ -523,6 +540,8 @@ public:
private:
template<typename... Masks>
requires((IsRegisterMask<Masks>, ...) &&
(UsesSomeRegister<Masks, Registers...>, ...))
static void apply(auto fn) {
(Registers::template apply<Masks...>(fn), ...);
}

Loading…
Cancel
Save