528 lines
8.6 KiB
C#
528 lines
8.6 KiB
C#
namespace BizHawk.Emulation.Cores.Components.LR35902
|
|
{
|
|
public partial class LR35902
|
|
{
|
|
// this contains the vectors of instruction operations
|
|
// NOTE: This list is NOT confirmed accurate for each individual cycle
|
|
|
|
private void NOP_()
|
|
{
|
|
cur_instr = new[]
|
|
{
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP
|
|
};
|
|
}
|
|
|
|
private void INC_16(ushort srcL, ushort srcH)
|
|
{
|
|
cur_instr = new[]
|
|
{
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
INC16,
|
|
srcL,
|
|
srcH,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP
|
|
};
|
|
}
|
|
|
|
private void DEC_16(ushort src_l, ushort src_h)
|
|
{
|
|
cur_instr = new[]
|
|
{
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
DEC16,
|
|
src_l,
|
|
src_h,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP
|
|
};
|
|
}
|
|
|
|
private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
ADD16, dest_l, dest_h, src_l, src_h,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void REG_OP(ushort operation, ushort dest, ushort src)
|
|
{
|
|
cur_instr = new[]
|
|
{operation, dest, src,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void STOP_()
|
|
{
|
|
cur_instr = new[]
|
|
{RD, Z, PCl, PCh,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
STOP };
|
|
}
|
|
|
|
private void HALT_()
|
|
{
|
|
if (FlagI && (EI_pending == 0) && !interrupts_enabled)
|
|
{
|
|
if (is_GBC)
|
|
{
|
|
// in GBC mode, the HALT bug is worked around by simply adding a NOP
|
|
// so it just takes 4 cycles longer to reach the next instruction
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
OP_G};
|
|
}
|
|
else
|
|
{ // if interrupts are disabled,
|
|
// a glitchy decrement to the program counter happens
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
OP_G};
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new ushort[]
|
|
{
|
|
IDLE,
|
|
HALT_CHK,
|
|
IDLE,
|
|
HALT, 0 };
|
|
|
|
if (!is_GBC) { skip_once = true; }
|
|
// If the interrupt flag is not currently set, but it does get set in the first check
|
|
// then a bug is triggered
|
|
// With interrupts enabled, this runs the halt command twice
|
|
// when they are disabled, it reads the next byte twice
|
|
if (!FlagI ||(FlagI && !interrupts_enabled)) { Halt_bug_2 = true; }
|
|
|
|
}
|
|
}
|
|
|
|
private void JR_COND(bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
cur_instr = new ushort[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
ASGN, Z, 0,
|
|
IDLE,
|
|
ADDS, PCl, PCh, W, Z,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, Z, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
}
|
|
|
|
private void JP_COND(bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
RD, Z, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
TR, PCl, W,
|
|
IDLE,
|
|
TR, PCh, Z,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
RD, Z, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
}
|
|
|
|
private void RET_()
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, PCl, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
RD, PCh, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void RETI_()
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, PCl, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
RD, PCh, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
EI_RETI,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
|
|
private void RET_COND(bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, PCl, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
RD, PCh, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
}
|
|
|
|
private void CALL_COND(bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
IDLE,
|
|
RD, Z, PCl, PCh,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
DEC16, SPl, SPh,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
WR, SPl, SPh, PCh,
|
|
IDLE,
|
|
IDLE,
|
|
DEC16, SPl, SPh,
|
|
WR, SPl, SPh, PCl,
|
|
TR, PCl, W,
|
|
TR, PCh, Z,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
RD, Z, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
}
|
|
|
|
private void INT_OP(ushort operation, ushort src)
|
|
{
|
|
cur_instr = new[]
|
|
{operation, src,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void BIT_OP(ushort operation, ushort bit, ushort src)
|
|
{
|
|
cur_instr = new[]
|
|
{operation, bit, src,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void PUSH_(ushort src_l, ushort src_h)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
DEC16, SPl, SPh,
|
|
IDLE,
|
|
WR, SPl, SPh, src_h,
|
|
IDLE,
|
|
DEC16, SPl, SPh,
|
|
IDLE,
|
|
WR, SPl, SPh, src_l,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
// NOTE: this is the only instruction that can write to F
|
|
// but the bottom 4 bits of F are always 0, so instead of putting a special check for every read op
|
|
// let's just put a special operation here specifically for F
|
|
private void POP_(ushort src_l, ushort src_h)
|
|
{
|
|
if (src_l != F)
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, src_l, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
RD, src_h, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
else
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD_F, src_l, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
IDLE,
|
|
RD, src_h, SPl, SPh,
|
|
IDLE,
|
|
INC16, SPl, SPh,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
}
|
|
|
|
private void RST_(ushort n)
|
|
{
|
|
cur_instr = new ushort[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
DEC16, SPl, SPh,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
WR, SPl, SPh, PCh,
|
|
DEC16, SPl, SPh,
|
|
IDLE,
|
|
IDLE,
|
|
WR, SPl, SPh, PCl,
|
|
ASGN, PCh, 0,
|
|
ASGN, PCl, n,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void PREFIX_()
|
|
{
|
|
cur_instr = new[]
|
|
{PREFIX,
|
|
IDLE,
|
|
IDLE,
|
|
OP };
|
|
}
|
|
|
|
private void DI_()
|
|
{
|
|
cur_instr = new[]
|
|
{DI,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void EI_()
|
|
{
|
|
cur_instr = new[]
|
|
{EI,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void JP_HL()
|
|
{
|
|
cur_instr = new[]
|
|
{TR, PCl, L,
|
|
TR, PCh, H,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void ADD_SP()
|
|
{
|
|
cur_instr = new ushort[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
IDLE,
|
|
ASGN, Z, 0,
|
|
IDLE,
|
|
ADDS, SPl, SPh, W, Z,
|
|
IDLE,
|
|
IDLE,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void LD_SP_HL()
|
|
{
|
|
cur_instr = new[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
TR, SPl, L,
|
|
IDLE,
|
|
TR, SPh, H,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void LD_HL_SPn()
|
|
{
|
|
cur_instr = new ushort[]
|
|
{IDLE,
|
|
IDLE,
|
|
IDLE,
|
|
RD, W, PCl, PCh,
|
|
IDLE,
|
|
INC16, PCl, PCh,
|
|
TR, H, SPh,
|
|
TR, L, SPl,
|
|
ASGN, Z, 0,
|
|
ADDS, L, H, W, Z,
|
|
HALT_CHK,
|
|
OP };
|
|
}
|
|
|
|
private void JAM_()
|
|
{
|
|
cur_instr = new[]
|
|
{JAM,
|
|
IDLE,
|
|
IDLE,
|
|
IDLE };
|
|
}
|
|
}
|
|
}
|