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