Search
lxdream.org :: lxdream/src/sh4/shadow.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/shadow.c
changeset 1191:12fdf3aafcd4
prev1128:180abbb2a1f3
next1194:ee6ce5804608
author nkeynes
date Fri Dec 02 18:18:04 2011 +1000 (8 years ago)
permissions -rw-r--r--
last change SH4 shadow-mode tweaks
- Fix exceptions generated by the translator to account for the excepting
instruction(s) in the cycle counts.
- Compare floating point regs bitwise rather than with FP comparisons
(otherwise can fail due to nan != nan)
- Dump the translated block when we abort with an inconsistency
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/sh4trans.h"
    28 #include "sh4/mmu.h"
    30 typedef enum {
    31     READ_LONG,
    32     WRITE_LONG,
    33     READ_WORD,
    34     WRITE_WORD,
    35     READ_BYTE,
    36     WRITE_BYTE,
    37     PREFETCH,
    38     READ_BYTE_FOR_WRITE
    39 } MemOp;
    41 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
    42         "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
    44 struct mem_log_entry {
    45     MemOp op;
    46     sh4addr_t addr;
    47     uint32_t value;
    48 };
    50 static struct sh4_registers shadow_sh4r;
    51 static struct mem_region_fn **log_address_space;
    52 static struct mem_region_fn **check_address_space;
    53 static struct mem_region_fn **real_address_space;
    55 #define MEM_LOG_SIZE 4096
    56 static struct mem_log_entry *mem_log;
    57 static uint32_t mem_log_posn, mem_log_size;
    58 static uint32_t mem_check_posn;
    60 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
    62 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
    63 {
    64     if( mem_log_posn == mem_log_size ) {
    65         struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
    66         assert( tmp != NULL );
    67         mem_log_size *= 2;
    68         mem_log = tmp;
    69     }
    70     mem_log[mem_log_posn].op = op;
    71     mem_log[mem_log_posn].addr = addr;
    72     mem_log[mem_log_posn].value = value;
    73     mem_log_posn++;
    74 }
    76 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
    77 {
    78     if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
    79         fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
    80     } else {
    81         fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
    82     }
    83 }
    85 static void dump_mem_ops()
    86 {
    87     for( unsigned i=0; i<mem_log_posn; i++ ) {
    88         print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
    89     }
    90 }
    92 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
    93 {
    94     if( mem_check_posn >= mem_log_posn ) {
    95         fprintf( stderr, "Unexpected interpreter memory operation: " );
    96         print_mem_op(stderr, op, addr, value );
    97         abort();
    98     }
    99     if( mem_log[mem_check_posn].op != op ||
   100         mem_log[mem_check_posn].addr != addr ||
   101         (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
   102            mem_log[mem_check_posn].value != value ) ) {
   103         fprintf(stderr, "Memory operation mismatch. Translator: " );
   104         print_mem_op(stderr, mem_log[mem_check_posn].op,
   105                 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
   106         fprintf(stderr, "Emulator: ");
   107         print_mem_op(stderr, op, addr, value );
   108         abort();
   109     }
   110     return mem_log[mem_check_posn++].value;
   111 }
   113 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
   114     isgood = FALSE; fprintf( stderr, name "  Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
   116 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
   117 {
   118     gboolean isgood = TRUE;
   119     for( unsigned i=0; i<16; i++ ) {
   120         if( xsh4r->r[i] != esh4r->r[i] ) {
   121             isgood = FALSE;
   122             fprintf( stderr, "R%d  Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
   123         }
   124     }
   125     for( unsigned i=0; i<8; i++ ) {
   126         if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
   127             isgood = FALSE;
   128             fprintf( stderr, "R_BANK%d  Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
   129         }
   130     }
   131     for( unsigned i=0; i<16; i++ ) {
   132         if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
   133             isgood = FALSE;
   134             fprintf( stderr, "FR%d  Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i],
   135                     *((uint32_t *)&xsh4r->fr[0][i]),
   136                     esh4r->fr[0][i],
   137                     *((uint32_t *)&esh4r->fr[0][i])
   138                     );
   139         }
   140     }
   141     for( unsigned i=0; i<16; i++ ) {
   142         if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
   143             isgood = FALSE;
   144             fprintf( stderr, "XF%d  Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i],
   145                     *((uint32_t *)&xsh4r->fr[1][i]),
   146                     esh4r->fr[1][i],
   147                     *((uint32_t *)&esh4r->fr[1][i])
   148                     );
   149         }
   150     }
   152     CHECK_REG(t, "T");
   153     CHECK_REG(m, "M");
   154     CHECK_REG(s, "S");
   155     CHECK_REG(q, "Q");
   156     CHECK_REG(pc, "PC");
   157     CHECK_REG(pr, "PR");
   158     CHECK_REG(sr, "SR");
   159     CHECK_REG(fpscr, "FPSCR");
   160     CHECK_REG(fpul.i, "FPUL");
   161     if( xsh4r->mac != esh4r->mac ) {
   162         isgood = FALSE;
   163         fprintf( stderr, "MAC  Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
   164     }
   165     CHECK_REG(gbr, "GBR");
   166     CHECK_REG(ssr, "SSR");
   167     CHECK_REG(spc, "SPC");
   168     CHECK_REG(sgr, "SGR");
   169     CHECK_REG(dbr, "DBR");
   170     CHECK_REG(vbr, "VBR");
   171     CHECK_REG(sh4_state, "STATE");
   172     if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
   173         isgood = FALSE;
   174         fprintf( stderr, "Store queue  Xlt =\n" );
   175         fwrite_dump( xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
   176         fprintf( stderr, "             Emu =\n" );
   177         fwrite_dump( esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
   178     }
   179     return isgood;
   180 }
   182 static FASTCALL int32_t log_read_long( sh4addr_t addr )
   183 {
   184     int32_t rv = real_address_space[addr>>12]->read_long(addr);
   185     log_mem_op( READ_LONG, addr, rv );
   186     return rv;
   187 }
   189 static FASTCALL int32_t log_read_word( sh4addr_t addr )
   190 {
   191     int32_t rv = real_address_space[addr>>12]->read_word(addr);
   192     log_mem_op( READ_WORD, addr, rv );
   193     return rv;
   194 }
   196 static FASTCALL int32_t log_read_byte( sh4addr_t addr )
   197 {
   198     int32_t rv = real_address_space[addr>>12]->read_byte(addr);
   199     log_mem_op( READ_BYTE, addr, rv );
   200     return rv;
   201 }
   203 static FASTCALL int32_t log_read_byte_for_write( sh4addr_t addr )
   204 {
   205     int32_t rv = real_address_space[addr>>12]->read_byte_for_write(addr);
   206     log_mem_op( READ_BYTE_FOR_WRITE, addr, rv );
   207     return rv;
   208 }
   210 static FASTCALL void log_write_long( sh4addr_t addr, uint32_t val )
   211 {
   212     if( !IS_STORE_QUEUE(addr) )
   213         log_mem_op( WRITE_LONG, addr, val );
   214     real_address_space[addr>>12]->write_long(addr, val);
   215 }
   217 static FASTCALL void log_write_word( sh4addr_t addr, uint32_t val )
   218 {
   219     if( !IS_STORE_QUEUE(addr) )
   220         log_mem_op( WRITE_WORD, addr, val );
   221     real_address_space[addr>>12]->write_word(addr, val);
   222 }
   224 static FASTCALL void log_write_byte( sh4addr_t addr, uint32_t val )
   225 {
   226     if( !IS_STORE_QUEUE(addr) )
   227         log_mem_op( WRITE_BYTE, addr, val );
   228     real_address_space[addr>>12]->write_byte(addr, val);
   229 }
   231 static FASTCALL void log_prefetch( sh4addr_t addr )
   232 {
   233     log_mem_op( PREFETCH, addr, 0 );
   234     real_address_space[addr>>12]->prefetch(addr);
   235 }
   237 static FASTCALL int32_t check_read_long( sh4addr_t addr )
   238 {
   239     return check_mem_op( READ_LONG, addr, 0 );
   240 }
   242 static FASTCALL int32_t check_read_word( sh4addr_t addr )
   243 {
   244     return check_mem_op( READ_WORD, addr, 0 );
   245 }
   247 static FASTCALL int32_t check_read_byte( sh4addr_t addr )
   248 {
   249     return check_mem_op( READ_BYTE, addr, 0 );
   250 }
   252 static FASTCALL int32_t check_read_byte_for_write( sh4addr_t addr )
   253 {
   254     return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
   255 }
   257 static FASTCALL void check_write_long( sh4addr_t addr, uint32_t value )
   258 {
   259     if( !IS_STORE_QUEUE(addr) )
   260         check_mem_op( WRITE_LONG, addr, value );
   261 }
   263 static FASTCALL void check_write_word( sh4addr_t addr, uint32_t value )
   264 {
   265     if( !IS_STORE_QUEUE(addr) )
   266         check_mem_op( WRITE_WORD, addr, value );
   267 }
   269 static FASTCALL void check_write_byte( sh4addr_t addr, uint32_t value )
   270 {
   271     if( !IS_STORE_QUEUE(addr) )
   272         check_mem_op( WRITE_BYTE, addr, value );
   273 }
   275 static FASTCALL void check_prefetch( sh4addr_t addr )
   276 {
   277     check_mem_op( PREFETCH, addr, 0 );
   278 }
   280 struct mem_region_fn log_fns = { log_read_long, log_write_long,
   281         log_read_word, log_write_word,
   282         log_read_byte, log_write_byte,
   283         NULL, NULL, log_prefetch, log_read_byte_for_write };
   285 struct mem_region_fn check_fns = { check_read_long, check_write_long,
   286         check_read_word, check_write_word,
   287         check_read_byte, check_write_byte,
   288         NULL, NULL, check_prefetch, check_read_byte_for_write };
   293 void sh4_shadow_block_begin()
   294 {
   295     memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
   296     mem_log_posn = 0;
   297 }
   299 void sh4_shadow_block_end()
   300 {
   301     struct sh4_registers temp_sh4r;
   303     /* Save the end registers, and restore the state back to the start */
   304     memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
   305     memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
   307     sh4_address_space = check_address_space;
   308     mem_check_posn = 0;
   309     sh4r.new_pc = sh4r.pc + 2;
   310     while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
   311         sh4_execute_instruction();
   312         sh4r.slice_cycle += sh4_cpu_period;
   313     }
   315     if( !check_registers( &temp_sh4r, &sh4r ) ) {
   316         fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
   317         fprintf( stderr, "Translated block was:\n" );
   318         sh4_translate_dump_block(shadow_sh4r.pc);
   319         abort();
   320     }
   321     if( mem_check_posn < mem_log_posn ) {
   322         fprintf( stderr, "Additional translator memory operations:\n" );
   323         while( mem_check_posn < mem_log_posn ) {
   324             print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
   325             mem_check_posn++;
   326         }
   327         abort();
   328     }
   329     sh4_address_space = real_address_space;
   330 }
   333 void sh4_shadow_init()
   334 {
   335     real_address_space = sh4_address_space;
   336     log_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
   337     check_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
   338     for( unsigned i=0; i < (256 * 4096); i++ ) {
   339         log_address_space[i] = &log_fns;
   340         check_address_space[i] = &check_fns;
   341     }
   343     mem_log_size = MEM_LOG_SIZE;
   344     mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
   345     assert( mem_log != NULL );
   347     sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
   348     sh4_translate_set_fastmem( FALSE );
   349     sh4_translate_set_address_space( log_address_space, log_address_space );
   350 }
.