Search
lxdream.org :: lxdream/src/sh4/shadow.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/shadow.c
changeset 1217:677b1d85f1b4
prev1202:01ae5cbad4c8
next1298: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
.