diff --git a/repos/base/include/util/mmio.h b/repos/base/include/util/mmio.h index 17c6739578..42009e84ed 100644 --- a/repos/base/include/util/mmio.h +++ b/repos/base/include/util/mmio.h @@ -1,5 +1,5 @@ /* - * \brief Generic MMIO access framework + * \brief Type-safe, fine-grained access to a continuous MMIO region * \author Martin stein * \date 2011-10-26 */ @@ -15,590 +15,81 @@ #define _INCLUDE__UTIL__MMIO_H_ /* Genode includes */ -#include +#include -namespace Genode { class Mmio; } +namespace Genode { + class Mmio_plain_access; + class Mmio; +} /** - * A continuous MMIO region - * - * For correct behavior of the methods 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'. + * Plain access implementation for MMIO */ -class Genode::Mmio +class Genode::Mmio_plain_access { - /** - * Write '_ACCESS_T' typed 'value' to MMIO base + 'o' - */ - template - inline void _write(off_t const o, _ACCESS_T const value) - { - addr_t const dst = (addr_t)base + o; - *(_ACCESS_T volatile *)dst = value; - } - - /** - * Read '_ACCESS_T' typed from MMIO base + 'o' - */ - template - inline _ACCESS_T _read(off_t const o) const - { - addr_t const dst = (addr_t)base + o; - _ACCESS_T const value = *(_ACCESS_T volatile *)dst; - return value; - } + friend Register_set_plain_access; public: - enum { BYTE_WIDTH_LOG2 = 3, BYTE_WIDTH = 1 << BYTE_WIDTH_LOG2 }; + /** + * FIXME We keep this public only to stay interface compatible + * but the value should be accessible only through an + * accessor. + */ + addr_t const base; + + private: + /** - * 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. - * - * For further details See 'Genode::Register'. + * Write '_ACCESS_T' typed 'value' to MMIO base + 'offset' */ - template - - struct Register : public Genode::Register<_ACCESS_WIDTH> + template + inline void _write(off_t const offset, ACCESS_T const value) { - enum { - OFFSET = _OFFSET, - ACCESS_WIDTH = _ACCESS_WIDTH, - 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'. - * 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 - * - * For details see 'Genode::Register::Bitfield'. - */ - template - struct Bitfield : public Genode::Register:: - template Bitfield<_SHIFT, _WIDTH> - { - /* 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; - }; - }; + addr_t const dst = base + offset; + *(ACCESS_T volatile *)dst = value; + } /** - * An array of successive equally structured regions, called items - * - * \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. - * - * 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. + * Read '_ACCESS_T' typed from MMIO base + 'offset' */ - template - - struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH, - _STRICT_WRITE> + template + inline ACCESS_T _read(off_t const &offset) const { - typedef typename Trait::Uint_width<_ACCESS_WIDTH>:: - template Divisor<_ITEM_WIDTH> Item; + addr_t const dst = base + offset; + ACCESS_T const value = *(ACCESS_T volatile *)dst; + return value; + } - enum { - STRICT_WRITE = _STRICT_WRITE, - OFFSET = _OFFSET, - ACCESS_WIDTH = _ACCESS_WIDTH, - ITEMS = _ITEMS, - ITEM_WIDTH = _ITEM_WIDTH, - ITEM_WIDTH_LOG2 = Item::WIDTH_LOG2, - MAX_INDEX = ITEMS - 1, - ITEM_MASK = (1ULL << ITEM_WIDTH) - 1, - }; - - /* analogous to 'Mmio::Register::Register_base' */ - typedef Register_array - Register_array_base; - - typedef typename Register:: - 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 - * - * For details see 'Genode::Register::Bitfield'. - */ - template - struct Bitfield : - public Register:: - template Bitfield<_SHIFT, _SIZE> - { - /* analogous to 'Mmio::Register::Register_base' */ - typedef Bitfield<_SHIFT, _SIZE> Array_bitfield_base; - - /* back reference to containing register array */ - typedef Register_array - Compound_array; - }; - - /** - * 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 - */ - static inline void dst(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(access_t)-1) ); - shift = bit_off - ( offset << BYTE_WIDTH_LOG2 ); - offset += OFFSET; - } - - /** - * Calc destination of a simple array-item access without shift - * - * \param offset gets overridden with the offset of the the - * access destination, relative to the MMIO base - * \param index index of the targeted array item - */ - static inline void simple_dst(off_t & offset, - unsigned long const index) - { - offset = (index << ITEM_WIDTH_LOG2) >> BYTE_WIDTH_LOG2; - offset += OFFSET; - } - }; - - addr_t const base; /* base address of targeted MMIO region */ + public: /** * Constructor * - * \param mmio_base base address of targeted MMIO region + * \param base base address of targeted MMIO region */ - inline Mmio(addr_t mmio_base) : base(mmio_base) { } + Mmio_plain_access(addr_t const base) : base(base) { } +}; - /************************* - ** Access to registers ** - *************************/ - - /** - * Get the address of the register 'T' typed as its access type - */ - template - 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 register 'T' - */ - template - inline typename T::Register_base::access_t read() const - { - typedef typename T::Register_base Register; - typedef typename Register::access_t access_t; - return _read(Register::OFFSET); - } - - /** - * Override the register 'T' - */ - template - 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(Register::OFFSET, value); - } - - /****************************************** - ** Access to bitfields within registers ** - ******************************************/ - - /** - * Read the bitfield 'T' of a register - */ - template - 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(Register::OFFSET)); - } - - /** - * Override to the bitfield 'T' of a register - * - * \param value value that shall be written - */ - template - inline void - 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(); - Bitfield::clear(write_value); - } - /* apply bitfield value and override register */ - Bitfield::set(write_value, value); - write(write_value); - } - - - /******************************* - ** Access to register arrays ** - *******************************/ - - /** - * Read an item of the register array 'T' - * - * \param index index of the targeted item - */ - template - 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) { - Array::simple_dst(offset, index); - return _read(offset); - - /* access width and item width differ */ - } else { - long unsigned shift; - Array::dst(offset, shift, index); - return (_read(offset) >> shift) & - Array::ITEM_MASK; - } - } - - /** - * Override an item of the register array 'T' - * - * \param value value that shall be written - * \param index index of the targeted item - */ - template - 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) { - Array::simple_dst(offset, index); - _write(offset, value); - - /* access width and item width differ */ - } else { - long unsigned shift; - Array::dst(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(offset); - write_value &= ~(Array::ITEM_MASK << shift); - } - /* apply bitfield value and override register */ - write_value |= (value & Array::ITEM_MASK) << shift; - _write(offset, write_value); - } - } - - - /***************************************************** - ** Access to bitfields within register array items ** - *****************************************************/ - - /** - * Read the bitfield 'T' of a register array - * - * \param index index of the targeted item - */ - template - 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(index)); - } - - /** - * Override the bitfield 'T' of a register array - * - * \param value value that shall be written - * \param index index of the targeted array item - */ - template - inline void - 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(index); - Bitfield::clear(write_value); - } - /* apply bitfield value and override register */ - Bitfield::set(write_value, value); - write(write_value, index); - } - - - /*********************** - ** Access to bitsets ** - ***********************/ - - /** - * Read bitset 'T' (composed of 2 parts) - */ - template - inline typename T::Bitset_2_base::access_t const read() - { - typedef typename T::Bitset_2_base::Bits_0 Bits_0; - typedef typename T::Bitset_2_base::Bits_1 Bits_1; - typedef typename T::Bitset_2_base::access_t access_t; - enum { V1_SHIFT = Bits_0::BITFIELD_WIDTH }; - access_t const v0 = read(); - access_t const v1 = read(); - return v0 | (v1 << V1_SHIFT); - } - - /** - * Override bitset 'T' (composed of 2 parts) - * - * \param v value that shall be written - */ - template - inline void write(typename T::Bitset_2_base::access_t v) - { - typedef typename T::Bitset_2_base::Bits_0 Bits_0; - typedef typename T::Bitset_2_base::Bits_1 Bits_1; - write(v); - write(v >> Bits_0::BITFIELD_WIDTH); - } - - /** - * Read bitset 'T' (composed of 3 parts) - */ - template - inline typename T::Bitset_3_base::access_t const read() - { - typedef typename T::Bitset_3_base::Bits_0 Bits_0; - typedef typename T::Bitset_3_base::Bits_1 Bits_1; - typedef typename T::Bitset_3_base::Bits_2 Bits_2; - typedef typename T::Bitset_3_base::access_t access_t; - enum { - BITS_0_WIDTH = Bits_0::BITFIELD_WIDTH, - BITS_1_WIDTH = Bits_1::BITFIELD_WIDTH, - V1_SHIFT = BITS_0_WIDTH + BITS_1_WIDTH, - }; - access_t const v0 = read >(); - access_t const v1 = read(); - return v0 | (v1 << V1_SHIFT); - } - - /** - * Override bitset 'T' (composed of 3 parts) - * - * \param v value that shall be written - */ - template - inline void write(typename T::Bitset_3_base::access_t v) - { - typedef typename T::Bitset_3_base::Bits_0 Bits_0; - typedef typename T::Bitset_3_base::Bits_1 Bits_1; - typedef typename T::Bitset_3_base::Bits_2 Bits_2; - write >(v); - write(v >> (Bits_0::BITFIELD_WIDTH + - Bits_1::BITFIELD_WIDTH)); - } - - - /********************************* - ** Polling for bitfield states ** - *********************************/ - - /** - * Interface for delaying the execution of a calling thread - */ - struct Delayer - { - /** - * Delay execution of the caller for 'us' microseconds - */ - virtual void usleep(unsigned us) = 0; - }; - - /** - * Wait until register 'T' contains the specified 'value' - * - * \param value value to wait for - * \param delayer sleeping facility to be used when the - * value is not reached yet - * \param max_attempts number of register probing attempts - * \param us number of microseconds between attempts - */ - template - inline bool - wait_for(typename T::Register_base::access_t const value, - Delayer & delayer, - unsigned max_attempts = 500, - unsigned us = 1000) - { - typedef typename T::Register_base Register; - for (unsigned i = 0; i < max_attempts; i++, delayer.usleep(us)) - { - if (read() == value) return true; - } - return false; - } - - /** - * Wait until bitfield 'T' contains the specified 'value' - * - * \param value value to wait for - * \param delayer sleeping facility to be used when the - * value is not reached yet - * \param max_attempts number of bitfield probing attempts - * \param us number of microseconds between attempts - */ - template - inline bool - 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() == value) return true; - } - return false; - } +/** + * Type-safe, fine-grained access to a continuous MMIO region + * + * For further details refer to the documentation of the 'Register_set' class. + */ +struct Genode::Mmio : Mmio_plain_access, Register_set +{ + /** + * Constructor + * + * \param base base address of targeted MMIO region + */ + Mmio(addr_t const base) + : + Mmio_plain_access(base), + Register_set(*static_cast(this)) { } }; #endif /* _INCLUDE__UTIL__MMIO_H_ */ diff --git a/repos/base/include/util/register_set.h b/repos/base/include/util/register_set.h new file mode 100644 index 0000000000..807cb44212 --- /dev/null +++ b/repos/base/include/util/register_set.h @@ -0,0 +1,798 @@ +/* + * \brief Set of fine-grained and typesafe accessible registers with offsets + * \author Martin stein + * \date 2011-10-26 + */ + +/* + * Copyright (C) 2011-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__UTIL__REGISTER_SET_H_ +#define _INCLUDE__UTIL__REGISTER_SET_H_ + +/* Genode includes */ +#include +#include + +namespace Genode { + + struct Register_set_plain_access; + template class Register_set; +} + + +/** + * Interface declaration for implementations of plain access to a register set + * + * This class enables us to use the bit and offset logic of the Register_set + * template with different plain access implementations and, at the same time, + * keep the plain access implementation invisible at the front-end. The class + * circumvents the fact that we can't have virtual method templates nor + * template friends. The plain access implementation should keep its methods + * private and declare this class as friend. It is then handed over as + * argument to the Register_set template. + */ +struct Genode::Register_set_plain_access +{ + /** + * Write on plain integer level to a register of the set + * + * \param ACCESS_T plain integer type of the register to access + * \param IMPLEMENTATION implementation of access on the plain integer level + * \param impl instance of the access implementation + * \param offset register offset + * \param value value to be written to the register + */ + template + static inline + void write(IMPLEMENTATION &impl, off_t const offset, ACCESS_T const value) { + impl.template _write(offset, value); } + + /** + * Read on plain integer level from a register of the set + * + * \param ACCESS_T plain integer type of the register to access + * \param IMPLEMENTATION implementation of access on the plain integer level + * \param impl instance of the access implementation + * \param offset register offset + * \param value value to be written to the register + */ + template + static inline ACCESS_T read(IMPLEMENTATION &impl, off_t const offset) { + return impl.template _read(offset); } +}; + + +/** + * Set of fine-grained and typesafe accessible registers with offsets + * + * \param PLAIN_ACCESS Implementation of access on the plain integer level. + * Should derive from the Register_set_plain_access + * interface. + * + * A register set consists of individual registers and register arrays with + * different offsets. The class receives the specific implementation of plain + * access as argument. This way, it can be used with different types of IO + * (MMIO, I2C, Port IO, ...) . For correct behavior of the 'Register_set' + * methods, a class that derives from one of the subclasses of 'Register_set' + * must not define members named 'Register_base', 'Bitfield_base', + * 'Register_array_base' or 'Array_bitfield_base'. + */ +template +class Genode::Register_set +{ + private: + + using Plain_access = Register_set_plain_access; + + enum { BYTE_WIDTH_LOG2 = 3, BYTE_WIDTH = 1 << BYTE_WIDTH_LOG2 }; + + /** + * Return wether one IO condition is met + * + * \param CONDITION A condition subtype of Register, Bitfield, or + * such (for example the Bitfield::Equal type) + * \param condition the condition instance + */ + template + inline bool _conditions_met(CONDITION condition) { + return condition.met(read()); } + + /** + * Return wether a list of IO conditions is met + * + * \param CONDITION The type of the head of the condition list. + * A condition subtype of Register, Bitfield, or + * such (for example the Bitfield::Equal type). + * \param CONDITIONS The types of the tail of the condition list. + * condition subtypes of Register, Bitfield, or + * such (for example the Bitfield::Equal type) + * \param head the condition instance + */ + template + inline bool _conditions_met(CONDITION head, CONDITIONS... tail) { + return _conditions_met(head) ? _conditions_met(tail...) : false; } + + /** + * This template equips registers/bitfields with conditions for polling + * + * \param T register/bitfield type that the conditions shall be about + * + * The condition subtypes enable us to poll for a variable amount of + * conditions for different registers/bitfields at once. They are used + * as input to the 'wait_for' template. + */ + template + struct Conditions + { + /** + * Condition that the register/bitfield equals a value + */ + class Equal + { + private: + + typedef typename T::access_t access_t; + + access_t const _reference_val; + + public: + + typedef T Object; + + /** + * Constructor + * + * \param reference_val reference value + */ + explicit Equal(access_t const reference_val) + : _reference_val(reference_val) { } + + /** + * Return whether the condition is met + * + * \param actual_val actual regster/bitfield value + */ + bool met(access_t const actual_val) const { + return _reference_val == actual_val; } + }; + }; + + PLAIN_ACCESS &_plain_access; + + public: + + /** + * An integer like region at a specific place within a register set + * + * \param _OFFSET Offset of the region in the register set + * \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. + * + * For further details See 'Genode::Register'. + */ + template + + struct Register + : + public Genode::Register<_ACCESS_WIDTH>, + public Conditions > + { + enum { + OFFSET = _OFFSET, + ACCESS_WIDTH = _ACCESS_WIDTH, + 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'. + * 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; + + typedef typename Genode::Register<_ACCESS_WIDTH>::access_t + access_t; + + /** + * A region within a register + * + * \param _SHIFT Bit shift of the first bit within the + * compound register. + * \param _WIDTH bit width of the region + * + * For details see 'Genode::Register::Bitfield'. + */ + template + struct Bitfield + : + public Genode::Register:: + template Bitfield<_SHIFT, _WIDTH>, + public Conditions > + { + /* analogous to 'Register_set::Register::Register_base' */ + typedef Bitfield<_SHIFT, _WIDTH> Bitfield_base; + + /* back reference to containing register */ + typedef Register<_OFFSET, _ACCESS_WIDTH, _STRICT_WRITE> + Compound_reg; + + typedef Compound_reg::access_t access_t; + }; + }; + + /** + * An array of successive equally structured regions, called items + * + * \param _OFFSET Offset of the first item in the register set + * \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. + * + * 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 + + struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH, + _STRICT_WRITE> + { + typedef typename Trait::Uint_width<_ACCESS_WIDTH>:: + template Divisor<_ITEM_WIDTH> Item; + + enum { + STRICT_WRITE = _STRICT_WRITE, + OFFSET = _OFFSET, + ACCESS_WIDTH = _ACCESS_WIDTH, + ITEMS = _ITEMS, + ITEM_WIDTH = _ITEM_WIDTH, + ITEM_WIDTH_LOG2 = Item::WIDTH_LOG2, + MAX_INDEX = ITEMS - 1, + ITEM_MASK = (1ULL << ITEM_WIDTH) - 1, + }; + + /* analogous to 'Register_set::Register::Register_base' */ + typedef Register_array + Register_array_base; + + typedef typename Register:: + access_t access_t; + + /** + * A bit region within a register array item + * + * \param _SHIFT bit shift of the first bit within an item + * \param _WIDTH bit width of the region + * + * For details see 'Genode::Register::Bitfield'. + */ + template + struct Bitfield : + public Register:: + template Bitfield<_SHIFT, _SIZE> + { + /* analogous to 'Register_set::Register::Register_base' */ + typedef Bitfield<_SHIFT, _SIZE> Array_bitfield_base; + + /* back reference to containing register array */ + typedef Register_array + Compound_array; + }; + + /** + * Calculate destination of an array-item access + * + * \param offset Gets overridden with the offset of the + * access type instance, that contains the + * access destination + * \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 dst(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(access_t)-1) ); + shift = bit_off - ( offset << BYTE_WIDTH_LOG2 ); + offset += OFFSET; + } + + /** + * Calc destination of a simple array-item access without shift + * + * \param offset gets overridden with the offset of the the + * access destination + * \param index index of the targeted array item + */ + static inline void simple_dst(off_t & offset, + unsigned long const index) + { + offset = (index << ITEM_WIDTH_LOG2) >> BYTE_WIDTH_LOG2; + offset += OFFSET; + } + }; + + /** + * Constructor + * + * \param plain_access implementation of plain register access + */ + Register_set(PLAIN_ACCESS &plain_access) + : _plain_access(plain_access) { } + + + /************************* + ** Access to registers ** + *************************/ + + /** + * Read the register 'T' + */ + template + inline typename T::Register_base::access_t read() const + { + typedef typename T::Register_base Register; + typedef typename Register::access_t access_t; + return Plain_access::read(_plain_access, + Register::OFFSET); + } + + /** + * Override the register 'T' + */ + template + inline void + write(typename T::Register_base::access_t const value) + { + typedef typename T::Register_base Register; + typedef typename Register::access_t access_t; + Plain_access::write(_plain_access, Register::OFFSET, + value); + } + + /****************************************** + ** Access to bitfields within registers ** + ******************************************/ + + /** + * Read the bitfield 'T' of a register + */ + template + 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(Plain_access::read(_plain_access, + Register::OFFSET)); + } + + /** + * Override to the bitfield 'T' of a register + * + * \param value value that shall be written + */ + template + inline void + 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(); + Bitfield::clear(write_value); + } + /* apply bitfield value and override register */ + Bitfield::set(write_value, value); + write(write_value); + } + + + /******************************* + ** Access to register arrays ** + *******************************/ + + /** + * Read an item of the register array 'T' + * + * \param index index of the targeted item + */ + template + 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) { + Array::simple_dst(offset, index); + return Plain_access::read(_plain_access, offset); + + /* access width and item width differ */ + } else { + long unsigned shift; + Array::dst(offset, shift, index); + return (Plain_access::read(_plain_access, offset) + >> shift) & Array::ITEM_MASK; + } + } + + /** + * Override an item of the register array 'T' + * + * \param value value that shall be written + * \param index index of the targeted item + */ + template + 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) { + Array::simple_dst(offset, index); + Plain_access::write(_plain_access, offset, value); + + /* access width and item width differ */ + } else { + long unsigned shift; + Array::dst(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 = Plain_access::read(_plain_access, + offset); + write_value &= ~(Array::ITEM_MASK << shift); + } + /* apply bitfield value and override register */ + write_value |= (value & Array::ITEM_MASK) << shift; + Plain_access::write(_plain_access, offset, + write_value); + } + } + + + /***************************************************** + ** Access to bitfields within register array items ** + *****************************************************/ + + /** + * Read the bitfield 'T' of a register array + * + * \param index index of the targeted item + */ + template + 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(index)); + } + + /** + * Override the bitfield 'T' of a register array + * + * \param value value that shall be written + * \param index index of the targeted array item + */ + template + inline void + 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(index); + Bitfield::clear(write_value); + } + /* apply bitfield value and override register */ + Bitfield::set(write_value, value); + write(write_value, index); + } + + + /*********************** + ** Access to bitsets ** + ***********************/ + + /** + * Read bitset 'T' (composed of 2 parts) + */ + template + inline typename T::Bitset_2_base::access_t const read() + { + typedef typename T::Bitset_2_base::Bits_0 Bits_0; + typedef typename T::Bitset_2_base::Bits_1 Bits_1; + typedef typename T::Bitset_2_base::access_t access_t; + enum { V1_SHIFT = Bits_0::BITFIELD_WIDTH }; + access_t const v0 = read(); + access_t const v1 = read(); + return v0 | (v1 << V1_SHIFT); + } + + /** + * Override bitset 'T' (composed of 2 parts) + * + * \param v value that shall be written + */ + template + inline void write(typename T::Bitset_2_base::access_t v) + { + typedef typename T::Bitset_2_base::Bits_0 Bits_0; + typedef typename T::Bitset_2_base::Bits_1 Bits_1; + write(v); + write(v >> Bits_0::BITFIELD_WIDTH); + } + + /** + * Read bitset 'T' (composed of 3 parts) + */ + template + inline typename T::Bitset_3_base::access_t const read() + { + typedef typename T::Bitset_3_base::Bits_0 Bits_0; + typedef typename T::Bitset_3_base::Bits_1 Bits_1; + typedef typename T::Bitset_3_base::Bits_2 Bits_2; + typedef typename T::Bitset_3_base::access_t access_t; + enum { + BITS_0_WIDTH = Bits_0::BITFIELD_WIDTH, + BITS_1_WIDTH = Bits_1::BITFIELD_WIDTH, + V1_SHIFT = BITS_0_WIDTH + BITS_1_WIDTH, + }; + access_t const v0 = read >(); + access_t const v1 = read(); + return v0 | (v1 << V1_SHIFT); + } + + /** + * Override bitset 'T' (composed of 3 parts) + * + * \param v value that shall be written + */ + template + inline void write(typename T::Bitset_3_base::access_t v) + { + typedef typename T::Bitset_3_base::Bits_0 Bits_0; + typedef typename T::Bitset_3_base::Bits_1 Bits_1; + typedef typename T::Bitset_3_base::Bits_2 Bits_2; + write >(v); + write(v >> (Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH)); + } + + + /********************************* + ** Polling for bitfield states ** + *********************************/ + + struct Polling_timeout : Exception { }; + + struct Attempts + { + unsigned value; + explicit Attempts(unsigned value) : value(value) { } + }; + + struct Microseconds + { + unsigned value; + explicit Microseconds(unsigned value) : value(value) { } + }; + + /** + * Interface for delaying the execution of a calling thread + */ + struct Delayer + { + /** + * Delay execution of the caller for 'us' microseconds + */ + virtual void usleep(unsigned us) = 0; + }; + + + /** + * Wait until a list of IO conditions is met + * + * \param CONDITIONS Types of the of conditions in the condition + * list. Condition subtypes of the IO types. For + * example the Bitfield::Equal type. + * \param attempts maximum number of probing attempts + * \param us number of microseconds between attempts + * \param delayer Sleeping facility to be used when the + * conditions are not met + * \param conditions condition list + * + * \throw Polling_timeout + */ + template + inline void wait_for(Attempts attempts, + Microseconds us, + Delayer &delayer, + CONDITIONS... conditions) + { + for (unsigned i = 0; i < attempts.value; i++, + delayer.usleep(us.value)) + { + if (_conditions_met(conditions...)) { + return; } + } + throw Polling_timeout(); + } + + /** + * Shortcut for 'wait_for' with 'attempts = 500' and 'us = 1000' + */ + template + inline void wait_for(Delayer &delayer, CONDITIONS... conditions) + { + wait_for(Attempts(500), Microseconds(1000), + delayer, conditions...); + } + + /** + * Wait until register 'T' contains the specified 'value' + * + * \param value value to wait for + * \param delayer sleeping facility to be used when the + * value is not reached yet + * \param max_attempts number of register probing attempts + * \param us number of microseconds between attempts + * + * \noapi + * \deprecated use 'template wait_for' + */ + template + inline bool + wait_for(typename T::Register_base::access_t const value, + Delayer & delayer, + unsigned max_attempts = 500, + unsigned us = 1000) __attribute__ ((deprecated)); + + /** + * Wait until bitfield 'T' contains the specified 'value' + * + * \param value value to wait for + * \param delayer sleeping facility to be used when the + * value is not reached yet + * \param max_attempts number of bitfield probing attempts + * \param us number of microseconds between attempts + * + * \noapi + * \deprecated use 'template wait_for' + */ + template + inline bool + wait_for(typename T::Bitfield_base::Compound_reg::access_t const value, + Delayer & delayer, + unsigned max_attempts = 500, + unsigned us = 1000) __attribute__ ((deprecated)); +}; + + +template +template +bool Genode::Register_set:: +wait_for(typename T::Register_base::access_t const value, + Delayer &delayer, + unsigned max_attempts, + unsigned us) +{ + typedef typename T::Register_base Register; + for (unsigned i = 0; i < max_attempts; i++, delayer.usleep(us)) + { + if (read() == value) { + return true; } + } + return false; +} + + +template +template +bool Genode::Register_set:: +wait_for(typename T::Bitfield_base::Compound_reg::access_t const value, + Delayer &delayer, + unsigned max_attempts, + unsigned us) +{ + typedef typename T::Bitfield_base Bitfield; + for (unsigned i = 0; i < max_attempts; i++, delayer.usleep(us)) + { + if (read() == value) { + return true; } + } + return false; +} + + +#endif /* _INCLUDE__UTIL__REGISTER_SET_H_ */