//! Register type implementation.
/**
* @file Register.h
* @author Nicolas Clauvelin (nclauvelin@sendyne.com)
* @copyright Copyright 2010-2022 Sendyne Corp. All rights reserved.
*
* This header provides the definitions related to register implementation.
*/
#ifndef CPPREG_REGISTER_H
#define CPPREG_REGISTER_H
#include "Memory.h"
#include "MergeWrite.h"
#include "ShadowValue.h"
namespace cppreg {
//! Register data structure.
/**
* @tparam reg_address Register address.
* @tparam reg_size Register size enum value.
* @tparam reset_value Register reset value (0x0 if unknown).
* @tparam use_shadow shadow Boolean flag to enable shadow value.
*
* This data structure will act as a container for fields and is
* therefore limited to a strict minimum. It only carries information
* about the register base address, size, and reset value.
* In practice, register are implemented by deriving from this class to
* create custom types.
*/
template
::type reset_value = 0x0,
bool use_shadow = false>
struct Register {
//! Register base type.
using type = typename TypeTraits::type; // NOLINT
//! MMIO pointer type.
using MMIO = volatile type;
//! Boolean flag for shadow value management.
using shadow = Shadow; // NOLINT
//! Register base address.
constexpr static auto base_address = reg_address;
//! Register size in bits.
constexpr static auto size = TypeTraits::bit_size;
//! Register reset value.
constexpr static auto reset = reset_value;
//! Register pack for memory device.
using pack = RegisterPack; // NOLINT
//! Memory modifier.
/**
* @return A reference to the writable register memory.
*/
static MMIO& rw_mem_device() {
using MemDevice = typename RegisterMemoryDevice::mem_device;
return MemDevice::template rw_memory();
}
//! Memory accessor.
/**
* @return A reference to the read-only register memory.
*/
static const MMIO& ro_mem_device() {
using MemDevice = typename RegisterMemoryDevice::mem_device;
return MemDevice::template ro_memory();
}
//! Merge write start function.
/**
* @tparam F Field on which to perform the first write operation.
* @param value Value to be written to the field.
* @return A merge write data structure to chain further writes.
*/
template
static MergeWrite merge_write(
const typename F::type value) noexcept {
const auto lhs = static_cast(value << F::offset);
return MergeWrite::create(
static_cast(lhs & F::mask));
}
//! Merge write start function for constant value.
/**
* @tparam F Field on which to perform the first write operation.
* @tparam value Value to be written to the field.
* @return A merge write data structure to chain further writes.
*/
template >
static T merge_write() noexcept {
// Check overflow.
static_assert(
internals::check_overflow> F::offset)>::
value,
"Register::merge_write:: value too large for the field");
return T::create();
}
// Sanity check.
static_assert(size != 0, "Register:: register definition with zero size");
// Enforce alignment.
static_assert(internals::is_aligned::byte_size>::value,
"Register:: address is mis-aligned for register type");
};
} // namespace cppreg
#endif // CPPREG_REGISTER_H