mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 20:05:54 +00:00
Fix bug in MMIO framework and test it
Avoid that members of a inheritor overlay those of the register- and MMIO-framework. Beautify register- and MMIO-framework.
This commit is contained in:
parent
e6b72030d3
commit
66bec10276
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _BASE__INCLUDE__UTIL__MMIO_H_
|
||||
#define _BASE__INCLUDE__UTIL__MMIO_H_
|
||||
#ifndef _INCLUDE__UTIL__MMIO_H_
|
||||
#define _INCLUDE__UTIL__MMIO_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/register.h>
|
||||
@ -21,6 +21,11 @@ namespace Genode
|
||||
{
|
||||
/**
|
||||
* A continuous MMIO region
|
||||
*
|
||||
* For correct behavior of the member functions of 'Mmio', a class that
|
||||
* derives from one of the subclasses of 'Mmio' must not define members
|
||||
* named 'Register_base', 'Bitfield_base', 'Register_array_base' or
|
||||
* 'Array_bitfield_base'.
|
||||
*/
|
||||
class Mmio
|
||||
{
|
||||
@ -30,15 +35,15 @@ namespace Genode
|
||||
* Write typed 'value' to MMIO base + 'o'
|
||||
*/
|
||||
template <typename _ACCESS_T>
|
||||
inline void _write(off_t const o, _ACCESS_T const value) {
|
||||
*(_ACCESS_T volatile *)((addr_t)base + o) = value; }
|
||||
inline void _write(off_t const o, _ACCESS_T const value)
|
||||
{ *(_ACCESS_T volatile *)((addr_t)base + o) = value; }
|
||||
|
||||
/**
|
||||
* Read typed from MMIO base + 'o'
|
||||
*/
|
||||
template <typename _ACCESS_T>
|
||||
inline _ACCESS_T _read(off_t const o) const {
|
||||
return *(_ACCESS_T volatile *)((addr_t)base + o); }
|
||||
inline _ACCESS_T _read(off_t const o) const
|
||||
{ return *(_ACCESS_T volatile *)((addr_t)base + o); }
|
||||
|
||||
public:
|
||||
|
||||
@ -47,23 +52,24 @@ namespace Genode
|
||||
/**
|
||||
* An integer like region within a MMIO region.
|
||||
*
|
||||
* \param _OFFSET Offset of the region relative to the
|
||||
* base of the compound MMIO
|
||||
* \param _ACCESS_WIDTH Bit width of the region, for a list of
|
||||
* supported widths see 'Genode::Register'
|
||||
* \param _STRICT_WRITE If set to 0, when writing a bitfield, we
|
||||
* read the register value, update the bits
|
||||
* on it, and write it back to the register.
|
||||
* If set to 1 we take an empty register
|
||||
* value instead, apply the bitfield on it,
|
||||
* and write it to the register. This can
|
||||
* be useful if you have registers that have
|
||||
* different means on reads and writes.
|
||||
* \param _OFFSET Offset of the region relative to the
|
||||
* base of the compound MMIO.
|
||||
* \param _ACCESS_WIDTH Bit width of the region, for a list of
|
||||
* supported widths see 'Genode::Register'.
|
||||
* \param _STRICT_WRITE If set to 0, when writing a bitfield, we
|
||||
* read the register value, update the bits
|
||||
* on it, and write it back to the register.
|
||||
* If set to 1 we take an empty register
|
||||
* value instead, apply the bitfield on it,
|
||||
* and write it to the register. This can
|
||||
* be useful if you have registers that have
|
||||
* different means on reads and writes.
|
||||
*
|
||||
* \detail See 'Genode::Register'
|
||||
* For further details See 'Genode::Register'.
|
||||
*/
|
||||
template <off_t _OFFSET, unsigned long _ACCESS_WIDTH,
|
||||
bool _STRICT_WRITE = false>
|
||||
|
||||
struct Register : public Genode::Register<_ACCESS_WIDTH>
|
||||
{
|
||||
enum {
|
||||
@ -72,56 +78,71 @@ namespace Genode
|
||||
STRICT_WRITE = _STRICT_WRITE,
|
||||
};
|
||||
|
||||
/*
|
||||
* GCC 4.4, in contrast to GCC versions >= 4.5, can't
|
||||
* select function templates like 'write(typename
|
||||
* T::Register::access_t value)' through a given 'T'
|
||||
* that, in this case, derives from 'Register<X, Y, Z>'.
|
||||
* It seems this is due to the fact that 'T::Register'
|
||||
* is a template. Thus we provide some kind of stamp
|
||||
* that solely must not be redefined by the deriving
|
||||
* class to ensure correct template selection.
|
||||
*/
|
||||
typedef Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE>
|
||||
Register_base;
|
||||
|
||||
/**
|
||||
* A region within a register
|
||||
*
|
||||
* \param _SHIFT Bit shift of the first bit within the
|
||||
* compound register
|
||||
* \param _WIDTH Bit width of the region
|
||||
* \param _SHIFT Bit shift of the first bit within the
|
||||
* compound register.
|
||||
* \param _WIDTH bit width of the region
|
||||
*
|
||||
* \detail See 'Genode::Register::Bitfield'
|
||||
* For details see 'Genode::Register::Bitfield'.
|
||||
*/
|
||||
template <unsigned long _SHIFT, unsigned long _WIDTH>
|
||||
struct Bitfield :
|
||||
public Genode::Register<ACCESS_WIDTH>::template Bitfield<_SHIFT, _WIDTH>
|
||||
struct Bitfield : public Genode::Register<ACCESS_WIDTH>::
|
||||
template Bitfield<_SHIFT, _WIDTH>
|
||||
{
|
||||
/* Back reference to containing register */
|
||||
typedef Register<OFFSET, ACCESS_WIDTH, STRICT_WRITE> Compound_reg;
|
||||
/* analogous to 'Mmio::Register::Register_base' */
|
||||
typedef Bitfield<_SHIFT, _WIDTH> Bitfield_base;
|
||||
|
||||
/* back reference to containing register */
|
||||
typedef Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE>
|
||||
Compound_reg;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* An array of successive equally structured regions
|
||||
* An array of successive equally structured regions, called items
|
||||
*
|
||||
* \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
|
||||
* \param _STRICT_WRITE If set to 0, when writing a bitfield, we
|
||||
* read the register value, update the bits
|
||||
* on it, and write it back to the register.
|
||||
* If set to 1, we take an empty register
|
||||
* value instead, apply the bitfield on it,
|
||||
* and write it to the register. This can
|
||||
* be useful if you have registers that have
|
||||
* different means on reads and writes.
|
||||
* Please note that ACCESS_WIDTH is decisive
|
||||
* for the range of such strictness.
|
||||
* \param _OFFSET Offset of the first item 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 item gets iterated
|
||||
* successively.
|
||||
* \param _ITEM_WIDTH bit width of an item
|
||||
* \param _STRICT_WRITE If set to 0, when writing a bitfield, we
|
||||
* read the register value, update the bits
|
||||
* on it, and write it back to the register.
|
||||
* If set to 1, we take an empty register
|
||||
* value instead, apply the bitfield on it,
|
||||
* and write it to the register. This can
|
||||
* be useful if you have registers that have
|
||||
* different means on reads and writes.
|
||||
* Please note that ACCESS_WIDTH is decisive
|
||||
* for the range of such strictness.
|
||||
*
|
||||
* \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
|
||||
* The array takes all inner structures, wich are covered by an
|
||||
* item width and iterates them successively. 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 _OFFSET, unsigned long _ACCESS_WIDTH,
|
||||
unsigned long _ITEMS, unsigned long _ITEM_WIDTH,
|
||||
@ -130,9 +151,8 @@ namespace Genode
|
||||
struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH,
|
||||
_STRICT_WRITE>
|
||||
{
|
||||
typedef
|
||||
typename Trait::Uint_type<_ACCESS_WIDTH>::template Divisor<_ITEM_WIDTH>
|
||||
Item;
|
||||
typedef typename Trait::Uint_type<_ACCESS_WIDTH>::
|
||||
template Divisor<_ITEM_WIDTH> Item;
|
||||
|
||||
enum {
|
||||
STRICT_WRITE = _STRICT_WRITE,
|
||||
@ -140,29 +160,36 @@ namespace Genode
|
||||
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, STRICT_WRITE>::access_t
|
||||
access_t;
|
||||
/* analogous to 'Mmio::Register::Register_base' */
|
||||
typedef Register_array<OFFSET, ACCESS_WIDTH, ITEMS,
|
||||
ITEM_WIDTH, STRICT_WRITE>
|
||||
Register_array_base;
|
||||
|
||||
typedef typename Register<OFFSET, ACCESS_WIDTH, STRICT_WRITE>::
|
||||
access_t access_t;
|
||||
|
||||
/**
|
||||
* A bitregion within a register array item
|
||||
*
|
||||
* \param _SHIFT Bit shift of the first bit within an item
|
||||
* \param _WIDTH Bit width of the region
|
||||
* \param _SHIFT bit shift of the first bit within an item
|
||||
* \param _WIDTH bit width of the region
|
||||
*
|
||||
* \detail See 'Genode::Register::Bitfield'
|
||||
* For details see 'Genode::Register::Bitfield'.
|
||||
*/
|
||||
template <unsigned long _SHIFT, unsigned long _SIZE>
|
||||
struct Bitfield :
|
||||
public Register<OFFSET, ACCESS_WIDTH, STRICT_WRITE>::template Bitfield<_SHIFT, _SIZE>
|
||||
public Register<OFFSET, ACCESS_WIDTH, STRICT_WRITE>::
|
||||
template Bitfield<_SHIFT, _SIZE>
|
||||
{
|
||||
/* Back reference to containing register array */
|
||||
/* analogous to 'Mmio::Register::Register_base' */
|
||||
typedef Bitfield<_SHIFT, _SIZE> Array_bitfield_base;
|
||||
|
||||
/* back reference to containing register array */
|
||||
typedef Register_array<OFFSET, ACCESS_WIDTH, ITEMS,
|
||||
ITEM_WIDTH, STRICT_WRITE>
|
||||
Compound_array;
|
||||
@ -171,14 +198,14 @@ namespace Genode
|
||||
/**
|
||||
* Calculate destination of an array-item access
|
||||
*
|
||||
* \param offset Gets overridden with the offset of the
|
||||
* access type instance, that contains the
|
||||
* access destination, relative to the MMIO
|
||||
* base
|
||||
* \param shift Gets overridden with the shift of the
|
||||
* destination within the access type instance
|
||||
* targeted by 'offset'
|
||||
* \param index Index of the targeted array item
|
||||
* \param offset Gets overridden with the offset of the
|
||||
* access type instance, that contains the
|
||||
* access destination, relative to the MMIO
|
||||
* base.
|
||||
* \param shift Gets overridden with the shift of the
|
||||
* destination within the access type instance
|
||||
* targeted by 'offset'.
|
||||
* \param index index of the targeted array item
|
||||
*/
|
||||
static inline void access_dest(off_t & offset,
|
||||
unsigned long & shift,
|
||||
@ -192,10 +219,12 @@ namespace Genode
|
||||
}
|
||||
};
|
||||
|
||||
addr_t const base;
|
||||
addr_t const base; /* base address of targeted MMIO region */
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param mmio_base base address of targeted MMIO region
|
||||
*/
|
||||
inline Mmio(addr_t mmio_base) : base(mmio_base) { }
|
||||
|
||||
@ -205,44 +234,85 @@ namespace Genode
|
||||
*************************/
|
||||
|
||||
/**
|
||||
* Typed address of register 'REGISTER'
|
||||
* Get the address of the register 'T' typed as its access type
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline typename REGISTER::access_t volatile * typed_addr() const {
|
||||
return (typename REGISTER::access_t volatile *)
|
||||
base + REGISTER::OFFSET; }
|
||||
template <typename T>
|
||||
inline typename T::Register_base::access_t volatile * typed_addr() const
|
||||
{
|
||||
typedef typename T::Register_base Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
return (access_t volatile *)(base + Register::OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the whole register 'REGISTER'
|
||||
* Read the register 'T'
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline typename REGISTER::access_t read() const {
|
||||
return _read<typename REGISTER::access_t>(REGISTER::OFFSET); }
|
||||
template <typename T>
|
||||
inline typename T::Register_base::access_t read() const
|
||||
{
|
||||
typedef typename T::Register_base Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
return _read<access_t>(Register::OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 'value' to the register 'REGISTER'
|
||||
* Override the register 'T'
|
||||
*/
|
||||
template <typename REGISTER>
|
||||
inline void write(typename REGISTER::access_t const value) {
|
||||
_write<typename REGISTER::access_t>(REGISTER::OFFSET, value); }
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
write(typename T::Register_base::access_t const value)
|
||||
{
|
||||
typedef typename T::Register_base Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
_write<access_t>(Register::OFFSET, value);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
** Access to bitfields within registers **
|
||||
******************************************/
|
||||
|
||||
/**
|
||||
* Read the bitfield 'BITFIELD'
|
||||
* Read the bitfield 'T' of a register
|
||||
*/
|
||||
template <typename BITFIELD>
|
||||
inline typename BITFIELD::Compound_reg::access_t read() const;
|
||||
template <typename T>
|
||||
inline typename T::Bitfield_base::Compound_reg::access_t
|
||||
read() const
|
||||
{
|
||||
typedef typename T::Bitfield_base Bitfield;
|
||||
typedef typename Bitfield::Compound_reg Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
return Bitfield::get(_read<access_t>(Register::OFFSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value to the bitfield 'BITFIELD'
|
||||
* Override to the bitfield 'T' of a register
|
||||
*
|
||||
* \param value value that shall be written
|
||||
*/
|
||||
template <typename BITFIELD>
|
||||
template <typename T>
|
||||
inline void
|
||||
write(typename BITFIELD::Compound_reg::access_t const value);
|
||||
write(typename T::Bitfield_base::Compound_reg::access_t const value)
|
||||
{
|
||||
typedef typename T::Bitfield_base Bitfield;
|
||||
typedef typename Bitfield::Compound_reg Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
|
||||
/* initialize the pattern written finally to the register */
|
||||
access_t write_value;
|
||||
if (Register::STRICT_WRITE)
|
||||
{
|
||||
/* apply the bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* apply the bitfield to the old register value */
|
||||
write_value = read<Register>();
|
||||
Bitfield::clear(write_value);
|
||||
}
|
||||
/* apply bitfield value and override register */
|
||||
Bitfield::set(write_value, value);
|
||||
write<Register>(write_value);
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
@ -250,18 +320,81 @@ namespace Genode
|
||||
*******************************/
|
||||
|
||||
/**
|
||||
* Read the whole item 'index' of the array 'REGISTER_ARRAY'
|
||||
* Read an item of the register array 'T'
|
||||
*
|
||||
* \param index index of the targeted item
|
||||
*/
|
||||
template <typename REGISTER_ARRAY>
|
||||
inline typename REGISTER_ARRAY::access_t
|
||||
read(unsigned long const index) const;
|
||||
template <typename T>
|
||||
inline typename T::Register_array_base::access_t
|
||||
read(unsigned long const index) const
|
||||
{
|
||||
typedef typename T::Register_array_base Array;
|
||||
typedef typename Array::access_t access_t;
|
||||
|
||||
/* reads outside the array return 0 */
|
||||
if (index > Array::MAX_INDEX) return 0;
|
||||
|
||||
/* if item width equals access width we optimize the access */
|
||||
off_t offset;
|
||||
if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) {
|
||||
offset = Array::OFFSET + (index << Array::ITEM_WIDTH_LOG2);
|
||||
return _read<access_t>(offset);
|
||||
|
||||
/* access width and item width differ */
|
||||
} else {
|
||||
long unsigned shift;
|
||||
Array::access_dest(offset, shift, index);
|
||||
return (_read<access_t>(offset) >> shift) &
|
||||
Array::ITEM_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 'value' to item 'index' of the array 'REGISTER_ARRAY'
|
||||
* Override an item of the register array 'T'
|
||||
*
|
||||
* \param value value that shall be written
|
||||
* \param index index of the targeted item
|
||||
*/
|
||||
template <typename REGISTER_ARRAY>
|
||||
inline void write(typename REGISTER_ARRAY::access_t const value,
|
||||
unsigned long const index);
|
||||
template <typename T>
|
||||
inline void
|
||||
write(typename T::Register_array_base::access_t const value,
|
||||
unsigned long const index)
|
||||
{
|
||||
typedef typename T::Register_array_base Array;
|
||||
typedef typename Array::access_t access_t;
|
||||
|
||||
/* ignore writes outside the array */
|
||||
if (index > Array::MAX_INDEX) return;
|
||||
|
||||
/* optimize the access if item width equals access width */
|
||||
off_t offset;
|
||||
if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) {
|
||||
offset = Array::OFFSET +
|
||||
(index << Array::ITEM_WIDTH_LOG2);
|
||||
_write<access_t>(offset, value);
|
||||
|
||||
/* access width and item width differ */
|
||||
} else {
|
||||
long unsigned shift;
|
||||
Array::access_dest(offset, shift, index);
|
||||
|
||||
/* insert new value into old register value */
|
||||
access_t write_value;
|
||||
if (Array::STRICT_WRITE)
|
||||
{
|
||||
/* apply bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* apply bitfield to the old register value */
|
||||
write_value = _read<access_t>(offset);
|
||||
write_value &= ~(Array::ITEM_MASK << shift);
|
||||
}
|
||||
/* apply bitfield value and override register */
|
||||
write_value |= (value & Array::ITEM_MASK) << shift;
|
||||
_write<access_t>(offset, write_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
@ -269,21 +402,50 @@ namespace Genode
|
||||
*****************************************************/
|
||||
|
||||
/**
|
||||
* Read the bitfield 'ARRAY_BITFIELD' of item 'index' of the
|
||||
* compound reg array
|
||||
* Read the bitfield 'T' of a register array
|
||||
*
|
||||
* \param index index of the targeted item
|
||||
*/
|
||||
template <typename ARRAY_BITFIELD>
|
||||
inline typename ARRAY_BITFIELD::Compound_array::access_t
|
||||
read(unsigned long const index) const;
|
||||
template <typename T>
|
||||
inline typename T::Array_bitfield_base::Compound_array::access_t
|
||||
read(unsigned long const index) const
|
||||
{
|
||||
typedef typename T::Array_bitfield_base Bitfield;
|
||||
typedef typename Bitfield::Compound_array Array;
|
||||
return Bitfield::get(read<Array>(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 'value' to bitfield 'ARRAY_BITFIELD' of item 'index' of
|
||||
* the compound reg array
|
||||
* Override the bitfield 'T' of a register array
|
||||
*
|
||||
* \param value value that shall be written
|
||||
* \param index index of the targeted array item
|
||||
*/
|
||||
template <typename ARRAY_BITFIELD>
|
||||
template <typename T>
|
||||
inline void
|
||||
write(typename ARRAY_BITFIELD::Compound_array::access_t const value,
|
||||
long unsigned const index);
|
||||
write(typename T::Array_bitfield_base::Compound_array::access_t const value,
|
||||
long unsigned const index)
|
||||
{
|
||||
typedef typename T::Array_bitfield_base Bitfield;
|
||||
typedef typename Bitfield::Compound_array Array;
|
||||
typedef typename Array::access_t access_t;
|
||||
|
||||
/* initialize the pattern written finally to the register */
|
||||
access_t write_value;
|
||||
if (Array::STRICT_WRITE)
|
||||
{
|
||||
/* apply the bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* apply the bitfield to the old register value */
|
||||
write_value = read<Array>(index);
|
||||
Bitfield::clear(write_value);
|
||||
}
|
||||
/* apply bitfield value and override register */
|
||||
Bitfield::set(write_value, value);
|
||||
write<Array>(write_value, index);
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
@ -296,14 +458,13 @@ namespace Genode
|
||||
struct Delayer
|
||||
{
|
||||
/**
|
||||
* Delay the execution of the caller for the specified amount
|
||||
* of microseconds
|
||||
* Delay execution of the caller for 'us' microseconds
|
||||
*/
|
||||
virtual void usleep(unsigned us) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait until the 'BITFIELD' contains the specified 'value'
|
||||
* Wait until bitfield 'T' contains the specified 'value'
|
||||
*
|
||||
* \param value value to wait for
|
||||
* \param delayer sleeping facility to be used when the
|
||||
@ -311,165 +472,22 @@ namespace Genode
|
||||
* \param max_attempts number of bitfield probing attempts
|
||||
* \param us number of microseconds between attempts
|
||||
*/
|
||||
template <typename BITFIELD>
|
||||
template <typename T>
|
||||
inline bool
|
||||
wait_for(typename BITFIELD::Compound_reg::access_t const value,
|
||||
Delayer &delayer,
|
||||
wait_for(typename T::Bitfield_base::Compound_reg::access_t const value,
|
||||
Delayer & delayer,
|
||||
unsigned max_attempts = 500,
|
||||
unsigned us = 1000)
|
||||
{
|
||||
typedef typename T::Bitfield_base Bitfield;
|
||||
for (unsigned i = 0; i < max_attempts; i++, delayer.usleep(us))
|
||||
if (read<BITFIELD>() == value)
|
||||
return true;
|
||||
|
||||
{
|
||||
if (read<Bitfield>() == value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/******************************************
|
||||
** Access to bitfields within registers **
|
||||
******************************************/
|
||||
|
||||
|
||||
template <typename BITFIELD>
|
||||
typename BITFIELD::Compound_reg::access_t Genode::Mmio::read() const
|
||||
{
|
||||
typedef typename BITFIELD::Compound_reg Register;
|
||||
typedef typename Register::access_t access_t;
|
||||
return BITFIELD::get(_read<access_t>(Register::OFFSET));
|
||||
}
|
||||
|
||||
|
||||
template <typename BITFIELD>
|
||||
void Genode::Mmio::write(typename BITFIELD::Compound_reg::access_t const value)
|
||||
{
|
||||
/* Initialize the pattern that is written finally to the register */
|
||||
typedef typename BITFIELD::Compound_reg Register;
|
||||
typename Register::access_t write_value;
|
||||
if (Register::STRICT_WRITE)
|
||||
{
|
||||
/* We must only apply the bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* We've got to apply the bitfield to the old register value */
|
||||
write_value = read<Register>();
|
||||
BITFIELD::clear(write_value);
|
||||
}
|
||||
/* Apply bitfield value and override register */
|
||||
BITFIELD::set(write_value, value);
|
||||
write<Register>(write_value);
|
||||
}
|
||||
|
||||
|
||||
/************************************
|
||||
** Access to register array items **
|
||||
************************************/
|
||||
|
||||
|
||||
template <typename REGISTER_ARRAY>
|
||||
typename REGISTER_ARRAY::access_t
|
||||
Genode::Mmio::read(unsigned long const index) const
|
||||
{
|
||||
/* Reads outside the array return 0 */
|
||||
if (index > REGISTER_ARRAY::MAX_INDEX) return 0;
|
||||
|
||||
/* If item width equals access width we optimize the access */
|
||||
off_t offset;
|
||||
if (REGISTER_ARRAY::ITEM_WIDTH == REGISTER_ARRAY::ACCESS_WIDTH) {
|
||||
offset = REGISTER_ARRAY::OFFSET
|
||||
+ (index << REGISTER_ARRAY::ITEM_WIDTH_LOG2);
|
||||
return _read<typename REGISTER_ARRAY::access_t>(offset);
|
||||
|
||||
/* Access width and item width differ */
|
||||
} else {
|
||||
long unsigned shift;
|
||||
REGISTER_ARRAY::access_dest(offset, shift, index);
|
||||
return (_read<typename REGISTER_ARRAY::access_t>(offset) >> shift)
|
||||
& REGISTER_ARRAY::ITEM_MASK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename REGISTER_ARRAY>
|
||||
void Genode::Mmio::write(typename REGISTER_ARRAY::access_t const value,
|
||||
unsigned long const index)
|
||||
{
|
||||
/* Writes outside the array are ignored */
|
||||
if (index > REGISTER_ARRAY::MAX_INDEX) return;
|
||||
|
||||
/* If item width equals access width we optimize the access */
|
||||
off_t offset;
|
||||
if (REGISTER_ARRAY::ITEM_WIDTH == REGISTER_ARRAY::ACCESS_WIDTH) {
|
||||
offset = REGISTER_ARRAY::OFFSET
|
||||
+ (index << REGISTER_ARRAY::ITEM_WIDTH_LOG2);
|
||||
_write<typename REGISTER_ARRAY::access_t>(offset, value);
|
||||
|
||||
/* Access width and item width differ */
|
||||
} else {
|
||||
long unsigned shift;
|
||||
REGISTER_ARRAY::access_dest(offset, shift, index);
|
||||
|
||||
/* Insert new value into old register value */
|
||||
typename REGISTER_ARRAY::access_t write_value;
|
||||
if (REGISTER_ARRAY::STRICT_WRITE)
|
||||
{
|
||||
/* We must only apply the bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* We've got to apply the bitfield to the old register value */
|
||||
write_value = _read<typename REGISTER_ARRAY::access_t>(offset);
|
||||
write_value &= ~(REGISTER_ARRAY::ITEM_MASK << shift);
|
||||
}
|
||||
/* Apply bitfield value and override register */
|
||||
write_value |= (value & REGISTER_ARRAY::ITEM_MASK) << shift;
|
||||
_write<typename REGISTER_ARRAY::access_t>(offset, write_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
** Access to bitfields within register array items **
|
||||
*****************************************************/
|
||||
|
||||
|
||||
template <typename ARRAY_BITFIELD>
|
||||
void
|
||||
Genode::Mmio::write(typename ARRAY_BITFIELD::Compound_array::access_t const value,
|
||||
long unsigned const index)
|
||||
{
|
||||
/* Initialize the pattern that is finally written to the register */
|
||||
typedef typename ARRAY_BITFIELD::Compound_array Register_array;
|
||||
typename Register_array::access_t write_value;
|
||||
if (Register_array::STRICT_WRITE)
|
||||
{
|
||||
/* We must only apply the bitfield to an empty write pattern */
|
||||
write_value = 0;
|
||||
} else {
|
||||
|
||||
/* We've got to apply the bitfield to the old register value */
|
||||
write_value = read<Register_array>(index);
|
||||
ARRAY_BITFIELD::clear(write_value);
|
||||
}
|
||||
/* Apply bitfield value and override register */
|
||||
ARRAY_BITFIELD::set(write_value, value);
|
||||
write<Register_array>(write_value, index);
|
||||
}
|
||||
|
||||
|
||||
template <typename ARRAY_BITFIELD>
|
||||
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::access_t access_t;
|
||||
return ARRAY_BITFIELD::get(read<Array>(index));
|
||||
}
|
||||
|
||||
|
||||
#endif /* _BASE__INCLUDE__UTIL__MMIO_H_ */
|
||||
#endif /* _INCLUDE__UTIL__MMIO_H_ */
|
||||
|
||||
|
@ -11,9 +11,10 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _BASE__INCLUDE__UTIL__REGISTER_H_
|
||||
#define _BASE__INCLUDE__UTIL__REGISTER_H_
|
||||
#ifndef _INCLUDE__UTIL__REGISTER_H_
|
||||
#define _INCLUDE__UTIL__REGISTER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Genode
|
||||
@ -83,7 +84,7 @@ namespace Genode
|
||||
/**
|
||||
* An integer like highly structured memory region
|
||||
*
|
||||
* \param _ACCESS_WIDTH Bit width of the region
|
||||
* \param _ACCESS_WIDTH bit width of the region
|
||||
*
|
||||
* The register can contain multiple bitfields. Bitfields that are
|
||||
* partially exceed the register range are read and written also partially.
|
||||
@ -104,13 +105,12 @@ namespace Genode
|
||||
/**
|
||||
* A bitregion within a register
|
||||
*
|
||||
* \param _SHIFT Bit shift of the first bit within the compound
|
||||
* register
|
||||
* \param _WIDTH Bit width of the region
|
||||
* \param _SHIFT bit shift of 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
|
||||
* 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 _SHIFT, unsigned long _WIDTH>
|
||||
struct Bitfield
|
||||
@ -124,8 +124,19 @@ namespace Genode
|
||||
WIDTH = _WIDTH,
|
||||
};
|
||||
|
||||
static access_t mask() { return ((access_t)1 << WIDTH) - 1; }
|
||||
static access_t reg_mask() { return mask() << SHIFT; }
|
||||
/**
|
||||
* Get an unshifted mask of this field
|
||||
*/
|
||||
static access_t mask() { return ((access_t)1 << WIDTH) - 1; }
|
||||
|
||||
/**
|
||||
* Get a mask of this field shifted by its shift in the register
|
||||
*/
|
||||
static access_t reg_mask() { return mask() << SHIFT; }
|
||||
|
||||
/**
|
||||
* Get the bitwise negation of 'reg_mask'
|
||||
*/
|
||||
static access_t clear_mask() { return ~reg_mask(); }
|
||||
|
||||
/**
|
||||
@ -134,11 +145,10 @@ namespace Genode
|
||||
typedef Register<ACCESS_WIDTH> Compound_reg;
|
||||
|
||||
/**
|
||||
* Get a register value with this bitfield set to 'value' and the
|
||||
* rest left zero
|
||||
* Get register with this bitfield set to 'value' and rest left 0
|
||||
*
|
||||
* \detail Useful to combine successive access to multiple
|
||||
* bitfields into one operation
|
||||
* Useful to combine successive access to multiple
|
||||
* bitfields into one operation.
|
||||
*/
|
||||
static inline access_t bits(access_t const value) {
|
||||
return (value & mask()) << SHIFT; }
|
||||
@ -146,17 +156,17 @@ namespace Genode
|
||||
/**
|
||||
* Get a register value 'reg' masked according to this bitfield
|
||||
*
|
||||
* \detail E.g. '0x1234' masked according to a
|
||||
* 'Register<16>::Bitfield<5,7>' returns '0x0220'
|
||||
* E.g. '0x1234' masked according to a
|
||||
* 'Register<16>::Bitfield<5,7>' returns '0x0220'.
|
||||
*/
|
||||
static inline access_t masked(access_t const reg) {
|
||||
return reg & reg_mask(); }
|
||||
static inline access_t masked(access_t const reg)
|
||||
{ return reg & reg_mask(); }
|
||||
|
||||
/**
|
||||
* Get value of this bitfield from 'reg'
|
||||
*/
|
||||
static inline access_t get(access_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
|
||||
@ -175,5 +185,5 @@ namespace Genode
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _BASE__INCLUDE__UTIL__REGISTER_H_ */
|
||||
#endif /* _INCLUDE__UTIL__REGISTER_H_ */
|
||||
|
||||
|
@ -69,6 +69,14 @@ struct Test_mmio : public Mmio
|
||||
|
||||
struct Reg : Register<0x04, 8>
|
||||
{
|
||||
enum
|
||||
{
|
||||
/* ensure that we can not falsely overlay inherited enums */
|
||||
OFFSET = 0x1234,
|
||||
ACCESS_WIDTH = 1,
|
||||
STRICT_WRITE = 1,
|
||||
};
|
||||
|
||||
struct Bit_1 : Bitfield<0,1> { };
|
||||
struct Area : Bitfield<1,3>
|
||||
{
|
||||
@ -86,6 +94,16 @@ struct Test_mmio : public Mmio
|
||||
|
||||
struct Array : Register_array<0x2, 16, 10, 4>
|
||||
{
|
||||
enum
|
||||
{
|
||||
/* ensure that we can not falsely overlay inherited enums */
|
||||
STRICT_WRITE = 1,
|
||||
OFFSET = 0x1234,
|
||||
ACCESS_WIDTH = 1,
|
||||
ITEMS = 1,
|
||||
ITEM_WIDTH = 1,
|
||||
};
|
||||
|
||||
struct A : Bitfield<0,1> { };
|
||||
struct B : Bitfield<1,2> { };
|
||||
struct C : Bitfield<3,1> { };
|
||||
|
Loading…
x
Reference in New Issue
Block a user