Multiplayer SGB APIs/SGB detection
This commit is contained in:
parent
5c581651ce
commit
7735d638c6
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
18
Core/sgb.c
18
Core/sgb.c
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user