mirror of
https://github.com/libretro/beetle-pce-fast-libretro.git
synced 2024-11-26 17:40:40 +00:00
761 lines
21 KiB
C
761 lines
21 KiB
C
/* Mednafen - Multi-system Emulator
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <boolean.h>
|
|
|
|
#include "pce.h"
|
|
#include "vdc.h"
|
|
#include "../state_helpers.h"
|
|
|
|
bool PCE_IsCD;
|
|
int pce_overclocked;
|
|
static uint8 dummy_bank[8192 + 8192]; // + 8192 for PC-as-ptr safety padding
|
|
struct HuC6280 HuCPU;
|
|
|
|
#define HU_PC PC_local //HuCPU.PC
|
|
#define HU_PC_base HuCPU.PC_base
|
|
#define HU_A HuCPU.A
|
|
#define HU_X X_local //HuCPU.X
|
|
#define HU_Y Y_local //HuCPU.Y
|
|
#define HU_S HuCPU.S
|
|
#define HU_P P_local //HuCPU.P
|
|
#define HU_PI HuCPU.mooPI
|
|
#define HU_IRQlow HuCPU.IRQlow
|
|
#define HU_Page1 Page1_local
|
|
//HuCPU.Page1
|
|
//Page1_local //HuCPU.Page1
|
|
|
|
#ifdef HUC6280_LAZY_FLAGS
|
|
#define HU_ZNFlags HuCPU.ZNFlags
|
|
#endif
|
|
|
|
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
#define LOAD_LOCALS_PC() uintptr_t PC_local = HuCPU.PC;
|
|
#else
|
|
#define LOAD_LOCALS_PC() uint32 PC_local /*asm ("edi")*/ = HuCPU.PC; // asm ("edi") = HuCPU.PC;
|
|
#endif
|
|
|
|
#define LOAD_LOCALS() \
|
|
|
|
#define SAVE_LOCALS() HuCPU.PC = PC_local; \
|
|
HuCPU.X = X_local; \
|
|
HuCPU.Y = Y_local; \
|
|
HuCPU.P = P_local; \
|
|
HuCPU.Page1 = Page1_local;
|
|
|
|
#ifdef HUC6280_LAZY_FLAGS
|
|
#define COMPRESS_FLAGS() HU_P &= ~(N_FLAG | Z_FLAG); HU_P |= ((HU_ZNFlags >> 24) & 0x80) | ((HU_ZNFlags & 0xFF) ? 0 : Z_FLAG);
|
|
//((((HU_ZNFlags & 0xFF) - 1) >> 8) & Z_FLAG);
|
|
#define EXPAND_FLAGS() HU_ZNFlags = (HU_P << 24) | ((HU_P & Z_FLAG) ^ Z_FLAG);
|
|
#else
|
|
#define COMPRESS_FLAGS()
|
|
#define EXPAND_FLAGS()
|
|
#endif
|
|
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
#define GetRealPC() ((unsigned int)(HU_PC - HU_PC_base))
|
|
#define GetRealPC_EXTERNAL() ((unsigned int)(HuCPU.PC - HuCPU.PC_base))
|
|
#else
|
|
#define GetRealPC() (HU_PC)
|
|
#define GetRealPC_EXTERNAL() (HuCPU.PC)
|
|
#endif
|
|
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
#define SetPC(value) { unsigned int tempmoo = value; HU_PC = HuCPU.FastPageR[tempmoo >> 13] + tempmoo; \
|
|
HU_PC_base = HU_PC - tempmoo; }
|
|
#define SetPC_EXTERNAL(value) { unsigned int tempmoo = value; \
|
|
HuCPU.PC = HuCPU.FastPageR[tempmoo >> 13] + tempmoo; HuCPU.PC_base = HuCPU.PC - tempmoo; }
|
|
#else
|
|
#define SetPC(value) { HU_PC = (value); }
|
|
#define SetPC_EXTERNAL(value) { HuCPU.PC = (value); }
|
|
#endif
|
|
|
|
// Page change PC, GET IT?!
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
#define FixPC_PC() SetPC(GetRealPC());
|
|
#else
|
|
#define FixPC_PC()
|
|
#endif
|
|
|
|
#define IncPC() HU_PC++;
|
|
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
#define RdAtPC() (*(uint8*)HU_PC)
|
|
#else
|
|
#define RdAtPC() RdOp(HU_PC)
|
|
#endif
|
|
|
|
// If we change this definition, we'll need to also fix HuC6280_StealCycle() in huc6280.h
|
|
#define ADDCYC(x) { HuCPU.timestamp += x; }
|
|
|
|
#define SET_MPR(arg_i, arg_v) \
|
|
{ \
|
|
const unsigned int wmpr = arg_i, wbank = arg_v; \
|
|
if(wmpr == 1) \
|
|
{ \
|
|
HU_Page1 = HuCPU.FastMap[wbank]; \
|
|
} \
|
|
HuCPU.MPR[wmpr] = wbank; \
|
|
HuCPU.FastPageR[wmpr] = (uintptr_t)HuCPU.FastMap[wbank] - wmpr * 8192; \
|
|
}
|
|
|
|
void HuC6280_SetMPR(int i, int v)
|
|
{
|
|
uint8 *Page1_local = HuCPU.Page1;
|
|
|
|
SET_MPR(i, v);
|
|
|
|
HuCPU.Page1 = Page1_local;
|
|
}
|
|
|
|
|
|
static void HuC6280_FlushMPRCache(void)
|
|
{
|
|
int x;
|
|
for(x = 0; x < 9; x++)
|
|
HuC6280_SetMPR(x, HuCPU.MPR[x & 0x7]);
|
|
}
|
|
|
|
static INLINE uint8 RdMem(unsigned int A)
|
|
{
|
|
uint8 wmpr = HuCPU.MPR[A >> 13];
|
|
return(HuCPU.PCERead[wmpr]((wmpr << 13) | (A & 0x1FFF)));
|
|
}
|
|
|
|
static INLINE uint16 RdMem16(unsigned int A)
|
|
{
|
|
uint16 ret;
|
|
|
|
ret = RdMem(A);
|
|
ret |= RdMem(A + 1) << 8;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
static INLINE void WrMem(unsigned int A, uint8 V)
|
|
{
|
|
uint8 wmpr = HuCPU.MPR[A >> 13];
|
|
HuCPU.PCEWrite[wmpr]((wmpr << 13) | (A & 0x1FFF), V);
|
|
}
|
|
|
|
static INLINE uint8 RdOp(unsigned int A)
|
|
{
|
|
return *(uint8*)(HuCPU.FastPageR[A >> 13] + A);
|
|
}
|
|
|
|
#define PUSH(V) \
|
|
{ \
|
|
HU_Page1[0x100 + HU_S] = V; \
|
|
HU_S--; \
|
|
}
|
|
|
|
#define PUSH_PC() \
|
|
{ \
|
|
unsigned int real_pc = GetRealPC(); \
|
|
PUSH(real_pc >> 8); \
|
|
PUSH(real_pc); \
|
|
}
|
|
|
|
#define POP() HU_Page1[0x100 + ++HU_S]
|
|
|
|
#define POP_PC() \
|
|
{ \
|
|
unsigned int npc; \
|
|
npc = POP(); \
|
|
npc |= POP() << 8; \
|
|
SetPC(npc); \
|
|
}
|
|
|
|
// Hopefully we never RTS to 0x0000. ;)
|
|
#define POP_PC_AP() \
|
|
{ \
|
|
uint32 npc; \
|
|
npc = POP(); \
|
|
npc |= POP() << 8; \
|
|
npc++; \
|
|
SetPC(npc); \
|
|
}
|
|
|
|
/* Some of these operations will only make sense if you know what the flag
|
|
constants are. */
|
|
|
|
#ifdef HUC6280_LAZY_FLAGS
|
|
#define X_ZN(zort) { HU_ZNFlags = (int32)(int8)(uint8)(zort); }
|
|
#define X_ZN_BIT(opres, argie) { HU_ZNFlags = (opres) | ((argie) << 24); }
|
|
#else
|
|
static uint8 ZNTable[256];
|
|
#define X_ZN(zort) HU_P&=~(Z_FLAG|N_FLAG);HU_P|=ZNTable[zort]
|
|
#define X_ZN_BIT(opres, argie) { HU_P &= ~(Z_FLAG | N_FLAG); HU_P |= ZNTable[opres] & Z_FLAG; HU_P |= argie & N_FLAG; }
|
|
#endif
|
|
|
|
#define JR(cond) \
|
|
{ \
|
|
if(cond) \
|
|
{ \
|
|
int32 disp; \
|
|
disp = 1 + (int8)RdAtPC(); \
|
|
ADDCYC(2); \
|
|
HU_PC+=disp; \
|
|
} \
|
|
else IncPC(); \
|
|
}
|
|
|
|
#define BRA \
|
|
{ \
|
|
int32 disp; \
|
|
disp = 1 + (int8)RdAtPC(); \
|
|
HU_PC+=disp; \
|
|
}
|
|
|
|
#define BBRi(bitto) JR(!(x & (1 << bitto)))
|
|
#define BBSi(bitto) JR(x & (1 << bitto))
|
|
|
|
#define ST0 VDC_Write_ST(0, x)
|
|
#define ST1 VDC_Write_ST(2, x)
|
|
#define ST2 VDC_Write_ST(3, x)
|
|
|
|
#define LDA HU_A=x;X_ZN(HU_A)
|
|
#define LDX HU_X=x;X_ZN(HU_X)
|
|
#define LDY HU_Y=x;X_ZN(HU_Y)
|
|
|
|
/* All of the freaky arithmetic operations. */
|
|
#define AND HU_A&=x;X_ZN(HU_A);
|
|
|
|
#define BIT HU_P&=~V_FLAG; X_ZN_BIT(x & HU_A, x); HU_P |= x & V_FLAG;
|
|
#define EOR HU_A^=x;X_ZN(HU_A);
|
|
#define ORA HU_A|=x;X_ZN(HU_A);
|
|
|
|
#define ADC { \
|
|
if(HU_P & D_FLAG) \
|
|
{ \
|
|
uint32 tmp; \
|
|
tmp = (HU_A & 0x0F) + (x & 0x0F) + (HU_P & 1); \
|
|
if(tmp >= 0x0A) \
|
|
tmp += 0x06; \
|
|
tmp += (HU_A & 0xF0) + (x & 0xF0); \
|
|
if(tmp >= 0xA0) \
|
|
tmp += 0x60; \
|
|
HU_P &= ~C_FLAG; \
|
|
if(tmp & 0xFF00) \
|
|
HU_P |= C_FLAG; \
|
|
HU_A = tmp; \
|
|
X_ZN(HU_A); \
|
|
} \
|
|
else \
|
|
{ \
|
|
uint32 l=HU_A+x+(HU_P&1); \
|
|
HU_P&=~(C_FLAG|V_FLAG); \
|
|
HU_P|=((((HU_A^x)&0x80)^0x80) & ((HU_A^l)&0x80))>>1; \
|
|
HU_P|=(l>>8)&C_FLAG; \
|
|
HU_A=l; \
|
|
X_ZN(HU_A); \
|
|
} \
|
|
}
|
|
|
|
#define SBC if(HU_P & D_FLAG) \
|
|
{ \
|
|
const uint8 m = (HU_A & 0xF) - (x & 0xF) - ((HU_P & 1) ^ 1); \
|
|
const uint8 n = (HU_A >> 4) - (x >> 4) - ((m >> 4) & 1); \
|
|
uint8 res = (n << 4) | (m & 0xF); \
|
|
if(m & 0x10) \
|
|
res -= 0x06; \
|
|
if(n & 0x10) \
|
|
res -= 0x60; \
|
|
HU_A = res; \
|
|
HU_P &= ~C_FLAG; \
|
|
HU_P |= ((n >> 4) & 0x1) ^ 1; \
|
|
X_ZN(HU_A); \
|
|
} else { \
|
|
uint32 l=HU_A-x-((HU_P&1)^1); \
|
|
HU_P&=~(C_FLAG|V_FLAG); \
|
|
HU_P|=((HU_A^l)&(HU_A^x)&0x80)>>1; \
|
|
HU_P|=((l>>8)&C_FLAG)^C_FLAG; \
|
|
HU_A=l; \
|
|
X_ZN(HU_A); \
|
|
}
|
|
|
|
#define CMPL(a1,a2) { \
|
|
uint32 t=a1-a2; \
|
|
X_ZN(t&0xFF); \
|
|
HU_P&=~C_FLAG; \
|
|
HU_P|=((t>>8)&C_FLAG)^C_FLAG; \
|
|
}
|
|
|
|
#define TAM \
|
|
for(i = 0; i < 8; i ++) { \
|
|
if(x & (1 << i)) \
|
|
{ \
|
|
SET_MPR(i, HU_A); \
|
|
} \
|
|
} SET_MPR(8, HuCPU.MPR[0]);
|
|
|
|
#define TMA \
|
|
for(i = 0; i < 8; i ++) { \
|
|
if(x & (1 << i)) \
|
|
HU_A = HuCPU.MPR[i]; \
|
|
}
|
|
|
|
#define CSL
|
|
#define CSH
|
|
|
|
#define RMB(bitto) x &= ~(1 << (bitto & 7))
|
|
#define SMB(bitto) x |= 1 << (bitto & 7)
|
|
|
|
#define TSB { HU_P &= ~V_FLAG; X_ZN_BIT(x | HU_A, x); HU_P |= x & V_FLAG; x |= HU_A; }
|
|
#define TRB { HU_P &= ~V_FLAG; X_ZN_BIT(x & ~HU_A, x); HU_P |= x & V_FLAG; x &= ~HU_A; }
|
|
#define TST { HU_P &= ~V_FLAG; X_ZN_BIT(x & zoomhack, x); HU_P |= x & V_FLAG; }
|
|
|
|
#define CMP CMPL(HU_A,x)
|
|
#define CPX CMPL(HU_X,x)
|
|
#define CPY CMPL(HU_Y,x)
|
|
|
|
/* The following operations modify the byte being worked on. */
|
|
#define DEC x--;X_ZN(x)
|
|
#define INC x++;X_ZN(x)
|
|
|
|
#define ASL HU_P&=~C_FLAG;HU_P|=x>>7;x<<=1;X_ZN(x)
|
|
#define LSR HU_P&=~C_FLAG;HU_P|=x&1;x>>=1;X_ZN(x)
|
|
|
|
#define ROL { \
|
|
uint8 l=x>>7; \
|
|
x<<=1; \
|
|
x|=HU_P&C_FLAG; \
|
|
HU_P&=~C_FLAG; \
|
|
HU_P|=l; \
|
|
X_ZN(x); \
|
|
}
|
|
#define ROR { \
|
|
uint8 l=x&1; \
|
|
x>>=1; \
|
|
x|=(HU_P&C_FLAG)<<7; \
|
|
HU_P&=~C_FLAG; \
|
|
HU_P|=l; \
|
|
X_ZN(x); \
|
|
}
|
|
|
|
/* Absolute */
|
|
#define GetAB(target) \
|
|
{ \
|
|
target=RdAtPC(); \
|
|
IncPC(); \
|
|
target|=RdAtPC()<<8; \
|
|
IncPC(); \
|
|
}
|
|
|
|
/* Absolute Indexed(for reads) */
|
|
#define GetABI(target, i) \
|
|
{ \
|
|
unsigned int tmp; \
|
|
GetAB(tmp); \
|
|
target=tmp; \
|
|
target+=i; \
|
|
}
|
|
|
|
/* Zero Page */
|
|
#define GetZP(target) \
|
|
{ \
|
|
target=RdAtPC(); \
|
|
IncPC(); \
|
|
}
|
|
|
|
/* Zero Page Indexed */
|
|
#define GetZPI(target,i) \
|
|
{ \
|
|
target=i+RdAtPC(); \
|
|
IncPC(); \
|
|
}
|
|
|
|
/* Indirect */
|
|
#define GetIND(target) \
|
|
{ \
|
|
uint8 tmp; \
|
|
tmp=RdAtPC(); \
|
|
IncPC(); \
|
|
target=HU_Page1[tmp]; \
|
|
tmp++; \
|
|
target|=HU_Page1[tmp]<<8; \
|
|
}
|
|
|
|
|
|
/* Indexed Indirect */
|
|
#define GetIX(target) \
|
|
{ \
|
|
uint8 tmp; \
|
|
tmp=RdAtPC(); \
|
|
IncPC(); \
|
|
tmp+=HU_X; \
|
|
target=HU_Page1[tmp]; \
|
|
tmp++; \
|
|
target|=HU_Page1[tmp] <<8; \
|
|
}
|
|
|
|
/* Indirect Indexed(for reads) */
|
|
#define GetIY(target) \
|
|
{ \
|
|
unsigned int rt; \
|
|
uint8 tmp; \
|
|
tmp=RdAtPC(); \
|
|
rt=HU_Page1[tmp]; \
|
|
tmp++; \
|
|
rt|=HU_Page1[tmp]<<8; \
|
|
target = (rt + HU_Y); \
|
|
IncPC(); \
|
|
}
|
|
|
|
/* Now come the macros to wrap up all of the above stuff addressing mode functions
|
|
and operation macros. Note that operation macros will always operate(redundant
|
|
redundant) on the variable "x".
|
|
*/
|
|
|
|
#define RMW_A(op) {uint8 x=HU_A; op; HU_A=x; break; } /* Meh... */
|
|
#define RMW_AB(op) {unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
|
|
#define RMW_ABI(reg,op) {unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; WrMem(EA,x); break; }
|
|
#define RMW_ABX(op) RMW_ABI(HU_X,op)
|
|
#define RMW_ABY(op) RMW_ABI(HU_Y,op)
|
|
#define RMW_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x = RdMem(EA); op; WrMem(EA, x); break; }
|
|
#define RMW_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
|
|
#define RMW_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; WrMem(EA,x); break; }
|
|
#define RMW_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break; }
|
|
#define RMW_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; HU_Page1[EA] = x; break;}
|
|
|
|
#define LD_IM(op) { uint8 x; x=RdAtPC(); IncPC(); op; break; }
|
|
#define LD_ZP(op) { uint8 EA; uint8 x; GetZP(EA); x=HU_Page1[EA]; op; break; }
|
|
#define LD_ZPX(op) { uint8 EA; uint8 x; GetZPI(EA,HU_X); x=HU_Page1[EA]; op; break; }
|
|
#define LD_ZPY(op) { uint8 EA; uint8 x; GetZPI(EA,HU_Y); x=HU_Page1[EA]; op; break; }
|
|
#define LD_AB(op) { unsigned int EA; uint8 x; GetAB(EA); x=RdMem(EA); op; break; }
|
|
#define LD_ABI(reg,op) { unsigned int EA; uint8 x; GetABI(EA,reg); x=RdMem(EA); op; break; }
|
|
#define LD_ABX(op) LD_ABI(HU_X,op)
|
|
#define LD_ABY(op) LD_ABI(HU_Y,op)
|
|
|
|
#define LD_IND(op) { unsigned int EA; uint8 x; GetIND(EA); x=RdMem(EA); op; break; }
|
|
#define LD_IX(op) { unsigned int EA; uint8 x; GetIX(EA); x=RdMem(EA); op; break; }
|
|
#define LD_IY(op) { unsigned int EA; uint8 x; GetIY(EA); x=RdMem(EA); op; break; }
|
|
|
|
#define BMT_PREHONK(pork) HuCPU.in_block_move = IBM_##pork;
|
|
#define BMT_HONKHONK(pork) if(HuCPU.timestamp >= next_user_event) goto GetOutBMT; continue_the_##pork:
|
|
|
|
#define BMT_TDD BMT_PREHONK(TDD); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src--; HuCPU.bmt_dest--; BMT_HONKHONK(TDD); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
|
|
#define BMT_TAI BMT_PREHONK(TAI); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src + HuCPU.bmt_alternate)); HuCPU.bmt_dest++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TAI); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
|
|
#define BMT_TIA BMT_PREHONK(TIA); {HuCPU.bmt_alternate = 0; do { ADDCYC(6); WrMem(HuCPU.bmt_dest + HuCPU.bmt_alternate, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_alternate ^= 1; BMT_HONKHONK(TIA); HuCPU.bmt_length--; } while(HuCPU.bmt_length); }
|
|
#define BMT_TII BMT_PREHONK(TII); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; HuCPU.bmt_dest++; BMT_HONKHONK(TII); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
|
|
#define BMT_TIN BMT_PREHONK(TIN); do { ADDCYC(6); WrMem(HuCPU.bmt_dest, RdMem(HuCPU.bmt_src)); HuCPU.bmt_src++; BMT_HONKHONK(TIN); HuCPU.bmt_length--; } while(HuCPU.bmt_length);
|
|
|
|
// Block memory transfer load
|
|
#define LD_BMT(op) { PUSH(HU_Y); PUSH(HU_A); PUSH(HU_X); GetAB(HuCPU.bmt_src); GetAB(HuCPU.bmt_dest); GetAB(HuCPU.bmt_length); op; HuCPU.in_block_move = 0; HU_X = POP(); HU_A = POP(); HU_Y = POP(); break; }
|
|
|
|
#define ST_ZP(r) {uint8 EA; GetZP(EA); HU_Page1[EA] = r; break;}
|
|
#define ST_ZPX(r) {uint8 EA; GetZPI(EA,HU_X); HU_Page1[EA] = r; break;}
|
|
#define ST_ZPY(r) {uint8 EA; GetZPI(EA,HU_Y); HU_Page1[EA] = r; break;}
|
|
#define ST_AB(r) {unsigned int EA; GetAB(EA); WrMem(EA, r); break;}
|
|
#define ST_ABI(reg,r) {unsigned int EA; GetABI(EA,reg); WrMem(EA,r); break; }
|
|
#define ST_ABX(r) ST_ABI(HU_X,r)
|
|
#define ST_ABY(r) ST_ABI(HU_Y,r)
|
|
|
|
#define ST_IND(r) {unsigned int EA; GetIND(EA); WrMem(EA,r); break; }
|
|
#define ST_IX(r) {unsigned int EA; GetIX(EA); WrMem(EA,r); break; }
|
|
#define ST_IY(r) {unsigned int EA; GetIY(EA); WrMem(EA,r); break; }
|
|
|
|
static const uint8 CycTable[256] =
|
|
{
|
|
/*0x00*/ 8, 7, 3, 4, 6, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,
|
|
/*0x10*/ 2, 7, 7, 4, 6, 4, 6, 7, 2, 5, 2, 2, 7, 5, 7, 6,
|
|
/*0x20*/ 7, 7, 3, 4, 4, 4, 6, 7, 4, 2, 2, 2, 5, 5, 7, 6,
|
|
/*0x30*/ 2, 7, 7, 2, 4, 4, 6, 7, 2, 5, 2, 2, 5, 5, 7, 6,
|
|
/*0x40*/ 7, 7, 3, 4, 8, 4, 6, 7, 3, 2, 2, 2, 4, 5, 7, 6,
|
|
/*0x50*/ 2, 7, 7, 5, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
|
|
/*0x60*/ 7, 7, 2, 2, 4, 4, 6, 7, 4, 2, 2, 2, 7, 5, 7, 6,
|
|
/*0x70*/ 2, 7, 7, 17, 4, 4, 6, 7, 2, 5, 4, 2, 7, 5, 7, 6,
|
|
|
|
/*0x80*/ 4, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
|
|
/*0x90*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
|
|
/*0xA0*/ 2, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,
|
|
/*0xB0*/ 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,
|
|
/*0xC0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
|
|
/*0xD0*/ 2, 7, 7, 17, 3, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,
|
|
/*0xE0*/ 2, 7, 2, 17, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,
|
|
/*0xF0*/ 2, 7, 7, 17, 2, 4, 6, 7, 2, 5, 4, 2, 2, 5, 7, 6,
|
|
};
|
|
|
|
void HuC6280_Reset(void)
|
|
{
|
|
int i;
|
|
unsigned int npc;
|
|
HuCPU.timer_next_timestamp = HuCPU.timestamp + 1024;
|
|
|
|
HuCPU.timer_load = 0;
|
|
HuCPU.timer_value = 0;
|
|
HuCPU.timer_status = 0;
|
|
HuCPU.in_block_move = 0;
|
|
|
|
HuCPU.IRQMask = HuCPU.IRQMaskDelay = 7;
|
|
|
|
HuC6280_SetMPR(0, 0xFF);
|
|
HuC6280_SetMPR(8, 0xFF);
|
|
HuC6280_SetMPR(1, 0xF8);
|
|
|
|
for(i = 2; i < 8; i++)
|
|
HuC6280_SetMPR(i, 0);
|
|
|
|
npc = RdMem16(0xFFFE);
|
|
|
|
#define PC_local HuCPU.PC
|
|
SetPC(npc);
|
|
#undef PC_local
|
|
|
|
HuCPU.mooPI = I_FLAG;
|
|
HuCPU.P = I_FLAG;
|
|
|
|
HU_IRQlow = 0;
|
|
}
|
|
|
|
void HuC6280_Init(void)
|
|
{
|
|
int x;
|
|
unsigned i;
|
|
memset(&HuCPU,0,sizeof(HuCPU));
|
|
|
|
#ifdef HUC6280_LAZY_FLAGS
|
|
#else
|
|
for(x=0; x < 256; x++)
|
|
{
|
|
if(!x) ZNTable[x]=Z_FLAG;
|
|
else if (x&0x80) ZNTable[x]=N_FLAG;
|
|
else ZNTable[x]=0;
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < 0x100; i++)
|
|
HuCPU.FastMap[i] = dummy_bank;
|
|
}
|
|
|
|
void HuC6280_Power(void)
|
|
{
|
|
int i;
|
|
memset(dummy_bank, 0, sizeof(dummy_bank));
|
|
|
|
HuCPU.IRQlow = 0;
|
|
|
|
HuCPU.A = 0;
|
|
HuCPU.X = 0;
|
|
HuCPU.Y = 0;
|
|
HuCPU.S = 0;
|
|
HuCPU.P = 0;
|
|
HuCPU.mooPI = 0;
|
|
|
|
HuCPU.PC = 0;
|
|
|
|
HuCPU.timestamp = 0;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
HuCPU.MPR[i] = 0;
|
|
HuCPU.FastPageR[i] = 0;
|
|
}
|
|
HuC6280_Reset();
|
|
}
|
|
|
|
void HuC6280_Run(int32 cycles)
|
|
{
|
|
int i;
|
|
int32 next_event;
|
|
const int32 next_user_event = HuCPU.previous_next_user_event + cycles * pce_overclocked;
|
|
|
|
HuCPU.previous_next_user_event = next_user_event;
|
|
|
|
{
|
|
#ifdef HUC6280_CRAZY_VERSION
|
|
uintptr_t PC_local = HuCPU.PC;
|
|
#else
|
|
uint32 PC_local = HuCPU.PC;
|
|
#endif
|
|
uint8 X_local = HuCPU.X;
|
|
uint8 Y_local = HuCPU.Y;
|
|
uint8 P_local = HuCPU.P;
|
|
uint8 *Page1_local = HuCPU.Page1;
|
|
|
|
if(HuCPU.timestamp >= next_user_event)
|
|
return;
|
|
|
|
if(HuCPU.in_block_move)
|
|
{
|
|
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
|
|
|
|
switch(HuCPU.in_block_move)
|
|
{
|
|
case IBM_TIA: goto continue_the_TIA;
|
|
case IBM_TAI: goto continue_the_TAI;
|
|
case IBM_TDD: goto continue_the_TDD;
|
|
case IBM_TII: goto continue_the_TII;
|
|
case IBM_TIN: goto continue_the_TIN;
|
|
}
|
|
}
|
|
|
|
while(MDFN_LIKELY(HuCPU.timestamp < next_user_event))
|
|
{
|
|
next_event = (next_user_event < HuCPU.timer_next_timestamp) ? next_user_event : HuCPU.timer_next_timestamp;
|
|
|
|
while(MDFN_LIKELY(HuCPU.timestamp < next_event))
|
|
{
|
|
uint8 b1;
|
|
|
|
if(HU_IRQlow)
|
|
{
|
|
if(!(HU_PI&I_FLAG))
|
|
{
|
|
uint32 tmpa = 0;
|
|
|
|
if(HU_IRQlow & MDFN_IQTIMER & HuCPU.IRQMaskDelay)
|
|
tmpa = 0xFFFA;
|
|
else if((HU_IRQlow & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay) || ((HU_IRQlow >> 8) & MDFN_IQIRQ1 & HuCPU.IRQMaskDelay))
|
|
tmpa = 0xFFF8;
|
|
else if(HU_IRQlow & MDFN_IQIRQ2 & HuCPU.IRQMaskDelay)
|
|
tmpa = 0xFFF6;
|
|
|
|
if(tmpa)
|
|
{
|
|
unsigned int npc;
|
|
|
|
ADDCYC(8);
|
|
PUSH_PC();
|
|
|
|
COMPRESS_FLAGS();
|
|
PUSH((HU_P&~B_FLAG));
|
|
HU_P |= I_FLAG;
|
|
HU_P &= ~(T_FLAG | D_FLAG);
|
|
HU_PI = HU_P;
|
|
|
|
npc = RdMem16(tmpa);
|
|
SetPC(npc);
|
|
|
|
if(tmpa == 0xFFF8)
|
|
HU_IRQlow &= ~0x200;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
} // end if(HU_IRQlow)
|
|
|
|
HU_PI = HU_P;
|
|
HuCPU.IRQMaskDelay = HuCPU.IRQMask;
|
|
|
|
b1 = RdAtPC();
|
|
|
|
ADDCYC(CycTable[b1]);
|
|
|
|
IncPC();
|
|
|
|
switch(b1)
|
|
{
|
|
#include "huc6280_ops.h"
|
|
}
|
|
|
|
#ifndef HUC6280_EXTRA_CRAZY
|
|
FixPC_PC();
|
|
#endif
|
|
} // end while(HuCPU.timestamp < next_event)
|
|
|
|
while(HuCPU.timestamp >= HuCPU.timer_next_timestamp)
|
|
{
|
|
HuCPU.timer_next_timestamp += 1024 * pce_overclocked;
|
|
|
|
if(HuCPU.timer_status)
|
|
{
|
|
HuCPU.timer_value --;
|
|
if(HuCPU.timer_value < 0)
|
|
{
|
|
HuCPU.timer_value = HuCPU.timer_load;
|
|
HuC6280_IRQBegin(MDFN_IQTIMER);
|
|
}
|
|
}
|
|
}
|
|
} // end while(HuCPU.timestamp < next_user_event)
|
|
|
|
GetOutBMT:
|
|
|
|
SAVE_LOCALS();
|
|
}
|
|
}
|
|
|
|
void HuC6280_ResetTS(void)
|
|
{
|
|
HuCPU.timer_next_timestamp -= HuCPU.timestamp;
|
|
HuCPU.previous_next_user_event -= HuCPU.timestamp;
|
|
HuCPU.timestamp = 0;
|
|
}
|
|
|
|
int HuC6280_StateAction(StateMem *sm, int load, int data_only)
|
|
{
|
|
int ret;
|
|
uint16 tmp_PC = GetRealPC_EXTERNAL();
|
|
|
|
#define P_local HuCPU.P
|
|
COMPRESS_FLAGS();
|
|
|
|
{
|
|
SFORMAT SFCPU[]=
|
|
{
|
|
SFVARN(tmp_PC, "PC"),
|
|
SFVARN(HuCPU.A, "A"),
|
|
SFVARN(HuCPU.P, "P"),
|
|
SFVARN(HuCPU.X, "X"),
|
|
SFVARN(HuCPU.Y, "Y"),
|
|
SFVARN(HuCPU.S, "S"),
|
|
SFVARN(HuCPU.mooPI, "PI"),
|
|
|
|
SFVARN(HuCPU.IRQMask, "IRQMask"),
|
|
SFVARN(HuCPU.IRQMaskDelay, "IRQMaskDelay"),
|
|
SFARRAYN(HuCPU.MPR, 8, "MPR"),
|
|
SFVARN(HuCPU.timer_status, "timer_status"),
|
|
SFVARN(HuCPU.timer_value, "timer_value"),
|
|
SFVARN(HuCPU.timer_load, "timer_load"),
|
|
|
|
|
|
SFVARN(HuCPU.IRQlow, "IRQlow"),
|
|
SFVARN(HuCPU.in_block_move, "IBM"),
|
|
SFVARN(HuCPU.bmt_src, "IBM_SRC"),
|
|
SFVARN(HuCPU.bmt_dest, "IBM_DEST"),
|
|
SFVARN(HuCPU.bmt_length, "IBM_LENGTH"),
|
|
SFVARN(HuCPU.bmt_alternate, "IBM_ALTERNATE"),
|
|
|
|
SFVARN(HuCPU.timestamp, "timestamp"),
|
|
SFVARN(HuCPU.timer_next_timestamp, "timer_next_timestamp"),
|
|
SFVARN(HuCPU.previous_next_user_event, "previous_next_user_event"),
|
|
|
|
SFEND
|
|
};
|
|
|
|
ret = MDFNSS_StateAction(sm, load, data_only, SFCPU, "CPU", false);
|
|
|
|
if(load)
|
|
{
|
|
// Update MPR cache
|
|
HuC6280_FlushMPRCache();
|
|
|
|
// This must be after the MPR cache is updated:
|
|
SetPC_EXTERNAL(tmp_PC);
|
|
}
|
|
|
|
EXPAND_FLAGS();
|
|
#undef P_local
|
|
}
|
|
|
|
return(ret);
|
|
}
|