filename | src/sh4/shadow.c |
changeset | 1198:407659e01ef0 |
prev | 1194:ee6ce5804608 |
next | 1201:5502572ce192 |
author | Nathan Keynes <nkeynes@lxdream.org> |
date | Fri Dec 16 10:08:45 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Add volatile qualifier to return-address frobbing - works around optimizer bug in GCC versions after 4.2 |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * SH4 shadow execution core - runs xlat + emu together and checks that the
5 * results are the same.
6 *
7 * Copyright (c) 2010 Nathan Keynes.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
24 #include "clock.h"
25 #include "mem.h"
26 #include "sh4/sh4.h"
27 #include "sh4/sh4core.h"
28 #include "sh4/sh4trans.h"
29 #include "sh4/mmu.h"
31 #ifdef HAVE_FRAME_ADDRESS
32 static FASTCALL __attribute__((noinline)) void *__first_arg(void *a, void *b) { return a; }
33 #define INIT_EXCEPTIONS(label) goto *__first_arg(&&fnstart,&&label); fnstart:
34 #define EXCEPTION_EXIT(exc) do{ *(((void * volatile *)__builtin_frame_address(0))+1) = exc; } while(0)
35 #else
36 #define INIT_EXCEPTIONS(label)
37 #define EXCEPTION_EXIT() sh4_core_exit(CORE_EXIT_EXCEPTION)
38 #endif
40 typedef enum {
41 READ_LONG,
42 WRITE_LONG,
43 READ_WORD,
44 WRITE_WORD,
45 READ_BYTE,
46 WRITE_BYTE,
47 PREFETCH,
48 READ_BYTE_FOR_WRITE
49 } MemOp;
51 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
52 "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
54 struct mem_log_entry {
55 MemOp op;
56 sh4addr_t addr;
57 uint32_t value;
58 sh4addr_t exception_pc;
59 };
61 static struct sh4_registers shadow_sh4r;
62 static struct mem_region_fn **log_address_space;
63 static struct mem_region_fn **check_address_space;
64 static struct mem_region_fn **real_address_space;
66 #define MEM_LOG_SIZE 4096
67 static struct mem_log_entry *mem_log;
68 static uint32_t mem_log_posn, mem_log_size;
69 static uint32_t mem_check_posn;
71 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
73 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value, int exception )
74 {
75 if( mem_log_posn == mem_log_size ) {
76 struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
77 assert( tmp != NULL );
78 mem_log_size *= 2;
79 mem_log = tmp;
80 }
81 mem_log[mem_log_posn].op = op;
82 mem_log[mem_log_posn].addr = addr;
83 mem_log[mem_log_posn].value = value;
84 if( exception ) {
85 mem_log[mem_log_posn].exception_pc = sh4r.pc;
86 } else {
87 mem_log[mem_log_posn].exception_pc = -1;
88 }
89 mem_log_posn++;
90 }
92 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
93 {
94 if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
95 fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
96 } else {
97 fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
98 }
99 }
101 static void dump_mem_ops()
102 {
103 for( unsigned i=0; i<mem_log_posn; i++ ) {
104 print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
105 }
106 }
108 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value, int *exception )
109 {
110 if( mem_check_posn >= mem_log_posn ) {
111 fprintf( stderr, "Unexpected interpreter memory operation: " );
112 print_mem_op(stderr, op, addr, value );
113 abort();
114 }
115 if( mem_log[mem_check_posn].op != op ||
116 mem_log[mem_check_posn].addr != addr ||
117 (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
118 mem_log[mem_check_posn].value != value ) ) {
119 fprintf(stderr, "Memory operation mismatch. Translator: " );
120 print_mem_op(stderr, mem_log[mem_check_posn].op,
121 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
122 fprintf(stderr, "Emulator: ");
123 print_mem_op(stderr, op, addr, value );
124 abort();
125 }
127 if( mem_log[mem_check_posn].exception_pc != -1 ) {
128 sh4_reraise_exception(mem_log[mem_check_posn].exception_pc);
129 *exception = 1;
130 } else {
131 *exception = 0;
132 }
134 return mem_log[mem_check_posn++].value;
135 }
137 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
138 isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
140 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
141 {
142 gboolean isgood = TRUE;
143 for( unsigned i=0; i<16; i++ ) {
144 if( xsh4r->r[i] != esh4r->r[i] ) {
145 isgood = FALSE;
146 fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
147 }
148 }
149 for( unsigned i=0; i<8; i++ ) {
150 if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
151 isgood = FALSE;
152 fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
153 }
154 }
155 for( unsigned i=0; i<16; i++ ) {
156 if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
157 isgood = FALSE;
158 fprintf( stderr, "FR%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i],
159 *((uint32_t *)&xsh4r->fr[0][i]),
160 esh4r->fr[0][i],
161 *((uint32_t *)&esh4r->fr[0][i])
162 );
163 }
164 }
165 for( unsigned i=0; i<16; i++ ) {
166 if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
167 isgood = FALSE;
168 fprintf( stderr, "XF%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i],
169 *((uint32_t *)&xsh4r->fr[1][i]),
170 esh4r->fr[1][i],
171 *((uint32_t *)&esh4r->fr[1][i])
172 );
173 }
174 }
176 CHECK_REG(t, "T");
177 CHECK_REG(m, "M");
178 CHECK_REG(s, "S");
179 CHECK_REG(q, "Q");
180 CHECK_REG(pc, "PC");
181 CHECK_REG(pr, "PR");
182 CHECK_REG(sr, "SR");
183 CHECK_REG(fpscr, "FPSCR");
184 CHECK_REG(fpul.i, "FPUL");
185 if( xsh4r->mac != esh4r->mac ) {
186 isgood = FALSE;
187 fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
188 }
189 CHECK_REG(gbr, "GBR");
190 CHECK_REG(ssr, "SSR");
191 CHECK_REG(spc, "SPC");
192 CHECK_REG(sgr, "SGR");
193 CHECK_REG(dbr, "DBR");
194 CHECK_REG(vbr, "VBR");
195 CHECK_REG(sh4_state, "STATE");
196 if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
197 isgood = FALSE;
198 fprintf( stderr, "Store queue Xlt =\n" );
199 fwrite_dump( (unsigned char *)xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
200 fprintf( stderr, " Emu =\n" );
201 fwrite_dump( (unsigned char *)esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
202 }
203 return isgood;
204 }
206 static FASTCALL int32_t log_read_long( sh4addr_t addr, void *exc )
207 {
208 INIT_EXCEPTIONS(except);
209 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_long)(addr, &&except);
210 log_mem_op( READ_LONG, addr, rv, 0 );
211 return rv;
212 except:
213 log_mem_op( READ_LONG, addr, rv, 1 );
214 EXCEPTION_EXIT(exc);
215 }
217 static FASTCALL int32_t log_read_word( sh4addr_t addr, void *exc )
218 {
219 INIT_EXCEPTIONS(except);
220 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_word)(addr, &&except);
221 log_mem_op( READ_WORD, addr, rv, 0 );
222 return rv;
223 except:
224 log_mem_op( READ_WORD, addr, rv, 1 );
225 EXCEPTION_EXIT(exc);
226 }
228 static FASTCALL int32_t log_read_byte( sh4addr_t addr, void *exc )
229 {
230 INIT_EXCEPTIONS(except);
231 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_byte)(addr, &&except);
232 log_mem_op( READ_BYTE, addr, rv, 0 );
233 return rv;
234 except:
235 log_mem_op( READ_BYTE, addr, rv, 1 );
236 EXCEPTION_EXIT(exc);
237 }
239 static FASTCALL int32_t log_read_byte_for_write( sh4addr_t addr, void *exc )
240 {
241 INIT_EXCEPTIONS(except);
242 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_byte_for_write)(addr, &&except);
243 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv, 0 );
244 return rv;
245 except:
246 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv, 1 );
247 EXCEPTION_EXIT(exc);
248 }
250 static FASTCALL void log_write_long( sh4addr_t addr, uint32_t val, void *exc )
251 {
252 INIT_EXCEPTIONS(except);
253 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_long)(addr, val, &&except);
254 if( !IS_STORE_QUEUE(addr) )
255 log_mem_op( WRITE_LONG, addr, val, 0 );
256 return;
257 except:
258 if( !IS_STORE_QUEUE(addr) )
259 log_mem_op( WRITE_LONG, addr, val, 1 );
260 EXCEPTION_EXIT(exc);
261 }
263 static FASTCALL void log_write_word( sh4addr_t addr, uint32_t val, void *exc )
264 {
265 INIT_EXCEPTIONS(except);
266 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_word)(addr, val, &&except);
267 if( !IS_STORE_QUEUE(addr) )
268 log_mem_op( WRITE_WORD, addr, val, 0 );
269 return;
270 except:
271 if( !IS_STORE_QUEUE(addr) )
272 log_mem_op( WRITE_WORD, addr, val, 1 );
273 EXCEPTION_EXIT(exc);
274 }
276 static FASTCALL void log_write_byte( sh4addr_t addr, uint32_t val, void *exc )
277 {
278 INIT_EXCEPTIONS(except);
279 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_byte)(addr, val, &&except);
280 if( !IS_STORE_QUEUE(addr) )
281 log_mem_op( WRITE_BYTE, addr, val, 0 );
282 return;
283 except:
284 if( !IS_STORE_QUEUE(addr) )
285 log_mem_op( WRITE_BYTE, addr, val, 1 );
286 EXCEPTION_EXIT(exc);
287 }
289 static FASTCALL void log_prefetch( sh4addr_t addr, void *exc )
290 {
291 INIT_EXCEPTIONS(except);
292 ((mem_prefetch_exc_fn_t)real_address_space[addr>>12]->prefetch)(addr, &&except);
293 log_mem_op( PREFETCH, addr, 0, 0 );
294 return;
295 except:
296 log_mem_op( PREFETCH, addr, 0, 1 );
297 EXCEPTION_EXIT(exc);
298 }
300 static FASTCALL int32_t check_read_long( sh4addr_t addr, void *exc )
301 {
302 int except;
303 int32_t value = check_mem_op( READ_LONG, addr, 0, &except );
304 if( except ) {
305 EXCEPTION_EXIT(exc);
306 }
307 return value;
308 }
310 static FASTCALL int32_t check_read_word( sh4addr_t addr, void *exc )
311 {
312 int except;
313 int32_t value = check_mem_op( READ_WORD, addr, 0, &except );
314 if( except ) {
315 EXCEPTION_EXIT(exc);
316 }
317 return value;
318 }
320 static FASTCALL int32_t check_read_byte( sh4addr_t addr, void *exc )
321 {
322 int except;
323 int32_t value = check_mem_op( READ_BYTE, addr, 0, &except );
324 if( except ) {
325 EXCEPTION_EXIT(exc);
326 }
327 return value;
328 }
330 static FASTCALL int32_t check_read_byte_for_write( sh4addr_t addr, void *exc )
331 {
332 int except;
333 int32_t value = check_mem_op( READ_BYTE_FOR_WRITE, addr, 0, &except );
334 if( except ) {
335 EXCEPTION_EXIT(exc);
336 }
337 return value;
338 }
340 static FASTCALL void check_write_long( sh4addr_t addr, uint32_t value, void *exc )
341 {
342 if( !IS_STORE_QUEUE(addr) ) {
343 int except;
344 check_mem_op( WRITE_LONG, addr, value, &except );
345 if( except ) {
346 EXCEPTION_EXIT(exc);
347 }
348 } else {
349 real_address_space[addr>>12]->write_long(addr, value);
350 }
351 }
353 static FASTCALL void check_write_word( sh4addr_t addr, uint32_t value, void *exc )
354 {
355 if( !IS_STORE_QUEUE(addr) ) {
356 int except;
357 check_mem_op( WRITE_WORD, addr, value, &except );
358 if( except ) {
359 EXCEPTION_EXIT(exc);
360 }
361 } else {
362 real_address_space[addr>>12]->write_word(addr, value);
363 }
364 }
366 static FASTCALL void check_write_byte( sh4addr_t addr, uint32_t value, void *exc )
367 {
368 if( !IS_STORE_QUEUE(addr) ){
369 int except;
370 check_mem_op( WRITE_BYTE, addr, value, &except );
371 if( except ) {
372 EXCEPTION_EXIT(exc);
373 }
374 } else {
375 real_address_space[addr>>12]->write_byte(addr, value);
376 }
377 }
379 static FASTCALL void check_prefetch( sh4addr_t addr, void *exc )
380 {
381 int except;
382 check_mem_op( PREFETCH, addr, 0, &except );
383 if( except ) {
384 EXCEPTION_EXIT(exc);
385 }
386 }
388 struct mem_region_fn log_fns = {
389 (mem_read_fn_t)log_read_long, (mem_write_fn_t)log_write_long,
390 (mem_read_fn_t)log_read_word, (mem_write_fn_t)log_write_word,
391 (mem_read_fn_t)log_read_byte, (mem_write_fn_t)log_write_byte,
392 NULL, NULL, (mem_prefetch_fn_t)log_prefetch, (mem_read_fn_t)log_read_byte_for_write };
394 struct mem_region_fn check_fns = {
395 (mem_read_fn_t)check_read_long, (mem_write_fn_t)check_write_long,
396 (mem_read_fn_t)check_read_word, (mem_write_fn_t)check_write_word,
397 (mem_read_fn_t)check_read_byte, (mem_write_fn_t)check_write_byte,
398 NULL, NULL, (mem_prefetch_fn_t)check_prefetch, (mem_read_fn_t)check_read_byte_for_write };
403 void sh4_shadow_block_begin()
404 {
405 memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
406 mem_log_posn = 0;
407 }
409 void sh4_shadow_block_end()
410 {
411 struct sh4_registers temp_sh4r;
413 /* Save the end registers, and restore the state back to the start */
414 memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
415 memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
417 sh4_address_space = check_address_space;
418 mem_check_posn = 0;
419 sh4r.new_pc = sh4r.pc + 2;
420 while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
421 sh4_execute_instruction();
422 sh4r.slice_cycle += sh4_cpu_period;
423 }
425 if( !check_registers( &temp_sh4r, &sh4r ) ) {
426 fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
427 fprintf( stderr, "Translated block was:\n" );
428 sh4_translate_dump_block(shadow_sh4r.pc);
429 abort();
430 }
431 if( mem_check_posn < mem_log_posn ) {
432 fprintf( stderr, "Additional translator memory operations:\n" );
433 while( mem_check_posn < mem_log_posn ) {
434 print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
435 mem_check_posn++;
436 }
437 abort();
438 }
439 sh4_address_space = real_address_space;
440 }
443 void sh4_shadow_init()
444 {
445 real_address_space = sh4_address_space;
446 log_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
447 check_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
448 for( unsigned i=0; i < (256 * 4096); i++ ) {
449 log_address_space[i] = &log_fns;
450 check_address_space[i] = &check_fns;
451 }
453 mem_log_size = MEM_LOG_SIZE;
454 mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
455 assert( mem_log != NULL );
457 sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
458 sh4_translate_set_fastmem( FALSE );
459 sh4_translate_set_address_space( log_address_space, log_address_space );
460 }
.