#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_CHECK_BRANCHES\r
+#define FAMEC_EMULATE_TRACE\r
+#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
#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
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
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
#endif\r
\r
\r
-static int init_jump_table(void);\r
-\r
// global variable\r
///////////////////\r
\r
#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
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
}\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
// main exec function\r
//////////////////////\r
\r
-int fm68k_emulate(s32 cycles, int dualcore)\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
\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 (dualcore) goto dualcore_mode;\r
-famec_restart:\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
#endif\r
if (cycles_needed != 0)\r
{\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
printf("pc: 0x%08x\n",m68kcontext.pc);\r
#endif\r
\r
-#ifdef PICODRIVE_HACK\r
- if (!dualcore)\r
-#endif\r
- return cycles - m68kcontext.io_cycle_counter;\r
-\r
-#ifdef PICODRIVE_HACK\r
-dualcore_mode:\r
-\r
- while (1)\r
- {\r
- extern int SekCycleAim, SekCycleCnt, SekCycleAimS68k, SekCycleCntS68k;\r
- #define PS_STEP_M68K ((488<<16)/20) // ~24\r
- if (dualcore == 1)\r
- {\r
- dualcore = (488<<16); // ~ cycn in Pico.c\r
- // adjust for first iteration\r
- g_m68kcontext = &PicoCpuFS68k;\r
- cycles = m68kcontext.io_cycle_counter = 0;\r
- }\r
- if (g_m68kcontext == &PicoCpuFS68k)\r
- {\r
- SekCycleCntS68k += cycles - m68kcontext.io_cycle_counter;\r
- // end?\r
- dualcore -= PS_STEP_M68K;\r
- if (dualcore < 0) return 0;\r
- // become main 68k\r
- g_m68kcontext = &PicoCpuFM68k;\r
- if ((cycles = SekCycleAim-SekCycleCnt-(dualcore>>16)) > 0)\r
- {\r
- if ((m68kcontext.execinfo & FM68K_HALTED) && m68kcontext.interrupts[0] <= (M68K_PPL))\r
- SekCycleCnt += cycles; // halted\r
- else goto famec_restart;\r
- //else { printf("go main %i\n", cycles); goto famec_restart; }\r
- }\r
- cycles = m68kcontext.io_cycle_counter = 0;\r
- }\r
- if (g_m68kcontext == &PicoCpuFM68k)\r
- {\r
- int cycn_s68k = (dualcore + dualcore/2 + dualcore/8) >> 16;\r
- SekCycleCnt += cycles - m68kcontext.io_cycle_counter;\r
- // become sub 68k\r
- g_m68kcontext = &PicoCpuFS68k;\r
- if ((cycles = SekCycleAimS68k-SekCycleCntS68k-cycn_s68k) > 0)\r
- {\r
- if ((m68kcontext.execinfo & FM68K_HALTED) && m68kcontext.interrupts[0] <= (M68K_PPL))\r
- SekCycleCntS68k += cycles; // halted\r
- else goto famec_restart;\r
- }\r
- cycles = m68kcontext.io_cycle_counter = 0;\r
- }\r
- }\r
-#endif\r
-\r
-\r
-\r
-#ifdef FAMEC_NO_GOTOS\r
-}\r
+ return cycles - m68kcontext.io_cycle_counter;\r
\r
-static int init_jump_table(void)\r
-{{\r
-#else\r
init_jump_table:\r
{\r
-#endif\r
u32 i, j;\r
\r
for(i = 0x0000; i <= 0xFFFF; i += 0x0001)\r
\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