//! 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