From bbdf51315618325f904d6a2729584bd422c48a8f Mon Sep 17 00:00:00 2001 From: Nicolas Clauvelin Date: Tue, 13 Mar 2018 08:47:47 -0400 Subject: [PATCH] ADD MIXED REGISTER SIZES SUPPORT TO REGISTER PACK This relies on a memory map implementation based on std::array and specialized over the register size. PackedRegister can now be used with all supported register sizes (i.e., widths). This relates to #7 and the finalization of the API before performance testing. --- cppreg.h | 7 +- register/Register.h | 8 +-- register/RegisterPack.h | 148 ++++++++++++++++++++++++++-------------- single/cppreg-all.h | 60 +++++++++------- 4 files changed, 139 insertions(+), 84 deletions(-) diff --git a/cppreg.h b/cppreg.h index 475b94d..72afa45 100644 --- a/cppreg.h +++ b/cppreg.h @@ -10,10 +10,11 @@ #define CPPREG_CPPREG_H -#include "Register.h" -#include "Field.h" -#include "MergeWrite.h" #include "Overflow.h" +#include "MergeWrite.h" +#include "Register.h" +#include "RegisterPack.h" +#include "Field.h" #endif // CPPREG_CPPREG_H diff --git a/register/Register.h b/register/Register.h index a964acd..63f0651 100644 --- a/register/Register.h +++ b/register/Register.h @@ -23,10 +23,10 @@ namespace cppreg { //! Register data structure. /** - * @tparam address Register address. - * @tparam width Register total width (i.e., size). - * @tparam reset Register reset value (0x0 if unknown). - * @tparam shadow Boolean flag to enable shadow value (enabled if `true`). + * @tparam RegAddress Register address. + * @tparam RegWidth Register total width (i.e., size). + * @tparam ResetValue Register reset value (0x0 if unknown). + * @tparam UseShadow 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 diff --git a/register/RegisterPack.h b/register/RegisterPack.h index a802745..33ea6a1 100644 --- a/register/RegisterPack.h +++ b/register/RegisterPack.h @@ -19,90 +19,108 @@ namespace cppreg { + //! Memory map implementation. + /** + * @tparam Address Memory base address. + * @tparam N Memory size in bytes. + * @tparam W Width in bits of the memory "elements". + * + * This structure is used to map an array structure onto a memory region. + * The width parameter will correspond to the register size. + */ + template + struct memory_map { + + //! Array type. + using mem_array_t = std::array< + volatile typename RegisterType::type, + N / sizeof(typename RegisterType::type) + >; + + //! Static reference to memory array. + /** + * This is defined below. + */ + static mem_array_t& array; + + }; + + //! Memory array reference definition. + template + typename memory_map::mem_array_t& + memory_map::array = *( + reinterpret_cast::mem_array_t*>( + Address + ) + ); + + //! Register pack base implementation. /** + * @tparam PackBase Pack base address. + * @tparam PackByteSize Pack size in bytes. */ template < Address_t PackBase, - Width_t RegWidth, - std::uint32_t N + std::uint32_t PackByteSize > struct RegisterPack { - //! Pack register type. - using register_type = typename RegisterType::type; - - //! Type alias for byte array. - using mem_array_t =std::array; - //! Base address. constexpr static const Address_t pack_base = PackBase; //! Pack size in bytes. - constexpr static const std::uint32_t size_in_bytes = - N * sizeof(register_type); - - //! Register width in the pack. - constexpr static const Width_t register_width = RegWidth; - - //! Reference to the byte array. - /** - * This is explicitly defined below. - */ - static mem_array_t& _mem_array; + constexpr static const std::uint32_t size_in_bytes = PackByteSize; }; - //! RegisterPack byte array reference definition. - template < - Address_t PackBase, - Width_t RegWidth, - std::uint32_t N - > - typename RegisterPack::mem_array_t& - RegisterPack::_mem_array = - *( - reinterpret_cast< - RegisterPack::mem_array_t* const - >( - RegisterPack::pack_base - ) - ); - //! Packed register implementation. /** + * @tparam RegisterPack Pack to which the register belongs. + * @tparam BitOffset Offset in bits for the register with respect to base. + * @tparam RegWidth Register width. + * @tparam ResetValue Register reset value (0x0 if unknown). + * @tparam UseShadow shadow Boolean flag to enable shadow value. * * This implementation is intended to be used when defining a register - * that belongs to a type. + * that belongs to a peripheral group. */ template < typename RegisterPack, - std::uint32_t OffsetInPack, - typename RegisterType::type ResetValue = 0x0, + std::uint32_t BitOffset, + Width_t RegWidth, + typename RegisterType::type ResetValue = 0x0, bool UseShadow = false > struct PackedRegister : Register< - RegisterPack::pack_base + OffsetInPack, - RegisterPack::register_width, + RegisterPack::pack_base + (BitOffset / 8u), + RegWidth, ResetValue, UseShadow > { //! Register type. using base_reg = Register< - RegisterPack::pack_base + OffsetInPack, - RegisterPack::register_width, + RegisterPack::pack_base + (BitOffset / 8u), + RegWidth, ResetValue, UseShadow >; + //! Memory map type. + using mem_map_t = memory_map< + RegisterPack::pack_base, + RegisterPack::size_in_bytes, + RegWidth + >; + //! Memory modifier. /** * @return A reference to the writable register memory. */ static typename base_reg::MMIO_t& rw_mem_device() { - return RegisterPack::_mem_array[OffsetInPack]; + return mem_map_t::array[BitOffset / RegWidth]; }; //! Memory accessor. @@ -110,14 +128,25 @@ namespace cppreg { * @return A reference to the read-only register memory. */ static const typename base_reg::MMIO_t& ro_mem_device() { - return RegisterPack::_mem_array[OffsetInPack]; + return mem_map_t::array[BitOffset / RegWidth]; }; // Safety check to detect if are overflowing the pack. - static_assert((OffsetInPack + (RegisterPack::register_width / 8u)) <= - RegisterPack::size_in_bytes, + static_assert((BitOffset / 8u) <= RegisterPack::size_in_bytes, "packed register is overflowing the pack"); + // Safety check to detect if the register is mis-aligned. + // A register is mis-aligned if it its offset is not a multiple of + // its size and if the pack base address alignment is different from + // its type alignment. + static_assert(( + (BitOffset % RegWidth) == 0 + && + (RegisterPack::pack_address % (RegWidth / 8u) == 0) + ), + "register mis-alignment with respect to pack base"); + + }; @@ -137,22 +166,35 @@ namespace cppreg { //! Template for loop implementation. + /** + * @tparam start Start index value. + * @tparam end End index value. + */ template struct for_loop { + + //! Loop method. + /** + * @tparam Op Operation to be called at each iteration. + * + * This will call Op for the range [start, end). + */ template