Search
lxdream.org :: lxdream/src/sh4/sh4trans.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4trans.c
changeset 571:9bc09948d0f2
prev569:a1c49e1e8776
next577:a181aeacd6e8
author nkeynes
date Mon Jan 14 09:08:58 2008 +0000 (14 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Fix TRAPA in emulator core
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * 
     4  * SH4 translation core module. This part handles the non-target-specific
     5  * section of the translation.
     6  *
     7  * Copyright (c) 2005 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  */
    19 #include <assert.h>
    20 #include <setjmp.h>
    21 #include "eventq.h"
    22 #include "syscall.h"
    23 #include "clock.h"
    24 #include "sh4/sh4core.h"
    25 #include "sh4/sh4trans.h"
    26 #include "sh4/xltcache.h"
    29 static jmp_buf xlat_jmp_buf;
    30 /**
    31  * Execute a timeslice using translated code only (ie translate/execute loop)
    32  * Note this version does not support breakpoints
    33  */
    34 uint32_t sh4_xlat_run_slice( uint32_t nanosecs ) 
    35 {
    36     sh4r.slice_cycle = 0;
    38     if( sh4r.sh4_state != SH4_STATE_RUNNING ) {
    39 	if( sh4r.event_pending < nanosecs ) {
    40 	    sh4r.sh4_state = SH4_STATE_RUNNING;
    41 	    sh4r.slice_cycle = sh4r.event_pending;
    42 	}
    43     }
    45     int jmp = setjmp(xlat_jmp_buf);
    47     void * (*code)() = NULL;
    48     while( sh4r.slice_cycle < nanosecs ) {
    49 	if( sh4r.event_pending <= sh4r.slice_cycle ) {
    50 	    if( sh4r.event_types & PENDING_EVENT ) {
    51 		event_execute();
    52 	    }
    53 	    /* Eventq execute may (quite likely) deliver an immediate IRQ */
    54 	    if( sh4r.event_types & PENDING_IRQ ) {
    55 		sh4_accept_interrupt();
    56 		code = NULL;
    57 	    }
    58 	}
    60 	if( code == NULL ) {
    61 	    if( sh4r.pc > 0xFFFFFF00 ) {
    62 		syscall_invoke( sh4r.pc );
    63 		sh4r.in_delay_slot = 0;
    64 		sh4r.pc = sh4r.pr;
    65 	    }
    67 	    code = xlat_get_code_by_vma( sh4r.pc );
    68 	    if( code == NULL ) {
    69 		code = sh4_translate_basic_block( sh4r.pc );
    70 	    }
    71 	}
    72 	code = code();
    73     }
    75     if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
    76 	TMU_run_slice( nanosecs );
    77 	SCIF_run_slice( nanosecs );
    78     }
    79     return nanosecs;
    80 }
    82 uint8_t *xlat_output;
    83 struct xlat_recovery_record xlat_recovery[MAX_RECOVERY_SIZE];
    84 uint32_t xlat_recovery_posn;
    86 /**
    87  * Translate a linear basic block, ie all instructions from the start address
    88  * (inclusive) until the next branch/jump instruction or the end of the page
    89  * is reached.
    90  * @return the address of the translated block
    91  * eg due to lack of buffer space.
    92  */
    93 void * sh4_translate_basic_block( sh4addr_t start )
    94 {
    95     sh4addr_t pc = start;
    96     sh4addr_t lastpc = (pc&0xFFFFF000)+0x1000;
    97     int done;
    98     xlat_cache_block_t block = xlat_start_block( start );
    99     xlat_output = (uint8_t *)block->code;
   100     xlat_recovery_posn = 0;
   101     uint8_t *eob = xlat_output + block->size;
   102     sh4_translate_begin_block(pc);
   104     do {
   105 	if( eob - xlat_output < MAX_INSTRUCTION_SIZE ) {
   106 	    uint8_t *oldstart = block->code;
   107 	    block = xlat_extend_block( xlat_output - oldstart + MAX_INSTRUCTION_SIZE );
   108 	    xlat_output = block->code + (xlat_output - oldstart);
   109 	    eob = block->code + block->size;
   110 	}
   111 	done = sh4_translate_instruction( pc ); 
   112 	assert( xlat_output <= eob );
   113 	pc += 2;
   114 	if ( pc >= lastpc ) {
   115 	    done = 2;
   116 	}
   117     } while( !done );
   118     pc += (done - 2);
   119     if( eob - xlat_output < EPILOGUE_SIZE ) {
   120 	uint8_t *oldstart = block->code;
   121 	block = xlat_extend_block( xlat_output - oldstart + EPILOGUE_SIZE );
   122 	xlat_output = block->code + (xlat_output - oldstart);
   123     }	
   124     sh4_translate_end_block(pc);
   126     /* Write the recovery records onto the end of the code block */
   127     uint32_t recovery_size = sizeof(struct xlat_recovery_record)*xlat_recovery_posn;
   128     uint32_t finalsize = xlat_output - block->code + recovery_size;
   129     if( finalsize > block->size ) {
   130 	uint8_t *oldstart = block->code;
   131 	block = xlat_extend_block( finalsize );
   132 	xlat_output = block->code + (xlat_output - oldstart);
   133     }
   134     memcpy( xlat_output, xlat_recovery, recovery_size);
   135     block->recover_table = (xlat_recovery_record_t)xlat_output;
   136     block->recover_table_size = xlat_recovery_posn;
   137     xlat_commit_block( finalsize, pc-start );
   138     return block->code;
   139 }
   141 /**
   142  * Translate a linear basic block to a temporary buffer, execute it, and return
   143  * the result of the execution. The translation is discarded.
   144  */
   145 void *sh4_translate_and_run( sh4addr_t start )
   146 {
   147     unsigned char buf[65536];
   149     sh4addr_t pc = start;
   150     int done;
   151     xlat_output = buf;
   152     uint8_t *eob = xlat_output + sizeof(buf);
   154     sh4_translate_begin_block(pc);
   156     while( (done = sh4_translate_instruction( pc )) == 0 ) {
   157 	assert( (eob - xlat_output) >= MAX_INSTRUCTION_SIZE );
   158 	pc += 2;
   159     }
   160     pc+=2;
   161     sh4_translate_end_block(pc);
   163     void * (*code)() = (void *)buf;
   164     return code();
   165 }
   167 /**
   168  * "Execute" the supplied recovery record. Currently this only updates
   169  * sh4r.pc and sh4r.slice_cycle according to the currently executing
   170  * instruction. In future this may be more sophisticated (ie will
   171  * call into generated code).
   172  */
   173 void sh4_translate_run_recovery( xlat_recovery_record_t recovery )
   174 {
   175     sh4r.slice_cycle += (recovery->sh4_icount * sh4_cpu_period);
   176     sh4r.pc += (recovery->sh4_icount<<1);
   177 }
   179 void sh4_translate_unwind_stack( gboolean abort_after, unwind_thunk_t thunk )
   180 {
   181     void *pc = xlat_get_native_pc();
   182     if( pc == NULL ) {
   183 	// This should never happen - indicative of a bug somewhere.
   184 	FATAL("Attempted to unwind stack, but translator is not running or stack is corrupt");
   185     }
   186     void *code = xlat_get_code( sh4r.pc );
   187     xlat_recovery_record_t recover = xlat_get_recovery(code, pc, TRUE);
   188     if( recover != NULL ) {
   189 	// Can be null if there is no recovery necessary
   190 	sh4_translate_run_recovery(recover);
   191     }
   192     if( thunk != NULL ) {
   193 	thunk();
   194     }
   195     // finally longjmp back into sh4_xlat_run_slice
   196     longjmp(xlat_jmp_buf, 1);
   197 } 
   199 /**
   200  * Exit the current block at the end of the current instruction, flush the
   201  * translation cache (completely) and return control to sh4_xlat_run_slice.
   202  *
   203  * As a special case, if the current instruction is actually the last 
   204  * instruction in the block (ie it's in a delay slot), this function 
   205  * returns to allow normal completion of the translation block. Otherwise
   206  * this function never returns.
   207  *
   208  * Must only be invoked (indirectly) from within translated code.
   209  */
   210 void sh4_translate_flush_cache()
   211 {
   212     void *pc = xlat_get_native_pc();
   213     if( pc == NULL ) {
   214 	// This should never happen - indicative of a bug somewhere.
   215 	FATAL("Attempted to unwind stack, but translator is not running or stack is corrupt");
   216     }
   217     void *code = xlat_get_code( sh4r.pc );
   218     xlat_recovery_record_t recover = xlat_get_recovery(code, pc, TRUE);
   219     if( recover != NULL ) {
   220 	// Can be null if there is no recovery necessary
   221 	sh4_translate_run_recovery(recover);
   222 	xlat_flush_cache();
   223 	longjmp(xlat_jmp_buf, 1);
   224     } else {
   225 	xlat_flush_cache();
   226 	return;
   227     }
   228 }
   230 void *xlat_get_code_by_vma( sh4vma_t vma )
   231 {
   232     void *result = NULL;
   234     if( !IS_IN_ICACHE(vma) ) {
   235 	if( !mmu_update_icache(sh4r.pc) ) {
   236 	    // fault - off to the fault handler
   237 	    if( !mmu_update_icache(sh4r.pc) ) {
   238 		// double fault - halt
   239 		dreamcast_stop();
   240 		ERROR( "Double fault - halting" );
   241 		return NULL;
   242 	    }
   243 	}
   244     }
   245     if( sh4_icache.page_vma != -1 ) {
   246 	result = xlat_get_code( GET_ICACHE_PHYS(vma) );
   247     }
   249     return result;
   250 }
.