1 #include "gb.h"
2 #include <assert.h>
3 
GB_update_joyp(GB_gameboy_t * gb)4 void GB_update_joyp(GB_gameboy_t *gb)
5 {
6     if (gb->model & GB_MODEL_NO_SFC_BIT) return;
7 
8     uint8_t key_selection = 0;
9     uint8_t previous_state = 0;
10 
11     /* Todo: add delay to key selection */
12     previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
13     key_selection = (gb->io_registers[GB_IO_JOYP] >> 4) & 3;
14     gb->io_registers[GB_IO_JOYP] &= 0xF0;
15     uint8_t current_player = gb->sgb? gb->sgb->current_player : 0;
16     switch (key_selection) {
17         case 3:
18             if (gb->sgb && gb->sgb->player_count > 1) {
19                 gb->io_registers[GB_IO_JOYP] |= 0xF - current_player;
20             }
21             else {
22                 /* Nothing is wired, all up */
23                 gb->io_registers[GB_IO_JOYP] |= 0x0F;
24             }
25             break;
26 
27         case 2:
28             /* Direction keys */
29             for (uint8_t i = 0; i < 4; i++) {
30                 gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i]) << i;
31             }
32             /* Forbid pressing two opposing keys, this breaks a lot of games; even if it's somewhat possible. */
33             if (!(gb->io_registers[GB_IO_JOYP] & 1)) {
34                 gb->io_registers[GB_IO_JOYP] |= 2;
35             }
36             if (!(gb->io_registers[GB_IO_JOYP] & 4)) {
37                 gb->io_registers[GB_IO_JOYP] |= 8;
38             }
39             break;
40 
41         case 1:
42             /* Other keys */
43             for (uint8_t i = 0; i < 4; i++) {
44                 gb->io_registers[GB_IO_JOYP] |= (!gb->keys[current_player][i + 4]) << i;
45             }
46             break;
47 
48         case 0:
49             for (uint8_t i = 0; i < 4; i++) {
50                 gb->io_registers[GB_IO_JOYP] |= (!(gb->keys[current_player][i] || gb->keys[current_player][i + 4])) << i;
51             }
52             break;
53 
54         default:
55             __builtin_unreachable();
56             break;
57     }
58 
59     /* Todo: This assumes the keys *always* bounce, which is incorrect when emulating an SGB */
60     if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) {
61         /* The joypad interrupt DOES occur on CGB (Tested on CGB-E), unlike what some documents say. */
62         gb->io_registers[GB_IO_IF] |= 0x10;
63     }
64 
65     gb->io_registers[GB_IO_JOYP] |= 0xC0;
66 }
67 
GB_icd_set_joyp(GB_gameboy_t * gb,uint8_t value)68 void GB_icd_set_joyp(GB_gameboy_t *gb, uint8_t value)
69 {
70     uint8_t previous_state = gb->io_registers[GB_IO_JOYP] & 0xF;
71     gb->io_registers[GB_IO_JOYP] &= 0xF0;
72     gb->io_registers[GB_IO_JOYP] |= value & 0xF;
73 
74     if (previous_state & ~(gb->io_registers[GB_IO_JOYP] & 0xF)) {
75         gb->io_registers[GB_IO_IF] |= 0x10;
76     }
77     gb->io_registers[GB_IO_JOYP] |= 0xC0;
78 }
79 
GB_set_key_state(GB_gameboy_t * gb,GB_key_t index,bool pressed)80 void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
81 {
82     assert(index >= 0 && index < GB_KEY_MAX);
83     gb->keys[0][index] = pressed;
84     GB_update_joyp(gb);
85 }
86 
GB_set_key_state_for_player(GB_gameboy_t * gb,GB_key_t index,unsigned player,bool pressed)87 void GB_set_key_state_for_player(GB_gameboy_t *gb, GB_key_t index, unsigned player, bool pressed)
88 {
89     assert(index >= 0 && index < GB_KEY_MAX);
90     assert(player < 4);
91     gb->keys[player][index] = pressed;
92     GB_update_joyp(gb);
93 }
94