/* 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
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
// 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
\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
- 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
+ PC = (u16*)((pc & M68K_ADR_MASK) + 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
+#else\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
+ BasePC -= pc & 0xFF000000; \\r
+ PC = (u16*)(pc + BasePC); \\r
+}\r
+\r
+#endif\r
\r
\r
#define PRE_IO \\r
#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
\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
#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
#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
#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 void 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
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
-\r
-/********************/\r
-/* helper functions */\r
-/********************/\r
-\r
-\r
-#if 0\r
-static void famec_SetFetch(u32 low_adr, u32 high_adr, u32 fetch_adr)\r
-{\r
- u32 i, j;\r
-\r
- i = (low_adr >> M68K_FETCHSFT) & M68K_FETCHMASK;\r
- j = (high_adr >> M68K_FETCHSFT) & M68K_FETCHMASK;\r
-\r
- while (i <= j)\r
- g_m68kcontext->Fetch[i++] = fetch_adr;\r
-}\r
-\r
-static void famec_SetBanks(void)\r
-{\r
- u32 i=0;\r
- while(m68kcontext.fetch[i].low_addr != (u32)-1)\r
- {\r
- famec_SetFetch(m68kcontext.fetch[i].low_addr,m68kcontext.fetch[i].high_addr,m68kcontext.fetch[i].offset);\r
- i++;\r
- }\r
-}\r
-#endif\r
-\r
+static int init_jump_table(void);\r
\r
/***********************/\r
/* core main functions */\r
/* 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
/* 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
/* No recibe parametros */\r
/* Retorna 68k PC */\r
/****************************************************************************/\r
-u32 m68k_get_pc(M68K_CONTEXT *context)\r
+u32 fm68k_get_pc(const M68K_CONTEXT *ctx)\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
-{\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 = (u32)(PC) - BasePC;\r
- PUSH_32_F(oldPC)\r
- PUSH_16_F(oldSR)\r
+ //oldPC = GET_PC;\r
+ PUSH_32_F(oldPC)\r
+ PUSH_16_F(oldSR)\r
\r
- /* adjust SR */\r
- flag_S = M68K_SR_S;\r
+ /* adjust SR */\r
+ flag_S = M68K_SR_S;\r
+ flag_T = 0;\r
\r
- newPC&=M68K_ADR_MASK;\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
+ // SET_PC(newPC)\r
\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
// 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
- init_jump_table();\r
- return 0;\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
#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
#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
#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
-}\r
-\r
+ return cycles - ctx->io_cycle_counter;\r
\r
+#ifndef FAMEC_NO_GOTOS\r
+init_jump_table:\r
+#else\r
+}\r
\r
-static void init_jump_table(void)\r
+static int init_jump_table(void)\r
+#endif\r
{\r
u32 i, j;\r
\r
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
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
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
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
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
JumpTable[0xF000 + i] = CAST_OP(0xF000);\r
\r
initialised = 1;\r
+ return 0;\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