107 lines
2.2 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|