/* Copyright (C) 2009 Free Software Foundation, Inc.
|
/* Copyright (C) 2009 Free Software Foundation, Inc.
|
|
|
This file is free software; you can redistribute it and/or modify it under
|
This file 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
|
the terms of the GNU General Public License as published by the Free
|
Software Foundation; either version 3 of the License, or (at your option)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This file is distributed in the hope that it will be useful, but WITHOUT
|
This file is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
for more details.
|
for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this file; see the file COPYING3. If not see
|
along with this file; see the file COPYING3. If not see
|
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
|
|
/* { dg-do run } */
|
/* { dg-do run } */
|
/* { dg-require-effective-target "ealib" } */
|
/* { dg-require-effective-target "ealib" } */
|
|
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <string.h>
|
#include <ea.h>
|
#include <ea.h>
|
#include <spu_cache.h>
|
#include <spu_cache.h>
|
|
|
#ifdef __EA64__
|
#ifdef __EA64__
|
#define addr unsigned long long
|
#define addr unsigned long long
|
#else
|
#else
|
#define addr unsigned long
|
#define addr unsigned long
|
#endif
|
#endif
|
|
|
static __ea void *bigblock;
|
static __ea void *bigblock;
|
static __ea void *block;
|
static __ea void *block;
|
static int *ls_block;
|
static int *ls_block;
|
|
|
extern char __cache_tag_array_size[];
|
extern char __cache_tag_array_size[];
|
#define CACHE_SIZE (4 * (int) &__cache_tag_array_size[0])
|
#define CACHE_SIZE (4 * (int) &__cache_tag_array_size[0])
|
#define LINE_SIZE ((addr)128)
|
#define LINE_SIZE ((addr)128)
|
|
|
void
|
void
|
init_mem (void)
|
init_mem (void)
|
{
|
{
|
bigblock = malloc_ea (CACHE_SIZE + 2 * LINE_SIZE);
|
bigblock = malloc_ea (CACHE_SIZE + 2 * LINE_SIZE);
|
block = malloc_ea (2 * LINE_SIZE);
|
block = malloc_ea (2 * LINE_SIZE);
|
ls_block = malloc (LINE_SIZE);
|
ls_block = malloc (LINE_SIZE);
|
|
|
memset_ea (bigblock, 0, CACHE_SIZE + 2 * LINE_SIZE);
|
memset_ea (bigblock, 0, CACHE_SIZE + 2 * LINE_SIZE);
|
memset_ea (block, -1, 2 * LINE_SIZE);
|
memset_ea (block, -1, 2 * LINE_SIZE);
|
memset (ls_block, -1, LINE_SIZE);
|
memset (ls_block, -1, LINE_SIZE);
|
cache_flush ();
|
cache_flush ();
|
}
|
}
|
|
|
/* Test 1: Simple cache fetching. */
|
/* Test 1: Simple cache fetching. */
|
void
|
void
|
test1 (void)
|
test1 (void)
|
{
|
{
|
addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
|
addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
|
int *p1 = NULL;
|
int *p1 = NULL;
|
int *p2 = NULL;
|
int *p2 = NULL;
|
int i = 0;
|
int i = 0;
|
|
|
/* First, check if the same addr give the same cache ptr. */
|
/* First, check if the same addr give the same cache ptr. */
|
p1 = cache_fetch ((__ea void *) aligned);
|
p1 = cache_fetch ((__ea void *) aligned);
|
p2 = cache_fetch ((__ea void *) aligned);
|
p2 = cache_fetch ((__ea void *) aligned);
|
|
|
if (p1 != p2)
|
if (p1 != p2)
|
abort ();
|
abort ();
|
|
|
/* Check that the data actually is in the cache. */
|
/* Check that the data actually is in the cache. */
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
{
|
{
|
if (p1[i] != -1)
|
if (p1[i] != -1)
|
abort ();
|
abort ();
|
}
|
}
|
|
|
/* Check returning within the cache line. */
|
/* Check returning within the cache line. */
|
p2 = cache_fetch ((__ea void *) (aligned + sizeof (int)));
|
p2 = cache_fetch ((__ea void *) (aligned + sizeof (int)));
|
|
|
if (p2 - p1 != 1)
|
if (p2 - p1 != 1)
|
abort ();
|
abort ();
|
|
|
/* Finally, check that fetching an LS pointer returns that pointer. */
|
/* Finally, check that fetching an LS pointer returns that pointer. */
|
p1 = cache_fetch ((__ea char *) ls_block);
|
p1 = cache_fetch ((__ea char *) ls_block);
|
if (p1 != ls_block)
|
if (p1 != ls_block)
|
abort ();
|
abort ();
|
}
|
}
|
|
|
/* Test 2: Eviction testing. */
|
/* Test 2: Eviction testing. */
|
void
|
void
|
test2 (void)
|
test2 (void)
|
{
|
{
|
addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
|
addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
|
int *p = NULL;
|
int *p = NULL;
|
int i = 0;
|
int i = 0;
|
|
|
/* First check that clean evictions don't write back. */
|
/* First check that clean evictions don't write back. */
|
p = cache_fetch ((__ea void *) aligned);
|
p = cache_fetch ((__ea void *) aligned);
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
p[i] = 0;
|
p[i] = 0;
|
|
|
cache_evict ((__ea void *) aligned);
|
cache_evict ((__ea void *) aligned);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
|
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
{
|
{
|
if (ls_block[i] == 0)
|
if (ls_block[i] == 0)
|
abort ();
|
abort ();
|
}
|
}
|
|
|
/* Now check that dirty evictions do write back. */
|
/* Now check that dirty evictions do write back. */
|
p = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
|
p = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
p[i] = 0;
|
p[i] = 0;
|
|
|
cache_evict ((__ea void *) aligned);
|
cache_evict ((__ea void *) aligned);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
|
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
{
|
{
|
if (ls_block[i] != 0)
|
if (ls_block[i] != 0)
|
abort ();
|
abort ();
|
}
|
}
|
|
|
/* Finally, check that non-atomic writeback only writes dirty bytes. */
|
/* Finally, check that non-atomic writeback only writes dirty bytes. */
|
|
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
{
|
{
|
p = cache_fetch_dirty ((__ea void *) (aligned + i * sizeof (int)),
|
p = cache_fetch_dirty ((__ea void *) (aligned + i * sizeof (int)),
|
(i % 2) * sizeof (int));
|
(i % 2) * sizeof (int));
|
p[0] = -1;
|
p[0] = -1;
|
}
|
}
|
|
|
cache_evict ((__ea void *) aligned);
|
cache_evict ((__ea void *) aligned);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
|
|
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
for (i = 0; i < LINE_SIZE / sizeof (int); i++)
|
{
|
{
|
if ((ls_block[i] == -1) && (i % 2 == 0))
|
if ((ls_block[i] == -1) && (i % 2 == 0))
|
abort ();
|
abort ();
|
if ((ls_block[i] == 0) && (i % 2 == 1))
|
if ((ls_block[i] == 0) && (i % 2 == 1))
|
abort ();
|
abort ();
|
}
|
}
|
}
|
}
|
|
|
/* Test LS forced-eviction. */
|
/* Test LS forced-eviction. */
|
void
|
void
|
test3 (void)
|
test3 (void)
|
{
|
{
|
addr aligned = ((((addr) bigblock) + LINE_SIZE - 1) & -LINE_SIZE);
|
addr aligned = ((((addr) bigblock) + LINE_SIZE - 1) & -LINE_SIZE);
|
char *test = NULL;
|
char *test = NULL;
|
char *ls = NULL;
|
char *ls = NULL;
|
int i = 0;
|
int i = 0;
|
|
|
/* Init memory, fill the cache to capacity. */
|
/* Init memory, fill the cache to capacity. */
|
ls = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
|
ls = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
|
for (i = 1; i < (CACHE_SIZE / LINE_SIZE); i++)
|
for (i = 1; i < (CACHE_SIZE / LINE_SIZE); i++)
|
cache_fetch_dirty ((__ea void *) (aligned + i * LINE_SIZE), LINE_SIZE);
|
cache_fetch_dirty ((__ea void *) (aligned + i * LINE_SIZE), LINE_SIZE);
|
|
|
memset (ls, -1, LINE_SIZE);
|
memset (ls, -1, LINE_SIZE);
|
test = cache_fetch ((__ea void *) (aligned + CACHE_SIZE));
|
test = cache_fetch ((__ea void *) (aligned + CACHE_SIZE));
|
|
|
/* test == ls indicates cache collision. */
|
/* test == ls indicates cache collision. */
|
if (test != ls)
|
if (test != ls)
|
abort ();
|
abort ();
|
|
|
/* Make sure it actually wrote the cache line. */
|
/* Make sure it actually wrote the cache line. */
|
for (i = 0; i < LINE_SIZE; i++)
|
for (i = 0; i < LINE_SIZE; i++)
|
{
|
{
|
if (ls[i] != 0)
|
if (ls[i] != 0)
|
abort ();
|
abort ();
|
}
|
}
|
|
|
ls = cache_fetch ((__ea void *) aligned);
|
ls = cache_fetch ((__ea void *) aligned);
|
|
|
/* test != ls indicates another entry was evicted. */
|
/* test != ls indicates another entry was evicted. */
|
if (test == ls)
|
if (test == ls)
|
abort ();
|
abort ();
|
|
|
/* Make sure that the previous eviction actually wrote back. */
|
/* Make sure that the previous eviction actually wrote back. */
|
for (i = 0; i < LINE_SIZE; i++)
|
for (i = 0; i < LINE_SIZE; i++)
|
{
|
{
|
if (ls[i] != 0xFF)
|
if (ls[i] != 0xFF)
|
abort ();
|
abort ();
|
}
|
}
|
}
|
}
|
|
|
int
|
int
|
main (int argc, char **argv)
|
main (int argc, char **argv)
|
{
|
{
|
init_mem ();
|
init_mem ();
|
test1 ();
|
test1 ();
|
test2 ();
|
test2 ();
|
test3 ();
|
test3 ();
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|