mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
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:
parent
9329b91aca
commit
01bb7536dd
@ -4,6 +4,13 @@
|
|||||||
* \date 2011-10-26
|
* \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_
|
#ifndef _BASE__INCLUDE__UTIL__MMIO_H_
|
||||||
#define _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'
|
* Calculate the MMIO-relative offset 'offset' and shift 'shift'
|
||||||
* within the according 'storage_t' value to acces subreg no. 'index'
|
* within the according 'storage_t' value to acces subreg no. 'index'
|
||||||
*/
|
*/
|
||||||
inline static void access_dest(off_t & offset, unsigned long & shift,
|
static void access_dest(off_t & offset, unsigned long & shift,
|
||||||
unsigned long const index);
|
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>
|
template <typename STORAGE_T>
|
||||||
void Genode::Mmio::_write(off_t const o, STORAGE_T const value)
|
void Genode::Mmio::_write(off_t const o, STORAGE_T const value)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,13 @@
|
|||||||
* \date 2011-11-10
|
* \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_
|
#ifndef _BASE__INCLUDE__UTIL__REGISTER_H_
|
||||||
#define _BASE__INCLUDE__UTIL__REGISTER_H_
|
#define _BASE__INCLUDE__UTIL__REGISTER_H_
|
||||||
|
|
||||||
@ -37,32 +44,34 @@ namespace Genode
|
|||||||
typedef Register<storage_t> Compound_reg;
|
typedef Register<storage_t> Compound_reg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a register value with this subreg set to 'value'
|
* Get a register value with this subreg set to 'value' and the rest left zero
|
||||||
* 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; }
|
static storage_t bits(storage_t const value) { return (value & MASK) << SHIFT; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get value of this subreg from 'reg'
|
* 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
|
* 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'
|
* 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;
|
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
35
base/run/util_mmio.run
Normal 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
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Basic test for MMIO access framework
|
* \brief Basic test for MMIO access framework
|
||||||
* \author Christian Helmuth
|
* \author Christian Helmuth
|
||||||
|
* \author Martin Stein
|
||||||
* \date 2012-01-09
|
* \date 2012-01-09
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -12,8 +13,265 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <util/mmio.h>
|
#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()
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user