fame: fix roxr
[picodrive.git] / cpu / fame / famec.c
index 2549147..db4eae6 100644 (file)
@@ -4,13 +4,17 @@
 /* Autor: Oscar Orallo Pelaez                                               */\r
 /* Fecha de comienzo: 03-10-2006                                            */\r
 /* Ultima actualizacion: 08-10-2006                                         */\r
-/* Based on the excellent FAMEC emulator by Stèphane Dallongueville          */\r
+/* Based on the excellent C68K emulator by Stèphane Dallongueville          */\r
 /****************************************************************************/\r
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
 #include <string.h>\r
 \r
+#ifdef __GNUC__\r
+#pragma GCC diagnostic ignored "-Wunused-variable"\r
+#endif\r
+\r
 #include "fame.h"\r
 \r
 \r
@@ -20,7 +24,7 @@
 #define FAMEC_CHECK_BRANCHES\r
 #define FAMEC_EXTRA_INLINE\r
 // #define FAMEC_DEBUG\r
-#define FAMEC_NO_GOTOS\r
+// #define FAMEC_NO_GOTOS\r
 #define FAMEC_ADR_BITS  24\r
 // #define FAMEC_FETCHBITS 8\r
 #define FAMEC_DATABITS  8\r
 \r
 #define USE_CYCLONE_TIMING\r
 #define USE_CYCLONE_TIMING_DIV\r
+#define PICODRIVE_HACK\r
 // Options //\r
 \r
-\r
+#ifndef FAMEC_NO_GOTOS\r
+// computed gotos is a GNU extension\r
+#ifndef __GNUC__\r
+#define FAMEC_NO_GOTOS\r
+#endif\r
+// as of 3.3, clang takes over 3h to compile this in computed goto mode..\r
+#ifdef __clang__\r
+#define FAMEC_NO_GOTOS\r
+#endif\r
+#endif\r
\r
 #undef INLINE\r
-#ifndef INLINE\r
+#ifdef _MSC_VER\r
+#define INLINE\r
+#else\r
 #define INLINE __inline__\r
 #endif\r
 \r
 #undef s32\r
 #endif\r
 \r
+#ifdef uptr\r
+#undef uptr\r
+#endif\r
+\r
 #define u8     unsigned char\r
 #define s8     signed char\r
 #define u16    unsigned short\r
 #define s16    signed short\r
 #define u32    unsigned int\r
 #define s32    signed int\r
