ref: 4787a909b713b7f655172177fc8ea509cc1b2f17
parent: 71654b54031465d6eef062cacf718975f24fe668
author: allkern <lisandroaalarcon@gmail.com>
date: Thu Jul 6 18:07:08 EDT 2023
Properly implemented input
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@
SOURCES := $(wildcard psx/*.c)
SOURCES += $(wildcard psx/dev/*.c)
+SOURCES += $(wildcard psx/input/*.c)
SOURCES += $(wildcard frontend/*.c)
bin/psxe frontend/main.c:
--- a/build-win32.ps1
+++ b/build-win32.ps1
@@ -14,6 +14,7 @@
-I"`"$($SDL2_DIR)\include\SDL2`"" `
"psx\*.c" `
"psx\dev\*.c" `
+ "psx\input\*.c" `
"frontend\*.c" `
-o "bin\psxe.exe" `
-DREP_VERSION="`"$($VERSION_TAG)`"" `
--- a/build-win64.ps1
+++ b/build-win64.ps1
@@ -14,6 +14,7 @@
-I"`"$($SDL2_DIR)\include\SDL2`"" `
"psx\*.c" `
"psx\dev\*.c" `
+ "psx\input\*.c" `
"frontend\*.c" `
-o "bin\psxe.exe" `
-DREP_VERSION="`"$($VERSION_TAG)`"" `
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -1,4 +1,5 @@
#include "psx/psx.h"
+#include "psx/input/sda.h"
#include "screen.h"
#include "config.h"
@@ -17,17 +18,29 @@
psx_t* psx = psx_create();
psx_init(psx, cfg->bios);
- psx_gpu_t* gpu = psx_get_gpu(psx);
-
psxe_screen_t* screen = psxe_screen_create();
psxe_screen_init(screen, psx);
psxe_screen_set_scale(screen, 2);
psxe_screen_reload(screen);
+ psx_gpu_t* gpu = psx_get_gpu(psx);
+
psx_gpu_set_event_callback(gpu, GPU_EVENT_DMODE, psxe_gpu_dmode_event_cb);
psx_gpu_set_event_callback(gpu, GPU_EVENT_VBLANK, psxe_gpu_vblank_event_cb);
psx_gpu_set_udata(gpu, 0, screen);
+ psxi_sda_t* controller = psxi_sda_create();
+
+ psxi_sda_init(controller, SDA_MODEL_DIGITAL);
+
+ psx_input_t* input = psx_input_create();
+
+ psx_input_init(input);
+
+ psxi_sda_init_input(controller, input);
+
+ psx_pad_init_slot(psx->pad, 0, input);
+
if (cfg->exe) { while (psx->cpu->pc != 0x80030000) {psx_update(psx);
@@ -54,7 +67,9 @@
log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]); log_fatal("pc=%08x hi=%08x lo=%08x ep=%08x", cpu->pc, cpu->hi, cpu->lo, cpu->cop0_r[COP0_EPC]);+ psx_input_destroy(input);
psx_destroy(psx);
+ psxi_sda_destroy(controller);
psxe_screen_destroy(screen);
return 0;
--- a/frontend/screen.c
+++ b/frontend/screen.c
@@ -120,13 +120,13 @@
uint16_t mask = screen_get_button(event.key.keysym.sym);
- psx_pad_button_press(screen->pad, mask);
+ psx_pad_button_press(screen->pad, 0, mask);
} break;
case SDL_KEYUP: {uint16_t mask = screen_get_button(event.key.keysym.sym);
- psx_pad_button_release(screen->pad, mask);
+ psx_pad_button_release(screen->pad, 0, mask);
} break;
}
}
--- a/psx/dev/ic.h
+++ b/psx/dev/ic.h
@@ -32,7 +32,7 @@
IC_TMR0 = 0x010,
IC_TMR1 = 0x020,
IC_TMR2 = 0x040,
- IC_CTRL = 0x080,
+ IC_JOY = 0x080,
IC_SIO = 0x100,
IC_SPU = 0x200,
IC_LP_PIO = 0x400
--- /dev/null
+++ b/psx/dev/input.c
@@ -1,0 +1,41 @@
+#ifndef PAD_H
+#define PAD_H
+
+#include "input.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+psx_input_t* psx_input_create() {+ return (psx_input_t*)malloc(sizeof(psx_input_t));
+}
+
+void psx_input_init(psx_input_t* input) {+ memset(input, 0, sizeof(psx_input_t));
+}
+
+void psx_input_set_write_func(psx_input_t* input, psx_input_write_t write_func) {+ input->write_func = write_func;
+}
+
+void psx_input_set_read_func(psx_input_t* input, psx_input_read_t read_func) {+ input->read_func = read_func;
+}
+
+void psx_input_set_on_button_press_func(psx_input_t* input, psx_input_on_button_press_t on_button_press_func) {+ input->on_button_press_func = on_button_press_func;
+}
+
+void psx_input_set_on_button_release_func(psx_input_t* input, psx_input_on_button_release_t on_button_release_func) {+ input->on_button_release_func = on_button_release_func;
+}
+
+void psx_input_set_on_analog_change_func(psx_input_t* input, psx_input_on_analog_change_t on_analog_change_func) {+ input->on_analog_change_func = on_analog_change_func;
+}
+
+void psx_input_destroy(psx_input_t* input) {+ free(input);
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+++ b/psx/dev/input.h
@@ -1,0 +1,38 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <stdint.h>
+
+struct psx_input_t;
+
+typedef struct psx_input_t psx_input_t;
+
+typedef void (*psx_input_write_t)(void*, uint16_t);
+typedef uint32_t (*psx_input_read_t)(void*);
+typedef void (*psx_input_on_button_press_t)(void*, uint16_t);
+typedef void (*psx_input_on_button_release_t)(void*, uint16_t);
+typedef void (*psx_input_on_analog_change_t)(void*, uint16_t);
+typedef int (*psx_input_query_fifo_t)(void*);
+
+struct psx_input_t {+ void* udata;
+
+ psx_input_write_t write_func;
+ psx_input_read_t read_func;
+ psx_input_on_button_press_t on_button_press_func;
+ psx_input_on_button_release_t on_button_release_func;
+ psx_input_on_analog_change_t on_analog_change_func;
+ psx_input_query_fifo_t query_fifo_func;
+};
+
+psx_input_t* psx_input_create();
+void psx_input_init(psx_input_t*);
+void psx_input_set_write_func(psx_input_t*, psx_input_write_t);
+void psx_input_set_read_func(psx_input_t*, psx_input_read_t);
+void psx_input_set_on_button_press_func(psx_input_t*, psx_input_on_button_press_t);
+void psx_input_set_on_button_release_func(psx_input_t*, psx_input_on_button_release_t);
+void psx_input_set_on_analog_change_func(psx_input_t*, psx_input_on_analog_change_t);
+void psx_input_set_query_fifo_func(psx_input_t*, psx_input_query_fifo_t);
+void psx_input_destroy(psx_input_t*);
+
+#endif
\ No newline at end of file
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -5,6 +5,55 @@
#include "pad.h"
#include "../log.h"
+uint32_t pad_read_rx(psx_pad_t* pad) {+ psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+
+ if (!current_slot)
+ return 0xffffffff;
+
+ if (!(pad->ctrl & CTRL_JOUT)) {+ if (pad->ctrl & CTRL_RXEN) {+ uint32_t data = current_slot->read_func(current_slot);
+
+ pad->ctrl &= ~CTRL_RXEN;
+
+ return data;
+ }
+
+ return 0xffffffff;
+ }
+
+ return current_slot->read_func(current_slot->udata);
+}
+
+void pad_write_tx(psx_pad_t* pad, uint16_t data) {+ psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+
+ if (!current_slot)
+ return;
+
+ if (!(pad->ctrl & CTRL_TXEN))
+ return;
+
+ pad->cycles_until_irq = 512;
+
+ current_slot->write_func(current_slot->udata, data);
+}
+
+uint32_t pad_handle_stat_read(psx_pad_t* pad) {+ return 0x07;
+ psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+
+ if (!current_slot)
+ return 0x5 | pad->stat;
+
+ return 0x5 | (current_slot->query_fifo_func(current_slot->udata) << 1);
+}
+
+void pad_handle_ctrl_write(psx_pad_t* pad, uint32_t value) {+ pad->ctrl = value;
+}
+
psx_pad_t* psx_pad_create() {return (psx_pad_t*)malloc(sizeof(psx_pad_t));
}
@@ -16,23 +65,16 @@
pad->io_base = PSX_PAD_BEGIN;
pad->io_size = PSX_PAD_SIZE;
-
- pad->rx_buf[0] = 0xff;
- pad->rx_buf[1] = 0xff;
- pad->rx_buf[2] = 0x41;
- pad->rx_buf[3] = 0x5a;
- pad->rx_buf[4] = 0xff;
- pad->rx_buf[5] = 0xff;
}
uint32_t psx_pad_read32(psx_pad_t* pad, uint32_t offset) {- // switch (offset) {- // case 0: return 0x00;
- // case 4: return 0x01;
- // case 8: return pad->mode;
- // case 10: return pad->ctrl;
- // case 14: return pad->baud;
- // }
+ switch (offset) {+ case 0: log_fatal("RX read 32"); return pad_read_rx(pad);+ case 4: log_fatal("ST read 32"); return pad_handle_stat_read(pad);+ case 8: log_fatal("MD read 32"); return pad->mode;+ case 10: log_fatal("CT read 32"); return pad->ctrl;+ case 14: log_fatal("BD read 32"); return pad->baud;+ }
log_fatal("Unhandled 32-bit PAD read at offset %08x", offset);@@ -41,11 +83,11 @@
uint16_t psx_pad_read16(psx_pad_t* pad, uint32_t offset) { switch (offset) {- // case 0: return 0x00;
- case 4: return 0x07;
- // case 8: return pad->mode;
- case 10: return pad->ctrl;
- // case 14: return pad->baud;
+ case 0: log_fatal("RX read 16"); return pad_read_rx(pad) & 0xffff;+ case 4: log_fatal("ST read 16 %04x", pad_handle_stat_read(pad) & 0xffff); return pad_handle_stat_read(pad) & 0xffff;+ case 8: log_fatal("MD read 16"); return pad->mode;+ case 10: log_fatal("CT read 16 %04x", pad->ctrl & 0xffff); return pad->ctrl & 0xffff;+ case 14: log_fatal("BD read 16"); return pad->baud;}
log_fatal("Unhandled 16-bit PAD read at offset %08x", offset);@@ -55,11 +97,11 @@
uint8_t psx_pad_read8(psx_pad_t* pad, uint32_t offset) { switch (offset) {- case 0: return pad->rx_buf[(pad->rx_index++) % 6];
- case 4: return 0x03;
- case 8: return pad->mode;
- case 10: return pad->ctrl;
- case 14: return pad->baud;
+ case 0: log_fatal("RX read 8 %02x", pad_read_rx(pad) & 0xff); return pad_read_rx(pad) & 0xff;+ case 4: log_fatal("ST read 8"); return pad_handle_stat_read(pad) & 0xff;+ case 8: log_fatal("MD read 8"); return pad->mode & 0xff;+ case 10: log_fatal("CT read 8"); return pad->ctrl & 0xff;+ case 14: log_fatal("BD read 8"); return pad->baud & 0xff;}
log_fatal("Unhandled 8-bit PAD read at offset %08x", offset);@@ -68,13 +110,12 @@
}
void psx_pad_write32(psx_pad_t* pad, uint32_t offset, uint32_t value) {- // switch (offset) {- // case 0: log_fatal("PAD write %08x", value); break;- // case 4: break;
- // case 8: pad->mode = value & 0xffff; return;
- // case 10: pad->ctrl = value & 0xffff; return;
- // case 14: pad->baud = value & 0xffff; return;
- // }
+ switch (offset) {+ case 0: log_fatal("TX write 32 %08x", value); pad_write_tx(pad, value); return;+ case 8: log_fatal("MD write 32 %08x", value); pad->mode = value & 0xffff; return;+ case 10: log_fatal("CT write 32 %08x", value); pad_handle_ctrl_write(pad, value); return;+ case 14: log_fatal("BD write 32 %08x", value); pad->baud = value & 0xffff; return;+ }
log_fatal("Unhandled 32-bit PAD write at offset %08x (%08x)", offset, value);}
@@ -81,11 +122,10 @@
void psx_pad_write16(psx_pad_t* pad, uint32_t offset, uint16_t value) { switch (offset) {- // case 0: break;
- // case 4: break;
- // case 8: pad->mode = value; return;
- case 10: pad->ctrl = value; return;
- // case 14: pad->baud = value; return;
+ case 0: log_fatal("TX write 16 %04x", value); pad_write_tx(pad, value); return;+ case 8: log_fatal("MD write 16 %04x", value); pad->mode = value; return;+ case 10: log_fatal("CT write 16 %04x", value); pad_handle_ctrl_write(pad, value); return;+ case 14: log_fatal("BD write 16 %04x", value); pad->baud = value; return;}
log_fatal("Unhandled 16-bit PAD write at offset %08x (%04x)", offset, value);@@ -93,22 +133,45 @@
void psx_pad_write8(psx_pad_t* pad, uint32_t offset, uint8_t value) { switch (offset) {- case 0: return; break;
- case 4: break;
- case 8: pad->mode = value; return;
- case 10: pad->ctrl = value; return;
- case 14: pad->baud = value; return;
+ case 0: log_fatal("TX write 8 %02x", value); pad_write_tx(pad, value); return;+ case 8: log_fatal("MD write 8 %02x", value); pad->mode = value; return;+ case 10: log_fatal("CT write 8 %02x", value); pad_handle_ctrl_write(pad, value); return;+ case 14: log_fatal("BD write 8 %02x", value); pad->baud = value; return;}
log_fatal("Unhandled 8-bit PAD write at offset %08x (%02x)", offset, value);}
-void psx_pad_button_press(psx_pad_t* pad, uint16_t data) {- *((uint16_t*)(&pad->rx_buf[4])) &= ~data;
+void psx_pad_button_press(psx_pad_t* pad, int slot, uint16_t data) {+ psx_input_t* selected_slot = pad->slot[slot];
+
+ if (selected_slot)
+ selected_slot->on_button_press_func(selected_slot->udata, data);
}
-void psx_pad_button_release(psx_pad_t* pad, uint16_t data) {- *((uint16_t*)(&pad->rx_buf[4])) |= data;
+void psx_pad_button_release(psx_pad_t* pad, int slot, uint16_t data) {+ psx_input_t* selected_slot = pad->slot[slot];
+
+ if (selected_slot)
+ selected_slot->on_button_release_func(selected_slot->udata, data);
+}
+
+void psx_pad_init_slot(psx_pad_t* pad, int slot, psx_input_t* input) {+ pad->slot[slot] = input;
+}
+
+void psx_pad_update(psx_pad_t* pad, int cyc) {+ if (pad->cycles_until_irq) {+ pad->cycles_until_irq -= cyc;
+
+ if (pad->cycles_until_irq <= 0) {+ psx_ic_irq(pad->ic, IC_JOY);
+
+ log_fatal("PAD IRQ");+
+ pad->cycles_until_irq = 0;
+ }
+ }
}
void psx_pad_destroy(psx_pad_t* pad) {--- a/psx/dev/pad.h
+++ b/psx/dev/pad.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include "ic.h"
+#include "input.h"
#define PSX_PAD_BEGIN 0x1f801040
#define PSX_PAD_SIZE 0x10
@@ -32,6 +33,62 @@
#define PSXI_SW_SDA_SQUARE 0x8000
/*
+ 0 TX Ready Flag 1 (1=Ready/Started)
+ 1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
+ 2 TX Ready Flag 2 (1=Ready/Finished)
+ 3 RX Parity Error (0=No, 1=Error; Wrong Parity, when enabled) (sticky)
+ 4 Unknown (zero) (unlike SIO, this isn't RX FIFO Overrun flag)
+ 5 Unknown (zero) (for SIO this would be RX Bad Stop Bit)
+ 6 Unknown (zero) (for SIO this would be RX Input Level AFTER Stop bit)
+ 7 /ACK Input Level (0=High, 1=Low)
+ 8 Unknown (zero) (for SIO this would be CTS Input Level)
+ 9 Interrupt Request (0=None, 1=IRQ7) (See JOY_CTRL.Bit4,10-12) (sticky)
+ 10 Unknown (always zero)
+ 11-31 Baudrate Timer (21bit timer, decrementing at 33MHz)
+*/
+
+#define STAT_TXR1 0x0001
+#define STAT_RXNE 0x0002
+#define STAT_TXR2 0x0004
+#define STAT_RXPE 0x0008
+#define STAT_UNK4 0x0010
+#define STAT_UNK5 0x0020
+#define STAT_UNK6 0x0040
+#define STAT_ACKL 0x0080
+#define STAT_UNK8 0x0100
+#define STAT_IRQ7 0x0200
+
+/*
+ 0 TX Enable (TXEN) (0=Disable, 1=Enable)
+ 1 /JOYn Output (0=High, 1=Low/Select) (/JOYn as defined in Bit13)
+ 2 RX Enable (RXEN) (0=Normal, when /JOYn=Low, 1=Force Enable Once)
+ 3 Unknown? (read/write-able) (for SIO, this would be TX Output Level)
+ 4 Acknowledge (0=No change, 1=Reset JOY_STAT.Bits 3,9) (W)
+ 5 Unknown? (read/write-able) (for SIO, this would be RTS Output Level)
+ 6 Reset (0=No change, 1=Reset most JOY_registers to zero) (W)
+ 7 Not used (always zero) (unlike SIO, no matter of FACTOR)
+ 8-9 RX Interrupt Mode (0..3 = IRQ when RX FIFO contains 1,2,4,8 bytes)
+ 10 TX Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.0-or-2 ;Ready
+ 11 RX Interrupt Enable (0=Disable, 1=Enable) ;when N bytes in RX FIFO
+ 12 ACK Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.7 ;/ACK=LOW
+ 13 Desired Slot Number (0=/JOY1, 1=/JOY2) (set to LOW when Bit1=1)
+ 14-15 Not used (always zero)
+*/
+
+#define CTRL_TXEN 0x0001
+#define CTRL_JOUT 0x0002
+#define CTRL_RXEN 0x0004
+#define CTRL_UNK3 0x0008
+#define CTRL_ACKN 0x0010
+#define CTRL_UNK5 0x0020
+#define CTRL_NUS7 0x0040
+#define CTRL_RXIM 0x0180
+#define CTRL_TXIE 0x0200
+#define CTRL_RXIE 0x0400
+#define CTRL_ACIE 0x0800
+#define CTRL_SLOT 0x1000
+
+/*
To-do: Design API to interface any type of controller.
Possible names:
@@ -53,11 +110,13 @@
uint32_t io_base, io_size;
psx_ic_t* ic;
+ psx_input_t* slot[2];
- uint8_t rx_buf[6];
- int rx_index;
+ int enable_once;
+ int cycles_until_irq;
+ int cycle_counter;
- uint16_t mode, ctrl, baud;
+ uint16_t mode, ctrl, baud, stat;
} psx_pad_t;
psx_pad_t* psx_pad_create();
@@ -69,7 +128,9 @@
void psx_pad_write16(psx_pad_t*, uint32_t, uint16_t);
void psx_pad_write8(psx_pad_t*, uint32_t, uint8_t);
void psx_pad_destroy(psx_pad_t*);
-void psx_pad_button_press(psx_pad_t*, uint16_t);
-void psx_pad_button_release(psx_pad_t*, uint16_t);
+void psx_pad_button_press(psx_pad_t*, int, uint16_t);
+void psx_pad_button_release(psx_pad_t*, int, uint16_t);
+void psx_pad_init_slot(psx_pad_t*, int, psx_input_t*);
+void psx_pad_update(psx_pad_t*, int);
#endif
\ No newline at end of file
--- /dev/null
+++ b/psx/input/sda.c
@@ -1,0 +1,115 @@
+/*
+ This file is part of the PSXE Emulator Project
+
+ Sony PlayStation Standard Digital/Analog Controller Emulator
+*/
+
+#include "sda.h"
+#include "../log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+psxi_sda_t* psxi_sda_create() {+ return (psxi_sda_t*)malloc(sizeof(psxi_sda_t));
+}
+
+void psxi_sda_init(psxi_sda_t* sda, uint16_t model) {+ memset(sda, 0, sizeof(psxi_sda_t));
+
+ sda->tx_data = 0xff;
+ sda->model = model;
+ sda->state = SDA_STATE_WFC;
+ sda->sw = 0xffff;
+}
+
+uint32_t psxi_sda_read(void* udata) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ return sda->tx_data;
+}
+
+void psxi_sda_write(void* udata, uint16_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ switch (sda->state) {+ case SDA_STATE_WFC: {+ if (data == 0x01) {+ sda->tx_data_ready = 1;
+ sda->tx_data = 0xff;
+ sda->state = SDA_STATE_WFR;
+ }
+ } break;
+
+ case SDA_STATE_WFR: {+ if (data == 'B') {+ sda->tx_data = sda->model;
+ sda->state = SDA_STATE_TX_IDH;
+ }
+ } break;
+
+ case SDA_STATE_TX_IDH: {+ // To-do: Handle MOT
+ sda->tx_data = 0x5a;
+ sda->state = SDA_STATE_TX_SWL;
+ } break;
+
+ case SDA_STATE_TX_SWL: {+ sda->tx_data = sda->sw & 0xff;
+ sda->state = SDA_STATE_TX_SWH;
+ } break;
+
+ case SDA_STATE_TX_SWH: {+ sda->tx_data = sda->sw >> 8;
+
+ switch (sda->model) {+ case 0x41:
+ sda->state = SDA_STATE_WFC;
+ break;
+
+ // To-do: Implement analog mode
+ case 0x73:
+ case 0x53:
+ sda->state = SDA_STATE_WFC;
+ break;
+ }
+ } break;
+ }
+}
+
+void psxi_sda_on_button_press(void* udata, uint16_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ sda->sw &= ~data;
+}
+
+void psxi_sda_on_button_release(void* udata, uint16_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ sda->sw |= data;
+}
+
+// To-do: Implement analog mode
+void psxi_sda_on_analog_change(void* udata, uint16_t data) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+}
+
+int psxi_sda_query_fifo(void* udata) {+ psxi_sda_t* sda = (psxi_sda_t*)udata;
+
+ return sda->tx_data_ready;
+}
+
+void psxi_sda_init_input(psxi_sda_t* sda, psx_input_t* input) {+ input->udata = sda;
+ input->write_func = psxi_sda_write;
+ input->read_func = psxi_sda_read;
+ input->on_button_press_func = psxi_sda_on_button_press;
+ input->on_button_release_func = psxi_sda_on_button_release;
+ input->on_analog_change_func = psxi_sda_on_analog_change;
+ input->query_fifo_func = psxi_sda_query_fifo;
+}
+
+void psxi_sda_destroy(psxi_sda_t* sda) {+ free(sda);
+}
\ No newline at end of file
--- /dev/null
+++ b/psx/input/sda.h
@@ -1,0 +1,61 @@
+/*
+ This file is part of the PSXE Emulator Project
+
+ Sony PlayStation Standard Digital/Analog Controller Emulator
+*/
+
+#ifndef SDA_H
+#define SDA_H
+
+#include "../dev/input.h"
+
+// Controller/Input IDs
+#define SDA_MODEL_DIGITAL 0x41
+#define SDA_MODEL_ANALOG_PAD 0x73
+#define SDA_MODEL_ANALOG_STICK 0x53
+
+#define PSXI_SW_SDA_SELECT 0x0001
+#define PSXI_SW_SDA_L3 0x0002
+#define PSXI_SW_SDA_R3 0x0004
+#define PSXI_SW_SDA_START 0x0008
+#define PSXI_SW_SDA_PAD_UP 0x0010
+#define PSXI_SW_SDA_PAD_RIGHT 0x0020
+#define PSXI_SW_SDA_PAD_DOWN 0x0040
+#define PSXI_SW_SDA_PAD_LEFT 0x0080
+#define PSXI_SW_SDA_L2 0x0100
+#define PSXI_SW_SDA_R2 0x0200
+#define PSXI_SW_SDA_L1 0x0400
+#define PSXI_SW_SDA_R1 0x0800
+#define PSXI_SW_SDA_TRIANGLE 0x1000
+#define PSXI_SW_SDA_CIRCLE 0x2000
+#define PSXI_SW_SDA_CROSS 0x4000
+#define PSXI_SW_SDA_SQUARE 0x8000
+
+enum {+ SDA_STATE_WFC = 0,
+ SDA_STATE_WFR,
+ SDA_STATE_TX_IDH,
+ SDA_STATE_TX_SWL,
+ SDA_STATE_TX_SWH
+};
+
+enum {+ SA_MODE_DIGITAL = 0,
+ SA_MODE_ANALOG
+};
+
+typedef struct {+ uint8_t model;
+ int state;
+ int sa_mode;
+ uint16_t sw;
+ uint8_t tx_data;
+ int tx_data_ready;
+} psxi_sda_t;
+
+psxi_sda_t* psxi_sda_create();
+void psxi_sda_init(psxi_sda_t*, uint16_t);
+void psxi_sda_init_input(psxi_sda_t*, psx_input_t*);
+void psxi_sda_destroy(psxi_sda_t*);
+
+#endif
\ No newline at end of file
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -28,6 +28,7 @@
psx_cpu_cycle(psx->cpu);
psx_cdrom_update(psx->cdrom);
psx_gpu_update(psx->gpu, psx->cpu->last_cycles);
+ psx_pad_update(psx->pad, psx->cpu->last_cycles);
}
void psx_run_frame(psx_t* psx) {--
⑨