Multiplayer SGB APIs/SGB detection

This commit is contained in:
Lior Halphon 2018-11-12 00:37:06 +02:00
parent 5c581651ce
commit 7735d638c6
6 changed files with 42 additions and 9 deletions

View File

@ -640,6 +640,8 @@ void GB_reset(GB_gameboy_t *gb)
gb->accessed_oam_row = -1; gb->accessed_oam_row = -1;
gb->sgb_player_count = 1;
/* Todo: Ugly, fixme, see comment in the timer state machine */ /* Todo: Ugly, fixme, see comment in the timer state machine */
gb->div_state = 3; gb->div_state = 3;

View File

@ -474,6 +474,8 @@ struct GB_gameboy_internal_s {
bool sgb_ready_for_pulse; bool sgb_ready_for_pulse;
bool sgb_ready_for_write; bool sgb_ready_for_write;
bool sgb_disable_commands; bool sgb_disable_commands;
/* Multiplayer Input */
uint8_t sgb_player_count, sgb_current_player;
); );
/* 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 */
@ -500,7 +502,7 @@ struct GB_gameboy_internal_s {
uint32_t background_palettes_rgb[0x20]; uint32_t background_palettes_rgb[0x20];
uint32_t sprite_palettes_rgb[0x20]; uint32_t sprite_palettes_rgb[0x20];
GB_color_correction_mode_t color_correction_mode; GB_color_correction_mode_t color_correction_mode;
bool keys[GB_KEY_MAX]; bool keys[4][GB_KEY_MAX];
/* Timing */ /* Timing */
uint64_t last_sync; uint64_t last_sync;

View File

@ -13,14 +13,19 @@ void GB_update_joyp(GB_gameboy_t *gb)
gb->io_registers[GB_IO_JOYP] &= 0xF0; gb->io_registers[GB_IO_JOYP] &= 0xF0;
switch (key_selection) { switch (key_selection) {
case 3: case 3:
if (gb->sgb_player_count > 1) {
gb->io_registers[GB_IO_JOYP] |= 0xF - gb->sgb_current_player;
}
else {
/* Nothing is wired, all up */ /* Nothing is wired, all up */
gb->io_registers[GB_IO_JOYP] |= 0x0F; gb->io_registers[GB_IO_JOYP] |= 0x0F;
}
break; break;
case 2: case 2:
/* Direction keys */ /* Direction keys */
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i]) << i; gb->io_registers[GB_IO_JOYP] |= (!gb->keys[gb->sgb_current_player][i]) << i;
} }
/* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */ /* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */
if (!(gb->io_registers[GB_IO_JOYP] & 1)) { if (!(gb->io_registers[GB_IO_JOYP] & 1)) {
@ -34,13 +39,13 @@ void GB_update_joyp(GB_gameboy_t *gb)
case 1: case 1:
/* Other keys */ /* Other keys */
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[i + 4]) << i; gb->io_registers[GB_IO_JOYP] |= (!gb->keys[gb->sgb_current_player][i + 4]) << i;
} }
break; break;
case 0: case 0:
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[i] || gb->keys[i + 4])) << i; gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[gb->sgb_current_player][i] || gb->keys[gb->sgb_current_player][i + 4])) << i;
} }
break; break;
@ -60,5 +65,12 @@ void GB_update_joyp(GB_gameboy_t *gb)
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed) void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
{ {
assert(index >= 0 && index < GB_KEY_MAX); assert(index >= 0 && index < GB_KEY_MAX);
gb->keys[index] = pressed; gb->keys[0][index] = pressed;
}
void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed)
{
assert(index >= 0 && index < GB_KEY_MAX);
assert(player < 4);
gb->keys[player][index] = pressed;
} }

View File

@ -16,6 +16,7 @@ typedef enum {
} GB_key_t; } GB_key_t;
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed); void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed);
void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed);
#ifdef GB_INTERNAL #ifdef GB_INTERNAL
void GB_update_joyp(GB_gameboy_t *gb); void GB_update_joyp(GB_gameboy_t *gb);

View File

@ -730,10 +730,10 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return; return;
case GB_IO_JOYP: case GB_IO_JOYP:
GB_sgb_write(gb, value);
gb->io_registers[GB_IO_JOYP] &= 0x0F; gb->io_registers[GB_IO_JOYP] &= 0x0F;
gb->io_registers[GB_IO_JOYP] |= value & 0xF0; gb->io_registers[GB_IO_JOYP] |= value & 0xF0;
GB_update_joyp(gb); GB_update_joyp(gb);
GB_sgb_write(gb, value);
return; return;
case GB_IO_BIOS: case GB_IO_BIOS:

View File

@ -1,5 +1,9 @@
#include "sgb.h" #include "sgb.h"
enum {
MLT_REQ = 0x11,
};
static void command_ready(GB_gameboy_t *gb) static void command_ready(GB_gameboy_t *gb)
{ {
/* SGB header commands are used to send the contents of the header to the SNES CPU. /* SGB header commands are used to send the contents of the header to the SNES CPU.
@ -31,12 +35,20 @@ static void command_ready(GB_gameboy_t *gb)
gb->sgb_disable_commands = true; gb->sgb_disable_commands = true;
} }
} }
switch (gb->sgb_command[0] >> 3) {
case MLT_REQ:
gb->sgb_player_count = (uint8_t[]){1, 2, 1, 4}[gb->sgb_command[1] & 3];
gb->sgb_current_player = gb->sgb_player_count - 1;
break;
}
} }
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value) void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
{ {
if (!GB_is_sgb(gb)) return; if (!GB_is_sgb(gb)) return;
if (gb->sgb_disable_commands) return; if (gb->sgb_disable_commands) return;
switch ((value >> 4) & 3) { switch ((value >> 4) & 3) {
case 3: case 3:
gb->sgb_ready_for_pulse = true; gb->sgb_ready_for_pulse = true;
@ -73,6 +85,10 @@ void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
gb->sgb_ready_for_write = true; gb->sgb_ready_for_write = true;
gb->sgb_command_write_index = 0; gb->sgb_command_write_index = 0;
memset(gb->sgb_command, 0, sizeof(gb->sgb_command)); memset(gb->sgb_command, 0, sizeof(gb->sgb_command));
if (gb->sgb_player_count > 1 && (value & 0x30) != (gb->io_registers[GB_IO_JOYP] & 0x30)) {
gb->sgb_current_player++;
gb->sgb_current_player &= gb->sgb_player_count - 1;
}
break; break;
default: default: