famec: eliminate global context ptr
[picodrive.git] / cpu / fame / famec.c
index 8c71c07..4162094 100644 (file)
@@ -4,42 +4,59 @@
 /* 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
 // Options //\r
 #define FAMEC_ROLL_INLINE\r
 #define FAMEC_EMULATE_TRACE\r
-#define FAMEC_IRQ_CYCLES\r
 #define FAMEC_CHECK_BRANCHES\r
-// #define FAMEC_USE_DATA_BANKS\r
-// #define FAMEC_EXTRA_INLINE\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
+#define FAMEC_32BIT_PC\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
 #ifndef FAMEC_EXTRA_INLINE\r
 #define FAMEC_EXTRA_INLINE\r
 #else\r
+#undef FAMEC_EXTRA_INLINE\r
 #define FAMEC_EXTRA_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
@@ -83,17 +105,6 @@ typedef unsigned int        u32;
 typedef signed int     s32;\r
 */\r
 \r
-#ifdef FAMEC_EMULATE_TRACE\r
-static u32 flag_T;\r
-#endif\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;         // 16 bytes aligned\r
-static u32 flag_S;\r
-static u32 flag_I;\r
-\r
 #ifndef M68K_OK\r
     #define M68K_OK 0\r
 #endif\r
@@ -217,21 +228,21 @@ static u32 flag_I;
 // internals core macros\r
 /////////////////////////\r
 \r
-#define DREG(X)         (m68kcontext.dreg[(X)].D)\r
-#define DREGu32(X)      (m68kcontext.dreg[(X)].D)\r
-#define DREGs32(X)      (m68kcontext.dreg[(X)].SD)\r
-#define DREGu16(X)      (m68kcontext.dreg[(X)].W)\r
-#define DREGs16(X)      (m68kcontext.dreg[(X)].SW)\r
-#define DREGu8(X)       (m68kcontext.dreg[(X)].B)\r
-#define DREGs8(X)       (m68kcontext.dreg[(X)].SB)\r
+#define DREG(X)         (ctx->dreg[(X)].D)\r
+#define DREGu32(X)      (ctx->dreg[(X)].D)\r
+#define DREGs32(X)      (ctx->dreg[(X)].SD)\r
+#define DREGu16(X)      (ctx->dreg[(X)].W)\r
+#define DREGs16(X)      (ctx->dreg[(X)].SW)\r
+#define DREGu8(X)       (ctx->dreg[(X)].B)\r
+#define DREGs8(X)       (ctx->dreg[(X)].SB)\r
 \r
-#define AREG(X)         (m68kcontext.areg[(X)].D)\r
-#define AREGu32(X)      (m68kcontext.areg[(X)].D)\r
-#define AREGs32(X)      (m68kcontext.areg[(X)].SD)\r
-#define AREGu16(X)      (m68kcontext.areg[(X)].W)\r
-#define AREGs16(X)      (m68kcontext.areg[(X)].SW)\r
+#define AREG(X)         (ctx->areg[(X)].D)\r
+#define AREGu32(X)      (ctx->areg[(X)].D)\r
+#define AREGs32(X)      (ctx->areg[(X)].SD)\r
+#define AREGu16(X)      (ctx->areg[(X)].W)\r
+#define AREGs16(X)      (ctx->areg[(X)].SW)\r
 \r
-#define ASP             (m68kcontext.asp)\r
+#define ASP             (ctx->asp)\r
 \r
 #define LSL(A, C)       ((A) << (C))\r
 #define LSR(A, C)       ((A) >> (C))\r
@@ -260,44 +271,72 @@ static u32 flag_I;
 \r
 #ifdef FAMEC_ROLL_INLINE\r
 #define RET(A)                                      \\r
-    m68kcontext.io_cycle_counter -= (A);                        \\r
-    if (m68kcontext.io_cycle_counter <= 0) goto famec_Exec_End;        \\r
+    ctx->io_cycle_counter -= (A);                        \\r
+    if (ctx->io_cycle_counter <= 0) goto famec_Exec_End;       \\r
     NEXT\r
 #else\r
 #define RET(A)                                      \\r
-    m68kcontext.io_cycle_counter -= (A);                        \\r
-    if (m68kcontext.io_cycle_counter <= 0) goto famec_Exec_End;        \\r
+    ctx->io_cycle_counter -= (A);                        \\r
+    if (ctx->io_cycle_counter <= 0) goto famec_Exec_End;       \\r
     goto famec_Exec;\r
 #endif\r
 \r
+#define RET0() \\r
+    ctx->io_cycle_counter = -6; \\r
+    goto famec_End;\r
+\r
 #else\r
 \r
 #define NEXT \\r
-    do{ \\r
-       FETCH_WORD(Opcode); \\r
-       JumpTable[Opcode](); \\r
-    }while(m68kcontext.io_cycle_counter>0);\r
+    do { \\r
+        FETCH_WORD(Opcode); \\r
+        JumpTable[Opcode](ctx); \\r
+    } while (ctx->io_cycle_counter > 0);\r
 \r
 #define RET(A) \\r
