//! cppreg library. /** * @file cppreg-all.h * @author Nicolas Clauvelin (nclauvelin@sendyne.com) * @copyright Copyright 2010-2018 Sendyne Corp. All rights reserved. */ #include #include #include #include // cppreg_Defines.h #ifndef CPPREG_CPPREG_DEFINES_H #define CPPREG_CPPREG_DEFINES_H namespace cppreg { using Address_t = std::uintptr_t; using Width_t = std::uint8_t; using Offset_t = std::uint8_t; template struct type_mask { constexpr static const T value = std::numeric_limits::max(); }; } #endif // AccessPolicy.h #ifndef CPPREG_ACCESSPOLICY_H #define CPPREG_ACCESSPOLICY_H namespace cppreg { template struct RegisterRead { constexpr static const bool is_trivial = (mask == type_mask::value) && (offset == 0u); template inline static T read( const MMIO_t& mmio_device, typename std::enable_if::type = nullptr ) noexcept { return static_cast((mmio_device & mask) >> offset); }; template inline static T read( const MMIO_t& mmio_device, typename std::enable_if::type = nullptr ) noexcept { return static_cast(mmio_device); }; }; template struct RegisterWrite { constexpr static const bool is_trivial = (mask == type_mask::value) && (offset == 0u); template inline static void write( MMIO_t& mmio_device, T value, typename std::enable_if::type = nullptr ) noexcept { mmio_device = static_cast( (mmio_device & ~mask) | ((value << offset) & mask) ); }; template inline static void write( MMIO_t& mmio_device, T value, typename std::enable_if::type = nullptr ) noexcept { mmio_device = value; }; }; template struct RegisterWriteConstant { constexpr static const bool is_trivial = (mask == type_mask::value) && (offset == 0u); template inline static void write( MMIO_t& mmio_device, typename std::enable_if::type = nullptr ) noexcept { mmio_device = static_cast( (mmio_device & ~mask) | ((value << offset) & mask) ); }; template inline static void write( MMIO_t& mmio_device, typename std::enable_if::type = nullptr ) noexcept { mmio_device = value; }; }; struct read_only { template inline static T read(const MMIO_t& mmio_device) noexcept { return RegisterRead::read(mmio_device); }; }; struct read_write : read_only { template inline static void write(MMIO_t& mmio_device, const T value) noexcept { RegisterWrite::write(mmio_device, value); }; template inline static void write(MMIO_t& mmio_device) noexcept { RegisterWriteConstant ::write(mmio_device); }; template inline static void set(MMIO_t& mmio_device) noexcept { RegisterWriteConstant ::write(mmio_device); }; template inline static void clear(MMIO_t& mmio_device) noexcept { RegisterWriteConstant ::write(mmio_device); }; template inline static void toggle(MMIO_t& mmio_device) noexcept { mmio_device = static_cast((mmio_device) ^ mask); }; }; struct write_only { template inline static void write(MMIO_t& mmio_device, const T value) noexcept { RegisterWrite::value, 0u>::write( mmio_device, ((value << offset) & mask) ); }; template inline static void write(MMIO_t& mmio_device) noexcept { RegisterWriteConstant< MMIO_t, T, type_mask::value, 0u, ((value << offset) & mask) > ::write(mmio_device); }; }; } #endif // Traits.h #ifndef CPPREG_TRAITS_H #define CPPREG_TRAITS_H namespace cppreg { template struct RegisterType; template <> struct RegisterType<8u> { using type = std::uint8_t; }; template <> struct RegisterType<16u> { using type = std::uint16_t; }; template <> struct RegisterType<32u> { using type = std::uint32_t; }; } #endif // Overflow.h #ifndef CPPREG_OVERFLOW_H #define CPPREG_OVERFLOW_H namespace cppreg { namespace internals { template < Width_t W, typename RegisterType::type value, typename RegisterType::type limit > struct check_overflow { using result = typename std::integral_constant::type; }; } } #endif // Mask.h #ifndef CPPREG_MASK_H #define CPPREG_MASK_H namespace cppreg { template constexpr Mask_t make_mask(const Width_t width) noexcept { return width == 0 ? 0u : static_cast( (make_mask(Width_t(width - 1)) << 1) | 1 ); }; template constexpr Mask_t make_shifted_mask(const Width_t width, const Offset_t offset) noexcept { return static_cast(make_mask(width) << offset); }; } #endif // ShadowValue.h #ifndef CPPREG_SHADOWVALUE_H #define CPPREG_SHADOWVALUE_H namespace cppreg { template struct Shadow : std::false_type {}; template struct Shadow : std::true_type { static typename Register::type shadow_value; }; template typename Register::type Shadow::shadow_value = Register::reset; } #endif // MergeWrite.h #ifndef CPPREG_MERGEWRITE_H #define CPPREG_MERGEWRITE_H namespace cppreg { template < typename Register, typename Register::type mask, Offset_t offset, typename Register::type value > class MergeWrite_tmpl { public: using base_type = typename Register::type; private: static_assert(!Register::shadow::value, "merge write is not available for shadow value register"); constexpr static const base_type _accumulated_value = ((value << offset) & mask); constexpr static const base_type _combined_mask = mask; MergeWrite_tmpl() {}; public: inline static MergeWrite_tmpl make() noexcept { return {}; }; MergeWrite_tmpl(const MergeWrite_tmpl&) = delete; MergeWrite_tmpl& operator=(const MergeWrite_tmpl&) = delete; MergeWrite_tmpl& operator=(MergeWrite_tmpl&&) = delete; MergeWrite_tmpl operator=(MergeWrite_tmpl) = delete; MergeWrite_tmpl(MergeWrite_tmpl&&) = delete; inline void done() const && noexcept { typename Register::MMIO_t& mmio_device = Register::rw_mem_device(); RegisterWriteConstant< typename Register::MMIO_t, typename Register::type, _combined_mask, 0u, _accumulated_value >::write(mmio_device); }; template < typename F, base_type new_value, typename T = MergeWrite_tmpl< Register, (_combined_mask | F::mask), 0u, (_accumulated_value & ~F::mask) | ((new_value << F::offset) & F::mask) > > inline typename std::enable_if< (internals::check_overflow< Register::size, new_value, (F::mask >> F::offset) >::result::value), T >::type&& with() const && noexcept { return std::move(T::make()); }; }; template < typename Register, typename Register::type mask > class MergeWrite { public: using base_type = typename Register::type; private: constexpr static const base_type _combined_mask = mask; public: constexpr static MergeWrite make(const base_type value) noexcept { return MergeWrite(value); }; MergeWrite(MergeWrite&& mw) noexcept : _accumulated_value(mw._accumulated_value) {}; MergeWrite(const MergeWrite&) = delete; MergeWrite& operator=(const MergeWrite&) = delete; MergeWrite& operator=(MergeWrite&&) = delete; inline void done() const && noexcept { typename Register::MMIO_t& mmio_device = Register::rw_mem_device(); RegisterWrite< typename Register::MMIO_t, base_type, _combined_mask, 0u >::write(mmio_device, _accumulated_value); }; template inline MergeWrite with (const base_type value) && noexcept { static_assert(std::is_same< typename F::parent_register, Register >::value, "field is not from the same register in merge_write"); F::policy::template write< base_type, base_type, F::mask, F::offset >(_accumulated_value, value); return std::move( MergeWrite ::make(_accumulated_value) ); }; private: static_assert(!Register::shadow::value, "merge write is not available for shadow value register"); constexpr MergeWrite() : _accumulated_value(0u) {}; constexpr MergeWrite(const base_type v) : _accumulated_value(v) {}; base_type _accumulated_value; }; } #endif // Register.h #ifndef CPPREG_REGISTER_H #define CPPREG_REGISTER_H namespace cppreg { template < Address_t RegAddress, Width_t RegWidth, typename RegisterType::type ResetValue = 0x0, bool UseShadow = false > struct Register { using type = typename RegisterType::type; using MMIO_t = volatile type; constexpr static const Address_t base_address = RegAddress; constexpr static const Width_t size = RegWidth; constexpr static const type reset = ResetValue; using shadow = Shadow; static MMIO_t& rw_mem_device() { return *(reinterpret_cast(base_address)); }; static const MMIO_t& ro_mem_device() { return *(reinterpret_cast(base_address)); }; template inline static MergeWrite merge_write(const typename F::type value) noexcept { return MergeWrite ::make(((value << F::offset) & F::mask)); }; template < typename F, type value, typename T = MergeWrite_tmpl< typename F::parent_register, F::mask, F::offset, value > > inline static typename std::enable_if< internals::check_overflow< size, value, (F::mask >> F::offset) >::result::value, T >::type&& merge_write() noexcept { return std::move(T::make()); }; 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 struct memory_map { using mem_array_t = std::array< volatile typename RegisterType::type, N / sizeof(typename RegisterType::type) >; static mem_array_t& array; }; template typename memory_map::mem_array_t& memory_map::array = *( reinterpret_cast::mem_array_t*>( Address ) ); template < Address_t PackBase, std::uint32_t PackByteSize > struct RegisterPack { constexpr static const Address_t pack_base = PackBase; constexpr static const std::uint32_t size_in_bytes = PackByteSize; }; template < typename RegisterPack, std::uint32_t BitOffset, Width_t RegWidth, typename RegisterType::type ResetValue = 0x0, bool UseShadow = false > struct PackedRegister : Register< RegisterPack::pack_base + (BitOffset / 8u), RegWidth, ResetValue, UseShadow > { using base_reg = Register< RegisterPack::pack_base + (BitOffset / 8u), RegWidth, ResetValue, UseShadow >; using mem_map_t = memory_map< RegisterPack::pack_base, RegisterPack::size_in_bytes, RegWidth >; static typename base_reg::MMIO_t& rw_mem_device() { return mem_map_t::array[BitOffset / RegWidth]; }; static const typename base_reg::MMIO_t& ro_mem_device() { return mem_map_t::array[BitOffset / RegWidth]; }; static_assert((BitOffset / 8u) <= RegisterPack::size_in_bytes, "packed register is overflowing the pack"); static_assert(( (BitOffset % RegWidth) == 0 && (RegisterPack::pack_address % (RegWidth / 8u) == 0) ), "register mis-alignment with respect to pack base"); }; template struct PackIndexing { template using regs = typename std::tuple_element>::type; }; template struct for_loop { template