Complement test for MMIO framework

The run script 'run/util_mmio.run' runs a test over basic
functionalities of 'Mmio::Register' and 'Mmio::Register::Subreg'. The
test covers the functions 'read' and 'bits', 'set', 'clear' and 'get'.

Inline function in 'Mmio::Register::Subreg' whose definition otherwise
looks ugly.
This commit is contained in:
Martin Stein 2012-01-10 12:56:45 +01:00 committed by Norman Feske
parent 9329b91aca
commit 01bb7536dd
4 changed files with 324 additions and 23 deletions

View File

@ -4,6 +4,13 @@
* \date 2011-10-26
*/
/*
* Copyright (C) 2011-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.
*/
#ifndef _BASE__INCLUDE__UTIL__MMIO_H_
#define _BASE__INCLUDE__UTIL__MMIO_H_
@ -87,8 +94,14 @@ namespace Genode
* Calculate the MMIO-relative offset 'offset' and shift 'shift'
* within the according 'storage_t' value to acces subreg no. 'index'
*/
inline static void access_dest(off_t & offset, unsigned long & shift,
unsigned long const index);
static void access_dest(off_t & offset, unsigned long & shift,
unsigned long const index)
{
unsigned long const bit_off = (index+1) * ITERATION_WIDTH - WIDTH;
offset = (off_t) ((bit_off / STORAGE_WIDTH) * sizeof(STORAGE_T));
shift = bit_off - ( offset << BYTE_EXP );
offset += Compound_reg::OFFSET;
}
};
};
@ -166,20 +179,6 @@ namespace Genode
}
template <Genode::off_t OFFSET, typename STORAGE_T>
template <unsigned long BIT_SHIFT, unsigned long BIT_SIZE, unsigned long SUBREGS>
void
Genode::Mmio::Register<OFFSET, STORAGE_T>::Subreg_array<BIT_SHIFT, BIT_SIZE, SUBREGS>::access_dest(Genode::off_t & offset,
unsigned long & shift,
unsigned long const index)
{
unsigned long const bit_off = (index+1) * ITERATION_WIDTH - WIDTH;
offset = (off_t) ((bit_off / STORAGE_WIDTH) * sizeof(STORAGE_T));
shift = bit_off - ( offset << BYTE_EXP );
offset += Compound_reg::OFFSET;
}
template <typename STORAGE_T>
void Genode::Mmio::_write(off_t const o, STORAGE_T const value)
{

View File

@ -4,6 +4,13 @@
* \date 2011-11-10
*/
/*
* Copyright (C) 2011-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.
*/
#ifndef _BASE__INCLUDE__UTIL__REGISTER_H_
#define _BASE__INCLUDE__UTIL__REGISTER_H_
@ -37,32 +44,34 @@ namespace Genode
typedef Register<storage_t> Compound_reg;
/**
* Get a register value with this subreg set to 'value'
* and the rest left zero
* Get a register value with this subreg set to 'value' and the rest left zero
*
* \detail Useful to combine successive access to multiple subregs
* into one operation
*/
static storage_t bits(storage_t const value) { return (value & MASK) << SHIFT; }
/**
* Get value of this subreg from 'reg'
*/
static storage_t value(storage_t const reg) { return (reg >> SHIFT) & MASK; }
static storage_t get(storage_t const reg) { return (reg >> SHIFT) & MASK; }
/**
* Get registervalue 'reg' with this subreg set to zero
*/
static void clear_bits(storage_t & reg) { reg &= ~(MASK << SHIFT); }
static void clear(storage_t & reg) { reg &= ~(MASK << SHIFT); }
/**
* Get registervalue 'reg' with this subreg set to 'value'
*/
static void set_bits(storage_t & reg, storage_t const value = ~0)
static void set(storage_t & reg, storage_t const value = ~0)
{
clear_bits(reg);
clear(reg);
reg |= (value & MASK) << SHIFT;
};
};
};
}
#endif /* _BASE__INCLUDE__UTIL__CPU_REGISTER_H_ */
#endif /* _BASE__INCLUDE__UTIL__REGISTER_H_ */

35
base/run/util_mmio.run Normal file
View File

