2016-03-30 20:07:55 +00:00
|
|
|
#include "gb.h"
|
2017-04-17 17:16:17 +00:00
|
|
|
#include <assert.h>
|
2016-03-30 20:07:55 +00:00
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
void GB_update_joyp(GB_gameboy_t *gb)
|
2016-03-30 20:07:55 +00:00
|
|
|
{
|
2019-07-19 17:27:53 +00:00
|
|
|
if (gb->model & GB_MODEL_NO_SFC_BIT) return;
|
2019-07-16 18:42:57 +00:00
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
uint8_t key_selection = 0;
|
|
|
|
uint8_t previous_state = 0;
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
/* Todo: add delay to key selection */
|
|
|
|
previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
|
|
|
key_selection = (gb->io_registers[GB_IO_JOYP] >> 4) & 3;
|
|
|
|
gb->io_registers[GB_IO_JOYP] &= 0xF0;
|
2021-10-09 11:52:28 +00:00
|
|
|
uint8_t current_player = gb->sgb? gb->sgb->current_player : 0;
|
2016-03-30 20:07:55 +00:00
|
|
|
switch (key_selection) {
|
|
|
|
case 3:
|
2018-11-15 23:53:01 +00:00
|
|
|
if (gb->sgb && gb->sgb->player_count > 1) {
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= 0xF - current_player;
|
2018-11-11 22:37:06 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Nothing is wired, all up */
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= 0x0F;
|
|
|
|
}
|
2016-03-30 20:07:55 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
/* Direction keys */
|
2016-06-18 17:29:11 +00:00
|
|
|
for (uint8_t i = 0; i < 4; i++) {
|
2018-11-15 23:53:01 +00:00
|
|
|
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i]) << i;
|
2016-03-30 20:07:55 +00:00
|
|
|
}
|
2016-09-20 23:15:02 +00:00
|
|
|
/* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */
|
2021-12-18 22:28:24 +00:00
|
|
|
if (likely(!gb->illegal_inputs_allowed)) {
|
|
|
|
if (!(gb->io_registers[GB_IO_JOYP] & 1)) {
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= 2;
|
|
|
|
}
|
|
|
|
if (!(gb->io_registers[GB_IO_JOYP] & 4)) {
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= 8;
|
|
|
|
}
|
2016-09-20 23:15:02 +00:00
|
|
|
}
|
2016-03-30 20:07:55 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
/* Other keys */
|
2016-06-18 17:29:11 +00:00
|
|
|
for (uint8_t i = 0; i < 4; i++) {
|
2018-11-15 23:53:01 +00:00
|
|
|
gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i + 4]) << i;
|
2016-03-30 20:07:55 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0:
|
2016-06-18 17:29:11 +00:00
|
|
|
for (uint8_t i = 0; i < 4; i++) {
|
2018-11-15 23:53:01 +00:00
|
|
|
gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[current_player][i] || gb->keys[current_player][i + 4])) << i;
|
2016-03-30 20:07:55 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-10-30 13:03:13 +00:00
|
|
|
__builtin_unreachable();
|
2016-03-30 20:07:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-11-10 23:16:32 +00:00
|
|
|
|
2019-07-16 18:42:57 +00:00
|
|
|
/* Todo: This assumes the keys *always* bounce, which is incorrect when emulating an SGB */
|
2016-03-30 20:07:55 +00:00
|
|
|
if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
2019-07-16 18:42:57 +00:00
|
|
|
/* The joypad interrupt DOES occur on CGB (Tested on CGB-E), unlike what some documents say. */
|
2016-03-30 20:07:55 +00:00
|
|
|
gb->io_registers[GB_IO_IF] |= 0x10;
|
|
|
|
}
|
2018-11-10 23:16:32 +00:00
|
|
|
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= 0xC0;
|
2017-04-17 17:16:17 +00:00
|
|
|
}
|
|
|
|
|
2019-07-16 18:42:57 +00:00
|
|
|
void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value)
|
|
|
|
{
|
|
|
|
uint8_t previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
|
|
|
|
gb->io_registers[GB_IO_JOYP] &= 0xF0;
|
|
|
|
gb->io_registers[GB_IO_JOYP] |= value & 0xF;
|
|
|
|
|
|
|
|
if (previous_state & ~(gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
|
|
|
gb->io_registers[GB_IO_IF] |= 0x10;
|
|
|
|
}
|
2019-09-13 10:13:28 +00:00
|
|
|
gb->io_registers[GB_IO_JOYP] |= 0xC0;
|
2019-07-16 18:42:57 +00:00
|
|
|
}
|
|
|
|
|
2017-04-17 17:16:17 +00:00
|
|
|
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
|
|
|
|
{
|
|
|
|
assert(index >= 0 && index < GB_KEY_MAX);
|
2018-11-11 22:37:06 +00:00
|
|
|
gb->keys[0][index] = pressed;
|
2019-06-07 15:27:25 +00:00
|
|
|
GB_update_joyp(gb);
|
2018-11-11 22:37:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-06-07 15:27:25 +00:00
|
|
|
GB_update_joyp(gb);
|
2017-04-17 17:16:17 +00:00
|
|
|
}
|
2021-12-02 09:23:44 +00:00
|
|
|
|
|
|
|
void GB_set_key_mask(GB_gameboy_t *gb, GB_key_mask_t mask)
|
|
|
|
{
|
|
|
|
memset(gb->keys, 0, sizeof(gb->keys));
|
|
|
|
bool *key = &gb->keys[0][0];
|
|
|
|
while (mask) {
|
|
|
|
if (mask & 1) {
|
|
|
|
*key = true;
|
|
|
|
}
|
|
|
|
mask >>= 1;
|
2021-12-02 09:54:26 +00:00
|
|
|
key++;
|
2021-12-02 09:23:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GB_update_joyp(gb);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GB_set_key_mask_for_player(GB_gameboy_t *gb, GB_key_mask_t mask, unsigned player)
|
|
|
|
{
|
|
|
|
memset(gb->keys[player], 0, sizeof(gb->keys[player]));
|
|
|
|
bool *key = gb->keys[player];
|
|
|
|
while (mask) {
|
|
|
|
if (mask & 1) {
|
|
|
|
*key = true;
|
|
|
|
}
|
|
|
|
mask >>= 1;
|
2021-12-02 09:54:26 +00:00
|
|
|
key++;
|
2021-12-02 09:23:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GB_update_joyp(gb);
|
|
|
|
}
|
2021-12-17 23:25:06 +00:00
|
|
|
|
|
|
|
bool GB_get_joyp_accessed(GB_gameboy_t *gb)
|
|
|
|
{
|
|
|
|
return gb->joyp_accessed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GB_clear_joyp_accessed(GB_gameboy_t *gb)
|
|
|
|
{
|
|
|
|
gb->joyp_accessed = false;
|
|
|
|
}
|
2021-12-18 22:28:24 +00:00
|
|
|
|
|
|
|
void GB_set_allow_illegal_inputs(GB_gameboy_t *gb, bool allow)
|
|
|
|
{
|
|
|
|
gb->illegal_inputs_allowed = allow;
|
|
|
|
}
|