ADD TEMPLATE FOR LOOP IMPLEMENTATION

This commit is contained in:
Nicolas Clauvelin 2018-03-12 17:51:00 -04:00
parent 327e230847
commit 984d4ceb58
4 changed files with 196 additions and 121 deletions

View File

@ -25,6 +25,7 @@ set(CPPREG_API_HEADERS
register/Mask.h
register/Overflow.h
register/Register.h
register/RegisterPack.h
register/ShadowValue.h
register/Traits.h)

View File

@ -124,120 +124,6 @@ namespace cppreg {
};
//! Register pack base implementation.
/**
* @tparam PackBase Base address to use for the pack memory.
* @tparam PackByteSize Size in bytes of the memory region for the pack.
*/
template <
Address_t PackBase,
std::uint32_t PackByteSize
> struct RegisterPack {
//! Type alias for byte array.
using mem_array_t = std::array<volatile std::uint8_t, PackByteSize>;
//! Base address.
constexpr static const Address_t pack_base = PackBase;
//! Pack size in bytes.
constexpr static const std::uint32_t size_in_bytes = PackByteSize;
//! Reference to the byte array.
/**
* This is explicitly defined below.
*/
static mem_array_t& _mem_array;
};
//! RegisterPack byte array reference definition.
template <
Address_t PackBase,
std::uint32_t PackByteSize
>
typename RegisterPack<PackBase, PackByteSize>::mem_array_t&
RegisterPack<PackBase, PackByteSize>::_mem_array =
*(
reinterpret_cast<
RegisterPack<PackBase, PackByteSize>::mem_array_t* const
>(RegisterPack<PackBase, PackByteSize>::pack_base)
);
//! Packed register implementation.
/**
* @tparam RegisterPack Pack to which the register belongs.
* @tparam RegWidth Register total width in bits.
* @tparam OffsetInPack Register offset in the pack in bytes.
* @tparam reset Register reset value (0x0 if unknown).
* @tparam shadow Boolean flag to enable shadow value (enabled if `true`).
*
* This implementation is intended to be used when defining a register
* that belongs to a type.
*/
template <
typename RegisterPack,
Width_t RegWidth,
std::uint32_t OffsetInPack,
typename RegisterType<RegWidth>::type ResetValue = 0x0,
bool UseShadow = false
>
struct PackedRegister :
Register<
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
> {
//! Register type.
using base_reg = Register<
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
>;
//! Memory modifier.
/**
* @return A reference to the writable register memory.
*/
static typename base_reg::MMIO_t& rw_mem_device() {
return RegisterPack::_mem_array[OffsetInPack];
};
//! Memory accessor.
/**
* @return A reference to the read-only register memory.
*/
static const typename base_reg::MMIO_t& ro_mem_device() {
return RegisterPack::_mem_array[OffsetInPack];
};
// Safety check to detect if are overflowing the pack.
static_assert((OffsetInPack + (RegWidth / 8u)) <=
RegisterPack::size_in_bytes,
"packed register is overflowing the pack");
};
//! Pack indexing structure.
/**
* @tparam T List of types (registers or fields) to index.
*
* This can be used to conveniently map indices over packed registers.
* The order in the variadic parameter pack will define the indexing
* (starting at zero).
*/
template <typename... T>
struct PackIndexing {
template <std::size_t N>
using regs = typename std::tuple_element<N, std::tuple<T...>>::type;
};
}

158
register/RegisterPack.h Normal file
View File