@ -0,0 +1,35 @@
build "core init test/util_mmio"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> </any-service>
</default-route>
<start name="test-util_mmio">
<resource name="RAM" quantum="10M"/>
</start>
</config>
}
build_boot_image "core init test-util_mmio"
append qemu_args "-nographic -m 64"
run_genode_until {.*Test ended.*} 10
grep_output {\[init -\> test-util_mmio\]}
compare_output_to {
[init -> test-util_mmio] Test ended successfully
}

View File

@ -1,6 +1,7 @@
/*
* \brief Basic test for MMIO access framework
* \author Christian Helmuth
* \author Martin Stein
* \date 2012-01-09
*/
@ -12,8 +13,265 @@
*/
#include <util/mmio.h>
#include <base/printf.h>
using namespace Genode;
/**
* Assume this one is a cpu register, accessed by special ops
*/
static uint16_t cpu_state;
/**
* Assume this is a MMIO region
*/
enum{ MMIO_SIZE = 8 };
static uint8_t mmio_mem[MMIO_SIZE];
/**
* Exemplary highly structured type for accessing 'cpu_state'
*/
struct Cpu_state : Register<uint16_t>
{
struct Mode : Subreg<0,4>
{
enum {
KERNEL = 0b1000,
USER = 0b1001,
MONITOR = 0b1010,
};
};
struct A : Subreg<6,1> { };
struct B : Subreg<8,1> { };
struct C : Subreg<10,1> { };
struct Irq : Subreg<12,3> { };
struct Invalid_bit : Subreg<18,1> { };
struct Invalid_area : Subreg<15,4> { };
inline static storage_t read() { return cpu_state; }
inline static void write(storage_t & v) { cpu_state = v; }
};
/**
* Exemplary MMIO region type
*/
struct Test_mmio : public Mmio
{
Test_mmio(addr_t const base) : Mmio(base) { }
struct Reg : Register<0x04, uint8_t>
{
struct Bit_1 : Subreg<0,1> { };
struct Area : Subreg<1,3>
{
enum {
VALUE_1 = 3,
VALUE_2 = 4,
VALUE_3 = 5,
};
};
struct Bit_2 : Subreg<4,1> { };
struct Invalid_bit : Subreg<8,1> { };
struct Invalid_area : Subreg<6,8> { };
struct Overlapping_area : Subreg<0,6> { };
};
};
/**
* Print out memory content hexadecimal
*/
void dump_mem(uint8_t * base, size_t size)
{
addr_t top = (addr_t)base + size;
for(; (addr_t)base < top;) {
printf("%2X ", *(uint8_t *)base);
base = (uint8_t *)((addr_t)base + sizeof(uint8_t));
}
}
/**
* Zero-fill memory region
*/
void zero_mem(uint8_t * base, size_t size)
{
addr_t top = (addr_t)base + size;
for(; (addr_t)base < top;) {
*base = 0;
base = (uint8_t *)((addr_t)base + sizeof(uint8_t));
}
}
/**
* Compare content of two memory regions
*/
int compare_mem(uint8_t * base1, uint8_t * base2, size_t size)
{
addr_t top = (addr_t)base1 + size;
for(; (addr_t)base1 < top;) {
if(*base1 != *base2) return -1;
base1 = (uint8_t *)((addr_t)base1 + sizeof(uint8_t));
base2 = (uint8_t *)((addr_t)base2 + sizeof(uint8_t));
}
return 0;
}
/**
* End a failed test
*/
int test_failed(unsigned test_id)
{
PERR("Test ended, test %i failed", test_id);
printf(" mmio_mem: 0x ");
dump_mem(mmio_mem, sizeof(mmio_mem));
printf("\n cpu_state: 0x%4X\n", cpu_state);
return -1;
}
int main()
{
/**********************************
** Genode::Mmio::Register tests **
**********************************/
/**
* Init fake MMIO
*/
Test_mmio mmio((addr_t)&mmio_mem[0]);
/**
* Test 1, read/write whole reg, use 'Subreg::bits' with overflowing values
*/
zero_mem(mmio_mem, sizeof(mmio_mem));
mmio.write<Test_mmio::Reg>(Test_mmio::Reg::Bit_1::bits(7) |
Test_mmio::Reg::Area::bits(10) |
Test_mmio::Reg::Bit_2::bits(9) );
static uint8_t mmio_cmpr_1[MMIO_SIZE] = {0,0,0,0,0b00010101,0,0,0};
if (compare_mem(mmio_mem, mmio_cmpr_1, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg>() != 0x15)
{ return test_failed(1); }
/**
* Test 2, read/write bit appropriately
*/
zero_mem(mmio_mem, sizeof(mmio_mem));
mmio.write<Test_mmio::Reg::Bit_1>(1);
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<Test_mmio::Reg::Bit_1>() != 1)
{ return test_failed(2); }
/**
* Test 3, read/write bit overflowing
*/
mmio.write<Test_mmio::Reg::Bit_2>(0xff);
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<Test_mmio::Reg::Bit_2>() != 1)
{ return test_failed(3); }
/**
* Test 4, read/write bitarea appropriately
*/
mmio.write<Test_mmio::Reg::Area>(Test_mmio::Reg::Area::VALUE_3);
static uint8_t mmio_cmpr_4[MMIO_SIZE] = {0,0,0,0,0b00011011,0,0,0};
if (compare_mem(mmio_mem, mmio_cmpr_4, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg::Area>() != Test_mmio::Reg::Area::VALUE_3)
{ return test_failed(4); }
/**
* Test 5, read/write bitarea overflowing
*/
zero_mem(mmio_mem, sizeof(mmio_mem));
mmio.write<Test_mmio::Reg::Area>(0b11111101);
static uint8_t mmio_cmpr_5[MMIO_SIZE] = {0,0,0,0,0b00001010,0,0,0};
if (compare_mem(mmio_mem, mmio_cmpr_5, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg::Area>() != 0b101)
{ return test_failed(5); }
/**
* Test 6, read/write bit out of regrange
*/
mmio.write<Test_mmio::Reg::Invalid_bit>(1);
if (compare_mem(mmio_mem, mmio_cmpr_5, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg::Invalid_bit>() != 0)
{ return test_failed(6); }
/**
* Test 7, read/write bitarea that exceeds regrange
*/
mmio.write<Test_mmio::Reg::Invalid_area>(0xff);
static uint8_t mmio_cmpr_7[MMIO_SIZE] = {0,0,0,0,0b11001010,0,0,0};
if (compare_mem(mmio_mem, mmio_cmpr_7, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg::Invalid_area>() != 0b11)
{ return test_failed(7); }
/**
* Test 8, read/write bitarea that overlaps other subregs
*/
mmio.write<Test_mmio::Reg::Overlapping_area>(0b00110011);
static uint8_t mmio_cmpr_8[MMIO_SIZE] = {0,0,0,0,0b11110011,0,0,0};
if (compare_mem(mmio_mem, mmio_cmpr_8, sizeof(mmio_mem)) ||
mmio.read<Test_mmio::Reg::Overlapping_area>() != 0b110011)
{ return test_failed(8); }
/****************************
** Genode::Register tests **
****************************/
/**
* Test 9, read/write subregs appropriately, overflowing and out of range
*/
Cpu_state::storage_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);
Cpu_state::C::set(state, 0xdddd);
Cpu_state::Irq::set(state, 0xdddd);
Cpu_state::Invalid_bit::set(state, 0xdddd);
Cpu_state::Invalid_area::set(state, 0xdddd);
Cpu_state::write(state);
state = Cpu_state::read();
if (cpu_state != 0b1101010101001010
|| Cpu_state::Mode::get(state) != Cpu_state::Mode::MONITOR
|| Cpu_state::A::get(state) != 1
|| Cpu_state::B::get(state) != 1
|| Cpu_state::C::get(state) != 1
|| Cpu_state::Irq::get(state) != 0b101
|| Cpu_state::Invalid_bit::get(state) != 0
|| Cpu_state::Invalid_area::get(state) != 1)
{ return test_failed(9); }
/**
* Test 10, clear subregs
*/
Cpu_state::B::clear(state);
Cpu_state::Irq::clear(state);
Cpu_state::write(state);
state = Cpu_state::read();
if (cpu_state != 0b1000010001001010
|| Cpu_state::B::get(state) != 0
|| Cpu_state::Irq::get(state) != 0)
{ return test_failed(10); }
printf("Test ended successfully\n");
return 0;
}