+#define uptr   unsigned long\r
 \r
 /*\r
 typedef unsigned char  u8;\r
@@ -259,6 +281,10 @@ typedef signed int s32;
     goto famec_Exec;\r
 #endif\r
 \r
+#define RET0() \\r
+    m68kcontext.io_cycle_counter = -6; \\r
+    goto famec_End;\r
+\r
 #else\r
 \r
 #define NEXT \\r
@@ -271,19 +297,30 @@ typedef signed int        s32;
     m68kcontext.io_cycle_counter -= (A);  \\r
     return;\r
 \r
+#define RET0() \\r
+    m68kcontext.io_cycle_counter = -6; \\r
+    return;\r
+\r
 #endif\r
 \r
 #define M68K_PPL (m68kcontext.sr >> 8) & 7\r
 \r
 #define GET_PC                  \\r
-       ((u32)PC - BasePC)\r
+       (u32)((uptr)PC - BasePC)\r
 \r
 \r
+#ifdef FAMEC_CHECK_BRANCHES\r
+#define FORCE_ALIGNMENT(pc)\r
+#else\r
+#define FORCE_ALIGNMENT(pc) pc&=~1;\r
+#endif\r
+\r
 #ifndef FAMEC_32BIT_PC\r
 \r
 #define SET_PC(A)               \\r
 { \\r
     u32 pc = A; \\r
+    FORCE_ALIGNMENT(pc); \\r
     BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
     PC = (u16*)((pc & M68K_ADR_MASK) + BasePC);        \\r
 }\r
@@ -293,6 +330,7 @@ typedef signed int  s32;
 #define SET_PC(A)               \\r
 { \\r
     u32 pc = A; \\r
+    FORCE_ALIGNMENT(pc); \\r
     BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
     BasePC -= pc & 0xFF000000;    \\r
     PC = (u16*)(pc + BasePC); \\r
@@ -492,8 +530,6 @@ typedef signed int  s32;
 #endif\r
 \r
 \r
-static int init_jump_table(void);\r
-\r
 // global variable\r
 ///////////////////\r
 \r
@@ -502,25 +538,27 @@ M68K_CONTEXT *g_m68kcontext;
 #define m68kcontext (*g_m68kcontext)\r
 \r
 #ifdef FAMEC_NO_GOTOS\r
-static u32 Opcode;\r
-static s32 cycles_needed;\r
-static u16 *PC;\r
-static u32 BasePC;\r
-static u32 flag_C;\r
-static u32 flag_V;\r
-static u32 flag_NotZ;\r
-static u32 flag_N;\r
-static u32 flag_X;\r
+#define Opcode m68kcontext.Opcode\r
+#define cycles_needed m68kcontext.cycles_needed\r
+#define PC m68kcontext.PC\r
+#define BasePC m68kcontext.BasePC\r
+#define flag_C m68kcontext.flag_C\r
+#define flag_V m68kcontext.flag_V\r
+#define flag_NotZ m68kcontext.flag_NotZ\r
+#define flag_N m68kcontext.flag_N\r
+#define flag_X m68kcontext.flag_X\r
 #endif\r
 \r
-#ifdef FAMEC_EMULATE_TRACE\r
-static u32 flag_T;\r
-#endif\r
-static u32 flag_S;\r
-static u32 flag_I;\r
+#define flag_T m68kcontext.flag_T\r
+#define flag_S m68kcontext.flag_S\r
+#define flag_I m68kcontext.flag_I\r
 \r
 static u32 initialised = 0;\r
 \r
+#ifdef PICODRIVE_HACK\r
+extern M68K_CONTEXT PicoCpuFM68k, PicoCpuFS68k;\r
+#endif\r
+\r
 /* Custom function handler */\r
 typedef void (*opcode_func)(void);\r
 \r
@@ -619,7 +657,7 @@ void fm68k_init(void)
 #endif\r
 \r
     if (!initialised)\r
-           fm68k_emulate(0);\r
+           fm68k_emulate(0, 0);\r
 \r
 #ifdef FAMEC_DEBUG\r
        puts("FAME initialized.");\r
