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