filename | src/sh4/shadow.c |
changeset | 1202:01ae5cbad4c8 |
prev | 1201:5502572ce192 |
next | 1217:677b1d85f1b4 |
author | nkeynes |
date | Mon Feb 13 12:26:01 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Add GTK_LIBS to ldadd for testlxpaths, as GLIB_LIBS isn't defined for GTK builds... |
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 #else
35 #define INIT_EXCEPTIONS(label)
36 #endif
38 typedef enum {
39 READ_LONG,
40 WRITE_LONG,
41 READ_WORD,
42 WRITE_WORD,
43 READ_BYTE,
44 WRITE_BYTE,
45 PREFETCH,
46 READ_BYTE_FOR_WRITE
47 } MemOp;
49 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
50 "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
52 struct mem_log_entry {
53 MemOp op;
54 sh4addr_t addr;
55 uint32_t value;
56 sh4addr_t exception_pc;
57 };
59 static struct sh4_registers shadow_sh4r;
60 static struct mem_region_fn **log_address_space;
61 static struct mem_region_fn **check_address_space;
62 static struct mem_region_fn **real_address_space;
64 #define MEM_LOG_SIZE 4096
65 static struct mem_log_entry *mem_log;
66 static uint32_t mem_log_posn, mem_log_size;
67 static uint32_t mem_check_posn;
69 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
71 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value, int exception )
72 {
73 if( mem_log_posn == mem_log_size ) {
74 struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
75 assert( tmp != NULL );
76 mem_log_size *= 2;
77 mem_log = tmp;
78 }
79 mem_log[mem_log_posn].op = op;
80 mem_log[mem_log_posn].addr = addr;
81 mem_log[mem_log_posn].value = value;
82 if( exception ) {
83 mem_log[mem_log_posn].exception_pc = sh4r.pc;
84 } else {
85 mem_log[mem_log_posn].exception_pc = -1;
86 }
87 mem_log_posn++;
88 }
90 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
91 {
92 if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
93 fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
94 } else {
95 fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
96 }
97 }
99 static void dump_mem_ops()
100 {
101 for( unsigned i=0; i<mem_log_posn; i++ ) {
102 print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
103 }
104 }
106 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value, int *exception )
107 {
108 if( mem_check_posn >= mem_log_posn ) {
109 fprintf( stderr, "Unexpected interpreter memory operation: " );
110 print_mem_op(stderr, op, addr, value );
111 abort();
112 }
113 if( mem_log[mem_check_posn].op != op ||
114 mem_log[mem_check_posn].addr != addr ||
115 (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
116 mem_log[mem_check_posn].value != value ) ) {
117 fprintf(stderr, "Memory operation mismatch. Translator: " );
118 print_mem_op(stderr, mem_log[mem_check_posn].op,
119 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
120 fprintf(stderr, "Emulator: ");
121 print_mem_op(stderr, op, addr, value );
122 abort();
123 }
125 if( mem_log[mem_check_posn].exception_pc != -1 ) {
126 sh4_reraise_exception(mem_log[mem_check_posn].exception_pc);
127 *exception = 1;
128 } else {
129 *exception = 0;
130 }
132 return mem_log[mem_check_posn++].value;
133 }
135 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
136 isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
138 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
139 {
140 gboolean isgood = TRUE;
141 for( unsigned i=0; i<16; i++ ) {
142 if( xsh4r->r[i] != esh4r->r[i] ) {
143 isgood = FALSE;
144 fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
145 }
146 }
147 for( unsigned i=0; i<8; i++ ) {
148 if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
149 isgood = FALSE;
150 fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
151 }
152 }
153 for( unsigned i=0; i<16; i++ ) {
154 if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
155 isgood = FALSE;
156 fprintf( stderr, "FR%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i],
157 *((uint32_t *)&xsh4r->fr[0][i]),
158 esh4r->fr[0][i],
159 *((uint32_t *)&esh4r->fr[0][i])
160 );
161 }
162 }
163 for( unsigned i=0; i<16; i++ ) {
164 if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
165 isgood = FALSE;
166 fprintf( stderr, "XF%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i],
167 *((uint32_t *)&xsh4r->fr[1][i]),
168 esh4r->fr[1][i],
169 *((uint32_t *)&esh4r->fr[1][i])
170 );
171 }
172 }
174 CHECK_REG(t, "T");
175 CHECK_REG(m, "M");
176 CHECK_REG(s, "S");
177 CHECK_REG(q, "Q");
178 CHECK_REG(pc, "PC");
179 CHECK_REG(pr, "PR");
180 CHECK_REG(sr, "SR");
181 CHECK_REG(fpscr, "FPSCR");
182 CHECK_REG(fpul.i, "FPUL");
183 if( xsh4r->mac != esh4r->mac ) {
184 isgood = FALSE;
185 fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
186 }
187 CHECK_REG(gbr, "GBR");
188 CHECK_REG(ssr, "SSR");
189 CHECK_REG(spc, "SPC");
190 CHECK_REG(sgr, "SGR");
191 CHECK_REG(dbr, "DBR");
192 CHECK_REG(vbr, "VBR");
193 CHECK_REG(sh4_state, "STATE");
194 if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
195 isgood = FALSE;
196 fprintf( stderr, "Store queue Xlt =\n" );
197 fwrite_dump( (unsigned char *)xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
198 fprintf( stderr, " Emu =\n" );
199 fwrite_dump( (unsigned char *)esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
200 }
201 return isgood;
202 }
204 static FASTCALL int32_t log_read_long( sh4addr_t addr, void *exc )
205 {
206 INIT_EXCEPTIONS(except);
207 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_long)(addr, &&except);
208 log_mem_op( READ_LONG, addr, rv, 0 );
209 return rv;
210 except:
211 log_mem_op( READ_LONG, addr, rv, 1 );
212 SH4_EXCEPTION_EXIT();
213 }
215 static FASTCALL int32_t log_read_word( sh4addr_t addr, void *exc )
216 {
217 INIT_EXCEPTIONS(except);
218 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_word)(addr, &&except);
219 log_mem_op( READ_WORD, addr, rv, 0 );
220 return rv;
221 except:
222 log_mem_op( READ_WORD, addr, rv, 1 );
223 SH4_EXCEPTION_EXIT();
224 }
226 static FASTCALL int32_t log_read_byte( sh4addr_t addr, void *exc )
227 {
228 INIT_EXCEPTIONS(except);
229 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_byte)(addr, &&except);
230 log_mem_op( READ_BYTE, addr, rv, 0 );
231 return rv;
232 except:
233 log_mem_op( READ_BYTE, addr, rv, 1 );
234 SH4_EXCEPTION_EXIT();
235 }
237 static FASTCALL int32_t log_read_byte_for_write( sh4addr_t addr, void *exc )
238 {
239 INIT_EXCEPTIONS(except);
240 int32_t rv = ((mem_read_exc_fn_t)real_address_space[addr>>12]->read_byte_for_write)(addr, &&except);
241 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv, 0 );
242 return rv;
243 except:
244 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv, 1 );
245 SH4_EXCEPTION_EXIT();
246 }
248 static FASTCALL void log_write_long( sh4addr_t addr, uint32_t val, void *exc )
249 {
250 INIT_EXCEPTIONS(except);
251 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_long)(addr, val, &&except);
252 if( !IS_STORE_QUEUE(addr) )
253 log_mem_op( WRITE_LONG, addr, val, 0 );
254 return;
255 except:
256 if( !IS_STORE_QUEUE(addr) )
257 log_mem_op( WRITE_LONG, addr, val, 1 );
258 SH4_EXCEPTION_EXIT();
259 }
261 static FASTCALL void log_write_word( sh4addr_t addr, uint32_t val, void *exc )
262 {
263 INIT_EXCEPTIONS(except);
264 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_word)(addr, val, &&except);
265 if( !IS_STORE_QUEUE(addr) )
266 log_mem_op( WRITE_WORD, addr, val, 0 );
267 return;
268 except:
269 if( !IS_STORE_QUEUE(addr) )
270 log_mem_op( WRITE_WORD, addr, val, 1 );
271 SH4_EXCEPTION_EXIT();
272 }
274 static FASTCALL void log_write_byte( sh4addr_t addr, uint32_t val, void *exc )
275 {
276 INIT_EXCEPTIONS(except);
277 ((mem_write_exc_fn_t)real_address_space[addr>>12]->write_byte)(addr, val, &&except);
278 if( !IS_STORE_QUEUE(addr) )
279 log_mem_op( WRITE_BYTE, addr, val, 0 );
280 return;
281 except:
282 if( !IS_STORE_QUEUE(addr) )
283 log_mem_op( WRITE_BYTE, addr, val, 1 );
284 SH4_EXCEPTION_EXIT();
285 }
287 static FASTCALL void log_prefetch( sh4addr_t addr, void *exc )
288 {
289 INIT_EXCEPTIONS(except);
290 ((mem_prefetch_exc_fn_t)real_address_space[addr>>12]->prefetch)(addr, &&except);
291 log_mem_op( PREFETCH, addr, 0, 0 );
292 return;
293 except:
294 log_mem_op( PREFETCH, addr, 0, 1 );
295 SH4_EXCEPTION_EXIT();
296 }
298 static FASTCALL int32_t check_read_long( sh4addr_t addr, void *exc )
299 {
300 int except;
301 int32_t value = check_mem_op( READ_LONG, addr, 0, &except );
302 if( except ) {
303 SH4_EXCEPTION_EXIT();
304 }
305 return value;
306 }
308 static FASTCALL int32_t check_read_word( sh4addr_t addr, void *exc )
309 {
310 int except;
311 int32_t value = check_mem_op( READ_WORD, addr, 0, &except );
312 if( except ) {
313 SH4_EXCEPTION_EXIT();
314 }
315 return value;
316 }
318 static FASTCALL int32_t check_read_byte( sh4addr_t addr, void *exc )
319 {
320 int except;
321 int32_t value = check_mem_op( READ_BYTE, addr, 0, &except );
322 if( except ) {
323 SH4_EXCEPTION_EXIT();
324 }
325 return value;
326 }
328 static FASTCALL int32_t check_read_byte_for_write( sh4addr_t addr, void *exc )
329 {
330 int except;
331 int32_t value = check_mem_op( READ_BYTE_FOR_WRITE, addr, 0, &except );
332 if( except ) {
333 SH4_EXCEPTION_EXIT();
334 }
335 return value;
336 }
338 static FASTCALL void check_write_long( sh4addr_t addr, uint32_t value, void *exc )
339 {
340 if( !IS_STORE_QUEUE(addr) ) {
341 int except;
342 check_mem_op( WRITE_LONG, addr, value, &except );
343 if( except ) {
344 SH4_EXCEPTION_EXIT();
345 }
346 } else {
347 real_address_space[addr>>12]->write_long(addr, value);
348 }
349 }
351 static FASTCALL void check_write_word( sh4addr_t addr, uint32_t value, void *exc )
352 {
353 if( !IS_STORE_QUEUE(addr) ) {
354 int except;
355 check_mem_op( WRITE_WORD, addr, value, &except );
356 if( except ) {
357 SH4_EXCEPTION_EXIT();
358 }
359 } else {
360 real_address_space[addr>>12]->write_word(addr, value);
361 }
362 }
364 static FASTCALL void check_write_byte( sh4addr_t addr, uint32_t value, void *exc )
365 {
366 if( !IS_STORE_QUEUE(addr) ){
367 int except;
368 check_mem_op( WRITE_BYTE, addr, value, &except );
369 if( except ) {
370 SH4_EXCEPTION_EXIT();
371 }
372 } else {
373 real_address_space[addr>>12]->write_byte(addr, value);
374 }
375 }
377 static FASTCALL void check_prefetch( sh4addr_t addr, void *exc )
378 {
379 int except;
380 check_mem_op( PREFETCH, addr, 0, &except );
381 if( except ) {
382 SH4_EXCEPTION_EXIT();
383 }
384 }
386 struct mem_region_fn log_fns = {
387 (mem_read_fn_t)log_read_long, (mem_write_fn_t)log_write_long,
388 (mem_read_fn_t)log_read_word, (mem_write_fn_t)log_write_word,
389 (mem_read_fn_t)log_read_byte, (mem_write_fn_t)log_write_byte,
390 NULL, NULL, (mem_prefetch_fn_t)log_prefetch, (mem_read_fn_t)log_read_byte_for_write };
392 struct mem_region_fn check_fns = {
393 (mem_read_fn_t)check_read_long, (mem_write_fn_t)check_write_long,
394 (mem_read_fn_t)check_read_word, (mem_write_fn_t)check_write_word,
395 (mem_read_fn_t)check_read_byte, (mem_write_fn_t)check_write_byte,
396 NULL, NULL, (mem_prefetch_fn_t)check_prefetch, (mem_read_fn_t)check_read_byte_for_write };
401 void sh4_shadow_block_begin()
402 {
403 memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
404 mem_log_posn = 0;
405 }
407 void sh4_shadow_block_end()
408 {
409 struct sh4_registers temp_sh4r;
411 /* Save the end registers, and restore the state back to the start */
412 memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
413 memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
415 sh4_address_space = check_address_space;
416 mem_check_posn = 0;
417 sh4r.new_pc = sh4r.pc + 2;
418 while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
419 sh4_execute_instruction();
420 sh4r.slice_cycle += sh4_cpu_period;
421 }
423 if( !check_registers( &temp_sh4r, &sh4r ) ) {
424 fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
425 fprintf( stderr, "Translated block was:\n" );
426 sh4_translate_dump_block(shadow_sh4r.pc);
427 abort();
428 }
429 if( mem_check_posn < mem_log_posn ) {
430 fprintf( stderr, "Additional translator memory operations:\n" );
431 while( mem_check_posn < mem_log_posn ) {
432 print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
433 mem_check_posn++;
434 }
435 abort();
436 }
437 sh4_address_space = real_address_space;
438 }
441 void sh4_shadow_init()
442 {
443 real_address_space = sh4_address_space;
444 log_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
445 check_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
446 for( unsigned i=0; i < (256 * 4096); i++ ) {
447 log_address_space[i] = &log_fns;
448 check_address_space[i] = &check_fns;
449 }
451 mem_log_size = MEM_LOG_SIZE;
452 mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
453 assert( mem_log != NULL );
455 sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
456 sh4_translate_set_fastmem( FALSE );
457 sh4_translate_set_address_space( log_address_space, log_address_space );
458 }
.