Search
lxdream.org :: lxdream :: r1128:180abbb2a1f3
lxdream 0.9.1
released Jun 29
Download Now
changeset1128:180abbb2a1f3
parent1127:4b8194e3974c
child1129:7b16bbd6209c
authornkeynes
dateFri Sep 17 20:04:02 2010 +1000 (9 years ago)
Add missing shadow.c
src/sh4/shadow.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/shadow.c Fri Sep 17 20:04:02 2010 +1000
1.3 @@ -0,0 +1,341 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * SH4 shadow execution core - runs xlat + emu together and checks that the
1.8 + * results are the same.
1.9 + *
1.10 + * Copyright (c) 2010 Nathan Keynes.
1.11 + *
1.12 + * This program is free software; you can redistribute it and/or modify
1.13 + * it under the terms of the GNU General Public License as published by
1.14 + * the Free Software Foundation; either version 2 of the License, or
1.15 + * (at your option) any later version.
1.16 + *
1.17 + * This program is distributed in the hope that it will be useful,
1.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 + * GNU General Public License for more details.
1.21 + */
1.22 +
1.23 +#include <stdlib.h>
1.24 +#include <string.h>
1.25 +#include <assert.h>
1.26 +
1.27 +#include "clock.h"
1.28 +#include "mem.h"
1.29 +#include "sh4/sh4.h"
1.30 +#include "sh4/sh4trans.h"
1.31 +#include "sh4/mmu.h"
1.32 +
1.33 +typedef enum {
1.34 + READ_LONG,
1.35 + WRITE_LONG,
1.36 + READ_WORD,
1.37 + WRITE_WORD,
1.38 + READ_BYTE,
1.39 + WRITE_BYTE,
1.40 + PREFETCH,
1.41 + READ_BYTE_FOR_WRITE
1.42 +} MemOp;
1.43 +
1.44 +char *memOpNames[] = { "read_long", "write_long", "read_word", "write_word",
1.45 + "read_byte", "write_byte", "prefetch", "read_byte_for_write" };
1.46 +
1.47 +struct mem_log_entry {
1.48 + MemOp op;
1.49 + sh4addr_t addr;
1.50 + uint32_t value;
1.51 +};
1.52 +
1.53 +static struct sh4_registers shadow_sh4r;
1.54 +static struct mem_region_fn **log_address_space;
1.55 +static struct mem_region_fn **check_address_space;
1.56 +static struct mem_region_fn **real_address_space;
1.57 +
1.58 +#define MEM_LOG_SIZE 4096
1.59 +static struct mem_log_entry *mem_log;
1.60 +static uint32_t mem_log_posn, mem_log_size;
1.61 +static uint32_t mem_check_posn;
1.62 +
1.63 +#define IS_STORE_QUEUE(X) (((X)&0xFC000000) == 0xE0000000)
1.64 +
1.65 +static void log_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
1.66 +{
1.67 + if( mem_log_posn == mem_log_size ) {
1.68 + struct mem_log_entry *tmp = realloc(mem_log, mem_log_size * sizeof(struct mem_log_entry) * 2);
1.69 + assert( tmp != NULL );
1.70 + mem_log_size *= 2;
1.71 + mem_log = tmp;
1.72 + }
1.73 + mem_log[mem_log_posn].op = op;
1.74 + mem_log[mem_log_posn].addr = addr;
1.75 + mem_log[mem_log_posn].value = value;
1.76 + mem_log_posn++;
1.77 +}
1.78 +
1.79 +static void print_mem_op( FILE *f, MemOp op, sh4addr_t addr, uint32_t value )
1.80 +{
1.81 + if( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) {
1.82 + fprintf( f, "%s( %08X, %08X )\n", memOpNames[op], addr, value );
1.83 + } else {
1.84 + fprintf( f, "%s( %08X )\n", memOpNames[op], addr );
1.85 + }
1.86 +}
1.87 +
1.88 +static void dump_mem_ops()
1.89 +{
1.90 + for( unsigned i=0; i<mem_log_posn; i++ ) {
1.91 + print_mem_op( stderr, mem_log[i].op, mem_log[i].addr, mem_log[i].value );
1.92 + }
1.93 +}
1.94 +
1.95 +static int32_t check_mem_op( MemOp op, sh4addr_t addr, uint32_t value )
1.96 +{
1.97 + if( mem_check_posn >= mem_log_posn ) {
1.98 + fprintf( stderr, "Unexpected interpreter memory operation: " );
1.99 + print_mem_op(stderr, op, addr, value );
1.100 + abort();
1.101 + }
1.102 + if( mem_log[mem_check_posn].op != op ||
1.103 + mem_log[mem_check_posn].addr != addr ||
1.104 + (( op == WRITE_LONG || op == WRITE_WORD || op == WRITE_BYTE ) &&
1.105 + mem_log[mem_check_posn].value != value ) ) {
1.106 + fprintf(stderr, "Memory operation mismatch. Translator: " );
1.107 + print_mem_op(stderr, mem_log[mem_check_posn].op,
1.108 + mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
1.109 + fprintf(stderr, "Emulator: ");
1.110 + print_mem_op(stderr, op, addr, value );
1.111 + abort();
1.112 + }
1.113 + return mem_log[mem_check_posn++].value;
1.114 +}
1.115 +
1.116 +#define CHECK_REG(sym, name) if( xsh4r->sym != esh4r->sym ) { \
1.117 + isgood = FALSE; fprintf( stderr, name " Xlt = %08X, Emu = %08X\n", xsh4r->sym, esh4r->sym ); }
1.118 +
1.119 +static gboolean check_registers( struct sh4_registers *xsh4r, struct sh4_registers *esh4r )
1.120 +{
1.121 + gboolean isgood = TRUE;
1.122 + for( unsigned i=0; i<16; i++ ) {
1.123 + if( xsh4r->r[i] != esh4r->r[i] ) {
1.124 + isgood = FALSE;
1.125 + fprintf( stderr, "R%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r[i], esh4r->r[i] );
1.126 + }
1.127 + }
1.128 + for( unsigned i=0; i<8; i++ ) {
1.129 + if( xsh4r->r_bank[i] != esh4r->r_bank[i] ) {
1.130 + isgood = FALSE;
1.131 + fprintf( stderr, "R_BANK%d Xlt = %08X, Emu = %08X\n", i, xsh4r->r_bank[i], esh4r->r_bank[i] );
1.132 + }
1.133 + }
1.134 + for( unsigned i=0; i<16; i++ ) {
1.135 + if( xsh4r->fr[0][i] != esh4r->fr[0][i] ) {
1.136 + isgood = FALSE;
1.137 + fprintf( stderr, "FR%d Xlt = %f, Emu = %f\n", i, xsh4r->fr[0][i], esh4r->fr[0][i] );
1.138 + }
1.139 + }
1.140 + for( unsigned i=0; i<16; i++ ) {
1.141 + if( xsh4r->fr[1][i] != esh4r->fr[1][i] ) {
1.142 + isgood = FALSE;
1.143 + fprintf( stderr, "XF%d Xlt = %f, Emu = %f\n", i, xsh4r->fr[1][i], esh4r->fr[1][i] );
1.144 + }
1.145 + }
1.146 +
1.147 + CHECK_REG(t, "T");
1.148 + CHECK_REG(m, "M");
1.149 + CHECK_REG(s, "S");
1.150 + CHECK_REG(q, "Q");
1.151 + CHECK_REG(pc, "PC");
1.152 + CHECK_REG(pr, "PR");
1.153 + CHECK_REG(sr, "SR");
1.154 + CHECK_REG(fpscr, "FPSCR");
1.155 + CHECK_REG(fpul.i, "FPUL");
1.156 + if( xsh4r->mac != esh4r->mac ) {
1.157 + isgood = FALSE;
1.158 + fprintf( stderr, "MAC Xlt = %016llX, Emu = %016llX\n", xsh4r->mac, esh4r->mac );
1.159 + }
1.160 + CHECK_REG(gbr, "GBR");
1.161 + CHECK_REG(ssr, "SSR");
1.162 + CHECK_REG(spc, "SPC");
1.163 + CHECK_REG(sgr, "SGR");
1.164 + CHECK_REG(dbr, "DBR");
1.165 + CHECK_REG(vbr, "VBR");
1.166 + CHECK_REG(sh4_state, "STATE");
1.167 + if( memcmp( xsh4r->store_queue, esh4r->store_queue, sizeof(xsh4r->store_queue) ) != 0 ) {
1.168 + isgood = FALSE;
1.169 + fprintf( stderr, "Store queue Xlt =\n" );
1.170 + fwrite_dump( xsh4r->store_queue, sizeof(xsh4r->store_queue), stderr );
1.171 + fprintf( stderr, " Emu =\n" );
1.172 + fwrite_dump( esh4r->store_queue, sizeof(esh4r->store_queue), stderr );
1.173 + }
1.174 + return isgood;
1.175 +}
1.176 +
1.177 +static FASTCALL int32_t log_read_long( sh4addr_t addr )
1.178 +{
1.179 + int32_t rv = real_address_space[addr>>12]->read_long(addr);
1.180 + log_mem_op( READ_LONG, addr, rv );
1.181 + return rv;
1.182 +}
1.183 +
1.184 +static FASTCALL int32_t log_read_word( sh4addr_t addr )
1.185 +{
1.186 + int32_t rv = real_address_space[addr>>12]->read_word(addr);
1.187 + log_mem_op( READ_WORD, addr, rv );
1.188 + return rv;
1.189 +}
1.190 +
1.191 +static FASTCALL int32_t log_read_byte( sh4addr_t addr )
1.192 +{
1.193 + int32_t rv = real_address_space[addr>>12]->read_byte(addr);
1.194 + log_mem_op( READ_BYTE, addr, rv );
1.195 + return rv;
1.196 +}
1.197 +
1.198 +static FASTCALL int32_t log_read_byte_for_write( sh4addr_t addr )
1.199 +{
1.200 + int32_t rv = real_address_space[addr>>12]->read_byte_for_write(addr);
1.201 + log_mem_op( READ_BYTE_FOR_WRITE, addr, rv );
1.202 + return rv;
1.203 +}
1.204 +
1.205 +static FASTCALL void log_write_long( sh4addr_t addr, uint32_t val )
1.206 +{
1.207 + if( !IS_STORE_QUEUE(addr) )
1.208 + log_mem_op( WRITE_LONG, addr, val );
1.209 + real_address_space[addr>>12]->write_long(addr, val);
1.210 +}
1.211 +
1.212 +static FASTCALL void log_write_word( sh4addr_t addr, uint32_t val )
1.213 +{
1.214 + if( !IS_STORE_QUEUE(addr) )
1.215 + log_mem_op( WRITE_WORD, addr, val );
1.216 + real_address_space[addr>>12]->write_word(addr, val);
1.217 +}
1.218 +
1.219 +static FASTCALL void log_write_byte( sh4addr_t addr, uint32_t val )
1.220 +{
1.221 + if( !IS_STORE_QUEUE(addr) )
1.222 + log_mem_op( WRITE_BYTE, addr, val );
1.223 + real_address_space[addr>>12]->write_byte(addr, val);
1.224 +}
1.225 +
1.226 +static FASTCALL void log_prefetch( sh4addr_t addr )
1.227 +{
1.228 + log_mem_op( PREFETCH, addr, 0 );
1.229 + real_address_space[addr>>12]->prefetch(addr);
1.230 +}
1.231 +
1.232 +static FASTCALL int32_t check_read_long( sh4addr_t addr )
1.233 +{
1.234 + return check_mem_op( READ_LONG, addr, 0 );
1.235 +}
1.236 +
1.237 +static FASTCALL int32_t check_read_word( sh4addr_t addr )
1.238 +{
1.239 + return check_mem_op( READ_WORD, addr, 0 );
1.240 +}
1.241 +
1.242 +static FASTCALL int32_t check_read_byte( sh4addr_t addr )
1.243 +{
1.244 + return check_mem_op( READ_BYTE, addr, 0 );
1.245 +}
1.246 +
1.247 +static FASTCALL int32_t check_read_byte_for_write( sh4addr_t addr )
1.248 +{
1.249 + return check_mem_op( READ_BYTE_FOR_WRITE, addr, 0 );
1.250 +}
1.251 +
1.252 +static FASTCALL void check_write_long( sh4addr_t addr, uint32_t value )
1.253 +{
1.254 + if( !IS_STORE_QUEUE(addr) )
1.255 + check_mem_op( WRITE_LONG, addr, value );
1.256 +}
1.257 +
1.258 +static FASTCALL void check_write_word( sh4addr_t addr, uint32_t value )
1.259 +{
1.260 + if( !IS_STORE_QUEUE(addr) )
1.261 + check_mem_op( WRITE_WORD, addr, value );
1.262 +}
1.263 +
1.264 +static FASTCALL void check_write_byte( sh4addr_t addr, uint32_t value )
1.265 +{
1.266 + if( !IS_STORE_QUEUE(addr) )
1.267 + check_mem_op( WRITE_BYTE, addr, value );
1.268 +}
1.269 +
1.270 +static FASTCALL void check_prefetch( sh4addr_t addr )
1.271 +{
1.272 + check_mem_op( PREFETCH, addr, 0 );
1.273 +}
1.274 +
1.275 +struct mem_region_fn log_fns = { log_read_long, log_write_long,
1.276 + log_read_word, log_write_word,
1.277 + log_read_byte, log_write_byte,
1.278 + NULL, NULL, log_prefetch, log_read_byte_for_write };
1.279 +
1.280 +struct mem_region_fn check_fns = { check_read_long, check_write_long,
1.281 + check_read_word, check_write_word,
1.282 + check_read_byte, check_write_byte,
1.283 + NULL, NULL, check_prefetch, check_read_byte_for_write };
1.284 +
1.285 +
1.286 +
1.287 +
1.288 +void sh4_shadow_block_begin()
1.289 +{
1.290 + memcpy( &shadow_sh4r, &sh4r, sizeof(struct sh4_registers) );
1.291 + mem_log_posn = 0;
1.292 +}
1.293 +
1.294 +void sh4_shadow_block_end()
1.295 +{
1.296 + struct sh4_registers temp_sh4r;
1.297 +
1.298 + /* Save the end registers, and restore the state back to the start */
1.299 + memcpy( &temp_sh4r, &sh4r, sizeof(struct sh4_registers) );
1.300 + memcpy( &sh4r, &shadow_sh4r, sizeof(struct sh4_registers) );
1.301 +
1.302 + sh4_address_space = check_address_space;
1.303 + mem_check_posn = 0;
1.304 + sh4r.new_pc = sh4r.pc + 2;
1.305 + while( sh4r.slice_cycle < temp_sh4r.slice_cycle ) {
1.306 + sh4_execute_instruction();
1.307 + sh4r.slice_cycle += sh4_cpu_period;
1.308 + }
1.309 +
1.310 + if( !check_registers( &temp_sh4r, &sh4r ) ) {
1.311 + fprintf( stderr, "After executing block at %08X\n", shadow_sh4r.pc );
1.312 + abort();
1.313 + }
1.314 + if( mem_check_posn < mem_log_posn ) {
1.315 + fprintf( stderr, "Additional translator memory operations:\n" );
1.316 + while( mem_check_posn < mem_log_posn ) {
1.317 + print_mem_op( stderr, mem_log[mem_check_posn].op, mem_log[mem_check_posn].addr, mem_log[mem_check_posn].value );
1.318 + mem_check_posn++;
1.319 + }
1.320 + abort();
1.321 + }
1.322 + sh4_address_space = real_address_space;
1.323 +}
1.324 +
1.325 +
1.326 +void sh4_shadow_init()
1.327 +{
1.328 + real_address_space = sh4_address_space;
1.329 + log_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
1.330 + check_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
1.331 + for( unsigned i=0; i < (256 * 4096); i++ ) {
1.332 + log_address_space[i] = &log_fns;
1.333 + check_address_space[i] = &check_fns;
1.334 + }
1.335 +
1.336 + mem_log_size = MEM_LOG_SIZE;
1.337 + mem_log = malloc( mem_log_size * sizeof(struct mem_log_entry) );
1.338 + assert( mem_log != NULL );
1.339 +
1.340 + sh4_translate_set_callbacks( sh4_shadow_block_begin, sh4_shadow_block_end );
1.341 + sh4_translate_set_fastmem( FALSE );
1.342 + sh4_translate_set_address_space( log_address_space, log_address_space );
1.343 +}
1.344 +
.