Loading...
Searching...
No Matches
hw_register_block
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2014-2021, 2023-2024 Kernkonzept GmbH.
* Author(s): Alexander Warg <alexander.warg@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/types.h>
#include <l4/cxx/type_traits>
namespace L4drivers {
template< unsigned MAX_BITS = 32 >
struct Register_block_base;
template<>
struct Register_block_base<8>
{
virtual l4_uint8_t do_read_8(l4_addr_t reg) const = 0;
virtual void do_write_8(l4_uint8_t value, l4_addr_t reg) = 0;
virtual ~Register_block_base() = 0;
};
inline Register_block_base<8>::~Register_block_base() {}
template<>
struct Register_block_base<16> : Register_block_base<8>
{
virtual l4_uint16_t do_read_16(l4_addr_t reg) const = 0;
virtual void do_write_16(l4_uint16_t value, l4_addr_t reg) = 0;
};
template<>
struct Register_block_base<32> : Register_block_base<16>
{
virtual l4_uint32_t do_read_32(l4_addr_t reg) const = 0;
virtual void do_write_32(l4_uint32_t value, l4_addr_t reg) = 0;
};
template<>
struct Register_block_base<64> : Register_block_base<32>
{
virtual l4_uint64_t do_read_64(l4_addr_t reg) const = 0;
virtual void do_write_64(l4_uint64_t value, l4_addr_t reg) = 0;
};
#undef REGBLK_READ_TEMPLATE
#undef REGBLK_WRITE_TEMPLATE
template<typename CHILD>
struct Register_block_modify_mixin
{
template< typename T >
T modify(T clear_bits, T set_bits, l4_addr_t reg) const
{
CHILD const *c = static_cast<CHILD const *>(this);
T r = (c->template read<T>(reg) & ~clear_bits) | set_bits;
c->template write<T>(r, reg);
return r;
}
template< typename T >
T set(T set_bits, l4_addr_t reg) const
{ return this->template modify<T>(T(0), set_bits, reg); }
template< typename T >
T clear(T clear_bits, l4_addr_t reg) const
{ return this->template modify<T>(clear_bits, T(0), reg); }
};
#define REGBLK_READ_TEMPLATE(sz) \
template< typename T > \
typename cxx::enable_if<sizeof(T) == (sz / 8), T>::type read(l4_addr_t reg) const \
{ \
union X { T t; l4_uint##sz##_t v; } m; \
m.v = _b->do_read_##sz (reg); \
return m.t; \
}
#define REGBLK_WRITE_TEMPLATE(sz) \
template< typename T > \
void write(T value, l4_addr_t reg, typename cxx::enable_if<sizeof(T) == (sz / 8), T>::type = T()) const \
{ \
union X { T t; l4_uint##sz##_t v; } m; \
m.t = value; \
_b->do_write_##sz(m.v, reg); \
}
template< typename BLOCK >
class Register_block_tmpl
: public Register_block_modify_mixin<Register_block_tmpl<BLOCK> >
{
private:
BLOCK *_b;
public:
Register_block_tmpl(BLOCK *blk) : _b(blk) {}
Register_block_tmpl() = default;
operator BLOCK * () const { return _b; }
REGBLK_READ_TEMPLATE(8)
REGBLK_WRITE_TEMPLATE(8)
REGBLK_READ_TEMPLATE(16)
REGBLK_WRITE_TEMPLATE(16)
REGBLK_READ_TEMPLATE(32)
REGBLK_WRITE_TEMPLATE(32)
REGBLK_READ_TEMPLATE(64)
REGBLK_WRITE_TEMPLATE(64)
};
#undef REGBLK_READ_TEMPLATE
#undef REGBLK_WRITE_TEMPLATE
namespace __Type_helper {
template<unsigned> struct Unsigned;
template<> struct Unsigned<8> { typedef l4_uint8_t type; };
template<> struct Unsigned<16> { typedef l4_uint16_t type; };
template<> struct Unsigned<32> { typedef l4_uint32_t type; };
template<> struct Unsigned<64> { typedef l4_uint64_t type; };
};
template< unsigned BITS, typename BLOCK >
class Ro_register_tmpl
{
protected:
BLOCK _b;
unsigned _o;
public:
typedef typename __Type_helper::Unsigned<BITS>::type value_type;
Ro_register_tmpl(BLOCK const &blk, unsigned offset) : _b(blk), _o(offset) {}
Ro_register_tmpl() = default;
operator value_type () const
{ return _b.template read<value_type>(_o); }
value_type read() const
{ return _b.template read<value_type>(_o); }
};
template< unsigned BITS, typename BLOCK >
class Register_tmpl : public Ro_register_tmpl<BITS, BLOCK>
{
public:
typedef typename Ro_register_tmpl<BITS, BLOCK>::value_type value_type;
Register_tmpl(BLOCK const &blk, unsigned offset)
: Ro_register_tmpl<BITS, BLOCK>(blk, offset)
{}
Register_tmpl() = default;
Register_tmpl &operator = (value_type val)
{ this->_b.template write<value_type>(val, this->_o); return *this; }
void write(value_type val)
{ this->_b.template write<value_type>(val, this->_o); }
value_type set(value_type set_bits)
{ return this->_b.template set<value_type>(set_bits, this->_o); }
value_type clear(value_type clear_bits)
{ return this->_b.template clear<value_type>(clear_bits, this->_o); }
value_type modify(value_type clear_bits, value_type set_bits)
{ return this->_b.template modify<value_type>(clear_bits, set_bits, this->_o); }
};
template<
unsigned MAX_BITS,
typename BLOCK = Register_block_tmpl<
Register_block_base<MAX_BITS>
>
>
class Register_block
{
private:
template< unsigned B, typename BLK > friend class Register_block;
template< unsigned B, typename BLK > friend class Ro_register_block;
typedef BLOCK Block;
Block _b;
public:
Register_block() = default;
Register_block(Block const &blk) : _b(blk) {}
Register_block &operator = (Block const &blk)
{ _b = blk; return *this; }
template< unsigned BITS >
Register_block(Register_block<BITS> blk) : _b(blk._b) {}
typedef Register_tmpl<MAX_BITS, Block> Register;
typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register;
template< unsigned BITS >
Ro_register_tmpl<BITS, Block> r(unsigned offset) const
{ return Ro_register_tmpl<BITS, Block>(this->_b, offset); }
Ro_register operator [] (unsigned offset) const
{ return this->r<MAX_BITS>(offset); }
template< unsigned BITS >
Register_tmpl<BITS, Block> r(unsigned offset)
{ return Register_tmpl<BITS, Block>(this->_b, offset); }
Register operator [] (unsigned offset)
{ return this->r<MAX_BITS>(offset); }
};
template<
unsigned MAX_BITS,
typename BLOCK = Register_block_tmpl<
Register_block_base<MAX_BITS> const
>
>
class Ro_register_block
{
private:
template< unsigned B, typename BLK > friend class Ro_register_block;
typedef BLOCK Block;
Block _b;
public:
Ro_register_block() = default;
Ro_register_block(BLOCK const &blk) : _b(blk) {}
template< unsigned BITS >
Ro_register_block(Register_block<BITS> const &blk) : _b(blk._b) {}
typedef Ro_register_tmpl<MAX_BITS, Block> Ro_register;
typedef Ro_register Register;
Ro_register operator [] (unsigned offset) const
{ return Ro_register(this->_b, offset); }
template< unsigned BITS >
Ro_register_tmpl<BITS, Block> r(unsigned offset) const
{ return Ro_register_tmpl<BITS, Block>(this->_b, offset); }
};
template< typename BASE, unsigned MAX_BITS = 32 >
struct Register_block_impl;
#define REGBLK_IMPL_RW_TEMPLATE(sz, ...) \
l4_uint##sz##_t do_read_##sz(l4_addr_t reg) const override \
{ return static_cast<BASE const *>(this)->template read<l4_uint##sz##_t>(reg); } \
\
void do_write_##sz(l4_uint##sz##_t value, l4_addr_t reg) override \
{ static_cast<BASE*>(this)->template write<l4_uint##sz##_t>(value, reg); }
template< typename BASE >
struct Register_block_impl<BASE, 8> : public Register_block_base<8>
{
REGBLK_IMPL_RW_TEMPLATE(8);
};
template< typename BASE >
struct Register_block_impl<BASE, 16> : public Register_block_base<16>
{
REGBLK_IMPL_RW_TEMPLATE(8);
REGBLK_IMPL_RW_TEMPLATE(16);
};
template< typename BASE >
struct Register_block_impl<BASE, 32> : public Register_block_base<32>
{
REGBLK_IMPL_RW_TEMPLATE(8);
REGBLK_IMPL_RW_TEMPLATE(16);
REGBLK_IMPL_RW_TEMPLATE(32);
};
template< typename BASE >
struct Register_block_impl<BASE, 64> : public Register_block_base<64>
{
REGBLK_IMPL_RW_TEMPLATE(8);
REGBLK_IMPL_RW_TEMPLATE(16);
REGBLK_IMPL_RW_TEMPLATE(32);
REGBLK_IMPL_RW_TEMPLATE(64);
};
#undef REGBLK_IMPL_RW_TEMPLATE
}
L4drivers::Register_block
Handles a reference to a register block of the given maximum access width.
Definition hw_register_block:331
L4drivers::Register_block::operator[]
Ro_register operator[](unsigned offset) const
Read only access to register at offset offset.
Definition hw_register_block:365
L4drivers::Register_block::r
Register_tmpl< BITS, Block > r(unsigned offset)
Read/write access to register at offset offset.
Definition hw_register_block:376
L4drivers::Register_block::r
Ro_register_tmpl< BITS, Block > r(unsigned offset) const
Read only access to register at offset offset.
Definition hw_register_block:357
L4drivers::Register_tmpl
Single hardware register inside a Register_block_base interface.
Definition hw_register_block:238
L4drivers::Register_tmpl::clear
value_type clear(value_type clear_bits)
clears bits in clear_bits in the hardware register.
Definition hw_register_block:290
L4drivers::Register_tmpl::modify
value_type modify(value_type clear_bits, value_type set_bits)
clears bits in clear_bits and sets bits in set_bits in the hardware register.
Definition hw_register_block:308
L4drivers::Register_tmpl::set
value_type set(value_type set_bits)
set bits in set_bits in the hardware register.
Definition hw_register_block:274
L4drivers::Register_tmpl::write
void write(value_type val)
write val into the hardware register.
Definition hw_register_block:259
L4drivers::Register_tmpl::operator=
Register_tmpl & operator=(value_type val)
write val into the hardware register.
Definition hw_register_block:252
L4drivers::Ro_register_block::operator[]
Ro_register operator[](unsigned offset) const
Read only access to register at offset offset.
Definition hw_register_block:426
L4drivers::Ro_register_block::r
Ro_register_tmpl< BITS, Block > r(unsigned offset) const
Read only access to register at offset offset.
Definition hw_register_block:436
L4drivers::Ro_register_tmpl
Single read only register inside a Register_block_base interface.
Definition hw_register_block:202
L4drivers::Ro_register_tmpl::read
value_type read() const
read the value from the hardware register.
Definition hw_register_block:224
l4_addr_t
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
l4_uint8_t
unsigned char l4_uint8_t
Unsigned 8bit value.
Definition l4int.h:25
l4_uint32_t
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
l4_uint16_t
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
l4_uint64_t
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
types.h
Common L4 ABI Data Types.
L4drivers::Register_block_base
Abstract register block interface.
Definition hw_register_block:72
L4drivers::Register_block_impl
Implementation helper for register blocks.
Definition hw_register_block:455