📄 kcache2.c
字号:
/*=================================================================
//
// kcache2.c
//
// Cache feature/timing tests
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov, based on kcache1.c by dsm
// Contributors: jskov, gthomas
// Date: 1998-12-10
// Description: Tests some of the more exotic cache macros.
//####DESCRIPTIONEND####
*/
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
#include <cyg/kernel/kapi.h>
#include <cyg/infra/testcase.h>
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
#ifdef CYGFUN_KERNEL_API_C
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_cache.h>
// -------------------------------------------------------------------------
#define NTHREADS 1
#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
// The following are defaults for loop variables. Note they will be overriden
// on simulator targets, where detected - there is no point testing a cache
// which doesn't exist :-).
#define TEST_DZERO_LOOPS 5000 // default number of loops for test_dzero()
#define TIME_ILOCK_LOOPS 10000 // default number of loops for time_ilock()
#define TIME_DLOCK_LOOPS 10000 // default number of loops for time_dlock()
// Define this to enable a simple, but hopefully useful, data cache
// test. It may help discover if the cache support has been defined
// properly (in terms of size and shape)
#ifdef HAL_DCACHE_LINE_SIZE
#define _TEST_DCACHE_OPERATION
#endif
static cyg_handle_t thread[NTHREADS];
static cyg_thread thread_obj[NTHREADS];
static char stack[NTHREADS][STACKSIZE];
#define MAXSIZE 1<<18
volatile char m[MAXSIZE];
// -------------------------------------------------------------------------
// Test of data cache zero.
// o Timing comparison with instructions doing the same amount of work.
// o Check that area cleared with the DCACHE_ZERO macro contains zeros.
#ifdef HAL_DCACHE_ZERO
static void test_dzero(void)
{
register cyg_uint32 k, i;
cyg_tick_count_t count0, count1;
cyg_ucount32 t;
volatile cyg_uint32* aligned_p;
volatile cyg_uint32* p;
register CYG_INTERRUPT_STATE oldints;
cyg_ucount32 test_dzero_loops = TEST_DZERO_LOOPS;
CYG_TEST_INFO("Data cache zero");
if (cyg_test_is_simulator)
test_dzero_loops=10;
aligned_p = (volatile cyg_uint32*)
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
& ~(HAL_DCACHE_LINE_SIZE-1));
// Time with conventional instructions.
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
count0 = cyg_current_time();
for (k = 0; k < test_dzero_loops; k++) {
p = aligned_p;
for (i = 0; i < HAL_DCACHE_SETS; i++) {
#if (16 == HAL_DCACHE_LINE_SIZE)
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
#elif (32 == HAL_DCACHE_LINE_SIZE)
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
#else
#error "Not defined for this cache line size."
#endif
}
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
}
count1 = cyg_current_time();
t = count1 - count0;
diag_printf("time with instructions: %d\n", t);
// Initialize the area with non-zero so we can check whether
// the macro cleared the area properly.
p = aligned_p;
for (i = 0;
i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32);
i++) {
*p++ = 0xdeadbeef;
}
// Time with DCACHE_ZERO.
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
count0 = cyg_current_time();
for (k = 0; k < test_dzero_loops; k++) {
HAL_DCACHE_ZERO(aligned_p, HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE);
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
}
count1 = cyg_current_time();
t = count1 - count0;
diag_printf("time with HAL_DCACHE_ZERO: %d\n", t);
// Verify that the area was actually cleared.
{
cyg_uint32 d;
d = 0;
p = aligned_p;
for (i = 0;
i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32);
i++) {
d |= *p++;
}
CYG_TEST_CHECK(0 == d, "region not properly cleared");
}
}
#endif
// -------------------------------------------------------------------------
// Test of data cache write hint.
// Just check that the macro compiles.
#ifdef HAL_DCACHE_WRITE_HINT
static void test_dwrite_hint(void)
{
register cyg_uint32 k;
register CYG_INTERRUPT_STATE oldints;
CYG_TEST_INFO("Data cache write hint");
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
HAL_DCACHE_WRITE_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE);
for (k = 0; k < 20; k++);
m[HAL_DCACHE_LINE_SIZE*2] = 42;
}
#endif
// -------------------------------------------------------------------------
// Test of data cache read hint.
// Just check that the macro compiles.
#ifdef HAL_DCACHE_READ_HINT
static void test_dread_hint(void)
{
register char c;
register cyg_uint32 k;
register CYG_INTERRUPT_STATE oldints;
CYG_TEST_INFO("Data cache read hint");
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
HAL_DCACHE_READ_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE);
for (k = 0; k < 20; k++);
c = m[HAL_DCACHE_LINE_SIZE*2];
}
#endif
// -------------------------------------------------------------------------
// Test of data cache line store
// o No semantic requirement.
// o Check that flushed data is written to memory.
// o Simple invocation check of macro.
#ifdef HAL_DCACHE_STORE
static void test_dstore(void)
{
volatile cyg_uint8* aligned_p;
cyg_int32 i;
register CYG_INTERRUPT_STATE oldints;
CYG_TEST_INFO("Data cache store region");
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
m[i] = 0;
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
aligned_p = (volatile cyg_uint8*)
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
& ~(HAL_DCACHE_LINE_SIZE-1));
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
HAL_DCACHE_STORE(aligned_p, HAL_DCACHE_LINE_SIZE);
CYG_TEST_CHECK(42 == aligned_p[0],
"memory didn't contain flushed data");
HAL_DCACHE_INVALIDATE_ALL(); // Discard...
CYG_TEST_CHECK(42 == aligned_p[0],
"memory didn't contain flushed data after invalidate all");
HAL_RESTORE_INTERRUPTS(oldints);
}
#endif
// -------------------------------------------------------------------------
// Test of data cache total flush (sync).
// o No semantic requirement.
// o Check that flushed data is written to memory.
// o Simple invocation check of macro.
#ifdef HAL_DCACHE_LINE_SIZE // So we can find our way around memory
#ifdef _TEST_DCACHE_OPERATION
static void
test_dcache_operation(void)
{
long *lp = (long *)m;
int i, errs;
cyg_uint32 oldints;
CYG_TEST_INFO("Data cache basic");
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
// Fill test buffer
for (i = 0; i < sizeof(m)/sizeof(*lp); i++) {
lp[i] = i;
}
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
// Now push data through the cache
// Note: 256 seems like a reasonable offset. It may be useful to actually
// compute this (and the size of the test region) based on cache geometry
for (i = 256; i < 256+HAL_DCACHE_SIZE/sizeof(*lp); i++) {
lp[i] = 0xFF000000 + i;
}
// Now force cache clean and off
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
// Verify the data
diag_printf("Verify data with cache off\n");
errs = 0;
for (i = 0; i < sizeof(m)/sizeof(*lp); i++) {
if ((i >= 256) && (i < 256+HAL_DCACHE_SIZE/sizeof(*lp))) {
if (lp[i] != (0xFF000000 + i)) {
if (++errs < 16) {
diag_printf("Data inside test range changed - was: %x, is %x, index: %x\n",
0xFF000000+i, lp[i], i);
}
}
} else {
if (lp[i] != i) {
if (++errs < 16) {
diag_printf("Data outside test range changed - was: %x, is %x, index: %x\n",
i, lp[i], i);
}
}
}
}
CYG_TEST_CHECK(0 == errs, "dcache basic failed");
#if 0 // Additional information
diag_printf("%d total errors during compare\n", errs);
diag_dump_buf(&lp[240], 128);
#endif
HAL_RESTORE_INTERRUPTS(oldints);
}
#endif
static void test_dsync(void)
{
volatile cyg_uint8* aligned_p;
cyg_int32 i;
register CYG_INTERRUPT_STATE oldints;
CYG_TEST_INFO("Data cache sync all");
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
m[i] = 0;
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
aligned_p = (volatile cyg_uint8*)
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
& ~(HAL_DCACHE_LINE_SIZE-1));
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
HAL_DCACHE_SYNC();
CYG_TEST_CHECK(42 == aligned_p[0],
"memory didn't contain flushed data");
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
"memory didn't contain flushed data next block");
HAL_DCACHE_INVALIDATE_ALL();
CYG_TEST_CHECK(42 == aligned_p[0],
"memory didn't contain flushed data after invalidate");
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
"memory didn't contain flushed data next block after invalidate");
HAL_RESTORE_INTERRUPTS(oldints);
HAL_ICACHE_INVALIDATE_ALL();
HAL_DCACHE_DISABLE();
CYG_TEST_CHECK(42 == aligned_p[0],
"memory didn't contain flushed data after disable");
CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
"memory didn't contain flushed data next block after disable");
HAL_DCACHE_ENABLE();
}
#endif // HAL_DCACHE_LINE_SIZE
// -------------------------------------------------------------------------
// Test of data cache line flush.
// o Requires write-back cache.
// o Check that flushed data is written to memory.
// o Simple range check of macro.
#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test:
#ifdef HAL_DCACHE_FLUSH
static void test_dflush(void)
{
volatile cyg_uint8* aligned_p;
cyg_int32 i;
register CYG_INTERRUPT_STATE oldints;
CYG_TEST_INFO("Data cache flush region");
for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
m[i] = 0;
HAL_DISABLE_INTERRUPTS(oldints);
HAL_DCACHE_SYNC();
HAL_DCACHE_DISABLE();
HAL_DCACHE_SYNC();
HAL_DCACHE_INVALIDATE_ALL();
HAL_DCACHE_ENABLE();
HAL_RESTORE_INTERRUPTS(oldints);
aligned_p = (volatile cyg_uint8*)
(((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
& ~(HAL_DCACHE_LINE_SIZE-1));
HAL_DISABLE_INTERRUPTS(oldints);
aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
HAL_DCACHE_FLUSH(aligned_p, HAL_DCACHE_LINE_SIZE);
HAL_DCACHE_DISABLE();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -