diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs index 2df6418354..65f3d98597 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs @@ -381,9 +381,9 @@ namespace BizHawk.Emulation.Common.Components.LR35902 else { cur_instr = new ushort[] - {IDLE, - HALT_CHK, - IDLE, + {HALT_CHK, + IDLE, + IDLE, HALT, 0 }; } diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs index b5e005948f..b75e3ce92d 100644 --- a/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs +++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Tables_Direct.cs @@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902 private void NOP_() { cur_instr = new ushort[] - {IDLE, + {IDLE, IDLE, HALT_CHK, OP }; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs index 2573b546a3..e6de37117d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBC_PPU.cs @@ -130,7 +130,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 0xFF43: // SCX scroll_x = value; - break; case 0xFF44: // LY LY = 0; /*reset*/ @@ -418,12 +417,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((cycle == 4) && (LY == 144)) { - - HBL_INT = false; - + if ((cycle == 2) && (LY == 144)) + { // there is an edge case where a VBL INT is triggered if STAT bit 5 is set if (STAT.Bit(5)) { VBL_INT = true; } + } + + if ((cycle == 4) && (LY == 144)) + { + HBL_INT = false; // set STAT mode to 1 (VBlank) and interrupt flag if it is enabled STAT &= 0xFC; @@ -433,12 +435,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Core.REG_FF0F |= 0x01; } - if ((cycle == 84) && (LY == 144)) + if ((cycle == 4) && (LY == 144)) { if (STAT.Bit(5)) { VBL_INT = false; } } - - if ((LY == 153) && (cycle == 6)) + + if ((cycle == 6) && (LY == 153)) { LY = 0; LY_inc = 0; @@ -528,7 +530,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else if ((cycle >= 80) && (LY < 144)) { - if (cycle >= 84) + if (cycle >= 83) { if (cycle == 84) { @@ -540,7 +542,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // render the screen and handle hblank - render(cycle - 84); + render(cycle - 83); } else if (cycle == 80) { @@ -552,13 +554,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((LY_inc == 0)) + if (LY_inc == 0) { - if (cycle == 12) + if (cycle == 10) { LYC_INT = false; STAT &= 0xFB; - + } + else if (cycle == 12) + { // Special case of LY = LYC if ((LY == LYC) && !STAT.Bit(2)) { @@ -650,12 +654,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk read_case = 0; internal_cycle = 0; pre_render = true; + pre_render_2 = true; tile_inc = 0; pixel_counter = -8; sl_use_index = 0; fetch_sprite = false; - fetch_sprite_01 = false; - fetch_sprite_4 = false; going_to_fetch = false; first_fetch = true; no_sprites = false; @@ -855,7 +858,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (!fetch_sprite) { - if (!pre_render) + if (!pre_render_2) { // before we go on to read case 3, we need to know if we stall there or not // Gekkio's tests show that if sprites are at position 0 or 1 (mod 8) @@ -871,15 +874,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { going_to_fetch = true; fetch_sprite = true; - - if ((SL_sprites[i * 4 + 1] % 8) < 2) - { - fetch_sprite_01 = true; - } - if ((SL_sprites[i * 4 + 1] % 8) > 3) - { - fetch_sprite_4 = true; - } } } } @@ -888,20 +882,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk switch (read_case) { case 0: // read a background tile - if ((internal_cycle % 2) == 0) + if ((internal_cycle % 2) == 1) { // calculate the row number of the tiles to be fetched y_tile = ((int)Math.Floor((float)(scroll_y + LY) / 8)) % 32; temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32; - tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch]; + tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch]; tile_data[2] = Core.VRAM[0x3800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch]; VRAM_sel = tile_data[2].Bit(3) ? 1 : 0; - + BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat; - } - else - { + read_case = 1; if (!pre_render) { @@ -911,7 +903,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 1: // read from tile graphics (0) - if ((internal_cycle % 2) == 0) + if ((internal_cycle % 2) == 1) { y_scroll_offset = (scroll_y + LY) % 8; @@ -933,15 +925,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } tile_data[0] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; } - } - else - { + read_case = 2; } break; case 2: // read from tile graphics (1) if ((internal_cycle % 2) == 0) + { + pre_render_2 = false; + } + else { y_scroll_offset = (scroll_y + LY) % 8; @@ -968,9 +962,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } tile_data[1] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; } - } - else - { + if (pre_render) { // here we set up rendering @@ -988,11 +980,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 3: // read from sprite data - if ((internal_cycle % 2) == 0) - { - // nothing to do if not fetching - } - else + if ((internal_cycle % 2) == 1) { read_case = 0; latch_new_data = true; @@ -1000,16 +988,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 4: // read from window data - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32; tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch]; tile_data[2] = Core.VRAM[0x3800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch]; VRAM_sel = tile_data[2].Bit(3) ? 1 : 0; - BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat; - } - else - { + BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat; + window_tile_inc++; read_case = 5; } @@ -1017,7 +1003,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 5: // read from tile graphics (for the window) - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { y_scroll_offset = (window_y_tile_inc) % 8; @@ -1027,8 +1013,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } if (LCDC.Bit(4)) - { - tile_data[0] = Core.VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; + { + tile_data[0] = Core.VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2]; } else { @@ -1036,19 +1022,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (tile_byte.Bit(7)) { tile_byte -= 256; - } - tile_data[0] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; + } + tile_data[0] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2]; } - } - else - { + read_case = 6; } window_counter++; break; case 6: // read from tile graphics (for the window) - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { y_scroll_offset = (window_y_tile_inc) % 8; @@ -1063,8 +1047,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (tile_byte < 0) { tile_byte += 256; - } - tile_data[1] = Core.VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; + } + tile_data[1] = Core.VRAM[(VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1]; } else { @@ -1072,13 +1056,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (tile_byte.Bit(7) && tile_byte > 0) { tile_byte -= 256; - } - tile_data[1] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; + } + tile_data[1] = Core.VRAM[(VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; } - } - else - { if (window_pre_render) { // here we set up rendering @@ -1101,11 +1082,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 7: // read from sprite data - if ((window_counter % 2) == 0) - { - // nothing to do if not fetching - } - else + if ((window_counter % 2) == 1) { read_case = 4; latch_new_data = true; @@ -1114,18 +1091,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 8: // done reading, we are now in phase 0 - pre_render = true; // the other interrupts appear to be delayed by 1 CPU cycle, so do the same here if (hbl_countdown > 0) { hbl_countdown--; + STAT &= 0xFC; + STAT |= 0x00; + if (hbl_countdown == 0) { - STAT &= 0xFC; - STAT |= 0x00; - if (STAT.Bit(3)) { HBL_INT = true; } OAM_access_read = true; @@ -1163,22 +1139,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (going_to_fetch) { going_to_fetch = false; - sprite_fetch_counter = first_fetch ? 2 : 0; - first_fetch = false; - if (fetch_sprite_01) - { - sprite_fetch_counter += 2; - fetch_sprite_01 = false; - } - - if (fetch_sprite_4) - { - sprite_fetch_counter -= 2; - fetch_sprite_4 = false; - } - - int last_eval = 0; + last_eval = 0; // at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles for (int i = 0; i < SL_sprites_index; i++) @@ -1193,16 +1155,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - // if we didn't evaluate all the sprites immediately, 2 more cycles are added to restart it - if (evaled_sprites != (Math.Pow(2,SL_sprites_index) - 1)) + // there is no penalty if the next sprites to be fetched are within the currentfetch block (8 pixels) + if (first_fetch || (last_eval >= consecutive_sprite)) { - if ((last_eval % 8) == 0) { sprite_fetch_counter += 3; } - else if ((last_eval % 8) == 1) { sprite_fetch_counter += 2; } + if ((last_eval % 8) == 0) { sprite_fetch_counter += 5; } + else if ((last_eval % 8) == 1) { sprite_fetch_counter += 4; } else if ((last_eval % 8) == 2) { sprite_fetch_counter += 3; } else if ((last_eval % 8) == 3) { sprite_fetch_counter += 2; } - else if ((last_eval % 8) == 4) { sprite_fetch_counter += 3; } - else { sprite_fetch_counter += 2; } + else if ((last_eval % 8) == 4) { sprite_fetch_counter += 1; } + else if ((last_eval % 8) == 5) { sprite_fetch_counter += 0; } + else if ((last_eval % 8) == 6) { sprite_fetch_counter += 0; } + else if ((last_eval % 8) == 7) { sprite_fetch_counter += 0; } } + + total_counter += sprite_fetch_counter; + consecutive_sprite = last_eval + (8 - (last_eval % 8)); + + first_fetch = false; } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs index 14570a59f2..be2812ef86 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs @@ -162,9 +162,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk //if (ticker > 10000000) { vblank_rise = true; }//throw new Exception("ERROR: Unable to Resolve Frame"); } in_vblank_old = in_vblank; + REG_FF0F_OLD = REG_FF0F; } - vblank_rise = false; + vblank_rise = false; } // Switch Speed (GBC only) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs index c7f2f425f3..104274715c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs @@ -72,6 +72,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("REG_FFFF", ref REG_FFFF); ser.Sync("REG_FF0F", ref REG_FF0F); + ser.Sync("REG_FF0F_OLD", ref REG_FF0F_OLD); // memory domains ser.Sync("RAM", ref RAM, false); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 462f5e9964..0f05fb3259 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -28,6 +28,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public byte REG_FFFF; // The unused bits in this register (interrupt flags) are always set public byte REG_FF0F = 0xE0; + // Updating reg FF0F seemsto be delayed by one cycle + // tests + public byte REG_FF0F_OLD = 0xE0; // memory domains public byte[] RAM = new byte[0x8000]; // only 0x2000 available to GB @@ -109,12 +112,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { if (game.System == "GB") { - Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load"); + Bios = comm.CoreFileProvider.GetFirmware("GBS", "World", true, "BIOS Not Found, Cannot Load"); ppu = new GB_PPU(); } else { - Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", true, "BIOS Not Found, Cannot Load"); + Bios = comm.CoreFileProvider.GetFirmware("GBCS", "World", true, "BIOS Not Found, Cannot Load"); ppu = new GBC_PPU(); is_GBC = true; } @@ -122,12 +125,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else if (_syncSettings.ConsoleMode == GBSyncSettings.ConsoleModeType.GB) { - Bios = comm.CoreFileProvider.GetFirmware("GB", "World", true, "BIOS Not Found, Cannot Load"); + Bios = comm.CoreFileProvider.GetFirmware("GBS", "World", true, "BIOS Not Found, Cannot Load"); ppu = new GB_PPU(); } else { - Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", true, "BIOS Not Found, Cannot Load"); + Bios = comm.CoreFileProvider.GetFirmware("GBCS", "World", true, "BIOS Not Found, Cannot Load"); ppu = new GBC_PPU(); is_GBC = true; } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs index 396c602f0a..7b6a0ce9cc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GB_PPU.cs @@ -53,16 +53,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 0xFF41: // STAT // writing to STAT during mode 0 or 1 causes a STAT IRQ + // this appears to be a glitchy LYC compare if (LCDC.Bit(7)) { if (((STAT & 3) == 0) || ((STAT & 3) == 1)) { LYC_INT = true; + //if (Core.REG_FFFF.Bit(1)) { Core.cpu.FlagI = true; } + //Core.REG_FF0F |= 0x02; + } + else + { + if (value.Bit(6)) + { + if (LY == LYC) { LYC_INT = true; } + else { LYC_INT = false; } + } } } STAT = (byte)((value & 0xF8) | (STAT & 7) | 0x80); - if (!STAT.Bit(6)) { LYC_INT = false; } + //if (!STAT.Bit(6)) { LYC_INT = false; } if (!STAT.Bit(4)) { VBL_INT = false; } break; case 0xFF42: // SCY @@ -78,8 +89,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk LYC = value; if (LCDC.Bit(7)) { - if (LY != LYC) { STAT &= 0xFB; } - else { STAT |= 0x4; } + if (LY != LYC) { STAT &= 0xFB; LYC_INT = false; } + else { STAT |= 0x4; LYC_INT = true; } + + // special case: the transition from 153 -> 0 acts strange + // the comparison to 153 expects to be true for longer then the value of LY expects to be 153 + // this appears to be fixed in CGB + if ((LY_inc == 0) && cycle == 8) + { + if (153 != LYC) { STAT &= 0xFB; LYC_INT = false; } + else { STAT |= 0x4; LYC_INT = true; } + } } break; case 0xFF46: // DMA @@ -191,12 +211,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((cycle == 4) && (LY == 144)) { - - HBL_INT = false; - + if ((cycle == 2) && (LY == 144)) + { // there is an edge case where a VBL INT is triggered if STAT bit 5 is set if (STAT.Bit(5)) { VBL_INT = true; } + } + + if ((cycle == 4) && (LY == 144)) + { + HBL_INT = false; // set STAT mode to 1 (VBlank) and interrupt flag if it is enabled STAT &= 0xFC; @@ -206,12 +229,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Core.REG_FF0F |= 0x01; } - if ((cycle == 84) && (LY == 144)) + if ((cycle == 4) && (LY == 144)) { if (STAT.Bit(5)) { VBL_INT = false; } } - if ((LY == 153) && (cycle == 6)) + if ((cycle == 6) && (LY == 153)) { LY = 0; LY_inc = 0; @@ -301,7 +324,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } else if ((cycle >= 80) && (LY < 144)) { - if (cycle >= 84) + if (cycle >= 83) { if (cycle == 84) { @@ -313,7 +336,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } // render the screen and handle hblank - render(cycle - 84); + render(cycle - 83); } else if (cycle == 80) { @@ -325,13 +348,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - if ((LY_inc == 0)) + if (LY_inc == 0) { - if (cycle == 12) + if (cycle == 10) { LYC_INT = false; STAT &= 0xFB; - + } + else if (cycle == 12) + { // Special case of LY = LYC if ((LY == LYC) && !STAT.Bit(2)) { @@ -423,12 +448,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk read_case = 0; internal_cycle = 0; pre_render = true; + pre_render_2 = true; tile_inc = 0; pixel_counter = -8; sl_use_index = 0; fetch_sprite = false; - fetch_sprite_01 = false; - fetch_sprite_4 = false; going_to_fetch = false; first_fetch = true; no_sprites = false; @@ -436,6 +460,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk window_pre_render = false; window_latch = LCDC.Bit(5); + total_counter = 0; + // 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))) { @@ -577,7 +603,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (!fetch_sprite) { - if (!pre_render) + if (!pre_render_2) { // before we go on to read case 3, we need to know if we stall there or not // Gekkio's tests show that if sprites are at position 0 or 1 (mod 8) @@ -593,15 +619,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { going_to_fetch = true; fetch_sprite = true; - - if ((SL_sprites[i * 4 + 1] % 8) < 2) - { - fetch_sprite_01 = true; - } - if ((SL_sprites[i * 4 + 1] % 8) > 3) - { - fetch_sprite_4 = true; - } } } } @@ -610,16 +627,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk switch (read_case) { case 0: // read a background tile - if ((internal_cycle % 2) == 0) + if ((internal_cycle % 2) == 1) { // calculate the row number of the tiles to be fetched y_tile = ((int)Math.Floor((float)(scroll_y + LY) / 8)) % 32; temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32; tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch]; - } - else - { + read_case = 1; if (!pre_render) { @@ -629,7 +644,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 1: // read from tile graphics (0) - if ((internal_cycle % 2) == 0) + if ((internal_cycle % 2) == 1) { y_scroll_offset = (scroll_y + LY) % 8; @@ -647,9 +662,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk tile_data[0] = Core.VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2]; } - } - else - { read_case = 2; } break; @@ -657,6 +669,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 2: // read from tile graphics (1) if ((internal_cycle % 2) == 0) { + pre_render_2 = false; + } + else + { y_scroll_offset = (scroll_y + LY) % 8; if (LCDC.Bit(4)) @@ -680,9 +696,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk tile_data[1] = Core.VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; } - } - else - { if (pre_render) { // here we set up rendering @@ -700,25 +713,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 3: // read from sprite data - if ((internal_cycle % 2) == 0) - { - // nothing to do if not fetching - } - else - { + if ((internal_cycle % 2) == 1) + { read_case = 0; latch_new_data = true; } break; case 4: // read from window data - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32; - tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch]; ; - } - else - { + tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch]; + window_tile_inc++; read_case = 5; } @@ -726,15 +733,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 5: // read from tile graphics (for the window) - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { y_scroll_offset = (window_y_tile_inc) % 8; if (LCDC.Bit(4)) { - + tile_data[0] = Core.VRAM[tile_byte * 16 + y_scroll_offset * 2]; - + } else { @@ -743,19 +750,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { tile_byte -= 256; } - + tile_data[0] = Core.VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2]; } - } - else - { + read_case = 6; } window_counter++; break; case 6: // read from tile graphics (for the window) - if ((window_counter % 2) == 0) + if ((window_counter % 2) == 1) { y_scroll_offset = (window_y_tile_inc) % 8; if (LCDC.Bit(4)) @@ -779,9 +784,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk tile_data[1] = Core.VRAM[0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1]; } - } - else - { if (window_pre_render) { // here we set up rendering @@ -804,11 +806,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; case 7: // read from sprite data - if ((window_counter % 2) == 0) - { - // nothing to do if not fetching - } - else + if ((window_counter % 2) == 1) { read_case = 4; latch_new_data = true; @@ -823,11 +821,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (hbl_countdown > 0) { hbl_countdown--; + STAT &= 0xFC; + STAT |= 0x00; + if (hbl_countdown == 0) { - STAT &= 0xFC; - STAT |= 0x00; - if (STAT.Bit(3)) { HBL_INT = true; } OAM_access_read = true; @@ -854,6 +852,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk tile_data_latch[0] = tile_data[0]; tile_data_latch[1] = tile_data[1]; } + + if (consecutive_sprite > 0) { consecutive_sprite -= 1; } } // every in range sprite takes 6 cycles to process @@ -864,22 +864,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk if (going_to_fetch) { going_to_fetch = false; - sprite_fetch_counter = first_fetch ? 2 : 0; - first_fetch = false; - if (fetch_sprite_01) - { - sprite_fetch_counter += 2; - fetch_sprite_01 = false; - } - - if (fetch_sprite_4) - { - sprite_fetch_counter -= 2; - fetch_sprite_4 = false; - } - - int last_eval = 0; + last_eval = 0; // at this time it is unknown what each cycle does, but we only need to accurately keep track of cycles for (int i = 0; i < SL_sprites_index; i++) @@ -894,16 +880,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk } } - // if we didn't evaluate all the sprites immediately, 2 more cycles are added to restart it - if (evaled_sprites != (Math.Pow(2,SL_sprites_index) - 1)) + // x scroll offsets the penalty table + // there is no penalty if the next sprites to be fetched are within the currentfetch block (8 pixels) + if (first_fetch || (last_eval >= consecutive_sprite)) { - if ((last_eval % 8) == 0) { sprite_fetch_counter += 3; } - else if ((last_eval % 8) == 1) { sprite_fetch_counter += 2; } - else if ((last_eval % 8) == 2) { sprite_fetch_counter += 3; } - else if ((last_eval % 8) == 3) { sprite_fetch_counter += 2; } - else if ((last_eval % 8) == 4) { sprite_fetch_counter += 3; } - else { sprite_fetch_counter += 2; } + if (((last_eval + render_offset) % 8) == 0) { sprite_fetch_counter += 5; } + else if (((last_eval + render_offset) % 8) == 1) { sprite_fetch_counter += 4; } + else if (((last_eval + render_offset) % 8) == 2) { sprite_fetch_counter += 3; } + else if (((last_eval + render_offset) % 8) == 3) { sprite_fetch_counter += 2; } + else if (((last_eval + render_offset) % 8) == 4) { sprite_fetch_counter += 1; } + else if (((last_eval + render_offset) % 8) == 5) { sprite_fetch_counter += 0; } + else if (((last_eval + render_offset) % 8) == 6) { sprite_fetch_counter += 0; } + else if (((last_eval + render_offset) % 8) == 7) { sprite_fetch_counter += 0; } } + + total_counter += sprite_fetch_counter; + consecutive_sprite = last_eval + (8 - (last_eval % 8)); + + first_fetch = false; } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs index a3ef71cad3..bbb583efda 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs @@ -39,7 +39,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk // Interrupt flags case 0xFF0F: - ret = REG_FF0F; + ret = REG_FF0F_OLD; break; // audio regs @@ -316,6 +316,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Console.Write("GBC Compatibility? "); Console.WriteLine(value); GBC_compat = false; + // cpu operation is a function of hardware only + //cpu.is_GBC = GBC_compat; } break; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs index 6c86840b18..37ffb9078e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs @@ -66,8 +66,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int tile_byte; public int sprite_fetch_cycles; public bool fetch_sprite; - public bool fetch_sprite_01; - public bool fetch_sprite_4; public bool going_to_fetch; public bool first_fetch; public int sprite_fetch_counter; @@ -77,6 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int temp_fetch; public int tile_inc; public bool pre_render; + public bool pre_render_2; public byte[] tile_data = new byte[3]; public byte[] tile_data_latch = new byte[3]; public int latch_counter; @@ -94,7 +93,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk public int sprite_ordered_index; public bool blank_frame; public bool window_latch; + public int consecutive_sprite; + public int last_eval; + public int total_counter; // windowing state public int window_counter; public bool window_pre_render; @@ -218,8 +220,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("tile_byte", ref tile_byte); ser.Sync("sprite_fetch_cycles", ref sprite_fetch_cycles); ser.Sync("fetch_sprite", ref fetch_sprite); - ser.Sync("fetch_sprite_01", ref fetch_sprite_01); - ser.Sync("fetch_sprite_4", ref fetch_sprite_4); ser.Sync("going_to_fetch", ref going_to_fetch); ser.Sync("first_fetch", ref first_fetch); ser.Sync("sprite_fetch_counter", ref sprite_fetch_counter); @@ -229,6 +229,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("temp_fetch", ref temp_fetch); ser.Sync("tile_inc", ref tile_inc); ser.Sync("pre_render", ref pre_render); + ser.Sync("pre_render_2", ref pre_render_2); ser.Sync("tile_data", ref tile_data, false); ser.Sync("tile_data_latch", ref tile_data_latch, false); ser.Sync("latch_counter", ref latch_counter); @@ -246,6 +247,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk ser.Sync("sprite_ordered_index", ref sprite_ordered_index); ser.Sync("blank_frame", ref blank_frame); ser.Sync("window_latch", ref window_latch); + ser.Sync("consecutive_sprite", ref consecutive_sprite); + ser.Sync("last_eval", ref last_eval); ser.Sync("window_counter", ref window_counter); ser.Sync("window_pre_render", ref window_pre_render);