GBHawk: make timer <> cpu loop interaction consistent

This commit is contained in:
alyosha-tas 2020-08-19 11:58:06 -04:00
parent 96fa21e238
commit 6e8362eef0
4 changed files with 46 additions and 31 deletions

View File

@ -462,7 +462,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
break; break;
} }
if (stop_time == (32768 - 2)) if (stop_time == (32769))
{ {
SpeedFunc(1); SpeedFunc(1);
} }

View File

@ -896,6 +896,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
} }
} }
} }
timer_bit_old = Core.double_speed ? Core.timer.divider_reg.Bit(13) : Core.timer.divider_reg.Bit(12); timer_bit_old = Core.double_speed ? Core.timer.divider_reg.Bit(13) : Core.timer.divider_reg.Bit(12);
if (sequencer_reset_cd > 0) if (sequencer_reset_cd > 0)
@ -904,17 +905,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (sequencer_reset_cd == 0) if (sequencer_reset_cd == 0)
{ {
// seems to be off by one issues here, hard to tell since the write takes place in the cpu loop
// but the effect takes place in the sound loop
if (Core.double_speed) if (Core.double_speed)
{ {
sequencer_len = Core.timer.divider_reg.Bit(13) ? 0 : 1;
sequencer_vol = Core.timer.divider_reg.Bit(13) ? 0 : 1; sequencer_len = (Core.timer.divider_reg - 1).Bit(13) ? 0 : 1;
sequencer_swp = Core.timer.divider_reg.Bit(13) ? 0 : 1; sequencer_vol = (Core.timer.divider_reg - 1).Bit(13) ? 0 : 1;
sequencer_swp = (Core.timer.divider_reg - 1).Bit(13) ? 0 : 1;
} }
else else
{ {
sequencer_len = Core.timer.divider_reg.Bit(12) ? 0 : 1; sequencer_len = (Core.timer.divider_reg + 1).Bit(12) ? 0 : 1;
sequencer_vol = Core.timer.divider_reg.Bit(12) ? 0 : 1; sequencer_vol = (Core.timer.divider_reg + 1).Bit(12) ? 0 : 1;
sequencer_swp = Core.timer.divider_reg.Bit(12) ? 0 : 1; sequencer_swp = (Core.timer.divider_reg + 1).Bit(12) ? 0 : 1;
} }
} }
} }

View File

@ -108,28 +108,34 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{ {
if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); } if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); }
serialport.serial_transfer_tick(); serialport.serial_transfer_tick();
cpu.ExecuteOne();
timer.tick(); timer.tick();
cpu.ExecuteOne();
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); } if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); }
serialport.serial_transfer_tick(); serialport.serial_transfer_tick();
cpu.ExecuteOne();
timer.tick(); timer.tick();
cpu.ExecuteOne();
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
else else
{ {
if (double_speed) if (double_speed)
{ {
cpu.TotalExecutedCycles++;
timer.tick(); timer.tick();
cpu.TotalExecutedCycles++;
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
cpu.TotalExecutedCycles++;
timer.tick(); timer.tick();
cpu.TotalExecutedCycles++;
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
@ -190,29 +196,37 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// These things all tick twice as fast in GBC double speed mode // These things all tick twice as fast in GBC double speed mode
if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); } if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); }
serialport.serial_transfer_tick(); serialport.serial_transfer_tick();
cpu.ExecuteOne();
timer.tick(); timer.tick();
cpu.ExecuteOne();
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
if (double_speed) if (double_speed)
{ {
if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); } if (ppu.DMA_start && !cpu.halted && !cpu.stopped) { ppu.DMA_tick(); }
serialport.serial_transfer_tick(); serialport.serial_transfer_tick();
cpu.ExecuteOne();
timer.tick(); timer.tick();
cpu.ExecuteOne();
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
} }
else else
{ {
cpu.TotalExecutedCycles++;
timer.tick(); timer.tick();
cpu.TotalExecutedCycles++;
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
if (double_speed) if (double_speed)
{ {
cpu.TotalExecutedCycles++;
timer.tick(); timer.tick();
cpu.TotalExecutedCycles++;
timer.divider_reg++;
if (delays_to_process) { process_delays(); } if (delays_to_process) { process_delays(); }
} }
} }
@ -286,9 +300,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
speed_switch = false; speed_switch = false;
Console.WriteLine("Speed Switch: " + cpu.TotalExecutedCycles); Console.WriteLine("Speed Switch: " + cpu.TotalExecutedCycles);
// reset the divider (only way for speed_change_timing_fine.gbc and speed_change_cancel.gbc to both work)
timer.divider_reg = 0;
int ret = double_speed ? 32769 : 32769; // actual time needs checking int ret = double_speed ? 32769 : 32769; // actual time needs checking
return ret; return ret;
} }
@ -302,6 +313,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
} }
else else
{ {
// reset the divider (only way for speed_change_timing_fine.gbc and speed_change_cancel.gbc to both work)
timer.divider_reg = 1;
double_speed = !double_speed; double_speed = !double_speed;
return 0; return 0;
} }
@ -330,7 +343,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void SetIntRegs(byte r) public void SetIntRegs(byte r)
{ {
if (((REG_FF0F & 4) == 4) && ((r & 4) == 0) && is_GBC) { timer.IRQ_block = true; } if (((REG_FF0F & 4) == 4) && ((r & 4) == 0) && timer.IRQ_block && !is_GBC) { r |= 4; }
REG_FF0F = r; REG_FF0F = r;
} }

View File

@ -56,6 +56,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{ {
// DIV register // DIV register
case 0xFF04: case 0xFF04:
// NOTE: even though there is an automatic increment directly after the CPU loop,
// it is still expected that 0 is written here
divider_reg = 0; divider_reg = 0;
break; break;
@ -143,7 +145,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void tick() public void tick()
{ {
divider_reg++; IRQ_block = false;
// pick a bit to test based on the current value of timer control // pick a bit to test based on the current value of timer control
switch (timer_control & 3) switch (timer_control & 3)
@ -201,20 +203,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
next_free_cycle = 4 + Core.cpu.TotalExecutedCycles; next_free_cycle = 4 + Core.cpu.TotalExecutedCycles;
// set interrupts // set interrupts
if (!IRQ_block)
{
if (Core.REG_FFFF.Bit(2)) { Core.cpu.FlagI = true; } if (Core.REG_FFFF.Bit(2)) { Core.cpu.FlagI = true; }
Core.REG_FF0F |= 0x04; Core.REG_FF0F |= 0x04;
IRQ_block = true;
} }
} }
} }
IRQ_block = false;
}
public void Reset() public void Reset()
{ {
divider_reg = (ushort)(Core.is_GBC ? 0xFFFF : 0x1); divider_reg = (ushort)(Core.is_GBC ? 0xFFFE : 0xFFFE);
timer_reload = 0; timer_reload = 0;
timer = 0; timer = 0;
timer_old = 0; timer_old = 0;