1 /* Copyright (C) 2009 Free Software Foundation, Inc.
2 
3    This file is free software; you can redistribute it and/or modify it under
4    the terms of the GNU General Public License as published by the Free
5    Software Foundation; either version 3 of the License, or (at your option)
6    any later version.
7 
8    This file is distributed in the hope that it will be useful, but WITHOUT
9    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11    for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this file; see the file COPYING3.  If not see
15    <http://www.gnu.org/licenses/>.  */
16 
17 /* { dg-do run } */
18 /* { dg-require-effective-target "ealib" } */
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ea.h>
23 #include <spu_cache.h>
24 
25 #ifdef __EA64__
26 #define addr unsigned long long
27 #else
28 #define addr unsigned long
29 #endif
30 
31 static __ea void *bigblock;
32 static __ea void *block;
33 static int *ls_block;
34 
35 extern char __cache_tag_array_size[];
36 #define CACHE_SIZE (4 * (int) &__cache_tag_array_size[0])
37 #define LINE_SIZE ((addr)128)
38 
39 void
init_mem(void)40 init_mem (void)
41 {
42   bigblock = malloc_ea (CACHE_SIZE + 2 * LINE_SIZE);
43   block = malloc_ea (2 * LINE_SIZE);
44   ls_block = malloc (LINE_SIZE);
45 
46   memset_ea (bigblock, 0, CACHE_SIZE + 2 * LINE_SIZE);
47   memset_ea (block, -1, 2 * LINE_SIZE);
48   memset (ls_block, -1, LINE_SIZE);
49   cache_flush ();
50 }
51 
52 /* Test 1: Simple cache fetching.  */
53 void
test1(void)54 test1 (void)
55 {
56   addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
57   int *p1 = NULL;
58   int *p2 = NULL;
59   int i = 0;
60 
61   /* First, check if the same addr give the same cache ptr.  */
62   p1 = cache_fetch ((__ea void *) aligned);
63   p2 = cache_fetch ((__ea void *) aligned);
64 
65   if (p1 != p2)
66     abort ();
67 
68   /* Check that the data actually is in the cache. */
69   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
70     {
71       if (p1[i] != -1)
72 	abort ();
73     }
74 
75   /* Check returning within the cache line. */
76   p2 = cache_fetch ((__ea void *) (aligned + sizeof (int)));
77 
78   if (p2 - p1 != 1)
79     abort ();
80 
81   /* Finally, check that fetching an LS pointer returns that pointer.  */
82   p1 = cache_fetch ((__ea char *) ls_block);
83   if (p1 != ls_block)
84     abort ();
85 }
86 
87 /* Test 2: Eviction testing. */
88 void
test2(void)89 test2 (void)
90 {
91   addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE);
92   int *p = NULL;
93   int i = 0;
94 
95   /* First check that clean evictions don't write back.  */
96   p = cache_fetch ((__ea void *) aligned);
97   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
98     p[i] = 0;
99 
100   cache_evict ((__ea void *) aligned);
101   memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
102 
103   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
104     {
105       if (ls_block[i] == 0)
106 	abort ();
107     }
108 
109   /* Now check that dirty evictions do write back.  */
110   p = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
111   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
112     p[i] = 0;
113 
114   cache_evict ((__ea void *) aligned);
115   memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
116 
117   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
118     {
119       if (ls_block[i] != 0)
120 	abort ();
121     }
122 
123   /* Finally, check that non-atomic writeback only writes dirty bytes.  */
124 
125   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
126     {
127       p = cache_fetch_dirty ((__ea void *) (aligned + i * sizeof (int)),
128 			     (i % 2) * sizeof (int));
129       p[0] = -1;
130     }
131 
132   cache_evict ((__ea void *) aligned);
133   memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE);
134 
135   for (i = 0; i < LINE_SIZE / sizeof (int); i++)
136     {
137       if ((ls_block[i] == -1) && (i % 2 == 0))
138 	abort ();
139       if ((ls_block[i] == 0) && (i % 2 == 1))
140 	abort ();
141     }
142 }
143 
144 /* Test LS forced-eviction. */
145 void
test3(void)146 test3 (void)
147 {
148   addr aligned = ((((addr) bigblock) + LINE_SIZE - 1) & -LINE_SIZE);
149   char *test = NULL;
150   char *ls = NULL;
151   int i = 0;
152 
153   /* Init memory, fill the cache to capacity.  */
154   ls = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE);
155   for (i = 1; i < (CACHE_SIZE / LINE_SIZE); i++)
156     cache_fetch_dirty ((__ea void *) (aligned + i * LINE_SIZE), LINE_SIZE);
157 
158   memset (ls, -1, LINE_SIZE);
159   test = cache_fetch ((__ea void *) (aligned + CACHE_SIZE));
160 
161   /* test == ls indicates cache collision.  */
162   if (test != ls)
163     abort ();
164 
165   /* Make sure it actually wrote the cache line.  */
166   for (i = 0; i < LINE_SIZE; i++)
167     {
168       if (ls[i] != 0)
169 	abort ();
170     }
171 
172   ls = cache_fetch ((__ea void *) aligned);
173 
174   /* test != ls indicates another entry was evicted.  */
175   if (test == ls)
176     abort ();
177 
178   /* Make sure that the previous eviction actually wrote back.  */
179   for (i = 0; i < LINE_SIZE; i++)
180     {
181       if (ls[i] != 0xFF)
182 	abort ();
183     }
184 }
185 
186 int
main(int argc,char ** argv)187 main (int argc, char **argv)
188 {
189   init_mem ();
190   test1 ();
191   test2 ();
192   test3 ();
193 
194   return 0;
195 }
196