GBHawk: refactor some ppu code to prepare for more accurate VRAm glitch emulation
This commit is contained in:
parent
bd3ee6f45c
commit
2a92121483
|
@ -136,7 +136,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// don't draw for one frame after turning on
|
||||
blank_frame = true;
|
||||
}
|
||||
|
||||
LCDC = value;
|
||||
break;
|
||||
case 0xFF41: // STAT
|
||||
|
@ -198,7 +197,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
case 0xFF4B: // WX
|
||||
window_x = value;
|
||||
break;
|
||||
|
||||
// These are GBC specific Regs
|
||||
case 0xFF51: // HDMA1
|
||||
HDMA_src_hi = value;
|
||||
|
@ -284,9 +282,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
BG_transfer_byte = value;
|
||||
BG_bytes[BG_bytes_index] = value;
|
||||
}
|
||||
|
||||
//Console.WriteLine("BG PAL " + value + " " + Core.cpu.TotalExecutedCycles + " " + BG_bytes_index);
|
||||
// change the appropriate palette color
|
||||
color_compute_BG();
|
||||
if (!pal_change_blocked) { color_compute_BG(); }
|
||||
|
||||
if (BG_bytes_inc) { BG_bytes_index++; BG_bytes_index &= 0x3F; }
|
||||
break;
|
||||
case 0xFF6A: // OBPI
|
||||
|
@ -301,7 +300,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
|
||||
// change the appropriate palette color
|
||||
color_compute_OBJ();
|
||||
if (!pal_change_blocked) { color_compute_OBJ(); }
|
||||
|
||||
if (OBJ_bytes_inc) { OBJ_bytes_index++; OBJ_bytes_index &= 0x3F; }
|
||||
break;
|
||||
|
@ -766,6 +765,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
read_case = 0;
|
||||
internal_cycle = 0;
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
tile_inc = 0;
|
||||
pixel_counter = -8;
|
||||
|
@ -834,6 +834,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// don't evaluate sprites until pre-render for window is over
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
}
|
||||
|
||||
|
@ -852,7 +853,348 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 0;
|
||||
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
//bus_address = 0x1800 + (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)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here, only the lower 3 bits are latched though
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 3;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 4;
|
||||
|
||||
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];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat;
|
||||
|
||||
window_tile_inc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
read_case++;
|
||||
break;
|
||||
case 21:
|
||||
// hardware tests indicate that HDMA starts at this point, not immediately after mode 3 ends
|
||||
rendering_complete = true;
|
||||
HDMA_can_start = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
|
@ -976,297 +1318,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 2;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
// hbl_countdown = 1;
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
|
||||
BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat;
|
||||
|
||||
read_case = 1;
|
||||
if (!pre_render)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here, only the lower 3 bits are latched though
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
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];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat;
|
||||
|
||||
window_tile_inc++;
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
|
||||
if (hbl_countdown > 0)
|
||||
{
|
||||
hbl_countdown--;
|
||||
if (hbl_countdown == 0)
|
||||
{
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
|
@ -1285,36 +1338,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
read_case++;
|
||||
break;
|
||||
case 21:
|
||||
// hardware tests indicate that HDMA starts at this point, not immediately after mode 3 ends
|
||||
rendering_complete = true;
|
||||
HDMA_can_start = true;
|
||||
break;
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
internal_cycle++;
|
||||
|
||||
if (latch_new_data)
|
||||
|
@ -1324,6 +1354,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
tile_data_latch[1] = tile_data[1];
|
||||
tile_data_latch[2] = tile_data[2];
|
||||
}
|
||||
|
||||
was_pre_render = pre_render;
|
||||
}
|
||||
|
||||
// every in range sprite takes 6 cycles to process
|
||||
|
@ -1797,6 +1829,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
for (int i = 0; i < BG_bytes.Length; i++) { BG_bytes[i] = 0xFF; }
|
||||
for (int i = 0; i < OBJ_bytes.Length; i++) { OBJ_bytes[i] = 0xFF; }
|
||||
|
||||
pal_change_blocked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -759,6 +759,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
read_case = 0;
|
||||
internal_cycle = 0;
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
tile_inc = 0;
|
||||
pixel_counter = -8;
|
||||
|
@ -830,6 +831,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// don't evaluate sprites until pre-render for window is over
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
}
|
||||
|
||||
|
@ -848,7 +850,355 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 0;
|
||||
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
|
||||
BG_V_flip = tile_data[2].Bit(6);
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 1;
|
||||
if (!pre_render)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here, only the lower 3 bits are latched though
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 3;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 4;
|
||||
|
||||
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];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
BG_V_flip = tile_data[2].Bit(6);
|
||||
|
||||
window_tile_inc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
read_case = 18;
|
||||
|
||||
if (Core.double_speed)
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
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
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
read_case++;
|
||||
break;
|
||||
case 21:
|
||||
// hardware tests indicate that HDMA starts at this point, not immediately after mode 3 ends
|
||||
rendering_complete = true;
|
||||
HDMA_can_start = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
|
@ -932,306 +1282,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 2;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
// hbl_countdown = 1;
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
tile_byte = Core.VRAM[0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
|
||||
BG_V_flip = tile_data[2].Bit(6);
|
||||
|
||||
read_case = 1;
|
||||
if (!pre_render)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here, only the lower 3 bits are latched though
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
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];
|
||||
|
||||
bus_address = 0x3800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_data[2] = Core.VRAM[bus_address];
|
||||
|
||||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
BG_V_flip = tile_data[2].Bit(6);
|
||||
|
||||
window_tile_inc++;
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
{
|
||||
y_scroll_offset = 7 - y_scroll_offset;
|
||||
}
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
|
||||
if (hbl_countdown > 0)
|
||||
{
|
||||
hbl_countdown--;
|
||||
|
||||
if (hbl_countdown == 0)
|
||||
{
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
read_case = 18;
|
||||
|
||||
if (Core.double_speed)
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
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
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Core.double_speed)
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
|
@ -1253,36 +1305,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
read_case++;
|
||||
break;
|
||||
case 21:
|
||||
// hardware tests indicate that HDMA starts at this point, not immediately after mode 3 ends
|
||||
rendering_complete = true;
|
||||
HDMA_can_start = true;
|
||||
break;
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
internal_cycle++;
|
||||
|
||||
if (latch_new_data)
|
||||
|
@ -1292,6 +1321,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
tile_data_latch[1] = tile_data[1];
|
||||
tile_data_latch[2] = tile_data[2];
|
||||
}
|
||||
|
||||
was_pre_render = pre_render;
|
||||
}
|
||||
|
||||
// every in range sprite takes 6 cycles to process
|
||||
|
|
|
@ -449,6 +449,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
read_case = 0;
|
||||
internal_cycle = 0;
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
tile_inc = 0;
|
||||
pixel_counter = -8;
|
||||
|
@ -517,6 +518,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
// don't evaluate sprites until pre-render for window is over
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
pre_render_2 = true;
|
||||
}
|
||||
|
||||
|
@ -536,7 +538,312 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 0;
|
||||
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
|
||||
bus_address = 0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_byte = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 1;
|
||||
|
||||
if (!pre_render)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 3;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 4;
|
||||
|
||||
temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32;
|
||||
|
||||
bus_address = 0x1800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_byte = Core.VRAM[bus_address];
|
||||
|
||||
window_tile_inc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
rendering_complete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
|
@ -608,270 +915,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
hbl_countdown = 2;
|
||||
read_case = 8;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
// hbl_countdown = 1;
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
// calculate the row number of the tiles to be fetched
|
||||
y_tile = (((int)scroll_y + LY) >> 3) % 32;
|
||||
x_tile = scroll_x >> 3;
|
||||
|
||||
temp_fetch = y_tile * 32 + (x_tile + tile_inc) % 32;
|
||||
|
||||
bus_address = 0x1800 + (LCDC.Bit(3) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_byte = Core.VRAM[bus_address];
|
||||
|
||||
read_case = 1;
|
||||
|
||||
if (!pre_render)
|
||||
{
|
||||
tile_inc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // read from tile graphics (0)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
|
||||
// window X is latched for the scanline, mid-line changes have no effect
|
||||
window_x_latch = window_x;
|
||||
|
||||
// x scroll is latched here
|
||||
render_offset = scroll_offset = scroll_x % 8;
|
||||
|
||||
// sprite scroll offset could change depending on window usage
|
||||
sprite_scroll_offset = scroll_offset;
|
||||
|
||||
render_counter = 0;
|
||||
latch_counter = 0;
|
||||
read_case = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
temp_fetch = window_y_tile * 32 + (window_x_tile + window_tile_inc) % 32;
|
||||
|
||||
bus_address = 0x1800 + (LCDC.Bit(6) ? 1 : 0) * 0x400 + temp_fetch;
|
||||
tile_byte = Core.VRAM[bus_address];
|
||||
|
||||
window_tile_inc++;
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7))
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
read_case = 6;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 6: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
// if LCDC somehow changed between the two reads, make sure we have a positive number
|
||||
if (tile_byte < 0)
|
||||
{
|
||||
tile_byte += 256;
|
||||
}
|
||||
|
||||
bus_address = tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
else
|
||||
{
|
||||
// same as before except now tile byte represents a signed byte
|
||||
if (tile_byte.Bit(7) && tile_byte > 0)
|
||||
{
|
||||
tile_byte -= 256;
|
||||
}
|
||||
|
||||
bus_address = 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
if (window_pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
// unlike for the normal background case, there is no pre-render period for the window
|
||||
// so start shifting in data to the screen right away
|
||||
pre_render = false;
|
||||
pre_render_2 = false;
|
||||
first_fetch = true;
|
||||
|
||||
if (window_x_latch <= 7)
|
||||
{
|
||||
if (scroll_offset == 0)
|
||||
{
|
||||
read_case = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 8 + scroll_offset;
|
||||
}
|
||||
render_counter = 8 - scroll_offset;
|
||||
|
||||
render_offset = 7 - window_x_latch;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch + 8 - 7) % 8) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_offset = 0;
|
||||
read_case = 4;
|
||||
render_counter = 8;
|
||||
|
||||
sprite_scroll_offset = (8 - (window_x_latch - 7) % 8) % 8;
|
||||
}
|
||||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 7;
|
||||
}
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
|
||||
if (hbl_countdown > 0)
|
||||
{
|
||||
hbl_countdown--;
|
||||
if (hbl_countdown == 0)
|
||||
{
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
|
@ -890,29 +936,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// this is a degenerate case for starting the window at 0
|
||||
// kevtris' timing doc indicates an additional normal BG access
|
||||
// but this information is thrown away, so it's faster to do this then constantly check
|
||||
// for it in read case 0
|
||||
read_case = 4;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
read_case--;
|
||||
break;
|
||||
case 18:
|
||||
rendering_complete = true;
|
||||
break;
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
internal_cycle++;
|
||||
|
||||
if (latch_new_data)
|
||||
|
@ -921,6 +951,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
tile_data_latch[0] = tile_data[0];
|
||||
tile_data_latch[1] = tile_data[1];
|
||||
}
|
||||
|
||||
was_pre_render = pre_render;
|
||||
}
|
||||
|
||||
// every in range sprite takes 6 cycles to process
|
||||
|
|
|
@ -407,6 +407,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
if (GB_bios_register == 0)
|
||||
{
|
||||
GB_bios_register = value;
|
||||
if (!GBC_compat) { ppu.pal_change_blocked = true; }
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -502,7 +503,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
default:
|
||||
Console.WriteLine(addr + " " + value);
|
||||
//Console.WriteLine(addr + " " + value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,12 +81,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
return 0x0;
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0x0;
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,9 +143,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (ppu.pixel_counter == 160)
|
||||
{
|
||||
//Console.WriteLine("VRAM Glitch " + cpu.TotalExecutedCycles + " " + ppu.bus_address + " " +
|
||||
//VRAM[ppu.bus_address] + " " + ppu.read_case_prev + " " + (ppu.internal_cycle & 1) + " " +
|
||||
//(VRAM_Bank * 0x2000 + (addr - 0x8000)) + " " + VRAM[VRAM_Bank * 0x2000 + (addr - 0x8000)]);
|
||||
|
||||
// This is a complicated case because the PPU is accessing 2 areas of VRAM at the same time.
|
||||
if (is_GBC && ((ppu.read_case_prev == 0) || (ppu.read_case_prev == 4)))
|
||||
{
|
||||
//if ((VRAM_Bank * 0x2000 + (addr - 0x8000)) < 0x3800)
|
||||
//{
|
||||
// return VRAM[VRAM_Bank * 0x2000 + (addr - 0x8000)];
|
||||
//}
|
||||
return VRAM[ppu.bus_address];
|
||||
}
|
||||
|
||||
// What is returned when the ppu isn't accessing VRAM?
|
||||
if ((ppu.read_case_prev == 3) || (ppu.read_case_prev == 7))
|
||||
{
|
||||
return VRAM[VRAM_Bank * 0x2000 + (addr - 0x8000)];
|
||||
}
|
||||
return VRAM[ppu.bus_address];
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -110,6 +110,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
public int hbl_countdown;
|
||||
public int sprite_scroll_offset;
|
||||
public bool was_pre_render;
|
||||
public int read_case_prev;
|
||||
public bool pal_change_blocked; // in compatability mode, you can change palette values but not displayed color
|
||||
|
||||
// variables not in state
|
||||
public int total_counter;
|
||||
|
@ -270,6 +273,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
ser.Sync(nameof(hbl_countdown), ref hbl_countdown);
|
||||
ser.Sync(nameof(sprite_scroll_offset), ref sprite_scroll_offset);
|
||||
ser.Sync(nameof(was_pre_render), ref was_pre_render);
|
||||
ser.Sync(nameof(read_case_prev), ref read_case_prev);
|
||||
ser.Sync(nameof(pal_change_blocked), ref pal_change_blocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue