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