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 Sat Aug 25 14:09:07 2012 +1000 (11 years ago)
permissions -rw-r--r--
last change Subst LDFLAGS_FOR_BUILD in configure
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 "mmio.h"
    27 #include "sh4/sh4.h"
    28 #include "sh4/sh4core.h"
    29 #include "sh4/sh4trans.h"
    30 #include "sh4/mmu.h"
    32 typedef enum {
    33     READ_LONG,
    34     WRITE_LONG,
    35     READ_WORD,
    36     WRITE_WORD,
    37     READ_BYTE,
    38     WRITE_BYTE,
    39     PREFETCH,
    40     READ_BYTE_FOR_WRITE
    41 } MemOp;
    43 char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
    44         "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
    46 struct mem_log_entry {
    47     MemOp op;
    48     sh4addr_t addr;
    49     uint32_t value;
    50 };
    52 static struct sh4_registers shadow_sh4r;
    53 static struct mem_region_fn **shadow_address_space;
    54 static struct mem_region_fn **p4_address_space;
    56 typedef enum {
    57     SHADOW_LOG,
    58     SHADOW_CHECK
    59 } shadow_mode_t;
    60 static shadow_mode_t shadow_address_mode = SHADOW_LOG;
    62 #define MEM_LOG_SIZE 4096
    63 static struct mem_log_entry *mem_log;
    64 static uint32_t mem_log_posn, mem_log_size;
    65 static uint32_t mem_check_posn;
    67 #define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
    69 static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
    70 {
    71     if( mem_log_posn == mem_log_size ) {
    72         struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
    73         assert( tmp != NULL );
    74         mem_log_size *= 2;
    75         mem_log = tmp;
    76     }
    77     mem_log[mem_log_posn].op = op;
    78     mem_log[mem_log_posn].addr = addr;
    79     mem_log[mem_log_posn].value = value;
    80     mem_log_posn++;
    81 }
    83 static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
    84 {
    85     if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
    86         fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
    87     } else {
    88         fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
    89     }
    90 }
    92 static void dump_mem_ops()
    93 {
    94     for( unsigned i=0; i<mem_log_posn; i++ ) {
    95         print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
    96     }
    97 }
    99 static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
   100 {
   101     if( mem_check_posn >= mem_log_posn ) {
   102         fprintf( stderr, "Unexpected interpreter memory operation: " );
   103         print_mem_op(stderr, op, addr, value );
   104         abort();
   105     }
   106     if( mem_log[mem_check_posn].op != op ||
   107         mem_log[mem_check_posn].addr != addr ||
   108         (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
   109            mem_log[mem_check_posn].value != value ) ) {
   110         fprintf(stderr, "Memory operation mismatch. Translator: " );
   111         print_mem_op(stderr, mem_log[mem_check_posn].op,
   112                 mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
   113         fprintf(stderr, "Emulator: ");
   114         print_mem_op(stderr, op, addr, value );
   115         abort();
   116     }
   117     return mem_log[mem_check_posn++].value;
   118 }
   120 #define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
   121     isgood = FALSE; fprintf( stderr, name "  Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
   123 static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
   124 {
   125     gboolean isgood = TRUE;
   126     for( unsigned i=0; i<16; i++ ) {
   127         if( xsh4r->r[i] != esh4r->r[i] ) {
   128             isgood = FALSE;
   129             fprintf( stderr, "R%d  Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
   130         }
   131     }
   132     for( unsigned i=0; i<8; i++ ) {
   133         if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
   134             isgood = FALSE;
   135             fprintf( stderr, "R_BANK%d  Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
   136         }
   137     }
   138     for( unsigned i=0; i<16; i++ ) {
   139         if( *((uint32_t *)&xsh4r->fr[0][i]) != *((uint32_t *)&esh4r->fr[0][i]) ) {
   140             isgood = FALSE;
   141             fprintf( stderr, "FR%d  Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[0][i],
   142                     *((uint32_t *)&xsh4r->fr[0][i]),
   143                     esh4r->fr[0][i],
   144                     *((uint32_t *)&esh4r->fr[0][i])
   145                     );
   146         }
   147     }
   148     for( unsigned i=0; i<16; i++ ) {
   149         if( *((uint32_t *)&xsh4r->fr[1][i]) != *((uint32_t *)&esh4r->fr[1][i]) ) {
   150             isgood = FALSE;
   151             fprintf( stderr, "XF%d  Xlt = %f (0x%08X), Emu = %f (0x%08X)\n", i, xsh4r->fr[1][i],
   152                     *((uint32_t *)&xsh4r->fr[1][i]),
   153                     esh4r->fr[1][i],
   154                     *((uint32_t *)&esh4r->fr[1][i])
   155                     );
   156         }
   157     }
   159     CHECK_REG(t, "T");
   160     CHECK_REG(m, "M");
   161     CHECK_REG(s, "S");
   162     CHECK_REG(q, "Q");
   163     CHECK_REG(pc, "PC");
   164     CHECK_REG(pr, "PR");
   165     CHECK_REG(sr, "SR");
   166     CHECK_REG(fpscr, "FPSCR");
   167     CHECK_REG(fpul.i, "FPUL");
   168     if( xsh4r->mac != esh4r->mac ) {
   169         isgood = FALSE;
   170         fprintf( stderr, "MAC  Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
   171     }
   172     CHECK_REG(gbr, "GBR");
   173     CHECK_REG(ssr, "SSR");
   174     CHECK_REG(spc, "SPC");
   175     CHECK_REG(sgr, "SGR");
   176     CHECK_REG(dbr, "DBR");
   177     CHECK_REG(vbr, "VBR");
   178     CHECK_REG(sh4_state, "STATE");
   179     if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
   180         isgood = FALSE;
   181         fprintf( stderr, "Store queue  Xlt =\n" );
   182         fwrite_dump( (unsigned char *)xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
   183         fprintf( stderr, "             Emu =\n" );
   184         fwrite_dump( (unsigned char *)esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
   185     }
   186     return isgood;
   187 }
   189 static mem_region_fn_t real_region( sh4addr_t addr )
   190 {
   191     if( addr >= 0xE0000000 )
   192         return p4_address_space[VMA_TO_EXT_ADDR(addr)>>12];
   193     else
   194         return ext_address_space[VMA_TO_EXT_ADDR(addr)>>12];
   195 }
   197 static FASTCALL int32_t shadow_read_long( sh4addr_t addr )
   198 {
   199     if( shadow_address_mode == SHADOW_LOG ) {
   200         int32_t rv = real_region(addr)->read_long(addr);
   201         log_mem_op( READ_LONG, addr, rv );
   202         return rv;
   203     } else {
   204         return check_mem_op( READ_LONG, addr, 0 );
   205     }
   206 }
   208 static FASTCALL int32_t shadow_read_word( sh4addr_t addr )
   209 {
   210     if( shadow_address_mode == SHADOW_LOG ) {
   211         int32_t rv = real_region(addr)->read_word(addr);
   212         log_mem_op( READ_WORD, addr, rv );
   213         return rv;
   214     } else {
   215         return check_mem_op( READ_WORD, addr, 0 );
   216     }
   217 }
   219 static FASTCALL int32_t shadow_read_byte( sh4addr_t addr )
   220 {
   221     if( shadow_address_mode == SHADOW_LOG ) {
   222         int32_t rv = real_region(addr)->read_byte(addr);
   223         log_mem_op( READ_BYTE, addr, rv );
   224         return rv;
   225     } else {
   226         return check_mem_op( READ_BYTE, addr, 0 );
   227     }
   228 }
   230 static FASTCALL int32_t shadow_read_byte_for_write( sh4addr_t addr )
   231 {
   232     if( shadow_address_mode == SHADOW_LOG ) {
   233         int32_t rv = real_region(addr)->read_byte_for_write(addr);
   234         log_mem_op( READ_BYTE_FOR_WRITE, addr, rv );
   235         return rv;
   236     } else {
   237         return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
   238     }
   239 }
   241 static FASTCALL void shadow_write_long( sh4addr_t addr, uint32_t val )
   242 {
   243     if( shadow_address_mode == SHADOW_LOG ) {
   244         real_region(addr)->write_long(addr, val);
   245         if( !IS_STORE_QUEUE(addr) )
   246             log_mem_op( WRITE_LONG, addr, val );
   247     } else {
   248         if( !IS_STORE_QUEUE(addr) ) {
   249             check_mem_op( WRITE_LONG, addr, val );
   250         } else {
   251             real_region(addr)->write_long(addr, val);
   252         }
   253     }
   254 }
   256 static FASTCALL void shadow_write_word( sh4addr_t addr, uint32_t val )
   257 {
   258     if( shadow_address_mode == SHADOW_LOG ) {
   259         real_region(addr)->write_word(addr, val);
   260         if( !IS_STORE_QUEUE(addr) )
   261             log_mem_op( WRITE_WORD, addr, val );
   262     } else {
   263         if( !IS_STORE_QUEUE(addr) ) {
   264             check_mem_op( WRITE_WORD, addr, val );
   265         } else {
   266             real_region(addr)->write_word(addr, val);
   267         }
   268     }
   269 }
   271 static FASTCALL void shadow_write_byte( sh4addr_t addr, uint32_t val )
   272 {
   273     if( shadow_address_mode == SHADOW_LOG ) {
   274         real_region(addr)->write_byte(addr, val);
   275         if( !IS_STORE_QUEUE(addr) )
   276             log_mem_op( WRITE_BYTE, addr, val );
   277     } else {
   278         if( !IS_STORE_QUEUE(addr) ) {
   279             check_mem_op( WRITE_BYTE, addr, val );
   280         } else {
   281             real_region(addr)->write_byte(addr, val);
   282         }
   283     }
   284 }
   286 static FASTCALL void shadow_prefetch( sh4addr_t addr )
   287 {
   288     if( shadow_address_mode == SHADOW_LOG ) {
   289         real_region(addr)->prefetch(addr);
   290         log_mem_op( PREFETCH, addr, 0 );
   291     } else {
   292         check_mem_op( PREFETCH, addr, 0 );
   293     }
   294 }
   295 struct mem_region_fn shadow_fns = {
   296         shadow_read_long, shadow_write_long,
   297         shadow_read_word, shadow_write_word,
   298         shadow_read_byte, shadow_write_byte,
   299         NULL, NULL, shadow_prefetch, shadow_read_byte_for_write };
   301 void sh4_shadow_block_begin()
   302 {
   303     memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
   304     mem_log_posn = 0;
   305 }
   307 void sh4_shadow_block_end()
   308 {
   309     struct sh4_registers temp_sh4r;
   311     /* Save the end registers, and restore the state back to the start */
   312     memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
   313     memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
   315     shadow_address_mode = SHADOW_CHECK;
   316     mem_check_posn = 0;
   317     sh4r.new_pc = sh4r.pc + 2;
   318     while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
   319         sh4_execute_instruction();
   320         sh4r.slice_cycle += sh4_cpu_period;
   321     }
   323     if( !check_registers( &temp_sh4r, &sh4r ) ) {
   324         fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
   325         fprintf( stderr, "Translated block was:\n" );
   326         sh4_translate_dump_block(shadow_sh4r.pc);
   327         abort();
   328     }
   329     if( mem_check_posn < mem_log_posn ) {
   330         fprintf( stderr, "Additional translator memory operations:\n" );
   331         while( mem_check_posn < mem_log_posn ) {
   332             print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
   333             mem_check_posn++;
   334         }
   335         abort();
   336     }
   337     shadow_address_mode = SHADOW_LOG;
   338 }
   341 void sh4_shadow_init()
   342 {
   343     shadow_address_mode = SHADOW_LOG;
   344     p4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 );
   345     shadow_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 32 );
   346     for( unsigned i=0; i < (32 * 4096); i++ ) {
   347         shadow_address_space[i] = &shadow_fns;
   348     }
   350     mem_log_size = MEM_LOG_SIZE;
   351     mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
   352     assert( mem_log != NULL );
   354     sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
   355     sh4_translate_set_fastmem( FALSE );
   356     memcpy( p4_address_space, sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS),
   357             sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) );
   358     memcpy( sh4_address_space + (0xE0000000>>LXDREAM_PAGE_BITS), shadow_address_space,
   359             sizeof(mem_region_fn_t) * (0x20000000>>LXDREAM_PAGE_BITS) );
   360     mmu_set_ext_address_space(shadow_address_space);
   361 }
.