4 * SH4 shadow execution core - runs xlat + emu together and checks that the
5 * results are the same.
7 * Copyright (c) 2010 Nathan Keynes.
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.
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.
28 #include "sh4/sh4core.h"
29 #include "sh4/sh4trans.h"
43 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
44 "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
46 struct mem_log_entry {
52 static struct sh4_registers shadow_sh4r;
53 static struct mem_region_fn **shadow_address_space;
54 static struct mem_region_fn **p4_address_space;
60 static shadow_mode_t shadow_address_mode = SHADOW_LOG;
62 #define MEM_LOG_SIZE 4096
63 static struct mem_log_entry *mem_log;
64 static uint32_t mem_log_posn, mem_log_size;
65 static uint32_t mem_check_posn;
67 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
69 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
71 if( mem_log_posn == mem_log_size ) {
72 struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
73 assert( tmp != NULL );
77 mem_log[mem_log_posn].op = op;
78 mem_log[mem_log_posn].addr = addr;
79 mem_log[mem_log_posn].value = value;
83 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
85 if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
86 fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
88 fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
92 static void dump_mem_ops()
94 for( unsigned i=0; i<mem_log_posn; i++ ) {
95 print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
99 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
101 if( mem_check_posn >= mem_log_posn ) {
102 fprintf( stderr, "Unexpected interpreter memory operation: " );
103 print_mem_op(stderr, op, addr, value );
106 if( mem_log[mem_check_posn].op != op ||
107 mem_log[mem_check_posn].addr != addr ||
108 (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
109 mem_log[mem_check_posn].value != value ) ) {
110 fprintf(stderr, "Memory operation mismatch. Translator: " );
111 print_mem_op(stderr, mem_log[mem_check_posn].op,
112 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
113 fprintf(stderr, "Emulator: ");
114 print_mem_op(stderr, op, addr, value );
117 return mem_log[mem_check_posn++].value;
120 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
121 isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
123 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
125 gboolean isgood = TRUE;
126 for( unsigned i=0; i<16; i++ ) {
127 if( xsh4r->r[i] != esh4r->r[i] ) {
129 fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
132 for( unsigned i=0; i<8; i++ ) {
133 if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
135 fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
138 for( unsigned i=0; i<16; i++ ) {
139 if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
141 fprintf( stderr, "FR%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i],
142 *((uint32_t *)&xsh4r->fr[0][i]),
144 *((uint32_t *)&esh4r->fr[0][i])
148 for( unsigned i=0; i<16; i++ ) {
149 if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
151 fprintf( stderr, "XF%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i],
152 *((uint32_t *)&xsh4r->fr[1][i]),
154 *((uint32_t *)&esh4r->fr[1][i])
166 CHECK_REG(fpscr, "FPSCR");
167 CHECK_REG(fpul.i, "FPUL");
168 if( xsh4r->mac != esh4r->mac ) {
170 fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
172 CHECK_REG(gbr, "GBR");
173 CHECK_REG(ssr, "SSR");
174 CHECK_REG(spc, "SPC");
175 CHECK_REG(sgr, "SGR");
176 CHECK_REG(dbr, "DBR");
177 CHECK_REG(vbr, "VBR");
178 CHECK_REG(sh4_state, "STATE");
179 if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
181 fprintf( stderr, "Store queue Xlt =\n" );
182 fwrite_dump( (unsigned char *)xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
183 fprintf( stderr, " Emu =\n" );
184 fwrite_dump( (unsigned char *)esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
189 static mem_region_fn_t real_region( sh4addr_t addr )
191 if( addr >= 0xE0000000 )
192 return p4_address_space[VMA_TO_EXT_ADDR(addr)>>12];
194 return ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];
197 static FASTCALL int32_t shadow_read_long( sh4addr_t addr )
199 if( shadow_address_mode == SHADOW_LOG ) {
200 int32_t rv = real_region(addr)->read_long(addr);
201 log_mem_op( READ_LONG, addr, rv );
204 return check_mem_op( READ_LONG, addr, 0 );
208 static FASTCALL int32_t shadow_read_word( sh4addr_t addr )
210 if( shadow_address_mode == SHADOW_LOG ) {
211 int32_t rv = real_region(addr)->read_word(addr);
212 log_mem_op( READ_WORD, addr, rv );
215 return check_mem_op( READ_WORD, addr, 0 );
219 static FASTCALL int32_t shadow_read_byte( sh4addr_t addr )
221 if( shadow_address_mode == SHADOW_LOG ) {
222 int32_t rv = real_region(addr)->read_byte(addr);
223 log_mem_op( READ_BYTE, addr, rv );
226 return check_mem_op( READ_BYTE, addr, 0 );
230 static FASTCALL int32_t shadow_read_byte_for_write( sh4addr_t addr )
232 if( shadow_address_mode == SHADOW_LOG ) {
233 int32_t rv = real_region(addr)->read_byte_for_write(addr);
234 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv );
237 return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
241 static FASTCALL void shadow_write_long( sh4addr_t addr, uint32_t val )
243 if( shadow_address_mode == SHADOW_LOG ) {
244 real_region(addr)->write_long(addr, val);
245 if( !IS_STORE_QUEUE(addr) )
246 log_mem_op( WRITE_LONG, addr, val );
248 if( !IS_STORE_QUEUE(addr) ) {
249 check_mem_op( WRITE_LONG, addr, val );
251 real_region(addr)->write_long(addr, val);
256 static FASTCALL void shadow_write_word( sh4addr_t addr, uint32_t val )
258 if( shadow_address_mode == SHADOW_LOG ) {
259 real_region(addr)->write_word(addr, val);
260 if( !IS_STORE_QUEUE(addr) )
261 log_mem_op( WRITE_WORD, addr, val );
263 if( !IS_STORE_QUEUE(addr) ) {
264 check_mem_op( WRITE_WORD, addr, val );
266 real_region(addr)->write_word(addr, val);
271 static FASTCALL void shadow_write_byte( sh4addr_t addr, uint32_t val )
273 if( shadow_address_mode == SHADOW_LOG ) {
274 real_region(addr)->write_byte(addr, val);
275 if( !IS_STORE_QUEUE(addr) )
276 log_mem_op( WRITE_BYTE, addr, val );
278 if( !IS_STORE_QUEUE(addr) ) {
279 check_mem_op( WRITE_BYTE, addr, val );
281 real_region(addr)->write_byte(addr, val);
286 static FASTCALL void shadow_prefetch( sh4addr_t addr )
288 if( shadow_address_mode == SHADOW_LOG ) {
289 real_region(addr)->prefetch(addr);
290 log_mem_op( PREFETCH, addr, 0 );
292 check_mem_op( PREFETCH, addr, 0 );
295 struct mem_region_fn shadow_fns = {
296 shadow_read_long, shadow_write_long,
297 shadow_read_word, shadow_write_word,
298 shadow_read_byte, shadow_write_byte,
299 NULL, NULL, shadow_prefetch, shadow_read_byte_for_write };
301 void sh4_shadow_block_begin()
303 memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
307 void sh4_shadow_block_end()
309 struct sh4_registers temp_sh4r;
311 /* Save the end registers, and restore the state back to the start */
312 memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
313 memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
315 shadow_address_mode = SHADOW_CHECK;
317 sh4r.new_pc = sh4r.pc + 2;
318 while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
319 sh4_execute_instruction();
320 sh4r.slice_cycle += sh4_cpu_period;
323 if( !check_registers( &temp_sh4r, &sh4r ) ) {
324 fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
325 fprintf( stderr, "Translated block was:\n" );
326 sh4_translate_dump_block(shadow_sh4r.pc);
329 if( mem_check_posn < mem_log_posn ) {
330 fprintf( stderr, "Additional translator memory operations:\n" );
331 while( mem_check_posn < mem_log_posn ) {
332 print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
337 shadow_address_mode = SHADOW_LOG;
341 void sh4_shadow_init()
343 shadow_address_mode = SHADOW_LOG;
344 p4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 );
345 shadow_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 );
346 for( unsigned i=0; i < (32 * 4096); i++ ) {
347 shadow_address_space[i] = &shadow_fns;
350 mem_log_size = MEM_LOG_SIZE;
351 mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
352 assert( mem_log != NULL );
354 sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
355 sh4_translate_set_fastmem( FALSE );
356 memcpy( p4_address_space, sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS),
357 sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) );
358 memcpy( sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS), shadow_address_space,
359 sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) );
360 mmu_set_ext_address_space(shadow_address_space);
.