/* Baremetal Risc-V USB <=> Amiga Joystick/Mouse HID converter. * March 2026 - Anders Holck * This software has no license. If you choose to use, please include my name :) */ #include "amiga_hw.h" #include "usb_dwc2.h" #define GPIOA_EXT_PORTA 0x03020050 // GPIOA Bit Mappings (From PINS.md) #define BIT_JOY1_FIRE 28 #define BIT_JOY1_UP 29 #define BIT_JOY1_DOWN 14 #define BIT_JOY1_LEFT 15 #define BIT_JOY1_RIGHT 16 #define BIT_JOY2_FIRE 17 #define BIT_JOY2_UP 18 #define BIT_JOY2_DOWN 19 #define BIT_JOY2_LEFT 20 #define BIT_JOY2_RIGHT 21 #define BIT_MOUSE_H_P 22 #define BIT_MOUSE_V_P 23 #define BIT_MOUSE_H_D 24 #define BIT_MOUSE_V_D 25 #define BIT_MOUSE_BT1 26 #define BIT_MOUSE_BT2 27 static uint8_t last_h_pulse = 0; static uint8_t last_v_pulse = 0; void amiga_hw_poll(amiga_input_t *input) { uint32_t val = read32(GPIOA_EXT_PORTA); // 1. Joystick 1 (Active Low - Amiga pulls to GND) input->joy1 = 0; if (!(val & (1 << BIT_JOY1_UP))) input->joy1 |= (1 << 0); if (!(val & (1 << BIT_JOY1_DOWN))) input->joy1 |= (1 << 1); if (!(val & (1 << BIT_JOY1_LEFT))) input->joy1 |= (1 << 2); if (!(val & (1 << BIT_JOY1_RIGHT))) input->joy1 |= (1 << 3); if (!(val & (1 << BIT_JOY1_FIRE))) input->joy1 |= (1 << 4); // 2. Joystick 2 input->joy2 = 0; if (!(val & (1 << BIT_JOY2_UP))) input->joy2 |= (1 << 0); if (!(val & (1 << BIT_JOY2_DOWN))) input->joy2 |= (1 << 1); if (!(val & (1 << BIT_JOY2_LEFT))) input->joy2 |= (1 << 2); if (!(val & (1 << BIT_JOY2_RIGHT))) input->joy2 |= (1 << 3); if (!(val & (1 << BIT_JOY2_FIRE))) input->joy2 |= (1 << 4); // 3. Mouse Buttons input->buttons = 0; if (!(val & (1 << BIT_MOUSE_BT1))) input->buttons |= (1 << 0); if (!(val & (1 << BIT_MOUSE_BT2))) input->buttons |= (1 << 1); // 4. Mouse Quadrature Decoding (Simplified) // Amiga Mouse uses 2 pulses per axis (Clock/Data or Phase A/B) // Here we treat H-Pulse and V-Pulse as "clocks" and H-Dir/V-Dir as "direction" uint8_t curr_h_pulse = (val >> BIT_MOUSE_H_P) & 1; uint8_t curr_v_pulse = (val >> BIT_MOUSE_V_P) & 1; input->mouse_x = 0; if (curr_h_pulse != last_h_pulse) { uint8_t h_dir = (val >> BIT_MOUSE_H_D) & 1; input->mouse_x = (h_dir == curr_h_pulse) ? 1 : -1; last_h_pulse = curr_h_pulse; } input->mouse_y = 0; if (curr_v_pulse != last_v_pulse) { uint8_t v_dir = (val >> BIT_MOUSE_V_D) & 1; input->mouse_y = (v_dir == curr_v_pulse) ? 1 : -1; last_v_pulse = curr_v_pulse; } }