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
#include "Overflow.h"
#include "Internals.h"
#include "MergeWrite.h"
#include "Register.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
#include "Overflow.h"
#include "Internals.h"
#include "AccessPolicy.h"
#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.
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 "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 <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.
/**
* @tparam base_address Pack base address.
@ -112,13 +57,12 @@ namespace internals {
typename TypeTraits<reg_size>::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<reg_size>::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<reg_size>::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<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:
// - the pack address to be N-bits aligned (N/8 aligned),
@ -164,13 +111,15 @@ namespace internals {
internals::is_aligned<
RegisterPack::pack_base,
TypeTraits<reg_size>::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<reg_size>::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 <typename Func>
inline static void loop() {
inline static void loop() noexcept {
Func().template operator()<start>();
if (start < end)
for_loop<start + 1, end>::template loop<Func>();
for_loop<start + 1ul, end>::template loop<Func>();
};
#if __cplusplus >= 201402L
@ -226,10 +175,10 @@ namespace internals {
* use lambda [](auto index) { index.value will be the loop index};
*/
template <typename Op>
inline static void apply(Op& f) {
inline static void apply(Op& f) noexcept {
if (start < end) {
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
@ -238,10 +187,10 @@ namespace internals {
template <std::size_t end>
struct for_loop<end, end> {
template <typename Func>
inline static void loop() {};
inline static void loop() noexcept {};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op& f) {};
inline static void apply(Op& f) noexcept {};
#endif // __cplusplus 201402L
};

View File

@ -32,33 +32,25 @@ namespace cppreg {
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;
constexpr static const std::uint8_t byte_size = bit_size / 8u;
};
//! 16-bit specialization.
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;
constexpr static const std::uint8_t byte_size = bit_size / 8u;
};
//! 32-bit specialization.
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;
constexpr static const std::uint8_t byte_size = bit_size / 8u;
};
//! 64-bit specialization.
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;
constexpr static const std::uint8_t byte_size = bit_size / 8u;
};
//!@}

View File

@ -30,6 +30,76 @@ namespace cppreg {
}
#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
#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 <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
#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<reg_address, TypeTraits<reg_size>::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 <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 <
Address_t base_address,
std::uint32_t pack_byte_size
@ -466,13 +465,12 @@ namespace internals {
typename TypeTraits<reg_size>::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<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
/ TypeTraits<reg_size>::bit_size];
};
static_assert((bit_offset / 8u) <= RegisterPack::size_in_bytes,
"packed register is overflowing the pack");
static_assert(
TypeTraits<reg_size>::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<reg_size>::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<reg_size>::byte_size
>::value,
"register is mis-aligned in the pack"
"PackedRegister: offset address is mis-aligned for register type"
);
};
template <typename... T>
@ -516,17 +519,17 @@ namespace internals {
template <std::size_t start, std::size_t end>
struct for_loop {
template <typename Func>
inline static void loop() {
inline static void loop() noexcept {
Func().template operator()<start>();
if (start < end)
for_loop<start + 1, end>::template loop<Func>();
for_loop<start + 1ul, end>::template loop<Func>();
};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op& f) {
inline static void apply(Op& f) noexcept {
if (start < end) {
f(std::integral_constant<std::size_t, start>{});
for_loop<start + 1, end>::apply(f);
for_loop<start + 1ul, end>::apply(f);
};
};
#endif
@ -534,10 +537,10 @@ namespace internals {
template <std::size_t end>
struct for_loop<end, end> {
template <typename Func>
inline static void loop() {};
inline static void loop() noexcept {};
#if __cplusplus >= 201402L
template <typename Op>
inline static void apply(Op& f) {};
inline static void apply(Op& f) noexcept {};
#endif
};
template <typename IndexedPack>