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