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