From d4ee8f480bbb141ebe1bb38b5949bdeb194a92a2 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Sun, 25 Mar 2018 21:22:27 -0400 Subject: [PATCH] GBHawk: HDMA and GBC halt commits --- .../CPUs/LR35902/LR35902.cs | 37 +++++++++++++++-- .../CPUs/LR35902/Tables_Direct.cs | 41 +++++++++++++------ .../Consoles/Nintendo/GBHawk/GBC_PPU.cs | 31 +++++++++++++- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs index 18312da82f..3ad5bdd7d4 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs @@ -57,6 +57,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 public const ushort RD_F = 42; // special read case to pop value into F 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 LR35902() { @@ -278,8 +279,21 @@ namespace BizHawk.Emulation.Common.Components.LR35902 }); } halted = false; - // call interrupt processor - INTERRUPT_(); + + if (is_GBC) + { + // call the interrupt processor after 4 extra cycles + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + GBC_INTERRUPT }; + } + else + { + // call interrupt processor + INTERRUPT_(); + } } else if (FlagI) { @@ -295,7 +309,19 @@ namespace BizHawk.Emulation.Common.Components.LR35902 halted = false; if (OnExecFetch != null) OnExecFetch(RegPC); if (TraceCallback != null && !CB_prefix) TraceCallback(State()); - FetchInstruction(ReadMemory(RegPC++)); + if (is_GBC) + { + // extra 4 cycles for GBC + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + OP }; + } + else + { + FetchInstruction(ReadMemory(RegPC++)); + } } else { @@ -419,6 +445,11 @@ namespace BizHawk.Emulation.Common.Components.LR35902 Regs[cur_instr[instr_pntr++]] = INT_vectors[int_src]; break; + case GBC_INTERRUPT: + // only used when exiting HALT from GBC, an extra NOP is added to avoid HALT bug + INTERRUPT_(); + instr_pntr = 0; + break; } totalExecutedCycles++; } diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs index a611b780b9..9eb91d9031 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs @@ -76,25 +76,42 @@ namespace BizHawk.Emulation.Common.Components.LR35902 private void HALT_() { + if (FlagI && (EI_pending == 0)) { - // if interrupts are disabled, - // a glitchy decrement to the program counter happens - cur_instr = new ushort[] - {IDLE, - IDLE, - IDLE, - OP_G}; + + 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 ushort[] + {IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + IDLE, + OP}; + } + else + { // if interrupts are disabled, + // a glitchy decrement to the program counter happens + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + OP_G}; + } } else { cur_instr = new ushort[] {IDLE, - IDLE, - IDLE, - HALT }; - } - + IDLE, + IDLE, + HALT }; + } } private void JR_COND(bool cond) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 56df77b4d9..b8dbb31086 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -31,6 +31,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public ushort cur_DMA_dest; public int HDMA_length; public int HDMA_countdown; + public int HBL_HDMA_count; + public int last_HBL; + public bool HBL_HDMA_go; + public bool HBL_test; public override byte ReadReg(int addr) { @@ -158,6 +162,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { // HDMA during HBlank only HDMA_active = true; + HBL_HDMA_count = 0x10; + last_HBL = LY; + HBL_test = true; + HBL_HDMA_go = false; } else { @@ -228,8 +236,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else { - // only transfer during mode 3, otherwise - if ((STAT & 3) == 3) + // only transfer during mode 3, and only 16 bytes at a time + if (((STAT & 3) == 3) && (LY != last_HBL) && HBL_test) + { + HBL_HDMA_go = true; + HBL_test = false; + } + + if (HBL_HDMA_go && (HBL_HDMA_count > 0)) { Core.HDMA_transfer = true; @@ -239,16 +253,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF); cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF); HDMA_length--; + HBL_HDMA_count--; Core.VRAM[(Core.VRAM_Bank * 0x2000) + cur_DMA_dest] = Core.ReadMemory(cur_DMA_src); cur_DMA_dest = (ushort)((cur_DMA_dest + 1) & 0x1FFF); cur_DMA_src = (ushort)((cur_DMA_src + 1) & 0xFFFF); HDMA_length--; + HBL_HDMA_count--; if (HDMA_length == 0) { HDMA_active = false; Core.HDMA_transfer = false; } + + if ((HBL_HDMA_count == 0) && (HDMA_length != 0)) + { + HBL_test = true; + last_HBL = LY; + HBL_HDMA_count = 0x10; + } } } else @@ -1294,6 +1317,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("cur_DMA_dest", ref cur_DMA_dest); ser.Sync("HDMA_length", ref HDMA_length); ser.Sync("HDMA_countdown", ref HDMA_countdown); + ser.Sync("HBL_HDMA_count", ref HBL_HDMA_count); + ser.Sync("last_HBL", ref last_HBL); + ser.Sync("HBL_HDMA_go", ref HBL_HDMA_go); + ser.Sync("HBL_test", ref HBL_test); base.SyncState(ser); }