filename | src/sh4/shadow.c |
changeset | 1217:677b1d85f1b4 |
prev | 1202:01ae5cbad4c8 |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Fri Aug 24 08:53:50 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Move the generated prologue/epilogue code out into a common entry stub (reduces space requirements) and pre-save all saved registers. Change FASTCALL to use 3 regs instead of 2 since we can now keep everything in regs. |
file | annotate | diff | log | raw |
nkeynes@1128 | 1 | /** |
nkeynes@1128 | 2 | * $Id$ |
nkeynes@1128 | 3 | * |
nkeynes@1128 | 4 | * SH4 shadow execution core - runs xlat + emu together and checks that the |
nkeynes@1128 | 5 | * results are the same. |
nkeynes@1128 | 6 | * |
nkeynes@1128 | 7 | * Copyright (c) 2010 Nathan Keynes. |
nkeynes@1128 | 8 | * |
nkeynes@1128 | 9 | * This program is free software; you can redistribute it and/or modify |
nkeynes@1128 | 10 | * it under the terms of the GNU General Public License as published by |
nkeynes@1128 | 11 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@1128 | 12 | * (at your option) any later version. |
nkeynes@1128 | 13 | * |
nkeynes@1128 | 14 | * This program is distributed in the hope that it will be useful, |
nkeynes@1128 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@1128 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@1128 | 17 | * GNU General Public License for more details. |
nkeynes@1128 | 18 | */ |
nkeynes@1128 | 19 | |
nkeynes@1128 | 20 | #include <stdlib.h> |
nkeynes@1128 | 21 | #include <string.h> |
nkeynes@1128 | 22 | #include <assert.h> |
nkeynes@1128 | 23 | |
nkeynes@1128 | 24 | #include "clock.h" |
nkeynes@1128 | 25 | #include "mem.h" |
nkeynes@1217 | 26 | #include "mmio.h" |
nkeynes@1128 | 27 | #include "sh4/sh4.h" |
nkeynes@1194 | 28 | #include "sh4/sh4core.h" |
nkeynes@1128 | 29 | #include "sh4/sh4trans.h" |
nkeynes@1128 | 30 | #include "sh4/mmu.h" |
nkeynes@1128 | 31 | |
nkeynes@1128 | 32 | typedef enum { |
nkeynes@1128 | 33 | READ_LONG, |
nkeynes@1128 | 34 | WRITE_LONG, |
nkeynes@1128 | 35 | READ_WORD, |
nkeynes@1128 | 36 | WRITE_WORD, |
nkeynes@1128 | 37 | READ_BYTE, |
nkeynes@1128 | 38 | WRITE_BYTE, |
nkeynes@1128 | 39 | PREFETCH, |
nkeynes@1128 | 40 | READ_BYTE_FOR_WRITE |
nkeynes@1128 | 41 | } MemOp; |
nkeynes@1128 | 42 | |
nkeynes@1128 | 43 | char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word", |
nkeynes@1128 | 44 | "read_byte", "write_byte", "prefetch", "read_byte_for_write" }; |
nkeynes@1128 | 45 | |
nkeynes@1128 | 46 | struct mem_log_entry { |
nkeynes@1128 | 47 | MemOp op; |
nkeynes@1128 | 48 | sh4addr_t addr; |
nkeynes@1128 | 49 | uint32_t value; |
nkeynes@1128 | 50 | }; |
nkeynes@1128 | 51 | |
nkeynes@1128 | 52 | static struct sh4_registers shadow_sh4r; |
nkeynes@1217 | 53 | static struct mem_region_fn **shadow_address_space; |
nkeynes@1217 | 54 | static struct mem_region_fn **p4_address_space; |
nkeynes@1217 | 55 | |
nkeynes@1217 | 56 | typedef enum { |
nkeynes@1217 | 57 | SHADOW_LOG, |
nkeynes@1217 | 58 | SHADOW_CHECK |
nkeynes@1217 | 59 | } shadow_mode_t; |
nkeynes@1217 | 60 | static shadow_mode_t shadow_address_mode = SHADOW_LOG; |
nkeynes@1128 | 61 | |
nkeynes@1128 | 62 | #define MEM_LOG_SIZE 4096 |
nkeynes@1128 | 63 | static struct mem_log_entry *mem_log; |
nkeynes@1128 | 64 | static uint32_t mem_log_posn, mem_log_size; |
nkeynes@1128 | 65 | static uint32_t mem_check_posn; |
nkeynes@1128 | 66 | |
nkeynes@1128 | 67 | #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000) |
nkeynes@1128 | 68 | |
nkeynes@1217 | 69 | static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value ) |
nkeynes@1128 | 70 | { |
nkeynes@1128 | 71 | if( mem_log_posn == mem_log_size ) { |
nkeynes@1128 | 72 | struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2); |
nkeynes@1128 | 73 | assert( tmp != NULL ); |
nkeynes@1128 | 74 | mem_log_size *= 2; |
nkeynes@1128 | 75 | mem_log = tmp; |
nkeynes@1128 | 76 | } |
nkeynes@1128 | 77 | mem_log[mem_log_posn].op = op; |
nkeynes@1128 | 78 | mem_log[mem_log_posn].addr = addr; |
nkeynes@1128 | 79 | mem_log[mem_log_posn].value = value; |
nkeynes@1128 | 80 | mem_log_posn++; |
nkeynes@1128 | 81 | } |
nkeynes@1128 | 82 | |
nkeynes@1128 | 83 | static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value ) |
nkeynes@1128 | 84 | { |
nkeynes@1128 | 85 | if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) { |
nkeynes@1128 | 86 | fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value ); |
nkeynes@1128 | 87 | } else { |
nkeynes@1128 | 88 | fprintf( f, "%s( %08X )\n", memOpNames[op], addr ); |
nkeynes@1128 | 89 | } |
nkeynes@1128 | 90 | } |
nkeynes@1128 | 91 | |
nkeynes@1128 | 92 | static void dump_mem_ops() |
nkeynes@1128 | 93 | { |
nkeynes@1128 | 94 | for( unsigned i=0; i<mem_log_posn; i++ ) { |
nkeynes@1128 | 95 | print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value ); |
nkeynes@1128 | 96 | } |
nkeynes@1128 | 97 | } |
nkeynes@1128 | 98 | |
nkeynes@1217 | 99 | static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value ) |
nkeynes@1128 | 100 | { |
nkeynes@1128 | 101 | if( mem_check_posn >= mem_log_posn ) { |
nkeynes@1128 | 102 | fprintf( stderr, "Unexpected interpreter memory operation: " ); |
nkeynes@1128 | 103 | print_mem_op(stderr, op, addr, value ); |
nkeynes@1128 | 104 | abort(); |
nkeynes@1128 | 105 | } |
nkeynes@1128 | 106 | if( mem_log[mem_check_posn].op != op || |
nkeynes@1128 | 107 | mem_log[mem_check_posn].addr != addr || |
nkeynes@1128 | 108 | (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) && |
nkeynes@1128 | 109 | mem_log[mem_check_posn].value != value ) ) { |
nkeynes@1128 | 110 | fprintf(stderr, "Memory operation mismatch. Translator: " ); |
nkeynes@1128 | 111 | print_mem_op(stderr, mem_log[mem_check_posn].op, |
nkeynes@1128 | 112 | mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value ); |
nkeynes@1128 | 113 | fprintf(stderr, "Emulator: "); |
nkeynes@1128 | 114 | print_mem_op(stderr, op, addr, value ); |
nkeynes@1128 | 115 | abort(); |
nkeynes@1128 | 116 | } |
nkeynes@1128 | 117 | return mem_log[mem_check_posn++].value; |
nkeynes@1128 | 118 | } |
nkeynes@1128 | 119 | |
nkeynes@1128 | 120 | #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \ |
nkeynes@1128 | 121 | isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); } |
nkeynes@1128 | 122 | |
nkeynes@1128 | 123 | static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r ) |
nkeynes@1128 | 124 | { |
nkeynes@1128 | 125 | gboolean isgood = TRUE; |
nkeynes@1128 | 126 | for( unsigned i=0; i<16; i++ ) { |
nkeynes@1128 | 127 | if( xsh4r->r[i] != esh4r->r[i] ) { |
nkeynes@1128 | 128 | isgood = FALSE; |
nkeynes@1128 | 129 | fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] ); |
nkeynes@1128 | 130 | } |
nkeynes@1128 | 131 | } |
nkeynes@1128 | 132 | for( unsigned i=0; i<8; i++ ) { |
nkeynes@1128 | 133 | if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) { |
nkeynes@1128 | 134 | isgood = FALSE; |
nkeynes@1128 | 135 | fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] ); |
nkeynes@1128 | 136 | } |
nkeynes@1128 | 137 | } |
nkeynes@1128 | 138 | for( unsigned i=0; i<16; i++ ) { |
nkeynes@1191 | 139 | if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) { |
nkeynes@1128 | 140 | isgood = FALSE; |
nkeynes@1191 | 141 | fprintf( stderr, "FR%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i], |
nkeynes@1191 | 142 | *((uint32_t *)&xsh4r->fr[0][i]), |
nkeynes@1191 | 143 | esh4r->fr[0][i], |
nkeynes@1191 | 144 | *((uint32_t *)&esh4r->fr[0][i]) |
nkeynes@1191 | 145 | ); |
nkeynes@1128 | 146 | } |
nkeynes@1128 | 147 | } |
nkeynes@1128 | 148 | for( unsigned i=0; i<16; i++ ) { |
nkeynes@1191 | 149 | if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) { |
nkeynes@1128 | 150 | isgood = FALSE; |
nkeynes@1191 | 151 | fprintf( stderr, "XF%d Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i], |
nkeynes@1191 | 152 | *((uint32_t *)&xsh4r->fr[1][i]), |
nkeynes@1191 | 153 | esh4r->fr[1][i], |
nkeynes@1191 | 154 | *((uint32_t *)&esh4r->fr[1][i]) |
nkeynes@1191 | 155 | ); |
nkeynes@1128 | 156 | } |
nkeynes@1128 | 157 | } |
nkeynes@1128 | 158 | |
nkeynes@1128 | 159 | CHECK_REG(t, "T"); |
nkeynes@1128 | 160 | CHECK_REG(m, "M"); |
nkeynes@1128 | 161 | CHECK_REG(s, "S"); |
nkeynes@1128 | 162 | CHECK_REG(q, "Q"); |
nkeynes@1128 | 163 | CHECK_REG(pc, "PC"); |
nkeynes@1128 | 164 | CHECK_REG(pr, "PR"); |
nkeynes@1128 | 165 | CHECK_REG(sr, "SR"); |
nkeynes@1128 | 166 | CHECK_REG(fpscr, "FPSCR"); |
nkeynes@1128 | 167 | CHECK_REG(fpul.i, "FPUL"); |
nkeynes@1128 | 168 | if( xsh4r->mac != esh4r->mac ) { |
nkeynes@1128 | 169 | isgood = FALSE; |
nkeynes@1128 | 170 | fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac ); |
nkeynes@1128 | 171 | } |
nkeynes@1128 | 172 | CHECK_REG(gbr, "GBR"); |
nkeynes@1128 | 173 | CHECK_REG(ssr, "SSR"); |
nkeynes@1128 | 174 | CHECK_REG(spc, "SPC"); |
nkeynes@1128 | 175 | CHECK_REG(sgr, "SGR"); |
nkeynes@1128 | 176 | CHECK_REG(dbr, "DBR"); |
nkeynes@1128 | 177 | CHECK_REG(vbr, "VBR"); |
nkeynes@1128 | 178 | CHECK_REG(sh4_state, "STATE"); |
nkeynes@1128 | 179 | if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) { |
nkeynes@1128 | 180 | isgood = FALSE; |
nkeynes@1128 | 181 | fprintf( stderr, "Store queue Xlt =\n" ); |
nkeynes@1194 | 182 | fwrite_dump( (unsigned char *)xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr ); |
nkeynes@1128 | 183 | fprintf( stderr, " Emu =\n" ); |
nkeynes@1194 | 184 | fwrite_dump( (unsigned char *)esh4r->store_queue, sizeof(esh4r->store_queue), stderr ); |
nkeynes@1128 | 185 | } |
nkeynes@1128 | 186 | return isgood; |
nkeynes@1128 | 187 | } |
nkeynes@1128 | 188 | |
nkeynes@1217 | 189 | static mem_region_fn_t real_region( sh4addr_t addr ) |
nkeynes@1128 | 190 | { |
nkeynes@1217 | 191 | if( addr >= 0xE0000000 ) |
nkeynes@1217 | 192 | return p4_address_space[VMA_TO_EXT_ADDR(addr)>>12]; |
nkeynes@1217 | 193 | else |
nkeynes@1217 | 194 | return ext_address_space[VMA_TO_EXT_ADDR(addr)>>12]; |
nkeynes@1128 | 195 | } |
nkeynes@1128 | 196 | |
nkeynes@1217 | 197 | static FASTCALL int32_t shadow_read_long( sh4addr_t addr ) |
nkeynes@1128 | 198 | { |
nkeynes@1217 | 199 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 200 | int32_t rv = real_region(addr)->read_long(addr); |
nkeynes@1217 | 201 | log_mem_op( READ_LONG, addr, rv ); |
nkeynes@1217 | 202 | return rv; |
nkeynes@1194 | 203 | } else { |
nkeynes@1217 | 204 | return check_mem_op( READ_LONG, addr, 0 ); |
nkeynes@1194 | 205 | } |
nkeynes@1128 | 206 | } |
nkeynes@1128 | 207 | |
nkeynes@1217 | 208 | static FASTCALL int32_t shadow_read_word( sh4addr_t addr ) |
nkeynes@1128 | 209 | { |
nkeynes@1217 | 210 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 211 | int32_t rv = real_region(addr)->read_word(addr); |
nkeynes@1217 | 212 | log_mem_op( READ_WORD, addr, rv ); |
nkeynes@1217 | 213 | return rv; |
nkeynes@1194 | 214 | } else { |
nkeynes@1217 | 215 | return check_mem_op( READ_WORD, addr, 0 ); |
nkeynes@1194 | 216 | } |
nkeynes@1128 | 217 | } |
nkeynes@1128 | 218 | |
nkeynes@1217 | 219 | static FASTCALL int32_t shadow_read_byte( sh4addr_t addr ) |
nkeynes@1128 | 220 | { |
nkeynes@1217 | 221 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 222 | int32_t rv = real_region(addr)->read_byte(addr); |
nkeynes@1217 | 223 | log_mem_op( READ_BYTE, addr, rv ); |
nkeynes@1217 | 224 | return rv; |
nkeynes@1194 | 225 | } else { |
nkeynes@1217 | 226 | return check_mem_op( READ_BYTE, addr, 0 ); |
nkeynes@1194 | 227 | } |
nkeynes@1128 | 228 | } |
nkeynes@1128 | 229 | |
nkeynes@1217 | 230 | static FASTCALL int32_t shadow_read_byte_for_write( sh4addr_t addr ) |
nkeynes@1128 | 231 | { |
nkeynes@1217 | 232 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 233 | int32_t rv = real_region(addr)->read_byte_for_write(addr); |
nkeynes@1217 | 234 | log_mem_op( READ_BYTE_FOR_WRITE, addr, rv ); |
nkeynes@1217 | 235 | return rv; |
nkeynes@1217 | 236 | } else { |
nkeynes@1217 | 237 | return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 ); |
nkeynes@1194 | 238 | } |
nkeynes@1128 | 239 | } |
nkeynes@1128 | 240 | |
nkeynes@1217 | 241 | static FASTCALL void shadow_write_long( sh4addr_t addr, uint32_t val ) |
nkeynes@1217 | 242 | { |
nkeynes@1217 | 243 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 244 | real_region(addr)->write_long(addr, val); |
nkeynes@1217 | 245 | if( !IS_STORE_QUEUE(addr) ) |
nkeynes@1217 | 246 | log_mem_op( WRITE_LONG, addr, val ); |
nkeynes@1217 | 247 | } else { |
nkeynes@1217 | 248 | if( !IS_STORE_QUEUE(addr) ) { |
nkeynes@1217 | 249 | check_mem_op( WRITE_LONG, addr, val ); |
nkeynes@1217 | 250 | } else { |
nkeynes@1217 | 251 | real_region(addr)->write_long(addr, val); |
nkeynes@1217 | 252 | } |
nkeynes@1217 | 253 | } |
nkeynes@1217 | 254 | } |
nkeynes@1128 | 255 | |
nkeynes@1217 | 256 | static FASTCALL void shadow_write_word( sh4addr_t addr, uint32_t val ) |
nkeynes@1217 | 257 | { |
nkeynes@1217 | 258 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 259 | real_region(addr)->write_word(addr, val); |
nkeynes@1217 | 260 | if( !IS_STORE_QUEUE(addr) ) |
nkeynes@1217 | 261 | log_mem_op( WRITE_WORD, addr, val ); |
nkeynes@1217 | 262 | } else { |
nkeynes@1217 | 263 | if( !IS_STORE_QUEUE(addr) ) { |
nkeynes@1217 | 264 | check_mem_op( WRITE_WORD, addr, val ); |
nkeynes@1217 | 265 | } else { |
nkeynes@1217 | 266 | real_region(addr)->write_word(addr, val); |
nkeynes@1217 | 267 | } |
nkeynes@1217 | 268 | } |
nkeynes@1217 | 269 | } |
nkeynes@1128 | 270 | |
nkeynes@1217 | 271 | static FASTCALL void shadow_write_byte( sh4addr_t addr, uint32_t val ) |
nkeynes@1217 | 272 | { |
nkeynes@1217 | 273 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 274 | real_region(addr)->write_byte(addr, val); |
nkeynes@1217 | 275 | if( !IS_STORE_QUEUE(addr) ) |
nkeynes@1217 | 276 | log_mem_op( WRITE_BYTE, addr, val ); |
nkeynes@1217 | 277 | } else { |
nkeynes@1217 | 278 | if( !IS_STORE_QUEUE(addr) ) { |
nkeynes@1217 | 279 | check_mem_op( WRITE_BYTE, addr, val ); |
nkeynes@1217 | 280 | } else { |
nkeynes@1217 | 281 | real_region(addr)->write_byte(addr, val); |
nkeynes@1217 | 282 | } |
nkeynes@1217 | 283 | } |
nkeynes@1217 | 284 | } |
nkeynes@1128 | 285 | |
nkeynes@1217 | 286 | static FASTCALL void shadow_prefetch( sh4addr_t addr ) |
nkeynes@1217 | 287 | { |
nkeynes@1217 | 288 | if( shadow_address_mode == SHADOW_LOG ) { |
nkeynes@1217 | 289 | real_region(addr)->prefetch(addr); |
nkeynes@1217 | 290 | log_mem_op( PREFETCH, addr, 0 ); |
nkeynes@1217 | 291 | } else { |
nkeynes@1217 | 292 | check_mem_op( PREFETCH, addr, 0 ); |
nkeynes@1217 | 293 | } |
nkeynes@1217 | 294 | } |
nkeynes@1217 | 295 | struct mem_region_fn shadow_fns = { |
nkeynes@1217 | 296 | shadow_read_long, shadow_write_long, |
nkeynes@1217 | 297 | shadow_read_word, shadow_write_word, |
nkeynes@1217 | 298 | shadow_read_byte, shadow_write_byte, |
nkeynes@1217 | 299 | NULL, NULL, shadow_prefetch, shadow_read_byte_for_write }; |
nkeynes@1128 | 300 | |
nkeynes@1128 | 301 | void sh4_shadow_block_begin() |
nkeynes@1128 | 302 | { |
nkeynes@1128 | 303 | memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) ); |
nkeynes@1128 | 304 | mem_log_posn = 0; |
nkeynes@1128 | 305 | } |
nkeynes@1128 | 306 | |
nkeynes@1128 | 307 | void sh4_shadow_block_end() |
nkeynes@1128 | 308 | { |
nkeynes@1128 | 309 | struct sh4_registers temp_sh4r; |
nkeynes@1128 | 310 | |
nkeynes@1128 | 311 | /* Save the end registers, and restore the state back to the start */ |
nkeynes@1128 | 312 | memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) ); |
nkeynes@1128 | 313 | memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) ); |
nkeynes@1128 | 314 | |
nkeynes@1217 | 315 | shadow_address_mode = SHADOW_CHECK; |
nkeynes@1128 | 316 | mem_check_posn = 0; |
nkeynes@1128 | 317 | sh4r.new_pc = sh4r.pc + 2; |
nkeynes@1128 | 318 | while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) { |
nkeynes@1128 | 319 | sh4_execute_instruction(); |
nkeynes@1128 | 320 | sh4r.slice_cycle += sh4_cpu_period; |
nkeynes@1128 | 321 | } |
nkeynes@1128 | 322 | |
nkeynes@1128 | 323 | if( !check_registers( &temp_sh4r, &sh4r ) ) { |
nkeynes@1128 | 324 | fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc ); |
nkeynes@1191 | 325 | fprintf( stderr, "Translated block was:\n" ); |
nkeynes@1191 | 326 | sh4_translate_dump_block(shadow_sh4r.pc); |
nkeynes@1128 | 327 | abort(); |
nkeynes@1128 | 328 | } |
nkeynes@1128 | 329 | if( mem_check_posn < mem_log_posn ) { |
nkeynes@1128 | 330 | fprintf( stderr, "Additional translator memory operations:\n" ); |
nkeynes@1128 | 331 | while( mem_check_posn < mem_log_posn ) { |
nkeynes@1128 | 332 | print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value ); |
nkeynes@1128 | 333 | mem_check_posn++; |
nkeynes@1128 | 334 | } |
nkeynes@1128 | 335 | abort(); |
nkeynes@1128 | 336 | } |
nkeynes@1217 | 337 | shadow_address_mode = SHADOW_LOG; |
nkeynes@1128 | 338 | } |
nkeynes@1128 | 339 | |
nkeynes@1128 | 340 | |
nkeynes@1128 | 341 | void sh4_shadow_init() |
nkeynes@1128 | 342 | { |
nkeynes@1217 | 343 | shadow_address_mode = SHADOW_LOG; |
nkeynes@1217 | 344 | p4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 ); |
nkeynes@1217 | 345 | shadow_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 ); |
nkeynes@1217 | 346 | for( unsigned i=0; i < (32 * 4096); i++ ) { |
nkeynes@1217 | 347 | shadow_address_space[i] = &shadow_fns; |
nkeynes@1128 | 348 | } |
nkeynes@1128 | 349 | |
nkeynes@1128 | 350 | mem_log_size = MEM_LOG_SIZE; |
nkeynes@1128 | 351 | mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) ); |
nkeynes@1128 | 352 | assert( mem_log != NULL ); |
nkeynes@1128 | 353 | |
nkeynes@1128 | 354 | sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end ); |
nkeynes@1128 | 355 | sh4_translate_set_fastmem( FALSE ); |
nkeynes@1217 | 356 | memcpy( p4_address_space, sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS), |
nkeynes@1217 | 357 | sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) ); |
nkeynes@1217 | 358 | memcpy( sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS), shadow_address_space, |
nkeynes@1217 | 359 | sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) ); |
nkeynes@1217 | 360 | mmu_set_ext_address_space(shadow_address_space); |
nkeynes@1128 | 361 | } |
nkeynes@1128 | 362 |
.