GBHawk: update HDMA implementation

This commit is contained in:
alyosha-tas 2020-11-25 14:05:17 -05:00
parent 13a8a602cf
commit 78ca48251f
5 changed files with 108 additions and 60 deletions
src/BizHawk.Emulation.Cores
CPUs/LR35902
Consoles/Nintendo/GBHawk

View File

@ -3,6 +3,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
public partial class LR35902
{
public ulong TotalExecutedCycles;
public ulong instruction_start;
private int EI_pending;
public bool interrupts_enabled;

View File

@ -180,6 +180,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
CDLCallback?.Invoke(RegPC, eCDLogMemFlags.FetchFirst);
FetchInstruction(ReadMemory(RegPC++));
}
instruction_start = TotalExecutedCycles + 1;
I_use = false;
break;
case RD:
@ -801,6 +802,7 @@ namespace BizHawk.Emulation.Cores.Components.LR35902
ser.Sync(nameof(Halt_bug_5), ref Halt_bug_5);
ser.Sync(nameof(halted), ref halted);
ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles);
ser.Sync(nameof(instruction_start), ref instruction_start);
ser.Sync(nameof(EI_pending), ref EI_pending);
ser.Sync(nameof(int_src), ref int_src);
ser.Sync(nameof(int_clear), ref int_clear);

View File

@ -223,7 +223,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 0xFF55: // HDMA5
if (!HDMA_active)
{
HDMA_countdown = 8; // run one cpu cycle, then wait another cycle to start transfer
HDMA_countdown = 4; // run one cpu cycle, then wait another cycle to start transfer
HDMA_mode = value.Bit(7);
HDMA_tick = 0;
@ -320,14 +320,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (HDMA_countdown > 0)
{
HDMA_countdown--;
if (HDMA_countdown == 3)
if ((Core.cpu.TotalExecutedCycles - Core.cpu.instruction_start) == 0)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if (HDMA_countdown == 3)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
}
}
else
{
HDMA_countdown++;
}
}
else
@ -384,11 +390,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (HDMA_countdown == 3)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if ((Core.cpu.TotalExecutedCycles - Core.cpu.instruction_start) == 0)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if (LCDC.Bit(7)) { last_HBL = LY; }
else { last_HBL = 0xFF; }
}
else
{
HDMA_countdown++;
}
}
}
else
@ -422,11 +438,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
HBL_test = true;
if (LCDC.Bit(7)) { last_HBL = LY; }
else { last_HBL = 0xFF; }
HBL_HDMA_count = 0x10;
HBL_HDMA_go = false;
HDMA_countdown = 8;
HDMA_countdown = 4;
}
HDMA_tick++;
@ -605,22 +619,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (cycle == 84)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
glitch_state = false;
OAM_access_read = false;
OAM_access_write = false;
VRAM_access_read_PPU = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_PPU = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
rendering_complete = false;
}
}
else if (!rendering_complete)
{
if (cycle == 86)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
glitch_state = false;
OAM_access_write = false;
VRAM_access_read_PPU = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_PPU = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
}
// render the screen and handle hblank
render(cycle - 85);
}
@ -1176,7 +1195,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
VRAM_access_write_PPU = true;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
HDMA_can_start = true;
//HDMA_can_start = true;
read_case = 18;
break;
@ -1332,7 +1351,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
STAT |= 0x00;
if (STAT.Bit(3)) { HBL_INT = true; }
HDMA_can_start = true;
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
{

View File

@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 0xFF52: ret = 0xFF; break; // HDMA2 (src_lo)
case 0xFF53: ret = 0xFF; break; // HDMA3 (dest_hi)
case 0xFF54: ret = 0xFF; break; // HDMA4 (dest_lo)
case 0xFF55: ret = HDMA_ctrl; break; // HDMA5
case 0xFF55: ret = HDMA_ctrl;Console.WriteLine("read"); break; // HDMA5
case 0xFF68: ret = BG_pal_ret; break; // BGPI
case 0xFF69: ret = BG_PAL_read(); break; // BGPD
case 0xFF6A: ret = OBJ_pal_ret; break; // OBPI
@ -221,7 +221,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 0xFF55: // HDMA5
if (!HDMA_active)
{
HDMA_countdown = Core.double_speed ? 4 : 8; // run one cpu cycle, then wait another cycle to start transfer
HDMA_countdown = Core.double_speed ? 2 : 4; // run one cpu cycle, then wait another cycle to start transfer
HDMA_mode = value.Bit(7);
HDMA_tick = 0;
@ -321,11 +321,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (HDMA_countdown == (Core.double_speed ? 1 : 3))
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if ((Core.cpu.TotalExecutedCycles - Core.cpu.instruction_start) == 0)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
}
else
{
HDMA_countdown++;
}
}
}
else
@ -380,11 +387,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (HDMA_countdown == (Core.double_speed ? 1 : 3))
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if ((Core.cpu.TotalExecutedCycles - Core.cpu.instruction_start) == 0)
{
if (!Core.HDMA_transfer) { Core.HDMA_start_stop(true); }
VRAM_access_read_HDMA = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_HDMA = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
if (LCDC.Bit(7)) { last_HBL = LY; }
else { last_HBL = 0xFF; }
}
else
{
HDMA_countdown++;
}
}
}
else
@ -414,13 +431,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if ((HBL_HDMA_count == 0) && (HDMA_length != 0))
{
HBL_test = true;
if (LCDC.Bit(7)) { last_HBL = LY; }
else { last_HBL = 0xFF; }
HBL_HDMA_count = 0x10;
HBL_HDMA_go = false;
HDMA_countdown = Core.double_speed ? 4 : 8;
HDMA_countdown = Core.double_speed ? 2 : 4;
}
HDMA_tick++;
@ -600,25 +614,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (STAT.Bit(6)) { LYC_INT = true; }
}
}
if (cycle == 84)
{
OAM_access_read = false;
rendering_complete = false;
}
}
else if (!rendering_complete)
{
if (cycle == 86)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
glitch_state = false;
OAM_access_read = false;
OAM_access_write = false;
VRAM_access_read_PPU = false;
VRAM_access_read = VRAM_access_read_PPU & VRAM_access_read_HDMA;
VRAM_access_write_PPU = false;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
rendering_complete = false;
}
}
else if (!rendering_complete)
{
// render the screen and handle hblank
render(cycle - 85);
}
@ -1179,7 +1199,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
VRAM_access_write_PPU = true;
VRAM_access_write = VRAM_access_write_PPU & VRAM_access_write_HDMA;
HDMA_can_start = true;
if (Core.double_speed) { HDMA_can_start = true; }
read_case = 18;
break;
@ -1295,7 +1315,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
STAT |= 0x00;
if (STAT.Bit(3)) { HBL_INT = true; }
// the CPU has to be able to see the transition from mode 3 to mode 0 to start HDMA
if (!Core.double_speed) { HDMA_can_start = true; }
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
{

View File

@ -287,20 +287,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (cycle == 84)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
glitch_state = false;
OAM_access_read = false;
OAM_access_write = false;
VRAM_access_read = false;
VRAM_access_write = false;
rendering_complete = false;
}
}
else if (!rendering_complete)
{
if (cycle == 86)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
glitch_state = false;
OAM_access_write = false;
VRAM_access_read = false;
VRAM_access_write = false;
rendering_complete = false;
}
// render the screen and handle hblank
render(cycle - 85);
}