⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kcache2.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*=================================================================
//
//        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 + -