From 4b90cba132b52767eed09cb4a947fa6ca2fef7ab Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 24 May 2012 11:56:54 +0200 Subject: [PATCH] Boolean fields and strict write on Registers/MMIO --- base/include/util/mmio.h | 201 +++++++++++++++--------------- base/include/util/register.h | 22 +++- base/src/test/util_mmio/main.cc | 74 +++++++++-- base/src/test/util_mmio/target.mk | 16 ++- 4 files changed, 191 insertions(+), 122 deletions(-) diff --git a/base/include/util/mmio.h b/base/include/util/mmio.h index 05ddfbd6d..458713cf2 100644 --- a/base/include/util/mmio.h +++ b/base/include/util/mmio.h @@ -14,6 +14,7 @@ #ifndef _BASE__INCLUDE__UTIL__MMIO_H_ #define _BASE__INCLUDE__UTIL__MMIO_H_ +/* Genode includes */ #include namespace Genode @@ -29,13 +30,15 @@ namespace Genode * Write typed 'value' to MMIO base + 'o' */ template - inline void _write(off_t const o, _ACCESS_T const 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; + inline _ACCESS_T _read(off_t const o) const { + return *(_ACCESS_T volatile *)((addr_t)base + o); } public: @@ -44,19 +47,29 @@ 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 _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' */ - template + template struct Register : public Genode::Register<_ACCESS_WIDTH> { enum { OFFSET = _OFFSET, ACCESS_WIDTH = _ACCESS_WIDTH, + STRICT_WRITE = _STRICT_WRITE, }; /** @@ -72,10 +85,8 @@ namespace Genode struct Bitfield : public Genode::Register::template Bitfield<_SHIFT, _WIDTH> { - /** - * Back reference to containing register - */ - typedef Register Compound_reg; + /* Back reference to containing register */ + typedef Register Compound_reg; }; }; @@ -89,6 +100,16 @@ namespace Genode * \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. * * \detail The array takes all inner structures, wich are covered * by an item width and iterates them successive. Such @@ -103,14 +124,18 @@ namespace Genode * effect */ template - struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH> + unsigned long _ITEMS, unsigned long _ITEM_WIDTH, + bool _STRICT_WRITE = false> + + struct Register_array : public Register<_OFFSET, _ACCESS_WIDTH, + _STRICT_WRITE> { typedef typename Trait::Uint_type<_ACCESS_WIDTH>::template Divisor<_ITEM_WIDTH> Item; enum { + STRICT_WRITE = _STRICT_WRITE, OFFSET = _OFFSET, ACCESS_WIDTH = _ACCESS_WIDTH, ITEMS = _ITEMS, @@ -121,7 +146,8 @@ namespace Genode ITEM_MASK = (1 << ITEM_WIDTH) - 1, }; - typedef typename Register::access_t + typedef + typename Register::access_t access_t; /** @@ -134,12 +160,11 @@ namespace Genode */ template struct Bitfield : - public Register::template Bitfield<_SHIFT, _SIZE> + public Register::template Bitfield<_SHIFT, _SIZE> { - /** - * Back reference to containing register array - */ - typedef Register_array + /* Back reference to containing register array */ + typedef Register_array Compound_array; }; @@ -183,19 +208,23 @@ namespace Genode * Typed address of register 'REGISTER' */ template - inline typename REGISTER::access_t volatile * typed_addr() const; + inline typename REGISTER::access_t volatile * typed_addr() const { + return (typename REGISTER::access_t volatile *) + base + REGISTER::OFFSET; } /** * Read the whole register 'REGISTER' */ template - inline typename REGISTER::access_t read() const; + inline typename REGISTER::access_t read() const { + return _read(REGISTER::OFFSET); } /** * Write 'value' to the register 'REGISTER' */ template - inline void write(typename REGISTER::access_t const value); + inline void write(typename REGISTER::access_t const value) { + _write(REGISTER::OFFSET, value); } /****************************************** @@ -259,46 +288,6 @@ namespace Genode } -template -void Genode::Mmio::_write(off_t const o, ACCESS_T const value) -{ - *(ACCESS_T volatile *)((addr_t)base + o) = value; -} - - -template -ACCESS_T Genode::Mmio::_read(off_t const o) const -{ - return *(ACCESS_T volatile *)((addr_t)base + o); -} - - -/************************* - ** Access to registers ** - *************************/ - - -template -typename REGISTER::access_t volatile * Genode::Mmio::typed_addr() const -{ - return (typename REGISTER::access_t volatile *)base + REGISTER::OFFSET; -} - - -template -typename REGISTER::access_t Genode::Mmio::read() const -{ - return _read(REGISTER::OFFSET); -} - - -template -void Genode::Mmio::write(typename REGISTER::access_t const value) -{ - _write(REGISTER::OFFSET, value); -} - - /****************************************** ** Access to bitfields within registers ** ******************************************/ @@ -309,7 +298,6 @@ 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)); } @@ -317,14 +305,22 @@ typename BITFIELD::Compound_reg::access_t Genode::Mmio::read() const 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; - typedef typename Register::access_t access_t; + 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 { - access_t new_reg = read(); - BITFIELD::clear(new_reg); - BITFIELD::set(new_reg, value); - - write(new_reg); + /* 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); } @@ -337,24 +333,18 @@ template typename REGISTER_ARRAY::access_t Genode::Mmio::read(unsigned long const index) const { - /** - * Handle array overflow - */ + /* 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; - - /** - * Optimize access if item width equals access width - */ 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) @@ -368,37 +358,36 @@ template void Genode::Mmio::write(typename REGISTER_ARRAY::access_t const value, unsigned long const index) { - /** - * Avoid array overflow - */ + /* 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; - - /** - * Optimize access if item width equals access width - */ 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 new_reg = - _read(offset); + /* 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 { - new_reg &= ~(REGISTER_ARRAY::ITEM_MASK << shift); - new_reg |= (value & REGISTER_ARRAY::ITEM_MASK) << shift; - - _write(offset, new_reg); + /* 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); } } @@ -413,13 +402,22 @@ 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 { - typename Register_array::access_t new_reg = read(index); - ARRAY_BITFIELD::clear(new_reg); - ARRAY_BITFIELD::set(new_reg, value); - - write(new_reg, index); + /* 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); } @@ -429,7 +427,6 @@ 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)); } diff --git a/base/include/util/register.h b/base/include/util/register.h index 1490662bd..6f5d64e3c 100644 --- a/base/include/util/register.h +++ b/base/include/util/register.h @@ -30,10 +30,10 @@ namespace Genode ** base of 2 for all supported widths in 'Uint_type' ** ***************************************************************/ - template <> struct Uint_type<8> + template <> struct Uint_type<1> { - typedef uint8_t Type; - enum { WIDTH_LOG2 = 3 }; + typedef bool Type; + enum { WIDTH_LOG2 = 0 }; /** * Access widths, wich are dividers to the compound type width @@ -41,6 +41,12 @@ namespace Genode template struct Divisor; }; + template <> struct Uint_type<8> : Uint_type<1> + { + typedef uint8_t Type; + enum { WIDTH_LOG2 = 3 }; + }; + template <> struct Uint_type<16> : Uint_type<8> { typedef uint16_t Type; @@ -65,7 +71,7 @@ namespace Genode ** access widths in 'Uint_type::Divisor' ** ********************************************************************/ - template <> struct Uint_type<8>::Divisor<1> { enum { WIDTH_LOG2 = 0 }; }; + template <> struct Uint_type<1>::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 }; }; @@ -137,6 +143,14 @@ namespace Genode static inline access_t bits(access_t const value) { return (value & MASK) << SHIFT; } + /** + * 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' + */ + static inline access_t masked(access_t const reg) { return reg & REG_MASK; } + /** * Get value of this bitfield from 'reg' */ diff --git a/base/src/test/util_mmio/main.cc b/base/src/test/util_mmio/main.cc index 28f7f89b8..0b86c67b7 100644 --- a/base/src/test/util_mmio/main.cc +++ b/base/src/test/util_mmio/main.cc @@ -1,17 +1,17 @@ /* - * \brief Basic test for MMIO access framework - * \author Christian Helmuth + * \brief Diversified test of the Register and MMIO framework * \author Martin Stein * \date 2012-01-09 */ /* - * Copyright (C) 2011-2012 Genode Labs GmbH + * Copyright (C) 2012 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ #include #include @@ -26,7 +26,7 @@ static uint16_t cpu_state; * Assume this is a MMIO region */ enum{ MMIO_SIZE = 8 }; -static uint8_t mmio_mem[MMIO_SIZE]; +static uint8_t mmio_mem[MMIO_SIZE]; /** * Exemplary highly structured type for accessing 'cpu_state' @@ -68,11 +68,11 @@ struct Test_mmio : public Mmio Test_mmio(addr_t const base) : Mmio(base) { } struct Reg : Register<0x04, 8> - { + { struct Bit_1 : Bitfield<0,1> { }; struct Area : Bitfield<1,3> { - enum { + enum { VALUE_1 = 3, VALUE_2 = 4, VALUE_3 = 5, @@ -91,16 +91,28 @@ struct Test_mmio : public Mmio struct C : Bitfield<3,1> { }; struct D : Bitfield<1,3> { }; }; + + struct Strict_array : Register_array<0x0, 16, 10, 4, true> + { + struct A : Bitfield<1,1> { }; + struct B : Bitfield<2,4> { }; + }; + + struct Strict_reg : Register<0x0, 32, true> + { + struct A : Bitfield<3,2> { }; + struct B : Bitfield<30,4> { }; + }; }; /** * Print out memory content hexadecimal */ -void dump_mem(uint8_t * base, size_t size) +void dump_mem(uint8_t * base, size_t size) { addr_t top = (addr_t)base + size; - for(; (addr_t)base < top;) { + for(; (addr_t)base < top;) { printf("%2X ", *(uint8_t *)base); base = (uint8_t *)((addr_t)base + sizeof(uint8_t)); } @@ -110,10 +122,10 @@ void dump_mem(uint8_t * base, size_t size) /** * Zero-fill memory region */ -void zero_mem(uint8_t * base, size_t size) +void zero_mem(uint8_t * base, size_t size) { addr_t top = (addr_t)base + size; - for(; (addr_t)base < top;) { + for(; (addr_t)base < top;) { *base = 0; base = (uint8_t *)((addr_t)base + sizeof(uint8_t)); } @@ -180,7 +192,7 @@ int main() static uint8_t mmio_cmpr_2[MMIO_SIZE] = {0,0,0,0,0b00000001,0,0,0}; if (compare_mem(mmio_mem, mmio_cmpr_2, sizeof(mmio_mem)) || - mmio.read() != 1) + mmio.read() != 1) { return test_failed(2); } /** @@ -190,7 +202,7 @@ int main() static uint8_t mmio_cmpr_3[MMIO_SIZE] = {0,0,0,0,0b00010001,0,0,0}; if (compare_mem(mmio_mem, mmio_cmpr_3, sizeof(mmio_mem)) || - mmio.read() != 1) + mmio.read() != 1) { return test_failed(3); } /** @@ -291,7 +303,7 @@ int main() ******************************************/ /** - * Test 11, read/write register array items with array- and item overflows + * Test 11, read/write register array items with array- and item overflows */ zero_mem(mmio_mem, sizeof(mmio_mem)); mmio.write(0xa, 0); @@ -339,6 +351,42 @@ int main() mmio.read(11) != 0 ) { return test_failed(12); } + /** + * Test 13, writing to registers with 'STRICT_WRITE' set + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + *(uint8_t*)((addr_t)mmio_mem + sizeof(uint32_t)) = 0xaa; + mmio.write(0xff); + mmio.write(0xff); + static uint8_t mmio_cmpr_13[MMIO_SIZE] = {0,0,0,0b11000000,0b10101010,0,0,0}; + if (compare_mem(mmio_mem, mmio_cmpr_13, sizeof(mmio_mem))) { + return test_failed(13); } + + /** + * Test 14, writing to register array items with 'STRICT_WRITE' set + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + *(uint8_t*)((addr_t)mmio_mem + sizeof(uint16_t)) = 0xaa; + mmio.write(0b1010, 0); + mmio.write(0b1010, 1); + mmio.write(0b1010, 2); + mmio.write(0b1100, 3); + mmio.write(0b110011, 3); + static uint8_t mmio_cmpr_14[MMIO_SIZE] = {0,0b00110000,0b10101010,0,0,0,0,0}; + if (compare_mem(mmio_mem, mmio_cmpr_14, sizeof(mmio_mem))) { + return test_failed(14); } + + /** + * Test 15, writing to register array bitfields with 'STRICT_WRITE' set + */ + zero_mem(mmio_mem, sizeof(mmio_mem)); + *(uint8_t*)((addr_t)mmio_mem + sizeof(uint16_t)) = 0xaa; + mmio.write(0xff, 3); + mmio.write(0xff, 3); + static uint8_t mmio_cmpr_15[MMIO_SIZE] = {0,0b11000000,0b10101010,0,0,0,0,0}; + if (compare_mem(mmio_mem, mmio_cmpr_15, sizeof(mmio_mem))) { + return test_failed(15); } + printf("Test ended successfully\n"); return 0; } diff --git a/base/src/test/util_mmio/target.mk b/base/src/test/util_mmio/target.mk index 42246e1da..2bbb0a9da 100644 --- a/base/src/test/util_mmio/target.mk +++ b/base/src/test/util_mmio/target.mk @@ -1,4 +1,14 @@ -TARGET = test-util_mmio -SRC_CC = main.cc +# +# \brief Diversified test of the Register and MMIO framework +# \author Martin Stein +# \date 2012-04-25 +# -LIBS = cxx env +# Set program name +TARGET = test-util_mmio + +# Add C++ sources +SRC_CC += main.cc + +# Add libraries +LIBS += cxx env thread