mmio: fix bug in read/write array items

Fix #668
This commit is contained in:
Martin Stein 2013-04-30 13:41:34 +02:00 committed by Norman Feske
parent 89109cf377
commit 028ef7d776
2 changed files with 39 additions and 8 deletions

View File

@ -207,9 +207,9 @@ namespace Genode
* targeted by 'offset'. * targeted by 'offset'.
* \param index index of the targeted array item * \param index index of the targeted array item
*/ */
static inline void access_dest(off_t & offset, static inline void dst(off_t & offset,
unsigned long & shift, unsigned long & shift,
unsigned long const index) unsigned long const index)
{ {
unsigned long const bit_off = index << ITEM_WIDTH_LOG2; unsigned long const bit_off = index << ITEM_WIDTH_LOG2;
offset = (off_t) ((bit_off >> BYTE_WIDTH_LOG2) offset = (off_t) ((bit_off >> BYTE_WIDTH_LOG2)
@ -217,6 +217,20 @@ namespace Genode
shift = bit_off - ( offset << BYTE_WIDTH_LOG2 ); shift = bit_off - ( offset << BYTE_WIDTH_LOG2 );
offset += OFFSET; 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 */ addr_t const base; /* base address of targeted MMIO region */
@ -337,13 +351,13 @@ namespace Genode
/* if item width equals access width we optimize the access */ /* if item width equals access width we optimize the access */
off_t offset; off_t offset;
if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) { if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) {
offset = Array::OFFSET + (index << Array::ITEM_WIDTH_LOG2); Array::simple_dst(offset, index);
return _read<access_t>(offset); return _read<access_t>(offset);
/* access width and item width differ */ /* access width and item width differ */
} else { } else {
long unsigned shift; long unsigned shift;
Array::access_dest(offset, shift, index); Array::dst(offset, shift, index);
return (_read<access_t>(offset) >> shift) & return (_read<access_t>(offset) >> shift) &
Array::ITEM_MASK; Array::ITEM_MASK;
} }
@ -369,14 +383,13 @@ namespace Genode
/* optimize the access if item width equals access width */ /* optimize the access if item width equals access width */
off_t offset; off_t offset;
if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) { if (Array::ITEM_WIDTH == Array::ACCESS_WIDTH) {
offset = Array::OFFSET + Array::simple_dst(offset, index);
(index << Array::ITEM_WIDTH_LOG2);
_write<access_t>(offset, value); _write<access_t>(offset, value);
/* access width and item width differ */ /* access width and item width differ */
} else { } else {
long unsigned shift; long unsigned shift;
Array::access_dest(offset, shift, index); Array::dst(offset, shift, index);
/* insert new value into old register value */ /* insert new value into old register value */
access_t write_value; access_t write_value;

View File

@ -110,6 +110,10 @@ struct Test_mmio : public Mmio
struct B : Bitfield<2,4> { }; struct B : Bitfield<2,4> { };
}; };
struct Simple_array_1 : Register_array<0x0, 32, 2, 32> { };
struct Simple_array_2 : Register_array<0x2, 16, 4, 16> { };
struct Strict_reg : Register<0x0, 32, true> struct Strict_reg : Register<0x0, 32, true>
{ {
struct A : Bitfield<3,2> { }; struct A : Bitfield<3,2> { };
@ -400,6 +404,20 @@ int main()
if (compare_mem(mmio_mem, mmio_cmpr_15, sizeof(mmio_mem))) { if (compare_mem(mmio_mem, mmio_cmpr_15, sizeof(mmio_mem))) {
return test_failed(15); } return test_failed(15); }
/**
* Test 16, writing to simple register array
*/
zero_mem(mmio_mem, sizeof(mmio_mem));
*(uint8_t*)((addr_t)mmio_mem + sizeof(uint16_t)) = 0xaa;
mmio.write<Test_mmio::Simple_array_1>(0x12345678, 0);
mmio.write<Test_mmio::Simple_array_1>(0x87654321, 1);
mmio.write<Test_mmio::Simple_array_2>(0xfedc, 0);
mmio.write<Test_mmio::Simple_array_2>(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); }
printf("Test done\n"); printf("Test done\n");
return 0; return 0;
} }