# HG changeset patch # User nkeynes # Date 1230972915 0 # Node ID c67574ed4355e2a9ec0c769a41ccc1f3a75828ce # Parent 81e0d3051d5f0ded5a8beebe9b65ad066ecb8b42 Implement CORE_EXIT_EXCEPTION for use when direct frame messing about doesn't work --- a/src/sh4/sh4.c Sat Jan 03 07:30:26 2009 +0000 +++ b/src/sh4/sh4.c Sat Jan 03 08:55:15 2009 +0000 @@ -202,7 +202,11 @@ if( sh4_running ) { #ifdef SH4_TRANSLATOR if( sh4_use_translator ) { - sh4_translate_exit_recover(); + if( exit_code == CORE_EXIT_EXCEPTION ) { + sh4_translate_exception_exit_recover(); + } else { + sh4_translate_exit_recover(); + } } #endif // longjmp back into sh4_run_slice --- a/src/sh4/sh4trans.c Sat Jan 03 07:30:26 2009 +0000 +++ b/src/sh4/sh4trans.c Sat Jan 03 08:55:15 2009 +0000 @@ -158,6 +158,16 @@ sh4r.pc += (recovery->sh4_icount<<1); } +/** + * Same as sh4_translate_run_recovery, but is used to recover from a taken + * exception - that is, it fixes sh4r.spc rather than sh4r.pc + */ +void sh4_translate_run_exception_recovery( xlat_recovery_record_t recovery ) +{ + sh4r.slice_cycle += (recovery->sh4_icount * sh4_cpu_period); + sh4r.spc += (recovery->sh4_icount<<1); +} + void sh4_translate_exit_recover( ) { void *code = xlat_get_code_by_vma( sh4r.pc ); @@ -175,6 +185,24 @@ } } +void sh4_translate_exception_exit_recover( ) +{ + void *code = xlat_get_code_by_vma( sh4r.spc ); + if( code != NULL ) { + uint32_t size = xlat_get_code_size( code ); + void *pc = xlat_get_native_pc( code, size ); + if( pc != NULL ) { + // could be null if we're not actually running inside the translator + xlat_recovery_record_t recover = xlat_get_pre_recovery(code, pc); + if( recover != NULL ) { + // Can be null if there is no recovery necessary + sh4_translate_run_exception_recovery(recover); + } + } + } + +} + void FASTCALL sh4_translate_breakpoint_hit(uint32_t pc) { if( sh4_starting && sh4r.slice_cycle == 0 && pc == sh4r.pc ) { --- a/src/sh4/sh4trans.h Sat Jan 03 07:30:26 2009 +0000 +++ b/src/sh4/sh4trans.h Sat Jan 03 08:55:15 2009 +0000 @@ -113,6 +113,12 @@ void sh4_translate_exit_recover( ); /** + * Called when doing a break out of the translator following a taken exception - + * finalizes the system state up to the start of the current instruction. + */ +void sh4_translate_exception_exit_recover( ); + +/** * From within the translator, exit the current block at the end of the * current instruction, flush the translation cache (completely) * @return TRUE to perform a vm-exit/continue after the flush --- a/src/sh4/sh4x86.in Sat Jan 03 07:30:26 2009 +0000 +++ b/src/sh4/sh4x86.in Sat Jan 03 08:55:15 2009 +0000 @@ -292,12 +292,18 @@ /* Note: For SR.MD == 1 && MMUCR.AT == 0, there are no memory exceptions, so * don't waste the cycles expecting them. Otherwise we need to save the exception pointer. */ + +#ifdef HAVE_FRAME_ADDRESS #define _CALL_READ(addr_reg, fn) if( !sh4_x86.tlb_on && (sh4r.xlat_sh4_mode & SR_MD) ) { \ call_func1_r32disp8(R_ECX, MEM_REGION_PTR(fn), addr_reg); } else { \ call_func1_r32disp8_exc(R_ECX, MEM_REGION_PTR(fn), addr_reg, pc); } #define _CALL_WRITE(addr_reg, val_reg, fn) if( !sh4_x86.tlb_on && (sh4r.xlat_sh4_mode & SR_MD) ) { \ call_func2_r32disp8(R_ECX, MEM_REGION_PTR(fn), addr_reg, val_reg); } else { \ - call_func2_r32disp8_exc(R_ECX, MEM_REGION_PTR(fn), addr_reg, val_reg, pc); } + call_func2_r32disp8_exc(R_ECX, MEM_REGION_PTR(fn), addr_reg, val_reg, pc); } +#else +#define _CALL_READ(addr_reg, fn) call_func1_r32disp8(R_ECX, MEM_REGION_PTR(fn), addr_reg) +#define _CALL_WRITE(addr_reg, val_reg, fn) call_func2_r32disp8(R_ECX, MEM_REGION_PTR(fn), addr_reg, val_reg) +#endif #define MEM_READ_BYTE( addr_reg, value_reg ) decode_address(addr_reg); _CALL_READ(addr_reg, read_byte); MEM_RESULT(value_reg) #define MEM_READ_WORD( addr_reg, value_reg ) decode_address(addr_reg); _CALL_READ(addr_reg, read_word); MEM_RESULT(value_reg)