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