-    m68kcontext.io_cycle_counter -= (A);  \\r
+    ctx->io_cycle_counter -= (A);  \\r
+    return;\r
+\r
+#define RET0() \\r
+    ctx->io_cycle_counter = -6; \\r
     return;\r
 \r
 #endif\r
 \r
-#define M68K_PPL (m68kcontext.sr >> 8) & 7\r
+#define M68K_PPL (ctx->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 = ctx->Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
+    PC = (u16*)((pc & M68K_ADR_MASK) + BasePC);        \\r
+}\r
+\r
+#else\r
 \r
 #define SET_PC(A)               \\r
-    BasePC = g_m68kcontext->Fetch[((A) >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
-   /*  BasePC -= (A) & 0xFF000000; */   \\r
-    PC = (u16*)(((A) & M68K_ADR_MASK) + BasePC);\r
+{ \\r
+    u32 pc = A; \\r
+    FORCE_ALIGNMENT(pc); \\r
+    BasePC = ctx->Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
+    BasePC -= pc & 0xFF000000;    \\r
+    PC = (u16*)(pc + BasePC); \\r
+}\r
 \r
-#define SET_PC_BASE(P,B,A)               \\r
-    (B) = g_m68kcontext->Fetch[((A) >> M68K_FETCHSFT) & M68K_FETCHMASK];    \\r
-   /* (B) -= (A) & 0xFF000000; */ \\r
-    (P) = (u16*)(((A) & M68K_ADR_MASK) + (B));\r
+#endif\r
 \r
 \r
 #define PRE_IO                  \\r
@@ -306,44 +345,38 @@ static u32 flag_I;
 #define POST_IO                 \\r
 //    CCnt = io_cycle_counter;\r
 \r
-#ifndef FAME_BIG_ENDIAN\r
+#define READ_BYTE_F(A, D)           \\r
+       D = ctx->read_byte(A) & 0xFF;\r
+\r
+#define READ_WORD_F(A, D)           \\r
+       D = ctx->read_word(A) & 0xFFFF;\r
 \r
-       #define READ_BYTE_F(A, D)           \\r
-               D = m68kcontext.read_byte(A) & 0xFF;\r
+#define READ_LONG_F(A, D)           \\r
+       D = ctx->read_long(A);\r
 \r
-       #define READ_WORD_F(A, D)           \\r
-               D = m68kcontext.read_word(A) & 0xFFFF;\r
+#define READSX_LONG_F READ_LONG_F\r
 \r
-       #define READ_LONG_F(A, D)               \\r
-               D = m68kcontext.read_word((A)) << 16;          \\r
-               D |= m68kcontext.read_word((A) + 2) & 0xFFFF;\r
+#define WRITE_LONG_F(A, D)          \\r
+       ctx->write_long(A, D);\r
 \r
-       #define READSX_LONG_F(A, D)             \\r
-               D = m68kcontext.read_word((A)) << 16;          \\r
-               D |= m68kcontext.read_word((A) + 2) & 0xFFFF;\r
+#define WRITE_LONG_DEC_F(A, D)          \\r
+       ctx->write_word((A) + 2, (D) & 0xFFFF);    \\r
+       ctx->write_word((A), (D) >> 16);\r
 \r
-       #define WRITE_LONG_F(A, D)              \\r
-               m68kcontext.write_word((A), (D) >> 16);        \\r
-               m68kcontext.write_word((A) + 2, (D) & 0xFFFF);\r
+#define PUSH_32_F(D)                        \\r
+       AREG(7) -= 4;                               \\r
+       ctx->write_long(AREG(7), D);\r
 \r
-       #define WRITE_LONG_DEC_F(A, D)          \\r
-               m68kcontext.write_word((A), (D) >> 16); \\r
-               m68kcontext.write_word((A) + 2, (D) & 0xFFFF);\r
+#define POP_32_F(D)                         \\r
+       D = ctx->read_long(AREG(7));         \\r
+       AREG(7) += 4;\r
+\r
+#ifndef FAME_BIG_ENDIAN\r
 \r
        #define FETCH_LONG(A)               \\r
                (A) = PC[1] | (PC[0] << 16);    \\r
                PC += 2;\r
 \r
-    #define PUSH_32_F(D)                            \\r
-       AREG(7) -= 4;                                   \\r
-       m68kcontext.write_word(AREG(7), (D) >> 16);     \\r
-       m68kcontext.write_word(AREG(7) + 2, (D) & 0xFFFF);\r
-\r
-    #define POP_32_F(D)                         \\r
-       D = m68kcontext.read_word(AREG(7)) << 16;          \\r
-       D |= m68kcontext.read_word(AREG(7) + 2) & 0xFFFF;  \\r
-       AREG(7) += 4;\r
-\r
        #define GET_SWORD           \\r
                (s16)(*PC)\r
 \r
@@ -372,37 +405,10 @@ static u32 flag_I;
 \r
 #else\r
 \r
-       #define READ_BYTE_F(A, D)           \\r
-               D = m68kcontext.read_byte(A) & 0xFF;\r
-\r
-       #define READ_WORD_F(A, D)           \\r
-               D = m68kcontext.read_word(A) & 0xFFFF;\r
-\r
-       #define READ_LONG_F(A, D)           \\r
-               D = m68kcontext.read_long(A);\r
-\r
-       #define READSX_LONG_F(A, D)         \\r
-               D = m68kcontext.read_long(A);\r
-\r
-       #define WRITE_LONG_F(A, D)          \\r
-               m68kcontext.write_long(A, D);\r
-\r
-       #define WRITE_LONG_DEC_F(A, D)          \\r
-               m68kcontext.write_word((A) + 2, (D) >> 16);    \\r
-               m68kcontext.write_word((A), (D) & 0xFFFF);\r
-\r
        #define FETCH_LONG(A)               \\r
                (A) = PC[0] | (PC[1] << 16);    \\r
                PC += 2;\r
 \r
-       #define PUSH_32_F(D)                        \\r
-               AREG(7) -= 4;                               \\r
-               m68kcontext.write_long(AREG(7), D);\r
-\r
-       #define POP_32_F(D)                         \\r
-               D = m68kcontext.read_long(AREG(7));         \\r
-               AREG(7) += 4;\r
-\r
        #define GET_SWORD                           \\r
                ((s16)(((*PC & 0xFF) << 8) | (*PC >> 8)))\r
 \r
@@ -434,23 +440,23 @@ static u32 flag_I;
 #endif\r
 \r
 #define READSX_BYTE_F(A, D)             \\r
-    D = (s8)m68kcontext.read_byte(A);\r
+    D = (s8)ctx->read_byte(A);\r
 \r
 #define READSX_WORD_F(A, D)             \\r
-    D = (s16)m68kcontext.read_word(A);\r
+    D = (s16)ctx->read_word(A);\r
 \r
 \r
 #define WRITE_BYTE_F(A, D)      \\r
-    m68kcontext.write_byte(A, D);\r
+    ctx->write_byte(A, D);\r
 \r
 #define WRITE_WORD_F(A, D)      \\r
-    m68kcontext.write_word(A, D);\r
+    ctx->write_word(A, D);\r
 \r
 #define PUSH_16_F(D)                    \\r
-    m68kcontext.write_word(AREG(7) -= 2, D);   \\r
+    ctx->write_word(AREG(7) -= 2, D);   \\r
 \r
 #define POP_16_F(D)                     \\r
-    D = (u16)m68kcontext.read_word(AREG(7));   \\r
+    D = (u16)ctx->read_word(AREG(7));   \\r
     AREG(7) += 2;\r
 \r
 #define GET_CCR                                     \\r
@@ -495,17 +501,17 @@ static u32 flag_I;
 #endif\r
 \r
 #define CHECK_INT_TO_JUMP(CLK) \\r
-       if (interrupt_chk__()) \\r
+       if (interrupt_chk__(ctx)) \\r
        { \\r
-               cycles_needed=m68kcontext.io_cycle_counter-(CLK); \\r
-               m68kcontext.io_cycle_counter= (CLK);  \\r
+               cycles_needed=ctx->io_cycle_counter-(CLK); \\r
+               ctx->io_cycle_counter=(CLK);  \\r
        }\r
 \r
 \r
 #ifdef FAMEC_CHECK_BRANCHES\r
 \r
 #ifdef FAMEC_NO_GOTOS\r
-#define CHECK_BRANCH_EXCEPTION_GOTO_END m68kcontext.io_cycle_counter=0; return;\r
+#define CHECK_BRANCH_EXCEPTION_GOTO_END ctx->io_cycle_counter=0; return;\r
 #else\r
 #define CHECK_BRANCH_EXCEPTION_GOTO_END goto famec_Exec_End;\r
 #endif\r
@@ -513,42 +519,46 @@ static u32 flag_I;
 #define CHECK_BRANCH_EXCEPTION(_PC_) \\r
        if ((_PC_)&1) \\r
        { \\r
-               u32 pr_PC=GET_PC; \\r
-               m68kcontext.execinfo |= M68K_EMULATE_GROUP_0; \\r
-               execute_exception_group_0(M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \\r
+               u32 new_PC, pr_PC=GET_PC; \\r
+               ctx->execinfo |= FM68K_EMULATE_GROUP_0; \\r
+               new_PC = execute_exception_group_0(ctx, M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \\r
+               SET_PC(new_PC); \\r
                CHECK_BRANCH_EXCEPTION_GOTO_END \\r
        }\r
 #else\r
 #define CHECK_BRANCH_EXCEPTION(_PC_)\r
 #endif\r
 \r
+#ifdef FAMEC_NO_GOTOS\r
+#define Opcode ctx->Opcode\r
+#define cycles_needed ctx->cycles_needed\r
+#define PC ctx->PC\r
+#define BasePC ctx->BasePC\r
+#define flag_C ctx->flag_C\r
+#define flag_V ctx->flag_V\r
+#define flag_NotZ ctx->flag_NotZ\r
+#define flag_N ctx->flag_N\r
+#define flag_X ctx->flag_X\r
+#endif\r
 \r
-static int init_jump_table(void);\r
-\r
-/* Custom function handler */\r
-typedef void (*icust_handler_func)(u32 vector);\r
+#define flag_T ctx->flag_T\r
+#define flag_S ctx->flag_S\r
+#define flag_I ctx->flag_I\r
 \r
 // global variable\r
 ///////////////////\r
 \r
-/* Current CPU context */\r
-M68K_CONTEXT *g_m68kcontext;\r
-#define m68kcontext (*g_m68kcontext)\r
+static u32 initialised = 0;\r
 \r
-/* static s32 io_cycle_counter; */\r
-static s32 cycles_needed=0;\r
-static u16 *PC;\r
-static u32 BasePC;\r
-// static u32 Fetch[M68K_FETCHBANK];\r
+#ifdef PICODRIVE_HACK\r
+extern M68K_CONTEXT PicoCpuFS68k;\r
+#endif\r
 \r
 /* Custom function handler */\r
-typedef void (*opcode_func)(void);\r
+typedef void (*opcode_func)(M68K_CONTEXT *ctx);\r
 \r
 static opcode_func JumpTable[0x10000];\r
 \r
-\r
-static u32 initialised = 0;\r
-\r
 // exception cycle table (taken from musashi core)\r
 static const s32 exception_cycle_table[256] =\r
 {\r
@@ -625,6 +635,7 @@ static const s32 exception_cycle_table[256] =
          4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4\r
 };\r
 \r
+static int init_jump_table(void);\r
 \r
 /***********************/\r
 /* core main functions */\r
@@ -635,14 +646,14 @@ static const s32 exception_cycle_table[256] =
 /* Debe ser llamado para inicializar la tabla de saltos de instruccion     */\r
 /* No recibe parametros y no devuelve nada                                 */\r
 /***************************************************************************/\r
-void m68k_init(void)\r
+void fm68k_init(void)\r
 {\r
 #ifdef FAMEC_DEBUG\r
        puts("Initializing FAME...");\r
 #endif\r
 \r
-    if (!initialised)\r
-           m68k_emulate(0);\r
+       if (!initialised)\r
+               init_jump_table();\r
 \r
 #ifdef FAMEC_DEBUG\r
        puts("FAME initialized.");\r
@@ -658,33 +669,33 @@ void m68k_init(void)
 /*     M68K_NO_SUP_ADDR_SPACE (2):  No se puede resetear porque no hay mapa   */\r
 /*             de memoria supervisor de extraccion de opcodes                 */\r
 /******************************************************************************/\r
-int m68k_reset(void)\r
+int fm68k_reset(M68K_CONTEXT *ctx)\r
 {\r
        if (!initialised)\r
-               m68k_emulate(0);\r
+               init_jump_table();\r
 \r
        // Si la CPU esta en ejecucion, salir con M68K_RUNNING\r
-       if (m68kcontext.execinfo & M68K_RUNNING)\r
+       if (ctx->execinfo & M68K_RUNNING)\r
                return M68K_RUNNING;\r
 \r
        // Resetear registros\r
-       memset(&m68kcontext.dreg[0], 0, 16*4);\r
+       //memset(&ctx->dreg[0], 0, 16*4);\r
 \r
        // Resetear interrupts, execinfo y ASP\r
-       m68kcontext.interrupts[0] = 0;\r
-       m68kcontext.execinfo = 0;\r
+       ctx->interrupts[0] = 0;\r
+       ctx->execinfo = 0;\r
        ASP = 0;\r
 \r
        // Fijar registro de estado\r
-       m68kcontext.sr = 0x2700;\r
+       ctx->sr = (ctx->sr & 0xff) | 0x2700;\r
 \r
        // Obtener puntero de pila inicial y PC\r
-       AREG(7) = m68kcontext.read_long(0);\r
-       m68kcontext.pc = m68kcontext.read_long(4);\r
+       AREG(7) = ctx->read_long(0);\r
+       ctx->pc = ctx->read_long(4);\r
 \r
 #ifdef FAMEC_DEBUG\r
        puts("Reset 68k done!\n");\r
-       printf("PC = 0x%08X\n",m68kcontext.pc);\r
+       printf("PC = 0x%08X\n",ctx->pc);\r
 #endif\r
 \r
     return M68K_OK;\r
@@ -696,208 +707,95 @@ int m68k_reset(void)
 /* No recibe parametros                                                     */\r
 /* Retorna 68k PC                                                           */\r
 /****************************************************************************/\r
-u32 m68k_get_pc(M68K_CONTEXT *context)\r
-{\r
-       return (context->execinfo & M68K_RUNNING)?(u32)PC-BasePC:context->pc;\r
-}\r
-\r
-\r
-/***************************************************************************/\r
-/*  m68k_get_register(register)                                            */\r
-/*  Parametro: Registro a obtener valor (indice)                           */\r
-/*  Retorno: Valor del registro requerido                                  */\r
-/*  Observacion: En caso de que el indice no sea correcto                  */\r
-/*               la funcion devolvera -1                                   */\r
-/***************************************************************************/\r
-u32 m68k_get_register(M68K_CONTEXT *context, m68k_register reg)\r
-{\r
-       M68K_CONTEXT *oldcontext = g_m68kcontext;\r
-       s32 ret;\r
-\r
-       g_m68kcontext = context;\r
-\r
-       switch (reg)\r
-       {\r
-               case M68K_REG_D0:\r
-               case M68K_REG_D1:\r
-               case M68K_REG_D2:\r
-               case M68K_REG_D3:\r
-               case M68K_REG_D4:\r
-               case M68K_REG_D5:\r
-               case M68K_REG_D6:\r
-               case M68K_REG_D7:\r
-                       ret = DREG(reg - M68K_REG_D0);\r
-                       break;\r
-\r
-               case M68K_REG_A0:\r
-               case M68K_REG_A1:\r
-               case M68K_REG_A2:\r
-               case M68K_REG_A3:\r
-               case M68K_REG_A4:\r
-               case M68K_REG_A5:\r
-               case M68K_REG_A6:\r
-               case M68K_REG_A7:\r
-                       ret = AREG(reg - M68K_REG_A0);\r
-                       break;\r
-\r
-               case M68K_REG_ASP:\r
-                       ret = ASP;\r
-                       break;\r
-\r
-               case M68K_REG_PC:\r
-                       ret = m68k_get_pc(context);\r
-                       break;\r
-\r
-               case M68K_REG_SR:\r
-                       ret = m68kcontext.sr;\r
-                       break;\r
-\r
-               default:\r
-                       ret = M68K_INV_REG;\r
-                       break;\r
-       }\r
-\r
-       g_m68kcontext = oldcontext;\r
-       return ret;\r
-}\r
-\r
-/***********************************************************************/\r
-/*  m68k_set_register(register,value)                                  */\r
-/*  Parametros: Registro (indice) y valor a asignar                    */\r
-/*  Retorno: Exito de la operacion                                     */\r
-/*           0  La operacion se ha realizado satisfactoriamente        */\r
-/*           1  El indice del registro no es valido (fuera de limites) */\r
-/***********************************************************************/\r
-u32 m68k_set_register(M68K_CONTEXT *context, m68k_register reg, u32 value)\r
+u32 fm68k_get_pc(const M68K_CONTEXT *ctx)\r
 {\r
-       M68K_CONTEXT *oldcontext = g_m68kcontext;\r
-       s32 ret = M68K_OK;\r
-\r
-       g_m68kcontext = context;\r
-\r
-       switch (reg)\r
-       {\r
-               case M68K_REG_D0:\r
-               case M68K_REG_D1:\r
-               case M68K_REG_D2:\r
-               case M68K_REG_D3:\r
-               case M68K_REG_D4:\r
-               case M68K_REG_D5:\r
-               case M68K_REG_D6:\r
-               case M68K_REG_D7:\r
-                       DREG(reg - M68K_REG_D0) = value;\r
-                       break;\r
-\r
-               case M68K_REG_A0:\r
-               case M68K_REG_A1:\r
-               case M68K_REG_A2:\r
-               case M68K_REG_A3:\r
-               case M68K_REG_A4:\r
-               case M68K_REG_A5:\r
-               case M68K_REG_A6:\r
-               case M68K_REG_A7:\r
-                       AREG(reg - M68K_REG_A0) = value;\r
-                       break;\r
-\r
-               case M68K_REG_ASP:\r
-                       ASP = value;\r
-                       break;\r
-\r
-               case M68K_REG_PC:\r
-                       if (m68kcontext.execinfo & M68K_RUNNING)\r
-                       {\r
-                               SET_PC(value & M68K_ADR_MASK);\r
-                       }\r
-                       else\r
-                       {\r
-                               m68kcontext.pc = value;\r
-                       }\r
-                       break;\r
-\r
-               case M68K_REG_SR:\r
-                       m68kcontext.sr = value & 0xFFFF;\r
-                       break;\r
-\r
-               default:\r
-                       ret = M68K_INV_REG;\r
-                       break;\r
-       }\r
-\r
-       g_m68kcontext = oldcontext;\r
-       return ret;\r
+#ifdef FAMEC_NO_GOTOS\r
+       return (ctx->execinfo & M68K_RUNNING)?(uptr)PC-BasePC:ctx->pc;\r
+#else\r
+       return ctx->pc; // approximate PC in this mode\r
+#endif\r
 }\r
 \r
 \r
 //////////////////////////\r
 // Chequea las interrupciones y las inicia\r
-static FAMEC_EXTRA_INLINE s32 interrupt_chk__(void)\r
+static FAMEC_EXTRA_INLINE s32 interrupt_chk__(M68K_CONTEXT *ctx)\r
 {\r
-       if (m68kcontext.interrupts[0] > flag_I)\r
-               return m68kcontext.interrupts[0];\r
+       if (ctx->interrupts[0] > flag_I)\r
+               return ctx->interrupts[0];\r
 \r
        return 0;\r
 }\r
 \r
+int fm68k_would_interrupt(M68K_CONTEXT *ctx)\r
+{\r
+       return interrupt_chk__(ctx);\r
+}\r
 \r
-static FAMEC_EXTRA_INLINE void execute_exception(s32 vect)\r
+static FAMEC_EXTRA_INLINE u32 execute_exception(M68K_CONTEXT *ctx, s32 vect, u32 oldPC, u32 oldSR)\r
 {\r
-       extern u32 flag_S;\r
-#ifndef FAMEC_IRQ_CYCLES\r
-       if ((vect<24)||(vect>31))\r
+       u32 newPC;\r
+       //u32 oldSR = GET_SR;\r
+\r
+        ctx->io_cycle_counter -= exception_cycle_table[vect];\r
+#ifdef FAMEC_EMULATE_TRACE\r
+       ctx->execinfo &= ~FM68K_EMULATE_TRACE;\r
 #endif\r
-        m68kcontext.io_cycle_counter -= exception_cycle_table[vect];\r
-       {\r
-               u32 newPC;\r
-               u32 oldPC;\r
-               u32 oldSR = GET_SR;\r
 \r
-               PRE_IO\r
+       PRE_IO\r
 \r
-               READ_LONG_F(vect * 4, newPC)\r
+       READ_LONG_F(vect * 4, newPC)\r
 \r
-               /* swap A7 and USP */\r
-               if (!flag_S)\r
-               {\r
-                       u32 tmpSP;\r
+       /* swap A7 and USP */\r
+       if (!flag_S)\r
+       {\r
+               u32 tmpSP;\r
 \r
-                       tmpSP = ASP;\r
-                       ASP = AREG(7);\r
-                       AREG(7) = tmpSP;\r
-               }\r
+               tmpSP = ASP;\r
+               ASP = AREG(7);\r
+               AREG(7) = tmpSP;\r
+       }\r
+\r
+       //oldPC = GET_PC;\r
+       PUSH_32_F(oldPC)\r
+       PUSH_16_F(oldSR)\r
 \r
-               oldPC = (u32)(PC) - BasePC;\r
-               PUSH_32_F(oldPC)\r
-               PUSH_16_F(oldSR)\r
+       /* adjust SR */\r
+       flag_S = M68K_SR_S;\r
+       flag_T = 0;\r
 \r
-               /* adjust SR */\r
-               flag_S = M68K_SR_S;\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
-               newPC&=M68K_ADR_MASK;\r
+       // SET_PC(newPC)\r
 \r
-               SET_PC(newPC)\r
+       POST_IO\r
 \r
-               POST_IO\r
-       }\r
+       return newPC;\r
 }\r
 \r
-static FAMEC_EXTRA_INLINE void execute_exception_group_0(s32 vect, u16 inst_reg, s32 addr, u16 spec_info)\r
+static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(M68K_CONTEXT *ctx, s32 vect, s32 addr, u16 spec_info, u32 oldSR)\r
 {\r
-       execute_exception(vect);\r
-       //if (!(m68kcontext.icust_handler && m68kcontext.icust_handler[vect]))\r
+       u32 newPC;\r
+       u16 inst_reg = 0;\r
+       newPC = execute_exception(ctx, vect, addr, oldSR);\r
+       //if (!(ctx->icust_handler && ctx->icust_handler[vect]))\r
        {\r
                PUSH_16_F(inst_reg);\r
                PUSH_32_F(addr);\r
                PUSH_16_F(spec_info);\r
        }\r
+       return newPC;\r
 }\r
 \r
 \r
-static void setup_jumptable(void);\r
-static u32 Opcode;\r
-\r
 #ifdef FAMEC_NO_GOTOS\r
 \r
-#define OPCODE(N_OP) static void OP_##N_OP(void)\r
+#define OPCODE(N_OP) static void OP_##N_OP(M68K_CONTEXT *ctx)\r
 #define CAST_OP(N_OP) (opcode_func)&OP_##N_OP\r
 #include "famec_opcodes.h"\r
 #endif\r
@@ -906,28 +804,47 @@ static u32 Opcode;
 // main exec function\r
 //////////////////////\r
 \r
-int m68k_emulate(s32 cycles)\r
+int fm68k_emulate(M68K_CONTEXT *ctx, s32 cycles, fm68k_call_reason reason)\r
 {\r
-       if (!initialised)\r
+#ifndef FAMEC_NO_GOTOS\r
+       u32 Opcode;\r
+       s32 cycles_needed;\r
+       u16 *PC;\r
+       uptr BasePC;\r
+       u32 flag_C;\r
+       u32 flag_V;\r
+       u32 flag_NotZ;\r
+       u32 flag_N;\r
+       u32 flag_X;\r
+\r
+       switch (reason)\r
        {\r
-#ifdef FAMEC_NO_GOTOS\r
-               init_jump_table();\r
-               return 0;\r
-#else\r
+       case fm68k_reason_init:\r
                goto init_jump_table;\r
+#ifdef PICODRIVE_HACK\r
+       case fm68k_reason_idle_install:\r
+               goto idle_install;\r
+       case fm68k_reason_idle_remove:\r
+               goto idle_remove;\r
 #endif\r
+       case fm68k_reason_emulate:\r
+               break;\r
        }\r
+#endif // FAMEC_NO_GOTOS\r
 \r
-       /* Comprobar si la CPU esta detenida debido a un doble error de bus */\r
-       if (m68kcontext.execinfo & M68K_FAULTED) return -1;\r
+       // won't emulate double fault\r
+       // if (ctx->execinfo & M68K_FAULTED) return -1;\r
 \r
-       if (m68kcontext.execinfo & M68K_HALTED)\r
+       // Cache PPL\r
+       flag_I = M68K_PPL;\r
+\r
+       if (ctx->execinfo & FM68K_HALTED)\r
        {\r
-               if (interrupt_chk__() <= 0)\r
+               if (interrupt_chk__(ctx) <= 0)\r
                {\r
                        return cycles;\r
                }\r
-               m68kcontext.execinfo &= ~M68K_HALTED;\r
+               ctx->execinfo &= ~FM68K_HALTED;\r
        }\r
 \r
 #ifdef FAMEC_DEBUG\r
@@ -935,16 +852,13 @@ int m68k_emulate(s32 cycles)
 #endif\r
 \r
        /* Poner la CPU en estado de ejecucion */\r
-       m68kcontext.execinfo |= M68K_RUNNING;\r
+       ctx->execinfo |= M68K_RUNNING;\r
 \r
        // Cache SR\r
-       SET_SR(m68kcontext.sr)\r
-\r
-       // Cache PPL\r
-       flag_I = M68K_PPL;\r
+       SET_SR(ctx->sr)\r
 \r
        // Fijar PC\r
-       SET_PC(m68kcontext.pc)\r
+       SET_PC(ctx->pc)\r
 \r
 #ifdef FAMEC_DEBUG\r
        printf("PC: %p\n",PC);\r
@@ -952,40 +866,41 @@ int m68k_emulate(s32 cycles)
 #endif\r
 \r
        /* guardar ciclos de ejecucion solicitados */\r
-       m68kcontext.io_cycle_counter = cycles;\r
+       ctx->io_cycle_counter = cycles;\r
        cycles_needed = 0;\r
 \r
 #ifdef FAMEC_EMULATE_TRACE\r
-       if (!(m68kcontext.execinfo & M68K_EMULATE_TRACE))\r
+       if (!(ctx->execinfo & FM68K_EMULATE_TRACE))\r
 #endif\r
        {\r
-               s32 line=interrupt_chk__();\r
+               s32 line=interrupt_chk__(ctx);\r
                if (line>0)\r
                {\r
                        /* comprobar si hay rutina de acknowledge */\r
-                       if (m68kcontext.iack_handler != NULL)\r
-                               m68kcontext.iack_handler(line);\r
+                       if (ctx->iack_handler != NULL)\r
+                               ctx->iack_handler(line);\r
                        else\r
-                               m68kcontext.interrupts[0] = 0;\r
+                               ctx->interrupts[0] = 0;\r
 \r
-                       execute_exception(line + 0x18);\r
+                       SET_PC(execute_exception(ctx, line + 0x18, GET_PC, GET_SR));\r
                        flag_I = (u32)line;\r
+                       if (ctx->io_cycle_counter <= 0) goto famec_End;\r
                }\r
 #ifdef FAMEC_EMULATE_TRACE\r
                else\r
                        if  (flag_T)\r
                        {\r
-                               m68kcontext.execinfo |= M68K_EMULATE_TRACE;\r
-                               cycles_needed= m68kcontext.io_cycle_counter;\r
-                               m68kcontext.io_cycle_counter=0;\r
+                               ctx->execinfo |= FM68K_EMULATE_TRACE;\r
+                               cycles_needed = ctx->io_cycle_counter;\r
+                               ctx->io_cycle_counter=0;\r
                        }\r
 #endif\r
        }\r
 \r
 \r
-#ifndef FAMEC_NO_GOTOS\r
+//#ifndef FAMEC_NO_GOTOS\r
 famec_Exec:\r
-#endif\r
+//#endif\r
 \r
 #ifdef FAMEC_DEBUG\r
        printf("Antes de NEXT... PC = %p\n", PC);\r
@@ -1003,66 +918,71 @@ famec_Exec:
 #endif\r
 \r
 #ifdef FAMEC_EMULATE_TRACE\r
-       if (m68kcontext.execinfo & M68K_EMULATE_TRACE)\r
+       if (ctx->execinfo & FM68K_EMULATE_TRACE)\r
        {\r
-               m68kcontext.io_cycle_counter= cycles_needed;\r
-               m68kcontext.execinfo &= ~M68K_EMULATE_TRACE;\r
-               m68kcontext.execinfo |= M68K_DO_TRACE;\r
-               execute_exception(M68K_TRACE_EX);\r
-               flag_T=0;\r
-               if (m68kcontext.io_cycle_counter > 0)\r
+               ctx->io_cycle_counter += cycles_needed;\r
+               cycles_needed = 0;\r
+               ctx->execinfo &= ~FM68K_EMULATE_TRACE;\r
+               ctx->execinfo |= FM68K_DO_TRACE;\r
+               SET_PC(execute_exception(ctx, M68K_TRACE_EX, GET_PC, GET_SR));\r
+               if (ctx->io_cycle_counter > 0)\r
                {\r
-                       NEXT\r
+                       //NEXT\r
+                       goto famec_Exec;\r
                }\r
        }\r
        else\r
 #endif\r
-               if (cycles_needed>0)\r
+               if (cycles_needed != 0)\r
                {\r
-                       s32 line=interrupt_chk__();\r
-                       m68kcontext.io_cycle_counter= cycles_needed;\r
+                       u32 line;\r
+                       ctx->io_cycle_counter += cycles_needed;\r
+                       cycles_needed = 0;\r
+                       //if (ctx->io_cycle_counter <= 0) goto famec_End;\r
+                       line=interrupt_chk__(ctx);\r
                        if (line>0)\r
                        {\r
-                               if (m68kcontext.iack_handler != NULL)\r
-                                       m68kcontext.iack_handler(line);\r
+                               if (ctx->iack_handler != NULL)\r
+                                       ctx->iack_handler(line);\r
                                else\r
-                                       m68kcontext.interrupts[0] = 0;\r
+                                       ctx->interrupts[0] = 0;\r
 \r
-                               execute_exception(line + 0x18);\r
+                               SET_PC(execute_exception(ctx, line + 0x18, GET_PC, GET_SR));\r
                                flag_I = (u32)line;\r
                        }\r
 #ifdef FAMEC_EMULATE_TRACE\r
-                       else if (!(flag_T))\r
+                       if (!(flag_T))\r
 #endif\r
-                       if (m68kcontext.io_cycle_counter > 0)\r
+                       if (ctx->io_cycle_counter > 0)\r
                        {\r
-                               NEXT\r
+                               //NEXT\r
+                               goto famec_Exec;\r
                        }\r
                }\r
 \r
-       m68kcontext.sr = GET_SR;\r
-       m68kcontext.pc = GET_PC;\r
+famec_End:\r
+       ctx->sr = GET_SR;\r
+       ctx->pc = GET_PC;\r
 \r
-       m68kcontext.execinfo &= ~M68K_RUNNING;\r
+       ctx->execinfo &= ~M68K_RUNNING;\r
 \r
 #ifdef FAMEC_DEBUG\r
        printf("En really end...\n");\r
        printf("PC: %p\n",PC);\r
        printf("BasePC: 0x%08x\n",BasePC);\r
-       printf("pc: 0x%08x\n",m68kcontext.pc);\r
+       printf("pc: 0x%08x\n",ctx->pc);\r
 #endif\r
 \r
-       return cycles - m68kcontext.io_cycle_counter;\r
+       return cycles - ctx->io_cycle_counter;\r
 \r
-#ifdef FAMEC_NO_GOTOS\r
+#ifndef FAMEC_NO_GOTOS\r
+init_jump_table:\r
+#else\r
 }\r
 \r
 static int init_jump_table(void)\r
-{{\r
-#else\r
-init_jump_table:\r
-{\r
 #endif\r
+{\r
        u32 i, j;\r
 \r
        for(i = 0x0000; i <= 0xFFFF; i += 0x0001)\r
@@ -1575,6 +1495,7 @@ init_jump_table:
                JumpTable[0x1EC0 + i] = CAST_OP(0x1EC0);\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                JumpTable[0x1F00 + i] = CAST_OP(0x1F00);\r
+#if 0\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0x1008 + i + j] = CAST_OP(0x1008);\r
@@ -1601,6 +1522,7 @@ init_jump_table:
                JumpTable[0x1EC8 + i] = CAST_OP(0x1EC8);\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                JumpTable[0x1F08 + i] = CAST_OP(0x1F08);\r
+#endif\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0x1010 + i + j] = CAST_OP(0x1010);\r
@@ -3730,9 +3652,11 @@ init_jump_table:
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0x9000 + i + j] = CAST_OP(0x9000);\r
+#if 0\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0x9008 + i + j] = CAST_OP(0x9008);\r
+#endif\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0x9010 + i + j] = CAST_OP(0x9010);\r
@@ -4009,9 +3933,11 @@ init_jump_table:
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xB000 + i + j] = CAST_OP(0xB000);\r
+#if 0\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xB008 + i + j] = CAST_OP(0xB008);\r
+#endif\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xB010 + i + j] = CAST_OP(0xB010);\r
@@ -4535,9 +4461,11 @@ init_jump_table:
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xD000 + i + j] = CAST_OP(0xD000);\r
+#if 0\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xD008 + i + j] = CAST_OP(0xD008);\r
+#endif\r
        for(i = 0x0000; i <= 0x0007; i += 0x0001)\r
                for(j = 0x0000; j <= 0x0E00; j += 0x0200)\r
                        JumpTable[0xD010 + i + j] = CAST_OP(0xD010);\r
@@ -5070,6 +4998,77 @@ 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
+#ifndef FAMEC_NO_GOTOS\r
+idle_install:\r
+#else\r
+int fm68k_idle_install(void)\r
+#endif\r
+{\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
+\r
+#ifndef FAMEC_NO_GOTOS\r
+idle_remove:\r
+#else\r
+int fm68k_idle_remove(void)\r
+#endif\r
+{\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 // PICODRIVE_HACK\r
+\r
+#ifndef FAMEC_NO_GOTOS\r
+}\r
+\r
+static int init_jump_table(void)\r
+{\r
+       return fm68k_emulate(NULL, 0, fm68k_reason_init);\r
+}\r
 \r
+#ifdef PICODRIVE_HACK\r
+int fm68k_idle_install(void)\r
+{\r
+       return fm68k_emulate(NULL, 0, fm68k_reason_idle_install);\r
+}\r
 \r
+int fm68k_idle_remove(void)\r
+{\r
+       return fm68k_emulate(NULL, 0, fm68k_reason_idle_remove);\r
+}\r
+#endif\r
+#endif // FAMEC_NO_GOTOS\r