/* 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 #include "usb_dwc2.h" #include "pinmux.h" #include "amiga_hw.h" void delay(int count) { for (volatile int i = 0; i < count; i++); } void usb_init_baremetal() { // 1. Enable USB Clocks uint32_t clk_en = read32(CLK_EN_1); clk_en |= (1 << 13) | (1 << 14); write32(CLK_EN_1, clk_en); // 2. Power on PHY and release reset write32(USB_PHY_CTRL, 0x07); delay(10000); // 3. Global Reset of DWC2 Core write32(GRSTCTL, (1 << 0)); // Soft Reset while (!(read32(GRSTCTL) & (1 << 29))); delay(10000); // 4. Force Device Mode and Basic Config write32(GUSBCFG, (1 << 30) | (1 << 29)); // Force Device, PHY Interface write32(DCFG, 0x0); // Full Speed write32(GINTMSK, (1 << 12) | (1 << 13) | (1 << 4) | (1 << 18)); // Reset, Enum, RXFLVL, IEPInt // 5. Connect write32(DCTL, 0); // Clear Soft Disconnect } int main() { pinmux_init_amiga(); usb_init_baremetal(); amiga_input_t input; uint8_t hid_report[4] = {0}; // 2 bytes buttons, 2 bytes mouse uint32_t report_timer = 0; while (1) { // 1. Poll Amiga Hardware amiga_hw_poll(&input); // 2. Poll USB State Machine dwc2_poll(); // 3. Send HID Report every ~10ms (approximate) if (++report_timer > 100) { report_timer = 0; // Format HID Report (Match hid_report_desc in usb_descriptors.h) // Byte 0: Joy1 (5 bits) + Joy2 (3 bits) // Byte 1: Joy2 (remaining 2 bits) + Padding // Byte 2: Mouse X // Byte 3: Mouse Y hid_report[0] = input.joy1 | ((input.joy2 & 0x07) << 5); hid_report[1] = (input.joy2 >> 3) & 0x03; if (input.buttons & 0x01) hid_report[1] |= (1 << 2); // Mouse B1 if (input.buttons & 0x02) hid_report[1] |= (1 << 3); // Mouse B2 hid_report[2] = (uint8_t)input.mouse_x; hid_report[3] = (uint8_t)input.mouse_y; // Send via Endpoint 1 (Interrupt IN) dwc2_send_packet(1, hid_report, 4); } delay(100); } return 0; }