saturn-examples/common/intback.hpp
Zack Buhman 5ee43d8a29 use new smpc ireg/oreg struct declaration
Previously operator[] overloads were used for ireg/oreg indexes.
2023-06-23 10:07:19 +00:00

107 lines
2.2 KiB
C++

namespace intback {
enum intback_fsm {
PORT_STATUS = 0,
PERIPHERAL_ID,
DATA1,
DATA2,
DATA3,
DATA4,
FSM_NEXT
};
struct intback_state {
uint8_t fsm;
uint8_t controller_ix;
uint8_t port_ix;
uint8_t oreg_ix;
uint8_t port_connected;
uint8_t data_size;
uint8_t peripheral_type;
uint8_t kbd_bits;
};
typedef void (*keyboard_func_ptr)(const enum keysym k, uint8_t kbd_bits);
static intback_state state;
inline void keyboard_fsm(keyboard_func_ptr callback)
{
if ((smpc.reg.SR & SR__PDL) != 0) {
// PDL == 1; 1st peripheral data
state.oreg_ix = 0;
state.controller_ix = 0;
state.port_ix = 0;
state.fsm = PORT_STATUS;
state.port_connected = 0;
state.data_size = 0;
state.peripheral_type = 0;
state.kbd_bits = 0;
}
/*
This intback handling is oversimplified:
- up to 2 controllers may be (directly) connected
- multitaps are not parsed correctly
*/
while (state.oreg_ix < 32) {
reg8 const& oreg = smpc.reg.OREG[state.oreg_ix++].val;
switch (state.fsm) {
case PORT_STATUS:
state.port_connected = (PORT_STATUS__CONNECTORS(oreg) == 1);
if (state.port_connected) {
if (PORT_STATUS__MULTITAP_ID(oreg) != 0xf) {
// this port is not directly connected; abort parse:
goto abort;
}
} else {
state.fsm = FSM_NEXT;
}
break;
case PERIPHERAL_ID:
state.peripheral_type = PERIPHERAL_ID__TYPE(oreg);
state.data_size = PERIPHERAL_ID__DATA_SIZE(oreg);
break;
case DATA1:
break;
case DATA2:
break;
case DATA3:
state.kbd_bits = oreg & 0b1111;
break;
case DATA4:
{
uint32_t keysym = oreg;
enum keysym k = scancode_to_keysym(keysym);
callback(k, state.kbd_bits);
}
break;
default:
break;
}
if ((state.fsm >= PERIPHERAL_ID && state.data_size <= 0) || state.fsm == FSM_NEXT) {
if (state.port_ix == 1)
break;
else {
state.port_ix++;
state.controller_ix++;
state.fsm = PORT_STATUS;
}
} else {
state.fsm++;
state.data_size--;
}
}
if ((smpc.reg.SR & SR__NPE) != 0) {
smpc.reg.IREG[0].val = INTBACK__IREG0__CONTINUE;
} else {
abort:
smpc.reg.IREG[0].val = INTBACK__IREG0__BREAK;
}
}
}