@ -0,0 +1,158 @@
//! Register pack implementation.
/**
* @file RegisterPack.h
* @author Nicolas Clauvelin (nclauvelin@sendyne.com)
* @copyright Copyright 2010-2018 Sendyne Corp. All rights reserved.
*
* This header provides the definitions related to register implementation.
*/
#include "Register.h"
#ifndef CPPREG_REGISTERPACK_H
#define CPPREG_REGISTERPACK_H
//! cppreg namespace.
namespace cppreg {
//! Register pack base implementation.
/**
* @tparam PackBase Base address to use for the pack memory.
* @tparam PackByteSize Size in bytes of the memory region for the pack.
*/
template <
Address_t PackBase,
std::uint32_t PackByteSize
> struct RegisterPack {
//! Type alias for byte array.
using mem_array_t = std::array<volatile std::uint8_t, PackByteSize>;
//! Base address.
constexpr static const Address_t pack_base = PackBase;
//! Pack size in bytes.
constexpr static const std::uint32_t size_in_bytes = PackByteSize;
//! Reference to the byte array.
/**
* This is explicitly defined below.
*/
static mem_array_t& _mem_array;
};
//! RegisterPack byte array reference definition.
template <
Address_t PackBase,
std::uint32_t PackByteSize
>
typename RegisterPack<PackBase, PackByteSize>::mem_array_t&
RegisterPack<PackBase, PackByteSize>::_mem_array =
*(
reinterpret_cast<
RegisterPack<PackBase, PackByteSize>::mem_array_t* const
>(RegisterPack<PackBase, PackByteSize>::pack_base)
);
//! Packed register implementation.
/**
* @tparam RegisterPack Pack to which the register belongs.
* @tparam RegWidth Register total width in bits.
* @tparam OffsetInPack Register offset in the pack in bytes.
* @tparam reset Register reset value (0x0 if unknown).
* @tparam shadow Boolean flag to enable shadow value (enabled if `true`).
*
* This implementation is intended to be used when defining a register
* that belongs to a type.
*/
template <
typename RegisterPack,
Width_t RegWidth,
std::uint32_t OffsetInPack,
typename RegisterType<RegWidth>::type ResetValue = 0x0,
bool UseShadow = false
>
struct PackedRegister :
Register<
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
> {
//! Register type.
using base_reg = Register<
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
>;
//! Memory modifier.
/**
* @return A reference to the writable register memory.
*/
static typename base_reg::MMIO_t& rw_mem_device() {
return RegisterPack::_mem_array[OffsetInPack];
};
//! Memory accessor.
/**
* @return A reference to the read-only register memory.
*/
static const typename base_reg::MMIO_t& ro_mem_device() {
return RegisterPack::_mem_array[OffsetInPack];
};
// Safety check to detect if are overflowing the pack.
static_assert((OffsetInPack + (RegWidth / 8u)) <=
RegisterPack::size_in_bytes,
"packed register is overflowing the pack");
};
//! Pack indexing structure.
/**
* @tparam T List of types (registers or fields) to index.
*
* This can be used to conveniently map indices over packed registers.
* The order in the variadic parameter pack will define the indexing
* (starting at zero).
*/
template <typename... T>
struct PackIndexing {
template <std::size_t N>
using regs = typename std::tuple_element<N, std::tuple<T...>>::type;
};
//! Template for loop implementation.
template <std::size_t start, std::size_t end>
struct for_loop {
template <template <std::size_t> class Op, typename T = void>
inline static void iterate(
typename std::enable_if<start < end, T>::type* = nullptr
) {
Op<start>()();
if (start < end)
for_loop<start + 1, end>::template iterate<Op>();
};
template <template <std::size_t> class Op, typename T = void>
inline static void iterate(
typename std::enable_if<start >= end, T>::type* = nullptr
) {};
};
}
#endif // CPPREG_REGISTERPACK_H

View File

@ -381,6 +381,13 @@ namespace cppreg {
static_assert(RegWidth != 0u,
"defining a Register type of width 0u is not allowed");
};
}
#endif
// RegisterPack.h
#ifndef CPPREG_REGISTERPACK_H
#define CPPREG_REGISTERPACK_H
namespace cppreg {
template <
Address_t PackBase,
std::uint32_t PackByteSize
@ -404,12 +411,22 @@ namespace cppreg {
template <
typename RegisterPack,
Width_t RegWidth,
std::uint32_t OffsetInPack
std::uint32_t OffsetInPack,
typename RegisterType<RegWidth>::type ResetValue = 0x0,
bool UseShadow = false
>
struct PackedRegister :
Register<RegisterPack::pack_base + OffsetInPack * 8, RegWidth> {
Register<
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
> {
using base_reg = Register<
RegisterPack::pack_base + OffsetInPack * 8, RegWidth
RegisterPack::pack_base + OffsetInPack * 8,
RegWidth,
ResetValue,
UseShadow
>;
static typename base_reg::MMIO_t& rw_mem_device() {
return RegisterPack::_mem_array[OffsetInPack];
@ -421,12 +438,25 @@ namespace cppreg {
RegisterPack::size_in_bytes,
"packed register is overflowing the pack");
};
template <typename... Regs>
template <typename... T>
struct PackIndexing {
template <std::size_t N>
using type = typename std::tuple_element<N, std::tuple<Regs...>>::type;
template <std::size_t N>
using regs = typename std::tuple_element<N, std::tuple<Regs...>>::type;
using regs = typename std::tuple_element<N, std::tuple<T...>>::type;
};
template <std::size_t start, std::size_t end>
struct for_loop {
template <template <std::size_t> class Op, typename T = void>
inline static void iterate(
typename std::enable_if<start < end, T>::type* = nullptr
) {
Op<start>()();
if (start < end)
for_loop<start + 1, end>::template iterate<Op>();
};
template <template <std::size_t> class Op, typename T = void>
inline static void iterate(
typename std::enable_if<start >= end, T>::type* = nullptr
) {};
};
}
#endif