1
0
mirror of https://github.com/sendyne/cppreg.git synced 2025-05-09 15:14:05 +00:00
cppreg/register/MergeWrite.h
Nicolas Clauvelin d7404ab946 INITIAL COMMIT
2018-02-20 15:38:59 -05:00

162 lines
4.6 KiB
C++

//! Merge write implementation.
/**
* @file MergeWrite.h
* @author Nicolas Clauvelin (nclauvelin@sendyne.com)
* @copyright Copyright 2010-2018 Sendyne Corp. All rights reserved.
*
* The "merge write" implementation is designed to make it possible to merge
* write operations on different fields into a single one.
*/
#ifndef CPPREG_MERGEWRITE_H
#define CPPREG_MERGEWRITE_H
#include "Overflow.h"
#include "AccessPolicy.h"
#include <functional>
//! cppreg namespace.
namespace cppreg {
//! Write operation holding structure.
/**
* @tparam Register Underlying register for the final write operation.
*/
template <typename Register>
class MergeWrite {
public:
//! Type alias to register base type.
using base_type = typename Register::type;
//! Static instantiation method.
static MergeWrite create_instance(const base_type value,
const base_type mask) noexcept {
MergeWrite mw;
mw._accumulated_value = value;
mw._combined_mask = mask;
return mw;
};
//!@ Move constructor.
MergeWrite(MergeWrite&& mw) noexcept
: _accumulated_value(mw._accumulated_value),
_combined_mask(mw._combined_mask) {
};
//!@{ Non-copyable.
MergeWrite(const MergeWrite&) = delete;
MergeWrite& operator=(const MergeWrite&) = delete;
//!@}
//! Destructor.
/**
* This is where the write operation is performed.
*/
~MergeWrite() {
// Get memory pointer.
typename Register::MMIO_t* const mmio_device =
Register::rw_mem_pointer();
// Write to the whole register using the current accumulated value
// and combined mask.
// No offset needed because we write to the whole register.
*mmio_device = static_cast<base_type>(
(*mmio_device & ~_combined_mask) |
((_accumulated_value) & _combined_mask)
);
};
//! With method.
/**
* @tparam F Field type describing where to write in the register.
* @param value Value to write to the register.
* @return A reference to the current merge write data.
*
* This method is used to add another operation to the final merged
* write.
*/
template <typename F>
MergeWrite&& with(const base_type value) && noexcept {
// Check that the field belongs to the register.
static_assert(std::is_same<
typename F::parent_register,
Register
>::value,
"field is not from the same register in merge_write");
// Update accumulated value.
F::policy::write(&_accumulated_value,
F::mask,
F::offset,
value);
// Update combine mask.
_combined_mask = _combined_mask | F::mask;
return std::move(*this);
};
//! With method with compile-time check.
/**
* @tparam F Field type describing where to write in the register.
* @param value Value to write to the register.
* @return A reference to the current merge write data.
*
* This method is used to add another operation to the final merged
* write.
*
* This method performs a compile-time check to avoid overflowing the
* field.
*/
template <
typename F,
base_type value,
typename T = MergeWrite
>
typename std::enable_if<
(internals::check_overflow<
Register::size, value, (F::mask >> F::offset)
>::result::value),
T
>::type&&
with() && noexcept {
return std::move(*this).template with<F>(value);
};
private:
// Disabled for shadow value register.
static_assert(!Register::shadow::use_shadow,
"merge write is not available for shadow value register");
// Private default constructor.
MergeWrite() : _accumulated_value(0u),
_combined_mask(0u) {};
// Accumulated value.
base_type _accumulated_value;
// Combined mask.
base_type _combined_mask;
};
}
#endif // CPPREG_MERGEWRITE_H