Correct emulation of FF6C (Turns out it controls object priority)

This commit is contained in:
Lior Halphon 2020-02-15 15:32:06 +02:00
parent f550360f1a
commit 08eb2f3d98
7 changed files with 38 additions and 12 deletions

View File

@ -939,7 +939,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->vram[line_address + 1], gb->vram[line_address + 1],
palette, palette,
object->flags & 0x80, object->flags & 0x80,
gb->cgb_mode? gb->visible_objs[gb->n_visible_objs - 1] : 0, gb->object_priority == GB_OBJECT_PRIORITY_INDEX? gb->visible_objs[gb->n_visible_objs - 1] : 0,
object->flags & 0x20); object->flags & 0x20);
gb->n_visible_objs--; gb->n_visible_objs--;

View File

@ -11,6 +11,13 @@ void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index
void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value); void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value);
void GB_STAT_update(GB_gameboy_t *gb); void GB_STAT_update(GB_gameboy_t *gb);
void GB_lcd_off(GB_gameboy_t *gb); void GB_lcd_off(GB_gameboy_t *gb);
enum {
GB_OBJECT_PRIORITY_UNDEFINED, // For save state compatibility
GB_OBJECT_PRIORITY_X,
GB_OBJECT_PRIORITY_INDEX,
};
#endif #endif
typedef enum { typedef enum {

View File

@ -1008,11 +1008,13 @@ void GB_reset(GB_gameboy_t *gb)
gb->vram_size = 0x2000 * 2; gb->vram_size = 0x2000 * 2;
memset(gb->vram, 0, gb->vram_size); memset(gb->vram, 0, gb->vram_size);
gb->cgb_mode = true; gb->cgb_mode = true;
gb->object_priority = GB_OBJECT_PRIORITY_INDEX;
} }
else { else {
gb->ram_size = 0x2000; gb->ram_size = 0x2000;
gb->vram_size = 0x2000; gb->vram_size = 0x2000;
memset(gb->vram, 0, gb->vram_size); memset(gb->vram, 0, gb->vram_size);
gb->object_priority = GB_OBJECT_PRIORITY_X;
update_dmg_palette(gb); update_dmg_palette(gb);
} }

View File

