filename | src/sh4/shadow.c |
changeset | 1128:180abbb2a1f3 |
next | 1191:12fdf3aafcd4 |
author | nkeynes |
date | Fri Dec 02 18:14:27 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Handle calls to sh4_disasm_instruction when the memory isn't mapped (as can happen if we try to print a translated block that's been unmapped) |
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/sh4trans.h"
28 #include "sh4/mmu.h"
30 typedef enum {
31 READ_LONG,
32 WRITE_LONG,
33 READ_WORD,
34 WRITE_WORD,
35 READ_BYTE,
36 WRITE_BYTE,
37 PREFETCH,
38 READ_BYTE_FOR_WRITE
39 } MemOp;
41 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
42 "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
44 struct mem_log_entry {
45 MemOp op;
46 sh4addr_t addr;
47 uint32_t value;
48 };
50 static struct sh4_registers shadow_sh4r;
51 static struct mem_region_fn **log_address_space;
52 static struct mem_region_fn **check_address_space;
53 static struct mem_region_fn **real_address_space;
55 #define MEM_LOG_SIZE 4096
56 static struct mem_log_entry *mem_log;
57 static uint32_t mem_log_posn, mem_log_size;
58 static uint32_t mem_check_posn;
60 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
62 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
63 {
64 if( mem_log_posn == mem_log_size ) {
65 struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
66 assert( tmp != NULL );
67 mem_log_size *= 2;
68 mem_log = tmp;
69 }
70 mem_log[mem_log_posn].op = op;
71 mem_log[mem_log_posn].addr = addr;
72 mem_log[mem_log_posn].value = value;
73 mem_log_posn++;
74 }
76 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
77 {
78 if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
79 fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
80 } else {
81 fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
82 }
83 }
85 static void dump_mem_ops()
86 {
87 for( unsigned i=0; i<mem_log_posn; i++ ) {
88 print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
89 }
90 }
92 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
93 {
94 if( mem_check_posn >= mem_log_posn ) {
95 fprintf( stderr, "Unexpected interpreter memory operation: " );
96 print_mem_op(stderr, op, addr, value );
97 abort();
98 }
99 if( mem_log[mem_check_posn].op != op ||
100 mem_log[mem_check_posn].addr != addr ||
101 (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
102 mem_log[mem_check_posn].value != value ) ) {
103 fprintf(stderr, "Memory operation mismatch. Translator: " );
104 print_mem_op(stderr, mem_log[mem_check_posn].op,
105 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
106 fprintf(stderr, "Emulator: ");
107 print_mem_op(stderr, op, addr, value );
108 abort();
109 }
110 return mem_log[mem_check_posn++].value;
111 }
113 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
114 isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
116 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
117 {
118 gboolean isgood = TRUE;
119 for( unsigned i=0; i<16; i++ ) {
120 if( xsh4r->r[i] != esh4r->r[i] ) {
121 isgood = FALSE;
122 fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
123 }
124 }
125 for( unsigned i=0; i<8; i++ ) {
126 if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
127 isgood = FALSE;
128 fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
129 }
130 }
131 for( unsigned i=0; i<16; i++ ) {
132 if( xsh4r->fr[0][i] != esh4r->fr[0][i] ) {
133 isgood = FALSE;
134 fprintf( stderr, "FR%d Xlt = %f, Emu = %f\n", i, xsh4r->fr[0][i], esh4r->fr[0][i] );
135 }
136 }
137 for( unsigned i=0; i<16; i++ ) {
138 if( xsh4r->fr[1][i] != esh4r->fr[1][i] ) {
139 isgood = FALSE;
140 fprintf( stderr, "XF%d Xlt = %f, Emu = %f\n", i, xsh4r->fr[1][i], esh4r->fr[1][i] );
141 }
142 }
144 CHECK_REG(t, "T");
145 CHECK_REG(m, "M");
146 CHECK_REG(s, "S");
147 CHECK_REG(q, "Q");
148 CHECK_REG(pc, "PC");
149 CHECK_REG(pr, "PR");
150 CHECK_REG(sr, "SR");
151 CHECK_REG(fpscr, "FPSCR");
152 CHECK_REG(fpul.i, "FPUL");
153 if( xsh4r->mac != esh4r->mac ) {
154 isgood = FALSE;
155 fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
156 }
157 CHECK_REG(gbr, "GBR");
158 CHECK_REG(ssr, "SSR");
159 CHECK_REG(spc, "SPC");
160 CHECK_REG(sgr, "SGR");
161 CHECK_REG(dbr, "DBR");
162 CHECK_REG(vbr, "VBR");
163 CHECK_REG(sh4_state, "STATE");
164 if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
165 isgood = FALSE;
166 fprintf( stderr, "Store queue Xlt =\n" );
167 fwrite_dump( xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
168 fprintf( stderr, " Emu =\n" );
169 fwrite_dump( esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
170 }
171 return isgood;
172 }
174 static FASTCALL int32_t log_read_long( sh4addr_t addr )
175 {
176 int32_t rv = real_address_space[addr>>12]->read_long(addr);
177 log_mem_op( READ_LONG, addr, rv );
178 return rv;
179 }
181 static FASTCALL int32_t log_read_word( sh4addr_t addr )
182 {
183 int32_t rv = real_address_space[addr>>12]->read_word(addr);
184 log_mem_op( READ_WORD, addr, rv );
185 return rv;
186 }
188 static FASTCALL int32_t log_read_byte( sh4addr_t addr )
189 {
190 int32_t rv = real_address_space[addr>>12]->read_byte(addr);
191 log_mem_op( READ_BYTE, addr, rv );
192 return rv;
193 }
195 static FASTCALL int32_t log_read_byte_for_write( sh4addr_t addr )
196 {
197 int32_t rv = real_address_space[addr>>12]->read_byte_for_write(addr);
198 log_mem_op( READ_BYTE_FOR_WRITE, addr, rv );
199 return rv;
200 }
202 static FASTCALL void log_write_long( sh4addr_t addr, uint32_t val )
203 {
204 if( !IS_STORE_QUEUE(addr) )
205 log_mem_op( WRITE_LONG, addr, val );
206 real_address_space[addr>>12]->write_long(addr, val);
207 }
209 static FASTCALL void log_write_word( sh4addr_t addr, uint32_t val )
210 {
211 if( !IS_STORE_QUEUE(addr) )
212 log_mem_op( WRITE_WORD, addr, val );
213 real_address_space[addr>>12]->write_word(addr, val);
214 }
216 static FASTCALL void log_write_byte( sh4addr_t addr, uint32_t val )
217 {
218 if( !IS_STORE_QUEUE(addr) )
219 log_mem_op( WRITE_BYTE, addr, val );
220 real_address_space[addr>>12]->write_byte(addr, val);
221 }
223 static FASTCALL void log_prefetch( sh4addr_t addr )
224 {
225 log_mem_op( PREFETCH, addr, 0 );
226 real_address_space[addr>>12]->prefetch(addr);
227 }
229 static FASTCALL int32_t check_read_long( sh4addr_t addr )
230 {
231 return check_mem_op( READ_LONG, addr, 0 );
232 }
234 static FASTCALL int32_t check_read_word( sh4addr_t addr )
235 {
236 return check_mem_op( READ_WORD, addr, 0 );
237 }
239 static FASTCALL int32_t check_read_byte( sh4addr_t addr )
240 {
241 return check_mem_op( READ_BYTE, addr, 0 );
242 }
244 static FASTCALL int32_t check_read_byte_for_write( sh4addr_t addr )
245 {
246 return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
247 }
249 static FASTCALL void check_write_long( sh4addr_t addr, uint32_t value )
250 {
251 if( !IS_STORE_QUEUE(addr) )
252 check_mem_op( WRITE_LONG, addr, value );
253 }
255 static FASTCALL void check_write_word( sh4addr_t addr, uint32_t value )
256 {
257 if( !IS_STORE_QUEUE(addr) )
258 check_mem_op( WRITE_WORD, addr, value );
259 }
261 static FASTCALL void check_write_byte( sh4addr_t addr, uint32_t value )
262 {
263 if( !IS_STORE_QUEUE(addr) )
264 check_mem_op( WRITE_BYTE, addr, value );
265 }
267 static FASTCALL void check_prefetch( sh4addr_t addr )
268 {
269 check_mem_op( PREFETCH, addr, 0 );
270 }
272 struct mem_region_fn log_fns = { log_read_long, log_write_long,
273 log_read_word, log_write_word,
274 log_read_byte, log_write_byte,
275 NULL, NULL, log_prefetch, log_read_byte_for_write };
277 struct mem_region_fn check_fns = { check_read_long, check_write_long,
278 check_read_word, check_write_word,
279 check_read_byte, check_write_byte,
280 NULL, NULL, check_prefetch, check_read_byte_for_write };
285 void sh4_shadow_block_begin()
286 {
287 memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
288 mem_log_posn = 0;
289 }
291 void sh4_shadow_block_end()
292 {
293 struct sh4_registers temp_sh4r;
295 /* Save the end registers, and restore the state back to the start */
296 memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
297 memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
299 sh4_address_space = check_address_space;
300 mem_check_posn = 0;
301 sh4r.new_pc = sh4r.pc + 2;
302 while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
303 sh4_execute_instruction();
304 sh4r.slice_cycle += sh4_cpu_period;
305 }
307 if( !check_registers( &temp_sh4r, &sh4r ) ) {
308 fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
309 abort();
310 }
311 if( mem_check_posn < mem_log_posn ) {
312 fprintf( stderr, "Additional translator memory operations:\n" );
313 while( mem_check_posn < mem_log_posn ) {
314 print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
315 mem_check_posn++;
316 }
317 abort();
318 }
319 sh4_address_space = real_address_space;
320 }
323 void sh4_shadow_init()
324 {
325 real_address_space = sh4_address_space;
326 log_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
327 check_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
328 for( unsigned i=0; i < (256 * 4096); i++ ) {
329 log_address_space[i] = &log_fns;
330 check_address_space[i] = &check_fns;
331 }
333 mem_log_size = MEM_LOG_SIZE;
334 mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
335 assert( mem_log != NULL );
337 sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
338 sh4_translate_set_fastmem( FALSE );
339 sh4_translate_set_address_space( log_address_space, log_address_space );
340 }
.