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
+60 -44
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)) uint8_t lcd_enabled;
{
gb->counter.lcd_count = 0; /* Check if LCD is already enabled. */
gb->lcd_blank = 1; 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) /* Check if LCD is being switched off. */
{ else if (lcd_enabled && !(val & LCDC_ENABLE))
gb->hram_io[IO_LCDC] |= LCDC_ENABLE; {
return; /* 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
* mode 1. */
if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK)
{
lcd_cycles = LCD_MODE_2_CYCLES -
gb->counter.lcd_count;
}
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM)
{ {
lcd_cycles = LCD_MODE_3_CYCLES - lcd_cycles = LCD_MODE_3_CYCLES -
gb->counter.lcd_count; gb->counter.lcd_count;
} }
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK) else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_TRANSFER)
{ {
lcd_cycles = LCD_MODE_2_CYCLES - lcd_cycles = LCD_MODE_0_CYCLES -
gb->counter.lcd_count; 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)
@@ -3292,15 +3300,15 @@ void __gb_step_cpu(struct gb_s *gb)
* updated. Also, only update lines on frames that are * updated. Also, only update lines on frames that are
* actually drawn when frame skip is enabled. */ * actually drawn when frame skip is enabled. */
if(gb->direct.interlace && if(gb->direct.interlace &&
(!gb->direct.frame_skip || (!gb->direct.frame_skip ||
gb->display.frame_skip_count)) gb->display.frame_skip_count))
{ {
gb->display.interlace_count = gb->display.interlace_count =
!gb->display.interlace_count; !gb->display.interlace_count;
} }
#endif #endif
} }
/* Normal Line */ /* Normal Line */
else if(gb->hram_io[IO_LY] < LCD_HEIGHT) else if(gb->hram_io[IO_LY] < LCD_HEIGHT)
{ {
if(gb->hram_io[IO_LY] == 0) if(gb->hram_io[IO_LY] == 0)
@@ -3321,9 +3329,9 @@ void __gb_step_cpu(struct gb_s *gb)
inst_cycles = LCD_MODE_2_CYCLES - gb->counter.lcd_count; inst_cycles = LCD_MODE_2_CYCLES - gb->counter.lcd_count;
} }
} }
/* OAM access */ /* OAM access */
else 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 &&
gb->counter.lcd_count >= LCD_MODE_2_CYCLES) gb->counter.lcd_count >= LCD_MODE_2_CYCLES)
{ {
gb->hram_io[IO_STAT] = gb->hram_io[IO_STAT] =
(gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_OAM; (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_OAM;
@@ -3335,9 +3343,9 @@ void __gb_step_cpu(struct gb_s *gb)
if (gb->counter.lcd_count < LCD_MODE_3_CYCLES) if (gb->counter.lcd_count < LCD_MODE_3_CYCLES)
inst_cycles = LCD_MODE_3_CYCLES - gb->counter.lcd_count; inst_cycles = LCD_MODE_3_CYCLES - gb->counter.lcd_count;
} }
/* Update LCD */ /* Update LCD */
else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM && else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM &&
gb->counter.lcd_count >= LCD_MODE_3_CYCLES) gb->counter.lcd_count >= LCD_MODE_3_CYCLES)
{ {
gb->hram_io[IO_STAT] = gb->hram_io[IO_STAT] =
(gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_TRANSFER; (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_TRANSFER;
@@ -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.