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->sgb_player_count = 1;
/* Todo: Ugly, fixme, see comment in the timer state machine */
gb->div_state = 3;

View File

@ -474,6 +474,8 @@ struct GB_gameboy_internal_s {
bool sgb_ready_for_pulse;
bool sgb_ready_for_write;
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 */
@ -500,7 +502,7 @@ struct GB_gameboy_internal_s {
uint32_t background_palettes_rgb[0x20];
uint32_t sprite_palettes_rgb[0x20];
GB_color_correction_mode_t color_correction_mode;
bool keys[GB_KEY_MAX];
bool keys[4][GB_KEY_MAX];
/* Timing */
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;
switch (key_selection) {
case 3:
/* Nothing is wired, all up */
gb->io_registers[GB_IO_JOYP] |= 0x0F;
if (gb->sgb_player_count > 1) {
gb->io_registers[GB_IO_JOYP] |= 0xF - gb->sgb_current_player;
}
else {
/* Nothing is wired, all up */
gb->io_registers[GB_IO_JOYP] |= 0x0F;
}
break;
case 2:
/* Direction keys */
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. */
if (!(gb->io_registers[GB_IO_JOYP] & 1)) {
@ -34,13 +39,13 @@ void GB_update_joyp(GB_gameboy_t *gb)
case 1:
/* Other keys */
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;
case 0:
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;
@ -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)
{
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;
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
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;
case GB_IO_JOYP:
GB_sgb_write(gb, value);
gb->io_registers[GB_IO_JOYP] &= 0x0F;
gb->io_registers[GB_IO_JOYP] |= value & 0xF0;
GB_update_joyp(gb);
GB_sgb_write(gb, value);
return;
case GB_IO_BIOS:

View File

@ -1,5 +1,9 @@
#include "sgb.h"
enum {
MLT_REQ = 0x11,
};
static void command_ready(GB_gameboy_t *gb)
{
/* SGB header commands are used to send the contents of the header to the SNES CPU.
@ -31,13 +35,21 @@ static void command_ready(GB_gameboy_t *gb)
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)
{
if (!GB_is_sgb(gb)) return;
if (gb->sgb_disable_commands) return;
switch ((value >> 4) & 3 ) {
switch ((value >> 4) & 3) {
case 3:
gb->sgb_ready_for_pulse = true;
break;
@ -73,6 +85,10 @@ void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
gb->sgb_ready_for_write = true;
gb->sgb_command_write_index = 0;
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;
default: