Search
lxdream.org :: lxdream/src/sh4/sh4trans.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4trans.c
changeset 914:72abecf5a315
prev906:268ea359f884
next936:f394309c399a
next953:f4a156508ad1
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
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 "eventq.h"
    21 #include "syscall.h"
    22 #include "clock.h"
    23 #include "dreamcast.h"
    24 #include "sh4/sh4core.h"
    25 #include "sh4/sh4trans.h"
    26 #include "sh4/xltcache.h"
    29 /**
    30  * Execute a timeslice using translated code only (ie translate/execute loop)
    31  */
    32 uint32_t sh4_translate_run_slice( uint32_t nanosecs ) 
    33 {
    34     void * (*code)() = NULL;
    35     while( sh4r.slice_cycle < nanosecs ) {
    36         if( sh4r.event_pending <= sh4r.slice_cycle ) {
    37             if( sh4r.event_types & PENDING_EVENT ) {
    38                 event_execute();
    39             }
    40             /* Eventq execute may (quite likely) deliver an immediate IRQ */
    41             if( sh4r.event_types & PENDING_IRQ ) {
    42                 sh4_accept_interrupt();
    43                 code = NULL;
    44             }
    45         }
    47         if( code == NULL ) {
    48             if( sh4r.pc > 0xFFFFFF00 ) {
    49                 syscall_invoke( sh4r.pc );
    50                 sh4r.in_delay_slot = 0;
    51                 sh4r.pc = sh4r.pr;
    52             }
    54             code = xlat_get_code_by_vma( sh4r.pc );
    55             if( code == NULL || (sh4r.fpscr & (FPSCR_PR|FPSCR_SZ)) != XLAT_BLOCK_FPSCR(code) ) {
    56                 code = sh4_translate_basic_block( sh4r.pc );
    57             }
    58         }
    59         code = code();
    60     }
    61     return nanosecs;
    62 }
    64 uint8_t *xlat_output;
    65 xlat_cache_block_t xlat_current_block;
    66 struct xlat_recovery_record xlat_recovery[MAX_RECOVERY_SIZE];
    67 uint32_t xlat_recovery_posn;
    69 void sh4_translate_add_recovery( uint32_t icount )
    70 {
    71     xlat_recovery[xlat_recovery_posn].xlat_offset = 
    72         ((uintptr_t)xlat_output) - ((uintptr_t)xlat_current_block->code);
    73     xlat_recovery[xlat_recovery_posn].sh4_icount = icount;
    74     xlat_recovery_posn++;
    75 }
    77 /**
    78  * Translate a linear basic block, ie all instructions from the start address
    79  * (inclusive) until the next branch/jump instruction or the end of the page
    80  * is reached.
    81  * @param start VMA of the block start (which must already be in the icache)
    82  * @return the address of the translated block
    83  * eg due to lack of buffer space.
    84  */
    85 void * sh4_translate_basic_block( sh4addr_t start )
    86 {
    87     sh4addr_t pc = start;
    88     sh4addr_t lastpc = (pc&0xFFFFF000)+0x1000;
    89     int done, i;
    90     xlat_current_block = xlat_start_block( GET_ICACHE_PHYS(start) );
    91     xlat_output = (uint8_t *)xlat_current_block->code;
    92     xlat_recovery_posn = 0;
    93     uint8_t *eob = xlat_output + xlat_current_block->size;
    95     if( GET_ICACHE_END() < lastpc ) {
    96         lastpc = GET_ICACHE_END();
    97     }
    99     sh4_translate_begin_block(pc);
   101     do {
   102         /* check for breakpoints at this pc */
   103         for( i=0; i<sh4_breakpoint_count; i++ ) {
   104             if( sh4_breakpoints[i].address == pc ) {
   105                 sh4_translate_emit_breakpoint(pc);
   106                 break;
   107             }
   108         }
   109         if( eob - xlat_output < MAX_INSTRUCTION_SIZE ) {
   110             uint8_t *oldstart = xlat_current_block->code;
   111             xlat_current_block = xlat_extend_block( xlat_output - oldstart + MAX_INSTRUCTION_SIZE );
   112             xlat_output = xlat_current_block->code + (xlat_output - oldstart);
   113             eob = xlat_current_block->code + xlat_current_block->size;
   114         }
   115         done = sh4_translate_instruction( pc ); 
   116         assert( xlat_output <= eob );
   117         pc += 2;
   118         if ( pc >= lastpc ) {
   119             done = 2;
   120         }
   121     } while( !done );
   122     pc += (done - 2);
   124     // Add end-of-block recovery for post-instruction checks
   125     sh4_translate_add_recovery( (pc - start)>>1 ); 
   127     int epilogue_size = sh4_translate_end_block_size();
   128     uint32_t recovery_size = sizeof(struct xlat_recovery_record)*xlat_recovery_posn;
   129     uint32_t finalsize = (xlat_output - xlat_current_block->code) + epilogue_size + recovery_size;
   130     if( xlat_current_block->size < finalsize ) {
   131         uint8_t *oldstart = xlat_current_block->code;
   132         xlat_current_block = xlat_extend_block( finalsize );
   133         xlat_output = xlat_current_block->code + (xlat_output - oldstart);
   134     }	
   135     sh4_translate_end_block(pc);
   136     assert( xlat_output <= (xlat_current_block->code + xlat_current_block->size - recovery_size) );
   138     /* Write the recovery records onto the end of the code block */
   139     memcpy( xlat_output, xlat_recovery, recovery_size);
   140     xlat_current_block->recover_table_offset = xlat_output - (uint8_t *)xlat_current_block->code;
   141     xlat_current_block->recover_table_size = xlat_recovery_posn;
   142     xlat_current_block->fpscr = sh4r.fpscr & (FPSCR_PR|FPSCR_SZ);
   143     xlat_current_block->fpscr_mask = (FPSCR_PR|FPSCR_SZ);
   144     xlat_commit_block( finalsize, pc-start );
   145     return xlat_current_block->code;
   146 }
   148 /**
   149  * "Execute" the supplied recovery record. Currently this only updates
   150  * sh4r.pc and sh4r.slice_cycle according to the currently executing
   151  * instruction. In future this may be more sophisticated (ie will
   152  * call into generated code).
   153  */
   154 void sh4_translate_run_recovery( xlat_recovery_record_t recovery )
   155 {
   156     sh4r.slice_cycle += (recovery->sh4_icount * sh4_cpu_period);
   157     sh4r.pc += (recovery->sh4_icount<<1);
   158 }
   160 void sh4_translate_exit_recover( )
   161 {
   162     void *code = xlat_get_code_by_vma( sh4r.pc );
   163     if( code != NULL ) {
   164         uint32_t size = xlat_get_code_size( code );
   165         void *pc = xlat_get_native_pc( code, size );
   166         if( pc != NULL ) {
   167             // could be null if we're not actually running inside the translator
   168             xlat_recovery_record_t recover = xlat_get_post_recovery(code, pc, TRUE);
   169             if( recover != NULL ) {
   170                 // Can be null if there is no recovery necessary
   171                 sh4_translate_run_recovery(recover);
   172             }
   173         }
   174     }
   175 }
   177 void FASTCALL sh4_translate_breakpoint_hit(uint32_t pc)
   178 {
   179     if( sh4_starting && sh4r.slice_cycle == 0 && pc == sh4r.pc ) {
   180         return;
   181     }
   182     sh4_core_exit( CORE_EXIT_BREAKPOINT );
   183 }
   185 /**
   186  * Exit the current block at the end of the current instruction, flush the
   187  * translation cache (completely) and return control to sh4_xlat_run_slice.
   188  *
   189  * As a special case, if the current instruction is actually the last 
   190  * instruction in the block (ie it's in a delay slot), this function 
   191  * returns to allow normal completion of the translation block. Otherwise
   192  * this function never returns.
   193  *
   194  * Must only be invoked (indirectly) from within translated code.
   195  */
   196 gboolean sh4_translate_flush_cache()
   197 {
   198     void *code = xlat_get_code_by_vma( sh4r.pc );
   199     if( code != NULL ) {
   200         uint32_t size = xlat_get_code_size( code );
   201         void *pc = xlat_get_native_pc( code, size );
   202         assert( pc != NULL );
   204         xlat_recovery_record_t recover = xlat_get_post_recovery(code, pc, FALSE);
   205         if( recover != NULL ) {
   206             // Can be null if there is no recovery necessary
   207             sh4_translate_run_recovery(recover);
   208             xlat_flush_cache();
   209             return TRUE;
   210         } else {
   211             xlat_flush_cache();
   212             return FALSE;
   213         }
   214     }
   215 }
   217 void * FASTCALL xlat_get_code_by_vma( sh4vma_t vma )
   218 {
   219     void *result = NULL;
   221     if( IS_IN_ICACHE(vma) ) {
   222         return xlat_get_code( GET_ICACHE_PHYS(vma) );
   223     }
   225     if( vma > 0xFFFFFF00 ) {
   226         // lxdream hook
   227         return NULL;
   228     }
   230     if( !mmu_update_icache(vma) ) {
   231         // fault - off to the fault handler
   232         if( !mmu_update_icache(sh4r.pc) ) {
   233             // double fault - halt
   234             ERROR( "Double fault - halting" );
   235             sh4_core_exit(CORE_EXIT_HALT);
   236             return NULL;
   237         }
   238     }
   240     assert( IS_IN_ICACHE(sh4r.pc) );
   241     result = xlat_get_code( GET_ICACHE_PHYS(sh4r.pc) );
   242     return result;
   243 }
.