BUG FIX IN MERGER WRITE IMPLEMENTATION FOR NON CONSTANT VALUES

* For write-only registers the merge write implementation for non-constant values
was properly updating the cache value.
* Unnecessary `inline` have been removed.
This commit is contained in:
Nicolas Clauvelin 2018-11-16 09:28:47 -05:00
parent e59bc356c8
commit 2e0d502674
6 changed files with 112 additions and 122 deletions

View File

@ -58,7 +58,7 @@ namespace cppreg {
* @return The content of the register field.
*/
template <typename U = void>
inline static T read(
static T read(
const MMIO_t& mmio_device,
typename std::enable_if<!is_trivial, U*>::type = nullptr
) noexcept {
@ -71,7 +71,7 @@ namespace cppreg {
* @return The content of the register field.
*/
template <typename U = void>
inline static T read(
static T read(
const MMIO_t& mmio_device,
typename std::enable_if<is_trivial, U*>::type = nullptr
) noexcept {
@ -111,7 +111,7 @@ namespace cppreg {
* @param value Value to be written to the register field.
*/
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
T value,
typename std::enable_if<!is_trivial, U*>::type = nullptr
@ -127,7 +127,7 @@ namespace cppreg {
* @param value Value to be written to the register field.
*/
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
T value,
typename std::enable_if<is_trivial, U*>::type = nullptr
@ -170,7 +170,7 @@ namespace cppreg {
* @param mmio_device Pointer to the register memory device.
*/
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
typename std::enable_if<!is_trivial, U*>::type = nullptr
) noexcept {
@ -184,7 +184,7 @@ namespace cppreg {
* @param mmio_device Pointer to the register memory device.
*/
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
typename std::enable_if<is_trivial, U*>::type = nullptr
) noexcept {
@ -207,7 +207,7 @@ namespace cppreg {
* @return The value at the field location.
*/
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static T read(const MMIO_t& mmio_device) noexcept {
static T read(const MMIO_t& mmio_device) noexcept {
return RegisterRead<MMIO_t, T, mask, offset>::read(mmio_device);
};
@ -227,7 +227,7 @@ namespace cppreg {
* @param value Value to be written at the field location.
*/
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static void write(MMIO_t& mmio_device,
static void write(MMIO_t& mmio_device,
const T value) noexcept {
RegisterWrite<MMIO_t, T, mask, offset>::write(mmio_device, value);
};
@ -244,7 +244,7 @@ namespace cppreg {
template <
typename MMIO_t, typename T, T mask, FieldOffset_t offset, T value
>
inline static void write(MMIO_t& mmio_device) noexcept {
static void write(MMIO_t& mmio_device) noexcept {
RegisterWriteConstant<MMIO_t, T, mask, offset, value>
::write(mmio_device);
};
@ -256,7 +256,7 @@ namespace cppreg {
* @param mmio_device Pointer to register mapped memory.
*/
template <typename MMIO_t, typename T, T mask>
inline static void set(MMIO_t& mmio_device)
static void set(MMIO_t& mmio_device)
noexcept {
RegisterWriteConstant<MMIO_t, T, mask, 0u, mask>
::write(mmio_device);
@ -270,7 +270,7 @@ namespace cppreg {
* @param mmio_device Pointer to register mapped memory.
*/
template <typename MMIO_t, typename T, T mask>
inline static void clear(MMIO_t& mmio_device)
static void clear(MMIO_t& mmio_device)
noexcept {
RegisterWriteConstant<MMIO_t, T, mask, 0u, ~mask>
::write(mmio_device);
@ -284,7 +284,7 @@ namespace cppreg {
* @param mmio_device Pointer to register mapped memory.
*/
template <typename MMIO_t, typename T, T mask>
inline static void toggle(MMIO_t& mmio_device)
static void toggle(MMIO_t& mmio_device)
noexcept {
mmio_device = static_cast<T>((mmio_device) ^ mask);
};
@ -305,8 +305,7 @@ namespace cppreg {
* @param value Value to be written at the field location.
*/
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static void write(MMIO_t& mmio_device,
const T value) noexcept {
static void write(MMIO_t& mmio_device, const T value) noexcept {
// For write-only fields we can only write to the whole register.
RegisterWrite<MMIO_t, T, type_mask<T>::value, 0u>::write(
@ -326,7 +325,7 @@ namespace cppreg {
template <
typename MMIO_t, typename T, T mask, FieldOffset_t offset, T value
>
inline static void write(MMIO_t& mmio_device) noexcept {
static void write(MMIO_t& mmio_device) noexcept {
// For write-only fields we can only write to the whole register.
RegisterWriteConstant<

View File

@ -89,7 +89,7 @@ namespace cppreg {
/**
* @return Field value.
*/
inline static type read() noexcept {
static type read() noexcept {
return policy::template read<MMIO_t, type, mask, offset>(
parent_register::ro_mem_device()
);
@ -100,7 +100,7 @@ namespace cppreg {
* @param value Value to be written to the field.
*/
template <typename T = type>
inline static void
static void
write(const typename std::enable_if<!has_shadow, T>::type value)
noexcept {
policy::template write<MMIO_t, type, mask, offset>(
@ -114,7 +114,7 @@ namespace cppreg {
* @param value Value to be written to the field.
*/
template <typename T = type>
inline static void
static void
write(const typename std::enable_if<has_shadow, T>::type value)
noexcept {
@ -140,14 +140,14 @@ namespace cppreg {
* field and uses the constant write implementation.
*/
template <type value, typename T = void>
inline static
typename std::enable_if<
!has_shadow
&&
check_overflow<value>::value,
T
>::type
write() noexcept {
static void write(
typename std::enable_if<
!has_shadow
&&
check_overflow<value>::value,
T
>::type* = nullptr
) noexcept {
policy::template write<MMIO_t, type, mask, offset, value>(
parent_register::rw_mem_device()
);
@ -161,14 +161,14 @@ namespace cppreg {
* field and uses the constant write implementation.
*/
template <type value, typename T = void>
inline static
typename std::enable_if<
has_shadow
&&
check_overflow<value>::value,
T
>::type
write() noexcept {
static void write(
typename std::enable_if<
has_shadow
&&
check_overflow<value>::value,
T
>::type* = nullptr
) noexcept {
// For this particular we simply forward to the non-constant
// implementation because the shadow value needs to be updated.
@ -180,7 +180,7 @@ namespace cppreg {
/**
* This method will set all bits in the field.
*/
inline static void set() noexcept {
static void set() noexcept {
policy::template
set<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
@ -189,7 +189,7 @@ namespace cppreg {
/**
* This method will clear all bits in the field.
*/
inline static void clear() noexcept {
static void clear() noexcept {
policy::template
clear<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
@ -198,7 +198,7 @@ namespace cppreg {
/**
* This method will toggle all bits in the field.
*/
inline static void toggle() noexcept {
static void toggle() noexcept {
policy::template
toggle<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
@ -207,7 +207,7 @@ namespace cppreg {
/**
* @return `true` if all the bits are set to 1, `false` otherwise.
*/
inline static bool is_set() noexcept {
static bool is_set() noexcept {
return (Field::read() == (mask >> offset));
};
@ -215,7 +215,7 @@ namespace cppreg {
/**
* @return `true` if all the bits are set to 0, `false` otherwise.
*/
inline static bool is_clear() noexcept {
static bool is_clear() noexcept {
return (Field::read() == 0u);
};

View File

@ -68,13 +68,13 @@ namespace cppreg {
constexpr static const base_type _combined_mask = mask;
// Default constructor.
MergeWrite_tmpl() {};
MergeWrite_tmpl() = default;
public:
//! Instantiation method.
inline static MergeWrite_tmpl make() noexcept { return {}; };
static MergeWrite_tmpl make() noexcept { return {}; };
//!@{ Non-copyable and non-moveable.
MergeWrite_tmpl(const MergeWrite_tmpl&) = delete;
@ -88,7 +88,7 @@ namespace cppreg {
/**
* This is where the write happens.
*/
inline void done() const && noexcept {
void done() const && noexcept {
// Get memory pointer.
typename Register::MMIO_t& mmio_device =
@ -124,7 +124,6 @@ namespace cppreg {
F::mask)
>
>
inline
typename std::enable_if<
(internals::check_overflow<
typename Register::type, new_value, (F::mask >> F::offset)
@ -196,7 +195,7 @@ namespace cppreg {
/**
* This is where the write happens.
*/
inline void done() const && noexcept {
void done() const && noexcept {
// Get memory pointer.
typename Register::MMIO_t& mmio_device =
@ -221,8 +220,8 @@ namespace cppreg {
* @return A reference to the current merge write data.
*/
template <typename F>
inline MergeWrite<Register, _combined_mask | F::mask> with
(const base_type value) && noexcept {
MergeWrite<Register, _combined_mask | F::mask>
with(const base_type value) && noexcept {
// Check that the field belongs to the register.
static_assert(std::is_same<
@ -232,12 +231,8 @@ namespace cppreg {
"field is not from the same register in merge_write");
// Update accumulated value.
F::policy::template write<
base_type,
base_type,
F::mask,
F::offset
>(_accumulated_value, value);
_accumulated_value = (_accumulated_value & ~F::mask)
| ((value << F::offset) & F::mask);
return
std::move(
@ -256,7 +251,8 @@ namespace cppreg {
// Private default constructor.
constexpr MergeWrite() : _accumulated_value(0u) {};
constexpr MergeWrite(const base_type v) : _accumulated_value(v) {};
constexpr explicit MergeWrite(const base_type v) :
_accumulated_value(v) {};
// Accumulated value.
base_type _accumulated_value;

View File

@ -84,7 +84,7 @@ namespace cppreg {
* @return A merge write data structure to chain further writes.
*/
template <typename F>
inline static MergeWrite<typename F::parent_register, F::mask>
static MergeWrite<typename F::parent_register, F::mask>
merge_write(const typename F::type value) noexcept {
return
MergeWrite<typename F::parent_register, F::mask>
@ -107,7 +107,7 @@ namespace cppreg {
value
>
>
inline static
static
typename std::enable_if<
internals::check_overflow<
type, value, (F::mask >> F::offset)

View File

@ -83,7 +83,7 @@ namespace cppreg {
/**
* @return A reference to the writable register memory.
*/
inline static typename base_reg::MMIO_t& rw_mem_device() noexcept {
static typename base_reg::MMIO_t& rw_mem_device() noexcept {
return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size];
};
@ -92,7 +92,7 @@ namespace cppreg {
/**
* @return A reference to the read-only register memory.
*/
inline static const typename base_reg::MMIO_t& ro_mem_device() noexcept {
static const typename base_reg::MMIO_t& ro_mem_device() noexcept {
return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size];
};
@ -166,7 +166,7 @@ namespace cppreg {
* This will call Op for the range [start, end).
*/
template <typename Func>
inline static void apply() noexcept {
static void apply() noexcept {
Func().template operator()<start>();
if (start < end)
for_loop<start + 1ul, end>::template apply<Func>();
@ -184,7 +184,7 @@ namespace cppreg {
* use lambda [](auto index) { index.value will be the loop index};
*/
template <typename Op>
inline static void apply(Op&& f) noexcept {
static void apply(Op&& f) noexcept {
if (start < end) {
f(std::integral_constant<std::size_t, start>{});
for_loop<start + 1ul, end>::apply(std::forward<Op>(f));
@ -196,10 +196,10 @@ namespace cppreg {
template <std::size_t end>
struct for_loop<end, end> {
template <typename Func>
inline static void apply() noexcept {};
static void apply() noexcept {};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op&& f) noexcept {};
static void apply(Op&& f) noexcept {};
#endif // __cplusplus 201402L
};

View File

@ -109,14 +109,14 @@ namespace cppreg {
constexpr static const bool is_trivial =
(mask == type_mask<T>::value) && (offset == 0u);
template <typename U = void>
inline static T read(
static T read(
const MMIO_t& mmio_device,
typename std::enable_if<!is_trivial, U*>::type = nullptr
) noexcept {
return static_cast<T>((mmio_device & mask) >> offset);
};
template <typename U = void>
inline static T read(
static T read(
const MMIO_t& mmio_device,
typename std::enable_if<is_trivial, U*>::type = nullptr
) noexcept {
@ -128,7 +128,7 @@ namespace cppreg {
constexpr static const bool is_trivial =
(mask == type_mask<T>::value) && (offset == 0u);
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
T value,
typename std::enable_if<!is_trivial, U*>::type = nullptr
@ -138,7 +138,7 @@ namespace cppreg {
);
};
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
T value,
typename std::enable_if<is_trivial, U*>::type = nullptr
@ -153,7 +153,7 @@ namespace cppreg {
constexpr static const bool is_trivial =
(mask == type_mask<T>::value) && (offset == 0u);
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
typename std::enable_if<!is_trivial, U*>::type = nullptr
) noexcept {
@ -162,7 +162,7 @@ namespace cppreg {
);
};
template <typename U = void>
inline static void write(
static void write(
MMIO_t& mmio_device,
typename std::enable_if<is_trivial, U*>::type = nullptr
) noexcept {
@ -171,45 +171,44 @@ namespace cppreg {
};
struct read_only {
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static T read(const MMIO_t& mmio_device) noexcept {
static T read(const MMIO_t& mmio_device) noexcept {
return RegisterRead<MMIO_t, T, mask, offset>::read(mmio_device);
};
};
struct read_write : read_only {
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static void write(MMIO_t& mmio_device,
static void write(MMIO_t& mmio_device,
const T value) noexcept {
RegisterWrite<MMIO_t, T, mask, offset>::write(mmio_device, value);
};
template <
typename MMIO_t, typename T, T mask, FieldOffset_t offset, T value
>
inline static void write(MMIO_t& mmio_device) noexcept {
static void write(MMIO_t& mmio_device) noexcept {
RegisterWriteConstant<MMIO_t, T, mask, offset, value>
::write(mmio_device);
};
template <typename MMIO_t, typename T, T mask>
inline static void set(MMIO_t& mmio_device)
static void set(MMIO_t& mmio_device)
noexcept {
RegisterWriteConstant<MMIO_t, T, mask, 0u, mask>
::write(mmio_device);
};
template <typename MMIO_t, typename T, T mask>
inline static void clear(MMIO_t& mmio_device)
static void clear(MMIO_t& mmio_device)
noexcept {
RegisterWriteConstant<MMIO_t, T, mask, 0u, ~mask>
::write(mmio_device);
};
template <typename MMIO_t, typename T, T mask>
inline static void toggle(MMIO_t& mmio_device)
static void toggle(MMIO_t& mmio_device)
noexcept {
mmio_device = static_cast<T>((mmio_device) ^ mask);
};
};
struct write_only {
template <typename MMIO_t, typename T, T mask, FieldOffset_t offset>
inline static void write(MMIO_t& mmio_device,
const T value) noexcept {
static void write(MMIO_t& mmio_device, const T value) noexcept {
RegisterWrite<MMIO_t, T, type_mask<T>::value, 0u>::write(
mmio_device, ((value << offset) & mask)
);
@ -217,7 +216,7 @@ namespace cppreg {
template <
typename MMIO_t, typename T, T mask, FieldOffset_t offset, T value
>
inline static void write(MMIO_t& mmio_device) noexcept {
static void write(MMIO_t& mmio_device) noexcept {
RegisterWriteConstant<
MMIO_t, T, type_mask<T>::value, 0u, ((value << offset) & mask)
>
@ -281,15 +280,15 @@ namespace cppreg {
constexpr static const base_type _accumulated_value =
((value << offset) & mask);
constexpr static const base_type _combined_mask = mask;
MergeWrite_tmpl() {};
MergeWrite_tmpl() = default;
public:
inline static MergeWrite_tmpl make() noexcept { return {}; };
static MergeWrite_tmpl make() noexcept { return {}; };
MergeWrite_tmpl(const MergeWrite_tmpl&) = delete;
MergeWrite_tmpl& operator=(const MergeWrite_tmpl&) = delete;
MergeWrite_tmpl& operator=(MergeWrite_tmpl&&) = delete;
MergeWrite_tmpl operator=(MergeWrite_tmpl) = delete;
MergeWrite_tmpl(MergeWrite_tmpl&&) = delete;
inline void done() const && noexcept {
void done() const && noexcept {
typename Register::MMIO_t& mmio_device =
Register::rw_mem_device();
RegisterWriteConstant<
@ -311,7 +310,6 @@ namespace cppreg {
F::mask)
>
>
inline
typename std::enable_if<
(internals::check_overflow<
typename Register::type, new_value, (F::mask >> F::offset)
@ -345,7 +343,7 @@ namespace cppreg {
MergeWrite(const MergeWrite&) = delete;
MergeWrite& operator=(const MergeWrite&) = delete;
MergeWrite& operator=(MergeWrite&&) = delete;
inline void done() const && noexcept {
void done() const && noexcept {
typename Register::MMIO_t& mmio_device =
Register::rw_mem_device();
RegisterWrite<
@ -356,19 +354,15 @@ namespace cppreg {
>::write(mmio_device, _accumulated_value);
};
template <typename F>
inline MergeWrite<Register, _combined_mask | F::mask> with
(const base_type value) && noexcept {
MergeWrite<Register, _combined_mask | F::mask>
with(const base_type value) && noexcept {
static_assert(std::is_same<
typename F::parent_register,
Register
>::value,
"field is not from the same register in merge_write");
F::policy::template write<
base_type,
base_type,
F::mask,
F::offset
>(_accumulated_value, value);
_accumulated_value = (_accumulated_value & ~F::mask)
| ((value << F::offset) & F::mask);
return
std::move(
MergeWrite<Register, (_combined_mask | F::mask)>
@ -379,7 +373,8 @@ namespace cppreg {
static_assert(!Register::shadow::value,
"merge write is not available for shadow value register");
constexpr MergeWrite() : _accumulated_value(0u) {};
constexpr MergeWrite(const base_type v) : _accumulated_value(v) {};
constexpr explicit MergeWrite(const base_type v) :
_accumulated_value(v) {};
base_type _accumulated_value;
};
}
@ -410,7 +405,7 @@ namespace cppreg {
return *(reinterpret_cast<const MMIO_t* const>(base_address));
};
template <typename F>
inline static MergeWrite<typename F::parent_register, F::mask>
static MergeWrite<typename F::parent_register, F::mask>
merge_write(const typename F::type value) noexcept {
return
MergeWrite<typename F::parent_register, F::mask>
@ -426,7 +421,7 @@ namespace cppreg {
value
>
>
inline static
static
typename std::enable_if<
internals::check_overflow<
type, value, (F::mask >> F::offset)
@ -482,11 +477,11 @@ namespace cppreg {
RegisterPack::size_in_bytes,
reg_size
>;
inline static typename base_reg::MMIO_t& rw_mem_device() noexcept {
static typename base_reg::MMIO_t& rw_mem_device() noexcept {
return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size];
};
inline static const typename base_reg::MMIO_t& ro_mem_device() noexcept {
static const typename base_reg::MMIO_t& ro_mem_device() noexcept {
return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size];
};
@ -521,14 +516,14 @@ namespace cppreg {
template <std::size_t start, std::size_t end>
struct for_loop {
template <typename Func>
inline static void apply() noexcept {
static void apply() noexcept {
Func().template operator()<start>();
if (start < end)
for_loop<start + 1ul, end>::template apply<Func>();
};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op&& f) noexcept {
static void apply(Op&& f) noexcept {
if (start < end) {
f(std::integral_constant<std::size_t, start>{});
for_loop<start + 1ul, end>::apply(std::forward<Op>(f));
@ -539,10 +534,10 @@ namespace cppreg {
template <std::size_t end>
struct for_loop<end, end> {
template <typename Func>
inline static void apply() noexcept {};
static void apply() noexcept {};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op&& f) noexcept {};
static void apply(Op&& f) noexcept {};
#endif
};
template <typename IndexedPack>
@ -577,13 +572,13 @@ namespace cppreg {
value,
(mask >> offset)
> {};
inline static type read() noexcept {
static type read() noexcept {
return policy::template read<MMIO_t, type, mask, offset>(
parent_register::ro_mem_device()
);
};
template <typename T = type>
inline static void
static void
write(const typename std::enable_if<!has_shadow, T>::type value)
noexcept {
policy::template write<MMIO_t, type, mask, offset>(
@ -592,7 +587,7 @@ namespace cppreg {
);
};
template <typename T = type>
inline static void
static void
write(const typename std::enable_if<has_shadow, T>::type value)
noexcept {
RegisterWrite<type, type, mask, offset>
@ -603,45 +598,45 @@ namespace cppreg {
);
};
template <type value, typename T = void>
inline static
typename std::enable_if<
!has_shadow
&&
check_overflow<value>::value,
T
>::type
write() noexcept {
static void write(
typename std::enable_if<
!has_shadow
&&
check_overflow<value>::value,
T
>::type* = nullptr
) noexcept {
policy::template write<MMIO_t, type, mask, offset, value>(
parent_register::rw_mem_device()
);
};
template <type value, typename T = void>
inline static
typename std::enable_if<
has_shadow
&&
check_overflow<value>::value,
T
>::type
write() noexcept {
static void write(
typename std::enable_if<
has_shadow
&&
check_overflow<value>::value,
T
>::type* = nullptr
) noexcept {
write(value);
};
inline static void set() noexcept {
static void set() noexcept {
policy::template
set<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
inline static void clear() noexcept {
static void clear() noexcept {
policy::template
clear<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
inline static void toggle() noexcept {
static void toggle() noexcept {
policy::template
toggle<MMIO_t, type, mask>(parent_register::rw_mem_device());
};
inline static bool is_set() noexcept {
static bool is_set() noexcept {
return (Field::read() == (mask >> offset));
};
inline static bool is_clear() noexcept {
static bool is_clear() noexcept {
return (Field::read() == 0u);
};
static_assert(parent_register::size >= width,