filename | src/sh4/shadow.c |
changeset | 1217:677b1d85f1b4 |
prev | 1202:01ae5cbad4c8 |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Mon Oct 15 21:19:22 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Merge workaround for interpreted mode accesses to the OC ram regions in AT=0 cases. Still broken for other cases |
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 "mmio.h"
27 #include "sh4/sh4.h"
28 #include "sh4/sh4core.h"
29 #include "sh4/sh4trans.h"
30 #include "sh4/mmu.h"
32 typedef enum {
33 READ_LONG,
34 WRITE_LONG,
35 READ_WORD,
36 WRITE_WORD,
37 READ_BYTE,
38 WRITE_BYTE,
39 PREFETCH,
40 READ_BYTE_FOR_WRITE
41 } MemOp;
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 {
47 MemOp op;
48 sh4addr_t addr;
49 uint32_t value;
50 };
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;
56 typedef enum {
57 SHADOW_LOG,
58 SHADOW_CHECK
59 } shadow_mode_t;
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 )
70 {
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 );
74 mem_log_size *= 2;
75 mem_log = tmp;
76 }
77 mem_log[mem_log_posn].op = op;
78 mem_log[mem_log_posn].addr = addr;
79 mem_log[mem_log_posn].value = value;
80 mem_log_posn++;
81 }
83 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
84 {
85 if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
86 fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
87 } else {
88 fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
89 }
90 }
92 static void dump_mem_ops()
93 {
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 );
96 }
97 }
99 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
100 {
101 if( mem_check_posn >= mem_log_posn ) {
102 fprintf( stderr, "Unexpected interpreter memory operation: " );
103 print_mem_op(stderr, op, addr, value );
104 abort();
105 }
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 );
115 abort();
116 }
117 return mem_log[mem_check_posn++].value;
118 }
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 )
124 {
125 gboolean isgood = TRUE;
126 for( unsigned i=0; i<16; i++ ) {
127 if( xsh4r->r[i] != esh4r->r[i] ) {
128 isgood = FALSE;
129 fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
130 }
131 }
132 for( unsigned i=0; i<8; i++ ) {
133 if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
134 isgood = FALSE;
135 fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
136 }
137 }
138 for( unsigned i=0; i<16; i++ ) {
139 if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
140 isgood = FALSE;
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]),
143 esh4r->fr[0][i],
144 *((uint32_t *)&esh4r->fr[0][i])
145 );
146 }
147 }
148 for( unsigned i=0; i<16; i++ ) {
149 if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
150 isgood = FALSE;
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]),
153 esh4r->fr[1][i],
154 *((uint32_t *)&esh4r->fr[1][i])
155 );
156 }
157 }
159 CHECK_REG(t, "T");
160 CHECK_REG(m, "M");
161 CHECK_REG(s, "S");
162 CHECK_REG(q, "Q");
163 CHECK_REG(pc, "PC");
164 CHECK_REG(pr, "PR");
165 CHECK_REG(sr, "SR");
166 CHECK_REG(fpscr, "FPSCR");
167 CHECK_REG(fpul.i, "FPUL");
168 if( xsh4r->mac != esh4r->mac ) {
169 isgood = FALSE;
170 fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
171 }
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 ) {
180 isgood = FALSE;
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 );
185 }
186 return isgood;
187 }
189 static mem_region_fn_t real_region( sh4addr_t addr )
190 {
191 if( addr >= 0xE0000000 )
192 return p4_address_space[VMA_TO_EXT_ADDR(addr)>>12];
193 else
194 return ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];
195 }
197 static FASTCALL int32_t shadow_read_long( sh4addr_t addr )
198 {
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 );
202 return rv;
203 } else {
204 return check_mem_op( READ_LONG, addr, 0 );
205 }
206 }
208 static FASTCALL int32_t shadow_read_word( sh4addr_t addr )
209 {
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 );
213 return rv;
214 } else {
215 return check_mem_op( READ_WORD, addr, 0 );
216 }
217 }
219 static FASTCALL int32_t shadow_read_byte( sh4addr_t addr )
220 {
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 );
224 return rv;
225 } else {
226 return check_mem_op( READ_BYTE, addr, 0 );
227 }
228 }
230 static FASTCALL int32_t shadow_read_byte_for_write( sh4addr_t addr )
231 {
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 );
235 return rv;
236 } else {
237 return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
238 }
239 }
241 static FASTCALL void shadow_write_long( sh4addr_t addr, uint32_t val )
242 {
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 );
247 } else {
248 if( !IS_STORE_QUEUE(addr) ) {
249 check_mem_op( WRITE_LONG, addr, val );
250 } else {
251 real_region(addr)->write_long(addr, val);
252 }
253 }
254 }
256 static FASTCALL void shadow_write_word( sh4addr_t addr, uint32_t val )
257 {
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 );
262 } else {
263 if( !IS_STORE_QUEUE(addr) ) {
264 check_mem_op( WRITE_WORD, addr, val );
265 } else {
266 real_region(addr)->write_word(addr, val);
267 }
268 }
269 }
271 static FASTCALL void shadow_write_byte( sh4addr_t addr, uint32_t val )
272 {
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 );
277 } else {
278 if( !IS_STORE_QUEUE(addr) ) {
279 check_mem_op( WRITE_BYTE, addr, val );
280 } else {
281 real_region(addr)->write_byte(addr, val);
282 }
283 }
284 }
286 static FASTCALL void shadow_prefetch( sh4addr_t addr )
287 {
288 if( shadow_address_mode == SHADOW_LOG ) {
289 real_region(addr)->prefetch(addr);
290 log_mem_op( PREFETCH, addr, 0 );
291 } else {
292 check_mem_op( PREFETCH, addr, 0 );
293 }
294 }
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()
302 {
303 memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
304 mem_log_posn = 0;
305 }
307 void sh4_shadow_block_end()
308 {
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;
316 mem_check_posn = 0;
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;
321 }
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);
327 abort();
328 }
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 );
333 mem_check_posn++;
334 }
335 abort();
336 }
337 shadow_address_mode = SHADOW_LOG;
338 }
341 void sh4_shadow_init()
342 {
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;
348 }
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);
361 }
.