mirror of https://github.com/bsnes-emu/bsnes.git
Merge branch 'master' into new_apu
This commit is contained in:
commit
ba0e66a5b7
|
@ -133,7 +133,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x += gb->effective_scx;
|
x += gb->effective_scx;
|
||||||
y += gb->io_registers[GB_IO_SCY];
|
y += gb->effective_scy;
|
||||||
}
|
}
|
||||||
if (gb->io_registers[GB_IO_LCDC] & 0x08 && !in_window) {
|
if (gb->io_registers[GB_IO_LCDC] & 0x08 && !in_window) {
|
||||||
map = 0x1C00;
|
map = 0x1C00;
|
||||||
|
@ -289,7 +289,10 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t atomic_increase = gb->cgb_double_speed? 2 : 4;
|
uint8_t atomic_increase = gb->cgb_double_speed? 2 : 4;
|
||||||
uint8_t stat_delay = gb->cgb_double_speed? 2 : (gb->cgb_mode? 0 : 4);
|
/* According to AntonioND's docs this value should be 0 in CGB mode, but tests I ran on my CGB seem to contradict
|
||||||
|
these findings.
|
||||||
|
Todo: Investigate what causes the difference between our findings */
|
||||||
|
uint8_t stat_delay = gb->cgb_double_speed? 2 : 4; //(gb->cgb_mode? 0 : 4);
|
||||||
/* Todo: This is correct for DMG. Is it correct for the 3 CGB modes (DMG/single/double)?*/
|
/* Todo: This is correct for DMG. Is it correct for the 3 CGB modes (DMG/single/double)?*/
|
||||||
uint8_t scx_delay = ((gb->effective_scx & 7) + atomic_increase - 1) & ~(atomic_increase - 1);
|
uint8_t scx_delay = ((gb->effective_scx & 7) + atomic_increase - 1) & ~(atomic_increase - 1);
|
||||||
/* Todo: These are correct for DMG, DMG-mode CGB, and single speed CGB. Is is correct for double speed CGB? */
|
/* Todo: These are correct for DMG, DMG-mode CGB, and single speed CGB. Is is correct for double speed CGB? */
|
||||||
|
@ -297,13 +300,13 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
uint8_t vram_blocking_rush = gb->is_cgb? 0 : 4;
|
uint8_t vram_blocking_rush = gb->is_cgb? 0 : 4;
|
||||||
|
|
||||||
for (; cycles; cycles -= atomic_increase) {
|
for (; cycles; cycles -= atomic_increase) {
|
||||||
|
gb->delayed_interrupts &= ~3;
|
||||||
gb->display_cycles += atomic_increase;
|
gb->display_cycles += atomic_increase;
|
||||||
/* The very first line is 2 (4 from the CPU's perseptive) clocks shorter when the LCD turns on.
|
/* The very first line is 4 clocks shorter when the LCD turns on. Verified on SGB2, CGB in CGB mode and
|
||||||
Todo: Verify on the 3 CGB modes, especially double speed mode. */
|
CGB in double speed mode. */
|
||||||
if (gb->first_scanline && gb->display_cycles >= LINE_LENGTH - atomic_increase) {
|
if (gb->first_scanline && gb->display_cycles >= LINE_LENGTH - 4) {
|
||||||
gb->first_scanline = false;
|
gb->first_scanline = false;
|
||||||
gb->display_cycles += atomic_increase;
|
gb->display_cycles += 4;
|
||||||
}
|
}
|
||||||
bool should_compare_ly = true;
|
bool should_compare_ly = true;
|
||||||
uint8_t ly_for_comparison = gb->io_registers[GB_IO_LY] = gb->display_cycles / LINE_LENGTH;
|
uint8_t ly_for_comparison = gb->io_registers[GB_IO_LY] = gb->display_cycles / LINE_LENGTH;
|
||||||
|
@ -341,6 +344,10 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
gb->io_registers[GB_IO_STAT] &= ~3;
|
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||||
gb->io_registers[GB_IO_STAT] |= 1;
|
gb->io_registers[GB_IO_STAT] |= 1;
|
||||||
gb->io_registers[GB_IO_IF] |= 1;
|
gb->io_registers[GB_IO_IF] |= 1;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
/* See comment on STAT interrupt at the end of the loop */
|
||||||
|
gb->delayed_interrupts |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Entering VBlank state triggers the OAM interrupt. In CGB, it happens 4 cycles earlier */
|
/* Entering VBlank state triggers the OAM interrupt. In CGB, it happens 4 cycles earlier */
|
||||||
if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->is_cgb) {
|
if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->is_cgb) {
|
||||||
|
@ -556,10 +563,18 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
|
|
||||||
if (gb->stat_interrupt_line && !previous_stat_interrupt_line) {
|
if (gb->stat_interrupt_line && !previous_stat_interrupt_line) {
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
gb->io_registers[GB_IO_IF] |= 2;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
/* On CGB, the STAT interrupt is not aligned to a T-Cycle, therefore it is only effective the next T-Cycle
|
||||||
|
Todo: verify on DMG mode CGB. This was only tested on LYC STAT interrupts, should be tested on others
|
||||||
|
as well. */
|
||||||
|
gb->delayed_interrupts |= 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* The value of LY is glitched in the last cycle of every line in CGB mode CGB in single speed
|
/* The value of LY is glitched in the last cycle of every line in CGB mode CGB in single speed
|
||||||
This is based on GiiBiiAdvance's docs */
|
This is based on AntonioND's docs, however I could not reproduce these findings on my CGB.
|
||||||
|
Todo: Find out why my tests contradict these docs */
|
||||||
if (gb->cgb_mode && !gb->cgb_double_speed &&
|
if (gb->cgb_mode && !gb->cgb_double_speed &&
|
||||||
gb->display_cycles % LINE_LENGTH == LINE_LENGTH - 4) {
|
gb->display_cycles % LINE_LENGTH == LINE_LENGTH - 4) {
|
||||||
uint8_t glitch_pattern[] = {0, 0, 2, 0, 4, 4, 6, 0, 8};
|
uint8_t glitch_pattern[] = {0, 0, 2, 0, 4, 4, 6, 0, 8};
|
||||||
|
@ -570,6 +585,7 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
gb->io_registers[GB_IO_LY] = glitch_pattern[gb->io_registers[GB_IO_LY] & 7] | (gb->io_registers[GB_IO_LY] & 0xF8);
|
gb->io_registers[GB_IO_LY] = glitch_pattern[gb->io_registers[GB_IO_LY] & 7] | (gb->io_registers[GB_IO_LY] & 0xF8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
|
@ -603,13 +619,17 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
|
|
||||||
|
|
||||||
/* Render */
|
/* Render */
|
||||||
/* Todo: it appears that the actual rendering starts 4 cycles after mode 3 starts. Is this correct? */
|
int16_t current_lcdc_x = gb->display_cycles % LINE_LENGTH - MODE2_LENGTH - (gb->effective_scx & 0x7) - 7;
|
||||||
int16_t current_lcdc_x = gb->display_cycles % LINE_LENGTH - MODE2_LENGTH - (gb->effective_scx & 0x7) - 4;
|
|
||||||
|
|
||||||
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) {
|
for (;gb->previous_lcdc_x < current_lcdc_x; gb->previous_lcdc_x++) {
|
||||||
if (gb->previous_lcdc_x >= WIDTH) {
|
if (gb->previous_lcdc_x >= WIDTH) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((gb->previous_lcdc_x + gb->effective_scx) & 7) == 0) {
|
||||||
|
gb->effective_scy = gb->io_registers[GB_IO_SCY];
|
||||||
|
}
|
||||||
|
|
||||||
if (gb->previous_lcdc_x < 0) {
|
if (gb->previous_lcdc_x < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,6 +331,10 @@ struct GB_gameboy_internal_s {
|
||||||
GB_PADDING(uint16_t, serial_cycles);
|
GB_PADDING(uint16_t, serial_cycles);
|
||||||
uint16_t serial_cycles; /* This field changed its meaning in v0.10 */
|
uint16_t serial_cycles; /* This field changed its meaning in v0.10 */
|
||||||
uint16_t serial_length;
|
uint16_t serial_length;
|
||||||
|
uint8_t delayed_interrupts; /* When an interrupt occurs while not aligned to a T-cycle, it must be "delayed" */
|
||||||
|
bool dont_delay_timer_interrupt; /* If the timer glitch causes a TIMA overflow, it causes the timer to overflow
|
||||||
|
with different timing, so the triggered interrupt is not delayed.
|
||||||
|
Todo: needs test ROM. */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* APU */
|
/* APU */
|
||||||
|
@ -383,6 +387,7 @@ struct GB_gameboy_internal_s {
|
||||||
bool oam_write_blocked;
|
bool oam_write_blocked;
|
||||||
bool vram_write_blocked;
|
bool vram_write_blocked;
|
||||||
bool window_disabled_while_active;
|
bool window_disabled_while_active;
|
||||||
|
uint8_t effective_scy; // SCY is latched when starting to draw a tile
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||||
|
|
|
@ -452,8 +452,6 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
|
|
||||||
case GB_IO_LCDC:
|
case GB_IO_LCDC:
|
||||||
if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
||||||
/* It appears that there's a slight delay after enabling the screen? */
|
|
||||||
/* Todo: verify this. */
|
|
||||||
gb->display_cycles = 0;
|
gb->display_cycles = 0;
|
||||||
gb->first_scanline = true;
|
gb->first_scanline = true;
|
||||||
if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) {
|
if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) {
|
||||||
|
|
|
@ -82,10 +82,15 @@ static void GB_ir_run(GB_gameboy_t *gb)
|
||||||
|
|
||||||
static void advance_tima_state_machine(GB_gameboy_t *gb)
|
static void advance_tima_state_machine(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
|
gb->delayed_interrupts &= ~4;
|
||||||
if (gb->tima_reload_state == GB_TIMA_RELOADED) {
|
if (gb->tima_reload_state == GB_TIMA_RELOADED) {
|
||||||
gb->tima_reload_state = GB_TIMA_RUNNING;
|
gb->tima_reload_state = GB_TIMA_RUNNING;
|
||||||
}
|
}
|
||||||
else if (gb->tima_reload_state == GB_TIMA_RELOADING) {
|
else if (gb->tima_reload_state == GB_TIMA_RELOADING) {
|
||||||
|
gb->io_registers[GB_IO_IF] |= 4;
|
||||||
|
if (!gb->dont_delay_timer_interrupt) {
|
||||||
|
gb->delayed_interrupts |= 4; // Timer interrupt is not aligned to a T-cycle and therefore is effective only the next one.
|
||||||
|
}
|
||||||
gb->tima_reload_state = GB_TIMA_RELOADED;
|
gb->tima_reload_state = GB_TIMA_RELOADED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,8 +157,8 @@ static void increase_tima(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
gb->io_registers[GB_IO_TIMA]++;
|
gb->io_registers[GB_IO_TIMA]++;
|
||||||
if (gb->io_registers[GB_IO_TIMA] == 0) {
|
if (gb->io_registers[GB_IO_TIMA] == 0) {
|
||||||
|
gb->dont_delay_timer_interrupt = false;
|
||||||
gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA];
|
gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA];
|
||||||
gb->io_registers[GB_IO_IF] |= 4;
|
|
||||||
gb->tima_reload_state = GB_TIMA_RELOADING;
|
gb->tima_reload_state = GB_TIMA_RELOADING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +201,7 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
|
||||||
/* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
|
/* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
|
||||||
if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) {
|
if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) {
|
||||||
increase_tima(gb);
|
increase_tima(gb);
|
||||||
|
gb->dont_delay_timer_interrupt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1337,9 +1337,9 @@ static GB_opcode_t *opcodes[256] = {
|
||||||
void GB_cpu_run(GB_gameboy_t *gb)
|
void GB_cpu_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
gb->vblank_just_occured = false;
|
gb->vblank_just_occured = false;
|
||||||
bool interrupt = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F;
|
uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F & ~gb->delayed_interrupts;
|
||||||
|
|
||||||
if (interrupt) {
|
if (interrupt_queue) {
|
||||||
gb->halted = false;
|
gb->halted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1354,9 +1354,8 @@ void GB_cpu_run(GB_gameboy_t *gb)
|
||||||
gb->ime_toggle = false;
|
gb->ime_toggle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effecitve_ime && interrupt) {
|
if (effecitve_ime && interrupt_queue) {
|
||||||
uint8_t interrupt_bit = 0;
|
uint8_t interrupt_bit = 0;
|
||||||
uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F;
|
|
||||||
while (!(interrupt_queue & 1)) {
|
while (!(interrupt_queue & 1)) {
|
||||||
interrupt_queue >>= 1;
|
interrupt_queue >>= 1;
|
||||||
interrupt_bit++;
|
interrupt_bit++;
|
||||||
|
|
Loading…
Reference in New Issue