@ -185,7 +185,7 @@ enum {
// Unfortunately it is not readable or writable after boot has finished, so research of this // Unfortunately it is not readable or writable after boot has finished, so research of this
// register is quite limited. The value written to this register, however, can be controlled // register is quite limited. The value written to this register, however, can be controlled
// in some cases. // in some cases.
GB_IO_DMG_EMULATION = 0x4c, GB_IO_MODE = 0x4c,
/* General CGB features */ /* General CGB features */
GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch
@ -212,9 +212,7 @@ enum {
GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data
GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index
GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data
GB_IO_OBJECT_PRIORITY = 0x6c, // Affects object priority (X based or index based)
// 1 is written for DMG ROMs on a CGB. Does not appear to have an effect.
GB_IO_DMG_EMULATION_INDICATION = 0x6c, // (FEh) Bit 0 (Read/Write)
/* Missing */ /* Missing */
@ -516,6 +514,7 @@ struct GB_gameboy_internal_s {
bool cgb_palettes_blocked; bool cgb_palettes_blocked;
uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases. uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases.
uint32_t cycles_in_stop_mode; uint32_t cycles_in_stop_mode;
uint8_t object_priority;
); );
/* 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 */

View File

@ -295,11 +295,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
return gb->io_registers[GB_IO_TAC] | 0xF8; return gb->io_registers[GB_IO_TAC] | 0xF8;
case GB_IO_STAT: case GB_IO_STAT:
return gb->io_registers[GB_IO_STAT] | 0x80; return gb->io_registers[GB_IO_STAT] | 0x80;
case GB_IO_DMG_EMULATION_INDICATION: case GB_IO_OBJECT_PRIORITY:
if (!gb->cgb_mode) { if (!GB_is_cgb(gb)) {
return 0xFF; return 0xFF;
} }
return gb->io_registers[GB_IO_DMG_EMULATION_INDICATION] | 0xFE; return gb->io_registers[GB_IO_OBJECT_PRIORITY] | 0xFE;
case GB_IO_PCM_12: case GB_IO_PCM_12:
if (!GB_is_cgb(gb)) return 0xFF; if (!GB_is_cgb(gb)) return 0xFF;
@ -656,13 +656,22 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_IO_OBP1: case GB_IO_OBP1:
case GB_IO_WY: case GB_IO_WY:
case GB_IO_SB: case GB_IO_SB:
case GB_IO_DMG_EMULATION_INDICATION:
case GB_IO_UNKNOWN2: case GB_IO_UNKNOWN2:
case GB_IO_UNKNOWN3: case GB_IO_UNKNOWN3:
case GB_IO_UNKNOWN4: case GB_IO_UNKNOWN4:
case GB_IO_UNKNOWN5: case GB_IO_UNKNOWN5:
gb->io_registers[addr & 0xFF] = value; gb->io_registers[addr & 0xFF] = value;
return; return;
case GB_IO_OBJECT_PRIORITY:
if ((!gb->boot_rom_finished || (gb->io_registers[GB_IO_MODE] & 8)) && GB_is_cgb(gb)) {
gb->io_registers[addr & 0xFF] = value;
gb->object_priority = (value & 1) ? GB_OBJECT_PRIORITY_X : GB_OBJECT_PRIORITY_INDEX;
}
else if (gb->cgb_mode) {
gb->io_registers[addr & 0xFF] = value;
}
return;
case GB_IO_LYC: case GB_IO_LYC:
/* TODO: Probably completely wrong in double speed mode */ /* TODO: Probably completely wrong in double speed mode */
@ -768,9 +777,10 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->boot_rom_finished = true; gb->boot_rom_finished = true;
return; return;
case GB_IO_DMG_EMULATION: case GB_IO_MODE:
if (GB_is_cgb(gb) && !gb->boot_rom_finished) { if (GB_is_cgb(gb) && !gb->boot_rom_finished) {
gb->cgb_mode = !(value & 0xC); /* The real "contents" of this register aren't quite known yet. */ gb->cgb_mode = !(value & 0xC); /* The real "contents" of this register aren't quite known yet. */
gb->io_registers[GB_IO_MODE] = value;
} }
return; return;

View File

@ -266,6 +266,10 @@ int GB_load_state(GB_gameboy_t *gb, const char *path)
gb->oam_fifo.read_end &= 0xF; gb->oam_fifo.read_end &= 0xF;
gb->oam_fifo.write_end &= 0xF; gb->oam_fifo.write_end &= 0xF;
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
}
error: error:
fclose(f); fclose(f);
return errno; return errno;
@ -371,6 +375,10 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le
gb->oam_fifo.read_end &= 0xF; gb->oam_fifo.read_end &= 0xF;
gb->oam_fifo.write_end &= 0xF; gb->oam_fifo.write_end &= 0xF;
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
}
return 0; return 0;
} }

View File

@ -55,7 +55,7 @@
00:FF69 IO_BGPD 00:FF69 IO_BGPD
00:FF6A IO_OBPI 00:FF6A IO_OBPI
00:FF6B IO_OBPD 00:FF6B IO_OBPD
00:FF6C IO_DMG_EMULATION_INDICATION 00:FF6C IO_OBJECT_PRIORITY
00:FF70 IO_SVBK 00:FF70 IO_SVBK
00:FF72 IO_UNKNOWN2 00:FF72 IO_UNKNOWN2
00:FF73 IO_UNKNOWN3 00:FF73 IO_UNKNOWN3
@ -64,4 +64,4 @@
00:FF76 IO_PCM_12 00:FF76 IO_PCM_12
00:FF77 IO_PCM_34 00:FF77 IO_PCM_34
00:FF7F IO_UNKNOWN8 00:FF7F IO_UNKNOWN8
00:FFFF IO_IE 00:FFFF IO_IE