mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
Simplify interface of the MMIO framework, ref #69
Parameterize register and bitfield templates to always take their bitwidth instead of the according types or width exponents as arguments.
This commit is contained in:
parent
7044b264e6
commit
70ae53fe3c
@ -15,8 +15,6 @@
|
||||
#define _BASE__INCLUDE__UTIL__MMIO_H_
|
||||
|
||||
#include <util/register.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
@ -30,110 +28,119 @@ namespace Genode
|
||||
/**
|
||||
* Write typed 'value' to MMIO base + 'o'
|
||||
*/
|
||||
template <typename STORAGE_T>
|
||||
inline void _write(off_t const o, STORAGE_T const value);
|
||||
template <typename _ACCESS_T>
|
||||
inline void _write(off_t const o, _ACCESS_T const value);
|
||||
|
||||
/**
|
||||
* Read typed from MMIO base + 'o'
|
||||
*/
|
||||
template <typename STORAGE_T>
|
||||
inline STORAGE_T _read(off_t const o) const;
|
||||
template <typename _ACCESS_T>
|
||||
inline _ACCESS_T _read(off_t const o) const;
|
||||
|
||||
public:
|
||||
|
||||
enum { BYTE_WIDTH_LOG2 = 3, BYTE_WIDTH = 1 << BYTE_WIDTH_LOG2 };
|
||||
|
||||
/**
|
||||
* A POD-like region at offset 'MMIO_OFFSET' within a MMIO region
|
||||
* An integer like region within a MMIO region.
|
||||
*
|
||||
* \detail The register can contain multiple bitfields. Bitfields
|
||||
* that are partially out of the register range are read and
|
||||
* written also partially. Bitfields that are completely out
|
||||
* of the register range are read as '0' and trying to
|
||||
* overwrite them has no effect
|
||||
* \param _OFFSET Offset of the region relative to the base
|
||||
* of the compound MMIO.
|
||||
* \param _ACCESS_WIDTH Bit width of the region.
|
||||
*
|
||||
* \detail See 'Genode::Register'
|
||||
*/
|
||||
template <off_t MMIO_OFFSET, typename STORAGE_T>
|
||||
struct Register : public Genode::Register<STORAGE_T>
|
||||
template <off_t _OFFSET, unsigned long _ACCESS_WIDTH>
|
||||
struct Register : public Genode::Register<_ACCESS_WIDTH>
|
||||
{
|
||||
enum { OFFSET = MMIO_OFFSET };
|
||||
enum {
|
||||
OFFSET = _OFFSET,
|
||||
ACCESS_WIDTH = _ACCESS_WIDTH,
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitregion within a register
|
||||
* A region within a register
|
||||
*
|
||||
* \detail Bitfields are read and written according to their range,
|
||||
* so if we have a 'Bitfield<2,3>' and write '0b11101' to it
|
||||
* only '0b101' (shiftet by 2 bits) is written
|
||||
* \param _SHIFT Bit shift of the first bit within the compound register
|
||||
* \param _WIDTH Bit width of the region
|
||||
*
|
||||
* \detail See 'Genode::Register::Bitfield'
|
||||
*/
|
||||
template <unsigned long BIT_SHIFT, unsigned long BIT_SIZE>
|
||||
struct Bitfield : public Genode::Register<STORAGE_T>::template Bitfield<BIT_SHIFT, BIT_SIZE>
|
||||
template <unsigned long _SHIFT, unsigned long _WIDTH>
|
||||
struct Bitfield : public Genode::Register<ACCESS_WIDTH>::template Bitfield<_SHIFT, _WIDTH>
|
||||
{
|
||||
/**
|
||||
* Back reference to containing register
|
||||
*/
|
||||
typedef Register<OFFSET, STORAGE_T> Compound_reg;
|
||||
typedef Register<OFFSET, ACCESS_WIDTH> Compound_reg;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* An array of successive similar items
|
||||
* An array of successive equally structured regions
|
||||
*
|
||||
* \detail 'STORAGE_T' width must be a power of 2. The array
|
||||
* takes all bitfields that are covered by an item width and
|
||||
* iterates them successive 'ITEMS' times. Thus bitfields out of
|
||||
* the range of the first item are not accessible in any item.
|
||||
* Furthermore the maximum item width is the width of 'STORAGE_T'.
|
||||
* The array is not limited to one 'STORAGE_T' instance,
|
||||
* it uses as much successive instances as needed.
|
||||
* \param _OFFSET Offset of the first region relative to the base
|
||||
* of the compound MMIO.
|
||||
* \param _ACCESS_WIDTH Bit width of a single access, must be at least
|
||||
* the item width.
|
||||
* \param _ITEMS How many times the region gets iterated successive
|
||||
* \param _ITEM_WIDTH Bit width of a region
|
||||
*
|
||||
* \detail The array takes all inner structures, wich are covered by an item
|
||||
* width and iterates them successive. Such structures that are partially
|
||||
* exceed an item range are read and written also partially. Structures that are
|
||||
* completely out of the item range are read as '0' and trying to overwrite
|
||||
* them has no effect. The array is not limited to its access width, it extends to
|
||||
* the memory region of its successive items. Trying to read out read with an item
|
||||
* index out of the array range returns '0', trying to write to such indices
|
||||
* has no effect
|
||||
*/
|
||||
template <off_t MMIO_OFFSET, typename STORAGE_T, unsigned long ITEMS, unsigned long _ITEM_WIDTH_LOG2>
|
||||
struct Register_array : public Register<MMIO_OFFSET, STORAGE_T>
|
||||
template <off_t _OFFSET, unsigned long _ACCESS_WIDTH, unsigned long _ITEMS, unsigned long _ITEM_WIDTH>
|
||||
struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH>
|
||||
{
|
||||
enum {
|
||||
MAX_INDEX = ITEMS - 1,
|
||||
ITEM_WIDTH_LOG2 = _ITEM_WIDTH_LOG2,
|
||||
ITEM_WIDTH = 1 << ITEM_WIDTH_LOG2,
|
||||
ITEM_MASK = (1 << ITEM_WIDTH) - 1,
|
||||
ITEMS_PER_REG = (sizeof(STORAGE_T) << BYTE_WIDTH_LOG2) >> ITEM_WIDTH_LOG2,
|
||||
ITEM_IS_REG = ITEMS_PER_REG == 1,
|
||||
STORAGE_WIDTH = BYTE_WIDTH * sizeof(STORAGE_T),
|
||||
typedef typename Trait::Uint_type<_ACCESS_WIDTH>::template Divisor<_ITEM_WIDTH> Item;
|
||||
|
||||
/**
|
||||
* Static sanity check
|
||||
*/
|
||||
ERROR_ITEMS_OVERSIZED = ITEMS_PER_REG / ITEMS_PER_REG,
|
||||
enum {
|
||||
OFFSET = _OFFSET,
|
||||
ACCESS_WIDTH = _ACCESS_WIDTH,
|
||||
ITEMS = _ITEMS,
|
||||
ITEM_WIDTH = _ITEM_WIDTH,
|
||||
|
||||
ITEM_WIDTH_LOG2 = Item::WIDTH_LOG2,
|
||||
MAX_INDEX = ITEMS - 1,
|
||||
ITEM_MASK = (1 << ITEM_WIDTH) - 1,
|
||||
};
|
||||
|
||||
typedef typename Register<OFFSET, ACCESS_WIDTH>::access_t access_t;
|
||||
|
||||
/**
|
||||
* A bitregion within a register array
|
||||
* A bitregion within a register array item
|
||||
*
|
||||
* \detail Bitfields are only written and read as far as the
|
||||
* item width reaches, i.e. assume a 'Register_array<0,uint8_t,6,2>'
|
||||
* that contains a 'Bitfield<1,5>' and we write '0b01101' to it, then
|
||||
* only '0b101' is written and read in consequence. Bitfields that are
|
||||
* completely out of the item range ar read as '0' and trying to overwrite
|
||||
* them has no effect.
|
||||
* \param _SHIFT Bit shift of the first bit within an item
|
||||
* \param _WIDTH Bit width of the region
|
||||
*
|
||||
* \detail See 'Genode::Register::Bitfield'
|
||||
*/
|
||||
template <unsigned long BIT_SHIFT, unsigned long BIT_SIZE>
|
||||
struct Bitfield : public Register<MMIO_OFFSET, STORAGE_T>::template Bitfield<BIT_SHIFT, BIT_SIZE>
|
||||
template <unsigned long _SHIFT, unsigned long _SIZE>
|
||||
struct Bitfield : public Register<OFFSET, ACCESS_WIDTH>::template Bitfield<_SHIFT, _SIZE>
|
||||
{
|
||||
/**
|
||||
* Back reference to containing register array
|
||||
*/
|
||||
typedef Register_array<MMIO_OFFSET, STORAGE_T, ITEMS, ITEM_WIDTH_LOG2> Compound_array;
|
||||
typedef Register_array<OFFSET, ACCESS_WIDTH, ITEMS, ITEM_WIDTH> Compound_array;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the MMIO-relative offset 'offset' and shift 'shift'
|
||||
* within the according 'storage_t' instance to access this bitfield
|
||||
* from item 'index'
|
||||
* within the according 'access_t' instance to access item 'index'
|
||||
*/
|
||||
static inline void access_dest(off_t & offset, unsigned long & shift,
|
||||
unsigned long const index)
|
||||
{
|
||||
unsigned long const bit_off = index << ITEM_WIDTH_LOG2;
|
||||
offset = (off_t) ((bit_off >> BYTE_WIDTH_LOG2) & ~(sizeof(STORAGE_T)-1) );
|
||||
offset = (off_t) ((bit_off >> BYTE_WIDTH_LOG2) & ~(sizeof(access_t)-1) );
|
||||
shift = bit_off - ( offset << BYTE_WIDTH_LOG2 );
|
||||
offset += MMIO_OFFSET;
|
||||
offset += OFFSET;
|
||||
}
|
||||
};
|
||||
|
||||
@ -153,19 +160,19 @@ namespace Genode
|
||||
* Typed address of register 'REGISTER'
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline typename REGISTER::storage_t volatile * typed_addr() const;
|
||||
inline typename REGISTER::access_t volatile * typed_addr() const;
|
||||
|
||||
/**
|
||||
* Read the whole register 'REGISTER'
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline typename REGISTER::storage_t read() const;
|
||||
inline typename REGISTER::access_t read() const;
|
||||
|
||||
/**
|
||||
* Write 'value' to the register 'REGISTER'
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline void write(typename REGISTER::storage_t const value);
|
||||
inline void write(typename REGISTER::access_t const value);
|
||||
|
||||
|
||||
/******************************************
|
||||
@ -176,13 +183,13 @@ namespace Genode
|
||||
* Read the bitfield 'BITFIELD'
|
||||
*/
|
||||
template <typename BITFIELD>
|
||||
inline typename BITFIELD::Compound_reg::storage_t read() const;
|
||||
inline typename BITFIELD::Compound_reg::access_t read() const;
|
||||
|
||||
/**
|
||||
* Write value to the bitfield 'BITFIELD'
|
||||
*/
|
||||
template <typename BITFIELD>
|
||||
inline void write(typename BITFIELD::Compound_reg::storage_t const value);
|
||||
inline void write(typename BITFIELD::Compound_reg::access_t const value);
|
||||
|
||||
|
||||
/*******************************
|
||||
@ -193,13 +200,13 @@ namespace Genode
|
||||
* Read the whole item 'index' of the array 'REGISTER_ARRAY'
|
||||
*/
|
||||
template <typename REGISTER_ARRAY>
|
||||
inline typename REGISTER_ARRAY::storage_t read(unsigned long const index) const;
|
||||
inline typename REGISTER_ARRAY::access_t read(unsigned long const index) const;
|
||||
|
||||
/**
|
||||
* Write 'value' to item 'index' of the array 'REGISTER_ARRAY'
|
||||
*/
|
||||
template <typename REGISTER_ARRAY>
|
||||
inline void write(typename REGISTER_ARRAY::storage_t const value,
|
||||
inline void write(typename REGISTER_ARRAY::access_t const value,
|
||||
unsigned long const index);
|
||||
|
||||
|
||||
@ -211,28 +218,28 @@ namespace Genode
|
||||
* Read the bitfield 'ARRAY_BITFIELD' of item 'index' of the compound reg array
|
||||
*/
|
||||
template <typename ARRAY_BITFIELD>
|
||||
inline typename ARRAY_BITFIELD::Compound_array::storage_t read(unsigned long const index) const;
|
||||
inline typename ARRAY_BITFIELD::Compound_array::access_t read(unsigned long const index) const;
|
||||
|
||||
/**
|
||||
* Write 'value' to bitfield 'ARRAY_BITFIELD' of item 'index' of the compound reg array
|
||||
*/
|
||||
template <typename ARRAY_BITFIELD>
|
||||
inline void write(typename ARRAY_BITFIELD::Compound_array::storage_t const value, long unsigned const index);
|
||||
inline void write(typename ARRAY_BITFIELD::Compound_array::access_t const value, long unsigned const index);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template <typename STORAGE_T>
|
||||
void Genode::Mmio::_write(off_t const o, STORAGE_T const value)
|
||||
template <typename ACCESS_T>
|
||||
void Genode::Mmio::_write(off_t const o, ACCESS_T const value)
|
||||
{
|
||||
*(STORAGE_T volatile *)((addr_t)base + o) = value;
|
||||
*(ACCESS_T volatile *)((addr_t)base + o) = value;
|
||||
}
|
||||
|
||||
|
||||
template <typename STORAGE_T>
|
||||
STORAGE_T Genode::Mmio::_read(off_t const o) const
|
||||
template <typename ACCESS_T>
|
||||
ACCESS_T Genode::Mmio::_read(off_t const o) const
|
||||
{
|
||||
return *(STORAGE_T volatile *)((addr_t)base + o);
|
||||
return *(ACCESS_T volatile *)((addr_t)base + o);
|
||||
}
|
||||
|
||||
|
||||
@ -242,23 +249,23 @@ STORAGE_T Genode::Mmio::_read(off_t const o) const
|
||||
|
||||
|
||||
template <typename REGISTER>
|
||||
typename REGISTER::storage_t volatile * Genode::Mmio::typed_addr() const
|
||||
typename REGISTER::access_t volatile * Genode::Mmio::typed_addr() const
|
||||
{
|
||||
return (typename REGISTER::storage_t volatile *)base + REGISTER::OFFSET;
|
||||
return (typename REGISTER::access_t volatile *)base + REGISTER::OFFSET;
|
||||
}
|
||||
|
||||
|
||||
template <typename REGISTER>
|
||||
typename REGISTER::storage_t Genode::Mmio::read() const
|
||||
typename REGISTER::access_t Genode::Mmio::read() const
|
||||
{
|
||||
return _read<typename REGISTER::storage_t>(REGISTER::OFFSET);
|
||||
return _read<typename REGISTER::access_t>(REGISTER::OFFSET);
|
||||
}
|
||||
|
||||
|
||||
template <typename REGISTER>
|
||||
void Genode::Mmio::write(typename REGISTER::storage_t const value)
|
||||
void Genode::Mmio::write(typename REGISTER::access_t const value)
|
||||
{
|
||||
_write<typename REGISTER::storage_t>(REGISTER::OFFSET, value);
|
||||
_write<typename REGISTER::access_t>(REGISTER::OFFSET, value);
|
||||
}
|
||||
|
||||
|
||||
@ -268,22 +275,22 @@ void Genode::Mmio::write(typename REGISTER::storage_t const value)
|
||||
|
||||
|
||||
template <typename BITFIELD>
|
||||
typename BITFIELD::Compound_reg::storage_t Genode::Mmio::read() const
|
||||
typename BITFIELD::Compound_reg::access_t Genode::Mmio::read() const
|
||||
{
|
||||
typedef typename BITFIELD::Compound_reg Register;
|
||||
typedef typename Register::storage_t storage_t;
|
||||
typedef typename Register::access_t access_t;
|
||||
|
||||
return BITFIELD::get(_read<storage_t>(Register::OFFSET));
|
||||
return BITFIELD::get(_read<access_t>(Register::OFFSET));
|
||||
}
|
||||
|
||||
|
||||
template <typename BITFIELD>
|
||||
void Genode::Mmio::write(typename BITFIELD::Compound_reg::storage_t const value)
|
||||
void Genode::Mmio::write(typename BITFIELD::Compound_reg::access_t const value)
|
||||
{
|
||||
typedef typename BITFIELD::Compound_reg Register;
|
||||
typedef typename Register::storage_t storage_t;
|
||||
typedef typename Register::access_t access_t;
|
||||
|
||||
storage_t new_reg = read<Register>();
|
||||
access_t new_reg = read<Register>();
|
||||
BITFIELD::clear(new_reg);
|
||||
BITFIELD::set(new_reg, value);
|
||||
|
||||
@ -297,7 +304,7 @@ void Genode::Mmio::write(typename BITFIELD::Compound_reg::storage_t const value)
|
||||
|
||||
|
||||
template <typename REGISTER_ARRAY>
|
||||
typename REGISTER_ARRAY::storage_t Genode::Mmio::read(unsigned long const index) const
|
||||
typename REGISTER_ARRAY::access_t Genode::Mmio::read(unsigned long const index) const
|
||||
{
|
||||
/**
|
||||
* Handle array overflow
|
||||
@ -307,25 +314,25 @@ typename REGISTER_ARRAY::storage_t Genode::Mmio::read(unsigned long const index)
|
||||
off_t offset;
|
||||
|
||||
/**
|
||||
* Optimize access if item width equals storage type width
|
||||
* Optimize access if item width equals access width
|
||||
*/
|
||||
if (REGISTER_ARRAY::ITEM_IS_REG) {
|
||||
if (REGISTER_ARRAY::ITEM_WIDTH == REGISTER_ARRAY::ACCESS_WIDTH) {
|
||||
|
||||
offset = REGISTER_ARRAY::OFFSET + (index << REGISTER_ARRAY::ITEM_WIDTH_LOG2);
|
||||
return _read<typename REGISTER_ARRAY::storage_t>(offset);
|
||||
return _read<typename REGISTER_ARRAY::access_t>(offset);
|
||||
|
||||
} else {
|
||||
|
||||
long unsigned shift;
|
||||
REGISTER_ARRAY::access_dest(offset, shift, index);
|
||||
return (_read<typename REGISTER_ARRAY::storage_t>(offset) >> shift) & REGISTER_ARRAY::ITEM_MASK;
|
||||
return (_read<typename REGISTER_ARRAY::access_t>(offset) >> shift) & REGISTER_ARRAY::ITEM_MASK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename REGISTER_ARRAY>
|
||||
void Genode::Mmio::write(typename REGISTER_ARRAY::storage_t const value,
|
||||
void Genode::Mmio::write(typename REGISTER_ARRAY::access_t const value,
|
||||
unsigned long const index)
|
||||
{
|
||||
/**
|
||||
@ -336,12 +343,12 @@ void Genode::Mmio::write(typename REGISTER_ARRAY::storage_t const value,
|
||||
off_t offset;
|
||||
|
||||
/**
|
||||
* Optimize access if item width equals storage type width
|
||||
* Optimize access if item width equals access width
|
||||
*/
|
||||
if (REGISTER_ARRAY::ITEM_IS_REG) {
|
||||
if (REGISTER_ARRAY::ITEM_WIDTH == REGISTER_ARRAY::ACCESS_WIDTH) {
|
||||
|
||||
offset = REGISTER_ARRAY::OFFSET + (index << REGISTER_ARRAY::ITEM_WIDTH_LOG2);
|
||||
_write<typename REGISTER_ARRAY::storage_t>(offset, value);
|
||||
_write<typename REGISTER_ARRAY::access_t>(offset, value);
|
||||
|
||||
} else {
|
||||
|
||||
@ -351,11 +358,11 @@ void Genode::Mmio::write(typename REGISTER_ARRAY::storage_t const value,
|
||||
/**
|
||||
* Insert new value into old register value
|
||||
*/
|
||||
typename REGISTER_ARRAY::storage_t new_reg = _read<typename REGISTER_ARRAY::storage_t>(offset);
|
||||
typename REGISTER_ARRAY::access_t new_reg = _read<typename REGISTER_ARRAY::access_t>(offset);
|
||||
new_reg &= ~(REGISTER_ARRAY::ITEM_MASK << shift);
|
||||
new_reg |= (value & REGISTER_ARRAY::ITEM_MASK) << shift;
|
||||
|
||||
_write<typename REGISTER_ARRAY::storage_t>(offset, new_reg);
|
||||
_write<typename REGISTER_ARRAY::access_t>(offset, new_reg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,12 +373,12 @@ void Genode::Mmio::write(typename REGISTER_ARRAY::storage_t const value,
|
||||
|
||||
|
||||
template <typename ARRAY_BITFIELD>
|
||||
void Genode::Mmio::write(typename ARRAY_BITFIELD::Compound_array::storage_t const value,
|
||||
void Genode::Mmio::write(typename ARRAY_BITFIELD::Compound_array::access_t const value,
|
||||
long unsigned const index)
|
||||
{
|
||||
typedef typename ARRAY_BITFIELD::Compound_array Register_array;
|
||||
|
||||
typename Register_array::storage_t new_reg = read<Register_array>(index);
|
||||
typename Register_array::access_t new_reg = read<Register_array>(index);
|
||||
ARRAY_BITFIELD::clear(new_reg);
|
||||
ARRAY_BITFIELD::set(new_reg, value);
|
||||
|
||||
@ -380,10 +387,10 @@ void Genode::Mmio::write(typename ARRAY_BITFIELD::Compound_array::storage_t cons
|
||||
|
||||
|
||||
template <typename ARRAY_BITFIELD>
|
||||
typename ARRAY_BITFIELD::Compound_array::storage_t Genode::Mmio::read(long unsigned const index) const
|
||||
typename ARRAY_BITFIELD::Compound_array::access_t Genode::Mmio::read(long unsigned const index) const
|
||||
{
|
||||
typedef typename ARRAY_BITFIELD::Compound_array Array;
|
||||
typedef typename Array::storage_t storage_t;
|
||||
typedef typename Array::access_t access_t;
|
||||
|
||||
return ARRAY_BITFIELD::get(read<Array>(index));
|
||||
}
|
||||
|
@ -18,23 +18,94 @@
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
namespace Trait {
|
||||
|
||||
/**
|
||||
* Get unsigned integer type for a given access width
|
||||
*/
|
||||
template <unsigned long _WIDTH> struct Uint_type;
|
||||
|
||||
template <> struct Uint_type<8>
|
||||
{
|
||||
typedef uint8_t Type;
|
||||
enum { WIDTH_LOG2 = 3 };
|
||||
|
||||
/**
|
||||
* Declare dividers of the compound type width
|
||||
*/
|
||||
template <unsigned long _DIVISOR_WIDTH> struct Divisor;
|
||||
};
|
||||
|
||||
template <> struct Uint_type<16> : Uint_type<8>
|
||||
{
|
||||
typedef uint16_t Type;
|
||||
enum { WIDTH_LOG2 = 4 };
|
||||
};
|
||||
|
||||
template <> struct Uint_type<32> : Uint_type<16>
|
||||
{
|
||||
typedef uint32_t Type;
|
||||
enum { WIDTH_LOG2 = 5 };
|
||||
};
|
||||
|
||||
template <> struct Uint_type<64> : Uint_type<32>
|
||||
{
|
||||
typedef uint32_t Type;
|
||||
enum { WIDTH_LOG2 = 6 };
|
||||
};
|
||||
|
||||
template <> struct Uint_type<8>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; };
|
||||
template <> struct Uint_type<8>::Divisor<2> { enum { WIDTH_LOG2 = 1 }; };
|
||||
template <> struct Uint_type<8>::Divisor<4> { enum { WIDTH_LOG2 = 2 }; };
|
||||
template <> struct Uint_type<8>::Divisor<8> { enum { WIDTH_LOG2 = 3 }; };
|
||||
template <> struct Uint_type<16>::Divisor<16> { enum { WIDTH_LOG2 = 4 }; };
|
||||
template <> struct Uint_type<32>::Divisor<32> { enum { WIDTH_LOG2 = 5 }; };
|
||||
template <> struct Uint_type<64>::Divisor<64> { enum { WIDTH_LOG2 = 6 }; };
|
||||
}
|
||||
|
||||
/**
|
||||
* A POD-like highly structured memory region
|
||||
* An integer like highly structured memory region
|
||||
*
|
||||
* \param _ACCESS_WIDTH Bit width of the region
|
||||
*
|
||||
* \detail The register can contain multiple bitfields. Bitfields
|
||||
* that are partially exceed the register range are read and
|
||||
* written also partially. Bitfields that are completely out
|
||||
* of the register range are read as '0' and trying to
|
||||
* overwrite them has no effect.
|
||||
*/
|
||||
template <typename STORAGE_T>
|
||||
template <unsigned long _ACCESS_WIDTH>
|
||||
struct Register
|
||||
{
|
||||
typedef STORAGE_T storage_t;
|
||||
enum {
|
||||
ACCESS_WIDTH = _ACCESS_WIDTH,
|
||||
|
||||
ACCESS_WIDTH_LOG2 = Trait::Uint_type<ACCESS_WIDTH>::WIDTH_LOG2,
|
||||
};
|
||||
|
||||
typedef typename Trait::Uint_type<ACCESS_WIDTH>::Type access_t;
|
||||
|
||||
/**
|
||||
* A bitregion within a register
|
||||
*
|
||||
* \param _SHIFT Bit shift of the first bit within the compound register
|
||||
* \param _WIDTH Bit width of the region
|
||||
*
|
||||
* \detail Bitfields are read and written according to their range,
|
||||
* so if we have a 'Bitfield<2,3>' and write '0b11101' to it
|
||||
* only '0b101' (shiftet by 2 bits) is written
|
||||
*/
|
||||
template <unsigned long BIT_SHIFT, unsigned long BIT_SIZE>
|
||||
template <unsigned long _SHIFT, unsigned long _WIDTH>
|
||||
struct Bitfield
|
||||
{
|
||||
enum {
|
||||
SHIFT = BIT_SHIFT,
|
||||
WIDTH = BIT_SIZE,
|
||||
|
||||
/**
|
||||
* Fetch template parameters
|
||||
*/
|
||||
SHIFT = _SHIFT,
|
||||
WIDTH = _WIDTH,
|
||||
|
||||
MASK = (1 << WIDTH) - 1,
|
||||
REG_MASK = MASK << SHIFT,
|
||||
CLEAR_MASK = ~REG_MASK,
|
||||
@ -43,7 +114,7 @@ namespace Genode
|
||||
/**
|
||||
* Back reference to containing register
|
||||
*/
|
||||
typedef Register<storage_t> Compound_reg;
|
||||
typedef Register<ACCESS_WIDTH> Compound_reg;
|
||||
|
||||
/**
|
||||
* Get a register value with this bitfield set to 'value' and the rest left zero
|
||||
@ -51,22 +122,22 @@ namespace Genode
|
||||
* \detail Useful to combine successive access to multiple bitfields
|
||||
* into one operation
|
||||
*/
|
||||
static inline storage_t bits(storage_t const value) { return (value & MASK) << SHIFT; }
|
||||
static inline access_t bits(access_t const value) { return (value & MASK) << SHIFT; }
|
||||
|
||||
/**
|
||||
* Get value of this bitfield from 'reg'
|
||||
*/
|
||||
static inline storage_t get(storage_t const reg) { return (reg >> SHIFT) & MASK; }
|
||||
static inline access_t get(access_t const reg) { return (reg >> SHIFT) & MASK; }
|
||||
|
||||
/**
|
||||
* Get registervalue 'reg' with this bitfield set to zero
|
||||
*/
|
||||
static inline void clear(storage_t & reg) { reg &= CLEAR_MASK; }
|
||||
static inline void clear(access_t & reg) { reg &= CLEAR_MASK; }
|
||||
|
||||
/**
|
||||
* Get registervalue 'reg' with this bitfield set to 'value'
|
||||
*/
|
||||
static inline void set(storage_t & reg, storage_t const value = ~0)
|
||||
static inline void set(access_t & reg, access_t const value = ~0)
|
||||
{
|
||||
clear(reg);
|
||||
reg |= (value & MASK) << SHIFT;
|
||||
|
@ -31,7 +31,7 @@ static uint8_t mmio_mem[MMIO_SIZE];
|
||||
/**
|
||||
* Exemplary highly structured type for accessing 'cpu_state'
|
||||
*/
|
||||
struct Cpu_state : Register<uint16_t>
|
||||
struct Cpu_state : Register<16>
|
||||
{
|
||||
struct Mode : Bitfield<0,4>
|
||||
{
|
||||
@ -49,9 +49,9 @@ struct Cpu_state : Register<uint16_t>
|
||||
struct Invalid_bit : Bitfield<18,1> { };
|
||||
struct Invalid_area : Bitfield<15,4> { };
|
||||
|
||||
inline static storage_t read() { return cpu_state; }
|
||||
inline static access_t read() { return cpu_state; }
|
||||
|
||||
inline static void write(storage_t & v) { cpu_state = v; }
|
||||
inline static void write(access_t & v) { cpu_state = v; }
|
||||
};
|
||||
|
||||
struct A : public Mmio {
|
||||
@ -67,15 +67,15 @@ struct Test_mmio : public Mmio
|
||||
{
|
||||
Test_mmio(addr_t const base) : Mmio(base) { }
|
||||
|
||||
struct Reg : Register<0x04, uint8_t>
|
||||
struct Reg : Register<0x04, 8>
|
||||
{
|
||||
struct Bit_1 : Bitfield<0,1> { };
|
||||
struct Area : Bitfield<1,3>
|
||||
{
|
||||
enum {
|
||||
VALUE_1 = 3,
|
||||
VALUE_2 = 4,
|
||||
VALUE_3 = 5,
|
||||
VALUE_1 = 3,
|
||||
VALUE_2 = 4,
|
||||
VALUE_3 = 5,
|
||||
};
|
||||
};
|
||||
struct Bit_2 : Bitfield<4,1> { };
|
||||
@ -84,7 +84,7 @@ struct Test_mmio : public Mmio
|
||||
struct Overlapping_area : Bitfield<0,6> { };
|
||||
};
|
||||
|
||||
struct Array : Register_array<0x2, uint16_t, 10, 2>
|
||||
struct Array : Register_array<0x2, 16, 10, 4>
|
||||
{
|
||||
struct A : Bitfield<0,1> { };
|
||||
struct B : Bitfield<1,2> { };
|
||||
@ -251,7 +251,7 @@ int main()
|
||||
/**
|
||||
* Test 9, read/write bitfields appropriately, overflowing and out of range
|
||||
*/
|
||||
Cpu_state::storage_t state = Cpu_state::read();
|
||||
Cpu_state::access_t state = Cpu_state::read();
|
||||
Cpu_state::Mode::set(state, Cpu_state::Mode::MONITOR);
|
||||
Cpu_state::A::set(state, 1);
|
||||
Cpu_state::B::set(state);
|
||||
|
Loading…
x
Reference in New Issue
Block a user