@@ -638,7 +676,7 @@ void fm68k_init(void)
 int fm68k_reset(void)\r
 {\r
        if (!initialised)\r
-               fm68k_emulate(0);\r
+               fm68k_emulate(0, 0);\r
 \r
        // Si la CPU esta en ejecucion, salir con M68K_RUNNING\r
        if (m68kcontext.execinfo & M68K_RUNNING)\r
@@ -676,7 +714,7 @@ int fm68k_reset(void)
 u32 fm68k_get_pc(M68K_CONTEXT *context)\r
 {\r
 #ifdef FAMEC_NO_GOTOS\r
-       return (context->execinfo & M68K_RUNNING)?(u32)PC-BasePC:context->pc;\r
+       return (context->execinfo & M68K_RUNNING)?(uptr)PC-BasePC:context->pc;\r
 #else\r
        return context->pc; // approximate PC in this mode\r
 #endif\r
@@ -704,6 +742,9 @@ static FAMEC_EXTRA_INLINE u32 execute_exception(s32 vect, u32 oldPC, u32 oldSR)
        //u32 oldSR = GET_SR;\r
 \r
         m68kcontext.io_cycle_counter -= exception_cycle_table[vect];\r
+#ifdef FAMEC_EMULATE_TRACE\r
+       m68kcontext.execinfo &= ~FM68K_EMULATE_TRACE;\r
+#endif\r
 \r
        PRE_IO\r
 \r
@@ -725,11 +766,14 @@ static FAMEC_EXTRA_INLINE u32 execute_exception(s32 vect, u32 oldPC, u32 oldSR)
 \r
        /* adjust SR */\r
        flag_S = M68K_SR_S;\r
+       flag_T = 0;\r
 \r
 #ifndef FAMEC_32BIT_PC\r
        newPC&=M68K_ADR_MASK\r
 #endif\r
+#ifdef FAMEC_CHECK_BRANCHES\r
        newPC&=~1; // don't crash on games with bad vector tables\r
+#endif\r
 \r
        // SET_PC(newPC)\r
 \r
@@ -753,8 +797,6 @@ static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(s32 vect, s32 addr, u16
 }\r
 \r
 \r
-static void setup_jumptable(void);\r
-\r
 #ifdef FAMEC_NO_GOTOS\r
 \r
 #define OPCODE(N_OP) static void OP_##N_OP(void)\r
@@ -766,13 +808,13 @@ static void setup_jumptable(void);
 // main exec function\r
 //////////////////////\r
 \r
-int fm68k_emulate(s32 cycles)\r
+int fm68k_emulate(s32 cycles, int idle_mode)\r
 {\r
 #ifndef FAMEC_NO_GOTOS\r
        u32 Opcode;\r
        s32 cycles_needed;\r
        u16 *PC;\r
-       u32 BasePC;\r
+       uptr BasePC;\r
        u32 flag_C;\r
        u32 flag_V;\r
        u32 flag_NotZ;\r
@@ -782,17 +824,20 @@ int fm68k_emulate(s32 cycles)
 \r
        if (!initialised)\r
        {\r
-#ifdef FAMEC_NO_GOTOS\r
-               init_jump_table();\r
-               return 0;\r
-#else\r
                goto init_jump_table;\r
-#endif\r
        }\r
 \r
+#ifdef PICODRIVE_HACK\r
+       if      (idle_mode == 1) goto idle_install;\r
+       else if (idle_mode == 2) goto idle_remove;\r
+#endif\r
+\r
        // won't emulate double fault\r
        // if (m68kcontext.execinfo & M68K_FAULTED) return -1;\r
 \r
+       // Cache PPL\r
+       flag_I = M68K_PPL;\r
+\r
        if (m68kcontext.execinfo & FM68K_HALTED)\r
        {\r
                if (interrupt_chk__() <= 0)\r
@@ -812,9 +857,6 @@ int fm68k_emulate(s32 cycles)
        // Cache SR\r
        SET_SR(m68kcontext.sr)\r
 \r
-       // Cache PPL\r
-       flag_I = M68K_PPL;\r
-\r
        // Fijar PC\r
        SET_PC(m68kcontext.pc)\r
 \r
@@ -878,12 +920,11 @@ famec_Exec:
 #ifdef FAMEC_EMULATE_TRACE\r
        if (m68kcontext.execinfo & FM68K_EMULATE_TRACE)\r
        {\r
-               m68kcontext.io_cycle_counter = cycles_needed;\r
+               m68kcontext.io_cycle_counter += cycles_needed;\r
                cycles_needed = 0;\r
                m68kcontext.execinfo &= ~FM68K_EMULATE_TRACE;\r
                m68kcontext.execinfo |= FM68K_DO_TRACE;\r
                SET_PC(execute_exception(M68K_TRACE_EX, GET_PC, GET_SR));\r
-               flag_T=0;\r
                if (m68kcontext.io_cycle_counter > 0)\r
                {\r
                        //NEXT\r
@@ -894,9 +935,11 @@ famec_Exec:
 #endif\r
                if (cycles_needed != 0)\r
                {\r
-                       m68kcontext.io_cycle_counter = cycles_needed;\r
+                       u32 line;\r
+                       m68kcontext.io_cycle_counter += cycles_needed;\r
                        cycles_needed = 0;\r
-                       s32 line=interrupt_chk__();\r
+                       //if (m68kcontext.io_cycle_counter <= 0) goto famec_End;\r
+                       line=interrupt_chk__();\r
                        if (line>0)\r
                        {\r
                                if (m68kcontext.iack_handler != NULL)\r
@@ -932,19 +975,10 @@ famec_End:
 \r
        return cycles - m68kcontext.io_cycle_counter;\r
 \r
-#ifdef FAMEC_NO_GOTOS\r
-}\r
-\r
-static int init_jump_table(void)\r
-{{\r
-#else\r
 init_jump_table:\r
 {\r
-#endif\r
        u32 i, j;\r
 \r
-       m68kcontext.sr = 0x2704; // Z flag\r
-\r
        for(i = 0x0000; i <= 0xFFFF; i += 0x0001)\r
                JumpTable[0x0000 + i] = CAST_OP(0x4AFC);\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
@@ -4958,6 +4992,49 @@ init_jump_table:
 \r
        initialised = 1;\r
        return 0;\r
-}}\r
+}\r
+\r
+#ifdef PICODRIVE_HACK\r
+\r
+#define INSTALL_IDLE(fake_op_base,real_op,detector,idle_handler,normal_handler) \\r
+       JumpTable[fake_op_base] = CAST_OP(idle_handler); \\r
+       JumpTable[fake_op_base|0x0200] = CAST_OP(normal_handler); \\r
+       JumpTable[real_op] = CAST_OP(detector)\r
+\r
+#define UNDO_IDLE(fake_op_base,real_op,normal_handler) \\r
+       JumpTable[fake_op_base] = JumpTable[fake_op_base|0x0200] = CAST_OP(0x4AFC); \\r
+       JumpTable[real_op] = CAST_OP(normal_handler)\r
+\r
+idle_install:\r
+       // printf("install..\n");\r
+       INSTALL_IDLE(0x71fa, 0x66fa, idle_detector_bcc8, 0x6601_idle, 0x6601);\r
+       INSTALL_IDLE(0x71f8, 0x66f8, idle_detector_bcc8, 0x6601_idle, 0x6601);\r
+       INSTALL_IDLE(0x71f6, 0x66f6, idle_detector_bcc8, 0x6601_idle, 0x6601);\r
+       INSTALL_IDLE(0x71f2, 0x66f2, idle_detector_bcc8, 0x6601_idle, 0x6601);\r
+       INSTALL_IDLE(0x75fa, 0x67fa, idle_detector_bcc8, 0x6701_idle, 0x6701);\r
+       INSTALL_IDLE(0x75f8, 0x67f8, idle_detector_bcc8, 0x6701_idle, 0x6701);\r
+       INSTALL_IDLE(0x75f6, 0x67f6, idle_detector_bcc8, 0x6701_idle, 0x6701);\r
+       INSTALL_IDLE(0x75f2, 0x67f2, idle_detector_bcc8, 0x6701_idle, 0x6701);\r
+       INSTALL_IDLE(0x7dfe, 0x60fe, idle_detector_bcc8, 0x6001_idle, 0x6001);\r
+       INSTALL_IDLE(0x7dfc, 0x60fc, idle_detector_bcc8, 0x6001_idle, 0x6001);\r
+       return 0;\r
+\r
+idle_remove:\r
+       // printf("remove..\n");\r
+       UNDO_IDLE(0x71fa, 0x66fa, 0x6601);\r
+       UNDO_IDLE(0x71f8, 0x66f8, 0x6601);\r
+       UNDO_IDLE(0x71f6, 0x66f6, 0x6601);\r
+       UNDO_IDLE(0x71f2, 0x66f2, 0x6601);\r
+       UNDO_IDLE(0x75fa, 0x67fa, 0x6701);\r
+       UNDO_IDLE(0x75f8, 0x67f8, 0x6701);\r
+       UNDO_IDLE(0x75f6, 0x67f6, 0x6701);\r
+       UNDO_IDLE(0x75f2, 0x67f2, 0x6701);\r
+       UNDO_IDLE(0x7dfe, 0x60fe, 0x6001);\r
+       UNDO_IDLE(0x7dfc, 0x60fc, 0x6001);\r
+       return 0;\r
+\r
+#endif\r
+}\r
 \r
+void *get_jumptab(void) { return JumpTable; }\r
 \r