1
0
mirror of https://github.com/sendyne/cppreg.git synced 2025-05-09 23:24:05 +00:00

INTERNAL IMPLEMENTATIONS RELOCATED TO AN INTERNALS HEADER

The Internals.h contains the overflow, is_aligned and memory array
implementations.
This commit is contained in:
Nicolas Clauvelin 2018-03-16 14:12:52 -04:00
parent 6085f47115
commit 5925c223c8
8 changed files with 243 additions and 234 deletions

View File

@ -10,7 +10,7 @@
#define CPPREG_CPPREG_H #define CPPREG_CPPREG_H
#include "Overflow.h" #include "Internals.h"
#include "MergeWrite.h" #include "MergeWrite.h"
#include "Register.h" #include "Register.h"
#include "RegisterPack.h" #include "RegisterPack.h"

102
register/Internals.h Normal file
View File

@ -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<bool, value <= limit> {};
//! 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 <Address_t address, std::size_t alignment>
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 <Address_t address, std::uint32_t n, RegBitSize reg_size>
struct memory_map {
//! Array type.
using mem_array_t = std::array<
volatile typename TypeTraits<reg_size>::type,
n / sizeof(typename TypeTraits<reg_size>::type)
>;
//! Static reference to memory array.
static mem_array_t& array;
// Alignment check.
static_assert(
is_aligned<address, TypeTraits<reg_size>::byte_size>::value,
"memory_map: base address is mis-aligned for register type"
);
};
//! Memory array reference definition.
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
typename memory_map<address, n, reg_size>::mem_array_t&
memory_map<address, n, reg_size>::array = *(
reinterpret_cast<typename memory_map<address, n, reg_size>
::mem_array_t*>(
address
)
);
}
}
#endif // CPPREG_INTERNALS_H

View File

@ -18,7 +18,7 @@
#define CPPREG_MERGEWRITE_H #define CPPREG_MERGEWRITE_H
#include "Overflow.h" #include "Internals.h"
#include "AccessPolicy.h" #include "AccessPolicy.h"
#include <functional> #include <functional>

View File

@ -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 <type_traits>
//! 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<bool, value <= limit> {};
}
}
#endif // CPPREG_OVERFLOW_H

View File

@ -120,7 +120,14 @@ namespace cppreg {
// Sanity check. // Sanity check.
static_assert(size != 0u, 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<reg_address, TypeTraits<reg_size>::byte_size>
::value,
"Register: address is mis-aligned for register type"
);
}; };

View File

