GBHawk: Attempt at some halt bugs
This commit is contained in:
parent
e977826c5e
commit
19c509e9c2
|
@ -4,12 +4,6 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
{
|
||||
public partial class LR35902
|
||||
{
|
||||
private bool iff1;
|
||||
public bool IFF1 { get { return iff1; } set { iff1 = value; } }
|
||||
|
||||
private bool iff2;
|
||||
public bool IFF2 { get { return iff2; } set { iff2 = value; } }
|
||||
|
||||
private bool nonMaskableInterrupt;
|
||||
public bool NonMaskableInterrupt
|
||||
{
|
||||
|
@ -87,11 +81,17 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
public int stop_time;
|
||||
public bool stop_check;
|
||||
public bool is_GBC; // GBC automatically adds a NOP to avoid the HALT bug (according to Sinimas)
|
||||
public bool I_use; // in halt mode, the I flag is checked earlier then when deicision to IRQ is taken
|
||||
public bool skip_once;
|
||||
public bool Halt_bug_2;
|
||||
public bool Halt_bug_3;
|
||||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IFF1 = false;
|
||||
IFF2 = false;
|
||||
I_use = false;
|
||||
skip_once = false;
|
||||
Halt_bug_2 = false;
|
||||
Halt_bug_3 = false;
|
||||
NonMaskableInterrupt = false;
|
||||
NonMaskableInterruptPending = false;
|
||||
InterruptMode = 1;
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
public const ushort EI_RETI = 43; // reti has no delay in interrupt enable
|
||||
public const ushort INT_GET = 44;
|
||||
public const ushort GBC_INTERRUPT = 45;
|
||||
public const ushort HALT_CHK = 46; // when in halt mode, actually check I Flag here
|
||||
|
||||
public LR35902()
|
||||
{
|
||||
|
@ -68,7 +69,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
{
|
||||
ResetRegisters();
|
||||
ResetInterrupts();
|
||||
TotalExecutedCycles = 0;
|
||||
TotalExecutedCycles = 8;
|
||||
stop_check = false;
|
||||
cur_instr = new ushort[] { OP };
|
||||
}
|
||||
|
@ -255,6 +256,17 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
case HALT:
|
||||
halted = true;
|
||||
|
||||
bool temp = false;
|
||||
|
||||
if (cur_instr[instr_pntr++] == 1)
|
||||
{
|
||||
temp = FlagI;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = I_use;
|
||||
}
|
||||
|
||||
if (EI_pending > 0 && !CB_prefix)
|
||||
{
|
||||
EI_pending--;
|
||||
|
@ -265,8 +277,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
}
|
||||
|
||||
// if the I flag is asserted at the time of halt, don't halt
|
||||
|
||||
if (FlagI && interrupts_enabled && !CB_prefix && !jammed)
|
||||
if (temp && interrupts_enabled && !CB_prefix && !jammed)
|
||||
{
|
||||
interrupts_enabled = false;
|
||||
|
||||
|
@ -298,7 +309,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
INTERRUPT_();
|
||||
}
|
||||
}
|
||||
else if (FlagI)
|
||||
else if (temp)
|
||||
{
|
||||
// even if interrupt servicing is disabled, any interrupt flag raised still resumes execution
|
||||
if (TraceCallback != null)
|
||||
|
@ -324,17 +335,44 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
}
|
||||
else
|
||||
{
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
if (Halt_bug_3)
|
||||
{
|
||||
//special variant of halt bug where RegPC also isn't incremented post fetch
|
||||
RegPC++;
|
||||
FetchInstruction(ReadMemory(RegPC));
|
||||
Halt_bug_3 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
FetchInstruction(ReadMemory(RegPC++));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
if (skip_once)
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT, 0 };
|
||||
|
||||
skip_once = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{
|
||||
IDLE,
|
||||
HALT_CHK,
|
||||
IDLE,
|
||||
|
||||
HALT, 0 };
|
||||
}
|
||||
|
||||
}
|
||||
I_use = false;
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case STOP:
|
||||
|
@ -453,6 +491,18 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
INTERRUPT_();
|
||||
instr_pntr = 0;
|
||||
break;
|
||||
case HALT_CHK:
|
||||
// only used when exiting HALT from GBC, an extra NOP is added to avoid HALT bug
|
||||
I_use = FlagI;
|
||||
if (Halt_bug_2 && I_use)
|
||||
{
|
||||
RegPC--;
|
||||
|
||||
if (!interrupts_enabled) { Halt_bug_3 = true; }
|
||||
}
|
||||
|
||||
Halt_bug_2 = false;
|
||||
break;
|
||||
}
|
||||
totalExecutedCycles++;
|
||||
}
|
||||
|
@ -506,8 +556,10 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
ser.Sync("NMI", ref nonMaskableInterrupt);
|
||||
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
|
||||
ser.Sync("IM", ref interruptMode);
|
||||
ser.Sync("IFF1", ref iff1);
|
||||
ser.Sync("IFF2", ref iff2);
|
||||
ser.Sync("I_use", ref I_use);
|
||||
ser.Sync("skip_once", ref skip_once);
|
||||
ser.Sync("Halt_bug_2", ref Halt_bug_2);
|
||||
ser.Sync("Halt_bug_3", ref Halt_bug_3);
|
||||
ser.Sync("Halted", ref halted);
|
||||
ser.Sync("ExecutedCycles", ref totalExecutedCycles);
|
||||
ser.Sync("EI_pending", ref EI_pending);
|
||||
|
|
|
@ -76,8 +76,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
|
||||
private void HALT_()
|
||||
{
|
||||
|
||||
if (FlagI && (EI_pending == 0))
|
||||
if (FlagI && (EI_pending == 0) && !interrupts_enabled)
|
||||
{
|
||||
if (is_GBC)
|
||||
{
|
||||
|
@ -96,21 +95,31 @@ namespace BizHawk.Emulation.Common.Components.LR35902
|
|||
else
|
||||
{ // if interrupts are disabled,
|
||||
// a glitchy decrement to the program counter happens
|
||||
cur_instr = new ushort[]
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
OP_G};
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_instr = new ushort[]
|
||||
{IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
HALT };
|
||||
}
|
||||
{
|
||||
IDLE,
|
||||
HALT_CHK,
|
||||
IDLE,
|
||||
HALT, 1 };
|
||||
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) { Halt_bug_2 = true; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void JR_COND(bool cond)
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
[DisplayName("Timer Div Initial Time")]
|
||||
[Description("Don't change from 0 unless it's hardware accurate. GBA GBC mode is known to be 8.")]
|
||||
[DefaultValue(0)]
|
||||
[DefaultValue(8)]
|
||||
public int DivInitialTime
|
||||
{
|
||||
get { return _DivInitialTime; }
|
||||
|
|
|
@ -75,7 +75,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
case 0xFF45: // LYC
|
||||
LYC = value;
|
||||
if (LY != LYC) { STAT &= 0xFB; }
|
||||
if (LCDC.Bit(7))
|
||||
{
|
||||
if (LY != LYC) { STAT &= 0xFB; }
|
||||
else { STAT |= 0x4; /*if (STAT.Bit(6)) { LYC_INT = true; } */}
|
||||
}
|
||||
break;
|
||||
case 0xFF46: // DMA
|
||||
DMA_addr = value;
|
||||
|
@ -124,7 +128,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
LY += LY_inc;
|
||||
no_scan = false;
|
||||
|
||||
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case
|
||||
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case)
|
||||
if (LY_inc == 1)
|
||||
{
|
||||
LYC_INT = false;
|
||||
|
@ -177,7 +181,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// also, the LCD does not enter mode 2 on scanline 0 when first turned on
|
||||
no_scan = true;
|
||||
cycle = 8;
|
||||
cycle = 4;
|
||||
}
|
||||
|
||||
// the VBL stat is continuously asserted
|
||||
|
@ -195,7 +199,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if ((cycle == 4) && (LY == 144)) {
|
||||
if ((cycle == 0) && (LY == 144)) {
|
||||
|
||||
HBL_INT = false;
|
||||
|
||||
|
@ -205,6 +209,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (Core.REG_FFFF.Bit(0)) { Core.cpu.FlagI = true; }
|
||||
Core.REG_FF0F |= 0x01;
|
||||
//Console.WriteLine(Core.cpu.TotalExecutedCycles);
|
||||
}
|
||||
|
||||
if ((LY >= 144) && (cycle == 4))
|
||||
|
@ -229,12 +234,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// there is no mode 2 (presumably it missed the trigger)
|
||||
// mode 3 is very short, probably in some self test mode before turning on?
|
||||
|
||||
if (cycle == 12)
|
||||
if (cycle == 8)
|
||||
{
|
||||
LYC_INT = false;
|
||||
STAT &= 0xFB;
|
||||
if (LY != LYC)
|
||||
{
|
||||
LYC_INT = false;
|
||||
STAT &= 0xFB;
|
||||
}
|
||||
|
||||
if (LY == LYC)
|
||||
if ((LY == LYC) && !STAT.Bit(2))
|
||||
{
|
||||
// set STAT coincidence FLAG and interrupt flag if it is enabled
|
||||
STAT |= 0x04;
|
||||
|
@ -314,7 +322,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
STAT &= 0xFB;
|
||||
|
||||
// Special case of LY = LYC
|
||||
if (LY == LYC)
|
||||
if ((LY == LYC) && !STAT.Bit(2))
|
||||
{
|
||||
// set STAT coincidence FLAG and interrupt flag if it is enabled
|
||||
STAT |= 0x04;
|
||||
|
@ -331,7 +339,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// here LY=LYC will be asserted
|
||||
if ((cycle == 4) && (LY != 0))
|
||||
{
|
||||
if (LY == LYC)
|
||||
if ((LY == LYC) && !STAT.Bit(2))
|
||||
{
|
||||
// set STAT coincidence FLAG and interrupt flag if it is enabled
|
||||
STAT |= 0x04;
|
||||
|
@ -343,7 +351,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
STAT &= 0xF8;
|
||||
STAT &= 0xFC;
|
||||
|
||||
VBL_INT = LYC_INT = HBL_INT = OAM_INT = false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue