diff --git a/base/include/util/mmio.h b/base/include/util/mmio.h index c2eafcbc7..da78c410b 100644 --- a/base/include/util/mmio.h +++ b/base/include/util/mmio.h @@ -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 @@ -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 - 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 - 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 + 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'. + * 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 - struct Bitfield : - public Genode::Register::template Bitfield<_SHIFT, _WIDTH> + struct Bitfield : public Genode::Register:: + template Bitfield<_SHIFT, _WIDTH> { - /* Back reference to containing register */ - typedef Register 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 { - 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::access_t - access_t; + /* 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 + * \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 struct Bitfield : - public Register::template Bitfield<_SHIFT, _SIZE> + public Register:: + 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 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 - inline typename REGISTER::access_t volatile * typed_addr() const { - return (typename REGISTER::access_t volatile *) - base + REGISTER::OFFSET; } + 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 whole register 'REGISTER' + * Read the register 'T' */ - template - inline typename REGISTER::access_t read() const { - return _read(REGISTER::OFFSET); } + 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); + } /** - * Write 'value' to the register 'REGISTER' + * Override the register 'T' */ - template - inline void write(typename REGISTER::access_t const value) { - _write(REGISTER::OFFSET, value); } - + 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 'BITFIELD' + * Read the bitfield 'T' of a register */ - template - inline typename BITFIELD::Compound_reg::access_t read() const; + 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)); + } /** - * Write value to the bitfield 'BITFIELD' + * Override to the bitfield 'T' of a register + * + * \param value value that shall be written */ - template + template 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(); + Bitfield::clear(write_value); + } + /* apply bitfield value and override register */ + Bitfield::set(write_value, value); + write(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 - inline typename REGISTER_ARRAY::access_t - read(unsigned long const index) const; + 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) { + offset = Array::OFFSET + (index << Array::ITEM_WIDTH_LOG2); + return _read(offset); + + /* access width and item width differ */ + } else { + long unsigned shift; + Array::access_dest(offset, shift, index); + return (_read(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 - inline void write(typename REGISTER_ARRAY::access_t const value, - unsigned long const index); + 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) { + offset = Array::OFFSET + + (index << Array::ITEM_WIDTH_LOG2); + _write(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(offset); + write_value &= ~(Array::ITEM_MASK << shift); + } + /* apply bitfield value and override register */ + write_value |= (value & Array::ITEM_MASK) << shift; + _write(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 - inline typename ARRAY_BITFIELD::Compound_array::access_t - read(unsigned long const index) const; + 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)); + } /** - * 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 + template 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(index); + Bitfield::clear(write_value); + } + /* apply bitfield value and override register */ + Bitfield::set(write_value, value); + write(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 + template 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() == value) - return true; - + { + if (read() == value) return true; + } return false; } }; } - -/****************************************** - ** Access to bitfields within registers ** - ******************************************/ - - -template -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(Register::OFFSET)); -} - - -template -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(); - BITFIELD::clear(write_value); - } - /* Apply bitfield value and override register */ - BITFIELD::set(write_value, value); - write(write_value); -} - - -/************************************ - ** Access to register array items ** - ************************************/ - - -template -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(offset); - - /* Access width and item width differ */ - } else { - long unsigned shift; - REGISTER_ARRAY::access_dest(offset, shift, index); - return (_read(offset) >> shift) - & REGISTER_ARRAY::ITEM_MASK; - } - -} - - -template -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(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(offset); - write_value &= ~(REGISTER_ARRAY::ITEM_MASK << shift); - } - /* Apply bitfield value and override register */ - write_value |= (value & REGISTER_ARRAY::ITEM_MASK) << shift; - _write(offset, write_value); - } -} - - -/***************************************************** - ** Access to bitfields within register array items ** - *****************************************************/ - - -template -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(index); - ARRAY_BITFIELD::clear(write_value); - } - /* Apply bitfield value and override register */ - ARRAY_BITFIELD::set(write_value, value); - write(write_value, index); -} - - -template -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(index)); -} - - -#endif /* _BASE__INCLUDE__UTIL__MMIO_H_ */ +#endif /* _INCLUDE__UTIL__MMIO_H_ */ diff --git a/base/include/util/register.h b/base/include/util/register.h index 1d5d800b0..0b3221998 100644 --- a/base/include/util/register.h +++ b/base/include/util/register.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 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 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 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_ */ diff --git a/base/src/test/util_mmio/main.cc b/base/src/test/util_mmio/main.cc index 0b86c67b7..c4f7cf621 100644 --- a/base/src/test/util_mmio/main.cc +++ b/base/src/test/util_mmio/main.cc @@ -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> { };