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,147 +853,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
if (tile_data_latch[2].Bit(5) && Core.GBC_compat)
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(render_counter % 8) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(render_counter % 8) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
}
|
||||
|
||||
int ref_pixel = pixel;
|
||||
|
||||
if (!Core.GBC_compat)
|
||||
{
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = BGP & 3;
|
||||
}
|
||||
}
|
||||
|
||||
int pal_num = tile_data_latch[2] & 0x7;
|
||||
|
||||
bool use_sprite = false;
|
||||
|
||||
int s_pixel = 0;
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
// There is another priority bit in GBC, that can still override sprite priority
|
||||
if (LCDC.Bit(0) && tile_data_latch[2].Bit(7) && (ref_pixel != 0) && Core.GBC_compat)
|
||||
{
|
||||
use_sprite = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
pal_num = sprite_attr & 7;
|
||||
|
||||
if (!Core.GBC_compat)
|
||||
{
|
||||
pal_num = sprite_attr.Bit(4) ? 1 : 0;
|
||||
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
if (Core.GBC_compat)
|
||||
{
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pixel];
|
||||
}
|
||||
}
|
||||
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 2;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
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;
|
||||
|
@ -1002,22 +871,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
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) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1038,16 +912,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
tile_byte -= 256;
|
||||
}
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2;
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
tile_data[0] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // read from tile graphics (1)
|
||||
if ((internal_cycle % 2) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1075,9 +953,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
|
||||
bus_address = (VRAM_sel * 0x2000) + 0x1000 + tile_byte * 16 + y_scroll_offset * 2 + 1;
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
|
||||
tile_data[1] = Core.VRAM[bus_address];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre_render)
|
||||
{
|
||||
// here we set up rendering
|
||||
|
@ -1105,7 +985,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 3;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
|
@ -1113,8 +998,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 1)
|
||||
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];
|
||||
|
||||
|
@ -1124,15 +1011,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
VRAM_sel = tile_data[2].Bit(3) ? 1 : 0;
|
||||
BG_V_flip = tile_data[2].Bit(6) & Core.GBC_compat;
|
||||
|
||||
window_tile_inc++;
|
||||
window_tile_inc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 5;
|
||||
}
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 5: // read from tile graphics (for the window)
|
||||
if ((window_counter % 2) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1155,16 +1047,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
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) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1194,7 +1090,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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
|
||||
|
@ -1242,49 +1140,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_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;
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
if (STAT.Bit(3)) { HBL_INT = true; }
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
read_case = 18;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
|
@ -1315,6 +1193,158 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
HDMA_can_start = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
if (tile_data_latch[2].Bit(5) && Core.GBC_compat)
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(render_counter % 8) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(render_counter % 8) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
}
|
||||
|
||||
int ref_pixel = pixel;
|
||||
|
||||
if (!Core.GBC_compat)
|
||||
{
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = BGP & 3;
|
||||
}
|
||||
}
|
||||
|
||||
int pal_num = tile_data_latch[2] & 0x7;
|
||||
|
||||
bool use_sprite = false;
|
||||
|
||||
int s_pixel = 0;
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
// There is another priority bit in GBC, that can still override sprite priority
|
||||
if (LCDC.Bit(0) && tile_data_latch[2].Bit(7) && (ref_pixel != 0) && Core.GBC_compat)
|
||||
{
|
||||
use_sprite = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
pal_num = sprite_attr & 7;
|
||||
|
||||
if (!Core.GBC_compat)
|
||||
{
|
||||
pal_num = sprite_attr.Bit(4) ? 1 : 0;
|
||||
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
if (Core.GBC_compat)
|
||||
{
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pixel];
|
||||
}
|
||||
}
|
||||
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
// hbl_countdown = 1;
|
||||
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
if (STAT.Bit(3)) { HBL_INT = true; }
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,107 +850,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
if (tile_data_latch[2].Bit(5))
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(render_counter % 8) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(render_counter % 8) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
}
|
||||
|
||||
int ref_pixel = pixel;
|
||||
|
||||
int pal_num = tile_data_latch[2] & 0x7;
|
||||
|
||||
bool use_sprite = false;
|
||||
|
||||
int s_pixel = 0;
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
// There is another priority bit in GBC, that can still override sprite priority
|
||||
if (LCDC.Bit(0) && tile_data_latch[2].Bit(7) && (ref_pixel != 0))
|
||||
{
|
||||
use_sprite = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
pal_num = sprite_attr & 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
hbl_countdown = 2;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
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;
|
||||
|
@ -962,18 +872,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -997,14 +911,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1034,7 +952,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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
|
||||
|
@ -1062,7 +982,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 3;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 0;
|
||||
latch_new_data = true;
|
||||
|
@ -1070,8 +995,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 4: // read from window data
|
||||
if ((window_counter % 2) == 1)
|
||||
{
|
||||
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];
|
||||
|
||||
|
@ -1082,14 +1009,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1113,15 +1045,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = window_y_tile_inc % 8;
|
||||
|
||||
if (BG_V_flip)
|
||||
|
@ -1151,7 +1087,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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
|
||||
|
@ -1188,7 +1126,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
latch_counter = 0;
|
||||
latch_new_data = true;
|
||||
window_pre_render = false;
|
||||
window_pre_render = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1199,59 +1137,35 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_pre_render = true;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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
|
||||
}
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -1275,7 +1189,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
read_case++;
|
||||
read_case++;
|
||||
break;
|
||||
case 21:
|
||||
// hardware tests indicate that HDMA starts at this point, not immediately after mode 3 ends
|
||||
|
@ -1283,6 +1197,121 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
HDMA_can_start = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
if (tile_data_latch[2].Bit(5))
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(render_counter % 8) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(render_counter % 8) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
}
|
||||
|
||||
int ref_pixel = pixel;
|
||||
|
||||
int pal_num = tile_data_latch[2] & 0x7;
|
||||
|
||||
bool use_sprite = false;
|
||||
|
||||
int s_pixel = 0;
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
// There is another priority bit in GBC, that can still override sprite priority
|
||||
if (LCDC.Bit(0) && tile_data_latch[2].Bit(7) && (ref_pixel != 0))
|
||||
{
|
||||
use_sprite = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
pal_num = sprite_attr & 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
if (use_sprite)
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = OBJ_palette[pal_num * 4 + s_pixel];
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = BG_palette[pal_num * 4 + pixel];
|
||||
}
|
||||
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
// hbl_countdown = 1;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,96 +538,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (!pre_render && !fetch_sprite)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
|
||||
int ref_pixel = pixel;
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = BGP & 3;
|
||||
}
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int s_pixel = 0;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
bool use_sprite = false;
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = color_palette[pixel];
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
hbl_countdown = 2;
|
||||
read_case = 8;
|
||||
}
|
||||
}
|
||||
else if (pixel_counter < 0)
|
||||
{
|
||||
pixel_counter++;
|
||||
}
|
||||
render_counter++;
|
||||
}
|
||||
|
||||
if (!fetch_sprite)
|
||||
{
|
||||
switch (read_case)
|
||||
{
|
||||
case 0: // read a background tile
|
||||
if ((internal_cycle % 2) == 1)
|
||||
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;
|
||||
|
@ -634,19 +555,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
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) == 1)
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 1;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
|
@ -665,14 +590,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
{
|
||||
if ((internal_cycle % 2) == 0)
|
||||
{
|
||||
read_case_prev = 2;
|
||||
|
||||
y_scroll_offset = (scroll_y + LY) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
|
@ -697,7 +626,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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
|
||||
|
@ -725,30 +656,42 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 3: // read from tile data
|
||||
if ((internal_cycle % 2) == 1)
|
||||
{
|
||||
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) == 1)
|
||||
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) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 5;
|
||||
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
|
||||
if (LCDC.Bit(4))
|
||||
|
@ -767,15 +710,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 6;
|
||||
|
||||
y_scroll_offset = (window_y_tile_inc) % 8;
|
||||
if (LCDC.Bit(4))
|
||||
{
|
||||
|
@ -799,7 +746,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
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
|
||||
|
@ -847,49 +796,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
break;
|
||||
|
||||
case 7: // read from tile data (window)
|
||||
if ((window_counter % 2) == 1)
|
||||
if ((window_counter % 2) == 0)
|
||||
{
|
||||
read_case_prev = 7;
|
||||
// What's on the bus?
|
||||
}
|
||||
else
|
||||
{
|
||||
read_case = 4;
|
||||
latch_new_data = true;
|
||||
}
|
||||
window_counter++;
|
||||
window_counter++;
|
||||
break;
|
||||
|
||||
case 8: // done reading, we are now in phase 0
|
||||
pre_render = true;
|
||||
was_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;
|
||||
VRAM_access_read = true;
|
||||
VRAM_access_write = true;
|
||||
OAM_access_read = true;
|
||||
OAM_access_write = true;
|
||||
|
||||
read_case = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
if (STAT.Bit(3)) { HBL_INT = true; }
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
read_case = 18;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
|
@ -913,6 +842,107 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
rendering_complete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!was_pre_render)
|
||||
{
|
||||
// start shifting data into the LCD
|
||||
if (render_counter >= (render_offset + 8))
|
||||
{
|
||||
pixel = tile_data_latch[0].Bit(7 - (render_counter % 8)) ? 1 : 0;
|
||||
pixel |= tile_data_latch[1].Bit(7 - (render_counter % 8)) ? 2 : 0;
|
||||
|
||||
int ref_pixel = pixel;
|
||||
if (LCDC.Bit(0))
|
||||
{
|
||||
pixel = (BGP >> (pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = BGP & 3;
|
||||
}
|
||||
|
||||
// now we have the BG pixel, we next need the sprite pixel
|
||||
if (!no_sprites)
|
||||
{
|
||||
bool have_sprite = false;
|
||||
int s_pixel = 0;
|
||||
int sprite_attr = 0;
|
||||
|
||||
if (sprite_present_list[pixel_counter] == 1)
|
||||
{
|
||||
have_sprite = true;
|
||||
s_pixel = sprite_pixel_list[pixel_counter];
|
||||
sprite_attr = sprite_attr_list[pixel_counter];
|
||||
}
|
||||
|
||||
if (have_sprite)
|
||||
{
|
||||
bool use_sprite = false;
|
||||
if (LCDC.Bit(1))
|
||||
{
|
||||
if (!sprite_attr.Bit(7))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
else if (ref_pixel == 0)
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
|
||||
if (!LCDC.Bit(0))
|
||||
{
|
||||
use_sprite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sprite)
|
||||
{
|
||||
if (sprite_attr.Bit(4))
|
||||
{
|
||||
pixel = (obj_pal_1 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (obj_pal_0 >> (s_pixel * 2)) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// based on sprite priority and pixel values, pick a final pixel color
|
||||
Core.vid_buffer[LY * 160 + pixel_counter] = color_palette[pixel];
|
||||
pixel_counter++;
|
||||
|
||||
if (pixel_counter == 160)
|
||||
{
|
||||
read_case = 8;
|
||||
// hbl_countdown = 1;
|
||||
|
||||
STAT &= 0xFC;
|
||||
STAT |= 0x00;
|
||||
|
||||
if (STAT.Bit(3)) { HBL_INT = true; }
|
||||
|
||||
// TODO: If Window is turned on midscanline what happens? When is this check done exactly?
|
||||
if ((window_started && window_latch) || (window_is_reset && !window_latch && (LY > window_y_latch)))
|
||||
{
|
||||
window_y_tile_inc++;
|
||||
if (window_y_tile_inc == 8)
|
||||
{
|
||||
window_y_tile_inc = 0;
|
||||
window_y_tile++;
|
||||
window_y_tile %= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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