GBHawk: Fix pokemon Crystal (HDMA bug)

This commit is contained in:
alyosha-tas 2019-09-23 20:13:08 -04:00
parent 815145c939
commit 514635c127
4 changed files with 56 additions and 62 deletions

View File

@ -178,6 +178,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public void WriteReg(int addr, byte value) public void WriteReg(int addr, byte value)
{ {
// while power is on, everything is writable // while power is on, everything is writable
//Console.WriteLine((addr & 0xFF) + " " + value);
if (AUD_CTRL_power) if (AUD_CTRL_power)
{ {
switch (addr) switch (addr)
@ -276,6 +277,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
} }
if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; } if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
if ((SQ1_vol_state == 0) && (SQ1_per == 0) && SQ1_env_add) { SQ1_vol_state = 16; }
} }
SQ1_len_en = (value & 0x40) > 0; SQ1_len_en = (value & 0x40) > 0;
@ -335,6 +337,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
SQ2_vol_state = SQ2_st_vol; SQ2_vol_state = SQ2_st_vol;
SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8; SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8;
if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; SQ2_output = 0; } if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; SQ2_output = 0; }
if ((SQ2_vol_state == 0) && (SQ2_per == 0) && SQ2_env_add) { SQ2_vol_state = 16; }
} }
SQ2_len_en = (value & 0x40) > 0; SQ2_len_en = (value & 0x40) > 0;
@ -602,7 +605,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
SQ1_output *= SQ1_vol_state; SQ1_output *= SQ1_vol_state;
// avoid aliasing at high frequenices // avoid aliasing at high frequenices
if (SQ1_frq > 0x7F0) { SQ1_output = 0; } //if (SQ1_frq > 0x7F0) { SQ1_output = 0; }
} }
} }
@ -620,7 +623,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
SQ2_output *= SQ2_vol_state; SQ2_output *= SQ2_vol_state;
// avoid aliasing at high frequenices // avoid aliasing at high frequenices
if (SQ2_frq > 0x7F0) { SQ2_output = 0; } //if (SQ2_frq > 0x7F0) { SQ2_output = 0; }
} }
} }

View File

@ -25,8 +25,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public int HDMA_tick; public int HDMA_tick;
public byte HDMA_byte; public byte HDMA_byte;
public int hbl_countdown;
// accessors for derived values // accessors for derived values
public byte BG_pal_ret public byte BG_pal_ret
{ {
@ -35,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public byte OBJ_pal_ret public byte OBJ_pal_ret
{ {
get { return (byte)(((OBJ_bytes_inc ? 1 : 0) << 7) | (OBJ_bytes_index & 0x3F)); } get { return(byte)(((OBJ_bytes_inc ? 1 : 0) << 7) | (OBJ_bytes_index & 0x3F)); }
} }
public byte HDMA_ctrl public byte HDMA_ctrl
@ -127,28 +125,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
LCDC = value; LCDC = value;
break; break;
case 0xFF41: // STAT case 0xFF41: // STAT
// note that their is no stat interrupt bug in GBC // note that their is no stat interrupt bug in GBC
// writing to STAT during mode 0 or 1 causes a STAT IRQ
if (LCDC.Bit(7))
{
if (!Core.GBC_compat)
{
if (((STAT & 3) == 0) || ((STAT & 3) == 1))
{
LYC_INT = true;
}
}
if (value.Bit(6))
{
if (LY == LYC) { LYC_INT = true; }
else { LYC_INT = false; }
}
}
STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80); STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80);
if (!STAT.Bit(6)) { LYC_INT = false; }
if (!STAT.Bit(4)) { VBL_INT = false; } if (((STAT & 3) == 0) && STAT.Bit(3)) { HBL_INT = true; } else { HBL_INT = false; }
if (((STAT & 3) == 1) && STAT.Bit(4)) { VBL_INT = true; } else { VBL_INT = false; }
// OAM not triggered?
// if (((STAT & 3) == 2) && STAT.Bit(5)) { OAM_INT = true; } else { OAM_INT = false; }
if (value.Bit(6))
{
if (LY == LYC) { LYC_INT = true; }
else { LYC_INT = false; }
}
break; break;
case 0xFF42: // SCY case 0xFF42: // SCY
scroll_y = value; scroll_y = value;
@ -218,16 +208,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
HDMA_active = true; HDMA_active = true;
HBL_HDMA_count = 0x10; HBL_HDMA_count = 0x10;
// TODO: DOES HDMA start if triggered in mode 0 immediately? (for now assume no) last_HBL = LY - 1;
if ((STAT & 3) == 0)
{
last_HBL = LY;
}
else
{
last_HBL = LY - 1;
}
HBL_test = true; HBL_test = true;
HBL_HDMA_go = false; HBL_HDMA_go = false;
} }
@ -310,7 +292,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
else else
{ {
// only transfer during mode 0, and only 16 bytes at a time // only transfer during mode 0, and only 16 bytes at a time
if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1)) if (((STAT & 3) == 0) && (LY != last_HBL) && HBL_test && (LY_inc == 1) && (cycle > 4))
{ {
HBL_HDMA_go = true; HBL_HDMA_go = true;
HBL_test = false; HBL_test = false;
@ -335,6 +317,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if ((HBL_HDMA_count == 0) && (HDMA_length != 0)) if ((HBL_HDMA_count == 0) && (HDMA_length != 0))
{ {
HBL_test = true; HBL_test = true;
last_HBL = LY; last_HBL = LY;
HBL_HDMA_count = 0x10; HBL_HDMA_count = 0x10;

View File

@ -128,27 +128,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
break; break;
case 0xFF41: // STAT case 0xFF41: // STAT
// note that their is no stat interrupt bug in GBC // note that their is no stat interrupt bug in GBC
// writing to STAT during mode 0 or 1 causes a STAT IRQ
if (LCDC.Bit(7))
{
if (!Core.GBC_compat)
{
if (((STAT & 3) == 0) || ((STAT & 3) == 1))
{
LYC_INT = true;
}
}
if (value.Bit(6))
{
if (LY == LYC) { LYC_INT = true; }
else { LYC_INT = false; }
}
}
STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80); STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80);
if (!STAT.Bit(6)) { LYC_INT = false; }
if (!STAT.Bit(4)) { VBL_INT = false; } if (((STAT & 3) == 0) && STAT.Bit(3)) { HBL_INT = true; } else { HBL_INT = false; }
if (((STAT & 3) == 1) && STAT.Bit(4)) { VBL_INT = true; } else { VBL_INT = false; }
// OAM not triggered?
// if (((STAT & 3) == 2) && STAT.Bit(5)) { OAM_INT = true; } else { OAM_INT = false; }
if (value.Bit(6))
{
if (LY == LYC) { LYC_INT = true; }
else { LYC_INT = false; }
}
break; break;
case 0xFF42: // SCY case 0xFF42: // SCY
scroll_y = value; scroll_y = value;
@ -887,6 +879,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (pixel_counter == 160) if (pixel_counter == 160)
{ {
read_case = 8; read_case = 8;
hbl_countdown = 2;
} }
} }
else if (pixel_counter < 0) else if (pixel_counter < 0)
@ -1133,15 +1126,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
case 8: // done reading, we are now in phase 0 case 8: // done reading, we are now in phase 0
pre_render = true; pre_render = true;
STAT &= 0xFC; if (hbl_countdown > 0)
STAT |= 0x00; {
hbl_countdown--;
if (hbl_countdown == 0)
{
if (STAT.Bit(3)) { HBL_INT = true; }
OAM_access_read = true; OAM_access_read = true;
OAM_access_write = true; OAM_access_write = true;
VRAM_access_read = true; VRAM_access_read = true;
VRAM_access_write = true; VRAM_access_write = true;
}
else
{
STAT &= 0xFC;
STAT |= 0x00;
if (STAT.Bit(3)) { HBL_INT = true; }
}
}
break; break;
case 9: case 9:

View File

@ -104,6 +104,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public int window_y_tile_inc; public int window_y_tile_inc;
public int window_x_latch; public int window_x_latch;
public int hbl_countdown;
public virtual byte ReadReg(int addr) public virtual byte ReadReg(int addr)
{ {
return 0; return 0;
@ -257,6 +259,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ser.Sync(nameof(window_x_tile), ref window_x_tile); ser.Sync(nameof(window_x_tile), ref window_x_tile);
ser.Sync(nameof(window_y_tile_inc), ref window_y_tile_inc); ser.Sync(nameof(window_y_tile_inc), ref window_y_tile_inc);
ser.Sync(nameof(window_x_latch), ref window_x_latch); ser.Sync(nameof(window_x_latch), ref window_x_latch);
ser.Sync(nameof(hbl_countdown), ref hbl_countdown);
} }
} }
} }