aboutsummaryrefslogtreecommitdiff
path: root/indev/psxpad
diff options
context:
space:
mode:
authorLameguy64 <lameguy64@gmail.com>2021-10-25 10:51:50 +0800
committerLameguy64 <lameguy64@gmail.com>2021-10-25 10:51:50 +0800
commit538f28cfbbbb8163ab8a96de77d6887123856c81 (patch)
treea3108f05c038d0f43f2e96ae4d2d34ce4da225b4 /indev/psxpad
parent7718b576b7aba725455ce510ee9632067a65f0d7 (diff)
downloadpsn00bsdk-538f28cfbbbb8163ab8a96de77d6887123856c81.tar.gz
Added indev directory
Diffstat (limited to 'indev/psxpad')
-rw-r--r--indev/psxpad/card.s377
-rw-r--r--indev/psxpad/main.c399
-rw-r--r--indev/psxpad/makefile39
-rw-r--r--indev/psxpad/pad.s264
4 files changed, 1079 insertions, 0 deletions
diff --git a/indev/psxpad/card.s b/indev/psxpad/card.s
new file mode 100644
index 0000000..2732194
--- /dev/null
+++ b/indev/psxpad/card.s
@@ -0,0 +1,377 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+_CardCSum:
+
+ # a0 - base csum
+ # a1 - data pointer
+ # a2 - length
+
+ lbu $v0, 0($a1)
+ addi $a2, -1
+ xor $a0, $v0
+ bgtz $a2, _CardCSum
+ addiu $a1, 1
+
+ jr $ra
+ move $v0, $a0
+
+
+.global _CardWrite
+.type _CardWrite, @function
+_CardWrite:
+
+ # a0 - port number
+ # a1 - pointer to 128 byte buffer
+ # a2 - sector number
+
+ # return values:
+ # 0 - ok
+ # 1 - no device
+ # 2 - timeout
+ # 3 - bad checksum
+ # 4 - bad sector
+
+ # note: you must wait at least two vsyncs between each sector write
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $t0, IOBASE
+
+ li $v0, 0x1003 # TX Enable, Joypad port select
+ andi $a0, 1
+ sll $a0, 13
+ or $v0, $a0 # Select port 2 if a0 is 1
+
+ sh $v0, JOY_CTRL($t0) # Set to Joypad control interface
+
+ jal _wait # Delay for analog pads
+ li $v0, 310 # (needs optimization testing)
+
+# May cause issues with third party adapters such as Brook wireless
+#.Lread_empty_fifo_write: # Flush the RX FIFO just in case
+# lbu $v1, JOY_TXRX($t0)
+# lhu $v0, JOY_STAT($t0)
+# nop
+# andi $v0, 0x2
+# bnez $v0, .Lread_empty_fifo_write
+# nop
+
+ lhu $v1, JOY_CTRL($t0)
+ nop
+ or $v1, 0x10
+ sh $v1, JOY_CTRL($t0)
+
+ jal _CardExchng # Send device check byte
+ li $a0, 0x81
+ andi $v1, $v0, 0x100 # No card if exchange timed out
+ bnez $v1, .Lno_device_write
+ addiu $v0, $0 , 1
+
+ jal _wait # 1st exchange needs 27microsec after ACK
+ li $v0, 190 # (e.g. 7 as usual + an extra 20)
+
+ jal _CardExchng # Send write command
+ li $a0, 0x57
+ andi $v1, $v0, 0x100 # No card if exchange timed out
+ bnez $v1, .Lno_device_write
+ addiu $v0, $0 , 1
+
+ jal _CardExchng # Receive card ID bytes
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+ jal _CardExchng
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+
+ jal _CardExchng # Send address bytes
+ srl $a0, $a2, 8
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+ jal _CardExchng
+ andi $a0, $a2, 0xFF
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+
+ srl $t1, $a2, 8 # Checksum address by MSB xor LSB
+ andi $v0, $a2, 0xFF
+ xor $t1, $v0
+
+ move $a2, $0 # Send data and compute checksum
+.Lwrite_loop:
+ lbu $a0, 0($a1)
+ addiu $a1, 1
+ jal _CardExchng
+ xor $t1, $a0
+ addiu $a2, 1
+ blt $a2, 128, .Lwrite_loop
+ nop
+
+ jal _CardExchng # Send checksum byte
+ move $a0, $t1
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+
+ jal _CardExchng # Receive card acknowledge bytes
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+ jal _CardExchng
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lwrite_timeout
+ addiu $v0, $0 , 2
+
+ sb $0 , JOY_TXRX($t0) # Gets end byte
+ nop
+.Lsend_wait_end_write:
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x6
+ bne $v0, 0x6, .Lsend_wait_end_write
+ nop
+ lbu $v0, JOY_TXRX($t0)
+ nop
+
+ beq $v0, 0x4e, .Lwrite_timeout # Bad checksum
+ addiu $v0, $0 , 3
+ beq $v0, 0xff, .Lwrite_timeout # Bad sector
+ addiu $v0, $0 , 4
+
+ move $v0, $0
+
+.Lwrite_timeout:
+.Lno_device_write:
+
+ sh $0 , JOY_CTRL($t0) # Apparently required
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+.global _CardRead
+.type _CardRead, @function
+_CardRead:
+
+ # a0 - port number
+ # a1 - pointer to 128 byte buffer
+ # a2 - sector number
+
+ addiu $sp, -12
+ sw $ra, 0($sp)
+ sw $a1, 4($sp)
+ sw $a2, 8($sp)
+
+ lui $t0, IOBASE
+
+ li $v0, 0x1003 # TX Enable, Joypad port select
+ andi $a0, 1
+ sll $a0, 13
+ or $v0, $a0 # Select port 2 if a0 is 1
+
+ sh $v0, JOY_CTRL($t0) # Set to Joypad control interface
+
+ jal _wait # Delay for analog pads (needs testing)
+ li $v0, 310
+
+# May cause issues with third party adapters such as Brook wireless
+#.Lread_empty_fifo: # Flush the RX FIFO just in case
+# lbu $v1, JOY_TXRX($t0)
+# lhu $v0, JOY_STAT($t0)
+# nop
+# andi $v0, 0x2
+# bnez $v0, .Lread_empty_fifo
+# nop
+
+ lhu $v1, JOY_CTRL($t0)
+ nop
+ or $v1, 0x10
+ sh $v1, JOY_CTRL($t0)
+
+ jal _CardExchng # Send device check byte
+ li $a0, 0x81
+ andi $v1, $v0, 0x100 # No card if exchange timed out
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 1
+
+ jal _wait # 1st exchange needs 27microsec after ACK
+ li $v0, 190 # (e.g. 7 as usual + an extra 20)
+
+ jal _CardExchng # Send read command
+ li $a0, 0x52
+ andi $v1, $v0, 0x100 # No card if exchange timed out
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 2
+
+ jal _CardExchng # Receive card ID bytes
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 3
+ jal _CardExchng
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 4
+
+ jal _CardExchng # Send address
+ srl $a0, $a2, 8
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 5
+ jal _CardExchng
+ andi $a0, $a2, 0xFF
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 6
+
+ sb $0 , JOY_TXRX($t0) # Receive command acknowledge 1
+ nop
+.Lsend_wait:
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x4
+ beqz $v0, .Lsend_wait
+ nop
+ move $v1, $0
+ lui $a0, 0xBFC0
+.Lwait_ack:
+ bgt $v1, 30000, .Lread_timeout
+ addiu $v0, $0, 10
+ lhu $v0, JOY_STAT($t0)
+ lw $0 , 4($a0)
+ lw $0 , 0($a0)
+ andi $v0, 0x202
+ bne $v0, 0x202, .Lwait_ack
+ addiu $v1, 1
+ lhu $v1, JOY_CTRL($t0)
+ lbu $v0, JOY_TXRX($t0)
+ or $v1, 0x10
+ sh $v1, JOY_CTRL($t0)
+
+ jal _CardExchng # Receive command acknowledge 2
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 7
+
+ jal _CardExchng # Receive confirmed address MSB
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 8
+
+ jal _CardExchng # Receive confirmed address LSB
+ move $a0, $0
+ andi $v1, $v0, 0x100
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 9
+
+ move $a2, $0
+.Ltransfer_loop:
+ jal _CardExchng
+ move $a0, $0
+ sb $v0, 0($a1)
+ addiu $a2, 1
+ blt $a2, 128, .Ltransfer_loop
+ addiu $a1, 1
+
+ jal _CardExchng # Gets checksum byte
+ move $a0, $0
+ move $a3, $v0
+
+ sb $0 , JOY_TXRX($t0) # Gets end byte
+ nop
+.Lsend_wait_end:
+ lhu $v1, JOY_STAT($t0)
+ nop
+ andi $v1, 0x6
+ bne $v1, 0x6, .Lsend_wait_end
+ nop
+ lbu $v1, JOY_TXRX($t0)
+ nop
+
+ lw $a2, 8($sp)
+ lw $a1, 4($sp)
+ andi $v1, $a2, 0xff
+ srl $a2, 8
+ xor $a0, $a2, $v1
+ jal _CardCSum
+ li $a2, 128
+
+ bne $v0, $a3, .Lno_device
+ addiu $v0, $0 , -1
+
+ move $v0, $0
+.Lread_timeout:
+.Lno_device:
+
+ sh $0 , JOY_CTRL($t0) # Apparently required
+
+ lw $ra, 0($sp)
+ addiu $sp, 12
+ jr $ra
+ nop
+
+
+.global _CardExchng
+.type _CardExchng, @function
+_CardExchng:
+
+ lui $t0, IOBASE
+
+ sb $a0, JOY_TXRX($t0)
+ nop
+.Lsend_wait_exchg:
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x4
+ beqz $v0, .Lsend_wait_exchg
+ nop
+
+ lui $a0, 0xBFC0
+ move $v1, $0
+.Lwait_ack_exchg:
+ bgt $v1, 500, .Ltimeout
+ lhu $v0, JOY_STAT($t0)
+ lw $0 , 4($a0)
+ lw $0 , 0($a0)
+ andi $v0, 0x202
+ bne $v0, 0x202, .Lwait_ack_exchg
+ addiu $v1, 1
+
+ b .Ldone
+ nop
+
+.Ltimeout:
+
+ lbu $v0, JOY_TXRX($t0)
+ nop
+ b .Lexit_exchg
+ ori $v0, 0x100
+
+.Ldone:
+
+ lhu $v1, JOY_CTRL($t0)
+ lbu $v0, JOY_TXRX($t0)
+ or $v1, 0x10
+ sh $v1, JOY_CTRL($t0)
+
+.Lexit_exchg:
+
+ jr $ra
+ nop
diff --git a/indev/psxpad/main.c b/indev/psxpad/main.c
new file mode 100644
index 0000000..e8a6181
--- /dev/null
+++ b/indev/psxpad/main.c
@@ -0,0 +1,399 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <siofs.h>
+
+#define OT_LEN 8
+
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+#define CENTER_X SCREEN_XRES/2
+#define CENTER_Y SCREEN_YRES/2
+
+
+/* Display and drawing environments */
+DISPENV disp[2];
+DRAWENV draw[2];
+
+char pribuff[2][16384]; /* Primitive packet buffers */
+unsigned int ot[2][OT_LEN]; /* Ordering tables */
+char *nextpri; /* Pointer to next packet buffer offset */
+int db = 0; /* Double buffer index */
+
+
+void init() {
+
+ int i;
+
+ /* Reset GPU (also installs event handler for VSync) */
+ printf("Init GPU... ");
+ ResetGraph( 0 );
+ printf("Done.\n");
+
+
+ printf("Set video mode... ");
+
+ /* Set display and draw environment parameters */
+ SetDefDispEnv( &disp[0], 0, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &draw[0], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES );
+ SetDefDispEnv( &disp[1], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &draw[1], 0, 0, SCREEN_XRES, SCREEN_YRES );
+
+ //disp[0].isinter = 1; /* Enable interlace (required for hires) */
+ //disp[1].isinter = 1;
+
+ /* Set clear color, area clear and dither processing */
+ setRGB0( &draw[0], 63, 0, 127 );
+ draw[0].isbg = 1;
+ draw[0].dtd = 1;
+
+ setRGB0( &draw[1], 63, 0, 127 );
+ draw[1].isbg = 1;
+ draw[1].dtd = 1;
+
+ /* Apply the display and drawing environments */
+ PutDispEnv( &disp[1] );
+ PutDrawEnv( &draw[1] );
+
+ /* Enable video output */
+ SetDispMask( 1 );
+
+ printf("Done.\n");
+
+
+ FntLoad( 960, 0 );
+ FntOpen( 8, 16, 304, 216, 0, 100 );
+
+}
+
+extern void _InitPadDirect(void);
+extern int _PadReadDirect(int port, unsigned char *data, int len);
+extern int _CardRead(int port, unsigned char *data, int lba);
+extern int _CardWrite(int port, unsigned char *data, int lba);
+extern int _PadExchng(int byte);
+extern void _PadSetPort(int port);
+
+extern unsigned char _pad_mot_values[];
+
+unsigned char padbuff[2][34];
+
+
+char *hex_tbl = "0123456789ABCDEF";
+
+void byte2str(unsigned char *in, int bytes, char *out)
+{
+ int i;
+
+ for( i=0; i<bytes; i++ )
+ {
+ *out = hex_tbl[in[i]>>4]; out++;
+ *out = hex_tbl[in[i]&0xF]; out++;
+ }
+
+ *out = 0x0;
+}
+
+unsigned char card_buff[128];
+
+void dump_data(unsigned char *buff)
+{
+ int ix,iy;
+
+ for( iy=0; iy<8; iy++ )
+ {
+ for( ix=0; ix<16; ix++ )
+ {
+ printf( "%02x", *buff );
+ buff++;
+ }
+ printf( "\n" );
+ }
+}
+
+void TurnOnVibrators(void)
+{
+ _PadSetPort(0);
+
+ if( _PadExchng(0x01) & 0x100 )
+ {
+ ExitCriticalSection();
+ return;
+ }
+
+ if( _PadExchng(0x43) & 0x100 )
+ {
+ ExitCriticalSection();
+ return;
+ }
+
+ _PadExchng(0x00);
+ _PadExchng(0x01);
+
+ while( !(_PadExchng(0) & 0x100) );
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+ EnterCriticalSection();
+
+ // Set analog state
+ _PadSetPort(0);
+
+ _PadExchng(0x01);
+ _PadExchng(0x4D);
+ _PadExchng(0x00);
+
+ _PadExchng(0x00);
+ _PadExchng(0x01);
+ _PadExchng(0xFF);
+ _PadExchng(0xFF);
+ _PadExchng(0xFF);
+ _PadExchng(0xFF);
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+ EnterCriticalSection();
+
+ // Exit configuration mode
+ _PadSetPort(0);
+
+ _PadExchng(0x01);
+ _PadExchng(0x43);
+ _PadExchng(0x00);
+ _PadExchng(0x00);
+
+ while( !(_PadExchng(0) & 0x100) );
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+}
+
+void TurnOnAnalog(void)
+{
+ EnterCriticalSection();
+
+ // Enter configuration mode
+ _PadSetPort(0);
+
+ if( _PadExchng(0x01) & 0x100 )
+ {
+ ExitCriticalSection();
+ return;
+ }
+
+ if( _PadExchng(0x43) & 0x100 )
+ {
+ ExitCriticalSection();
+ return;
+ }
+
+ _PadExchng(0x00);
+ _PadExchng(0x01);
+
+ while( !(_PadExchng(0) & 0x100) );
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+ EnterCriticalSection();
+
+ // Set analog state
+ _PadSetPort(0);
+
+ _PadExchng(0x01);
+ _PadExchng(0x44);
+ _PadExchng(0x00);
+ _PadExchng(0x01); // 0 - analog off, 1 - analog on
+ _PadExchng(0x02);
+
+ while( !(_PadExchng(0) & 0x100) );
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+ EnterCriticalSection();
+
+ // Exit configuration mode
+ _PadSetPort(0);
+
+ _PadExchng(0x01);
+ _PadExchng(0x43);
+ _PadExchng(0x00);
+ _PadExchng(0x00);
+
+ while( !(_PadExchng(0) & 0x100) );
+
+ _PadSetPort(2);
+
+ ExitCriticalSection();
+ VSync(0);
+}
+
+int main(int argc, const char* argv[]) {
+
+ DR_TPAGE *tpri;
+
+ int i,j,counter=0,fd;
+ char textbuff[64];
+ char *memcard_image,*p;
+
+ /* Init graphics and stuff before doing anything else */
+ init();
+
+ _InitPadDirect();
+
+
+ /*
+ if( fsInit(115200) >= 0 )
+ {
+ printf("Loading memory card image... ");
+
+ fd = fsOpen("cardimage.bin", FS_READ|FS_BINARY);
+
+ if( fd < 0 )
+ {
+ printf("File not found\n");
+ }
+ else
+ {
+ memcard_image = (char*)malloc(131072);
+
+ fsRead(fd, memcard_image, 131072);
+
+ fsClose(fd);
+
+ printf("Done.\n");
+
+ p = memcard_image;
+ for( j=0; j<1024; j++ )
+ {
+ i = _CardWrite(0, p, j);
+ printf("Writing memory card (%d/1024)... \r", j);
+ if( i )
+ printf("\nError %d at sector %d\n", i, j);
+ p += 128;
+ // Memory cards need at least 2 vsyncs between each write
+ // apparently
+ VSync(2);
+ }
+
+ }
+ }
+ else
+ {
+ fd = -1;
+ memcard_image = NULL;
+ }
+ */
+
+ /*
+ for( j=0; j<1024; j++ )
+ {
+ memset( card_buff, 0xff, 128 );
+ i = _CardRead( 0, card_buff, j );
+
+ printf("Reading memory card (%d/1024)... \r", j);
+
+ if( i != 0 )
+ {
+ printf("\nPotential read error at sector %d\n", j);
+ }
+
+ if( fd >= 0 )
+ fsWrite(fd, (u_char*)card_buff, 128);
+
+ if( i )
+ break;
+ }
+
+ if( fd >= 0 )
+ fsClose(fd);
+
+ printf("\nSuccessfully read entire memory card\n");
+ */
+
+ /*
+ i = _CardRead( 0, card_buff, j );
+ printf("Clearing memory card FAT.\n");
+ memset( card_buff, 0xff, 128 );
+ for(j=0; j<4; j++)
+ {
+ i = _CardWrite( 0, card_buff, 4 );
+ printf("_CardWrite returned %d\n", i);
+ VSync(2);
+ }
+ */
+
+
+ TurnOnAnalog();
+ TurnOnVibrators();
+
+ /* Main loop */
+ printf("Entering loop...\n");
+
+ while(1) {
+
+ /*
+ if((counter>>4)&0x1)
+ {
+ _pad_mot_values[0] = 0xff;
+ }
+ else
+ {
+ _pad_mot_values[0] = 0x0;
+ }
+ */
+
+ i = _PadReadDirect(0, padbuff[0], 34);
+ //_PadReadDirect(1, padbuff[1], 34);
+
+ FntPrint( -1, "HELLO WORLD %d\n", counter );
+
+ byte2str( padbuff[0], i, textbuff );
+ FntPrint( -1, "P1:%s\n", textbuff );
+ //byte2str( padbuff[1], 8, textbuff );
+ //FntPrint( -1, "P2:%s\n", textbuff );
+
+ /* Clear ordering table and set start address of primitive */
+ /* buffer for next frame */
+ ClearOTagR( ot[db], OT_LEN );
+ nextpri = pribuff[db];
+
+
+
+ /* Wait for GPU and VSync */
+ FntFlush(-1);
+ DrawSync( 0 );
+ VSync( 0 );
+
+ /* Since draw.isbg is non-zero this clears the screen */
+ PutDispEnv( &disp[db] );
+ PutDrawEnv( &draw[db] );
+
+ /* Begin drawing the new frame */
+ DrawOTag( ot[db]+(OT_LEN-1) );
+
+ /* Alternate to the next buffer */
+ db = !db;
+
+ /* Increment counter for the snake animation */
+ counter++;
+
+ }
+
+ return 0;
+
+}
diff --git a/indev/psxpad/makefile b/indev/psxpad/makefile
new file mode 100644
index 0000000..ab6a733
--- /dev/null
+++ b/indev/psxpad/makefile
@@ -0,0 +1,39 @@
+include ../../examples/sdk-common.mk
+
+TARGET = libpad.elf
+
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+
+INCLUDE +=
+LIBDIRS +=
+
+LIBS = -lsiofs -lpsxsio -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc
+
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+CPPFLAGS = $(CFLAGS) -fno-exceptions
+AFLAGS = -g -msoft-float
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)
diff --git a/indev/psxpad/pad.s b/indev/psxpad/pad.s
new file mode 100644
index 0000000..0fa66aa
--- /dev/null
+++ b/indev/psxpad/pad.s
@@ -0,0 +1,264 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+.global _InitPadDirect
+.type _InitPadDirect, @function
+_InitPadDirect:
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $t0, IOBASE
+
+ # Interface setup
+ li $v0, 0x40 # Interface reset
+ sh $v0, JOY_CTRL($t0)
+ li $v0, 0x88 # 250kHz clock rate
+ sh $v0, JOY_BAUD($t0)
+ li $v0, 0x0d # 8-bit, no parity, x1 multiplier
+ sh $v0, JOY_MODE($t0)
+ li $v0, 0x1003 # JOY1, TX enabled
+ sh $v0, JOY_CTRL($t0)
+
+ jal _wait
+ li $v0, 1000
+
+ # Empty RX fifo
+.Lempty_fifo:
+ lbu $v1, JOY_TXRX($t0)
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x2
+ bnez $v0, .Lempty_fifo
+ nop
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+.global _PadSetPort
+.type _PadSetPort, @function
+_PadSetPort:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $t0, IOBASE
+
+ beq $a0, 2, .Lstop_comms
+ nop
+
+ li $v0, 0x1003 # TX Enable, Joypad port select
+ andi $a0, 1
+ sll $a0, 13
+ or $v0, $a0 # Select port 2 if a0 is 1
+
+ sh $v0, JOY_CTRL($t0) # Set to Joypad control interface
+
+ jal _wait # Delay for analog pads (needs testing)
+ li $v0, 500
+
+.Lread_empty_fifo_set: # Flush the RX FIFO just in case
+ lbu $v1, JOY_TXRX($t0)
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x2
+ bnez $v0, .Lread_empty_fifo_set
+ nop
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+.Lstop_comms:
+
+ sh $0 , JOY_CTRL($t0)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+.global _PadReadDirect
+.type _PadReadDirect, @function
+_PadReadDirect:
+
+ # a0 - port number
+ # a1 - device data buffer
+ # a2 - data max length
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $t0, IOBASE
+
+ li $v0, 0x1003 # TX Enable, Joypad port select
+ andi $a0, 1
+ sll $a0, 13
+ or $v0, $a0 # Select port 2 if a0 is 1
+
+ sh $v0, JOY_CTRL($t0) # Set to Joypad control interface
+
+ jal _wait # Delay for analog pads (needs testing)
+ li $v0, 310
+
+# May cause issues with third party adapters such as Brook wireless
+#.Lread_empty_fifo: # Flush the RX FIFO just in case
+# lbu $v1, JOY_TXRX($t0)
+# lhu $v0, JOY_STAT($t0)
+# nop
+# andi $v0, 0x2
+# bnez $v0, .Lread_empty_fifo
+# nop
+
+ jal _PadExchng # Send device check byte
+ li $a0, 0x01
+
+ andi $v1, $v0, 0x100 # No pad if exchange timed out
+ bnez $v1, .Lno_device
+ addiu $v0, $0 , 1
+
+ sb $v0, 0($a1)
+ addiu $a1, 1
+
+ jal _wait # 1st exchange needs 27microsec after ACK
+ li $v0, 190 # (e.g. 7 as usual + an extra 20)
+
+ jal _PadExchng # Send command byte
+ li $a0, 0x42
+
+ sb $v0, 0($a1)
+ addiu $a1, 1
+ addiu $a2, -2
+
+ jal _PadExchng # Send 0 for pads, 1 for multitap
+ move $a0, $0 # Read is usually 0x5A
+
+ addi $a3, $0 , 1
+
+ la $t1, _pad_mot_values
+
+.Lread_loop: # Read until buffer full, or no more data
+
+ lbu $a0, 0($t1)
+ nop
+ beqz $a0, .Lskip_mot
+ nop
+
+ jal _PadExchng
+ nop
+
+ b .Ldone_exchg
+ addiu $t1, 1
+
+.Lskip_mot:
+
+ jal _PadExchng # when ACK is no longer triggered
+ move $a0, $0
+
+.Ldone_exchg:
+
+ sb $v0, 0($a1)
+
+ andi $v0, 0x100
+ bnez $v0, .Lread_end
+ addi $a3, 1
+
+ addiu $a2, -1
+ bgtz $a2, .Lread_loop
+ addiu $a1, 1
+
+.Lread_end:
+
+ b .Lexit
+ move $v0, $a3
+
+.Lno_device:
+
+ addiu $v0, $0 , -1
+ sb $v0, 0($a1)
+
+.Lexit:
+
+ sh $0 , JOY_CTRL($t0)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+.global _PadExchng
+.type _PadExchng, @function
+_PadExchng:
+
+ lui $t0, IOBASE
+
+ sb $a0, JOY_TXRX($t0)
+ nop
+.Lsend_wait:
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x4
+ beqz $v0, .Lsend_wait
+ nop
+
+ move $v1, $0
+.Lwait_ack:
+ bgt $v1, 100, .Ltimeout
+ lhu $v0, JOY_STAT($t0)
+ nop
+ andi $v0, 0x202
+ bne $v0, 0x202, .Lwait_ack
+ addiu $v1, 1
+
+ b .Ldone
+ nop
+
+.Ltimeout:
+
+ lbu $v0, JOY_TXRX($t0)
+ nop
+ b .Lexit_exchg
+ ori $v0, 0x100
+
+.Ldone:
+
+ lhu $v1, JOY_CTRL($t0)
+ lbu $v0, JOY_TXRX($t0)
+ or $v1, 0x10
+ sh $v1, JOY_CTRL($t0)
+
+.Lexit_exchg:
+
+ jr $ra
+ nop
+
+
+.global _wait
+.type _wait, @function
+_wait:
+ addiu $v0, -1
+ bgtz $v0, _wait
+ nop
+ jr $ra
+ nop
+
+
+.section .data
+
+.global _pad_mot_values
+.type _pad_mot_values, @object
+_pad_mot_values:
+ .byte 0 # Small motor
+ .byte 0 # Big motor
+ .byte 0
+ .byte 0
+
+