From 5925c223c84eb885a09d8b6642f3874670951cee Mon Sep 17 00:00:00 2001 From: Nicolas Clauvelin Date: Fri, 16 Mar 2018 14:12:52 -0400 Subject: [PATCH] INTERNAL IMPLEMENTATIONS RELOCATED TO AN INTERNALS HEADER The Internals.h contains the overflow, is_aligned and memory array implementations. --- cppreg.h | 2 +- register/Internals.h | 102 ++++++++++++++++++++ register/MergeWrite.h | 2 +- register/Overflow.h | 44 --------- register/Register.h | 9 +- register/RegisterPack.h | 103 ++++++--------------- register/Traits.h | 16 +--- single/cppreg-all.h | 199 ++++++++++++++++++++-------------------- 8 files changed, 243 insertions(+), 234 deletions(-) create mode 100644 register/Internals.h delete mode 100644 register/Overflow.h diff --git a/cppreg.h b/cppreg.h index 72afa45..759ec50 100644 --- a/cppreg.h +++ b/cppreg.h @@ -10,7 +10,7 @@ #define CPPREG_CPPREG_H -#include "Overflow.h" +#include "Internals.h" #include "MergeWrite.h" #include "Register.h" #include "RegisterPack.h" diff --git a/register/Internals.h b/register/Internals.h new file mode 100644 index 0000000..e80f7f0 --- /dev/null +++ b/register/Internals.h @@ -0,0 +1,102 @@ +//! Internals implementation. +/** + * @file Internals.h + * @author Nicolas Clauvelin (nclauvelin@sendyne.com) + * @copyright Copyright 2010-2018 Sendyne Corp. All rights reserved. + * + * This header collects various implementations which are required for cppreg + * implementation but not intended to be fully exposed to the user. + */ + + +#include "cppreg_Defines.h" +#include "Traits.h" + + +#ifndef CPPREG_INTERNALS_H +#define CPPREG_INTERNALS_H + + +//! cppreg::internals namespace. +namespace cppreg { +namespace internals { + + + //! Overflow check implementation. + /** + * @tparam T Data type. + * @tparam value Value to check. + * @tparam limit Overflow limit value. + * + * This structure defines a type result set to std::true_type if there is + * no overflow and set to std::false_type if there is overflow. + * There is overflow if value if strictly larger than limit. + */ + template < + typename T, + T value, + T limit + > + struct check_overflow : std::integral_constant {}; + + + //! is_aligned implementation. + /** + * @tparam address Address to be checked for alignment. + * @tparam alignment Alignment boundary in bytes. + * + * This will only derived from std::true_type if the address is aligned. + */ + template + struct is_aligned : std::integral_constant< + bool, + (address & (alignment - 1)) == 0 + > { + }; + + + //! Memory map implementation for packed registers. + /** + * @tparam address Memory region base address. + * @tparam n Memory size in bytes. + * @tparam reg_size Register bit size enum value. + * + * This structure is used to map an array structure onto a memory region. + * The size of the array elements is defined by the register size. + */ + template + struct memory_map { + + //! Array type. + using mem_array_t = std::array< + volatile typename TypeTraits::type, + n / sizeof(typename TypeTraits::type) + >; + + //! Static reference to memory array. + static mem_array_t& array; + + // Alignment check. + static_assert( + is_aligned::byte_size>::value, + "memory_map: base address is mis-aligned for register type" + ); + + }; + + //! Memory array reference definition. + template + typename memory_map::mem_array_t& + memory_map::array = *( + reinterpret_cast + ::mem_array_t*>( + address + ) + ); + + +} +} + + +#endif // CPPREG_INTERNALS_H diff --git a/register/MergeWrite.h b/register/MergeWrite.h index 28bd887..829d316 100644 --- a/register/MergeWrite.h +++ b/register/MergeWrite.h @@ -18,7 +18,7 @@ #define CPPREG_MERGEWRITE_H -#include "Overflow.h" +#include "Internals.h" #include "AccessPolicy.h" #include diff --git a/register/Overflow.h b/register/Overflow.h deleted file mode 100644 index bbd5684..0000000 --- a/register/Overflow.h +++ /dev/null @@ -1,44 +0,0 @@ -//! Overflow check implementation. -/** - * @file Overflow.h - * @author Nicolas Clauvelin (nclauvelin@sendyne.com) - * @copyright Copyright 2010-2018 Sendyne Corp. All rights reserved. - */ - - -#ifndef CPPREG_OVERFLOW_H -#define CPPREG_OVERFLOW_H - - -#include "Traits.h" -#include - - -//! cppreg::internals namespace. -namespace cppreg { -namespace internals { - - - //! Overflow check implementation. - /** - * @tparam T Data type. - * @tparam value Value to check. - * @tparam limit Overflow limit value. - * - * This structure defines a type result set to std::true_type if there is - * no overflow and set to std::false_type if there is overflow. - * There is overflow if value if strictly larger than limit. - */ - template < - typename T, - T value, - T limit - > - struct check_overflow : std::integral_constant {}; - - -} -} - - -#endif // CPPREG_OVERFLOW_H diff --git a/register/Register.h b/register/Register.h index 05653e3..6b94f43 100644 --- a/register/Register.h +++ b/register/Register.h @@ -120,7 +120,14 @@ namespace cppreg { // Sanity check. static_assert(size != 0u, - "defining a Register type of zero size is not allowed"); + "Register: register definition with zero size"); + + // Enforce alignment. + static_assert( + internals::is_aligned::byte_size> + ::value, + "Register: address is mis-aligned for register type" + ); }; diff --git a/register/RegisterPack.h b/register/RegisterPack.h index b0f269b..086920b 100644 --- a/register/RegisterPack.h +++ b/register/RegisterPack.h @@ -9,6 +9,7 @@ #include "Register.h" +#include "Internals.h" #ifndef CPPREG_REGISTERPACK_H @@ -19,62 +20,6 @@ namespace cppreg { -//! cppreg::internals namespace. -namespace internals { - - //! Memory map implementation. - /** - * @tparam address Memory base address. - * @tparam n Memory size in bytes. - * @tparam reg_size Register bit size for the array 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 TypeTraits::type, - n / sizeof(typename TypeTraits::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 - ) - ); - - - //! is_aligned implementation. - /** - * @tparam address Address to be checked for alignment. - * @tparam alignment Alignment constraint. - */ - template - struct is_aligned : std::integral_constant< - bool, - (address & (alignment - 1)) == 0 - > { - }; - - -} - - //! Register pack base implementation. /** * @tparam base_address Pack base address. @@ -112,13 +57,12 @@ namespace internals { typename TypeTraits::type reset_value = 0x0, bool use_shadow = false > - struct PackedRegister : - Register< - RegisterPack::pack_base + (bit_offset / 8u), - reg_size, - reset_value, - use_shadow - > { + struct PackedRegister : Register< + RegisterPack::pack_base + (bit_offset / 8u), + reg_size, + reset_value, + use_shadow + > { //! Register type. using base_reg = Register< @@ -139,7 +83,7 @@ namespace internals { /** * @return A reference to the writable register memory. */ - static typename base_reg::MMIO_t& rw_mem_device() { + inline static typename base_reg::MMIO_t& rw_mem_device() noexcept { return mem_map_t::array[bit_offset / TypeTraits::bit_size]; }; @@ -148,14 +92,17 @@ namespace internals { /** * @return A reference to the read-only register memory. */ - static const typename base_reg::MMIO_t& ro_mem_device() { + inline static const typename base_reg::MMIO_t& ro_mem_device() noexcept { return mem_map_t::array[bit_offset / TypeTraits::bit_size]; }; // Safety check to detect if are overflowing the pack. - static_assert((bit_offset / 8u) <= RegisterPack::size_in_bytes, - "packed register is overflowing the pack"); + static_assert( + TypeTraits::byte_size + (bit_offset / 8u) <= + RegisterPack::size_in_bytes, + "PackRegister: packed register is overflowing the pack" + ); // A packed register of width N bits requires: // - the pack address to be N-bits aligned (N/8 aligned), @@ -164,13 +111,15 @@ namespace internals { internals::is_aligned< RegisterPack::pack_base, TypeTraits::byte_size - >::value - && + >::value, + "PackedRegister: pack base address is mis-aligned for register type" + ); + static_assert( internals::is_aligned< - RegisterPack::pack_base + (bit_offset / 8), + RegisterPack::pack_base + (bit_offset / 8u), TypeTraits::byte_size >::value, - "register is mis-aligned in the pack" + "PackedRegister: offset address is mis-aligned for register type" ); @@ -208,10 +157,10 @@ namespace internals { * This will call Op for the range [start, end). */ template - inline static void loop() { + inline static void loop() noexcept { Func().template operator()(); if (start < end) - for_loop::template loop(); + for_loop::template loop(); }; #if __cplusplus >= 201402L @@ -226,10 +175,10 @@ namespace internals { * use lambda [](auto index) { index.value will be the loop index}; */ template - inline static void apply(Op& f) { + inline static void apply(Op& f) noexcept { if (start < end) { f(std::integral_constant{}); - for_loop::apply(f); + for_loop::apply(f); }; }; #endif // __cplusplus 201402L @@ -238,10 +187,10 @@ namespace internals { template struct for_loop { template - inline static void loop() {}; + inline static void loop() noexcept {}; #if __cplusplus >= 201402L template - inline static void apply(Op& f) {}; + inline static void apply(Op& f) noexcept {}; #endif // __cplusplus 201402L }; diff --git a/register/Traits.h b/register/Traits.h index abc1b81..b3359e0 100644 --- a/register/Traits.h +++ b/register/Traits.h @@ -32,33 +32,25 @@ namespace cppreg { template <> struct TypeTraits { using type = std::uint8_t; constexpr static const std::uint8_t bit_size = 8u; - constexpr static const std::uint8_t byte_size = 1u; - constexpr static const std::uint8_t max_field_width = 8u; - constexpr static const std::uint8_t max_field_offset = 8u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; }; //! 16-bit specialization. template <> struct TypeTraits { using type = std::uint16_t; constexpr static const std::uint8_t bit_size = 16u; - constexpr static const std::uint8_t byte_size = 2u; - constexpr static const std::uint8_t max_field_width = 16u; - constexpr static const std::uint8_t max_field_offset = 16u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; }; //! 32-bit specialization. template <> struct TypeTraits { using type = std::uint32_t; constexpr static const std::uint8_t bit_size = 32u; - constexpr static const std::uint8_t byte_size = 4u; - constexpr static const std::uint8_t max_field_width = 32u; - constexpr static const std::uint8_t max_field_offset = 32u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; }; //! 64-bit specialization. template <> struct TypeTraits { using type = std::uint64_t; constexpr static const std::uint8_t bit_size = 64u; - constexpr static const std::uint8_t byte_size = 8u; - constexpr static const std::uint8_t max_field_width = 64u; - constexpr static const std::uint8_t max_field_offset = 64u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; }; //!@} diff --git a/single/cppreg-all.h b/single/cppreg-all.h index ea65a02..2510465 100644 --- a/single/cppreg-all.h +++ b/single/cppreg-all.h @@ -30,6 +30,76 @@ namespace cppreg { } #endif +// Traits.h +#ifndef CPPREG_TRAITS_H +#define CPPREG_TRAITS_H +namespace cppreg { + template + struct TypeTraits; + template <> struct TypeTraits { + using type = std::uint8_t; + constexpr static const std::uint8_t bit_size = 8u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; + }; + template <> struct TypeTraits { + using type = std::uint16_t; + constexpr static const std::uint8_t bit_size = 16u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; + }; + template <> struct TypeTraits { + using type = std::uint32_t; + constexpr static const std::uint8_t bit_size = 32u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; + }; + template <> struct TypeTraits { + using type = std::uint64_t; + constexpr static const std::uint8_t bit_size = 64u; + constexpr static const std::uint8_t byte_size = bit_size / 8u; + }; +} +#endif + +// Internals.h +#ifndef CPPREG_INTERNALS_H +#define CPPREG_INTERNALS_H +namespace cppreg { +namespace internals { + template < + typename T, + T value, + T limit + > + struct check_overflow : std::integral_constant {}; + template + struct is_aligned : std::integral_constant< + bool, + (address & (alignment - 1)) == 0 + > { + }; + template + struct memory_map { + using mem_array_t = std::array< + volatile typename TypeTraits::type, + n / sizeof(typename TypeTraits::type) + >; + static mem_array_t& array; + static_assert( + is_aligned::byte_size>::value, + "memory_map: base address is mis-aligned for register type" + ); + }; + template + typename memory_map::mem_array_t& + memory_map::array = *( + reinterpret_cast + ::mem_array_t*>( + address + ) + ); +} +} +#endif + // AccessPolicy.h #ifndef CPPREG_ACCESSPOLICY_H #define CPPREG_ACCESSPOLICY_H @@ -157,58 +227,6 @@ namespace cppreg { } #endif -// Traits.h -#ifndef CPPREG_TRAITS_H -#define CPPREG_TRAITS_H -namespace cppreg { - template - struct TypeTraits; - template <> struct TypeTraits { - using type = std::uint8_t; - constexpr static const std::uint8_t bit_size = 8u; - constexpr static const std::uint8_t byte_size = 1u; - constexpr static const std::uint8_t max_field_width = 8u; - constexpr static const std::uint8_t max_field_offset = 8u; - }; - template <> struct TypeTraits { - using type = std::uint16_t; - constexpr static const std::uint8_t bit_size = 16u; - constexpr static const std::uint8_t byte_size = 2u; - constexpr static const std::uint8_t max_field_width = 16u; - constexpr static const std::uint8_t max_field_offset = 16u; - }; - template <> struct TypeTraits { - using type = std::uint32_t; - constexpr static const std::uint8_t bit_size = 32u; - constexpr static const std::uint8_t byte_size = 4u; - constexpr static const std::uint8_t max_field_width = 32u; - constexpr static const std::uint8_t max_field_offset = 32u; - }; - template <> struct TypeTraits { - using type = std::uint64_t; - constexpr static const std::uint8_t bit_size = 64u; - constexpr static const std::uint8_t byte_size = 8u; - constexpr static const std::uint8_t max_field_width = 64u; - constexpr static const std::uint8_t max_field_offset = 64u; - }; -} -#endif - -// Overflow.h -#ifndef CPPREG_OVERFLOW_H -#define CPPREG_OVERFLOW_H -namespace cppreg { -namespace internals { - template < - typename T, - T value, - T limit - > - struct check_overflow : std::integral_constant {}; -} -} -#endif - // Mask.h #ifndef CPPREG_MASK_H #define CPPREG_MASK_H @@ -419,7 +437,12 @@ namespace cppreg { return std::move(T::make()); }; static_assert(size != 0u, - "defining a Register type of zero size is not allowed"); + "Register: register definition with zero size"); + static_assert( + internals::is_aligned::byte_size> + ::value, + "Register: address is mis-aligned for register type" + ); }; } #endif @@ -428,30 +451,6 @@ namespace cppreg { #ifndef CPPREG_REGISTERPACK_H #define CPPREG_REGISTERPACK_H namespace cppreg { -namespace internals { - template - struct memory_map { - using mem_array_t = std::array< - volatile typename TypeTraits::type, - n / sizeof(typename TypeTraits::type) - >; - static mem_array_t& array; - }; - template - typename memory_map::mem_array_t& - memory_map::array = *( - reinterpret_cast - ::mem_array_t*>( - address - ) - ); - template - struct is_aligned : std::integral_constant< - bool, - (address & (alignment - 1)) == 0 - > { - }; -} template < Address_t base_address, std::uint32_t pack_byte_size @@ -466,13 +465,12 @@ namespace internals { typename TypeTraits::type reset_value = 0x0, bool use_shadow = false > - struct PackedRegister : - Register< - RegisterPack::pack_base + (bit_offset / 8u), - reg_size, - reset_value, - use_shadow - > { + struct PackedRegister : Register< + RegisterPack::pack_base + (bit_offset / 8u), + reg_size, + reset_value, + use_shadow + > { using base_reg = Register< RegisterPack::pack_base + (bit_offset / 8u), reg_size, @@ -484,27 +482,32 @@ namespace internals { RegisterPack::size_in_bytes, reg_size >; - static typename base_reg::MMIO_t& rw_mem_device() { + inline static typename base_reg::MMIO_t& rw_mem_device() noexcept { return mem_map_t::array[bit_offset / TypeTraits::bit_size]; }; - static const typename base_reg::MMIO_t& ro_mem_device() { + inline static const typename base_reg::MMIO_t& ro_mem_device() noexcept { return mem_map_t::array[bit_offset / TypeTraits::bit_size]; }; - static_assert((bit_offset / 8u) <= RegisterPack::size_in_bytes, - "packed register is overflowing the pack"); + static_assert( + TypeTraits::byte_size + (bit_offset / 8u) <= + RegisterPack::size_in_bytes, + "PackRegister: packed register is overflowing the pack" + ); static_assert( internals::is_aligned< RegisterPack::pack_base, TypeTraits::byte_size - >::value - && + >::value, + "PackedRegister: pack base address is mis-aligned for register type" + ); + static_assert( internals::is_aligned< - RegisterPack::pack_base + (bit_offset / 8), + RegisterPack::pack_base + (bit_offset / 8u), TypeTraits::byte_size >::value, - "register is mis-aligned in the pack" + "PackedRegister: offset address is mis-aligned for register type" ); }; template @@ -516,17 +519,17 @@ namespace internals { template struct for_loop { template - inline static void loop() { + inline static void loop() noexcept { Func().template operator()(); if (start < end) - for_loop::template loop(); + for_loop::template loop(); }; #if __cplusplus >= 201402L template - inline static void apply(Op& f) { + inline static void apply(Op& f) noexcept { if (start < end) { f(std::integral_constant{}); - for_loop::apply(f); + for_loop::apply(f); }; }; #endif @@ -534,10 +537,10 @@ namespace internals { template struct for_loop { template - inline static void loop() {}; + inline static void loop() noexcept {}; #if __cplusplus >= 201402L template - inline static void apply(Op& f) {}; + inline static void apply(Op& f) noexcept {}; #endif }; template