@ -9,6 +9,7 @@
#include "Register.h" #include "Register.h"
#include "Internals.h"
#ifndef CPPREG_REGISTERPACK_H #ifndef CPPREG_REGISTERPACK_H
@ -19,62 +20,6 @@
namespace cppreg { 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 <Address_t address, std::uint32_t n, RegBitSize reg_size>
struct memory_map {
//! Array type.
using mem_array_t = std::array<
volatile typename TypeTraits<reg_size>::type,
n / sizeof(typename TypeTraits<reg_size>::type)
>;
//! Static reference to memory array.
/**
* This is defined below.
*/
static mem_array_t& array;
};
//! Memory array reference definition.
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
typename memory_map<address, n, reg_size>::mem_array_t&
memory_map<address, n, reg_size>::array = *(
reinterpret_cast<typename memory_map<address, n, reg_size>
::mem_array_t*>(
address
)
);
//! is_aligned implementation.
/**
* @tparam address Address to be checked for alignment.
* @tparam alignment Alignment constraint.
*/
template <Address_t address, std::size_t alignment>
struct is_aligned : std::integral_constant<
bool,
(address & (alignment - 1)) == 0
> {
};
}
//! Register pack base implementation. //! Register pack base implementation.
/** /**
* @tparam base_address Pack base address. * @tparam base_address Pack base address.
@ -112,13 +57,12 @@ namespace internals {
typename TypeTraits<reg_size>::type reset_value = 0x0, typename TypeTraits<reg_size>::type reset_value = 0x0,
bool use_shadow = false bool use_shadow = false
> >
struct PackedRegister : struct PackedRegister : Register<
Register< RegisterPack::pack_base + (bit_offset / 8u),
RegisterPack::pack_base + (bit_offset / 8u), reg_size,
reg_size, reset_value,
reset_value, use_shadow
use_shadow > {
> {
//! Register type. //! Register type.
using base_reg = Register< using base_reg = Register<
@ -139,7 +83,7 @@ namespace internals {
/** /**
* @return A reference to the writable register memory. * @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 return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size]; / TypeTraits<reg_size>::bit_size];
}; };
@ -148,14 +92,17 @@ namespace internals {
/** /**
* @return A reference to the read-only register memory. * @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 return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size]; / TypeTraits<reg_size>::bit_size];
}; };
// Safety check to detect if are overflowing the pack. // Safety check to detect if are overflowing the pack.
static_assert((bit_offset / 8u) <= RegisterPack::size_in_bytes, static_assert(
"packed register is overflowing the pack"); TypeTraits<reg_size>::byte_size + (bit_offset / 8u) <=
RegisterPack::size_in_bytes,
"PackRegister: packed register is overflowing the pack"
);
// A packed register of width N bits requires: // A packed register of width N bits requires:
// - the pack address to be N-bits aligned (N/8 aligned), // - the pack address to be N-bits aligned (N/8 aligned),
@ -164,13 +111,15 @@ namespace internals {
internals::is_aligned< internals::is_aligned<
RegisterPack::pack_base, RegisterPack::pack_base,
TypeTraits<reg_size>::byte_size TypeTraits<reg_size>::byte_size
>::value >::value,
&& "PackedRegister: pack base address is mis-aligned for register type"
);
static_assert(
internals::is_aligned< internals::is_aligned<
RegisterPack::pack_base + (bit_offset / 8), RegisterPack::pack_base + (bit_offset / 8u),
TypeTraits<reg_size>::byte_size TypeTraits<reg_size>::byte_size
>::value, >::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). * This will call Op for the range [start, end).
*/ */
template <typename Func> template <typename Func>
inline static void loop() { inline static void loop() noexcept {
Func().template operator()<start>(); Func().template operator()<start>();
if (start < end) if (start < end)
for_loop<start + 1, end>::template loop<Func>(); for_loop<start + 1ul, end>::template loop<Func>();
}; };
#if __cplusplus >= 201402L #if __cplusplus >= 201402L
@ -226,10 +175,10 @@ namespace internals {
* use lambda [](auto index) { index.value will be the loop index}; * use lambda [](auto index) { index.value will be the loop index};
*/ */
template <typename Op> template <typename Op>
inline static void apply(Op& f) { inline static void apply(Op& f) noexcept {
if (start < end) { if (start < end) {
f(std::integral_constant<std::size_t, start>{}); f(std::integral_constant<std::size_t, start>{});
for_loop<start + 1, end>::apply(f); for_loop<start + 1ul, end>::apply(f);
}; };
}; };
#endif // __cplusplus 201402L #endif // __cplusplus 201402L
@ -238,10 +187,10 @@ namespace internals {
template <std::size_t end> template <std::size_t end>
struct for_loop<end, end> { struct for_loop<end, end> {
template <typename Func> template <typename Func>
inline static void loop() {}; inline static void loop() noexcept {};
#if __cplusplus >= 201402L #if __cplusplus >= 201402L
template <typename Op> template <typename Op>
inline static void apply(Op& f) {}; inline static void apply(Op& f) noexcept {};
#endif // __cplusplus 201402L #endif // __cplusplus 201402L
}; };

View File

@ -32,33 +32,25 @@ namespace cppreg {
template <> struct TypeTraits<RegBitSize::b8> { template <> struct TypeTraits<RegBitSize::b8> {
using type = std::uint8_t; using type = std::uint8_t;
constexpr static const std::uint8_t bit_size = 8u; constexpr static const std::uint8_t bit_size = 8u;
constexpr static const std::uint8_t byte_size = 1u; constexpr static const std::uint8_t byte_size = bit_size / 8u;
constexpr static const std::uint8_t max_field_width = 8u;
constexpr static const std::uint8_t max_field_offset = 8u;
}; };
//! 16-bit specialization. //! 16-bit specialization.
template <> struct TypeTraits<RegBitSize::b16> { template <> struct TypeTraits<RegBitSize::b16> {
using type = std::uint16_t; using type = std::uint16_t;
constexpr static const std::uint8_t bit_size = 16u; constexpr static const std::uint8_t bit_size = 16u;
constexpr static const std::uint8_t byte_size = 2u; constexpr static const std::uint8_t byte_size = bit_size / 8u;
constexpr static const std::uint8_t max_field_width = 16u;
constexpr static const std::uint8_t max_field_offset = 16u;
}; };
//! 32-bit specialization. //! 32-bit specialization.
template <> struct TypeTraits<RegBitSize::b32> { template <> struct TypeTraits<RegBitSize::b32> {
using type = std::uint32_t; using type = std::uint32_t;
constexpr static const std::uint8_t bit_size = 32u; constexpr static const std::uint8_t bit_size = 32u;
constexpr static const std::uint8_t byte_size = 4u; constexpr static const std::uint8_t byte_size = bit_size / 8u;
constexpr static const std::uint8_t max_field_width = 32u;
constexpr static const std::uint8_t max_field_offset = 32u;
}; };
//! 64-bit specialization. //! 64-bit specialization.
template <> struct TypeTraits<RegBitSize::b64> { template <> struct TypeTraits<RegBitSize::b64> {
using type = std::uint64_t; using type = std::uint64_t;
constexpr static const std::uint8_t bit_size = 64u; constexpr static const std::uint8_t bit_size = 64u;
constexpr static const std::uint8_t byte_size = 8u; constexpr static const std::uint8_t byte_size = bit_size / 8u;
constexpr static const std::uint8_t max_field_width = 64u;
constexpr static const std::uint8_t max_field_offset = 64u;
}; };
//!@} //!@}

View File

@ -30,6 +30,76 @@ namespace cppreg {
} }
#endif #endif
// Traits.h
#ifndef CPPREG_TRAITS_H
#define CPPREG_TRAITS_H
namespace cppreg {
template <RegBitSize S>
struct TypeTraits;
template <> struct TypeTraits<RegBitSize::b8> {
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<RegBitSize::b16> {
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<RegBitSize::b32> {
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<RegBitSize::b64> {
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<bool, value <= limit> {};
template <Address_t address, std::size_t alignment>
struct is_aligned : std::integral_constant<
bool,
(address & (alignment - 1)) == 0
> {
};
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
struct memory_map {
using mem_array_t = std::array<
volatile typename TypeTraits<reg_size>::type,
n / sizeof(typename TypeTraits<reg_size>::type)
>;
static mem_array_t& array;
static_assert(
is_aligned<address, TypeTraits<reg_size>::byte_size>::value,
"memory_map: base address is mis-aligned for register type"
);
};
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
typename memory_map<address, n, reg_size>::mem_array_t&
memory_map<address, n, reg_size>::array = *(
reinterpret_cast<typename memory_map<address, n, reg_size>
::mem_array_t*>(
address
)
);
}
}
#endif
// AccessPolicy.h // AccessPolicy.h
#ifndef CPPREG_ACCESSPOLICY_H #ifndef CPPREG_ACCESSPOLICY_H
#define CPPREG_ACCESSPOLICY_H #define CPPREG_ACCESSPOLICY_H
@ -157,58 +227,6 @@ namespace cppreg {
} }
#endif #endif
// Traits.h
#ifndef CPPREG_TRAITS_H
#define CPPREG_TRAITS_H
namespace cppreg {
template <RegBitSize S>
struct TypeTraits;
template <> struct TypeTraits<RegBitSize::b8> {
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<RegBitSize::b16> {
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<RegBitSize::b32> {
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<RegBitSize::b64> {
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<bool, value <= limit> {};
}
}
#endif
// Mask.h // Mask.h
#ifndef CPPREG_MASK_H #ifndef CPPREG_MASK_H
#define CPPREG_MASK_H #define CPPREG_MASK_H
@ -419,7 +437,12 @@ namespace cppreg {
return std::move(T::make()); return std::move(T::make());
}; };
static_assert(size != 0u, 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<reg_address, TypeTraits<reg_size>::byte_size>
::value,
"Register: address is mis-aligned for register type"
);
}; };
} }
#endif #endif
@ -428,30 +451,6 @@ namespace cppreg {
#ifndef CPPREG_REGISTERPACK_H #ifndef CPPREG_REGISTERPACK_H
#define CPPREG_REGISTERPACK_H #define CPPREG_REGISTERPACK_H
namespace cppreg { namespace cppreg {
namespace internals {
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
struct memory_map {
using mem_array_t = std::array<
volatile typename TypeTraits<reg_size>::type,
n / sizeof(typename TypeTraits<reg_size>::type)
>;
static mem_array_t& array;
};
template <Address_t address, std::uint32_t n, RegBitSize reg_size>
typename memory_map<address, n, reg_size>::mem_array_t&
memory_map<address, n, reg_size>::array = *(
reinterpret_cast<typename memory_map<address, n, reg_size>
::mem_array_t*>(
address
)
);
template <Address_t address, std::size_t alignment>
struct is_aligned : std::integral_constant<
bool,
(address & (alignment - 1)) == 0
> {
};
}
template < template <
Address_t base_address, Address_t base_address,
std::uint32_t pack_byte_size std::uint32_t pack_byte_size
@ -466,13 +465,12 @@ namespace internals {
typename TypeTraits<reg_size>::type reset_value = 0x0, typename TypeTraits<reg_size>::type reset_value = 0x0,
bool use_shadow = false bool use_shadow = false
> >
struct PackedRegister : struct PackedRegister : Register<
Register< RegisterPack::pack_base + (bit_offset / 8u),
RegisterPack::pack_base + (bit_offset / 8u), reg_size,
reg_size, reset_value,
reset_value, use_shadow
use_shadow > {
> {
using base_reg = Register< using base_reg = Register<
RegisterPack::pack_base + (bit_offset / 8u), RegisterPack::pack_base + (bit_offset / 8u),
reg_size, reg_size,
@ -484,27 +482,32 @@ namespace internals {
RegisterPack::size_in_bytes, RegisterPack::size_in_bytes,
reg_size 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 return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size]; / TypeTraits<reg_size>::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 return mem_map_t::array[bit_offset
/ TypeTraits<reg_size>::bit_size]; / TypeTraits<reg_size>::bit_size];
}; };
static_assert((bit_offset / 8u) <= RegisterPack::size_in_bytes, static_assert(
"packed register is overflowing the pack"); TypeTraits<reg_size>::byte_size + (bit_offset / 8u) <=
RegisterPack::size_in_bytes,
"PackRegister: packed register is overflowing the pack"
);
static_assert( static_assert(
internals::is_aligned< internals::is_aligned<
RegisterPack::pack_base, RegisterPack::pack_base,
TypeTraits<reg_size>::byte_size TypeTraits<reg_size>::byte_size
>::value >::value,
&& "PackedRegister: pack base address is mis-aligned for register type"
);
static_assert(
internals::is_aligned< internals::is_aligned<
RegisterPack::pack_base + (bit_offset / 8), RegisterPack::pack_base + (bit_offset / 8u),
TypeTraits<reg_size>::byte_size TypeTraits<reg_size>::byte_size
>::value, >::value,
"register is mis-aligned in the pack" "PackedRegister: offset address is mis-aligned for register type"
); );
}; };
template <typename... T> template <typename... T>
@ -516,17 +519,17 @@ namespace internals {
template <std::size_t start, std::size_t end> template <std::size_t start, std::size_t end>
struct for_loop { struct for_loop {
template <typename Func> template <typename Func>
inline static void loop() { inline static void loop() noexcept {
Func().template operator()<start>(); Func().template operator()<start>();
if (start < end) if (start < end)
for_loop<start + 1, end>::template loop<Func>(); for_loop<start + 1ul, end>::template loop<Func>();
}; };
#if __cplusplus >= 201402L #if __cplusplus >= 201402L
template <typename Op> template <typename Op>
inline static void apply(Op& f) { inline static void apply(Op& f) noexcept {
if (start < end) { if (start < end) {
f(std::integral_constant<std::size_t, start>{}); f(std::integral_constant<std::size_t, start>{});
for_loop<start + 1, end>::apply(f); for_loop<start + 1ul, end>::apply(f);
}; };
}; };
#endif #endif
@ -534,10 +537,10 @@ namespace internals {
template <std::size_t end> template <std::size_t end>
struct for_loop<end, end> { struct for_loop<end, end> {
template <typename Func> template <typename Func>
inline static void loop() {}; inline static void loop() noexcept {};
#if __cplusplus >= 201402L #if __cplusplus >= 201402L
template <typename Op> template <typename Op>
inline static void apply(Op& f) {}; inline static void apply(Op& f) noexcept {};
#endif #endif
}; };
template <typename IndexedPack> template <typename IndexedPack>