X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cpu%2Ffame%2Ffamec.c;h=db4eae692c919ee3590e2ee4ce90a26ae56128ae;hb=c041308933a54fce3b1e98b0228e19f96475ae40;hp=3dcb8b121aff011d9a80b2460724200eb3444d3f;hpb=03e4f2a349247334666c87abe3a908df72d23051;p=picodrive.git diff --git a/cpu/fame/famec.c b/cpu/fame/famec.c index 3dcb8b1..db4eae6 100644 --- a/cpu/fame/famec.c +++ b/cpu/fame/famec.c @@ -4,42 +4,59 @@ /* Autor: Oscar Orallo Pelaez */ /* Fecha de comienzo: 03-10-2006 */ /* Ultima actualizacion: 08-10-2006 */ -/* Based on the excellent FAMEC emulator by Stèphane Dallongueville */ +/* Based on the excellent C68K emulator by Stèphane Dallongueville */ /****************************************************************************/ #include #include #include +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + #include "fame.h" // Options // #define FAMEC_ROLL_INLINE #define FAMEC_EMULATE_TRACE -#define FAMEC_IRQ_CYCLES #define FAMEC_CHECK_BRANCHES -// #define FAMEC_USE_DATA_BANKS -// #define FAMEC_EXTRA_INLINE +#define FAMEC_EXTRA_INLINE // #define FAMEC_DEBUG -#define FAMEC_NO_GOTOS +// #define FAMEC_NO_GOTOS #define FAMEC_ADR_BITS 24 // #define FAMEC_FETCHBITS 8 #define FAMEC_DATABITS 8 +#define FAMEC_32BIT_PC #define USE_CYCLONE_TIMING #define USE_CYCLONE_TIMING_DIV +#define PICODRIVE_HACK // Options // - +#ifndef FAMEC_NO_GOTOS +// computed gotos is a GNU extension +#ifndef __GNUC__ +#define FAMEC_NO_GOTOS +#endif +// as of 3.3, clang takes over 3h to compile this in computed goto mode.. +#ifdef __clang__ +#define FAMEC_NO_GOTOS +#endif +#endif + #undef INLINE -#ifndef INLINE +#ifdef _MSC_VER +#define INLINE +#else #define INLINE __inline__ #endif #ifndef FAMEC_EXTRA_INLINE #define FAMEC_EXTRA_INLINE #else +#undef FAMEC_EXTRA_INLINE #define FAMEC_EXTRA_INLINE INLINE #endif @@ -67,12 +84,17 @@ #undef s32 #endif +#ifdef uptr +#undef uptr +#endif + #define u8 unsigned char #define s8 signed char #define u16 unsigned short #define s16 signed short #define u32 unsigned int #define s32 signed int +#define uptr unsigned long /* typedef unsigned char u8; @@ -83,17 +105,6 @@ typedef unsigned int u32; typedef signed int s32; */ -#ifdef FAMEC_EMULATE_TRACE -static u32 flag_T; -#endif -static u32 flag_C; -static u32 flag_V; -static u32 flag_NotZ; -static u32 flag_N; -static u32 flag_X; // 16 bytes aligned -static u32 flag_S; -static u32 flag_I; - #ifndef M68K_OK #define M68K_OK 0 #endif @@ -270,6 +281,10 @@ static u32 flag_I; goto famec_Exec; #endif +#define RET0() \ + m68kcontext.io_cycle_counter = -6; \ + goto famec_End; + #else #define NEXT \ @@ -282,22 +297,46 @@ static u32 flag_I; m68kcontext.io_cycle_counter -= (A); \ return; +#define RET0() \ + m68kcontext.io_cycle_counter = -6; \ + return; + #endif #define M68K_PPL (m68kcontext.sr >> 8) & 7 #define GET_PC \ - (u32)PC - BasePC; + (u32)((uptr)PC - BasePC) + + +#ifdef FAMEC_CHECK_BRANCHES +#define FORCE_ALIGNMENT(pc) +#else +#define FORCE_ALIGNMENT(pc) pc&=~1; +#endif + +#ifndef FAMEC_32BIT_PC + +#define SET_PC(A) \ +{ \ + u32 pc = A; \ + FORCE_ALIGNMENT(pc); \ + BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \ + PC = (u16*)((pc & M68K_ADR_MASK) + BasePC); \ +} + +#else #define SET_PC(A) \ - BasePC = g_m68kcontext->Fetch[((A) >> M68K_FETCHSFT) & M68K_FETCHMASK]; \ - /* BasePC -= (A) & 0xFF000000; */ \ - PC = (u16*)(((A) & M68K_ADR_MASK) + BasePC); +{ \ + u32 pc = A; \ + FORCE_ALIGNMENT(pc); \ + BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \ + BasePC -= pc & 0xFF000000; \ + PC = (u16*)(pc + BasePC); \ +} -#define SET_PC_BASE(P,B,A) \ - (B) = g_m68kcontext->Fetch[((A) >> M68K_FETCHSFT) & M68K_FETCHMASK]; \ - /* (B) -= (A) & 0xFF000000; */ \ - (P) = (u16*)(((A) & M68K_ADR_MASK) + (B)); +#endif #define PRE_IO \ @@ -465,7 +504,7 @@ static u32 flag_I; if (interrupt_chk__()) \ { \ cycles_needed=m68kcontext.io_cycle_counter-(CLK); \ - m68kcontext.io_cycle_counter= (CLK); \ + m68kcontext.io_cycle_counter=(CLK); \ } @@ -480,9 +519,10 @@ static u32 flag_I; #define CHECK_BRANCH_EXCEPTION(_PC_) \ if ((_PC_)&1) \ { \ - u32 pr_PC=GET_PC; \ + u32 new_PC, pr_PC=GET_PC; \ m68kcontext.execinfo |= FM68K_EMULATE_GROUP_0; \ - execute_exception_group_0(M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \ + new_PC = execute_exception_group_0(M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \ + SET_PC(new_PC); \ CHECK_BRANCH_EXCEPTION_GOTO_END \ } #else @@ -490,11 +530,6 @@ static u32 flag_I; #endif -static int init_jump_table(void); - -/* Custom function handler */ -typedef void (*icust_handler_func)(u32 vector); - // global variable /////////////////// @@ -502,20 +537,33 @@ typedef void (*icust_handler_func)(u32 vector); M68K_CONTEXT *g_m68kcontext; #define m68kcontext (*g_m68kcontext) -/* static s32 io_cycle_counter; */ -static s32 cycles_needed=0; -static u16 *PC; -static u32 BasePC; -// static u32 Fetch[M68K_FETCHBANK]; +#ifdef FAMEC_NO_GOTOS +#define Opcode m68kcontext.Opcode +#define cycles_needed m68kcontext.cycles_needed +#define PC m68kcontext.PC +#define BasePC m68kcontext.BasePC +#define flag_C m68kcontext.flag_C +#define flag_V m68kcontext.flag_V +#define flag_NotZ m68kcontext.flag_NotZ +#define flag_N m68kcontext.flag_N +#define flag_X m68kcontext.flag_X +#endif + +#define flag_T m68kcontext.flag_T +#define flag_S m68kcontext.flag_S +#define flag_I m68kcontext.flag_I + +static u32 initialised = 0; + +#ifdef PICODRIVE_HACK +extern M68K_CONTEXT PicoCpuFM68k, PicoCpuFS68k; +#endif /* Custom function handler */ typedef void (*opcode_func)(void); static opcode_func JumpTable[0x10000]; - -static u32 initialised = 0; - // exception cycle table (taken from musashi core) static const s32 exception_cycle_table[256] = { @@ -609,7 +657,7 @@ void fm68k_init(void) #endif if (!initialised) - fm68k_emulate(0); + fm68k_emulate(0, 0); #ifdef FAMEC_DEBUG puts("FAME initialized."); @@ -628,7 +676,7 @@ void fm68k_init(void) int fm68k_reset(void) { if (!initialised) - fm68k_emulate(0); + fm68k_emulate(0, 0); // Si la CPU esta en ejecucion, salir con M68K_RUNNING if (m68kcontext.execinfo & M68K_RUNNING) @@ -665,7 +713,11 @@ int fm68k_reset(void) /****************************************************************************/ u32 fm68k_get_pc(M68K_CONTEXT *context) { - return (context->execinfo & M68K_RUNNING)?(u32)PC-BasePC:context->pc; +#ifdef FAMEC_NO_GOTOS + return (context->execinfo & M68K_RUNNING)?(uptr)PC-BasePC:context->pc; +#else + return context->pc; // approximate PC in this mode +#endif } @@ -684,62 +736,67 @@ int fm68k_would_interrupt(void) return interrupt_chk__(); } -static FAMEC_EXTRA_INLINE void execute_exception(s32 vect) +static FAMEC_EXTRA_INLINE u32 execute_exception(s32 vect, u32 oldPC, u32 oldSR) { - extern u32 flag_S; -#ifndef FAMEC_IRQ_CYCLES - if ((vect<24)||(vect>31)) -#endif + u32 newPC; + //u32 oldSR = GET_SR; + m68kcontext.io_cycle_counter -= exception_cycle_table[vect]; - { - u32 newPC; - u32 oldPC; - u32 oldSR = GET_SR; +#ifdef FAMEC_EMULATE_TRACE + m68kcontext.execinfo &= ~FM68K_EMULATE_TRACE; +#endif - PRE_IO + PRE_IO - READ_LONG_F(vect * 4, newPC) + READ_LONG_F(vect * 4, newPC) - /* swap A7 and USP */ - if (!flag_S) - { - u32 tmpSP; + /* swap A7 and USP */ + if (!flag_S) + { + u32 tmpSP; - tmpSP = ASP; - ASP = AREG(7); - AREG(7) = tmpSP; - } + tmpSP = ASP; + ASP = AREG(7); + AREG(7) = tmpSP; + } - oldPC = (u32)(PC) - BasePC; - PUSH_32_F(oldPC) - PUSH_16_F(oldSR) + //oldPC = GET_PC; + PUSH_32_F(oldPC) + PUSH_16_F(oldSR) - /* adjust SR */ - flag_S = M68K_SR_S; + /* adjust SR */ + flag_S = M68K_SR_S; + flag_T = 0; - newPC&=M68K_ADR_MASK&~1; // don't crash on games with bad vector tables +#ifndef FAMEC_32BIT_PC + newPC&=M68K_ADR_MASK +#endif +#ifdef FAMEC_CHECK_BRANCHES + newPC&=~1; // don't crash on games with bad vector tables +#endif - SET_PC(newPC) + // SET_PC(newPC) - POST_IO - } + POST_IO + + return newPC; } -static FAMEC_EXTRA_INLINE void execute_exception_group_0(s32 vect, u16 inst_reg, s32 addr, u16 spec_info) +static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(s32 vect, s32 addr, u16 spec_info, u32 oldSR) { - execute_exception(vect); + u32 newPC; + u16 inst_reg = 0; + newPC = execute_exception(vect, addr, oldSR); //if (!(m68kcontext.icust_handler && m68kcontext.icust_handler[vect])) { PUSH_16_F(inst_reg); PUSH_32_F(addr); PUSH_16_F(spec_info); } + return newPC; } -static void setup_jumptable(void); -static u32 Opcode; - #ifdef FAMEC_NO_GOTOS #define OPCODE(N_OP) static void OP_##N_OP(void) @@ -751,21 +808,36 @@ static u32 Opcode; // main exec function ////////////////////// -int fm68k_emulate(s32 cycles) +int fm68k_emulate(s32 cycles, int idle_mode) { +#ifndef FAMEC_NO_GOTOS + u32 Opcode; + s32 cycles_needed; + u16 *PC; + uptr BasePC; + u32 flag_C; + u32 flag_V; + u32 flag_NotZ; + u32 flag_N; + u32 flag_X; +#endif + if (!initialised) { -#ifdef FAMEC_NO_GOTOS - init_jump_table(); - return 0; -#else goto init_jump_table; -#endif } +#ifdef PICODRIVE_HACK + if (idle_mode == 1) goto idle_install; + else if (idle_mode == 2) goto idle_remove; +#endif + // won't emulate double fault // if (m68kcontext.execinfo & M68K_FAULTED) return -1; + // Cache PPL + flag_I = M68K_PPL; + if (m68kcontext.execinfo & FM68K_HALTED) { if (interrupt_chk__() <= 0) @@ -785,9 +857,6 @@ int fm68k_emulate(s32 cycles) // Cache SR SET_SR(m68kcontext.sr) - // Cache PPL - flag_I = M68K_PPL; - // Fijar PC SET_PC(m68kcontext.pc) @@ -813,7 +882,7 @@ int fm68k_emulate(s32 cycles) else m68kcontext.interrupts[0] = 0; - execute_exception(line + 0x18); + SET_PC(execute_exception(line + 0x18, GET_PC, GET_SR)); flag_I = (u32)line; if (m68kcontext.io_cycle_counter <= 0) goto famec_End; } @@ -822,7 +891,7 @@ int fm68k_emulate(s32 cycles) if (flag_T) { m68kcontext.execinfo |= FM68K_EMULATE_TRACE; - cycles_needed= m68kcontext.io_cycle_counter; + cycles_needed = m68kcontext.io_cycle_counter; m68kcontext.io_cycle_counter=0; } #endif @@ -851,22 +920,26 @@ famec_Exec: #ifdef FAMEC_EMULATE_TRACE if (m68kcontext.execinfo & FM68K_EMULATE_TRACE) { - m68kcontext.io_cycle_counter= cycles_needed; + m68kcontext.io_cycle_counter += cycles_needed; + cycles_needed = 0; m68kcontext.execinfo &= ~FM68K_EMULATE_TRACE; m68kcontext.execinfo |= FM68K_DO_TRACE; - execute_exception(M68K_TRACE_EX); - flag_T=0; + SET_PC(execute_exception(M68K_TRACE_EX, GET_PC, GET_SR)); if (m68kcontext.io_cycle_counter > 0) { - NEXT + //NEXT + goto famec_Exec; } } else #endif if (cycles_needed != 0) { - s32 line=interrupt_chk__(); - m68kcontext.io_cycle_counter= cycles_needed; + u32 line; + m68kcontext.io_cycle_counter += cycles_needed; + cycles_needed = 0; + //if (m68kcontext.io_cycle_counter <= 0) goto famec_End; + line=interrupt_chk__(); if (line>0) { if (m68kcontext.iack_handler != NULL) @@ -874,11 +947,11 @@ famec_Exec: else m68kcontext.interrupts[0] = 0; - execute_exception(line + 0x18); + SET_PC(execute_exception(line + 0x18, GET_PC, GET_SR)); flag_I = (u32)line; } #ifdef FAMEC_EMULATE_TRACE - else if (!(flag_T)) + if (!(flag_T)) #endif if (m68kcontext.io_cycle_counter > 0) { @@ -902,19 +975,10 @@ famec_End: return cycles - m68kcontext.io_cycle_counter; -#ifdef FAMEC_NO_GOTOS -} - -static int init_jump_table(void) -{{ -#else init_jump_table: { -#endif u32 i, j; - m68kcontext.sr = 0x2704; // Z flag - for(i = 0x0000; i <= 0xFFFF; i += 0x0001) JumpTable[0x0000 + i] = CAST_OP(0x4AFC); for(i = 0x0000; i <= 0x0007; i += 0x0001) @@ -4928,6 +4992,49 @@ init_jump_table: initialised = 1; return 0; -}} +} + +#ifdef PICODRIVE_HACK + +#define INSTALL_IDLE(fake_op_base,real_op,detector,idle_handler,normal_handler) \ + JumpTable[fake_op_base] = CAST_OP(idle_handler); \ + JumpTable[fake_op_base|0x0200] = CAST_OP(normal_handler); \ + JumpTable[real_op] = CAST_OP(detector) + +#define UNDO_IDLE(fake_op_base,real_op,normal_handler) \ + JumpTable[fake_op_base] = JumpTable[fake_op_base|0x0200] = CAST_OP(0x4AFC); \ + JumpTable[real_op] = CAST_OP(normal_handler) + +idle_install: + // printf("install..\n"); + INSTALL_IDLE(0x71fa, 0x66fa, idle_detector_bcc8, 0x6601_idle, 0x6601); + INSTALL_IDLE(0x71f8, 0x66f8, idle_detector_bcc8, 0x6601_idle, 0x6601); + INSTALL_IDLE(0x71f6, 0x66f6, idle_detector_bcc8, 0x6601_idle, 0x6601); + INSTALL_IDLE(0x71f2, 0x66f2, idle_detector_bcc8, 0x6601_idle, 0x6601); + INSTALL_IDLE(0x75fa, 0x67fa, idle_detector_bcc8, 0x6701_idle, 0x6701); + INSTALL_IDLE(0x75f8, 0x67f8, idle_detector_bcc8, 0x6701_idle, 0x6701); + INSTALL_IDLE(0x75f6, 0x67f6, idle_detector_bcc8, 0x6701_idle, 0x6701); + INSTALL_IDLE(0x75f2, 0x67f2, idle_detector_bcc8, 0x6701_idle, 0x6701); + INSTALL_IDLE(0x7dfe, 0x60fe, idle_detector_bcc8, 0x6001_idle, 0x6001); + INSTALL_IDLE(0x7dfc, 0x60fc, idle_detector_bcc8, 0x6001_idle, 0x6001); + return 0; + +idle_remove: + // printf("remove..\n"); + UNDO_IDLE(0x71fa, 0x66fa, 0x6601); + UNDO_IDLE(0x71f8, 0x66f8, 0x6601); + UNDO_IDLE(0x71f6, 0x66f6, 0x6601); + UNDO_IDLE(0x71f2, 0x66f2, 0x6601); + UNDO_IDLE(0x75fa, 0x67fa, 0x6701); + UNDO_IDLE(0x75f8, 0x67f8, 0x6701); + UNDO_IDLE(0x75f6, 0x67f6, 0x6701); + UNDO_IDLE(0x75f2, 0x67f2, 0x6701); + UNDO_IDLE(0x7dfe, 0x60fe, 0x6001); + UNDO_IDLE(0x7dfc, 0x60fc, 0x6001); + return 0; + +#endif +} +void *get_jumptab(void) { return JumpTable; }