Import latest peanut_gb.h from deltabeard (commit ef26527)

This commit is contained in:
Vincent Mistler
2023-04-23 18:11:53 +02:00
parent da9680c9c7
commit 4fcf31bf53
+54 -38
View File
@@ -176,8 +176,8 @@
/** LCD characteristics **/ /** LCD characteristics **/
/* PPU cycles through modes every 456 cycles. */ /* PPU cycles through modes every 456 cycles. */
#define LCD_LINE_CYCLES 456 #define LCD_LINE_CYCLES 456
/* Mode 0 starts on cycle 0. */ /* Mode 0 starts on cycle 372. */
#define LCD_MODE_0_CYCLES 0 #define LCD_MODE_0_CYCLES 372
/* Mode 2 starts on cycle 204. */ /* Mode 2 starts on cycle 204. */
#define LCD_MODE_2_CYCLES 204 #define LCD_MODE_2_CYCLES 204
/* Mode 3 starts on cycle 284. */ /* Mode 3 starts on cycle 284. */
@@ -745,10 +745,8 @@ uint8_t __gb_read(struct gb_s *gb, const uint16_t addr)
return 0xFF; return 0xFF;
case 0xC: case 0xC:
return gb->wram[addr - WRAM_0_ADDR];
case 0xD: case 0xD:
return gb->wram[addr - WRAM_1_ADDR + WRAM_BANK_SIZE]; return gb->wram[addr - WRAM_0_ADDR];
case 0xE: case 0xE:
return gb->wram[addr - ECHO_ADDR]; return gb->wram[addr - ECHO_ADDR];
@@ -792,7 +790,7 @@ uint8_t __gb_read(struct gb_s *gb, const uint16_t addr)
/* Return address that caused read error. */ /* Return address that caused read error. */
(gb->gb_error)(gb, GB_INVALID_READ, addr); (gb->gb_error)(gb, GB_INVALID_READ, addr);
// PGB_UNREACHABLE(); PGB_UNREACHABLE();
} }
/** /**
@@ -991,35 +989,37 @@ void __gb_write(struct gb_s *gb, const uint_fast16_t addr, const uint8_t val)
/* LCD Registers */ /* LCD Registers */
case 0x40: case 0x40:
if(((gb->hram_io[IO_LCDC] & LCDC_ENABLE) == 0) &&
(val & LCDC_ENABLE))
{ {
gb->counter.lcd_count = 0; uint8_t lcd_enabled;
gb->lcd_blank = 1;
} /* Check if LCD is already enabled. */
lcd_enabled = (gb->hram_io[IO_LCDC] & LCDC_ENABLE);
gb->hram_io[IO_LCDC] = val; gb->hram_io[IO_LCDC] = val;
/* LY fixed to 0 when LCD turned off. */ /* Check if LCD is going to be switched on. */
if((gb->hram_io[IO_LCDC] & LCDC_ENABLE) == 0) if (!lcd_enabled && (val & LCDC_ENABLE))
{ {
/* Do not turn off LCD outside of VBLANK. This may gb->lcd_blank = 1;
* happen due to poor timing in this emulator. */
if((gb->hram_io[IO_STAT] & STAT_MODE) != IO_STAT_MODE_VBLANK)
{
gb->hram_io[IO_LCDC] |= LCDC_ENABLE;
return;
} }
/* Check if LCD is being switched off. */
else if (lcd_enabled && !(val & LCDC_ENABLE))
{
/* Peanut-GB will happily turn off LCD outside
* of VBLANK even though this damages real
* hardware. */
/* Set LCD to Mode 0. */ /* Set LCD to Mode 0. */
gb->hram_io[IO_STAT] = (gb->hram_io[IO_STAT] & ~0x03); gb->hram_io[IO_STAT] =
/* Set to line 0. */ (gb->hram_io[IO_STAT] & ~STAT_MODE) |
IO_STAT_MODE_HBLANK;
/* LY fixed to 0 when LCD turned off. */
gb->hram_io[IO_LY] = 0; gb->hram_io[IO_LY] = 0;
/* Reset LCD timer. */ /* Reset LCD timer. */
gb->counter.lcd_count = 0; gb->counter.lcd_count = 0;
} }
return; return;
}
case 0x41: case 0x41:
gb->hram_io[IO_STAT] = (val & STAT_USER_BITS) | (gb->hram_io[IO_STAT] & STAT_MODE); gb->hram_io[IO_STAT] = (val & STAT_USER_BITS) | (gb->hram_io[IO_STAT] & STAT_MODE);
@@ -2355,7 +2355,7 @@ void __gb_step_cpu(struct gb_s *gb)
/* This may be intentional, but this is required to stop an infinite /* This may be intentional, but this is required to stop an infinite
* loop. */ * loop. */
(gb->gb_error)(gb, GB_HALT_FOREVER, gb->cpu_reg.pc.reg - 1); (gb->gb_error)(gb, GB_HALT_FOREVER, gb->cpu_reg.pc.reg - 1);
// PGB_UNREACHABLE(); PGB_UNREACHABLE();
} }
if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START) if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START)
@@ -2376,22 +2376,31 @@ void __gb_step_cpu(struct gb_s *gb)
halt_cycles = tac_cycles; halt_cycles = tac_cycles;
} }
if((gb->hram_io[IO_LCDC] & LCDC_ENABLE) != 0) if((gb->hram_io[IO_LCDC] & LCDC_ENABLE))
{ {
int lcd_cycles; int lcd_cycles;
if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM) /* If LCD is in HBlank, calculate the number of cycles
{ * until the end of HBlank and the start of mode 2 or
lcd_cycles = LCD_MODE_3_CYCLES - * mode 1. */
gb->counter.lcd_count; if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK)
}
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK)
{ {
lcd_cycles = LCD_MODE_2_CYCLES - lcd_cycles = LCD_MODE_2_CYCLES -
gb->counter.lcd_count; gb->counter.lcd_count;
} }
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM)
{
lcd_cycles = LCD_MODE_3_CYCLES -
gb->counter.lcd_count;
}
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_TRANSFER)
{
lcd_cycles = LCD_MODE_0_CYCLES -
gb->counter.lcd_count;
}
else else
{ {
/* VBlank */
lcd_cycles = lcd_cycles =
LCD_LINE_CYCLES - gb->counter.lcd_count; LCD_LINE_CYCLES - gb->counter.lcd_count;
} }
@@ -3153,9 +3162,9 @@ void __gb_step_cpu(struct gb_s *gb)
break; break;
default: default:
/* Return address where invalid opcode that was read. */ /* Return address where invlid opcode that was read. */
(gb->gb_error)(gb, GB_INVALID_OPCODE, gb->cpu_reg.pc.reg - 1); (gb->gb_error)(gb, GB_INVALID_OPCODE, gb->cpu_reg.pc.reg - 1);
// PGB_UNREACHABLE(); PGB_UNREACHABLE();
} }
do do
@@ -3239,9 +3248,9 @@ void __gb_step_cpu(struct gb_s *gb)
} }
} }
/* TODO Check behaviour of LCD during LCD power off state. */ /* If LCD is off, don't update LCD state or increase the LCD
/* If LCD is off, don't update LCD state. */ * ticks. */
if((gb->hram_io[IO_LCDC] & LCDC_ENABLE) == 0) if(!(gb->hram_io[IO_LCDC] & LCDC_ENABLE))
continue; continue;
/* LCD Timing */ /* LCD Timing */
@@ -3279,7 +3288,6 @@ void __gb_step_cpu(struct gb_s *gb)
gb->hram_io[IO_IF] |= LCDC_INTR; gb->hram_io[IO_IF] |= LCDC_INTR;
#if ENABLE_LCD #if ENABLE_LCD
/* If frame skip is activated, check if we need to draw /* If frame skip is activated, check if we need to draw
* the frame or skip it. */ * the frame or skip it. */
if(gb->direct.frame_skip) if(gb->direct.frame_skip)
@@ -3346,8 +3354,8 @@ void __gb_step_cpu(struct gb_s *gb)
__gb_draw_line(gb); __gb_draw_line(gb);
#endif #endif
/* If halted immediately jump to next LCD mode. */ /* If halted immediately jump to next LCD mode. */
if (gb->counter.lcd_count < LCD_LINE_CYCLES) if (gb->counter.lcd_count < LCD_MODE_0_CYCLES)
inst_cycles = LCD_LINE_CYCLES - gb->counter.lcd_count; inst_cycles = LCD_MODE_0_CYCLES - gb->counter.lcd_count;
} }
} while(gb->gb_halt && (gb->hram_io[IO_IF] & gb->hram_io[IO_IE]) == 0); } while(gb->gb_halt && (gb->hram_io[IO_IF] & gb->hram_io[IO_IE]) == 0);
/* If halted, loop until an interrupt occurs. */ /* If halted, loop until an interrupt occurs. */
@@ -3687,6 +3695,14 @@ enum gb_init_error_e gb_init(struct gb_s *gb,
*/ */
void gb_run_frame(struct gb_s *gb); void gb_run_frame(struct gb_s *gb);
/**
* Internal function used to step the CPU. Used mainly for testing.
* Use gb_run_frame() instead.
*
* \param An initialised emulator context. Must not be NULL.
*/
void __gb_step_cpu(struct gb_s *gb);
/** Function prototypes: Optional Functions **/ /** Function prototypes: Optional Functions **/
/** /**
* Reset the emulator, like turning the Game Boy off and on again. * Reset the emulator, like turning the Game Boy off and on again.