diff --git a/base/include/util/mmio.h b/base/include/util/mmio.h index 793a7dc5a..4bb2d7fde 100644 --- a/base/include/util/mmio.h +++ b/base/include/util/mmio.h @@ -508,6 +508,67 @@ namespace Genode } + /*********************** + ** 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; + return read() | + (read() << Bits_0::BITFIELD_WIDTH); + } + + /** + * 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; + return read >() | + (read() << (Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH)); + } + + /** + * 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 ** *********************************/ diff --git a/base/include/util/register.h b/base/include/util/register.h index 7546024e4..b405c66aa 100644 --- a/base/include/util/register.h +++ b/base/include/util/register.h @@ -20,7 +20,20 @@ namespace Genode { - namespace Trait { + namespace Trait + { + /** + * Round bit width up to an appropriate uint width or 0 if not feasible + */ + template + struct Raise_to_uint_width + { + enum { WIDTH = _WIDTH < 2 ? 1 : + _WIDTH < 9 ? 8 : + _WIDTH < 17 ? 16 : + _WIDTH < 33 ? 32 : + _WIDTH < 65 ? 64 : 0, }; + }; /** * Properties of integer types with a given bitwidth @@ -113,6 +126,7 @@ namespace Genode enum { ACCESS_WIDTH = _ACCESS_WIDTH, ACCESS_WIDTH_LOG2 = Trait::Uint_width::WIDTH_LOG2, + BITFIELD_WIDTH = ACCESS_WIDTH, }; typedef typename Trait::Uint_width::Type access_t; @@ -135,8 +149,9 @@ namespace Genode /** * Fetch template parameters */ - SHIFT = _SHIFT, - WIDTH = _WIDTH, + SHIFT = _SHIFT, + WIDTH = _WIDTH, + BITFIELD_WIDTH = WIDTH, }; /** @@ -198,6 +213,54 @@ namespace Genode }; }; }; + + /** + * Bitfield that is composed of 2 separate parts + * + * \param _BITS_X Register, bitfield or/and bitset types the + * bitset is composed of. The order of arguments + * is also the order of bit significance starting + * with the least. + */ + template + struct Bitset_2 + { + typedef _BITS_0 Bits_0; + typedef _BITS_1 Bits_1; + enum { + WIDTH = Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH, + BITFIELD_WIDTH = WIDTH, + ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH, + }; + typedef typename Trait::Uint_width::Type access_t; + typedef Bitset_2 Bitset_2_base; + }; + + /** + * Bitfield that is composed of 3 separate parts + * + * \param _BITS_X Register, bitfield or/and bitset types the + * bitset is composed of. The order of arguments + * is also the order of bit significance starting + * with the least. + */ + template + struct Bitset_3 + { + typedef _BITS_0 Bits_0; + typedef _BITS_1 Bits_1; + typedef _BITS_2 Bits_2; + enum { + WIDTH = Bits_0::BITFIELD_WIDTH + + Bits_1::BITFIELD_WIDTH + + Bits_2::BITFIELD_WIDTH, + BITFIELD_WIDTH = WIDTH, + ACCESS_WIDTH = Trait::Raise_to_uint_width::WIDTH, + }; + typedef typename Trait::Uint_width::Type access_t; + typedef Bitset_3 Bitset_3_base; + }; } #endif /* _INCLUDE__UTIL__REGISTER_H_ */ diff --git a/base/src/test/util_mmio/main.cc b/base/src/test/util_mmio/main.cc index e17a2a44a..88fb54ddd 100644 --- a/base/src/test/util_mmio/main.cc +++ b/base/src/test/util_mmio/main.cc @@ -119,6 +119,22 @@ struct Test_mmio : public Mmio struct A : Bitfield<3,2> { }; struct B : Bitfield<30,4> { }; }; + + struct Reg_0 : Register<0x1, 8> { }; + + struct Reg_1 : Register<0x2, 16> + { + struct Bits_0 : Bitfield<1, 3> { }; + struct Bits_1 : Bitfield<12, 4> { }; + }; + struct Reg_2 : Register<0x4, 32> + { + struct Bits_0 : Bitfield<4, 5> { }; + struct Bits_1 : Bitfield<17, 12> { }; + }; + struct My_bitset_2 : Bitset_2 { }; + struct My_bitset_3 : Bitset_3 { }; + struct My_bitset_4 : Bitset_2 { }; }; @@ -416,7 +432,40 @@ int main() mmio.write(0xabcd, 2); static uint8_t mmio_cmpr_16[MMIO_SIZE] = {0x78,0x56,0xdc,0xfe,0x21,0x43,0xcd,0xab}; if (compare_mem(mmio_mem, mmio_cmpr_16, sizeof(mmio_mem))) { - return test_failed(16); } + return test_failed(16); } + + /** + * Test 17, write and read a bitset with 2 parts + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + mmio.write(0x1234); + static uint8_t mmio_cmpr_17[MMIO_SIZE] = {0x00,0x46,0x08,0x00,0x00,0x00,0x00,0x00}; + if (compare_mem(mmio_mem, mmio_cmpr_17, sizeof(mmio_mem))) + return test_failed(17); + if (mmio.read() != 0x234) + return test_failed(17); + + /** + * Test 18, write and read a bitset with 3 parts + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + mmio.write(0x12345678); + static uint8_t mmio_cmpr_18[MMIO_SIZE] = {0x00,0x78,0x00,0x00,0x30,0x00,0xac,0x08}; + if (compare_mem(mmio_mem, mmio_cmpr_18, sizeof(mmio_mem))) + return test_failed(18); + if (mmio.read() != 0x345678) + return test_failed(18); + + /** + * Test 19, write and read a nested bitset + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + mmio.write(0x5679); + static uint8_t mmio_cmpr_19[MMIO_SIZE] = {0x00,0xcf,0x02,0x00,0xa0,0x00,0x00,0x00}; + if (compare_mem(mmio_mem, mmio_cmpr_19, sizeof(mmio_mem))) + return test_failed(19); + if (mmio.read() != 0x5679) + return test_failed(19); printf("Test done\n"); return 0;