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