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