General cleanup. Minor fixes to LCD Controller accuracy.

This commit is contained in:
Lior Halphon 2016-06-12 19:39:05 +03:00
parent d7d8da3fa9
commit 8153b765a2
3 changed files with 61 additions and 63 deletions

View File

@ -683,8 +683,6 @@ void debugger_ret_hook(GB_gameboy_t *gb)
} }
} }
/* The debugger interface is quite primitive. One letter commands with a single parameter maximum.
Only one breakpoint is allowed at a time. More features will be added later. */
void debugger_run(GB_gameboy_t *gb) void debugger_run(GB_gameboy_t *gb)
{ {
char *input = NULL; char *input = NULL;

View File

@ -240,6 +240,23 @@ void palette_changed(GB_gameboy_t *gb, bool background_palette, unsigned char in
(background_palette? gb->background_palletes_rgb : gb->sprite_palletes_rgb)[index / 2] = gb->rgb_encode_callback(gb, r, g, b); (background_palette? gb->background_palletes_rgb : gb->sprite_palletes_rgb)[index / 2] = gb->rgb_encode_callback(gb, r, g, b);
} }
/*
Each line is 456 cycles, approximately:
Mode 2 - 80 cycles / OAM Transfer
Mode 3 - 172 cycles / Rendering
Mode 0 - 204 cycles / HBlank
Mode 1 is VBlank
Todo: Mode lengths are not constants, see http://blog.kevtris.org/blogfiles/Nitty%20Gritty%20Gameboy%20VRAM%20Timing.txt
*/
#define MODE2_LENGTH 80
#define MODE3_LENGTH 172
#define MODE1_LENGTH 204
#define LINE_LENGTH (MODE2_LENGTH + MODE3_LENGTH + MODE1_LENGTH) // = 456
void display_run(GB_gameboy_t *gb) void display_run(GB_gameboy_t *gb)
{ {
/* /*
@ -248,42 +265,43 @@ void display_run(GB_gameboy_t *gb)
See http://forums.nesdev.com/viewtopic.php?f=20&t=13727 See http://forums.nesdev.com/viewtopic.php?f=20&t=13727
*/ */
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
/* /*
STAT interrupt is implemented based on this finding: STAT interrupt is implemented based on this finding:
http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531 http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531
*/ */
unsigned char previous_stat_interrupt_line = gb->stat_interrupt_line; unsigned char previous_stat_interrupt_line = gb->stat_interrupt_line;
gb->stat_interrupt_line = false; gb->stat_interrupt_line = false;
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
gb->io_registers[GB_IO_STAT] &= ~3;
if (gb->display_cycles >= LCDC_PERIOD) { if (gb->display_cycles >= LCDC_PERIOD) {
/* VBlank! */ /* VBlank! */
gb->display_cycles -= LCDC_PERIOD; gb->display_cycles -= LCDC_PERIOD;
gb->ly144_bug_oam = false;
gb->ly144_bug_hblank = false;
display_vblank(gb); display_vblank(gb);
} }
if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) { if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) {
/* LCD is disabled, do nothing */ /* LCD is disabled, do nothing */
gb->io_registers[GB_IO_STAT] &= ~3;
/* Some games expect LY to be zero when the LCD is off.
Todo: Verify this behavior.
Keep in mind that this only affects the value being read from the Gameboy, not the actualy display state.
This also explains why the coincidence interrupt triggers when LYC = 0 and LY = 153. */
gb->io_registers[GB_IO_LY] = 0; gb->io_registers[GB_IO_LY] = 0;
return; return;
} }
gb->io_registers[GB_IO_STAT] &= ~3;
/* gb->io_registers[GB_IO_LY] = gb->display_cycles / LINE_LENGTH;
Each line is 456 cycles, approximately:
Mode 2 - 80 cycles
Mode 3 - 172 cycles
Mode 0 - 204 cycles
Todo: Mode lengths are not constants??? /* Todo: This behavior is seen in BGB and it fixes some ROMs with delicate timing, such as Hitman's 8bit.
*/ This should be verified to be correct on a real gameboy. */
if (gb->io_registers[GB_IO_LY] == 153 && gb->display_cycles % LINE_LENGTH > 8) {
gb->io_registers[GB_IO_LY] = gb->display_cycles / 456; gb->io_registers[GB_IO_LY] = 0;
}
gb->io_registers[GB_IO_STAT] &= ~4; gb->io_registers[GB_IO_STAT] &= ~4;
if (gb->io_registers[GB_IO_LY] == gb->io_registers[GB_IO_LYC]) { if (gb->io_registers[GB_IO_LY] == gb->io_registers[GB_IO_LYC]) {
@ -294,13 +312,7 @@ void display_run(GB_gameboy_t *gb)
} }
} }
/* Todo: This behavior is seen in BGB and it fixes some ROMs with delicate timing, such as Hitman's 8bit. if (gb->display_cycles >= LINE_LENGTH * 144) { /* VBlank */
This should be verified to be correct on a real gameboy. */
if (gb->io_registers[GB_IO_LY] == 153 && gb->display_cycles % 456 > 8) {
gb->io_registers[GB_IO_LY] = 0;
}
if (gb->display_cycles >= 456 * 144) { /* VBlank */
gb->io_registers[GB_IO_STAT] |= 1; /* Set mode to 1 */ gb->io_registers[GB_IO_STAT] |= 1; /* Set mode to 1 */
gb->effective_window_enabled = false; gb->effective_window_enabled = false;
gb->effective_window_y = 0xFF; gb->effective_window_y = 0xFF;
@ -314,23 +326,9 @@ void display_run(GB_gameboy_t *gb)
// LY = 144 interrupt bug // LY = 144 interrupt bug
if (gb->io_registers[GB_IO_LY] == 144) { if (gb->io_registers[GB_IO_LY] == 144) {
if (gb->display_cycles % 456 < 80) { // Mode 2 /* User requests an interrupt on Mode 2 */
if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->ly144_bug_oam) { /* User requests an interrupt on Mode 2 */ if (gb->display_cycles % LINE_LENGTH < 92 && gb->io_registers[GB_IO_STAT] & 0x20) { // Mode 2
gb->io_registers[GB_IO_IF] |= 2; gb->stat_interrupt_line = true;
}
gb->ly144_bug_oam = true;
}
if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */
// Nothing to do
}
else { /* Mode 0 */
if (gb->io_registers[GB_IO_STAT] & 8 && !gb->ly144_bug_hblank) { /* User requests an interrupt on Mode 0 */
/*
Todo: Verify if this actually happens.
gb->io_registers[GB_IO_IF] |= 2;
*/
}
gb->ly144_bug_hblank = true;
} }
} }
@ -342,7 +340,7 @@ void display_run(GB_gameboy_t *gb)
gb->effective_window_enabled = true; gb->effective_window_enabled = true;
} }
if (gb->display_cycles % 456 < 80) { /* Mode 2 */ if (gb->display_cycles % LINE_LENGTH < MODE2_LENGTH) { /* Mode 2 */
gb->io_registers[GB_IO_STAT] |= 2; /* Set mode to 2 */ gb->io_registers[GB_IO_STAT] |= 2; /* Set mode to 2 */
if (gb->io_registers[GB_IO_STAT] & 0x20) { /* User requests an interrupt on Mode 2 */ if (gb->io_registers[GB_IO_STAT] & 0x20) { /* User requests an interrupt on Mode 2 */
@ -359,32 +357,34 @@ void display_run(GB_gameboy_t *gb)
goto updateSTAT; goto updateSTAT;
} }
signed short current_lcdc_x = ((gb->display_cycles % 456 - 80) & ~7) - (gb->effective_scx & 0x7); if (gb->display_cycles % LINE_LENGTH < MODE2_LENGTH + MODE3_LENGTH) { /* Mode 3 */
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) { if (last_mode != 3) {
if (gb->previous_lcdc_x >= 160) {
continue;
}
if (gb->previous_lcdc_x < 0) {
continue;
}
gb->screen[gb->io_registers[GB_IO_LY] * 160 + gb->previous_lcdc_x] =
get_pixel(gb, gb->previous_lcdc_x, gb->io_registers[GB_IO_LY]);
}
if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */ }
signed short current_lcdc_x = ((gb->display_cycles % LINE_LENGTH - MODE2_LENGTH) & ~7) - (gb->effective_scx & 0x7);
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) {
if (gb->previous_lcdc_x >= 160) {
continue;
}
if (gb->previous_lcdc_x < 0) {
continue;
}
gb->screen[gb->io_registers[GB_IO_LY] * 160 + gb->previous_lcdc_x] =
get_pixel(gb, gb->previous_lcdc_x, gb->io_registers[GB_IO_LY]);
}
gb->io_registers[GB_IO_STAT] |= 3; /* Set mode to 3 */ gb->io_registers[GB_IO_STAT] |= 3; /* Set mode to 3 */
goto updateSTAT; goto updateSTAT;
} }
/* if (gb->display_cycles % 456 < 80 + 172 + 204) */ { /* Mode 0*/ /* Mode 0*/
if (gb->io_registers[GB_IO_STAT] & 8) { /* User requests an interrupt on Mode 0 */ if (gb->io_registers[GB_IO_STAT] & 8) { /* User requests an interrupt on Mode 0 */
gb->stat_interrupt_line = true; gb->stat_interrupt_line = true;
} }
if (last_mode != 0) {
if (gb->hdma_on_hblank) { if (last_mode != 0) {
gb->hdma_on = true; if (gb->hdma_on_hblank) {
gb->hdma_cycles = 0; gb->hdma_on = true;
} gb->hdma_cycles = 0;
} }
} }

View File

@ -261,8 +261,8 @@ typedef struct GB_gameboy_s {
unsigned char sprite_palletes_data[0x40]; unsigned char sprite_palletes_data[0x40];
uint32_t background_palletes_rgb[0x20]; uint32_t background_palletes_rgb[0x20];
uint32_t sprite_palletes_rgb[0x20]; uint32_t sprite_palletes_rgb[0x20];
bool ly144_bug_oam; GB_PADDING(bool, ly144_bug_oam);
bool ly144_bug_hblank; GB_PADDING(bool, ly144_bug_hblank);
signed short previous_lcdc_x; signed short previous_lcdc_x;
unsigned char padding; unsigned char padding;
bool effective_window_enabled; bool effective_window_enabled;