aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-04-06 10:11:07 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-04-06 10:11:07 +0800
commitf3e040230772f978540a71aea43dfde200992922 (patch)
treebd8ca31b72dd01e24980b073854e263589530f56 /libpsn00b
downloadpsn00bsdk-f3e040230772f978540a71aea43dfde200992922.tar.gz
First commit
Diffstat (limited to 'libpsn00b')
-rw-r--r--libpsn00b/include/ctype.h7
-rw-r--r--libpsn00b/include/gtereg.h81
-rw-r--r--libpsn00b/include/hwregs_a.h97
-rw-r--r--libpsn00b/include/inline_c.h433
-rw-r--r--libpsn00b/include/inline_s.h230
-rw-r--r--libpsn00b/include/lzconfig.h68
-rw-r--r--libpsn00b/include/malloc.h17
-rw-r--r--libpsn00b/include/psxapi.h97
-rw-r--r--libpsn00b/include/psxetc.h15
-rw-r--r--libpsn00b/include/psxgpu.h556
-rw-r--r--libpsn00b/include/psxgte.h72
-rw-r--r--libpsn00b/include/psxkernel.h45
-rw-r--r--libpsn00b/include/psxpad.h108
-rw-r--r--libpsn00b/include/psxspu.h138
-rw-r--r--libpsn00b/include/stdarg.h122
-rw-r--r--libpsn00b/include/stdio.h47
-rw-r--r--libpsn00b/include/stdlib.h57
-rw-r--r--libpsn00b/include/string.h42
-rw-r--r--libpsn00b/include/strings.h18
-rw-r--r--libpsn00b/include/sys/fcntl.h20
-rw-r--r--libpsn00b/include/sys/types.h9
-rw-r--r--libpsn00b/libc/makefile38
-rw-r--r--libpsn00b/libc/malloc.s216
-rw-r--r--libpsn00b/libc/memcmp.s31
-rw-r--r--libpsn00b/libc/memcpy.s28
-rw-r--r--libpsn00b/libc/memmove.s29
-rw-r--r--libpsn00b/libc/memset.s25
-rw-r--r--libpsn00b/libc/printf.c788
-rw-r--r--libpsn00b/libc/rand.s38
-rw-r--r--libpsn00b/libc/readme.txt48
-rw-r--r--libpsn00b/libc/scanf.c427
-rw-r--r--libpsn00b/libc/start.s39
-rw-r--r--libpsn00b/libc/string.c301
-rw-r--r--libpsn00b/lzp/bit.c65
-rw-r--r--libpsn00b/lzp/bit.h26
-rw-r--r--libpsn00b/lzp/compress.c488
-rw-r--r--libpsn00b/lzp/crc.c91
-rw-r--r--libpsn00b/lzp/lzp.c88
-rw-r--r--libpsn00b/lzp/lzp.h223
-rw-r--r--libpsn00b/lzp/lzqlp.h26
-rw-r--r--libpsn00b/lzp/makefile28
-rw-r--r--libpsn00b/lzp/qlp.c64
-rw-r--r--libpsn00b/makefile16
-rw-r--r--libpsn00b/psxapi/fs/_96_init.s10
-rw-r--r--libpsn00b/psxapi/fs/_96_remove.s10
-rw-r--r--libpsn00b/psxapi/fs/chdir.s10
-rw-r--r--libpsn00b/psxapi/fs/erase.s10
-rw-r--r--libpsn00b/psxapi/fs/firstfile.s10
-rw-r--r--libpsn00b/psxapi/fs/nextfile.s10
-rw-r--r--libpsn00b/psxapi/fs/rename.s10
-rw-r--r--libpsn00b/psxapi/makefile34
-rw-r--r--libpsn00b/psxapi/stdio/close.s10
-rw-r--r--libpsn00b/psxapi/stdio/getc.s10
-rw-r--r--libpsn00b/psxapi/stdio/ioctl.s10
-rw-r--r--libpsn00b/psxapi/stdio/open.s10
-rw-r--r--libpsn00b/psxapi/stdio/printf.s10
-rw-r--r--libpsn00b/psxapi/stdio/putc.s10
-rw-r--r--libpsn00b/psxapi/stdio/read.s10
-rw-r--r--libpsn00b/psxapi/stdio/seek.s10
-rw-r--r--libpsn00b/psxapi/stdio/write.s10
-rw-r--r--libpsn00b/psxapi/sys/adddev.s10
-rw-r--r--libpsn00b/psxapi/sys/b_initheap.s10
-rw-r--r--libpsn00b/psxapi/sys/changeclearpad.s10
-rw-r--r--libpsn00b/psxapi/sys/changeclearrcnt.s10
-rw-r--r--libpsn00b/psxapi/sys/deldev.s10
-rw-r--r--libpsn00b/psxapi/sys/disableevent.s10
-rw-r--r--libpsn00b/psxapi/sys/enableevent.s10
-rw-r--r--libpsn00b/psxapi/sys/entercriticalsection.s11
-rw-r--r--libpsn00b/psxapi/sys/exitcriticalsection.s11
-rw-r--r--libpsn00b/psxapi/sys/initcard.s10
-rw-r--r--libpsn00b/psxapi/sys/initpad.s11
-rw-r--r--libpsn00b/psxapi/sys/listdev.s10
-rw-r--r--libpsn00b/psxapi/sys/openevent.s10
-rw-r--r--libpsn00b/psxapi/sys/setcustomexitfromexception.s10
-rw-r--r--libpsn00b/psxapi/sys/setdefaultexitfromexception.s10
-rw-r--r--libpsn00b/psxapi/sys/startpad.s10
-rw-r--r--libpsn00b/psxapi/sys/stoppad.s10
-rw-r--r--libpsn00b/psxapi/sys/sysenqintrp.s10
-rw-r--r--libpsn00b/psxetc/dbugfont.c144
-rw-r--r--libpsn00b/psxetc/dbugfont.timbin0 -> 2112 bytes
-rw-r--r--libpsn00b/psxetc/fntsort.c47
-rw-r--r--libpsn00b/psxetc/font.c37
-rw-r--r--libpsn00b/psxetc/makefile38
-rw-r--r--libpsn00b/psxetc/readme.txt22
-rw-r--r--libpsn00b/psxgpu/addprim.s26
-rw-r--r--libpsn00b/psxgpu/clearotagr.s21
-rw-r--r--libpsn00b/psxgpu/drawotag.s38
-rw-r--r--libpsn00b/psxgpu/drawsync.s26
-rw-r--r--libpsn00b/psxgpu/gettimimage.c39
-rw-r--r--libpsn00b/psxgpu/getvideomode.s14
-rw-r--r--libpsn00b/psxgpu/loadimage.s70
-rw-r--r--libpsn00b/psxgpu/makefile38
-rw-r--r--libpsn00b/psxgpu/putdispenv.s174
-rw-r--r--libpsn00b/psxgpu/putdispenvraw.s71
-rw-r--r--libpsn00b/psxgpu/putdrawenv.s142
-rw-r--r--libpsn00b/psxgpu/readgpustat.s14
-rw-r--r--libpsn00b/psxgpu/readme.txt50
-rw-r--r--libpsn00b/psxgpu/resetgraph.s223
-rw-r--r--libpsn00b/psxgpu/setdefdispenv.c21
-rw-r--r--libpsn00b/psxgpu/setdefdrawenv.c26
-rw-r--r--libpsn00b/psxgpu/setdispmask.s19
-rw-r--r--libpsn00b/psxgpu/setvideomode.s50
-rw-r--r--libpsn00b/psxgpu/vsynccallback.s25
-rw-r--r--libpsn00b/psxgte/applymatrixlv.s40
-rw-r--r--libpsn00b/psxgte/compmatrixlv.s100
-rw-r--r--libpsn00b/psxgte/hirotmatrix.c35
-rw-r--r--libpsn00b/psxgte/hisin.c33
-rw-r--r--libpsn00b/psxgte/initgeom.s45
-rw-r--r--libpsn00b/psxgte/isin.c34
-rw-r--r--libpsn00b/psxgte/makefile38
-rw-r--r--libpsn00b/psxgte/matrix.c45
-rw-r--r--libpsn00b/psxgte/mulmatrix.s74
-rw-r--r--libpsn00b/psxgte/mulmatrix0.s74
-rw-r--r--libpsn00b/psxgte/pushpopmatrix.s68
-rw-r--r--libpsn00b/psxgte/readme.txt39
-rw-r--r--libpsn00b/psxgte/scalematrix.s68
-rw-r--r--libpsn00b/psxgte/square0.s27
-rw-r--r--libpsn00b/psxgte/squareroot.s121
-rw-r--r--libpsn00b/psxgte/vectornormals.s110
-rw-r--r--libpsn00b/psxspu/makefile34
-rw-r--r--libpsn00b/psxspu/readme.txt36
-rw-r--r--libpsn00b/psxspu/spuinit.s130
-rw-r--r--libpsn00b/psxspu/spukeyon.s16
-rw-r--r--libpsn00b/psxspu/spureverbon.s16
-rw-r--r--libpsn00b/psxspu/spusetkey.s26
-rw-r--r--libpsn00b/psxspu/spusetreverb.s24
-rw-r--r--libpsn00b/psxspu/spusetreverbaddr.s25
-rw-r--r--libpsn00b/psxspu/spusetvoiceraw.s60
-rw-r--r--libpsn00b/psxspu/transfer.s107
-rw-r--r--libpsn00b/readme.txt101
130 files changed, 8680 insertions, 0 deletions
diff --git a/libpsn00b/include/ctype.h b/libpsn00b/include/ctype.h
new file mode 100644
index 0000000..b79498a
--- /dev/null
+++ b/libpsn00b/include/ctype.h
@@ -0,0 +1,7 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+extern int tolower(int chr);
+extern int toupper(int chr);
+
+#endif \ No newline at end of file
diff --git a/libpsn00b/include/gtereg.h b/libpsn00b/include/gtereg.h
new file mode 100644
index 0000000..0d051fc
--- /dev/null
+++ b/libpsn00b/include/gtereg.h
@@ -0,0 +1,81 @@
+# GTE register definitions for GNU assembler (as).
+#
+# Part of the PSn00bSDK Project by Lameguy64.
+# 2019 Meido-Tek Productions
+
+#
+# GTE data registers (use mfc2, mtc2, lwc2, swc2)
+#
+.set C2_VXY0, $0
+.set C2_VZ0, $1
+.set C2_VXY1, $2
+.set C2_VZ1, $3
+.set C2_VXY2, $4
+.set C2_VZ2, $5
+.set C2_RGB, $6
+.set C2_OTZ, $7
+
+.set C2_IR0, $8
+.set C2_IR1, $9
+.set C2_IR2, $10
+.set C2_IR3, $11
+.set C2_SXY0, $12
+.set C2_SXY1, $13
+.set C2_SXY2, $14
+.set C2_SXYP, $15
+
+.set C2_SZ0, $16
+.set C2_SZ1, $17
+.set C2_SZ2, $18
+.set C2_SZ3, $19
+.set C2_RGB0, $20
+.set C2_RGB1, $21
+.set C2_RGB2, $22
+
+.set C2_MAC0, $24
+.set C2_MAC1, $25
+.set C2_MAC2, $26
+.set C2_MAC3, $27
+.set C2_IRGB, $28
+.set C2_ORGB, $29
+.set C2_LZCS, $30
+.set C2_LZCR, $31
+
+#
+# GTE control registers (use cfc2/ctc2)
+#
+.set C2_R11R12, $0
+.set C2_R13R21, $1
+.set C2_R22R23, $2
+.set C2_R31R32, $3
+.set C2_R33, $4
+.set C2_TRX, $5
+.set C2_TRY, $6
+.set C2_TRZ, $7
+
+.set C2_L11L12, $8
+.set C2_L13L21, $9
+.set C2_L22L23, $10
+.set C2_L31L32, $11
+.set C2_L33, $12
+.set C2_RBK, $13
+.set C2_GBK, $14
+.set C2_BBK, $15
+
+.set C2_LR1LR2, $16
+.set C2_LR3LG1, $17
+.set C2_LG2LG3, $18
+.set C2_LB1LB2, $19
+.set C2_LB3, $20
+.set C2_RFC, $21
+.set C2_GFC, $22
+.set C2_BFC, $23
+
+.set C2_OFX, $24
+.set C2_OFY, $25
+.set C2_H, $26
+.set C2_DQA, $27
+.set C2_DQB, $28
+.set C2_ZSF3, $29
+.set C2_ZSF4, $30
+.set C2_FLAG, $31
diff --git a/libpsn00b/include/hwregs_a.h b/libpsn00b/include/hwregs_a.h
new file mode 100644
index 0000000..a71a657
--- /dev/null
+++ b/libpsn00b/include/hwregs_a.h
@@ -0,0 +1,97 @@
+# Hardware register definitions for GNU assembler (as)
+#
+# Part of the PSn00bSDK Project by Lameguy64
+# 2019 Meido-Tek Productions
+
+
+.set IOBASE, 0x1f80 # IO segment base
+
+# GPU
+.set GP0, 0x1810 # Also GPUREAD
+.set GP1, 0x1814 # Also GPUSTAT
+
+# CD
+.set CD_STAT, 0x1800
+.set CD_CMD, 0x1801 # Also response FIFO
+.set CD_DATA, 0x1802 # Also parameters
+.set CD_IRQ, 0x1803
+
+.set CD_REG0, 0x1800
+.set CD_REG1, 0x1801
+.set CD_REG2, 0x1802
+.set CD_REG3, 0x1803
+
+.set COM_DELAY, 0x1020
+
+# SPU (must be used with 16-bit load/store instructions)
+.set SPU_VOICE_BASE, 0x1c00
+
+.set SPU_MASTER_VOL, 0x1d80
+.set SPU_REVERB_VOL, 0x1d84
+.set SPU_KEY_ON, 0x1d88
+.set SPU_KEY_OFF, 0x1d8c
+.set SPU_FM_MODE, 0x1d90
+.set SPU_NOISE_MODE, 0x1d94
+.set SPU_REVERB_ON, 0x1d98
+.set SPU_CHAN_STATUS, 0x1d9c
+
+.set SPU_REVERB_ADDR, 0x1da2
+.set SPU_IRQ_ADDR, 0x1da4
+.set SPU_ADDR, 0x1da6
+.set SPU_DATA, 0x1da8
+
+.set SPUCNT, 0x1daa
+.set SPUDTCNT, 0x1dac
+.set SPUSTAT, 0x1dae
+
+.set SPU_CD_VOL, 0x1db0
+.set SPU_EXT_VOL, 0x1db4
+.set SPU_CURRENT_VOL, 0x1db8
+
+.set SPU_VOICE_VOL_L, 0x00
+.set SPU_VOICE_VOL_R, 0x02
+.set SPU_VOICE_FREQ, 0x04
+.set SPU_VOICE_ADDR, 0x06
+.set SPU_VOICE_ADSR_L, 0x08
+.set SPU_VOICE_ADSR_H, 0x0a
+.set SPU_VOICE_LOOP, 0x0e
+
+# Pads
+.set JOY_TXRX, 0x1040
+.set JOY_STAT, 0x1044
+.set JOY_MODE, 0x1048
+.set JOY_CTRL, 0x104A
+.set JOY_BAUD, 0x104E
+
+# IRQ
+.set ISTAT, 0x1070
+.set IMASK, 0x1074
+
+# DMA
+.set DPCR, 0x10f0
+.set DICR, 0x10f4
+
+.set D2_MADR, 0x10a0
+.set D2_BCR, 0x10a4
+.set D2_CHCR, 0x10a8
+
+.set D4_MADR, 0x10c0
+.set D4_BCR, 0x10c4
+.set D4_CHCR, 0x10c8
+
+.set D6_MADR, 0x10e0
+.set D6_BCR, 0x10e4
+.set D6_CHCR, 0x10e8
+
+# Timers
+.set T0_CNT, 0x1100
+.set T0_MODE, 0x1104
+.set T0_TGT, 0x1108
+
+.set T1_CNT, 0x1110
+.set T1_MODE, 0x1114
+.set T1_TGT, 0x1118
+
+.set T2_CNT, 0x1120
+.set T2_MODE, 0x1124
+.set T2_TGT, 0x1128
diff --git a/libpsn00b/include/inline_c.h b/libpsn00b/include/inline_c.h
new file mode 100644
index 0000000..4341624
--- /dev/null
+++ b/libpsn00b/include/inline_c.h
@@ -0,0 +1,433 @@
+/* Inline GTE macros for the GNU C compiler.
+ *
+ * Part of the PSn00bSDK Project by Lameguy64.
+ * 2019 Meido-Tek Production
+ *
+ * All GTE commands can be used without having to pass your object file
+ * through some stupid tool such as DMPSX. Perhaps it was Sony's attempt
+ * to prevent people from quickly discovering the GTE commands from the
+ * official SDK easily? Though people could just extract the cop2 opcodes
+ * of an object file after it has been passed through DMPSX.
+ *
+ * Todo: A couple of GTE operation macros are still missing such as
+ * gte_rtv*() though they appear to be just variants of gte_mvmva more or
+ * less (gte_rtv0() is actually gte_mvmva(1, 0, 0, 3, 0) for example).
+ *
+ */
+
+#ifndef _INLINE_C_H
+#define _INLINE_C_H
+
+/*
+ * GTE load macros
+ */
+
+/* Load a SVECTOR (passed as a pointer) to GTE V0
+ */
+#define gte_ldv0( r0 ) __asm__ volatile ( \
+ "lwc2 $0 , 0( %0 );" \
+ "lwc2 $1 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/* Load a SVECTOR (passed as a pointer) to GTE V1
+ */
+#define gte_ldv1( r0 ) __asm__ volatile ( \
+ "lwc2 $2 , 0( %0 );" \
+ "lwc2 $3 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/* Load a SVECTOR (passed as a pointer) to GTE V2
+ */
+#define gte_ldv2( r0 ) __asm__ volatile ( \
+ "lwc2 $4 , 0( %0 );" \
+ "lwc2 $5 , 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "$t0" )
+
+/* Load three SVECTORs (passed as a pointer) to the GTE at once
+ */
+#define gte_ldv3( r0, r1, r2 ) __asm__ volatile ( \
+ "lwc2 $0 , 0( %0 );" \
+ "lwc2 $1 , 4( %0 );" \
+ "lwc2 $2 , 0( %1 );" \
+ "lwc2 $3 , 4( %1 );" \
+ "lwc2 $4 , 0( %2 );" \
+ "lwc2 $5 , 4( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) )
+
+#define gte_ldrgb( r0 ) __asm__ volatile ( \
+ "lwc2 $6 , 0( %0 );" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_ldopv2( r0 ) __asm__ volatile ( \
+ "lwc2 $11, 8( %0 );" \
+ "lwc2 $9 , 0( %0 );" \
+ "lwc2 $10, 4( %0 );" \
+ : \
+ : "r"( r0 ) )
+
+/* Sets the GTE offset
+ */
+#define gte_SetGeomOffset( r0, r1 ) __asm__ volatile ( \
+ "sll $t0, %0, 16;" \
+ "sll $t1, %1, 16;" \
+ "ctc2 $t0, $24;" \
+ "ctc2 $t1, $25;" \
+ : \
+ : "r"( r0 ), "r"( r1 ) \
+ : "$t0", "$t1" )
+
+#define gte_SetGeomScreen( r0 ) __asm__ volatile ( \
+ "ctc2 %0, $26;" \
+ : \
+ : "r"( r0 ) )
+
+#define gte_SetTransMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 20( %0 );" \
+ "lw $t1, 24( %0 );" \
+ "ctc2 $t0, $5;" \
+ "lw $t2, 28( %0 );" \
+ "ctc2 $t1, $6;" \
+ "ctc2 $t2, $7;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetRotMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $0;" \
+ "ctc2 $t1, $1;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $2;" \
+ "ctc2 $t1, $3;" \
+ "ctc2 $t2, $4;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetLightMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $8;" \
+ "ctc2 $t1, $9;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $10;" \
+ "ctc2 $t1, $11;" \
+ "ctc2 $t2, $12;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetColorMatrix( r0 ) __asm__ volatile ( \
+ "lw $t0, 0( %0 );" \
+ "lw $t1, 4( %0 );" \
+ "ctc2 $t0, $16;" \
+ "ctc2 $t1, $17;" \
+ "lw $t0, 8( %0 );" \
+ "lw $t1, 12( %0 );" \
+ "lhu $t2, 16( %0 );" \
+ "ctc2 $t0, $18;" \
+ "ctc2 $t1, $19;" \
+ "ctc2 $t2, $20;" \
+ : \
+ : "r"( r0 ) \
+ : "$t2" )
+
+#define gte_SetBackColor( r0, r1, r2 ) __asm__ volatile ( \
+ "sll $t0, %0, 4;" \
+ "sll $t1, %1, 4;" \
+ "sll $t2, %2, 4;" \
+ "ctc2 $t0, $13;" \
+ "ctc2 $t1, $14;" \
+ "ctc2 $t2, $15;" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) \
+ : "$t0", "$t1", "$t2" )
+
+/*
+ * GTE store macros
+ */
+
+#define gte_otz( r0 ) __asm__ volatile ( \
+ "swc2 $7, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stflg( r0 ) __asm__ volatile ( \
+ "cfc2 $t0, $31;" \
+ "nop;" \
+ "sw $t0, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy( r0 ) __asm__ volatile ( \
+ "swc2 $14, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy0( r0 ) __asm__ volatile ( \
+ "swc2 $12, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy1( r0 ) __asm__ volatile ( \
+ "swc2 $13, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy2( r0 ) __asm__ volatile ( \
+ "swc2 $14, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stsxy3( r0, r1, r2 ) __asm__ volatile ( \
+ "swc2 $12, 0( %0 );" \
+ "swc2 $13, 0( %1 );" \
+ "swc2 $14, 0( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r"( r2 ) \
+ : "memory" )
+
+#define gte_stotz( r0 ) __asm__ volatile ( \
+ "swc2 $7, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stopz( r0 ) __asm__ volatile ( \
+ "swc2 $24, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_strgb( r0 ) __asm__ volatile ( \
+ "swc2 $22, 0( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_strgb3( r0, r1, r2 ) __asm__ volatile ( \
+ "swc2 $20, 0( %0 );" \
+ "swc2 $21, 0( %1 );" \
+ "swc2 $22, 0( %2 );" \
+ : \
+ : "r"( r0 ), "r"( r1 ), "r" ( r2 ) \
+ : "memory" )
+
+#define gte_stsv( r0 ) __asm__ volatile ( \
+ "mfc2 $t0, $9;" \
+ "mfc2 $t1, $10;" \
+ "mfc2 $t2, $11;" \
+ "sh $t0, 0( %0 );" \
+ "sh $t1, 2( %0 );" \
+ "sh $t2, 4( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+#define gte_stlvnl( r0 ) __asm__ volatile ( \
+ "swc2 $25, 0( %0 );" \
+ "swc2 $26, 4( %0 );" \
+ "swc2 $27, 8( %0 );" \
+ : \
+ : "r"( r0 ) \
+ : "memory" )
+
+
+/*
+ * GTE operation macros (does not need a stupid tool such as dmpsx!)
+ */
+
+#define gte_rtps() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0180001;" )
+
+#define gte_rtpt() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0280030;" )
+
+#define gte_nclip() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1400006;" )
+
+#define gte_avsz3() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x158002D;" )
+
+#define gte_avsz4() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x168002E;" )
+
+#define gte_sqr0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0A00428;" )
+
+#define gte_sqr12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0A80428;" )
+
+#define gte_op0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x170000C;" )
+
+#define gte_op12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x178000C;" )
+
+#define gte_ncs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0C8041E;" )
+
+#define gte_nct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0D80420;" )
+
+#define gte_nccs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x108041B;" ) \
+
+#define gte_ncct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x118043F;" )
+
+#define gte_ncds() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0E80413;" )
+
+#define gte_ncdt() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0F80416;" )
+
+#define gte_cc() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x138041C;" )
+
+#define gte_cdp() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1280414;" )
+
+#define gte_dcpl() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0680029;" )
+
+#define gte_dpcs() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0780010;" )
+
+#define gte_dpct() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0180001;" )
+
+#define gte_intpl() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x0980011;" )
+
+#define gte_gpf0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x190003D;" )
+
+#define gte_gpf12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x198003D;" )
+
+#define gte_gpl0() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1A0003E;" )
+
+#define gte_gpl12() __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 0x1A8003E;" )
+
+#define gte_mvmva_core( r0 ) __asm__ volatile ( \
+ "nop;" \
+ "nop;" \
+ "cop2 %0" \
+ : \
+ : "g"( r0 ) )
+
+#define gte_mvmva(sf, mx, v, cv, lm) gte_mvmva_core( 0x0400012 | \
+ ((sf)<<19) | ((mx)<<17) | ((v)<<15) | ((cv)<<13) | ((lm)<<10) )
+
+
+/*
+ * GTE operation macros without leading nops
+ *
+ * Checking assembler output when using these is advised.
+ */
+
+#define gte_rtps_b() __asm__ volatile ( "cop2 0x0180001;" )
+#define gte_rtpt_b() __asm__ volatile ( "cop2 0x0280030;" )
+#define gte_nclip_b() __asm__ volatile ( "cop2 0x1400006;" )
+#define gte_avsz3_b() __asm__ volatile ( "cop2 0x158002D;" )
+#define gte_avsz4_b() __asm__ volatile ( "cop2 0x168002E;" )
+#define gte_sqr0_b() __asm__ volatile ( "cop2 0x0A00428;" )
+#define gte_sqr12_b() __asm__ volatile ( "cop2 0x0A80428;" )
+#define gte_op0_b() __asm__ volatile ( "cop2 0x170000C;" )
+#define gte_op12_b() __asm__ volatile ( "cop2 0x178000C;" )
+#define gte_ncs_b() __asm__ volatile ( "cop2 0x0C8041E;" )
+#define gte_nct_b() __asm__ volatile ( "cop2 0x0D80420;" )
+#define gte_nccs_b() __asm__ volatile ( "cop2 0x108041B;" )
+#define gte_ncct_b() __asm__ volatile ( "cop2 0x118043F;" )
+#define gte_ncds_b() __asm__ volatile ( "cop2 0x0E80413;" )
+#define gte_ncdt_b() __asm__ volatile ( "cop2 0x0F80416;" )
+#define gte_cc_b() __asm__ volatile ( "cop2 0x138041C;" )
+#define gte_cdp_b() __asm__ volatile ( "cop2 0x1280414;" )
+#define gte_dcpl_b() __asm__ volatile ( "cop2 0x0680029;" )
+#define gte_dpcs_b() __asm__ volatile ( "cop2 0x0780010;" )
+#define gte_dpct_b() __asm__ volatile ( "cop2 0x0180001;" )
+#define gte_intpl_b() __asm__ volatile ( "cop2 0x0980011;" )
+#define gte_gpf0_b() __asm__ volatile ( "cop2 0x190003D;" )
+#define gte_gpf12_b() __asm__ volatile ( "cop2 0x198003D;" )
+#define gte_gpl0_b() __asm__ volatile ( "cop2 0x1A0003E;" )
+#define gte_gpl12_b() __asm__ volatile ( "cop2 0x1A8003E;" )
+#define gte_mvmva_core_b( r0 ) __asm__ volatile ( \
+ "cop2 %0" \
+ : \
+ : "g"( r0 ) )
+#define gte_mvmva_b(sf, mx, v, cv, lm) gte_mvmva_core_b( 0x0400012 | \
+ ((sf)<<19) | ((mx)<<17) | ((v)<<15) | ((cv)<<13) | ((lm)<<10) )
+
+#endif // _INLINE_C_H \ No newline at end of file
diff --git a/libpsn00b/include/inline_s.h b/libpsn00b/include/inline_s.h
new file mode 100644
index 0000000..68e0d07
--- /dev/null
+++ b/libpsn00b/include/inline_s.h
@@ -0,0 +1,230 @@
+# Inline GTE macros for GNU assembler (as).
+#
+# Part of the PSn00bSDK Project by Lameguy64.
+# 2019 Meido-Tek Productions
+#
+# Similar to inline_c.h, it does not require running your object file
+# through some silly tool.
+
+.macro nRTPS
+ nop
+ nop
+ cop2 0x0180001
+.endm
+
+.macro nRTPT
+ nop
+ nop
+ cop2 0x0280030
+.endm
+
+.macro nNCLIP
+ nop
+ nop
+ cop2 0x1400006
+.endm
+
+.macro nAVSZ3
+ nop
+ nop
+ cop2 0x158002D
+.endm
+
+.macro nAVSZ4
+ nop
+ nop
+ cop2 0x168002E
+.endm
+
+.macro nMVMVA sf mx v cv lm
+ nop
+ nop
+ cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10)
+.endm
+
+.macro nSQR sf
+ nop
+ nop
+ cop2 0x0A00428|(\sf<<19)
+.endm
+
+.macro nnOP sf lm # extra n to prevent conflict with the nop opcode
+ nop
+ nop
+ cop2 0x170000C|(\sf<<19)|(\lm<<10)
+.endm
+
+.macro nNCS
+ nop
+ nop
+ cop2 0x0C8041E
+.endm
+
+.macro nNCT
+ nop
+ nop
+ cop2 0x0D80420
+.endm
+
+.macro nNCCS
+ nop
+ nop
+ cop2 0x108041B
+.endm
+
+.macro nNCCT
+ nop
+ nop
+ cop2 0x118043F
+.endm
+
+.macro nNCDS
+ nop
+ nop
+ cop2 0x0E80413
+.endm
+
+.macro nNCDT
+ nop
+ nop
+ cop2 0x0F80416
+.endm
+
+.macro nCC
+ nop
+ nop
+ cop2 0x138041C
+.endm
+
+.macro nCDP
+ nop
+ nop
+ cop2 0x1280414
+.endm
+
+.macro nDCPL
+ nop
+ nop
+ cop2 0x0680029
+.endm
+
+.macro nDPCS
+ nop
+ nop
+ cop2 0x0780010
+.endm
+
+.macro nDPCT
+ nop
+ nop
+ cop2 0x0180001
+.endm
+
+.macro nINTPL
+ nop
+ nop
+ cop2 0x0980011
+.endm
+
+.macro nGPF sf
+ nop
+ nop
+ cop2 0x190003D|(\sf<<19)
+.endm
+
+.macro nGPL sf
+ nop
+ nop
+ cop2 0x1A0003E|(\sf<<19)
+.endm
+
+#
+# Macros without leading nops (for optimized usage)
+#
+.macro RTPS
+ cop2 0x0180001
+.endm
+
+.macro RTPT
+ cop2 0x0280030
+.endm
+
+.macro NCLIP
+ cop2 0x1400006
+.endm
+
+.macro AVSZ3
+ cop2 0x158002D
+.endm
+
+.macro AVSZ4
+ cop2 0x168002E
+.endm
+
+.macro MVMVA sf mx v cv lm
+ cop2 0x0400012|(\sf<<19)|(\mx<<17)|(\v<<15)|(\cv<<13)|(\lm<<10)
+.endm
+
+.macro SQR sf
+ cop2 0x0A00428|(\sf<<19)
+.endm
+
+.macro OP sf lm
+ cop2 0x170000C|(\sf<<19)|(\lm<<10)
+.endm
+
+.macro NCS
+ cop2 0x0C8041E
+.endm
+
+.macro NCT
+ cop2 0x0D80420
+.endm
+
+.macro NCCS
+ cop2 0x108041B
+.endm
+
+.macro NCCT
+ cop2 0x118043F
+.endm
+
+.macro NCDS
+ cop2 0x0E80413
+.endm
+
+.macro NCDT
+ cop2 0x0F80416
+.endm
+
+.macro CC
+ cop2 0x138041C
+.endm
+
+.macro CDP
+ cop2 0x1280414
+.endm
+
+.macro DCPL
+ cop2 0x0680029
+.endm
+
+.macro DPCS
+ cop2 0x0780010
+.endm
+
+.macro DPCT
+ cop2 0x0180001
+.endm
+
+.macro INTPL
+ cop2 0x0980011
+.endm
+
+.macro GPF sf
+ cop2 0x190003D|(\sf<<19)
+.endm
+
+.macro GPL sf
+ cop2 0x1A0003E|(\sf<<19)
+.endm
diff --git a/libpsn00b/include/lzconfig.h b/libpsn00b/include/lzconfig.h
new file mode 100644
index 0000000..cb8a830
--- /dev/null
+++ b/libpsn00b/include/lzconfig.h
@@ -0,0 +1,68 @@
+/*! \file lzconfig.h
+ * \brief Library configuration header
+ * \details Define settings will only take effect when you recompile the library.
+ */
+
+#ifndef _LZP_CONFIG_H
+#define _LZP_CONFIG_H
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/* Set to TRUE to compile without data compression routines useful if you
+ * plan to use this library on a program that does not require said routines
+ * especially on a platform with limited memory (such as the PlayStation).
+ *
+ * This define will rule out lzCompress(), lzSetHashSizes() and
+ * lzResetHashSizes() functions and their associated functions.
+ */
+#define LZP_NO_COMPRESS TRUE
+
+
+/* Set to TRUE to make default compression table sizes to maximum and works best
+ * when compressing large amounts of data. LZP_USE_MALLOC must be set to TRUE to
+ * prevent stack overflow errors.
+ *
+ * Do not enable this if you plan to compile for a platform with limited memory
+ * otherwise, the library will consume all memory and crash the system.
+ *
+ * This define only affects lzCompress().
+ */
+#define LZP_MAX_COMPRESS FALSE
+
+
+/* Uncomment to make the library use malloc() instead of array initializers to
+ * allocate hash tables. Enabling this is a must if you plan to use large hash
+ * and window table sizes.
+ */
+#define LZP_USE_MALLOC FALSE
+
+
+/* Hash table sizes (in power-of-two multiple units)
+ *
+ * These define only affect lzCompress().
+ */
+#if LZP_MAX_COMPRESS == TRUE
+
+// Minimal defaults
+#define LZP_WINDOW_SIZE 17
+#define LZP_HASH1_SIZE 8
+#define LZP_HASH2_SIZE 10
+
+#else
+
+// Maximum defaults
+#define LZP_WINDOW_SIZE 17
+#define LZP_HASH1_SIZE 22
+#define LZP_HASH2_SIZE 24
+
+#endif
+
+
+#endif // _LZP_CONFIG_H
diff --git a/libpsn00b/include/malloc.h b/libpsn00b/include/malloc.h
new file mode 100644
index 0000000..e6cd126
--- /dev/null
+++ b/libpsn00b/include/malloc.h
@@ -0,0 +1,17 @@
+#ifndef _MALLOC_H
+#define _MALLOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int *GetBSSend();
+void InitHeap(unsigned int *addr, int size);
+void *malloc(int size);
+void free(void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _MALLOC_H \ No newline at end of file
diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h
new file mode 100644
index 0000000..54b87ee
--- /dev/null
+++ b/libpsn00b/include/psxapi.h
@@ -0,0 +1,97 @@
+#ifndef __PSXAPI__
+#define __PSXAPI__
+
+typedef struct { // Device control block
+ char *name;
+ int flags;
+ int ssize;
+ char *desc;
+ void *f_init;
+ void *f_open;
+ void *f_inout;
+ void *f_close;
+ void *f_ioctl;
+ void *f_read;
+ void *f_write;
+ void *f_erase;
+ void *f_undelete;
+ void *f_firstfile;
+ void *f_nextfile;
+ void *f_format;
+ void *f_chdir;
+ void *f_rename;
+ void *f_remove;
+ void *f_testdevice;
+} DCB;
+
+typedef struct { // File control block
+ int status;
+ unsigned int diskid;
+ void *trns_addr;
+ unsigned int trns_len;
+ unsigned int filepos;
+ unsigned int flags;
+ unsigned int lasterr;
+ DCB *dcb;
+ unsigned int filesize;
+ unsigned int lba;
+ unsigned int fcbnum;
+} FCB;
+
+struct DIRENTRY { // Directory entry
+ char name[20];
+ int attr;
+ int size;
+ struct DIRENTRY *next;
+ int head;
+ char system[4];
+};
+
+// Not recommended to use these functions to install IRQ handlers
+
+typedef struct {
+ unsigned int* next;
+ unsigned int* func2;
+ unsigned int* func1;
+ unsigned int pad;
+} INT_RP;
+
+extern void SysEnqIntRP(int pri, INT_RP *rp);
+extern void SysDeqIntRP(int pri, INT_RP *rp);
+
+// Use event handlers instead
+
+extern int OpenEvent(unsigned int class, int spec, int mode, void (*func)());
+extern int CloseEvent(int ev_desc);
+extern int EnableEvent(int ev_desc);
+extern int DisableEvent(int ev_desc);
+
+// BIOS file functions
+
+extern int open(const char *name, int mode);
+extern int close(int fd);
+extern int seek(int fd, unsigned int offset, int mode);
+extern int read(int fd, char *buff, unsigned int len);
+extern int write(int fd, const char *buff, unsigned int len);
+extern int ioctl(int fd, int cmd, int arg);
+extern struct DIRENTRY *firstfile(const char *wildcard, struct DIRENTRY *entry);
+extern struct DIRENTRY *nextfile(struct DIRENTRY *entry);
+extern int erase(const char *name);
+extern int chdir(const char *path);
+
+#define delete( p ) erase( p )
+#define cd( p ) chdir( p ) // For compatibility
+
+int AddDev(DCB *dcb);
+int DelDev(const char *name);
+extern void ListDev();
+
+extern void EnterCriticalSection();
+extern void ExitCriticalSection();
+
+extern void _96_init();
+extern void _96_remove();
+
+extern void ChangeClearPAD(int mode);
+
+#endif
diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h
new file mode 100644
index 0000000..67df29f
--- /dev/null
+++ b/libpsn00b/include/psxetc.h
@@ -0,0 +1,15 @@
+#ifndef _PSXETC_H
+#define _PSXETC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void FntLoad(int x, int y);
+char *FntSort(unsigned int *ot, char *pri, int x, int y, const char *text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h
new file mode 100644
index 0000000..24d023a
--- /dev/null
+++ b/libpsn00b/include/psxgpu.h
@@ -0,0 +1,556 @@
+#ifndef __PSXGPU_H
+#define __PSXGPU_H
+
+// Low-level display parameters for DISPENV_RAW. A leftover from prototyping
+#define DISP_WIDTH_256 0
+#define DISP_WIDTH_320 1
+#define DISP_WIDTH_384 64
+#define DISP_WIDTH_512 2
+#define DISP_WIDTH_640 3
+
+#define DISP_HEIGHT_LOW 0 // Could be 240 for NTSC, 256 for PAL
+#define DISP_HEIGHT_HIGH 4 // Could be 480 for NTSC, 512 for PAL
+#define DISP_INTERLACE 32
+#define DISP_24BIT_COLOR 16
+#define DISP_MODE_NTSC 0
+#define DISP_MODE_PAL 8
+
+
+#define MODE_NTSC 0
+#define MODE_PAL 1
+
+
+// Vector macros
+
+#define setVector( v, _x, _y, _z ) \
+ (v)->vx = _x, (v)->vy = _y, (v)->vz = _z
+
+#define setRECT( r, _x, _y, _w, _h ) \
+ (v)->x = _x, (v)->y = _y, (v)->w = _w, (v)->h = _h
+
+
+
+
+
+// Primitive macros
+
+
+#define setDrawTPage( p, tp, abr, x, y ) \
+ ( (p)->code[0] = getTPage( tp, abr, x, y ), \
+ setlen( p, 1 ), setcode( p, 0xe1 ) )
+
+/** ORIGINAL FUNCTION **/
+#define setDrawTPageVal( p, tp ) \
+ ( (p)->code[0] = tp, \
+ setlen( p, 1 ), setcode( p, 0xe1 ) )
+
+/*#define setVram2Vram( p ) ( setlen( p, 8 ), setcode( p, 0x80 ), \
+ (p)->nop[0] = 0, (p)->nop[1] = 0, (p)->nop[2] = 0, (p)->nop[3] = 0 )*/
+
+/*
+
+#define setTPagePri2( p, dth, tp, abr, x, y ) \
+ ( (p)->code[0] = getTPage( tp, abr, x, y )|(dth<<9), \
+ setlen( p, 1 ), setcode( p, 0xe1 ) )*/
+
+/*
+ * Set primitive attributes
+ */
+#define setTPage( p, tp, abr, x, y ) \
+ ( (p)->tpage = getTPage( tp, abr, x, y ) )
+
+#define setClut( p, x, y ) \
+ ( (p)->clut = getClut(x, y) )
+
+
+/*
+ * Set primitive colors
+ */
+#define setRGB0( p, r, g, b ) ( (p)->r0 = r, (p)->g0 = g, (p)->b0 = b )
+#define setRGB1( p, r, g, b ) ( (p)->r1 = r, (p)->g1 = g, (p)->b1 = b )
+#define setRGB2( p, r, g, b ) ( (p)->r2 = r, (p)->g2 = g, (p)->b2 = b )
+#define setRGB3( p, r, g, b ) ( (p)->r3 = r, (p)->g3 = g, (p)->b3 = b )
+
+
+/*
+ * Set primitive screen coordinates
+ */
+#define setXY0( p, _x0, _y0 ) \
+ (p)->x0 = _x0, (p)->y0 = _y0
+
+#define setXY2( p, _x0, _y0, _x1, _y1 ) \
+ (p)->x0 = _x0, (p)->y0 = _y0, \
+ (p)->x1 = _x1, (p)->y1 = _y1
+
+#define setXY3( p, _x0, _y0, _x1, _y1, _x2, _y2 ) \
+ (p)->x0 = _x0, (p)->y0 = _y0, \
+ (p)->x1 = _x1, (p)->y1 = _y1, \
+ (p)->x2 = _x2, (p)->y2 = _y2
+
+#define setXY4( p, _x0, _y0, _x1, _y1, _x2, _y2, _x3, _y3 ) \
+ (p)->x0 = _x0, (p)->y0 = _y0, \
+ (p)->x1 = _x1, (p)->y1 = _y1, \
+ (p)->x2 = _x2, (p)->y2 = _y2, \
+ (p)->x3 = _x3, (p)->y3 = _y3
+
+#define setWH( p, _w, _h ) \
+ (p)->w = _w, (p)->h = _h
+
+
+/*
+ * Set texture coordinates
+ */
+#define setUV0( p, _u0, _v0 ) \
+ (p)->u0 = _u0, (p)->v0 = _v0
+
+#define setUV3( p, _u0, _v0, _u1, _v1, _u2, _v2 ) \
+ (p)->u0 = _u0, (p)->v0 = _v0, \
+ (p)->u1 = _u1, (p)->v1 = _v1, \
+ (p)->u2 = _u2, (p)->v2 = _v2
+
+#define setUV4( p, _u0, _v0, _u1, _v1, _u2, _v2, _u3, _v3 ) \
+ (p)->u0 = _u0, (p)->v0 = _v0, \
+ (p)->u1 = _u1, (p)->v1 = _v1, \
+ (p)->u2 = _u2, (p)->v2 = _v2, \
+ (p)->u3 = _u3, (p)->v3 = _v3
+
+#define setUVWH( p, _u0, _v0, _w, _h ) \
+ (p)->u0 = _u0, (p)->v0 = _v0, \
+ (p)->u1 = _u1+(_w), (p)->v1 = _v1, \
+ (p)->u2 = _u2, (p)->v2 = _v2+(_h), \
+ (p)->u2 = _u3+(_h), (p)->v2 = _v3+(_h)
+
+
+/*
+ * Primitive handling macros
+ */
+#define setlen( p, _len ) ( ((P_TAG*)(p))->len = (unsigned char)_len )
+#define setaddr( p, _addr ) ( ((P_TAG*)(p))->addr = (unsigned int)_addr )
+#define setcode( p, _code ) ( ((P_TAG*)(p))->code = (unsigned char)_code )
+
+#define getlen( p ) ( ((P_TAG*)(p))->len )
+#define getaddr( p ) ( ((P_TAG*)(p))->addr )
+#define getcode( p ) ( ((P_TAG*)(p))->code )
+
+#define nextPrim( p ) (void*)((((P_TAG*)(p))->addr)|0x80000000)
+#define isendprim( p ) ((((P_TAG*)(p))->addr)==0xffffff)
+
+#define addPrim( ot, p ) setaddr( p, getaddr( ot ) ), setaddr( ot, p )
+#define addPrims(ot, p0, p1) setaddr( p1, getaddr( ot ) ), setaddr( ot, p0 )
+
+#define catPrim( p0, p1 ) setaddr( p0, p1 )
+#define termPrim( p ) setaddr( p, 0xffffffff )
+
+#define setSemiTrans( p, abe ) \
+ ( (abe)?setcode( p, getcode( p )|0x2 ):setcode( p, getcode( p )&~0x2 ) )
+
+#define setShadeTex( p, tge ) \
+ ( (tge)?setcode( p, getcode( p )|0x1 ):setcode( p, getcode( p )&~0x1 ) )
+
+
+/* ORIGINAl CODE */
+#define setDrawMask( p, sb, mt ) \
+ setlen( p, 1 ), p->code[0] = sb|(mt<<1), \
+ setcode( p, 0xe6 )
+
+
+#define getTPage( tp, abr, x, y ) \
+ ( (((x)&0x3ff)>>6) | (((y)>>8)<<4) | (((abr)&0x3)<<5) | (((tp)&0x3)<<7) )
+
+#define getClut( x, y ) \
+ ( ((y)<<6)|(((x)>>4)&0x3f) )
+
+
+/*
+ * Primitive initializers
+ */
+#define setPolyF3( p ) setlen( p, 4 ), setcode( p, 0x20 )
+#define setPolyFT3( p ) setlen( p, 7 ), setcode( p, 0x24 )
+#define setPolyG3( p ) setlen( p, 6 ), setcode( p, 0x30 )
+#define setPolyGT3( p ) setlen( p, 9 ), setcode( p, 0x34 )
+
+#define setPolyF4( p ) setlen( p, 5 ), setcode( p, 0x28 )
+#define setPolyFT4( p ) setlen( p, 9 ), setcode( p, 0x2c )
+#define setPolyG4( p ) setlen( p, 8 ), setcode( p, 0x38 )
+#define setPolyGT4( p ) setlen( p, 12 ), setcode( p, 0x3c )
+
+#define setSprt8( p ) setlen( p, 3 ), setcode( p, 0x74 )
+#define setSprt16( p ) setlen( p, 3 ), setcode( p, 0x7c )
+#define setSprt( p ) setlen( p, 4 ), setcode( p, 0x64 )
+
+#define setTile1( p ) setlen( p, 2 ), setcode( p, 0x68 )
+#define setTile8( p ) setlen( p, 2 ), setcode( p, 0x70 )
+#define setTile16( p ) setlen( p, 2 ), setcode( p, 0x78 )
+#define setTile( p ) setlen( p, 3 ), setcode( p, 0x60 )
+
+#define setLineG2( p ) setlen( p, 4 ), setcode( p, 0x50 )
+
+#define setLineF4( p ) setlen( p, 6 ), setcode( p, 0x4c ), (p)->pad = 0x55555555
+#define setLineG4( p ) setlen( p, 9 ), setcode( p, 0x5c ), (p)->pad = 0x55555555, \
+ (p)->p2 = 0, (p)->p3 = 0
+
+#define setFill( p ) setlen( p, 3 ), setcode( p, 0x02 )
+
+
+/*
+ * Primitive definitions
+ */
+typedef struct {
+ unsigned int addr:24;
+ unsigned int len:8;
+ unsigned char r,g,b;
+ unsigned char code;
+} P_TAG;
+
+/*
+ * Polygon primitive definitions
+ */
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short x1,y1;
+ short x2,y2;
+} POLY_F3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+ short x1,y1;
+ unsigned char u1,v1;
+ unsigned short tpage;
+ short x2,y2;
+ unsigned char u2,v2;
+ unsigned short pad;
+} POLY_FT3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char r1,g1,b1,pad0;
+ short x1,y1;
+ unsigned char r2,g2,b2,pad1;
+ short x2,y2;
+} POLY_G3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+ unsigned char r1,g1,b1,pad0;
+ short x1,y1;
+ unsigned char u1,v1;
+ unsigned short tpage;
+ unsigned char r2,g2,b2,pad1;
+ short x2,y2;
+ unsigned char u2,v2;
+ unsigned short pad2;
+} POLY_GT3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short x1,y1;
+ short x2,y2;
+ short x3,y3;
+} POLY_F4;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+ short x1,y1;
+ unsigned char u1,v1;
+ unsigned short tpage;
+ short x2,y2;
+ unsigned char u2,v2;
+ unsigned short pad0;
+ short x3,y3;
+ unsigned char u3,v3;
+ unsigned short pad1;
+} POLY_FT4;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char r1,g1,b1,pad0;
+ short x1,y1;
+ unsigned char r2,g2,b2,pad1;
+ short x2,y2;
+ unsigned char r3,g3,b3,pad2;
+ short x3,y3;
+} POLY_G4;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+ unsigned char r1,g1,b1,pad0;
+ short x1,y1;
+ unsigned char u1,v1;
+ unsigned short tpage;
+ unsigned char r2,g2,b2,pad1;
+ short x2,y2;
+ unsigned char u2,v2;
+ unsigned short pad2;
+ unsigned char r3,g3,b3,pad3;
+ short x3,y3;
+ unsigned char u3,v3;
+ unsigned short pad4;
+} POLY_GT4;
+
+/*
+ * Line primitive definitions
+ */
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short x1,y1;
+} LINE_F2;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char r1,g1,b1,p1;
+ short x1,y1;
+} LINE_G2;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short x1,y1;
+ short x2,y2;
+ unsigned int pad;
+} LINE_F3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char r1,g1,b1,p1;
+ short x1,y1;
+ unsigned char r2,g2,b2,p2;
+ short x2,y2;
+ unsigned int pad;
+} LINE_G3;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short x1,y1;
+ short x2,y2;
+ short x3,y3;
+ unsigned int pad;
+} LINE_F4;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char r1,g1,b1,p1;
+ short x1,y1;
+ unsigned char r2,g2,b2,p2;
+ short x2,y2;
+ unsigned char r3,g3,b3,p3;
+ short x3,y3;
+ unsigned int pad;
+} LINE_G4;
+
+/*
+ * Tile and sprite primitive definitions
+ */
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ short w,h;
+} TILE;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+} TILE_1;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+} TILE_8;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+} TILE_16;
+
+/*
+ * Sprite primitive definitions
+ */
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+ unsigned short w,h;
+} SPRT;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+} SPRT_8;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ short x0,y0;
+ unsigned char u0,v0;
+ unsigned short clut;
+} SPRT_16;
+
+/*
+ * VRAM fill and transfer primitive definitions
+ */
+typedef struct {
+ unsigned int tag;
+ unsigned char r0,g0,b0,code;
+ unsigned short x0,y0; // Note: coordinates must be in 16 pixel steps
+ unsigned short w,h;
+} FILL;
+
+typedef struct {
+ unsigned int tag;
+ unsigned char p0,p1,p2,code;
+ unsigned short x0,y0;
+ unsigned short x1,y1;
+ unsigned short w,h;
+ unsigned int nop[4];
+} VRAM2VRAM;
+
+typedef struct {
+ unsigned int tag;
+ unsigned int code[15];
+} DR_ENV;
+
+typedef struct {
+ unsigned int tag;
+ unsigned int code[2];
+} DR_TWIN;
+
+typedef struct {
+ unsigned int tag;
+ unsigned int code[1];
+} DR_TPAGE;
+
+typedef struct { /* ORIGINAL CODE */
+ unsigned int tag;
+ unsigned int code[1];
+} DR_MASK;
+
+
+// General structs
+
+typedef struct {
+ short x,y;
+ short w,h;
+} RECT;
+
+typedef struct {
+ unsigned int vid_mode; // Video mode
+ short vid_xpos,vid_ypos; // Video position (not framebuffer)
+ short fb_x,fb_y; // Framebuffer display position
+} DISPENV_RAW;
+
+typedef struct {
+ RECT disp;
+ RECT screen;
+ char isinter;
+ char isrgb24;
+ char reverse;
+ char pad;
+} DISPENV;
+
+typedef struct {
+ RECT clip; // Drawing area
+ short ofs[2]; // GPU draw offset (relative to draw area)
+ RECT tw; // Texture window (doesn't do anything atm)
+ unsigned short tpage; // Initial tpage value
+ unsigned char dtd; // Dither processing flag (simply OR'ed to tpage)
+ unsigned char dfe; // Drawing to display area blocked/allowed (simply OR'ed to tpage)
+ unsigned char isbg; // Clear draw area if non-zero
+ unsigned char r0,g0,b0; // Draw area clear color (if isbg iz nonzero)
+ DR_ENV dr_env; // Draw mode packet area (used by PutDrawEnv)
+} DRAWENV;
+
+typedef struct {
+ unsigned int mode;
+ RECT *crect;
+ unsigned int *caddr;
+ RECT *prect;
+ unsigned int *paddr;
+} TIM_IMAGE;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Function definitions (asm)
+
+void ResetGraph(int mode);
+
+int GetVideoMode();
+void SetVideoMode(int mode);
+
+void PutDispEnvRaw(DISPENV_RAW *disp);
+void PutDispEnv(DISPENV *disp);
+void PutDrawEnv(DRAWENV *draw);
+
+void SetDispMask(int mask);
+
+void VSync();
+void DrawSync();
+void WaitGPUcmd();
+void WaitGPUdma();
+
+void VSyncCallback(void (*func)());
+
+void LoadImage(RECT *rect, unsigned int *data);
+
+void ClearOTagR(unsigned int* ot, int n);
+void DrawOTag(unsigned int* ot);
+
+void AddPrim(unsigned int* ot, void* pri);
+
+// Function definitions (C)
+
+int GetTimInfo(unsigned int *tim, TIM_IMAGE *timimg);
+
+DISPENV *SetDefDispEnv(DISPENV *disp, int x, int y, int w, int h);
+DRAWENV *SetDefDrawEnv(DRAWENV *draw, int x, int y, int w, int h);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/libpsn00b/include/psxgte.h b/libpsn00b/include/psxgte.h
new file mode 100644
index 0000000..0a8ded0
--- /dev/null
+++ b/libpsn00b/include/psxgte.h
@@ -0,0 +1,72 @@
+#ifndef _PSXGTE_H
+#define _PSXGTE_H
+
+
+#define ONE 4096
+
+
+// For compatibility with official library syntax
+#define csin(a) isin(a)
+#define ccos(a) icos(a)
+#define rsin(a) isin(a)
+#define rcos(a) icos(a)
+
+
+typedef struct {
+ short m[3][3];
+ int t[3];
+} MATRIX;
+
+typedef struct {
+ int vx, vy, vz;
+} VECTOR;
+
+typedef struct {
+ short vx, vy, vz, pad;
+} SVECTOR;
+
+typedef struct {
+ unsigned char r, g, b, cd;
+} CVECTOR;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void InitGeom();
+
+// Integer SIN/COS functions (4096 = 360 degrees)
+// Does not use tables!
+int isin(int a);
+int icos(int a);
+
+// Higher precision integer sin/cos functions (131072 = 360 degrees)
+// Does not use tables!
+int hisin(int a);
+int hicos(int a);
+
+void PushMatrix();
+void PopMatrix();
+
+MATRIX *RotMatrix(SVECTOR *r, MATRIX *m);
+MATRIX *HiRotMatrix(VECTOR *r, MATRIX *m);
+
+MATRIX *TransMatrix(MATRIX *m, VECTOR *r);
+MATRIX *ScaleMatrix(MATRIX *m, VECTOR *s);
+
+MATRIX *MulMatrix(MATRIX *m0, MATRIX *m1);
+MATRIX *MulMatrix0(MATRIX *m0, MATRIX *m1, MATRIX *m2);
+
+MATRIX *CompMatrixLV(MATRIX *v0, MATRIX *v1, MATRIX *v2);
+VECTOR *ApplyMatrixLV(MATRIX *m, VECTOR *v0, VECTOR *v1);
+
+void VectorNormalS(VECTOR *v0, SVECTOR *v1);
+
+void Square0(VECTOR *v0, VECTOR *v1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _PSXGTE_H
diff --git a/libpsn00b/include/psxkernel.h b/libpsn00b/include/psxkernel.h
new file mode 100644
index 0000000..0c55bcb
--- /dev/null
+++ b/libpsn00b/include/psxkernel.h
@@ -0,0 +1,45 @@
+#ifndef _PSXKERNEL_H
+#define _PSXKERNEL_H
+
+// Event descriptors
+#define DescMask 0xff000000 // Event descriptor mask
+#define DescTH DescMask
+#define DescHW 0xf0000000 // Hardware event (IRQ)
+#define DescEV 0xf1000000 // Event event
+#define DescRC 0xf2000000 // Root counter event
+#define DescUEV 0xf3000000 // User event
+#define DescSW 0xf4000000 // BIOS event
+
+// Hardware events
+#define HwVBLANK (DescHW|0x01) // VBlank
+#define HwGPU (DescHW|0x02) // GPU
+#define HwCdRom (DescHW|0x03) // CDROM
+#define HwDMAC (DescHW|0x04) // DMA
+#define HwRTC0 (DescHW|0x05) // Timer 0
+#define HwRTC1 (DescHW|0x06) // Timer 1
+#define HwRTC2 (DescHW|0x07) // Timer 2
+#define HwCNTL (DescHW|0x08) // Controller
+#define HwSPU (DescHW|0x09) // SPU
+#define HwPIO (DescHW|0x0a) // PIO & lightgun
+#define HwSIO (DescHW|0x0b) // Serial
+
+#define HwCPU (DescHW|0x10) // Processor exception
+#define HwCARD (DescHW|0x11) // Memory card (lower level BIOS functions)
+#define HwCard_0 (DescHW|0x12) // Memory card (unused)
+#define HwCard_1 (DescHW|0x13) // Memory card (unused)
+#define SwCARD (DescSW|0x01) // Memory card (higher level BIOS functions)
+#define SwMATH (DescSW|0x02) // Libmath related apparently, unknown purpose
+
+#define RCntCNT0 (DescRC|0x00) // Root counter 0 (dot clock)
+#define RCntCNT1 (DescRC|0x01) // Horizontal sync
+#define RCntCNT2 (DescRC|0x02) // 1/8 of system clock
+#define RCntCNT3 (DescRC|0x03) // Vertical blank
+
+#define RCntMdINTR 0x1000 // General interrupt
+#define RCntMdNOINTR 0x2000 // New device
+#define RCntMdSC 0x0001 // Counter becomes zero
+#define RCntMdSP 0x0000 // Unknown purpose
+#define RCntMdFR 0x0000
+#define RCntMdGATE 0x0010 // Command acknowledged
+
+#endif // _PSXKERNEL_H \ No newline at end of file
diff --git a/libpsn00b/include/psxpad.h b/libpsn00b/include/psxpad.h
new file mode 100644
index 0000000..09d17b1
--- /dev/null
+++ b/libpsn00b/include/psxpad.h
@@ -0,0 +1,108 @@
+/* Controller support header
+ * Part of PSn00bSDK
+ * 2019 Lameguy64 / Meido-Tek Productions
+ *
+ * Currently only provides a bunch of definitions and a few structs but no
+ * handling functions yet. Use the code in pad.s in one of the sample
+ * programs for the meantime instead.
+ *
+ * Work in progress, subject to change significantly in future releases.
+ */
+
+#ifndef _PSXPAD_H
+#define _PSXPAD_H
+
+// Pad button definitions for digital pad, joystick, dual analog,
+// Dualshock and Jogcon
+#define PAD_SELECT 1
+#define PAD_L3 2
+#define PAD_R3 4
+#define PAD_START 8
+#define PAD_UP 16
+#define PAD_RIGHT 32
+#define PAD_DOWN 64
+#define PAD_LEFT 128
+#define PAD_L2 256
+#define PAD_R2 512
+#define PAD_L1 1024
+#define PAD_R1 2048
+#define PAD_TRIANGLE 4096
+#define PAD_CIRCLE 8192
+#define PAD_CROSS 16384
+#define PAD_SQUARE 32768
+
+// Mouse button definitions
+#define MOUSE_RIGHT 1024
+#define MOUSE_LEFT 2048
+
+// neGcon button definitions
+#define NCON_START 8
+#define NCON_UP 16
+#define NCON_RIGHT 32
+#define NCON_DOWN 64
+#define NCON_LEFT 128
+#define NCON_R 256
+#define NCON_B 512
+#define NCON_A 1024
+
+// Guncon button definitions
+#define GCON_A 8
+#define GCON_TRIGGER 8192
+#define GCON_B 16384
+
+// Struct for digital, joystick, dual analog and Dualshock controllers
+typedef struct {
+ unsigned char stat; // Status
+ unsigned char len:4; // Data length (in halfwords)
+ unsigned char type:4; // Device type:
+ // 0x4 - digital pad
+ // 0x5 - analog joystick
+ // 0x7 - dual analog & Dualshock
+ unsigned short btn; // Button states
+ unsigned char rs_x,rs_y; // Right stick coordinates
+ unsigned char ls_x,ls_y; // Left stick coordinates
+} PADTYPE;
+
+// Struct for a mouse controller
+typedef struct {
+ unsigned char stat;
+ unsigned char len:4;
+ unsigned char type:4; // Device type (0x1)
+ unsigned char btn;
+ char x_mov; // X movement of mouse
+ char y_mov; // Y movement of mouse
+} MOUSETYPE;
+
+// Struct for a neGcon controller (for Namco neGcon)
+typedef struct {
+ unsigned char stat;
+ unsigned char len:4;
+ unsigned char type:4; // (0x2)
+ unsigned short btn;
+ unsigned char twist; // Controller twist
+ unsigned char btn_i; // I button value
+ unsigned char btn_ii; // II button value
+ unsigned char trg_l; // L trigger value
+} NCONTYPE;
+
+// Struct for a Jogcon controller (for Namco Jogcon)
+typedef struct {
+ unsigned char stat;
+ unsigned char len:4;
+ unsigned char type:4; // (0xE)
+ unsigned short btn;
+ unsigned short jog_rot; // Jog rotation
+} JCONTYPE;
+
+// Struct for a Gun-Con controller (for Namco Gun-Con)
+typedef struct {
+ unsigned char status;
+ unsigned char len:4;
+ unsigned char type:4; // (0x6)
+ unsigned short btn;
+ unsigned short gun_x; // Gun X position in dotclocks
+ unsigned short gun_y; // Gun Y position in scanlines
+} GCONTYPE;
+
+
+#endif \ No newline at end of file
diff --git a/libpsn00b/include/psxspu.h b/libpsn00b/include/psxspu.h
new file mode 100644
index 0000000..a87e347
--- /dev/null
+++ b/libpsn00b/include/psxspu.h
@@ -0,0 +1,138 @@
+#ifndef __PSXSPU_H
+#define __PSXSPU_H
+
+#include <sys/types.h>
+
+// Mask settings bits for specifying voice channels
+
+#define SPU_00CH (1<<0)
+#define SPU_01CH (1<<1)
+#define SPU_02CH (1<<2)
+#define SPU_03CH (1<<3)
+#define SPU_04CH (1<<4)
+#define SPU_05CH (1<<5)
+#define SPU_06CH (1<<6)
+#define SPU_07CH (1<<7)
+#define SPU_08CH (1<<8)
+#define SPU_09CH (1<<9)
+#define SPU_10CH (1<<10)
+#define SPU_11CH (1<<11)
+#define SPU_12CH (1<<12)
+#define SPU_13CH (1<<13)
+#define SPU_14CH (1<<14)
+#define SPU_15CH (1<<15)
+#define SPU_16CH (1<<16)
+#define SPU_17CH (1<<17)
+#define SPU_18CH (1<<18)
+#define SPU_19CH (1<<19)
+#define SPU_20CH (1<<20)
+#define SPU_21CH (1<<21)
+#define SPU_22CH (1<<22)
+#define SPU_23CH (1<<23)
+
+#define SPU_0CH SPU_00CH
+#define SPU_1CH SPU_01CH
+#define SPU_2CH SPU_02CH
+#define SPU_3CH SPU_03CH
+#define SPU_4CH SPU_04CH
+#define SPU_5CH SPU_05CH
+#define SPU_6CH SPU_06CH
+#define SPU_7CH SPU_07CH
+#define SPU_8CH SPU_08CH
+#define SPU_9CH SPU_09CH
+
+#define SPU_KEYCH(x) (1<<(x))
+#define SPU_VOICECH(x) SPU_KEYCH(x)
+
+
+// Mask setting bits for SpuVoiceAttr.mask
+
+#define SPU_VOICE_VOLL (1<<0) // Left volume
+#define SPU_VOICE_VOLR (1<<1) // Right volume
+#define SPU_VOICE_VOLMODEL (1<<2) // Left volume mode
+#define SPU_VOICE_VOLMODER (1<<3) // Right volume mode
+#define SPU_VOICE_PITCH (1<<4) // Pitch tone
+#define SPU_VOICE_NOTE (1<<5) // Pitch note
+#define SPU_VOICE_SAMPLE_NOTE (1<<6) // Sample base frequency?
+#define SPU_VOICE_WDSA (1<<7) // Sample start address (in SPU RAM)
+#define SPU_VOICE_ADSR_AMODE (1<<8) // ADSR attack mode
+#define SPU_VOICE_ADSR_SMODE (1<<9) // ADSR sustain mode
+#define SPU_VOICE_ADSR_RMODE (1<<10) // ADSR release mode
+#define SPU_VOICE_ADSR_AR (1<<11) // ADSR attack rate
+#define SPU_VOICE_ADSR_DR (1<<12) // ADSR decay rate
+#define SPU_VOICE_ADSR_SR (1<<13) // ADSR sustain rate
+#define SPU_VOICE_ADSR_RR (1<<14) // ADSR release rate
+#define SPU_VOICE_ADSR_SL (1<<15) // ADSR sustain level
+#define SPU_VOICE_LSAX (1<<16) // Loop start address (in SPU RAM)
+#define SPU_VOICE_ADSR_ADSR1 (1<<17) // adsr1 for VagAtr (?)
+#define SPU_VOICE_ADSR_ADSR2 (1<<18) // adsr2 for VagAtr (?)
+
+
+#define SPU_TRANSFER_BY_DMA 0
+
+
+typedef struct {
+ short left;
+ short right;
+} SpuVolume;
+
+typedef struct {
+ SpuVolume vol; // 0
+ unsigned short freq; // 4
+ unsigned short addr; // 6
+ unsigned short loop_addr; // 8
+ unsigned short res; // 10
+ unsigned int adsr_param; // 12
+} SpuVoiceRaw;
+
+typedef struct {
+ u_int voice;
+ u_int mask;
+ SpuVolume volume;
+ SpuVolume volmode;
+ SpuVolume volumex;
+ u_short pitch;
+ u_short note;
+ u_short sample_note;
+ short envx;
+ u_int addr;
+ u_int loop_addr;
+ int a_mode;
+ int s_mode;
+ int r_mode;
+ u_short ar;
+ u_short dr;
+ u_short sr;
+ u_short rr;
+ u_short sl;
+ u_short adsr1;
+ u_short adsr2;
+} SpuVoiceAttr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void SpuInit();
+
+void SpuSetVoiceRaw( int voice, SpuVoiceRaw* param );
+void SpuReverbOn( int voice );
+void SpuSetReverb();
+
+void SpuSetReverbAddr( int addr );
+void SpuSetReverbVolume( int left, int right );
+
+
+void SpuSetKey(int on_off, u_int voice_bit);
+
+// SPU transfer functions
+int SpuSetTransferMode(int mode);
+int SpuSetTransferStartAddr(int addr);
+int SpuWrite(unsigned char* addr, int size);
+void SpuWait();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/libpsn00b/include/stdarg.h b/libpsn00b/include/stdarg.h
new file mode 100644
index 0000000..bdf4c00
--- /dev/null
+++ b/libpsn00b/include/stdarg.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
+This file is part of GCC.
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ * ISO C Standard: 7.15 Variable arguments <stdarg.h>
+ */
+
+#ifndef _STDARG_H
+#ifndef _ANSI_STDARG_H_
+#ifndef __need___va_list
+#define _STDARG_H
+#define _ANSI_STDARG_H_
+#endif /* not __need___va_list */
+#undef __need___va_list
+
+/* Define __gnuc_va_list. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+/* Define the standard macros for the user,
+ if this invocation was from the user program. */
+#ifdef _STDARG_H
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
+ || __cplusplus + 0 >= 201103L
+#define va_copy(d,s) __builtin_va_copy(d,s)
+#endif
+#define __va_copy(d,s) __builtin_va_copy(d,s)
+
+/* Define va_list, if desired, from __gnuc_va_list. */
+/* We deliberately do not define va_list when called from
+ stdio.h, because ANSI C says that stdio.h is not supposed to define
+ va_list. stdio.h needs to have access to that data type,
+ but must not use that name. It should use the name __gnuc_va_list,
+ which is safe because it is reserved for the implementation. */
+
+#ifdef _BSD_VA_LIST
+#undef _BSD_VA_LIST
+#endif
+
+#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
+/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
+ so we must avoid testing it and setting it here.
+ SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
+ have no conflict with that. */
+#ifndef _VA_LIST_
+#define _VA_LIST_
+#ifdef __i860__
+#ifndef _VA_LIST
+#define _VA_LIST va_list
+#endif
+#endif /* __i860__ */
+typedef __gnuc_va_list va_list;
+#ifdef _SCO_DS
+#define __VA_LIST
+#endif
+#endif /* _VA_LIST_ */
+#else /* not __svr4__ || _SCO_DS */
+
+/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
+/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */
+#ifndef _VA_LIST_DEFINED
+/* The macro _VA_LIST is used in SCO Unix 3.2. */
+#ifndef _VA_LIST
+/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+#ifndef _VA_LIST_T_H
+/* The macro __va_list__ is used by BeOS. */
+#ifndef __va_list__
+typedef __gnuc_va_list va_list;
+#endif /* not __va_list__ */
+#endif /* not _VA_LIST_T_H */
+#endif /* not _VA_LIST */
+#endif /* not _VA_LIST_DEFINED */
+#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
+#define _VA_LIST_
+#endif
+#ifndef _VA_LIST
+#define _VA_LIST
+#endif
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+#endif
+#ifndef _VA_LIST_T_H
+#define _VA_LIST_T_H
+#endif
+#ifndef __va_list__
+#define __va_list__
+#endif
+
+#endif /* not _VA_LIST_, except on certain systems */
+
+#endif /* not __svr4__ */
+
+#endif /* _STDARG_H */
+
+#endif /* not _ANSI_STDARG_H_ */
+#endif /* not _STDARG_H */ \ No newline at end of file
diff --git a/libpsn00b/include/stdio.h b/libpsn00b/include/stdio.h
new file mode 100644
index 0000000..5ee9e9b
--- /dev/null
+++ b/libpsn00b/include/stdio.h
@@ -0,0 +1,47 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <stdarg.h>
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+// BIOS seek modes
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* warning: reportedly buggy */
+#endif
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The following functions use the BIOS
+extern void printf (const char *__format, ...);
+
+extern int getc(int __fd);
+extern int putc(int __char, int __fd);
+extern void putchar(int __c);
+
+// The following functions do not use the BIOS
+int vsnprintf(char *string, unsigned int size, char *fmt, va_list ap);
+int vsprintf(char *string, char *fmt, va_list ap);
+int sprintf(char *string, char *fmt, ...);
+int snprintf(char *string, unsigned int size, char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _STDIO_H \ No newline at end of file
diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h
new file mode 100644
index 0000000..3909796
--- /dev/null
+++ b/libpsn00b/include/stdlib.h
@@ -0,0 +1,57 @@
+/*
+ * stdlib.h
+ *
+ * Standard library functions
+ *
+ * Inherited from PSXSDK
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#define RAND_MAX 0x7fff
+
+/* Conversion functions (not yet implemented) */
+
+/*
+extern int atoi(char *s);
+extern long atol(char *s);
+extern char atob(char *s); // Is this right?
+*/
+
+// Random number functions (not yet implemented)
+
+/*
+int rand();
+void srand(unsigned int seed);
+*/
+
+// Quick sort (not yet implemented)
+
+//void qsort(void *base , int nel , int width , int (*cmp)(const void *,const void *));
+
+// Memory allocation functions (not yet implemented, avoid using BIOS as they are reportedly buggy)
+
+/*
+#warning "malloc() family of functions NEEDS MORE TESTING"
+
+void *malloc(int size);
+void free(void *buf);
+void *calloc(int number, int size);
+void *realloc(void *buf , int n);
+*/
+
+int rand();
+void srand(unsigned long seed);
+
+int abs(int j);
+long long strtoll(const char *nptr, char **endptr, int base);
+long strtol(const char *nptr, char **endptr, int base);
+long double strtold(const char *nptr, char **endptr);
+
+// Note: these use floats internally!
+double strtod(const char *nptr, char **endptr);
+float strtof(const char *nptr, char **endptr);
+
+#endif
+
diff --git a/libpsn00b/include/string.h b/libpsn00b/include/string.h
new file mode 100644
index 0000000..95796d5
--- /dev/null
+++ b/libpsn00b/include/string.h
@@ -0,0 +1,42 @@
+/*
+ * string.h
+ *
+ * Prototypes for string functions of the C library
+ *
+ * PSXSDK
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+int strcmp(const char *dst , const char *src);
+int strncmp(const char *dst , const char *src , int len);
+char *strpbrk(const char *dst , const char *src);
+char *strtok(char *s , char *set);
+char *strstr(const char *big , const char *little);
+
+//int strspn(char *s , char *set);
+//int strcspn(char *s , char *set);
+//int index(char *s , int c);
+//int rindex(char *s , int c);
+
+char *strcat(char *s , const char *append);
+char *strncat(char *s , const char *append, int n);
+char *strcpy(char *dst , const char *src);
+char *strncpy(char *dst , const char *src , int n);
+int strlen(const char *s);
+//char *strchr(const char *s , int c);
+//char *strrchr(const char *s , int c);
+
+void *memmove(void *dst , const void *src , int n);
+void *memchr(void *s , int c , int n);
+
+// Functions converted to ASM
+
+void *memcpy(void *dst , const void *src , int n);
+void *memset(void *dst , char c , int n);
+int memcmp(const void *b1 , const void *b2 , int n);
+
+
+#endif
+
diff --git a/libpsn00b/include/strings.h b/libpsn00b/include/strings.h
new file mode 100644
index 0000000..e5e88d4
--- /dev/null
+++ b/libpsn00b/include/strings.h
@@ -0,0 +1,18 @@
+/*
+ * strings.h
+ *
+ * PSXSDK
+ */
+
+#ifndef _STRINGS_H
+#define _STRINGS_H
+
+#include <string.h>
+
+#define bcopy(src,dst,len) memmove(dst,src,len)
+#define bzero(ptr, len) memset(ptr, 0, len)
+#define bcmp(b1,b2,len) memcmp(b1,b2,len)
+#define index(s, c) strchr(s, c)
+#define rindex(s, c) strrchr(s, c)
+
+#endif
diff --git a/libpsn00b/include/sys/fcntl.h b/libpsn00b/include/sys/fcntl.h
new file mode 100644
index 0000000..dfbf5b2
--- /dev/null
+++ b/libpsn00b/include/sys/fcntl.h
@@ -0,0 +1,20 @@
+#ifndef _SYS_FCNTL_H
+#define _SYS_FCNTL_H
+
+// File control mode flags for BIOS file functions
+// (many weren't documented in nocash docs)
+#define FREAD 0x1 // Read
+#define FWRITE 0x2 // Write
+#define FNBLOCK 0x4 // Non-blocking read access
+#define FRLOCK 0x10 // Read lock
+#define FWLOCK 0x20 // Write lock
+#define FAPPEND 0x100 // Append
+#define FCREATE 0x200 // Create if not exist
+#define FTRUNC 0x400 // Truncate to zero length
+#define FSCAN 0x2000 // Scanning type
+#define FRCOM 0x2000 // Remote command entry
+#define FNBUF 0x4000 // No ring buffer and terminal interrupt
+#define FASYNC 0x8000 // Asynchronous I/O
+#define FNBLOCKS(a) (a<<16) // Number of blocks? (from nocash docs)
+
+#endif \ No newline at end of file
diff --git a/libpsn00b/include/sys/types.h b/libpsn00b/include/sys/types.h
new file mode 100644
index 0000000..2f30a5f
--- /dev/null
+++ b/libpsn00b/include/sys/types.h
@@ -0,0 +1,9 @@
+#ifndef _TYPES_H
+#define _TYPES_H
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+#endif // _TYPES_H \ No newline at end of file
diff --git a/libpsn00b/libc/makefile b/libpsn00b/libc/makefile
new file mode 100644
index 0000000..feadbdb
--- /dev/null
+++ b/libpsn00b/libc/makefile
@@ -0,0 +1,38 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libc.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -fdata-sections -ffunction-sections -Wa,--strip-local-absolute
+AFLAGS = -msoft-float -Wa,--strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(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)
diff --git a/libpsn00b/libc/malloc.s b/libpsn00b/libc/malloc.s
new file mode 100644
index 0000000..20e5371
--- /dev/null
+++ b/libpsn00b/libc/malloc.s
@@ -0,0 +1,216 @@
+# Custom first-fit malloc routines by Lameguy64
+# Part of the PSn00bSDK Project
+
+.set noreorder
+
+.set ND_PREV, 0 # Address to previous block (NULL if starting block)
+.set ND_NEXT, 4 # Address to next block (NULL if end block)
+.set ND_SIZE, 8 # Size of block
+.set ND_HSIZ, 12
+
+.section .text
+
+
+# Stupid small function just to get bss end
+# due to GCC insisting externs to be gp relative
+.global GetBSSend
+.type GetBSSend, @function
+GetBSSend:
+ la $v0, _end
+ jr $ra
+ nop
+
+
+# Initializes the heap for malloc
+# a0 - Starting address of heap
+# a1 - Size of memory heap
+#
+.global InitHeap
+.type InitHeap, @function
+InitHeap:
+ la $v0, _malloc_addr
+ sw $a0, 0($v0)
+ la $v0, _malloc_size
+ sw $a1, 0($v0)
+
+ sw $0 , ND_PREV($a0) # Set heap header
+ sw $0 , ND_NEXT($a0)
+ jr $ra
+ sw $0 , ND_SIZE($a0)
+
+
+# Allocates a block of memory in the heap
+# a0 - Size of memory block to allocate.
+#
+.global malloc
+.type malloc, @function
+malloc:
+ addiu $a0, 3 # Round size to a multiple of 4
+ srl $a0, 2
+
+ la $a2, _malloc_addr
+ lw $a2, 0($a2)
+ sll $a0, 2
+
+.find_next:
+
+ move $a1, $a2
+
+ lw $a2, ND_NEXT($a1) # Get block header
+ lw $v1, ND_SIZE($a1)
+
+ subu $v0, $a2, $a1 # Compute space between current and next
+
+ beqz $v1, .empty_block # Occupy empty block (if size = 0)
+ nop
+
+ beqz $a2, .new_block # Allocate a new block (if no next)
+ nop
+
+ addiu $v0, -(ND_HSIZ*2) # Compute remaining space of block
+ subu $v0, $v1
+
+ blt $v0, $a0, .find_next # Search for the next block if space is not big enough
+ nop
+
+ # Perform a block split using remaining space of current block
+
+ addiu $v0, $a1, ND_HSIZ # Compute address for new header
+ addu $v0, $v1
+
+ sw $a1, ND_PREV($v0) # Set the new block header
+ sw $a2, ND_NEXT($v0)
+ sw $a0, ND_SIZE($v0)
+
+ sw $v0, ND_NEXT($a1) # Update previous and next blocks
+ sw $v0, ND_PREV($a2)
+
+ jr $ra
+ addiu $v0, ND_HSIZ
+
+.empty_block: # Occupy an empty block
+
+ beqz $a2, .no_next # Skip size calculation if there's no next
+ nop
+
+ addiu $v0, -ND_HSIZ
+ blt $v0, $a0, .find_next
+ nop
+
+ b .skip_space_check
+ nop
+
+.no_next:
+
+ la $v1, _malloc_addr # Check if there's enough space for a block
+ lw $v1, 0($v1)
+ la $v0, _malloc_size
+ lw $v0, 0($v0)
+
+ subu $v1, $a1, $v1
+ addu $v1, $a0
+ addiu $v1, ND_HSIZ
+
+ bgt $v1, $v0, .no_space
+ nop
+
+.skip_space_check:
+
+ sw $a0, ND_SIZE($a1)
+ jr $ra # Return address
+ addiu $v0, $a1, ND_HSIZ
+
+.new_block: # Create a new block
+
+ addu $a2, $a1, $v1 # Compute address for new block
+ addiu $a2, ND_HSIZ
+
+ la $v1, _malloc_addr
+ lw $v1, 0($v1)
+ la $v0, _malloc_size
+ lw $v0, 0($v0)
+
+ subu $v1, $a2, $v1
+ addu $v1, $a0
+ addiu $v1, ND_HSIZ
+
+ bgt $v1, $v0, .no_space # Reject if it exceeds specified size
+ nop
+
+ sw $a1, ND_PREV($a2)
+ sw $0 , ND_NEXT($a2)
+ sw $a0, ND_SIZE($a2)
+
+ sw $a2, ND_NEXT($a1)
+
+ jr $ra # Return address
+ addiu $v0, $a2, ND_HSIZ
+
+.no_space: # Return a null if no space can be found
+ jr $ra
+ move $v0, $0
+
+
+# Allocates a block of memory in block units and zero fills the
+# allocated block.
+# a0 - Block size.
+# a1 - Number of blocks to allocate
+#
+.global calloc
+.type calloc, @function
+calloc:
+ mult $a0, $a1
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ jal malloc
+ mflo $a0
+
+ move $a0, $v0
+ mflo $a1
+.clear_loop:
+ sw $0 , 0($a0)
+ addi $a1, 4
+ bgtz $a1, .clear_loop
+ addiu $a0, 4
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+# Deallocates an allocated block
+# a0 - An address returned by malloc to deallocate
+#
+.global free
+.type free, @function
+free:
+
+ addiu $a0, -ND_HSIZ
+ lw $a1, ND_PREV($a0)
+ lw $a2, ND_NEXT($a0)
+
+ beqz $a1, .is_start # Check if block is a starting block
+ nop
+
+ beqz $a2, .is_end
+ nop
+
+ # Unlink
+
+ sw $a2, ND_NEXT($a1)
+ jr $ra
+ sw $a1, ND_PREV($a2)
+
+.is_end: # Unlinks the ending block
+ jr $ra
+ sw $0 , ND_NEXT($a1)
+.is_start: # Simply set size to 0 if starting block
+ jr $ra
+ sw $0 , ND_SIZE($a0)
+
+
+# Internal variables
+.comm _malloc_addr, 4, 4
+.comm _malloc_size, 4, 4
diff --git a/libpsn00b/libc/memcmp.s b/libpsn00b/libc/memcmp.s
new file mode 100644
index 0000000..b8b495d
--- /dev/null
+++ b/libpsn00b/libc/memcmp.s
@@ -0,0 +1,31 @@
+# High speed ASM memcmp implementation by Lameguy64
+#
+# Part of PSn00bSDK
+
+.set noreorder
+
+.section .text
+
+# Arguments:
+# a0 - buffer 1 address
+# a1 - buffer 2 address
+# a2 - bytes to compare
+.global memcmp
+.type memcmp, @function
+memcmp:
+ blez $a2, .exit
+ addi $a2, -1
+ lbu $v0, 0($a0)
+ lbu $v1, 0($a1)
+ addiu $a0, 1
+ bne $v0, $v1, .mismatch
+ addiu $a1, 1
+ b memcmp
+ nop
+.mismatch:
+ jr $ra
+ sub $v0, $v1
+.exit:
+ jr $ra
+ move $v0, $0
+ \ No newline at end of file
diff --git a/libpsn00b/libc/memcpy.s b/libpsn00b/libc/memcpy.s
new file mode 100644
index 0000000..e1a4e30
--- /dev/null
+++ b/libpsn00b/libc/memcpy.s
@@ -0,0 +1,28 @@
+# High speed ASM memcpy implementation by Lameguy64
+#
+# Part of PSn00bSDK
+
+.set noreorder
+
+.section .text
+
+# Arguments:
+# a0 - destination address
+# a1 - source adress
+# a2 - bytes to copy
+.global memcpy
+.type memcpy, @function
+memcpy:
+ move $v0, $a0
+.loop:
+ blez $a2, .exit
+ addi $a2, -1
+ lbu $a3, 0($a1)
+ addiu $a1, 1
+ sb $a3, 0($a0)
+ b .loop
+ addiu $a0, 1
+.exit:
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/libc/memmove.s b/libpsn00b/libc/memmove.s
new file mode 100644
index 0000000..961e71f
--- /dev/null
+++ b/libpsn00b/libc/memmove.s
@@ -0,0 +1,29 @@
+.set noreorder
+
+.section .text
+
+# Arguments
+# a0 - destination address
+# a1 - source address
+# a2 - bytes to move
+.global memmove
+.type memmove, @function
+memmove:
+ move $v0, $a0
+ addu $a0, $a2
+ addu $a1, $a2
+ addiu $a0, -1
+ addiu $a1, -1
+.loop:
+ blez $a2, .exit
+ addi $a2, -1
+ lbu $v1, 0($a1)
+ addiu $a1, -1
+ sb $v1, 0($a0)
+ addiu $a0, -1
+ b .loop
+ nop
+.exit:
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/libc/memset.s b/libpsn00b/libc/memset.s
new file mode 100644
index 0000000..f7d86b1
--- /dev/null
+++ b/libpsn00b/libc/memset.s
@@ -0,0 +1,25 @@
+# High speed ASM memset implementation by Lameguy64
+#
+# Part of PSn00bSDK
+
+.set noreorder
+
+.section .text
+
+# Arguments:
+# a0 - address to buffer
+# a1 - value to set
+# a2 - bytes to set
+.global memset
+.type memset,@function
+memset:
+ move $v0, $a0
+ blez $a2, .exit
+ addi $a2, -1
+ sb $a1, 0($a0)
+ b memset
+ addiu $a0, 1
+.exit:
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/libc/printf.c b/libpsn00b/libc/printf.c
new file mode 100644
index 0000000..7350648
--- /dev/null
+++ b/libpsn00b/libc/printf.c
@@ -0,0 +1,788 @@
+/* printf.c
+ *
+ * Inherited from the PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SPRINTF_ALT_FLAG (1<<0)
+#define SPRINTF_ZERO_FLAG (1<<1)
+#define SPRINTF_NEGFIELD_FLAG (1<<2)
+#define SPRINTF_SPACE_FLAG (1<<3)
+#define SPRINTF_SIGN_FLAG (1<<4)
+
+// sprintf() macros to calculate the real padding and to write it
+// these were made to not repeat the code in the function
+// they can only be used in sprintf()
+
+// sprintf macros START
+
+#define calculate_real_padding() \
+ y = 1; \
+ \
+ for(x=0;x<=19;x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if(arg / y) \
+ pad_quantity--; \
+ } \
+ \
+ y *= 10; \
+ } \
+ \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+/*#define calculate_real_padding_hex() \
+ for (x = 0; x < 8; x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if((arg >> (x * 4)) & 0xf) \
+ pad_quantity--; \
+ } \
+ }*/
+
+#define calculate_real_padding_hex() \
+ last = 0; \
+ for (x = 0; x < 16; x++) \
+ if((arg >> (x * 4)) & 0xf) \
+ last = x; \
+ \
+ pad_quantity = (pad_quantity - 1) - last; \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+#define write_padding() \
+ if(!(flags & SPRINTF_NEGFIELD_FLAG)) \
+ for(x = 0; x < pad_quantity; x++) \
+ { \
+ if(flags & SPRINTF_ZERO_FLAG) \
+ put_in_string(string, ssz, '0', string_pos++); \
+ else \
+ put_in_string(string, ssz, ' ', string_pos++); \
+ }
+
+#define write_neg_padding() \
+ if(flags & SPRINTF_NEGFIELD_FLAG) \
+ { \
+ for(x = 0; x < pad_quantity; x++) \
+ put_in_string(string, ssz, ' ', string_pos++);\
+ }
+
+// sprintf macros END
+
+enum
+{
+ SPRINTF_SIZE_CHAR,
+ SPRINTF_SIZE_SHORT,
+ SPRINTF_SIZE_INT,
+ SPRINTF_SIZE_LONG,
+ SPRINTF_SIZE_LONG_LONG,
+};
+
+unsigned int get_arg_in_size(int size, unsigned long long *arg, unsigned int check_sign)
+{
+ int s = 0;
+
+ switch(size)
+ {
+ case SPRINTF_SIZE_CHAR:
+ *arg &= 0xff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<7))
+ {
+ *arg |= 0xffffff00;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ case SPRINTF_SIZE_SHORT:
+ *arg &= 0xffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<15))
+ {
+ *arg |= 0xffff0000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+// sizeof(long) == sizeof(int) on 32bit, so this will suffice for the psx
+
+ case SPRINTF_SIZE_INT:
+ case SPRINTF_SIZE_LONG:
+ *arg &= 0xffffffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<31))
+ {
+ *arg |= (long long)0xffffffff00000000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+ case SPRINTF_SIZE_LONG_LONG:
+ if(check_sign)
+ {
+ if(*arg & ((long long)1<<63))
+ {
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ }
+
+ return s;
+}
+
+int put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ if(pos>=sz)
+ return 0;
+ else
+ string[pos] = c;
+
+ return 1;
+}
+
+int libc_ulltoa(unsigned long long i, char *dst, int n)
+{
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit = 1;
+ int sp=0;
+ int n2=0;
+
+ for(x=20;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (i/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ i -= b*a;
+
+ //put_in_string(string, ssz, b + '0', string_pos++);
+ if(n2!=n)
+ {
+ //printf("n2=%d\n",n2);
+ dst[sp++] = b + '0';
+ n2++;
+ }
+ }
+ }
+
+ if(n2!=n)dst[sp] = 0;
+
+ return n2;
+}
+
+void libc_float_to_string(float fl, char *dst, int n)
+{
+ unsigned int *p = (unsigned int*)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ int e, m, s;
+ int x, y;
+ unsigned long long z;
+
+ s = *p >> 31;
+
+ e = (*p >> 23) & 0xff;
+
+ m = *p & 0x7fffff;
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 127;
+ m |= 1<<23;
+
+
+
+ for(x = 23; x >= 0; x--)
+ {
+ if(m & (1<<x))
+ {
+ if(e >= 0)
+ {
+ z = 1;
+ for(y=0;y<e;y++)
+ z*=2;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ for(y = 1; y < -e; y++)
+ z /= 2;
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && n)
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n);
+ n-=x;
+ dst+=x;
+
+ if(n)
+ {
+ *(dst++) = '.';
+ n--;
+ if(n)
+ {
+ x = libc_ulltoa(f, dst, n<6?n:6);
+ n-=x;
+ dst+=x;
+
+ if(n)
+ *dst=0;
+ }
+ }
+ }
+}
+
+void libc_double_to_string(double fl, char *dst, int n)
+{
+ unsigned long long *p = (unsigned long long *)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ unsigned long long m, s;
+ long long e;
+ int x, y;
+ unsigned long long z;
+
+ s = *p >> 63;
+
+ e = (*p >> 52) & 0x7ff;
+ //printf("%d\n", e);
+
+ m = *p & 0xfffffffffffff;
+
+ for(x=0;x<52;x++)
+ if(m&((unsigned long long)1<<(52-x))) putchar('1'); else putchar('0');
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 1023;
+ m |= (unsigned long long)1<<52;
+
+ for(x = 52; x >= 0; x--)
+ {
+ if(m & ((unsigned long long)1<<x))
+ {
+ if(e >= 0)
+ {
+ z = (long long)1<<e;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ z >>= -(e + 1);
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && n)
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n);
+ n-=x;
+ dst+=x;
+
+ if(n)
+ {
+ *(dst++) = '.';
+ n--;
+ if(n)
+ libc_ulltoa(f, dst, n<6?n:6);
+ }
+ }
+}
+
+char libc_sprintf_floatbuf[64];
+
+int vsnprintf(char *string, unsigned int size, char *fmt, va_list ap)
+{
+ int string_pos,fmt_pos;
+ int l;
+ unsigned long long arg;
+ unsigned char *argcp;
+ unsigned char *argcp_tmp;
+ int directive_coming = 0;
+ int alternate_form = 0;
+ int flags = 0;
+ int argsize = 2; // int
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit;
+ int ssz = size - 1;
+ int zero_flag_imp = 0;
+ int pad_quantity = 0;
+ int last;
+
+ l = strlen(fmt);
+
+ string_pos = 0;
+
+ for(fmt_pos=0;fmt_pos<l;fmt_pos++)
+ {
+ if(directive_coming)
+ {
+ switch(fmt[fmt_pos])
+ {
+ case '%':
+ put_in_string(string, ssz, '%', string_pos++);
+ directive_coming = 0;
+ break;
+ case ' ':
+ flags |= SPRINTF_SPACE_FLAG;
+ break;
+ case '#': // Specify alternate form
+ flags |= SPRINTF_ALT_FLAG;
+ break;
+ case '+': // Specify sign in signed conversions
+ flags |= SPRINTF_SIGN_FLAG;
+ break;
+ case '0': // Padding with zeros...
+ if(zero_flag_imp == 0)
+ {
+ flags |= SPRINTF_ZERO_FLAG;
+ zero_flag_imp = 1;
+ //printf("Zero padding enabled!\n");
+ }
+ else
+ {
+ pad_quantity *= 10;
+ //printf("pad_quantity = %d\n", pad_quantity);
+ }
+ break;
+ case '1' ... '9': // '...' cases are a GNU extension,
+ // but they simplify a lot
+
+ pad_quantity *= 10;
+ pad_quantity += fmt[fmt_pos] - '0';
+ zero_flag_imp = 1;
+
+ //printf("pad_quantity = %d\n", pad_quantity);
+ break;
+ case '-': // Negative field flag
+ if(flags & SPRINTF_ZERO_FLAG)
+ flags &= ~SPRINTF_ZERO_FLAG;
+
+ flags |= SPRINTF_NEGFIELD_FLAG;
+ break;
+ case 'h': // Half argument size
+ if(argsize) argsize--;
+ break;
+ case 'l': // Double argument size
+ if(argsize < 2) argsize = 2;
+ else if(argsize < SPRINTF_SIZE_LONG_LONG) argsize++;
+ break;
+ case 'd': // signed decimal
+ case 'i':
+ empty_digit = 1;
+
+ //printf("argsize = %d\n", argsize);
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ if(get_arg_in_size(argsize, &arg, 1))
+ {
+ put_in_string(string, ssz, '-', string_pos++);
+ pad_quantity--;
+ }
+ else
+ {
+ if(flags & SPRINTF_SIGN_FLAG)
+ {
+ put_in_string(string, ssz, '+', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ /* Calculate how much padding we have to write */
+
+ /*y = 1;
+
+ for(x=0;x<=9;x++)
+ {
+ if(x == 0)
+ pad_quantity--;
+ else
+ {
+ if(arg / y)
+ pad_quantity--;
+ }
+
+ y *= 10;
+ }
+ if(pad_quantity < 0) pad_quantity = 0;*/
+
+ calculate_real_padding();
+
+ //printf("Actual pad quantity = %d\n", pad_quantity);
+
+
+
+ /*if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ for(x = 0; x < pad_quantity; x++)
+ {
+ if(flags & SPRINTF_ZERO_FLAG)
+ put_in_string(string, ssz, '0', string_pos++);
+ else
+ put_in_string(string, ssz, ' ', string_pos++);
+ }
+ }*/
+
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ /*if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ for(x = 0; x < pad_quantity; x++)
+ put_in_string(string, ssz, ' ', string_pos++);
+ }*/
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'u': // unsigned decimal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ calculate_real_padding();
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'x': // Hexadecimal
+ case 'X': // Hexadecimal with big letters
+ case 'p': // Hexadecimal with small letters with '0x' prefix
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long int);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ if(fmt_pos == 'p')
+ flags |= SPRINTF_ALT_FLAG;
+
+ if(flags & SPRINTF_ALT_FLAG)
+ {
+ put_in_string(string, ssz, '0', string_pos++);
+
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, 'X', string_pos++);
+ else
+ put_in_string(string, ssz, 'x', string_pos++);
+ }
+
+ calculate_real_padding_hex();
+ write_padding();
+
+ for(x=15;x>=0;x--)
+ {
+ y = arg >> (x << 2);
+ y &= 0xf;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ if(y>=0 && y<=9)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ else if(y>=0xA && y<=0xF)
+ {
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, (y - 0xa) + 'A', string_pos++);
+ else
+ put_in_string(string, ssz, (y - 0xa) + 'a', string_pos++);
+ }
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'c': // character
+ arg = va_arg(ap, int);
+
+ put_in_string(string, ssz, arg & 0xff, string_pos++);
+
+ directive_coming = 0;
+ break;
+ case 's': // string
+ argcp = va_arg(ap, char *);
+ argcp_tmp = argcp;
+
+ if(argcp == NULL)
+ {
+ // Non standard extension, but supported by Linux and the BSDs.
+
+ put_in_string(string, ssz, '(', string_pos++);
+ put_in_string(string, ssz, 'n', string_pos++);
+ put_in_string(string, ssz, 'u', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, ')', string_pos++);
+
+ directive_coming = 0;
+ break;
+ }
+
+ while(*argcp_tmp)
+ {
+ if(pad_quantity > 0) pad_quantity--;
+ argcp_tmp++;
+ }
+
+ if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ while(*argcp)
+ {
+ put_in_string(string, ssz, *argcp, string_pos++);
+ argcp++;
+ }
+
+ if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ directive_coming = 0;
+ break;
+ case 'o': // Octal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=21;x>=0;x--)
+ {
+ y = arg >> (x * 3);
+ y &= 0x7;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+ case '@': // Binary
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=63;x>=0;x--)
+ {
+ y = (arg >> x);
+ y &= 1;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+
+ case 'f':
+ libc_double_to_string(va_arg(ap, double), libc_sprintf_floatbuf, 64);
+
+ for(x=0;libc_sprintf_floatbuf[x]!=0;x++)
+ put_in_string(string, ssz, libc_sprintf_floatbuf[x], string_pos++);
+
+ directive_coming = 0;
+ break;
+ case 'n': // Number of characters written
+ *(va_arg(ap,unsigned int*)) = string_pos;
+
+ directive_coming = 0;
+ break;
+ // default
+ }
+ }
+ else
+ {
+ if(fmt[fmt_pos] == '%')
+ {
+ directive_coming = 1;
+ flags = 0;
+ argsize = 2;
+ pad_quantity = 0;
+ zero_flag_imp = 0;
+ }
+ else
+ put_in_string(string, ssz, fmt[fmt_pos], string_pos++);
+ }
+ }
+ string[string_pos] = 0;
+ return string_pos;
+}
+
+int vsprintf(char *string, char *fmt, va_list ap)
+{
+ return vsnprintf(string, 0xffffffff, fmt, ap);
+}
+
+int sprintf(char *string, char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsprintf(string, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+int snprintf(char *string, unsigned int size, char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsnprintf(string, size, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
diff --git a/libpsn00b/libc/rand.s b/libpsn00b/libc/rand.s
new file mode 100644
index 0000000..a502e87
--- /dev/null
+++ b/libpsn00b/libc/rand.s
@@ -0,0 +1,38 @@
+.set noreorder
+.set noat
+
+.section .text
+
+
+.global rand
+.type rand, @function
+rand:
+
+ la $at, _randseed
+ lw $v0, 0($at)
+ li $v1, 0x41c64e6d
+
+ multu $v0, $v1
+ mflo $v0
+ nop
+ addiu $v0, 12345
+ sw $v0, 0($at)
+
+ jr $ra
+ andi $v0, 0x7fff
+
+
+.global srand
+.type srand, @function
+srand:
+ la $at, _randseed
+ jr $ra
+ sw $a0, 0($at)
+
+
+.section .data
+
+.type _randseed, @object
+_randseed:
+ .word 1
+ \ No newline at end of file
diff --git a/libpsn00b/libc/readme.txt b/libpsn00b/libc/readme.txt
new file mode 100644
index 0000000..d7abf0a
--- /dev/null
+++ b/libpsn00b/libc/readme.txt
@@ -0,0 +1,48 @@
+Limited C standard library implementation, part of PSn00bSDK
+2019 Lameguy64 / Meido-Tek Productions
+
+ Some components were inherited from PSXSDK. This library covers only the
+most commonly used C functions, mainly most string and memory manipulation
+functions. Improvements to this library such as adding more standard C
+functions are welcome.
+
+ This library also contains the start code written in assembler which
+performs basic initialization such as clearing the bss section, setting the
+correct gp register value and initializing the heap for malloc.
+
+ The dynamic memory allocation functions featured in this library are of
+an original implementation and do not use the BIOS memory allocation functions
+as they are are reportedly prone to memory leakage and is even explained in
+the official library documents. The implementation employed uses a simple
+first-fit memory allocation logic.
+
+
+Library developer(s)/contributor(s):
+
+ Lameguy64
+
+
+Library header(s):
+
+ stdio.h
+ stdlib.h
+ string.h
+ strings.h
+ malloc.h
+
+
+Todo list:
+
+ * Current vsprintf/sprintf implementation from PSXSDK needs to be replaced
+ as it performs quite slow likely due to the unnecessary int64 arithmetic
+ performed on any integer value which the compiler has to emulate on the
+ R3000. A more efficient implementation that only uses int32 is much
+ preferred.
+
+ * Many of the string manipulation and memory fill functions in string.c
+ are yet to be replaced with more efficient assembly implementations.
+
+
+Changelog:
+
+ None thus far...
diff --git a/libpsn00b/libc/scanf.c b/libpsn00b/libc/scanf.c
new file mode 100644
index 0000000..b6d4510
--- /dev/null
+++ b/libpsn00b/libc/scanf.c
@@ -0,0 +1,427 @@
+// vsscanf
+// Programmed by Giuseppe Gatta, 2011
+// Inherited from PSXSDK C library
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+char libc_vsscanf_buf[512];
+char libc_vsscanf_allow[256];
+
+enum
+{
+ elem_skip_space = 1,
+};
+
+int libc_vsscanf_get_element(char *dst, const char *src, int flag, int s)
+{
+ int i;
+ const char *osrc = src;
+
+ if(flag & elem_skip_space)
+ {
+ while(*src == ' ')
+ src++;
+ }
+
+ for(i=0;i<s;i++)
+ {
+ if((flag & elem_skip_space) && *src == ' ')
+ break;
+
+ if(*src != 0)
+ *(dst++) = *(src++);
+ else
+ break;
+ }
+
+ *dst = 0;
+
+ return src - osrc;
+}
+
+enum
+{
+ scanf_s_char, scanf_s_short, scanf_s_int,
+ scanf_s_long,
+ scanf_s_long_long
+};
+
+int vsscanf(const char *str, const char *format, va_list ap)
+{
+ int fp = 0;
+ int sp = 0;
+ int conv = 0;
+ int sz = scanf_s_int; // size for numbers defaults to 32-bit
+ int i,x,y,z, h;
+ int suppress = 0;
+ int neg = 0;
+ int fsz = 512;
+ int def_fsz = 1;
+ int exspace = 0;
+ int alt = 0;
+ int r = 0;
+ int exit_loop=0;
+ int sp2,sp3;
+ char *ep;
+ long long buf;
+ double fbuf;
+
+
+ while(format[fp] && str[sp] && !exit_loop)
+ {
+ if(conv)
+ {
+ switch(format[fp])
+ {
+ case '%': // Percent, assignment does not occur
+ conv = 0;
+ break;
+
+ case 'h': // Halve size
+ sz--;
+ break;
+
+ case 'l': // Double size
+ sz++;
+ break;
+
+ case '*': // Suppress
+ suppress = 1;
+ break;
+
+ case ' ': // Explicit space
+ exspace = 1;
+ break;
+
+ case '#': // Alternate format
+ alt = 1;
+ break;
+
+ case '0' ... '9': // '0' ... '9' is a GNU C extension!
+ if(def_fsz)
+ {
+ def_fsz = 0;
+ fsz = 0;
+ }
+
+ fsz *= 10;
+ fsz+=format[fp]-'0';
+
+ if(fsz > 512)
+ fsz = 512; // 512 is the maximum.
+ break;
+
+ case '@': // Binary. Non-standard extension
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 2);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'D':
+ sz++;
+ case 'd': // Decimal
+ case 'u':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 10);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 's': // String
+ sp += libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'c':
+ if(def_fsz)
+ fsz = 1;
+
+ sp += (i = libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], (exspace ? elem_skip_space : 0), fsz));
+ if(!suppress)
+ {
+ memcpy(va_arg(ap, char*), libc_vsscanf_buf, (fsz>i)?i:fsz);
+ r++;
+ }
+ break;
+
+ case 'n':
+ if(!suppress)
+ {
+ *(va_arg(ap, int*)) = sp;
+ r++;
+ }
+ break;
+
+ case 'p':
+ case 'x':
+ case 'X':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 16);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf; break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf; break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'O':
+ sz++;
+ case 'o': // Octal integer
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 8);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf;break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf;break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf;break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'i':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(libc_vsscanf_buf[0] == '0')
+ {
+ if(libc_vsscanf_buf[1] == 'x' || libc_vsscanf_buf[1] == 'X')
+ i = 16;
+ else
+ i = 8;
+ }
+ else
+ i = 10;
+
+ buf = strtoll(libc_vsscanf_buf, &ep, i);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf; break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = (long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case '[':
+ i=0;
+ x=0; // Exclusion?
+ h=0; // Hyphen?
+
+ fp++;
+ i++;
+
+ while(format[fp])
+ {
+ if(format[fp] == '^' && i==1)
+ {
+ memset(libc_vsscanf_allow, 1, 256);
+ x = 1;
+ fp++; i++; continue;
+ }
+
+ if(x)
+ {
+ if(format[fp] == ']' && i>=3)
+ break;
+ }
+ else
+ {
+ if(format[fp] == ']' && i>=2)
+ break;
+ }
+
+ if(format[fp] == '-')
+ {
+ if(format[fp+1] != ']')
+ y = 1;
+ else
+ libc_vsscanf_allow['-'] = x^1;
+ }
+ else
+ {
+ if(y == 1)
+ {
+ if(format[fp] < format[fp-2])
+ libc_vsscanf_allow[format[fp]] = x^1;
+ else
+ for(z = format[fp-2]; z <= format[fp]; z++)
+ libc_vsscanf_allow[z] = x^1;
+
+ y = 0;
+
+ //printf("%s all chars from %c to %c\n", x?"Excluding":"Including",format[fp-2], format[fp]);
+ }
+ else
+ libc_vsscanf_allow[format[fp]] = x^1;
+ }
+
+ fp++;
+ i++;
+ }
+
+// Now as we know what our character set is, let's get data from the string
+ /* puts("Character set:");
+
+ for(y=0;y<16;y++)
+ {
+ for(x=0;x<16;x++)
+ if(libc_vsscanf_allow[(y*16) + x])
+ putchar((y*16)+x);
+ else
+ putchar('*');
+
+ putchar('\n');
+ }
+ */
+ i = 0;
+
+ while(libc_vsscanf_allow[str[sp]] && i<512)
+ libc_vsscanf_buf[i++] = str[sp++];
+
+ libc_vsscanf_buf[i] = 0;
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+ break;
+
+ case 'f': // Floating point number
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ fbuf = strtod(libc_vsscanf_buf, &ep);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char:
+ case scanf_s_short:
+ case scanf_s_int:
+ *(va_arg(ap, float*)) = (float)fbuf;
+ break;
+
+ case scanf_s_long:
+ case scanf_s_long_long:
+ *(va_arg(ap, double*)) = fbuf;
+ break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ }
+ }
+ else
+ {
+ if(format[fp] == '%')
+ {
+ conv = 1;
+ neg = 0;
+ suppress = 0;
+ sz = scanf_s_int;
+ fsz = 512;
+ def_fsz = 1;
+ exspace = 0;
+ alt = 0;
+ bzero(libc_vsscanf_allow, 256);
+ //chset = 0;
+ }
+ else if(format[fp] != ' ')
+ {
+ if(format[fp] != str[sp])
+ exit_loop=1;
+
+ sp++;
+ }
+
+ }
+
+ fp++;
+ }
+
+ return r;
+}
+
+int sscanf(const char *str, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+
+ va_start(ap, fmt);
+ r = vsscanf(str, fmt, ap);
+
+ va_end(ap);
+ return r;
+}
diff --git a/libpsn00b/libc/start.s b/libpsn00b/libc/start.s
new file mode 100644
index 0000000..c9b529b
--- /dev/null
+++ b/libpsn00b/libc/start.s
@@ -0,0 +1,39 @@
+# Start function!
+# This is essentially the entrypoint of the PS-EXE
+
+.set noreorder
+
+.section .text
+
+.global _start
+.type _start, @function
+_start:
+
+ addiu $sp, -32
+ sw $ra, 28($sp)
+
+ la $gp, _gp # Very important to set!
+
+ la $a0, .bss # What are the CORRECT symbols for BSS start and end?
+ la $a1, _end
+.clear_bss:
+ sb $0 , 0($a0)
+ blt $a0, $a1, .clear_bss
+ addiu $a0, 1
+
+ la $a0, _end+4 # Initialize heap for malloc (does not use BIOS maalloc)
+ li $a1, 1572864
+ jal InitHeap
+ nop
+
+ move $a0, $0 # No support for arguments for now
+ move $a1, $0
+
+ jal main
+ nop
+
+ lw $ra, 28($sp)
+ addiu $sp, 32
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/libc/string.c b/libpsn00b/libc/string.c
new file mode 100644
index 0000000..4943877
--- /dev/null
+++ b/libpsn00b/libc/string.c
@@ -0,0 +1,301 @@
+/*
+ * string.c
+ *
+ * Inherited from PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+int tolower(int chr)
+{
+ return (chr >='A' && chr<='Z') ? (chr + 32) : (chr);
+}
+
+int toupper(int chr)
+{
+ return (chr >='a' && chr<='z') ? (chr - 32) : (chr);
+}
+
+// Need to be replaced with MIPS assembler equivalents
+
+void *memchr(void *s , int c , int n)
+{
+ while(n--)
+ {
+ if(*((unsigned char*)s) == (unsigned char)c)
+ return s;
+
+ s++;
+ }
+
+ return NULL;
+}
+
+char *strncpy(char *dst, const char *src, int len)
+{
+ char *odst=dst;
+
+ while(*src && len)
+ {
+ *(dst++) = *(src++);
+ len--;
+ }
+
+ if(len)*dst = 0;
+
+ return odst;
+}
+
+char *strcpy(char *dst, const char *src)
+{
+ char *odst = dst;
+
+ while(*(dst++) = *(src++));
+ return odst;
+}
+
+char *strncat(char *s, const char *append, int len)
+{
+ char *o=s;
+
+ while(*s)
+ s++;
+
+ strncpy(s, append, len);
+
+ return o;
+}
+
+int strlen(const char *str)
+{
+ int i = 0;
+ while(*(str++))i++;
+ return i;
+}
+
+char *strchr(const char *s, int c)
+{
+ int x;
+
+ for(x = 0; x <= strlen(s); x++)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strrchr(const char *s, int c)
+{
+ int x;
+
+ for(x = strlen(s); x>=0; x--)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strpbrk(const char *s, const char *charset)
+{
+ int x,y;
+
+ for(x = 0; x < strlen(s); x++)
+ for(y = 0; y < strlen(charset); y++)
+ if(s[x] == charset[y]) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strstr(const char *big, const char *little)
+{
+ int ls = strlen(little);
+ int bs = strlen(big);
+ int x;
+
+ if(ls == 0)
+ return (char*)big;
+
+ if(ls > bs)
+ return NULL;
+
+ for(x = 0; x <= bs-ls; x++)
+ if(memcmp(little, &big[x], ls) == 0)
+ return (char*)&big[x];
+
+ return NULL;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+ while(*s1 && *s2 && (*s1 == *s2))
+ {
+ s1++;
+ s2++;
+ }
+
+ return *s1-*s2;
+}
+
+int strncmp(const char *s1, const char *s2, int len)
+{
+ int p = 0;
+
+ while(*s1 && *s2 && (*s1 == *s2) && p<len)
+ {
+ p++;
+
+ if(p<len)
+ {
+ s1++;
+ s2++;
+ }
+ }
+
+ return *s1-*s2;
+}
+
+// Requires a malloc implementation
+char *strdup(const char *str)
+{
+ char *ns = (void*)malloc(strlen(str) + 1);
+
+ if(ns == NULL)
+ return NULL;
+
+ strcpy(ns, str);
+ return ns;
+}
+
+char *strndup(const char *str, int len)
+{
+ int n=strlen(str);
+ char *ns = (void*)malloc((n+1)>len?len:(n+1));
+
+ if(ns == NULL)
+ return NULL;
+
+ strncpy(ns, str, (n+1)>len?len:(n+1));
+ return ns;
+}
+
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ int r = 0;
+ int t = 0;
+ int n = 0;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ n = 1;
+ }
+
+ if(base == 0)
+ if(*nptr == '0')
+ base = 8;
+ else
+ base = 10;
+
+ if(!(base >= 2 && base <= 36))
+ return 0;
+
+ if(base == 16 && *nptr == '0')
+ {
+ if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
+ nptr+=2;
+ }
+
+ while(*nptr)
+ {
+ switch(*nptr)
+ {
+ case '0'...'9':
+ t = *nptr - '0';
+ break;
+ case 'a' ... 'z':
+ t = (*nptr - 'a') + 10;
+ break;
+ case 'A' ... 'Z':
+ t = (*nptr - 'A') + 10;
+ break;
+ default:
+ t = 1000;
+ break;
+ }
+
+ if(t>=base)
+ break;
+
+ r*=base;
+ r+=t;
+ nptr++;
+ }
+
+ if(endptr)*endptr = (char*)nptr;
+ return n?-r:r;
+}
+
+long strtol(const char *nptr, char **endptr, int base)
+{
+ return (long)strtoll(nptr, endptr, base);
+}
+
+double strtod(const char *nptr, char **endptr)
+{
+ char strbuf[64];
+ int x = 0;
+ int y;
+ double i=0, d=0;
+ int s=1;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ s=-1;
+ }
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 18)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ i = (double)strtoll(strbuf, NULL, 10);
+
+ if(*nptr == '.')
+ {
+ nptr++;
+ x = 0;
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 7)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ if(endptr != NULL) *endptr = (char*)nptr;
+
+ y=1;
+
+ for(x=0;x<strlen(strbuf);x++)
+ y*=10;
+
+ d = (double)strtoll(strbuf, NULL, 10);
+ d /= y;
+ }
+ else
+ {
+ if(endptr != NULL)
+ *endptr = (char*)nptr;
+ }
+
+ return (i + d)*s;
+}
+
+long double strtold(const char *nptr, char **endptr)
+{
+ return (long double)strtod(nptr, endptr);
+}
+
+float strtof(const char *nptr, char **endptr)
+{
+ return (float)strtod(nptr, endptr);
+}
diff --git a/libpsn00b/lzp/bit.c b/libpsn00b/lzp/bit.c
new file mode 100644
index 0000000..aefa45d
--- /dev/null
+++ b/libpsn00b/lzp/bit.c
@@ -0,0 +1,65 @@
+#include "bit.h"
+
+// Bit I/O
+//
+
+unsigned char* inPtr = 0;
+int inBytes = 0;
+unsigned char* outPtr = 0;
+int outBytes = 0;
+
+int bit_buf;
+int bit_count;
+
+void init_bits() {
+
+ bit_count = bit_buf=0;
+
+}
+
+void put_bits(int n, int x) {
+
+ bit_buf |= x<<bit_count;
+ bit_count += n;
+
+ while(bit_count >= 8) {
+
+ *outPtr = bit_buf;
+ outPtr++;
+ outBytes++;
+
+ bit_buf >>= 8;
+ bit_count -= 8;
+
+ }
+
+}
+
+void flush_bits() {
+
+ put_bits(7, 0);
+ bit_count = bit_buf = 0;
+
+}
+
+int get_bits(int n) {
+
+ int x;
+
+ while(bit_count < n) {
+
+ bit_buf |= *inPtr<<bit_count;
+ inPtr++;
+ inBytes++;
+
+ bit_count += 8;
+
+ }
+
+ x = bit_buf&((1<<n)-1);
+ bit_buf >>= n;
+ bit_count -= n;
+
+ return(x);
+
+}
diff --git a/libpsn00b/lzp/bit.h b/libpsn00b/lzp/bit.h
new file mode 100644
index 0000000..ff71025
--- /dev/null
+++ b/libpsn00b/lzp/bit.h
@@ -0,0 +1,26 @@
+#ifndef _LZP_BIT_H
+#define _LZP_BIT_H
+
+extern unsigned char* inPtr;
+extern int inBytes;
+extern unsigned char* outPtr;
+extern int outBytes;
+
+extern int bit_buf;
+extern int bit_count;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void init_bits();
+void put_bits(int n, int x);
+void flush_bits();
+int get_bits(int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _LZP_BIT_H
diff --git a/libpsn00b/lzp/compress.c b/libpsn00b/lzp/compress.c
new file mode 100644
index 0000000..33af08d
--- /dev/null
+++ b/libpsn00b/lzp/compress.c
@@ -0,0 +1,488 @@
+// Based on ilia muraviev's CRUSH compressor program which falls under public domain
+
+#include <string.h>
+#if LZP_USE_MALLOC == TRUE
+#include <stdlib.h>
+#endif
+
+#include "lzconfig.h"
+#include "bit.h"
+#include "lzp.h"
+
+
+// Internal structure for hash table allocation sizes
+#if LZP_NO_COMPRESS == FALSE
+
+struct {
+ short WindowSize; // Window size (17 - 23)
+ short Hash1Size; // Hash 1 table size (10 - 21)
+ short Hash2Size; // Hash 2 table size (12 - 24)
+} lzHashParam = {
+ LZP_WINDOW_SIZE,
+ LZP_HASH1_SIZE,
+ LZP_HASH2_SIZE
+};
+
+#endif
+
+
+// Defines and macros for lz77 compression/decompression (don't touch)
+#define W_BITS lzHashParam.WindowSize
+#define HASH1_BITS lzHashParam.Hash1Size
+#define HASH2_BITS lzHashParam.Hash2Size
+
+#define W_SIZE (1<<W_BITS)
+#define W_MASK (W_SIZE-1)
+#define SLOT_BITS 4
+#define NUM_SLOTS (1<<SLOT_BITS)
+
+#define A_BITS 2 // 1 xx
+#define B_BITS 2 // 01 xx
+#define C_BITS 2 // 001 xx
+#define D_BITS 3 // 0001 xxx
+#define E_BITS 5 // 00001 xxxxx
+#define F_BITS 9 // 00000 xxxxxxxxx
+#define A (1<<A_BITS)
+#define B ((1<<B_BITS)+A)
+#define C ((1<<C_BITS)+B)
+#define D ((1<<D_BITS)+C)
+#define E ((1<<E_BITS)+D)
+#define F ((1<<F_BITS)+E)
+#define MIN_MATCH 3
+#define MAX_MATCH ((F-1)+MIN_MATCH)
+
+#define BUF_SIZE (1<<26)
+#define TOO_FAR (1<<16)
+
+#define HASH1_LEN MIN_MATCH
+#define HASH2_LEN (MIN_MATCH+1)
+#define HASH1_SIZE (1<<HASH1_BITS)
+#define HASH2_SIZE (1<<HASH2_BITS)
+#define HASH1_MASK (HASH1_SIZE-1)
+#define HASH2_MASK (HASH2_SIZE-1)
+#define HASH1_SHIFT ((HASH1_BITS+(HASH1_LEN-1))/HASH1_LEN)
+#define HASH2_SHIFT ((HASH2_BITS+(HASH2_LEN-1))/HASH2_LEN)
+
+
+// LZ77
+//
+
+#if LZP_NO_COMPRESS == FALSE
+
+int update_hash1(int h, int c) {
+
+ return(((h<<HASH1_SHIFT)+c)&HASH1_MASK);
+
+}
+
+int update_hash2(int h, int c) {
+
+ return(((h<<HASH2_SHIFT)+c)&HASH2_MASK);
+
+}
+
+int get_min(int a, int b) {
+
+ return(a<b?a:b);
+
+}
+
+int get_max(int a, int b) {
+
+ return(a>b?a:b);
+
+}
+
+int get_penalty(int a, int b) {
+
+ int p=0;
+
+ while(a > b) {
+ a >>= 3;
+ ++p;
+ }
+
+ return(p);
+
+}
+
+int lzCompress(void* outBuff, void* inBuff, int inSize, int level) {
+
+ #if LZP_USE_MALLOC == FALSE
+ int head[HASH1_SIZE+HASH2_SIZE];
+ int prev[W_SIZE];
+ #else
+ int* head = malloc(4*(HASH1_SIZE+HASH2_SIZE));
+ int* prev = malloc(4*W_SIZE);
+ #endif
+
+
+ int max_chain[] = {4, 256, 1<<12};
+
+ int i,s;
+ int h1=0;
+ int h2=0;
+ int p=0;
+
+ int len;
+ int offset;
+
+ int max_match;
+ int limit;
+
+ int chain_len;
+ int next_p;
+ int max_lazy;
+ int log;
+
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ outBytes = 0;
+
+
+ for (i=0; i<HASH1_SIZE+HASH2_SIZE; ++i)
+ head[i] = -1;
+
+ for (i=0; i<HASH1_LEN; ++i)
+ h1=update_hash1(h1, inPtr[i]);
+
+ for (i=0; i<HASH2_LEN; ++i)
+ h2=update_hash2(h2, inPtr[i]);
+
+ init_bits();
+
+ // Put window size value so that the compressed data will be independent of the compression settings
+ put_bits(5, lzHashParam.WindowSize);
+
+ while(p < inSize) {
+
+ len = MIN_MATCH-1;
+ offset = W_SIZE;
+
+ max_match = get_min(MAX_MATCH, inSize-p);
+ limit = get_max(p-W_SIZE, 0);
+
+ if (head[h1] >= limit) {
+
+ s = head[h1];
+
+ if (inPtr[s] == inPtr[p]) {
+
+ i = 0;
+
+ while(++i < max_match) {
+ if (inPtr[s+i] != inPtr[p+i])
+ break;
+ }
+
+ if (i > len) {
+ len = i;
+ offset = p-s;
+ }
+
+ }
+
+ }
+
+ if (len < MAX_MATCH) {
+
+ chain_len = max_chain[level];
+ s = head[h2+HASH1_SIZE];
+
+ while((chain_len-- != 0) && (s >= limit)) {
+
+ if ((inPtr[s+len] == inPtr[p+len]) && (inPtr[s] == inPtr[p])) {
+
+ i = 0;
+
+ while(++i < max_match) {
+ if (inPtr[s+i] != inPtr[p+i])
+ break;
+ }
+
+ if (i > len+get_penalty((p-s)>>4, offset)) {
+ len = i;
+ offset = p-s;
+ }
+
+ if (i == max_match)
+ break;
+
+ }
+
+ s=prev[s&W_MASK];
+
+ }
+
+ }
+
+ if ((len == MIN_MATCH) && (offset > TOO_FAR))
+ len=0;
+
+ if ((level >= 2) && (len >= MIN_MATCH) && (len < max_match)) {
+
+ next_p = p+1;
+ max_lazy = get_min(len+4, max_match);
+
+ chain_len = max_chain[level];
+ s = head[update_hash2(h2, inPtr[next_p+(HASH2_LEN-1)])+HASH1_SIZE];
+
+ while((chain_len-- != 0) && (s >= limit)) {
+
+ if ((inPtr[s+len] == inPtr[next_p+len]) && (inPtr[s] == inPtr[next_p])) {
+
+ i = 0;
+
+ while(++i < max_lazy) {
+ if (inPtr[s+i] != inPtr[next_p+i])
+ break;
+ }
+
+ if (i > len+get_penalty(next_p-s, offset)) {
+ len = 0;
+ break;
+ }
+
+ if (i == max_lazy)
+ break;
+
+ }
+
+ s = prev[s&W_MASK];
+
+ }
+
+ }
+
+
+ if (len >= MIN_MATCH) { // Match
+
+ put_bits(1, 1);
+
+ i = len-MIN_MATCH;
+
+ if (i < A) {
+ put_bits(1, 1); // 1
+ put_bits(A_BITS, i);
+ } else if (i < B) {
+ put_bits(2, 1<<1); // 01
+ put_bits(B_BITS, i-A);
+ } else if (i < C) {
+ put_bits(3, 1<<2); // 001
+ put_bits(C_BITS, i-B);
+ } else if (i < D) {
+ put_bits(4, 1<<3); // 0001
+ put_bits(D_BITS, i-C);
+ } else if (i < E) {
+ put_bits(5, 1<<4); // 00001
+ put_bits(E_BITS, i-D);
+ } else {
+ put_bits(5, 0); // 00000
+ put_bits(F_BITS, i-E);
+ }
+
+ --offset;
+ log = W_BITS-NUM_SLOTS;
+
+ while(offset >= (2<<log))
+ ++log;
+
+ put_bits(SLOT_BITS, log-(W_BITS-NUM_SLOTS));
+
+ if (log>(W_BITS-NUM_SLOTS))
+ put_bits(log, offset-(1<<log));
+ else
+ put_bits(W_BITS-(NUM_SLOTS-1), offset);
+
+ } else { // Literal
+
+ len = 1;
+ put_bits(9, inPtr[p]<<1); // 0 xxxxxxxx
+
+ }
+
+ while(len-- != 0) { // Insert new strings
+
+ head[h1] = p;
+ prev[p&W_MASK] = head[h2+HASH1_SIZE];
+ head[h2+HASH1_SIZE] = p;
+
+ ++p;
+
+ h1 = update_hash1(h1, inPtr[p+(HASH1_LEN-1)]);
+ h2 = update_hash2(h2, inPtr[p+(HASH2_LEN-1)]);
+
+ }
+
+ }
+
+ flush_bits();
+
+ #if LZP_USE_MALLOC == TRUE
+ free(head);
+ free(prev);
+ #endif
+
+ return(outBytes);
+
+}
+
+void lzSetHashSizes(int window, int hash1, int hash2) {
+
+ lzHashParam.WindowSize = window;
+ lzHashParam.Hash1Size = hash1;
+ lzHashParam.Hash2Size = hash2;
+
+}
+
+void lzResetHashSizes() {
+
+ lzHashParam.WindowSize = LZP_WINDOW_SIZE;
+ lzHashParam.Hash1Size = LZP_HASH1_SIZE;
+ lzHashParam.Hash2Size = LZP_HASH2_SIZE;
+
+}
+
+#endif // LZP_NO_COMPRESS
+
+int lzDecompress(void* outBuff, void* inBuff, int inSize) {
+
+ int p=0;
+ int len;
+ int log;
+ int s;
+ int windowSize;
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ inBytes = 0;
+ outBytes = 0;
+
+ init_bits();
+
+ // Get window size value
+ windowSize = get_bits(5);
+
+ while(inBytes < inSize) {
+
+ if (get_bits(1)) {
+
+ if (get_bits(1))
+ len = get_bits(A_BITS);
+ else if (get_bits(1))
+ len = get_bits(B_BITS)+A;
+ else if (get_bits(1))
+ len = get_bits(C_BITS)+B;
+ else if (get_bits(1))
+ len = get_bits(D_BITS)+C;
+ else if (get_bits(1))
+ len = get_bits(E_BITS)+D;
+ else
+ len = get_bits(F_BITS)+E;
+
+ log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
+
+ s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
+
+ if (s < 0)
+ return(LZP_ERR_DECOMPRESS);
+
+ outPtr[p++] = outPtr[s++];
+ outPtr[p++] = outPtr[s++];
+ outPtr[p++] = outPtr[s++];
+
+ while(len-- != 0)
+ outPtr[p++] = outPtr[s++];
+
+ } else {
+
+ outPtr[p++] = get_bits(8);
+
+ }
+
+ }
+
+ return(p);
+
+}
+
+int lzDecompressLen(void* outBuff, int outSize, void* inBuff, int inSize) {
+
+ int p=0;
+ int len;
+ int log;
+ int s;
+ int windowSize;
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ inBytes = 0;
+ outBytes = 0;
+
+ init_bits();
+
+ // Get window size value
+ windowSize = get_bits(5);
+
+ while(inBytes < inSize) {
+
+ if (get_bits(1)) {
+
+ if (get_bits(1))
+ len = get_bits(A_BITS);
+ else if (get_bits(1))
+ len = get_bits(B_BITS)+A;
+ else if (get_bits(1))
+ len = get_bits(C_BITS)+B;
+ else if (get_bits(1))
+ len = get_bits(D_BITS)+C;
+ else if (get_bits(1))
+ len = get_bits(E_BITS)+D;
+ else
+ len = get_bits(F_BITS)+E;
+
+ log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
+
+ s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
+
+ if (s < 0)
+ return(LZP_ERR_DECOMPRESS);
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ while(len-- != 0) {
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ }
+
+ if (p >= outSize)
+ break;
+
+ } else {
+
+ outPtr[p++] = get_bits(8);
+
+ }
+
+ if (p >= outSize)
+ break;
+
+ }
+
+ return(p);
+
+}
diff --git a/libpsn00b/lzp/crc.c b/libpsn00b/lzp/crc.c
new file mode 100644
index 0000000..c5ab702
--- /dev/null
+++ b/libpsn00b/lzp/crc.c
@@ -0,0 +1,91 @@
+#include "lzp.h"
+
+void initTable16(unsigned short* table) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = (unsigned short) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x0001 )
+ crc = ( crc >> 1 ) ^ 0xA001;
+ else
+ crc = crc >> 1;
+
+ c = c >> 1;
+ }
+
+ table[i] = crc;
+ }
+
+}
+
+void initTable32(unsigned int* table) {
+
+ int i,j;
+ unsigned int crcVal;
+
+ for(i=0; i<256; i++) {
+
+ crcVal = i;
+
+ for(j=0; j<8; j++) {
+
+ if (crcVal&0x00000001L)
+ crcVal = (crcVal>>1)^0xEDB88320L;
+ else
+ crcVal = crcVal>>1;
+
+ }
+
+ table[i] = crcVal;
+
+ }
+
+}
+
+unsigned short lzCRC16(void* buff, int bytes, unsigned short crc) {
+
+ int i;
+ unsigned short tmp, short_c;
+ unsigned short crcTable[256];
+
+ initTable16(crcTable);
+
+ for(i=0; i<bytes; i++) {
+
+ short_c = 0x00ff & (unsigned short)((unsigned char*)buff)[i];
+
+ tmp = crc ^ short_c;
+ crc = (crc >> 8) ^ crcTable[tmp&0xff];
+
+ }
+
+ return(crc);
+
+}
+
+unsigned int lzCRC32(void* buff, int bytes, unsigned int crc) {
+
+ int i;
+ unsigned char* byteBuff = (unsigned char*)buff;
+ unsigned int byte;
+ unsigned int crcTable[256];
+
+ initTable32(crcTable);
+
+ for(i=0; i<bytes; i++) {
+
+ byte = 0x000000ffL&(unsigned int)byteBuff[i];
+ crc = (crc>>8)^crcTable[(crc^byte)&0xff];
+
+ }
+
+ return(crc^0xFFFFFFFF);
+
+}
diff --git a/libpsn00b/lzp/lzp.c b/libpsn00b/lzp/lzp.c
new file mode 100644
index 0000000..1f4fea4
--- /dev/null
+++ b/libpsn00b/lzp/lzp.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "lzp.h"
+
+
+static char* lcase(char* text) {
+
+ int i;
+
+ for(i=0; text[i]!=0x00; i++)
+ text[i] = tolower(text[i]);
+
+ return(text);
+
+}
+
+
+int lzpSearchFile(const char* fileName, void* lzpack) {
+
+ int i;
+ char searchName[16];
+ char compareName[16];
+ LZP_FILE* fileEntry;
+
+ strcpy(searchName, fileName);
+ lcase(searchName);
+
+ fileEntry = (LZP_FILE*)(lzpack+4);
+ for(i=0; i<((LZP_HEAD*)lzpack)->numFiles; i++) {
+
+ strcpy(compareName, fileEntry[i].fileName);
+ lcase(compareName);
+
+ if (strcmp(searchName, compareName) == 0)
+ return(i);
+
+ }
+
+ return(LZP_ERR_NOTFOUND);
+
+}
+
+LZP_FILE* lzpFileEntry(void* lzpack, int fileNum) {
+
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return(NULL);
+
+ if ((fileNum < 0) || (fileNum > (((LZP_HEAD*)lzpack)->numFiles-1)))
+ return(NULL);
+
+ return(&((LZP_FILE*)(lzpack+4))[fileNum]);
+
+}
+
+int lzpFileSize(void* lzpack, int fileNum) {
+
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return 0;
+
+ if ((fileNum < 0) || (fileNum > (((LZP_HEAD*)lzpack)->numFiles-1)))
+ return 0;
+
+ return ((LZP_FILE*)(lzpack+4))[fileNum].fileSize;
+}
+
+int lzpUnpackFile(void* buff, void* lzpack, int fileNum) {
+
+ LZP_FILE* fileEntry = &((LZP_FILE*)(lzpack+4))[fileNum];
+ int unpackedSize;
+
+ // Check ID header
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return(LZP_ERR_INVALID_PACK);
+
+ // Do a CRC16 check of the compressed data's integrity
+ if (lzCRC32(lzpack+fileEntry->offset, fileEntry->packedSize, LZP_CRC32_REMAINDER) != fileEntry->crc)
+ return(LZP_ERR_CRC_MISMATCH);
+
+ // Decompress data to the specified address
+ unpackedSize = lzDecompress(buff, lzpack+fileEntry->offset, fileEntry->packedSize);
+ if (unpackedSize < 0)
+ return(unpackedSize);
+
+ return(unpackedSize);
+
+}
diff --git a/libpsn00b/lzp/lzp.h b/libpsn00b/lzp/lzp.h
new file mode 100644
index 0000000..ffd7933
--- /dev/null
+++ b/libpsn00b/lzp/lzp.h
@@ -0,0 +1,223 @@
+/*! \file lzp.h
+ * \brief Main library header
+ */
+
+/*! \mainpage
+ * \version 0.20b
+ * \author John Wilbert 'Lameguy64' Villamor
+ *
+ * \section creditsSection Credits
+ * - LZ77 data compression/decompression routines based from Ilya Muravyov's
+ * crush.cpp released under public domain. Refined and ported to C by Lameguy64.
+ * - CRC calculation routines based from Lammert Bies' lib_crc routines.
+ *
+ */
+
+#ifndef _LZPACK_H
+#define _LZPACK_H
+
+#include <sys/types.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+/*! \addtogroup crcBaseRemainders CRC Base Remainder Values
+ * @{
+ */
+//! Initial remainder value for lzCRC16()
+#define LZP_CRC16_REMAINDER 0x0000
+//! Initial remainder value for lzCRC32()
+#define LZP_CRC32_REMAINDER 0xFFFFFFFF
+/*! @} */
+
+
+/*! \addtogroup compLevels Compression Levels
+ * \brief Compression levels for the lzCompress() function.
+ * @{
+ */
+//! Minimal (but fast) compression
+#define LZP_COMPRESS_FAST 0
+//! Normal compression level
+#define LZP_COMPRESS_NORMAL 1
+//! Maximum compression level
+#define LZP_COMPRESS_MAX 2
+/*! @} */
+
+
+/*! \addtogroup libraryErrorCodes Library Error Codes
+ * @{
+ */
+//! No error
+#define LZP_ERR_NONE 0
+//! Decompression error
+#define LZP_ERR_DECOMPRESS -1
+//! Not a valid LZP/QLP/PCK archive
+#define LZP_ERR_INVALID_PACK -2
+//! File not found
+#define LZP_ERR_NOTFOUND -3
+//! CRC check mismatch (data corruption)
+#define LZP_ERR_CRC_MISMATCH -4
+/*! @} */
+
+
+//! Header structure of an LZP format archive file
+typedef struct {
+
+ //! File ID (must always be 'LZP')
+ char id[3];
+ //! File count
+ u_char numFiles;
+
+} LZP_HEAD;
+
+//! File entry structure for an LZP format archive file
+typedef struct {
+
+ //! File name
+ char fileName[16];
+ //! CRC32 checksum of file
+ u_int crc;
+ //! Original size of file in bytes
+ u_int fileSize;
+ //! Compressed size of file
+ u_int packedSize;
+ //! File data offset
+ u_int offset;
+
+} LZP_FILE;
+
+
+// Function prototypes
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*! \addtogroup compressFuncs Data Compression and Decompression Functions
+ * \brief Functions to compress and decompress data.
+ * @{
+ */
+
+/*! Compress a block of data.
+ *
+ * \details This function compresses a specified block of data in LZ77 encoding.
+ * Depending on the size of the input data and speed of the computer, compression
+ * may take a while to complete.
+ *
+ * \param[out] *outBuff Pointer to buffer to store compressed data.
+ * \param[in] *inBuff Pointer to data to compress.
+ * \param[in] inSize Size of data to compress in bytes.
+ * \param[in] level Compression level (see \ref compLevels).
+ *
+ * \returns The size of the compressed data in bytes.
+ */
+int lzCompress(void* outBuff, void* inBuff, int inSize, int level);
+
+/*! Decompress a compressed block of data.
+ *
+ * \details Decompressed a compressed block of data produced by lzCompress(). It cannot
+ * return the decompressed size of the data ahead of time so you must preserve the decompressed
+ * size of the data yourself.
+ *
+ * \note The decompression algorithm used in this function is completely independent
+ * of the compression settings set by lzSetHashSizes() before compressing the data with
+ * lzCompress().
+ *
+ * \param[out] *outBuff Pointer to buffer to store decompressed data.
+ * \param[in] *inBuff Pointer to compressed data to decompress.
+ * \param[in] inSize Compressed data size in bytes.
+ *
+ * \returns Size of decompressed data in bytes or LZP_ERR_DECOMPRESS if a
+ * decompression error occurred.
+ */
+int lzDecompress(void* outBuff, void* inBuff, int inSize);
+
+int lzDecompressLen(void* outBuff, int outSize, void* inBuff, int inSize);
+
+/*! Sets the sizes of hash tables for data compression.
+ *
+ * \param[in] window Sliding window size.
+ * \param[in] hash1 Hash table 1 size.
+ * \param[in] hash2 Hash table 2 size.
+ */
+void lzSetHashSizes(int window, int hash1, int hash2);
+
+/*! Reset the sizes of hash tables to their defaults.
+ */
+void lzResetHashSizes();
+
+/*! @} */
+
+
+/*! \addtogroup crcFuncs CRC Hashing Functions
+ * \brief Functions to calculate CRC hashes of data.
+ * @{
+ */
+
+/*! Calculates a CRC16 hash of the specified buffer.
+ *
+ * \param[in] *buff Pointer to buffer to calculate a hash of.
+ * \param[in] bytes Size of buffer in bytes.
+ * \param[in] crc CRC remainder (use LZP_CRC16_REMAINDER).
+ *
+ * \returns CRC16 hash of specified buffer.
+ */
+unsigned short lzCRC16(void* buff, int bytes, unsigned short crc);
+
+/*! Calculates a CRC32 hash of the specified buffer.
+ *
+ * \param[in] *buff Pointer to buffer to calculate a hash of.
+ * \param[in] bytes Size of buffer in bytes.
+ * \param[in] crc CRC remainder (use LZP_CRC16_REMAINDER).
+ *
+ * \returns CRC32 hash of specified buffer.
+ */
+unsigned int lzCRC32(void* buff, int bytes, unsigned int crc);
+
+/*! @} */
+
+
+/*! \addtogroup lzpFunctions LZP Archive Handling Routines
+ * \brief Functions to index and unpack files from LZP archives.
+ * @{
+ */
+
+/*! Searches for a file by name in an LZP archive and returns a file entry number.
+ *
+ * \param[in] *fileName String of file to search (must be less than 13 characters).
+ * \param[in] *lzpack Pointer to LZP archive file.
+ *
+ * \returns File index of found file or one of \ref libraryErrorCodes if an error occurred.
+ */
+int lzpSearchFile(const char* fileName, void* lzpack);
+
+int lzpFileSize(void* lzpack, int fileNum);
+
+/*! Get a pointer to a file entry inside of an LZP archive.
+ *
+ * \param[in] *lzpack Pointer to LZP archive file.
+ * \param[in] fileNum File number to get an entry of (you may use lzpSearchFile()).
+ *
+ * \returns A pointer to an LZP_FILE struct or NULL if an error occurred.
+ */
+LZP_FILE* lzpFileEntry(void* lzpack, int fileNum);
+
+/*! Unpacks a file from an LZP archive to the specified memory buffer.
+ *
+ * \param[in] *buff Pointer to buffer to store unpacked file.
+ * \param[in] *lzpack Pointer to LZP archive file.
+ * \param[in] fileNum File entry number of file to extract (you may use lzpSearchFile()).
+ *
+ * \returns Size of decompressed file in bytes or one of \ref libraryErrorCodes if an error occurred.
+ */
+int lzpUnpackFile(void* buff, void* lzpack, int fileNum);
+
+/*! @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _LZPACK_H
diff --git a/libpsn00b/lzp/lzqlp.h b/libpsn00b/lzp/lzqlp.h
new file mode 100644
index 0000000..fae6438
--- /dev/null
+++ b/libpsn00b/lzp/lzqlp.h
@@ -0,0 +1,26 @@
+#ifndef _QLP_H
+#define _QLP_H
+
+#define PACK_ERR_NONE 0
+#define PACK_ERR_INVALID -1
+#define PACK_ERR_NOTFOUND -2
+#define PACK_ERR_INCOMPLETE -3
+#define PACK_ERR_READ_FAULT -4
+
+typedef struct {
+ char id[3];
+ unsigned char numfiles;
+} QLP_HEAD;
+
+typedef struct {
+ char name[16];
+ unsigned int size;
+ unsigned int offs;
+} QLP_FILE;
+
+int qlpFileCount(void* qlpfile);
+QLP_FILE* qlpFileEntry(int index, void* qlpfile);
+void* qlpFileAddr(int index, void* qlpfile);
+int qlpFindFile(char* fileName, void* qlpfile);
+
+#endif // _QLP_H \ No newline at end of file
diff --git a/libpsn00b/lzp/makefile b/libpsn00b/lzp/makefile
new file mode 100644
index 0000000..cf82872
--- /dev/null
+++ b/libpsn00b/lzp/makefile
@@ -0,0 +1,28 @@
+PREFIX = mipsel-unknown-elf-
+
+TARGET = liblzp.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+OFILES = $(addprefix build/,$(CFILES:.c=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -nostdlib -Wa,--strip-local-absolute
+AFLAGS = -msoft-float --strip-local-absolute
+
+CC = $(PREFIX)gcc
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p build
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -Rf build $(OFILES) $(TARGET)
diff --git a/libpsn00b/lzp/qlp.c b/libpsn00b/lzp/qlp.c
new file mode 100644
index 0000000..3be8356
--- /dev/null
+++ b/libpsn00b/lzp/qlp.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lzqlp.h"
+
+static char* lcase(char* str) {
+
+ while(*str != 0x00) {
+ *str = tolower(*str);
+ str++;
+ }
+
+ return(str);
+
+}
+
+int qlpFileCount(void* qlpfile) {
+
+ if (strncmp(((QLP_HEAD*)qlpfile)->id, "QLP", 3) != 0)
+ return(PACK_ERR_INVALID);
+
+ return(((QLP_HEAD*)qlpfile)->numfiles);
+
+}
+
+QLP_FILE* qlpFileEntry(int index, void* qlpfile) {
+
+ if (strncmp(((QLP_HEAD*)qlpfile)->id, "QLP", 3) != 0)
+ return(NULL);
+
+ if (index > ((QLP_HEAD*)qlpfile)->numfiles)
+ return(NULL);
+
+ return(&((QLP_FILE*)(qlpfile+4))[index]);
+
+}
+
+void* qlpFileAddr(int index, void* qlpfile) {
+
+ return( qlpfile+((QLP_FILE*)(qlpfile+4))[index].offs );
+
+}
+
+int qlpFindFile(char* fileName, void* qlpfile) {
+
+ int i;
+ char nameBuff[2][16];
+
+ strcpy(nameBuff[0], fileName);
+ lcase(nameBuff[0]);
+
+ for(i=0; i<((QLP_HEAD*)qlpfile)->numfiles; i++) {
+
+ strcpy(nameBuff[1], ((QLP_FILE*)(qlpfile+4))[i].name);
+ lcase(nameBuff[1]);
+
+ if (strcmp(nameBuff[0], nameBuff[1]) == 0)
+ return(i);
+
+ }
+
+ return(PACK_ERR_NOTFOUND);
+
+} \ No newline at end of file
diff --git a/libpsn00b/makefile b/libpsn00b/makefile
new file mode 100644
index 0000000..bcfc9a5
--- /dev/null
+++ b/libpsn00b/makefile
@@ -0,0 +1,16 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+TOPTARGETS = all clean
+
+LIBDIRS = libc lzp psxgpu psxgte psxapi psxetc psxspu
+
+
+$(TOPTARGETS): $(LIBDIRS)
+$(LIBDIRS):
+ @$(MAKE) -C $@ $(MAKECMDGOALS)
+
+clean: $(LIBDIRS)
+
+.PHONY: $(TOPTARGETS) $(LIBDIRS)
diff --git a/libpsn00b/psxapi/fs/_96_init.s b/libpsn00b/psxapi/fs/_96_init.s
new file mode 100644
index 0000000..ac35d6b
--- /dev/null
+++ b/libpsn00b/psxapi/fs/_96_init.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global _96_init
+.type _96_init, @function
+_96_init:
+ addiu $t2, $0 , 0xa0
+ jr $t2
+ addiu $t1, $0 , 0x71
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/_96_remove.s b/libpsn00b/psxapi/fs/_96_remove.s
new file mode 100644
index 0000000..a65c0ba
--- /dev/null
+++ b/libpsn00b/psxapi/fs/_96_remove.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global _96_remove
+.type _96_remove, @function
+_96_remove:
+ addiu $t2, $0 , 0xa0
+ jr $t2
+ addiu $t1, $0 , 0x72
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/chdir.s b/libpsn00b/psxapi/fs/chdir.s
new file mode 100644
index 0000000..83abf70
--- /dev/null
+++ b/libpsn00b/psxapi/fs/chdir.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global chdir
+.type chdir, @function
+chdir:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x40
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/erase.s b/libpsn00b/psxapi/fs/erase.s
new file mode 100644
index 0000000..0ddd05f
--- /dev/null
+++ b/libpsn00b/psxapi/fs/erase.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global erase
+.type erase, @function
+erase:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x45
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/firstfile.s b/libpsn00b/psxapi/fs/firstfile.s
new file mode 100644
index 0000000..2d1c1cd
--- /dev/null
+++ b/libpsn00b/psxapi/fs/firstfile.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global firstfile
+.type firstfile, @function
+firstfile:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x42
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/nextfile.s b/libpsn00b/psxapi/fs/nextfile.s
new file mode 100644
index 0000000..51a285a
--- /dev/null
+++ b/libpsn00b/psxapi/fs/nextfile.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global nextfile
+.type nextfile, @function
+nextfile:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x43
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/fs/rename.s b/libpsn00b/psxapi/fs/rename.s
new file mode 100644
index 0000000..5815dba
--- /dev/null
+++ b/libpsn00b/psxapi/fs/rename.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global rename
+.type rename, @function
+rename:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x44
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/makefile b/libpsn00b/psxapi/makefile
new file mode 100644
index 0000000..30c1522
--- /dev/null
+++ b/libpsn00b/psxapi/makefile
@@ -0,0 +1,34 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libpsxapi.a
+
+SOURCES = stdio fs sys
+
+AFILES = $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.s))
+OFILES = $(addprefix build/,$(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+AFLAGS = -msoft-float -Wa,--strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -Rf build $(TARGET)
diff --git a/libpsn00b/psxapi/stdio/close.s b/libpsn00b/psxapi/stdio/close.s
new file mode 100644
index 0000000..6d52762
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/close.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global close
+.type close, @function
+close:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x04
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/getc.s b/libpsn00b/psxapi/stdio/getc.s
new file mode 100644
index 0000000..2a93af6
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/getc.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global getc
+.type getc, @function
+getc:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x08
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/ioctl.s b/libpsn00b/psxapi/stdio/ioctl.s
new file mode 100644
index 0000000..9ba17e6
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/ioctl.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global ioctl
+.type ioctl, @function
+ioctl:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x05
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/open.s b/libpsn00b/psxapi/stdio/open.s
new file mode 100644
index 0000000..ce8c684
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/open.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global open
+.type open, @function
+open:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x00
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/printf.s b/libpsn00b/psxapi/stdio/printf.s
new file mode 100644
index 0000000..64f1390
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/printf.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global printf
+.type printf, @function
+printf:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x3f
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/putc.s b/libpsn00b/psxapi/stdio/putc.s
new file mode 100644
index 0000000..7c73241
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/putc.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global putchar
+.type putc, @function
+putchar:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x09
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/read.s b/libpsn00b/psxapi/stdio/read.s
new file mode 100644
index 0000000..4209232
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/read.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global read
+.type read, @function
+read:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x02
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/seek.s b/libpsn00b/psxapi/stdio/seek.s
new file mode 100644
index 0000000..944afd9
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/seek.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global seek
+.type seek, @function
+seek:
+ addiu $t2, $0, 0xA0
+ jr $t2
+ addiu $t1, $0, 0x01
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/stdio/write.s b/libpsn00b/psxapi/stdio/write.s
new file mode 100644
index 0000000..c451952
--- /dev/null
+++ b/libpsn00b/psxapi/stdio/write.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global write
+.type write, @function
+write:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x03
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/adddev.s b/libpsn00b/psxapi/sys/adddev.s
new file mode 100644
index 0000000..7fa717d
--- /dev/null
+++ b/libpsn00b/psxapi/sys/adddev.s
@@ -0,0 +1,10 @@
+.set noreorder
+
+.section .text
+
+.global AddDev
+.type AddDev, @function
+AddDev:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x47 \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/b_initheap.s b/libpsn00b/psxapi/sys/b_initheap.s
new file mode 100644
index 0000000..7411dd6
--- /dev/null
+++ b/libpsn00b/psxapi/sys/b_initheap.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global b_InitHeap
+.type b_InitHeap, @function
+b_InitHeap:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x39
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/changeclearpad.s b/libpsn00b/psxapi/sys/changeclearpad.s
new file mode 100644
index 0000000..509b03f
--- /dev/null
+++ b/libpsn00b/psxapi/sys/changeclearpad.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global ChangeClearPAD
+.type ChangeClearPAD, @function
+ChangeClearPAD:
+ addiu $t2, $0 , 0xb0
+ jr $t2
+ addiu $t1, $0 , 0x5b
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/changeclearrcnt.s b/libpsn00b/psxapi/sys/changeclearrcnt.s
new file mode 100644
index 0000000..a65676d
--- /dev/null
+++ b/libpsn00b/psxapi/sys/changeclearrcnt.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global ChangeClearRCnt
+.type ChangeClearRCnt, @function
+ChangeClearRCnt:
+ addiu $t2, $0 , 0xc0
+ jr $t2
+ addiu $t1, $0 , 0x0a
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/deldev.s b/libpsn00b/psxapi/sys/deldev.s
new file mode 100644
index 0000000..185cd32
--- /dev/null
+++ b/libpsn00b/psxapi/sys/deldev.s
@@ -0,0 +1,10 @@
+.set noreorder
+
+.section .text
+
+.global DelDev
+.type DelDev, @function
+DelDev:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x48 \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/disableevent.s b/libpsn00b/psxapi/sys/disableevent.s
new file mode 100644
index 0000000..fb60549
--- /dev/null
+++ b/libpsn00b/psxapi/sys/disableevent.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global DisableEvent
+.type DisableEvent, @function
+DisableEvent:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x0d
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/enableevent.s b/libpsn00b/psxapi/sys/enableevent.s
new file mode 100644
index 0000000..a95e1fc
--- /dev/null
+++ b/libpsn00b/psxapi/sys/enableevent.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global EnableEvent
+.type EnableEvent, @function
+EnableEvent:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x0c
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/entercriticalsection.s b/libpsn00b/psxapi/sys/entercriticalsection.s
new file mode 100644
index 0000000..ce9a368
--- /dev/null
+++ b/libpsn00b/psxapi/sys/entercriticalsection.s
@@ -0,0 +1,11 @@
+.set noreorder
+.section .text
+
+.global EnterCriticalSection
+.type EnterCriticalSection, @function
+EnterCriticalSection:
+ addiu $a0, $0, 1
+ syscall 0
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/exitcriticalsection.s b/libpsn00b/psxapi/sys/exitcriticalsection.s
new file mode 100644
index 0000000..e2ee060
--- /dev/null
+++ b/libpsn00b/psxapi/sys/exitcriticalsection.s
@@ -0,0 +1,11 @@
+.set noreorder
+.section .text
+
+.global ExitCriticalSection
+.type ExitCriticalSection, @function
+ExitCriticalSection:
+ addiu $a0, $0, 2
+ syscall 0
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/initcard.s b/libpsn00b/psxapi/sys/initcard.s
new file mode 100644
index 0000000..e589592
--- /dev/null
+++ b/libpsn00b/psxapi/sys/initcard.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global InitCard
+.type InitCard, @function
+InitCard:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x4a
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/initpad.s b/libpsn00b/psxapi/sys/initpad.s
new file mode 100644
index 0000000..b0f1b6f
--- /dev/null
+++ b/libpsn00b/psxapi/sys/initpad.s
@@ -0,0 +1,11 @@
+.set noreorder
+.section .text
+
+.include "hwregs_a.h"
+
+.global InitPad
+.type InitPad, @function
+InitPad:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x12
diff --git a/libpsn00b/psxapi/sys/listdev.s b/libpsn00b/psxapi/sys/listdev.s
new file mode 100644
index 0000000..fa3afec
--- /dev/null
+++ b/libpsn00b/psxapi/sys/listdev.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global ListDev
+.type ListDev, @function
+ListDev:
+ addiu $t2, $0 , 0xb0
+ jr $t2
+ addiu $t1, $0 , 0x49
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/openevent.s b/libpsn00b/psxapi/sys/openevent.s
new file mode 100644
index 0000000..9be0a3e
--- /dev/null
+++ b/libpsn00b/psxapi/sys/openevent.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global OpenEvent
+.type OpenEvent, @function
+OpenEvent:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x08
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/setcustomexitfromexception.s b/libpsn00b/psxapi/sys/setcustomexitfromexception.s
new file mode 100644
index 0000000..bcba057
--- /dev/null
+++ b/libpsn00b/psxapi/sys/setcustomexitfromexception.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global SetCustomExitFromException
+.type SetCustomExitFromException, @function
+SetCustomExitFromException:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x19
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/setdefaultexitfromexception.s b/libpsn00b/psxapi/sys/setdefaultexitfromexception.s
new file mode 100644
index 0000000..baaf591
--- /dev/null
+++ b/libpsn00b/psxapi/sys/setdefaultexitfromexception.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global SetDefaultExitFromException
+.type SetDefaultExitFromException, @function
+SetDefaultExitFromException:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x18
+
diff --git a/libpsn00b/psxapi/sys/startpad.s b/libpsn00b/psxapi/sys/startpad.s
new file mode 100644
index 0000000..b15b0c0
--- /dev/null
+++ b/libpsn00b/psxapi/sys/startpad.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global StartPad
+.type StartPad, @function
+StartPad:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x13
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/stoppad.s b/libpsn00b/psxapi/sys/stoppad.s
new file mode 100644
index 0000000..562ac0f
--- /dev/null
+++ b/libpsn00b/psxapi/sys/stoppad.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global StopPad
+.type StopPad, @function
+StartPad:
+ addiu $t2, $0, 0xb0
+ jr $t2
+ addiu $t1, $0, 0x14
+ \ No newline at end of file
diff --git a/libpsn00b/psxapi/sys/sysenqintrp.s b/libpsn00b/psxapi/sys/sysenqintrp.s
new file mode 100644
index 0000000..b1efe65
--- /dev/null
+++ b/libpsn00b/psxapi/sys/sysenqintrp.s
@@ -0,0 +1,10 @@
+.set noreorder
+.section .text
+
+.global SysEnqIntRP
+.type SysEnqIntRP, @function
+SysEnqIntRP:
+ addiu $t2, $0, 0xc0
+ jr $t2
+ addiu $t1, $0, 0x02
+ \ No newline at end of file
diff --git a/libpsn00b/psxetc/dbugfont.c b/libpsn00b/psxetc/dbugfont.c
new file mode 100644
index 0000000..ff21d84
--- /dev/null
+++ b/libpsn00b/psxetc/dbugfont.c
@@ -0,0 +1,144 @@
+unsigned int dbugfont_size=2112;
+unsigned char dbugfont[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x00,0xe0,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x08,0x00,0x00,0x80,0x02,0x00,0x00,
+0x20,0x00,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x01,
+0x00,0x10,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x11,
+0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,
+0x00,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0x10,0x00,0x10,0x00,0x10,0x00,
+0x01,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x00,
+0x00,0x00,0x00,0x00,0x00,0x10,0x11,0x11,0x00,0x01,0x01,0x00,0x00,0x11,0x01,
+0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x00,
+0x10,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x11,
+0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x10,0x11,
+0x00,0x00,0x10,0x10,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x10,
+0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x11,0x00,0x00,0x11,0x11,0x01,0x00,
+0x00,0x00,0x00,0x00,0x11,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+0x00,0x10,0x10,0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x11,
+0x11,0x00,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x01,0x10,0x01,0x00,0x00,
+0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x01,0x01,0x01,0x00,
+0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x01,0x00,0x00,0x10,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0x10,0x10,0x11,0x00,0x01,
+0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x11,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x01,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x10,0x11,0x00,0x00,0x01,
+0x00,0x01,0x00,0x10,0x01,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
+0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x11,
+0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x11,0x01,0x00,0x00,
+0x11,0x01,0x00,0x00,0x10,0x01,0x00,0x10,0x11,0x11,0x00,0x00,0x10,0x01,0x00,
+0x10,0x11,0x11,0x00,0x00,0x11,0x01,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x11,0x11,0x00,0x00,0x11,0x00,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x01,0x00,0x10,0x00,0x00,0x00,
+0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x10,
+0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x01,0x00,
+0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,
+0x00,0x00,0x10,0x11,0x11,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x10,
+0x10,0x01,0x01,0x00,0x10,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x10,0x01,0x00,
+0x10,0x11,0x11,0x00,0x10,0x11,0x01,0x00,0x10,0x11,0x01,0x00,0x00,0x00,0x01,
+0x00,0x00,0x11,0x01,0x00,0x00,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x01,0x00,0x10,0x10,0x01,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x10,0x11,0x11,0x00,0x00,
+0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x11,0x00,0x00,0x10,0x00,0x00,
+0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,
+0x01,0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
+0x10,0x11,0x11,0x00,0x10,0x11,0x11,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x01,
+0x00,0x10,0x11,0x01,0x00,0x00,0x11,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x11,
+0x01,0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
+0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x00,
+0x00,0x11,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
+0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x11,0x01,
+0x00,0x00,0x11,0x01,0x00,0x10,0x11,0x01,0x00,0x10,0x11,0x11,0x00,0x10,0x11,
+0x11,0x00,0x00,0x11,0x11,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x11,0x00,0x00,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x00,0x11,0x01,0x00,0x10,0x11,0x01,0x00,0x00,0x01,0x01,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,
+0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,
+0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,
+0x10,0x01,0x11,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,
+0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x01,0x00,
+0x10,0x00,0x00,0x00,0x10,0x10,0x10,0x00,0x10,0x01,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x01,0x00,0x10,0x00,
+0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x00,0x00,0x10,0x11,0x00,0x00,0x10,
+0x10,0x11,0x00,0x10,0x11,0x11,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x00,
+0x10,0x11,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x10,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x11,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,
+0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,0x00,
+0x10,0x00,0x10,0x00,0x10,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x11,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x01,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,
+0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,
+0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x01,0x00,0x00,0x11,0x01,0x00,0x10,
+0x11,0x01,0x00,0x10,0x11,0x11,0x00,0x10,0x00,0x00,0x00,0x00,0x11,0x01,0x00,
+0x10,0x00,0x10,0x00,0x10,0x11,0x11,0x00,0x00,0x11,0x01,0x00,0x10,0x00,0x10,
+0x00,0x10,0x11,0x11,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x11,
+0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x10,
+0x11,0x01,0x00,0x00,0x11,0x01,0x00,0x10,0x11,0x11,0x00,0x10,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x11,0x11,0x00,0x00,0x11,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x11,
+0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,0x00,
+0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x01,0x00,0x00,0x10,0x00,
+0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
+0x11,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x00,
+0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x00,0x01,0x01,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x01,
+0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x01,0x11,0x00,0x00,
+0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x11,0x01,0x00,
+0x00,0x11,0x01,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x10,
+0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x00,
+0x10,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x10,
+0x00,0x10,0x00,0x10,0x00,0x10,0x10,0x10,0x00,0x00,0x01,0x01,0x00,0x00,0x10,
+0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
+0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x10,0x00,0x01,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,
+0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x01,0x00,0x10,0x01,0x11,0x00,0x10,0x00,
+0x10,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x11,0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x11,0x01,
+0x00,0x00,0x10,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x10,0x00,0x00,0x10,0x00,
+0x10,0x00,0x10,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x10,0x11,0x11,0x00,0x00,
+0x11,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,
+0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
diff --git a/libpsn00b/psxetc/dbugfont.tim b/libpsn00b/psxetc/dbugfont.tim
new file mode 100644
index 0000000..4e6cce2
--- /dev/null
+++ b/libpsn00b/psxetc/dbugfont.tim
Binary files differ
diff --git a/libpsn00b/psxetc/fntsort.c b/libpsn00b/psxetc/fntsort.c
new file mode 100644
index 0000000..29e7de5
--- /dev/null
+++ b/libpsn00b/psxetc/fntsort.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <psxgpu.h>
+
+extern unsigned short _font_tpage;
+extern unsigned short _font_clut;
+
+char *FntSort(unsigned int *ot, char *pri, int x, int y, const char *text) {
+
+ DR_TPAGE *tpage;
+ SPRT_8 *sprt = (SPRT_8*)pri;
+ int i;
+
+ while( *text != 0 ) {
+
+ i = toupper( *text )-32;
+
+ if( i > 0 ) {
+
+ i--;
+ setSprt8( sprt );
+ setRGB0( sprt, 128, 128, 128 );
+ setXY0( sprt, x, y );
+ setUV0( sprt, (i%16)<<3, (i>>4)<<3 );
+ sprt->clut = _font_clut;
+ addPrim( ot, sprt );
+ sprt++;
+
+ }
+
+ x += 8;
+ text++;
+
+ }
+
+ pri = (char*)sprt;
+
+ tpage = (DR_TPAGE*)pri;
+ setlen( tpage, 1 );
+ tpage->code[0] = _font_tpage;
+ setcode( tpage, 0xe1 );
+ addPrim( ot, pri );
+ pri += sizeof(DR_TPAGE);
+
+ return pri;
+
+} \ No newline at end of file
diff --git a/libpsn00b/psxetc/font.c b/libpsn00b/psxetc/font.c
new file mode 100644
index 0000000..3b0370b
--- /dev/null
+++ b/libpsn00b/psxetc/font.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <psxgpu.h>
+
+extern unsigned char dbugfont[];
+
+unsigned short _font_tpage;
+unsigned short _font_clut;
+
+void FntLoad(int x, int y) {
+
+ RECT pos;
+ TIM_IMAGE tim;
+
+ GetTimInfo( (unsigned int*)dbugfont, &tim );
+
+ // Load font image
+ pos = *tim.prect;
+ pos.x = x;
+ pos.y = y;
+
+ _font_tpage = getTPage( 0, 0, pos.x, 0 ) | 0x200;
+
+ LoadImage( &pos, tim.paddr );
+ DrawSync();
+
+ // Load font clut
+ pos = *tim.crect;
+ pos.x = x;
+ pos.y = y+tim.prect->h;
+
+ _font_clut = getClut( pos.x, pos.y );
+
+ LoadImage( &pos, tim.caddr );
+ DrawSync();
+
+} \ No newline at end of file
diff --git a/libpsn00b/psxetc/makefile b/libpsn00b/psxetc/makefile
new file mode 100644
index 0000000..676fc6e
--- /dev/null
+++ b/libpsn00b/psxetc/makefile
@@ -0,0 +1,38 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libpsxetc.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -nostdlib -Wa,--strip-local-absolute
+AFLAGS = -msoft-float --strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(AS) $(AFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+ rm -Rf build $(TARGET)
diff --git a/libpsn00b/psxetc/readme.txt b/libpsn00b/psxetc/readme.txt
new file mode 100644
index 0000000..ba4db50
--- /dev/null
+++ b/libpsn00b/psxetc/readme.txt
@@ -0,0 +1,22 @@
+PSX Misc library, part of PSn00bSDK
+2019 Lameguy64 / Meido-Tek Productions
+
+Licensed under Mozilla Public License
+
+Open source implementation of the ETC library. Doesn't really provide much
+aside from some debug font stuff at the moment.
+
+
+Library developer(s):
+
+ Lameguy64
+
+
+Library header(s):
+
+ psxetc.h
+
+
+Changelog:
+
+ None thus far...
diff --git a/libpsn00b/psxgpu/addprim.s b/libpsn00b/psxgpu/addprim.s
new file mode 100644
index 0000000..1b66274
--- /dev/null
+++ b/libpsn00b/psxgpu/addprim.s
@@ -0,0 +1,26 @@
+.set noreorder
+.set noat
+
+.section .text
+
+
+.global AddPrim
+.type AddPrim, @function
+AddPrim:
+
+ lw $v0, 0($a0) # Load OT entry
+ lw $v1, 0($a1) # Set packet length value (in words)
+ lui $at, 0x00ff
+ or $at, 0xffff
+ and $v0, $at # Mask off the upper 8 bits of OT entry
+ or $v1, $v0 # OR values together
+ sw $v1, 0($a1) # Store new address to primitive tag
+ lw $v0, 0($a0) # Load OT entry
+ and $a1, $at # Mask off the upper 8 bits of primitive tag
+ lui $at, 0xff00
+ and $v0, $at # Mask off the first 24 bits of OT entry
+ or $v0, $a1 # OR values together
+
+ jr $ra
+ sw $v0, 0($a0) # Store result to OT
+
diff --git a/libpsn00b/psxgpu/clearotagr.s b/libpsn00b/psxgpu/clearotagr.s
new file mode 100644
index 0000000..3e888f1
--- /dev/null
+++ b/libpsn00b/psxgpu/clearotagr.s
@@ -0,0 +1,21 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global ClearOTagR
+.type ClearOTagR, @function
+ClearOTagR:
+ lui $a2, 0x1f80
+ addi $v0, $a1, -1
+ sll $v0, 2
+ addu $a0, $v0
+ sw $a0, D6_MADR($a2)
+ andi $a1, 0xffff
+ sw $a1, D6_BCR($a2)
+ lui $v0, 0x1100
+ addiu $v0, 2
+ jr $ra
+ sw $v0, D6_CHCR($a2)
diff --git a/libpsn00b/psxgpu/drawotag.s b/libpsn00b/psxgpu/drawotag.s
new file mode 100644
index 0000000..8a5ff0c
--- /dev/null
+++ b/libpsn00b/psxgpu/drawotag.s
@@ -0,0 +1,38 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global DrawOTag
+.type DrawOTag, @function
+DrawOTag:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $a3, 0x1f80 # I/O segment base
+
+.gpu_wait: # Wait for GPU to be ready for commands & DMA
+ jal ReadGPUstat
+ nop
+ srl $v0, 26
+ andi $v0, 1
+ beqz $v0, .gpu_wait
+ nop
+
+ lui $v0, 0x0400 # Set DMA direction to CPUtoGPU
+ ori $v0, 0x2
+ sw $v0, GP1($a3)
+
+ sw $a0, D2_MADR($a3) # Set DMA base address to specified OT
+ sw $0, D2_BCR($a3)
+
+ lui $v0, 0x0100 # Begin OT transfer!
+ ori $v0, 0x0401
+ sw $v0, D2_CHCR($a3)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgpu/drawsync.s b/libpsn00b/psxgpu/drawsync.s
new file mode 100644
index 0000000..149519d
--- /dev/null
+++ b/libpsn00b/psxgpu/drawsync.s
@@ -0,0 +1,26 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global DrawSync
+.type DrawSync, @function
+DrawSync:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+.gpu_wait: # Wait for GPU to be ready for commands and DMA
+ jal ReadGPUstat
+ nop
+ srl $v0, 0x1a
+ andi $v0, 0x5
+ li $v1, 5
+ bne $v0, $v1, .gpu_wait
+ nop
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgpu/gettimimage.c b/libpsn00b/psxgpu/gettimimage.c
new file mode 100644
index 0000000..49ce8e9
--- /dev/null
+++ b/libpsn00b/psxgpu/gettimimage.c
@@ -0,0 +1,39 @@
+#include <psxgpu.h>
+
+int GetTimInfo(unsigned int *tim, TIM_IMAGE *timimg) {
+
+ unsigned int *rtim;
+
+ // Check ID
+ if( ( tim[0]&0xff ) != 0x10 ) {
+ return 1;
+ }
+
+ // Check version
+ if( ( (tim[0]>>8)&0xff ) != 0x0 ) {
+ return 2;
+ }
+
+ timimg->mode = tim[1];
+ rtim = tim+2;
+
+ // Clut present?
+ if( timimg->mode & 0x8 ) {
+
+ timimg->crect = (RECT*)(rtim+1);
+ timimg->caddr = (unsigned int*)(rtim+3);
+
+ rtim += rtim[0]>>2;
+
+ } else {
+
+ timimg->caddr = 0;
+
+ }
+
+ timimg->prect = (RECT*)(rtim+1);
+ timimg->paddr = (unsigned int*)(rtim+3);
+
+ return 0;
+
+}
diff --git a/libpsn00b/psxgpu/getvideomode.s b/libpsn00b/psxgpu/getvideomode.s
new file mode 100644
index 0000000..6f1613c
--- /dev/null
+++ b/libpsn00b/psxgpu/getvideomode.s
@@ -0,0 +1,14 @@
+.set noreorder
+
+
+.section .text
+
+.global GetVideoMode
+.type GetVideoMode, @function
+GetVideoMode:
+
+ la $v0, _gpu_standard
+ lw $v0, 0($v0)
+
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgpu/loadimage.s b/libpsn00b/psxgpu/loadimage.s
new file mode 100644
index 0000000..2376b31
--- /dev/null
+++ b/libpsn00b/psxgpu/loadimage.s
@@ -0,0 +1,70 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.set RECT_x, 0
+.set RECT_y, 2
+.set RECT_w, 4
+.set RECT_h, 6
+
+.section .text
+
+
+.global LoadImage
+.type LoadImage, @function
+LoadImage:
+ addiu $sp, -8
+ sw $ra, 0($sp)
+ sw $s0, 4($sp)
+
+ lui $s0, 0x1f80 # Set I/O segment base address
+
+.gpu_wait: # Wait for GPU to be ready for commands and DMA
+ jal ReadGPUstat
+ nop
+ srl $v0, 0x1a
+ andi $v0, 0x5
+ li $v1, 5
+ #srl $v0, 28
+ #andi $v0, 1
+ bne $v0, $v1, .gpu_wait
+ nop
+
+ lui $v0, 0x400 # Set DMA direction to off
+ sw $v0, GP1($s0)
+
+ lui $v0, 0x0100 # Clear GPU cache
+ sw $v0, GP0($s0)
+
+ lui $v1, 0xa000 # Load image to VRAM
+ sw $v1, GP0($s0)
+ lw $v0, RECT_x($a0) # Set XY and dimensions of image
+ lw $v1, RECT_w($a0)
+ sw $v0, GP0($s0)
+ sw $v1, GP0($s0)
+
+ lui $v0, 0x400 # Set DMA direction to CPUtoVRAM
+ ori $v0, 0x2
+ sw $v0, GP1($s0)
+
+ lhu $v0, RECT_w($a0) # Get rectangle size
+ lhu $v1, RECT_h($a0)
+ nop
+ mult $v0, $v1 # Calculate BCR value
+ mflo $v1
+ srl $v1, 0x4
+ sll $v1, 0x10
+ ori $v1, 0x8
+
+ sw $a1, D2_MADR($s0) # Set DMA base address and transfer length
+ sw $v1, D2_BCR($s0)
+
+ lui $v0, 0x100 # Start DMA transfer
+ ori $v0, 0x201
+ sw $v0, D2_CHCR($s0)
+
+ lw $ra, 0($sp)
+ lw $s0, 4($sp)
+ jr $ra
+ addiu $sp, 8
+
diff --git a/libpsn00b/psxgpu/makefile b/libpsn00b/psxgpu/makefile
new file mode 100644
index 0000000..5eb6265
--- /dev/null
+++ b/libpsn00b/psxgpu/makefile
@@ -0,0 +1,38 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libpsxgpu.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -Wa,--strip-local-absolute
+AFLAGS = -msoft-float -Wa,--strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(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)
diff --git a/libpsn00b/psxgpu/putdispenv.s b/libpsn00b/psxgpu/putdispenv.s
new file mode 100644
index 0000000..0993e5c
--- /dev/null
+++ b/libpsn00b/psxgpu/putdispenv.s
@@ -0,0 +1,174 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.set DISP_dx, 0
+.set DISP_dy, 2
+.set DISP_dw, 4
+.set DISP_dh, 6
+.set DISP_sx, 8
+.set DISP_sy, 10
+.set DISP_sw, 12
+.set DISP_sh, 14
+.set DISP_inter, 16
+.set DISP_isrgb24, 17
+.set DISP_reverse, 18
+
+.section .text
+
+
+.global PutDispEnv
+.type PutDispEnv, @function
+PutDispEnv:
+
+ lui $a3, IOBASE
+
+ # Horizontal resolution stuff
+
+ lh $a2, DISP_dw($a0) # Get X resolution
+
+ lh $v0, DISP_sx($a0)
+ lh $v1, DISP_sw($a0) # Get X screen width
+
+ move $a1, $0 # To use as mode value
+
+ bgt $a2, 560, .mode_640
+ nop
+ bgt $a2, 400, .mode_512
+ nop
+ bgt $a2, 352, .mode_384
+ nop
+ bgt $a2, 280, .mode_320
+ nop
+
+ .set noat
+
+.mode_256:
+ li $at, 10
+ mult $at, $v1
+ li $a2, 0x24e
+ sll $v0, 2
+ add $a2, $v0
+ b .mode_end
+ li $v1, 0xa00
+.mode_320:
+ li $at, 8
+ mult $at, $v1
+ li $a2, 0x258
+ ori $a1, 0x01
+ sll $v0, 2
+ add $a2, $v0
+ b .mode_end
+ li $v1, 0xa00
+.mode_384:
+ li $at, 7
+ mult $at, $v1
+ li $a2, 0x21b
+ ori $a1, 0x64
+ sll $v0, 2
+ add $a2, $v0
+ b .mode_end
+ li $v1, 0xa80
+.mode_512:
+ li $at, 5
+ mult $at, $v1
+ li $a2, 0x267
+ ori $a1, 0x02
+ sll $v0, 2
+ add $a2, $v0
+ b .mode_end
+ li $v1, 0xa00
+.mode_640:
+ li $at, 4
+ mult $at, $v1
+ li $a2, 0x26c
+ ori $a1, 0x03
+ sll $v0, 2
+ add $a2, $v0
+ li $v1, 0xa00
+.mode_end:
+
+ .set at
+
+ mflo $v0
+ bnez $v0, .no_default # Check if screen with is non zero
+ nop
+ move $v0, $v1 # Use default if screen width is 0
+.no_default:
+
+ addu $v0, $a2 # Apply horizontal display coordinates
+ sll $v0, 12
+ andi $a2, 0xfff
+ or $a2, $v0
+ lui $v0, 0x0600
+ or $v0, $a2
+ sw $v0, GP1($a3)
+
+ # Vertical resolution
+
+ lh $v0, DISP_dh($a0)
+ li $a2, 0x10
+ ble $v0, 256, .mode_low
+ nop
+
+.mode_high:
+ ori $a1, 0x04
+.mode_low:
+ lh $v0, DISP_sy($a0)
+ lh $v1, DISP_sh($a0)
+ add $a2, $v0
+ bnez $v1, .no_default_vert
+ nop
+ li $v1, 0xf0
+.no_default_vert:
+ add $v1, $a2
+ and $a2, 0x3ff
+ sll $v1, 10
+ or $v1, $a2
+ lui $v0, 0x0700
+ or $v1, $v0
+ sw $v1, GP1($a3)
+
+ # Video mode
+
+ la $v0, _gpu_standard
+ lbu $v0, 0($v0)
+ nop
+ beqz $v0, .config_ntsc
+ nop
+.config_pal:
+ ori $a1, 0x08
+.config_ntsc:
+
+ lbu $v0, DISP_inter($a0)
+ lbu $v1, DISP_isrgb24($a0)
+ beqz $v0, .no_inter
+ nop
+ or $a1, 0x20
+.no_inter:
+ beqz $v1, .no_rgb24
+ nop
+ or $a1, 0x10
+.no_rgb24:
+ lbu $v0, DISP_inter($a0)
+ nop
+ beqz $v0, .no_reverse
+ nop
+ or $a1, 0x80
+.no_reverse:
+
+ lui $v0, 0x800 # Apply mode
+ or $a1, $v0
+ sw $a1, GP1($a3)
+
+ lhu $v0, DISP_dx($a0) # Set VRAM XY offset
+ lhu $v1, DISP_dy($a0)
+ andi $v0, 0x3ff
+ andi $v1, 0x1ff
+ sll $v1, 10
+ or $v0, $v1
+ lui $v1, 0x500
+ or $v0, $v1
+
+ jr $ra
+ sw $v0, GP1($a3)
diff --git a/libpsn00b/psxgpu/putdispenvraw.s b/libpsn00b/psxgpu/putdispenvraw.s
new file mode 100644
index 0000000..157150d
--- /dev/null
+++ b/libpsn00b/psxgpu/putdispenvraw.s
@@ -0,0 +1,71 @@
+.set noreorder
+.set noat
+
+.include "hwregs_a.h"
+
+.set DISP_mode, 0
+.set DISP_vxpos, 4
+.set DISP_vypos, 6
+.set DISP_fbx, 8
+.set DISP_fby, 10
+
+.section .text
+
+
+.global PutDispEnvRaw
+.type PutDispEnvRaw, @function
+PutDispEnvRaw:
+ addiu $sp, -8
+ sw $ra, 0($sp)
+ sw $s0, 4($sp)
+
+ lui $s0, 0x1f80
+
+ lh $at, DISP_vxpos($a0) # Set horizontal display range
+ li $v0, 608
+ add $v0, $at
+ li $v1, 3168
+ add $v1, $at
+ sll $v1, 12
+ or $v0, $v1
+ lui $v1, 0x600
+ or $v1, $v0
+ sw $v1, GP1($s0)
+
+ lh $at, DISP_vypos($a0) # Set vertical display range (for NTSC)
+ li $v1, 120 # (values differet for PAL modes)
+ sub $v1, $at
+ li $v0, 136
+ sub $v0, $v1
+ andi $v0, 0x1ff
+ li $v1, 120
+ add $v1, $at
+ li $at, 136
+ add $at, $v1
+ andi $at, 0x1ff
+ sll $at, 10
+ or $v0, $at
+ lui $at, 0x700
+ or $v0, $at
+ sw $v0, GP1($s0)
+
+ lw $v0, DISP_mode($a0) # Set video mode
+ lui $at, 0x800
+ or $v0, $at
+ sw $v0, GP1($s0)
+
+ lhu $v0, DISP_fbx($a0) # Set VRAM XY offset
+ lhu $v1, DISP_fby($a0)
+ andi $v0, 0x3ff
+ andi $v1, 0x1ff
+ sll $v1, 10
+ or $v0, $v1
+ lui $v1, 0x500
+ or $v0, $v1
+ sw $v0, GP1($s0)
+
+ lw $ra, 0($sp)
+ lw $s0, 4($sp)
+ jr $ra
+ addiu $sp, 8
+
diff --git a/libpsn00b/psxgpu/putdrawenv.s b/libpsn00b/psxgpu/putdrawenv.s
new file mode 100644
index 0000000..69af437
--- /dev/null
+++ b/libpsn00b/psxgpu/putdrawenv.s
@@ -0,0 +1,142 @@
+.set noreorder
+.set noat
+
+.include "hwregs_a.h"
+
+.set DRAW_x, 0 # Drawing area
+.set DRAW_y, 2
+.set DRAW_w, 4
+.set DRAW_h, 6
+.set DRAW_ofx, 8 # Draw offset
+.set DRAW_ofy, 10
+.set DRAW_tx, 12 # Texture window
+.set DRAW_ty, 14
+.set DRAW_tw, 16
+.set DRAW_th, 18
+.set DRAW_tpage, 20 # TPage values
+.set DRAW_dtd, 22
+.set DRAW_dfe, 23
+.set DRAW_isbg, 24 # Clear draw area
+.set DRAW_r0, 25
+.set DRAW_g0, 26
+.set DRAW_b0, 27
+.set DRAW_env, 28
+
+
+.section .text
+
+.global PutDrawEnv
+.type PutDrawEnv, @function
+PutDrawEnv:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ addiu $a1, $a0, DRAW_env
+
+ li $v0, 0x04ffffff # Packet header (length+terminator)
+ sw $v0, 0($a1)
+
+ lhu $v0, DRAW_x($a0) # Set draw area top-left
+ lhu $v1, DRAW_y($a0)
+ andi $v0, 0x3ff
+ andi $v1, 0x1ff
+ sll $v1, 10
+ or $v0, $v1
+ lui $v1, 0xe300
+ or $v0, $v1
+ sw $v0, 4($a1) # 1
+
+ .set noat
+
+ lhu $v0, DRAW_w($a0) # Set draw area bottom-right
+ lhu $at, DRAW_x($a0)
+ addiu $v0, -1
+ addu $at, $v0
+ andi $at, 0x3ff
+ lhu $v1, DRAW_h($a0)
+ lhu $v0, DRAW_y($a0)
+ addiu $v1, -1
+ addu $v0, $v1
+ andi $v0, 0x1ff
+ sll $v0, 10
+ or $at, $v0
+ lui $v0, 0xe400
+ or $at, $v0
+ sw $at, 8($a1) # 2
+
+ lhu $v0, DRAW_x($a0) # Set drawing offset
+ lhu $v1, DRAW_ofx($a0)
+ nop
+ add $v0, $v1
+ andi $at, $v0, 0x7ff
+ lhu $v0, DRAW_y($a0)
+ lhu $v1, DRAW_ofy($a0)
+ nop
+ add $v0, $v1
+ andi $v0, 0x7ff
+ sll $v0, 11
+ or $at, $v0
+ lui $v0, 0xe500
+ or $at, $v0
+ sw $at, 12($a1) # 3
+
+ lhu $at, DRAW_tpage($a0) # Set tpage
+ lbu $v0, DRAW_dtd($a0)
+ lbu $v1, DRAW_dfe($a0)
+ andi $v0, 1
+ and $v1, 1
+ sll $v0, 9
+ sll $v1, 10
+ or $at, $v0
+ or $at, $v1
+ lui $v0, 0xe100
+ or $at, $v0
+ sw $at, 16($a1) # 4
+
+ .set at
+
+ lbu $v0, DRAW_isbg($a0)
+ nop
+ beqz $v0, .no_fillVRAM
+ nop
+
+ lw $v0, DRAW_isbg($a0) # FillVRAM
+ lui $v1, 0x0200
+ srl $v0, 8
+ or $v0, $v1
+ sw $v0, 20($a1) # 5
+ lw $v0, DRAW_x($a0)
+ lw $v1, DRAW_w($a0)
+ sw $v0, 24($a1) # 6
+
+ srl $v0, $v1, 16 # Workaround as rectangle primitives
+ blt $v0, 511, .no_overflow # don't accept a height of 512
+ nop
+
+ li $v0, 511
+ sll $v0, 16
+ andi $v1, 0xffff
+ or $v1, $v0
+
+.no_overflow:
+ sw $v1, 28($a1) # 7
+ li $v0, 0x07ffffff # Packet header (length+terminator)
+ sw $v0, 0($a1)
+
+.no_fillVRAM:
+
+.gpu_wait: # Wait for GPU to become ready for commands and DMA
+ jal ReadGPUstat
+ nop
+ srl $v0, 26
+ andi $v0, 1
+ beqz $v0, .gpu_wait
+ nop
+
+ jal DrawOTag
+ move $a0, $a1
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgpu/readgpustat.s b/libpsn00b/psxgpu/readgpustat.s
new file mode 100644
index 0000000..c587cfb
--- /dev/null
+++ b/libpsn00b/psxgpu/readgpustat.s
@@ -0,0 +1,14 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global ReadGPUstat
+.type ReadGPUstat, @function
+ReadGPUstat:
+ lui $v0, 0x1f80
+ lw $v0, GP1($v0)
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgpu/readme.txt b/libpsn00b/psxgpu/readme.txt
new file mode 100644
index 0000000..55fcb68
--- /dev/null
+++ b/libpsn00b/psxgpu/readme.txt
@@ -0,0 +1,50 @@
+PSX GPU library, part of PSn00bSDK
+2019 Lameguy64 / Meido-Tek Productions
+
+Licensed under Mozilla Public License
+
+ Open source implementation of the GPU library written mostly in MIPS
+assembly. Supports DMA transfers for ordering table draw and transferring
+image data to VRAM. The syntax is intentionally made to closely resemble
+Sony's syntax for familiarity and to make porting homebrew made using the
+official SDK to PSn00bSDK a little easier.
+
+
+Library developer(s):
+
+ Lameguy64
+
+
+Library header(s):
+
+ hwregs_a.h (GNU assembler port defs)
+ psxgpu.h
+
+
+Todo list:
+
+ * VSync() and DrawSync() functions lack alternate operating modes such as
+ getting number of vsyncs elapsed and waiting until a specified number of
+ vsyncs have passed.
+
+ * VSync interrupt handler should be hooked using BIOS function
+ SetCustomExitFromException() like the official GPU library instead of
+ hooking an event handler, but said hook never seems to work. Perhaps
+ something in the kernel area needs to be patched/set or some event/IRQ
+ handler needs to be removed as such handlers can skip the custom
+ exception exit entirely.
+
+ It also appears that all interrupt handling in the official libraries
+ are done through the GPU library. This would also explain why the
+ official documentation tells you to always call ResetGraph() at the
+ very beginning of your programs.
+
+ * ClearOTag() function (non reverse version of ClearOTagR()) yet to be
+ implemented.
+
+ * StoreImage() equivalent yet to be implemented.
+
+
+Changelog:
+
+ None thus far...
diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s
new file mode 100644
index 0000000..bc30d3b
--- /dev/null
+++ b/libpsn00b/psxgpu/resetgraph.s
@@ -0,0 +1,223 @@
+.set noreorder
+.set noat
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global ResetGraph # Resets the GPU and installs a
+.type ResetGraph, @function # VSync event handler
+ResetGraph:
+ addiu $sp, -0x20 # C style stack allocation (required if
+ sw $ra, 28($sp) # you call BIOS functions from asm)
+ sw $a0, 24($sp)
+
+ la $v0, _hooks_installed # Skip installing hooks if this function
+ lbu $v0, 0($v0) # has already been called before once
+ nop
+ bnez $v0, .skip_hook_init
+ nop
+
+ # Temporary, may help improve compatibility?
+ jal SetDefaultExitFromException
+ nop
+
+ jal ChangeClearPAD # Remove pad handler left by the BIOS
+ move $a0, $0
+
+ li $a0, 1
+ jal ChangeClearRCnt # Remove RCnt handler
+ move $a1, $0
+
+ jal _96_remove # Remove CD handling left by the BIOS
+ nop
+
+ lui $a3, 0x1f80 # Base address for I/O
+
+ lui $v0, 0x3b33 # Enables DMA channel 6 (for ClearOTag)
+ ori $v0, 0x3b33 # Enables DMA channel 2
+ sw $v0, DPCR($a3)
+ sw $0 , DICR($a3) # Clear DICR (not needed)
+
+ li $v0, 0x9 # Enable IRQ0 (vblank)
+ sw $v0, IMASK($a3)
+
+ # Set an event handler
+
+ li $a0, 0xf2000003 # RCntCNT3 (vsync class)
+ li $a1, 0x2
+ li $a2, 0x1000
+ la $a3, _vsync_func # VSync event handler
+
+ jal OpenEvent # Open a VSync event handler
+ # (PSXSDK style vsync handler)
+ nop
+
+ la $v1, _vsync_event_desc # Save event descriptor
+ sw $v0, 0($v1)
+
+ jal EnableEvent # Enable the opened event
+ move $a0, $v0
+
+ la $v0, _hooks_installed # Set installed flag
+ li $v1, 0x1
+ sb $v1, 0($v0)
+
+ la $v0, _vsync_counter # Clear VSync counter
+ sw $0 , 0($v0)
+
+ la $v0, _vsync_callback_func # Clear callback function
+ sw $0 , 0($v0)
+
+ jal ExitCriticalSection # Re-enable interrupts
+ nop
+
+.skip_hook_init:
+
+ lui $a3, 0x1f80
+
+ lw $v0, GP1($a3) # Get video standard
+ lui $v1, 0x0010
+ and $v0, $v1
+ la $v1, _gpu_standard
+ beqz $v0, .not_pal
+ sw $0 , 0($v1)
+ li $v0, 1
+ sw $v0, 0($v1)
+.not_pal:
+
+ lw $a0, 24($sp) # Get argument value
+
+ lui $a3, 0x1f80 # Set base I/O again (likely destroyed
+ # by previous calls)
+
+ li $v0, 0x1d00 # Configure timer 1 as Hblank counter
+ sw $v0, T1_MODE($a3) # Set timer 1 value
+
+ li $at, 1
+ beq $a0, $at, .gpu_init_1
+ nop
+ li $at, 3
+ beq $a0, $at, .gpu_init_3
+ nop
+
+ sw $0 , GP1($a3) # Reset the GPU
+
+ b .init_done
+ nop
+
+.gpu_init_1:
+
+ sw $0 , D2_CHCR($a3) # Stop any DMA
+
+.gpu_init_3:
+
+ li $v0, 0x1 # Reset the command buffer
+ sw $v0, GP1($a3)
+
+.init_done:
+
+ lw $ra, 28($sp)
+ lw $a0, 24($sp) # Return
+ jr $ra
+ addiu $sp, 0x20
+
+
+.global _vsync_func # VSync event handler, executed on
+.type _vsync_func, @function # every VBlank
+_vsync_func:
+
+ la $gp, _gp
+
+ lui $at, 0x1f80 # Check if there's a VSync IRQ
+ lw $v0, IMASK($at)
+ nop
+ andi $v0, $v0, 0x1
+ beqz $v0, .exit
+ nop
+
+ lw $v1, ISTAT($at)
+ nop
+ andi $v0, $v1, 0x1
+ beqz $v0, .exit
+ nop
+ xori $v1, $v1, 0x1 # Acknowledge the IRQ
+ sw $v1, ISTAT($at)
+
+ la $v1, _vsync_counter # Increment VSync counter
+ lw $v0, 0($v1)
+ nop
+ addiu $v0, 1
+ sw $v0, 0($v1)
+
+ la $v0, _vsync_callback_func # Check if a callback function is set
+ lw $v0, 0($v0)
+ nop
+ beqz $v0, .exit
+ nop
+
+ addiu $sp, -0x20 # Save return address
+ sw $ra, 28($sp)
+
+ jalr $v0 # Execute user function
+ nop
+
+ lw $ra, 28($sp) # Restore previous return address
+ addiu $sp, 0x20
+
+.exit:
+ jr $ra
+ nop
+
+
+.global VSync # VSync function
+.type VSync, @function
+VSync:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ la $a1, _vsync_counter
+ lw $v0, 0($a1)
+ nop
+.loop:
+ lw $v1, 0($a1)
+ nop
+ beq $v0, $v1, .loop
+ nop
+
+ la $v0, _gpu_current_field # Get last field value
+ lbu $v1, 0($v0)
+.wait_field: # Wait for field bit to change
+ jal ReadGPUstat
+ nop
+ srl $v0, 31
+ beq $v0, $v1, .wait_field
+ nop
+
+ la $v1, _gpu_current_field # Store new field value
+ sb $v0, 0($v1)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+.section .data
+
+.global library_credits
+.type library_credits, @object
+library_credits:
+ .string "psxgpu programs by Lameguy64"
+
+.type _vsync_counter, @object
+_vsync_counter:
+ .word 0
+
+.comm _vsync_callback_func, 4, 4
+.comm _vsync_event_desc, 4, 4
+
+.comm _gpu_standard, 4, 4
+.comm _gpu_current_field, 4, 4
+.comm _hooks_installed, 4, 4
diff --git a/libpsn00b/psxgpu/setdefdispenv.c b/libpsn00b/psxgpu/setdefdispenv.c
new file mode 100644
index 0000000..6dec49c
--- /dev/null
+++ b/libpsn00b/psxgpu/setdefdispenv.c
@@ -0,0 +1,21 @@
+#include <psxgpu.h>
+
+DISPENV *SetDefDispEnv(DISPENV *disp, int x, int y, int w, int h) {
+
+ disp->disp.x = x;
+ disp->disp.y = y;
+ disp->disp.w = w;
+ disp->disp.h = h;
+
+ disp->screen.x = 0;
+ disp->screen.y = 0;
+ disp->screen.w = 0;
+ disp->screen.h = 0;
+
+ disp->isinter = 0;
+ disp->isrgb24 = 0;
+ disp->reverse = 0;
+
+ return disp;
+
+}
diff --git a/libpsn00b/psxgpu/setdefdrawenv.c b/libpsn00b/psxgpu/setdefdrawenv.c
new file mode 100644
index 0000000..bcd93ca
--- /dev/null
+++ b/libpsn00b/psxgpu/setdefdrawenv.c
@@ -0,0 +1,26 @@
+#include <psxgpu.h>
+
+DRAWENV *SetDefDrawEnv(DRAWENV *draw, int x, int y, int w, int h) {
+
+ draw->clip.x = x;
+ draw->clip.y = y;
+ draw->clip.w = w;
+ draw->clip.h = h;
+
+ draw->ofs[0] = 0;
+ draw->ofs[1] = 0;
+
+ draw->tw.x = 0;
+ draw->tw.y = 0;
+ draw->tw.w = 0;
+ draw->tw.h = 0;
+
+ draw->tpage = 0x0a;
+ draw->dtd = 1;
+ draw->dfe = 0;
+ draw->isbg = 0;
+ setRGB0( draw, 0, 0, 0 );
+
+ return draw;
+
+}
diff --git a/libpsn00b/psxgpu/setdispmask.s b/libpsn00b/psxgpu/setdispmask.s
new file mode 100644
index 0000000..77ceb04
--- /dev/null
+++ b/libpsn00b/psxgpu/setdispmask.s
@@ -0,0 +1,19 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+
+.global SetDispMask
+.type SetDispMask, @function
+SetDispMask:
+ lui $v1, 0x1f80
+ andi $a0, 0x1
+ lui $v0, 0x300
+ ori $v0, 0x1
+ sub $v0, $a0
+ sw $v0, GP1($v1)
+ jr $ra
+ nop
+
diff --git a/libpsn00b/psxgpu/setvideomode.s b/libpsn00b/psxgpu/setvideomode.s
new file mode 100644
index 0000000..718a4dd
--- /dev/null
+++ b/libpsn00b/psxgpu/setvideomode.s
@@ -0,0 +1,50 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+
+.section .text
+
+.global SetVideoMode
+.type SetVideoMode, @function
+SetVideoMode:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ jal ReadGPUstat
+ nop
+
+ srl $a1, $v0, 17
+ andi $a1, 0x1f
+
+ srl $v1, $v0, 14 # Reverse flag
+ andi $v1, 1
+ sll $v1, 6
+ or $a1, $v1
+
+ srl $v1, $v0, 16 # Horizontal resolution 2
+ andi $v1, 1
+ sll $v1, 6
+ or $a1, $v1
+
+ andi $a1, 0xf7 # Mask off PAL bit
+
+ la $v0, _gpu_standard
+ beqz $a0, .set_done
+ sw $0 , 0($v0)
+ li $v1, 1
+ sw $v1, 0($v0)
+ b .set_done
+ or $a1, 0x8
+.set_done:
+
+ lui $v0, 0x800 # Apply new mode
+ or $a1, $v0
+ lui $v0, IOBASE
+ sw $a1, GP1($v0)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
diff --git a/libpsn00b/psxgpu/vsynccallback.s b/libpsn00b/psxgpu/vsynccallback.s
new file mode 100644
index 0000000..1f96bbc
--- /dev/null
+++ b/libpsn00b/psxgpu/vsynccallback.s
@@ -0,0 +1,25 @@
+.set noreorder
+
+.section .text
+
+.global VSyncCallback
+.type VSyncCallback, @function
+VSyncCallback:
+ addiu $sp, -8
+ sw $ra, 0($sp)
+
+ jal EnterCriticalSection
+ sw $a0, 4($sp)
+
+ lw $a0, 4($sp)
+ la $v0, _vsync_callback_func
+ sw $a0, 0($v0)
+
+ jal ExitCriticalSection
+ nop
+
+ lw $ra, 0($sp)
+ addiu $sp, 8
+ jr $ra
+ nop
+
diff --git a/libpsn00b/psxgte/applymatrixlv.s b/libpsn00b/psxgte/applymatrixlv.s
new file mode 100644
index 0000000..332a2f8
--- /dev/null
+++ b/libpsn00b/psxgte/applymatrixlv.s
@@ -0,0 +1,40 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global ApplyMatrixLV
+.type ApplyMatrixLV, @function
+ApplyMatrixLV:
+
+ # Load matrix to GTE
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a0)
+ lw $t1, 12($a0)
+ lhu $t2, 16($a0)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lw $t0, 0($a1)
+ lw $t1, 4($a1)
+ mtc2 $t0, C2_IR1
+ lw $t0, 8($a1)
+ mtc2 $t1, C2_IR2
+ mtc2 $t0, C2_IR3
+
+ nMVMVA(1, 0, 3, 3, 0)
+
+ swc2 C2_IR1, 0($a2)
+ swc2 C2_IR2, 4($a2)
+ swc2 C2_IR3, 8($a2)
+
+ jr $ra
+ move $v0, $a2
+ \ No newline at end of file
diff --git a/libpsn00b/psxgte/compmatrixlv.s b/libpsn00b/psxgte/compmatrixlv.s
new file mode 100644
index 0000000..95da5e9
--- /dev/null
+++ b/libpsn00b/psxgte/compmatrixlv.s
@@ -0,0 +1,100 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.set MATRIX_r11r12, 0
+.set MATRIX_r13r21, 4
+.set MATRIX_r22r23, 8
+.set MATRIX_r31r32, 12
+.set MATRIX_r33, 16
+.set MATRIX_trx, 20
+.set MATRIX_try, 24
+.set MATRIX_trz, 28
+
+
+.global CompMatrixLV
+.type CompMatrixLV, @function
+CompMatrixLV:
+
+ # Load matrix v0 to GTE
+ lw $t0, MATRIX_r11r12($a0)
+ lw $t1, MATRIX_r13r21($a0)
+ ctc2 $t0, C2_R11R12
+ ctc2 $t1, C2_R13R21
+ lw $t0, MATRIX_r22r23($a0)
+ lw $t1, MATRIX_r31r32($a0)
+ lhu $t2, MATRIX_r33($a0)
+ ctc2 $t0, C2_R22R23
+ lw $t0, MATRIX_trx($a0)
+ ctc2 $t1, C2_R31R32
+ lw $t1, MATRIX_try($a0)
+ ctc2 $t2, C2_R33
+ lw $t2, MATRIX_trz($a0)
+ ctc2 $t0, C2_TRX
+ ctc2 $t1, C2_TRY
+ ctc2 $t2, C2_TRZ
+
+ lw $t0, MATRIX_trx($a1)
+ lw $t1, MATRIX_try($a1)
+ mtc2 $t0, C2_IR1
+ lw $t0, MATRIX_trz($a1)
+ mtc2 $t1, C2_IR2
+ mtc2 $t0, C2_IR3
+
+ nMVMVA(1, 0, 3, 0, 0)
+
+ swc2 C2_IR1, MATRIX_trx($a2)
+ swc2 C2_IR2, MATRIX_try($a2)
+ swc2 C2_IR3, MATRIX_trz($a2)
+
+ lhu $t1, 2*(0+(3*1))($a1) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a1) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a1) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a1) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a2)
+ sh $t0, 2*(0+(3*2))($a2)
+
+ lhu $t1, 2*(2+(3*1))($a1) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a1) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a2)
+ sh $t0, 2*(1+(3*2))($a2)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a2)
+ sh $t0, 2*(2+(3*2))($a2)
+
+ jr $ra
+ move $v0, $a2 \ No newline at end of file
diff --git a/libpsn00b/psxgte/hirotmatrix.c b/libpsn00b/psxgte/hirotmatrix.c
new file mode 100644
index 0000000..56516b0
--- /dev/null
+++ b/libpsn00b/psxgte/hirotmatrix.c
@@ -0,0 +1,35 @@
+#include <psxgte.h>
+
+MATRIX *HiRotMatrix(VECTOR *r, MATRIX *m) {
+
+ short s[3],c[3];
+ MATRIX tm[3];
+
+ s[0] = hisin(r->vx); s[1] = hisin(r->vy); s[2] = hisin(r->vz);
+ c[0] = hicos(r->vx); c[1] = hicos(r->vy); c[2] = hicos(r->vz);
+
+ // mX
+ m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0;
+ m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0];
+ m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0];
+
+ // mY
+ tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1];
+ tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0;
+ tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1];
+
+ // mZ
+ tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0;
+ tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0;
+ tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE;
+
+ PushMatrix();
+
+ MulMatrix0( m, &tm[0], &tm[2] );
+ MulMatrix0( &tm[2], &tm[1], m );
+
+ PopMatrix();
+
+ return m;
+
+}
diff --git a/libpsn00b/psxgte/hisin.c b/libpsn00b/psxgte/hisin.c
new file mode 100644
index 0000000..68d5d28
--- /dev/null
+++ b/libpsn00b/psxgte/hisin.c
@@ -0,0 +1,33 @@
+/* Based on isin_S4 implementation from coranac:
+ * http://www.coranac.com/2009/07/sines/
+ *
+ */
+
+#define qN 15
+#define qA 12
+#define B 19900
+#define C 3516
+
+int hisin(int x) {
+
+ int c, x2, y;
+
+ c= x<<(30-qN); // Semi-circle info into carry.
+ x -= 1<<qN; // sine -> cosine calc
+
+ x= x<<(31-qN); // Mask with PI
+ x= x>>(31-qN); // Note: SIGNED shift! (to qN)
+ x= x*x>>(2*qN-14); // x=x^2 To Q14
+
+ y= B - (x*C>>14); // B - x^2*C
+ y= (1<<qA)-(x*y>>16); // A - x^2*(B-x^2*C)
+
+ return c>=0 ? y : -y;
+
+}
+
+int hicos(int x) {
+
+ return hisin( x+32768 );
+
+}
diff --git a/libpsn00b/psxgte/initgeom.s b/libpsn00b/psxgte/initgeom.s
new file mode 100644
index 0000000..14ca293
--- /dev/null
+++ b/libpsn00b/psxgte/initgeom.s
@@ -0,0 +1,45 @@
+.set noreorder
+
+.include "gtereg.h"
+
+.section .text
+
+
+.global InitGeom
+.type InitGeom, @function
+InitGeom:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ jal EnterCriticalSection
+ nop
+
+ mfc0 $v0, $12 # Get SR
+ lui $v1, 0x4000 # Set bit to enable cop2
+ or $v0, $v1
+ mtc0 $v0, $12 # Set new SR
+
+ jal ExitCriticalSection
+ nop
+
+ ctc2 $0 , $24 # Reset GTE offset
+ ctc2 $0 , $25
+
+ li $v0, 320 # Set default projection plane
+ ctc2 $v0, $26
+
+ li $v0, 0x155 # Set ZSF3 and ZSF4 defaults
+ ctc2 $v0, $29
+ li $v0, 0x100
+ ctc2 $v0, $30
+
+ li $v0, 0xef9e # DQA and DQB defaults
+ lui $v1, 0x0140
+ ctc2 $v0, C2_DQA
+ ctc2 $v1, C2_DQB
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
diff --git a/libpsn00b/psxgte/isin.c b/libpsn00b/psxgte/isin.c
new file mode 100644
index 0000000..79e2970
--- /dev/null
+++ b/libpsn00b/psxgte/isin.c
@@ -0,0 +1,34 @@
+/* Based on isin_S4 implementation from coranac:
+ * http://www.coranac.com/2009/07/sines/
+ *
+ */
+
+#define qN 10
+#define qA 12
+#define B 19900
+#define C 3516
+
+int isin(int x) {
+
+ int c, x2, y;
+
+ c= x<<(30-qN); // Semi-circle info into carry.
+ x -= 1<<qN; // sine -> cosine calc
+
+ x= x<<(31-qN); // Mask with PI
+ x= x>>(31-qN); // Note: SIGNED shift! (to qN)
+
+ x= x*x>>(2*qN-14); // x=x^2 To Q14
+
+ y= B - (x*C>>14); // B - x^2*C
+ y= (1<<qA)-(x*y>>16); // A - x^2*(B-x^2*C)
+
+ return c>=0 ? y : -y;
+
+}
+
+int icos(int x) {
+
+ return isin( x+1024 );
+
+}
diff --git a/libpsn00b/psxgte/makefile b/libpsn00b/psxgte/makefile
new file mode 100644
index 0000000..6b0cb28
--- /dev/null
+++ b/libpsn00b/psxgte/makefile
@@ -0,0 +1,38 @@
+# Run using make (Linux) or gmake (BSD)
+# Part of the PSn00bSDK Project
+# 2019 Lameguy64 / Meido-Tek Productions
+
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libpsxgte.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -fdata-sections -ffunction-sections -Wa,--strip-local-absolute
+AFLAGS = -msoft-float --strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(AS) $(AFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+ rm -Rf build $(TARGET)
diff --git a/libpsn00b/psxgte/matrix.c b/libpsn00b/psxgte/matrix.c
new file mode 100644
index 0000000..b4dea12
--- /dev/null
+++ b/libpsn00b/psxgte/matrix.c
@@ -0,0 +1,45 @@
+#include <psxgte.h>
+
+MATRIX *RotMatrix(SVECTOR *r, MATRIX *m) {
+
+ short s[3],c[3];
+ MATRIX tm[3];
+
+ s[0] = isin(r->vx); s[1] = isin(r->vy); s[2] = isin(r->vz);
+ c[0] = icos(r->vx); c[1] = icos(r->vy); c[2] = icos(r->vz);
+
+ // mX
+ m->m[0][0] = ONE; m->m[0][1] = 0; m->m[0][2] = 0;
+ m->m[1][0] = 0; m->m[1][1] = c[0]; m->m[1][2] = -s[0];
+ m->m[2][0] = 0; m->m[2][1] = s[0]; m->m[2][2] = c[0];
+
+ // mY
+ tm[0].m[0][0] = c[1]; tm[0].m[0][1] = 0; tm[0].m[0][2] = s[1];
+ tm[0].m[1][0] = 0; tm[0].m[1][1] = ONE; tm[0].m[1][2] = 0;
+ tm[0].m[2][0] = -s[1]; tm[0].m[2][1] = 0; tm[0].m[2][2] = c[1];
+
+ // mZ
+ tm[1].m[0][0] = c[2]; tm[1].m[0][1] = -s[2]; tm[1].m[0][2] = 0;
+ tm[1].m[1][0] = s[2]; tm[1].m[1][1] = c[2]; tm[1].m[1][2] = 0;
+ tm[1].m[2][0] = 0; tm[1].m[2][1] = 0; tm[1].m[2][2] = ONE;
+
+ PushMatrix();
+
+ MulMatrix0( m, &tm[0], &tm[2] );
+ MulMatrix0( &tm[2], &tm[1], m );
+
+ PopMatrix();
+
+ return m;
+
+}
+
+MATRIX *TransMatrix(MATRIX *m, VECTOR *r) {
+
+ m->t[0] = r->vx;
+ m->t[1] = r->vy;
+ m->t[2] = r->vz;
+
+ return m;
+
+}
diff --git a/libpsn00b/psxgte/mulmatrix.s b/libpsn00b/psxgte/mulmatrix.s
new file mode 100644
index 0000000..19dabe8
--- /dev/null
+++ b/libpsn00b/psxgte/mulmatrix.s
@@ -0,0 +1,74 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global MulMatrix
+.type MulMatrix, @function
+MulMatrix:
+
+ # Load m1 to GTE
+ lw $t0, 0($a1)
+ lw $t1, 4($a1)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a1)
+ lw $t1, 12($a1)
+ lhu $t2, 16($a1)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lhu $t1, 2*(0+(3*1))($a0) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a0) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a0) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a0) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a0)
+ sh $t0, 2*(0+(3*2))($a0)
+
+ lhu $t1, 2*(2+(3*1))($a0) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a0) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a0)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a0)
+ sh $t0, 2*(1+(3*2))($a0)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a0)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a0)
+ sh $t0, 2*(2+(3*2))($a0)
+
+ jr $ra
+ move $v0, $a0
diff --git a/libpsn00b/psxgte/mulmatrix0.s b/libpsn00b/psxgte/mulmatrix0.s
new file mode 100644
index 0000000..874226b
--- /dev/null
+++ b/libpsn00b/psxgte/mulmatrix0.s
@@ -0,0 +1,74 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global MulMatrix0
+.type MulMatrix0, @function
+MulMatrix0:
+
+ # Load m1 to GTE
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ ctc2 $t0, $0
+ ctc2 $t1, $1
+ lw $t0, 8($a0)
+ lw $t1, 12($a0)
+ lhu $t2, 16($a0)
+ ctc2 $t0, $2
+ ctc2 $t1, $3
+ ctc2 $t2, $4
+
+ lhu $t1, 2*(0+(3*1))($a1) # Load values for first
+ lhu $t0, 2*(0+(3*0))($a1) # R11 R21 R31
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(0+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ lhu $t1, 2*(1+(3*1))($a1) # Load values for second
+ lhu $t0, 2*(1+(3*0))($a1) # R12 R22 R32
+ MVMVA(1, 0, 0, 3, 0) # First multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(1+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of first
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(0+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(0+(3*1))($a2)
+ sh $t0, 2*(0+(3*2))($a2)
+
+ lhu $t1, 2*(2+(3*1))($a1) # Load values for third
+ lhu $t0, 2*(2+(3*0))($a1) # R13 R23 R33
+ MVMVA(1, 0, 0, 3, 0) # Second multiply
+ sll $t1, 16
+ or $t0, $t1
+ lhu $t1, 2*(2+(3*2))($a1)
+ mtc2 $t0, C2_VXY0
+ mtc2 $t1, C2_VZ0
+
+ mfc2 $t0, C2_IR1 # Store results of second
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(1+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(1+(3*1))($a2)
+ sh $t0, 2*(1+(3*2))($a2)
+ MVMVA(1, 0, 0, 3, 0) # Third multiply
+
+ mfc2 $t0, C2_IR1 # Store results of third
+ mfc2 $t1, C2_IR2
+ sh $t0, 2*(2+(3*0))($a2)
+ mfc2 $t0, C2_IR3
+ sh $t1, 2*(2+(3*1))($a2)
+ sh $t0, 2*(2+(3*2))($a2)
+
+ jr $ra
+ move $v0, $a2
diff --git a/libpsn00b/psxgte/pushpopmatrix.s b/libpsn00b/psxgte/pushpopmatrix.s
new file mode 100644
index 0000000..d10687a
--- /dev/null
+++ b/libpsn00b/psxgte/pushpopmatrix.s
@@ -0,0 +1,68 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global PushMatrix
+.type PushMatrix, @function
+PushMatrix:
+ la $a0, _matrix_stack
+ cfc2 $v0, C2_R11R12
+ cfc2 $v1, C2_R13R21
+ sw $v0, 0($a0)
+ cfc2 $v0, C2_R22R23
+ sw $v1, 4($a0)
+ sw $v0, 8($a0)
+ cfc2 $v0, C2_R31R32
+ cfc2 $v1, C2_R33
+ sw $v0, 12($a0)
+ sw $v1, 16($a0)
+ cfc2 $v0, C2_TRX
+ cfc2 $v1, C2_TRY
+ sw $v0, 20($a0)
+ cfc2 $v0, C2_TRZ
+ sw $v1, 24($a0)
+ jr $ra
+ sw $v0, 28($a0)
+
+.global PopMatrix
+.type PopMatrix, @function
+PopMatrix:
+ la $a0, _matrix_stack
+ lw $v0, 0($a0)
+ lw $v1, 4($a0)
+ ctc2 $v0, C2_R11R12
+ ctc2 $v1, C2_R13R21
+ lw $v0, 8($a0)
+ lw $v1, 12($a0)
+ ctc2 $v0, C2_R22R23
+ lw $v0, 16($a0)
+ ctc2 $v1, C2_R31R32
+ ctc2 $v0, C2_R33
+ lw $v0, 20($a0)
+ lw $v1, 24($a0)
+ ctc2 $v0, C2_TRX
+ lw $v0, 28($a0)
+ ctc2 $v1, C2_TRY
+ ctc2 $v0, C2_TRZ
+ jr $ra
+ nop
+
+
+.section .data
+
+
+.type matrix_stack, @object
+_matrix_stack:
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+
diff --git a/libpsn00b/psxgte/readme.txt b/libpsn00b/psxgte/readme.txt
new file mode 100644
index 0000000..13b92b6
--- /dev/null
+++ b/libpsn00b/psxgte/readme.txt
@@ -0,0 +1,39 @@
+PSX GTE library, part of PSn00bSDK
+2019 Lameguy64 / Meido-Tek Productions
+
+Licensed under Mozilla Public License
+
+ Open source implementation of the GTE library written mostly in MIPS
+assembly. It makes full use of the GTE in complex matrix multiplication
+operations. The syntax is intentionally made to closely resemble Sony's syntax
+for familiarity and to make porting homebrew made using the official SDK to
+PSn00bSDK a little easier.
+
+ Unlike the official GTE libraries using the inline GTE macro functions does
+not require running your object file through some stupid tool such as DMPSX.
+The GTE macros use the corresponding cop2 opcodes already.
+
+
+Library developer(s):
+
+ Lameguy64
+
+
+Library header(s):
+
+ gtereg.h
+ inline_c.h
+ inline_s.h
+ psxgte.h
+
+
+Todo list:
+
+ * Alternate RotMatrix() functions with different rotation order are yet to
+ be implemented.
+ * Various high level RotTransPersp style functions not yet implemented.
+
+
+Changelog:
+
+ None thus far...
diff --git a/libpsn00b/psxgte/scalematrix.s b/libpsn00b/psxgte/scalematrix.s
new file mode 100644
index 0000000..3e83800
--- /dev/null
+++ b/libpsn00b/psxgte/scalematrix.s
@@ -0,0 +1,68 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global ScaleMatrix
+.type ScaleMatrix, @function
+ScaleMatrix:
+
+ lwc2 C2_IR0, 0($a1) # X
+
+ lh $v0, 2*(0+(3*0))($a0)
+ lh $v1, 2*(0+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(0+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(0+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(0+(3*1))($a0)
+ sh $v0, 2*(0+(3*2))($a0)
+
+ lwc2 C2_IR0, 4($a1) # Y
+
+ lh $v0, 2*(1+(3*0))($a0)
+ lh $v1, 2*(1+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(1+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(1+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(1+(3*1))($a0)
+ sh $v0, 2*(1+(3*2))($a0)
+
+ lwc2 C2_IR0, 8($a1) # Z
+
+ lh $v0, 2*(2+(3*0))($a0)
+ lh $v1, 2*(2+(3*1))($a0)
+ mtc2 $v0, C2_IR1
+ lh $v0, 2*(2+(3*2))($a0)
+ mtc2 $v1, C2_IR2
+ mtc2 $v0, C2_IR3
+
+ nGPF(1)
+
+ mfc2 $v0, C2_IR1
+ mfc2 $v1, C2_IR2
+ sh $v0, 2*(2+(3*0))($a0)
+ mfc2 $v0, C2_IR3
+ sh $v1, 2*(2+(3*1))($a0)
+ sh $v0, 2*(2+(3*2))($a0)
+
+ jr $ra
+ move $v0, $a0
diff --git a/libpsn00b/psxgte/square0.s b/libpsn00b/psxgte/square0.s
new file mode 100644
index 0000000..d037b7e
--- /dev/null
+++ b/libpsn00b/psxgte/square0.s
@@ -0,0 +1,27 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global Square0
+.type Square0, @function
+Square0:
+
+ # a0 - Pointer to input vector (v0)
+ # a1 - Pointer to output vector (v1)
+
+ lwc2 C2_IR1, 0($a0)
+ lwc2 C2_IR2, 4($a0)
+ lwc2 C2_IR3, 8($a0)
+
+ nSQR(0)
+
+ swc2 C2_IR1, 0($a1)
+ swc2 C2_IR2, 4($a1)
+ swc2 C2_IR3, 8($a1)
+
+ jr $ra
+ nop
diff --git a/libpsn00b/psxgte/squareroot.s b/libpsn00b/psxgte/squareroot.s
new file mode 100644
index 0000000..71f40a9
--- /dev/null
+++ b/libpsn00b/psxgte/squareroot.s
@@ -0,0 +1,121 @@
+.set noreorder
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+.global SquareRoot12
+.type SquareRoot12, @function
+SquareRoot12:
+ mtc2 $a0, C2_LZCS
+ nop
+ nop
+ mfc2 $v0, C2_LZCR
+ beq $v0, 32, $bad_sqr12
+ nop
+ andi $t0, $v0, 0x1
+ addiu $v1, $0 , -2
+ and $t2, $v0, $v1
+ li $t1, 19
+ sub $t1, $t2
+ sra $t1, 1
+ addi $t3, $t2, -24
+ bltz $t3, $value_less12
+ nop
+ sllv $t4, $a0, $t3
+ b $value_greater12
+$value_less12:
+ addiu $t3, $0 , 24
+ sub $t3, $t2
+ srav $t4, $a0, $t3
+$value_greater12:
+ addi $t4, -64
+ sll $t4, 1
+ la $t5, sqrt_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+
+ bltz $t1, $1594c
+ nop
+ jr $ra
+ sllv $v0, $t5, $t1
+
+$1594c:
+
+ sub $t1, $0 , $t1
+ jr $ra
+ srl $v0, $t5, $t1
+
+$bad_sqr12:
+ jr $ra
+ move $v0, $0
+
+
+.global SquareRoot0
+.type SquareRoot0, @function
+SquareRoot0:
+ mtc2 $a0, C2_LZCS
+ nop
+ nop
+ mfc2 $v0, C2_LZCR
+ beq $v0, 32, $bad_sqr
+ nop
+ andi $t0, $v0, 0x1
+ addiu $v1, $0 , -2
+ and $t2, $v0, $v1
+ li $t1, 31
+ sub $t1, $t2
+ sra $t1, 1
+ addi $t3, $t2, -24
+ bltz $t3, $value_less
+ nop
+ sllv $t4, $a0, $t3
+ b $value_greater
+$value_less:
+ addiu $t3, $0 , 24
+ sub $t3, $t2
+ srav $t4, $a0, $t3
+$value_greater:
+ addi $t4, -64
+ sll $t4, 1
+ la $t5, sqrt_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+ sllv $t5, $t5, $t1
+ jr $ra
+ srl $v0, $t5, 12
+$bad_sqr:
+ jr $ra
+ move $v0, $0
+
+
+.section .data
+
+sqrt_table:
+ .hword 0x1000,0x101f,0x103f,0x105e,0x107e,0x109c,0x10bb,0x10da
+ .hword 0x10f8,0x1116,0x1134,0x1152,0x116f,0x118c,0x11a9,0x11c6
+ .hword 0x11e3,0x1200,0x121c,0x1238,0x1254,0x1270,0x128c,0x12a7
+ .hword 0x12c2,0x12de,0x12f9,0x1314,0x132e,0x1349,0x1364,0x137e
+ .hword 0x1398,0x13b2,0x13cc,0x13e6,0x1400,0x1419,0x1432,0x144c
+ .hword 0x1465,0x147e,0x1497,0x14b0,0x14c8,0x14e1,0x14f9,0x1512
+ .hword 0x152a,0x1542,0x155a,0x1572,0x158a,0x15a2,0x15b9,0x15d1
+ .hword 0x15e8,0x1600,0x1617,0x162e,0x1645,0x165c,0x1673,0x1689
+ .hword 0x16a0,0x16b7,0x16cd,0x16e4,0x16fa,0x1710,0x1726,0x173c
+ .hword 0x1752,0x1768,0x177e,0x1794,0x17aa,0x17bf,0x17d5,0x17ea
+ .hword 0x1800,0x1815,0x182a,0x183f,0x1854,0x1869,0x187e,0x1893
+ .hword 0x18a8,0x18bd,0x18d1,0x18e6,0x18fa,0x190f,0x1923,0x1938
+ .hword 0x194c,0x1960,0x1974,0x1988,0x199c,0x19b0,0x19c4,0x19d8
+ .hword 0x19ec,0x1a00,0x1a13,0x1a27,0x1a3a,0x1a4e,0x1a61,0x1a75
+ .hword 0x1a88,0x1a9b,0x1aae,0x1ac2,0xa1d5,0x1ae8,0x1afb,0x1b0e
+ .hword 0x1b21,0x1b33,0x1b46,0x1b59,0x1b6c,0x1b7e,0x1b91,0x1ba3
+ .hword 0x1bb6,0x1bc8,0x1bdb,0x1bed,0x1c00,0x1c12,0x1c24,0x1c36
+ .hword 0x1c48,0x1c5a,0x1c6c,0x1c7e,0x1c90,0x1ca2,0x1cb4,0x1cc6
+ .hword 0x1cd8,0x1ce9,0x1cfb,0x1d0d,0x1d1e,0x1d30,0x1d41,0x1d53
+ .hword 0x1d64,0x1d76,0x1d87,0x1d98,0x1daa,0x1dbb,0x1dcc,0x1ddd
+ .hword 0x1dee,0x1e00,0x1e11,0x1e22,0x1e33,0x1e43,0x1e54,0x1e65
+ .hword 0x1e76,0x1e87,0x1e98,0x1ea8,0x1eb9,0x1eca,0x1eda,0x1eeb
+ .hword 0x1efb,0x1f0c,0x1f1c,0x1f2d,0x1f3d,0x1f4e,0x1f5e,0x1f6e
+ .hword 0x1f7e,0x1f8f,0x1f9f,0x1faf,0x1fbf,0x1fcf,0x1fdf,0x1fef \ No newline at end of file
diff --git a/libpsn00b/psxgte/vectornormals.s b/libpsn00b/psxgte/vectornormals.s
new file mode 100644
index 0000000..8907d43
--- /dev/null
+++ b/libpsn00b/psxgte/vectornormals.s
@@ -0,0 +1,110 @@
+.set noreorder
+.set noat
+
+.include "gtereg.h"
+.include "inline_s.h"
+
+.section .text
+
+
+.global VectorNormalS
+.type VectorNormalS, @function
+VectorNormalS:
+
+ # Implementation ripped from Sony libs
+
+ lw $t0, 0($a0)
+ lw $t1, 4($a0)
+ lw $t2, 8($a0)
+
+ mtc2 $t0, C2_IR1
+ mtc2 $t1, C2_IR2
+ mtc2 $t2, C2_IR3
+
+ nSQR(0)
+
+ mfc2 $t3, C2_MAC1
+ mfc2 $t4, C2_MAC2
+ mfc2 $t5, C2_MAC3
+
+ add $t3, $t4
+ add $v0, $t3, $t5
+ mtc2 $v0, C2_LZCS
+ nop
+ nop
+ mfc2 $v1, C2_LZCR
+
+ addiu $at, $0 , -2
+ and $v1, $at
+
+ addiu $t6, $0 , 0x1f
+ sub $t6, $v1
+ sra $t6, 1
+ addiu $t3, $v1, -24
+
+ bltz $t3, $value_neg
+ nop
+ b $value_pos
+ sllv $t4, $v0, $t3
+$value_neg:
+ addiu $t3, $0 , 24
+ sub $t3, $v1
+ srav $t4, $v0, $t3
+$value_pos:
+ addi $t4, -64
+ sll $t4, 1
+
+ la $t5, _norm_table
+ addu $t5, $t4
+ lh $t5, 0($t5)
+ nop
+
+ mtc2 $t5, C2_IR0
+ mtc2 $t0, C2_IR1
+ mtc2 $t1, C2_IR2
+ mtc2 $t2, C2_IR3
+
+ nGPF(0)
+
+ mfc2 $t0, C2_MAC1
+ mfc2 $t1, C2_MAC2
+ mfc2 $t2, C2_MAC3
+
+ sra $t0, $t6
+ sra $t1, $t6
+ sra $t2, $t6
+
+ sh $t0, 0($a1)
+ sh $t1, 2($a1)
+ jr $ra
+ sh $t2, 4($a1)
+
+
+.section .data
+
+_norm_table:
+ .hword 0x1000, 0x0FE0, 0x0FC1, 0x0FA3, 0x0F85, 0x0F68, 0x0F4C, 0x0F30
+ .hword 0x0F15, 0x0EFB, 0x0EE1, 0x0EC7, 0x0EAE, 0x0E96, 0x0E7E, 0x0E66
+ .hword 0x0E4F, 0x0E38, 0x0E22, 0x0E0C, 0x0DF7, 0x0DE2, 0x0DCD, 0x0DB9
+ .hword 0x0DA5, 0x0D91, 0x0D7E, 0x0D6B, 0x0D58, 0x0D45, 0x0D33, 0x0D21
+ .hword 0x0D10, 0x0CFF, 0x0CEE, 0x0CDD, 0x0CCC, 0x0CBC, 0x0CAC, 0x0C9C
+ .hword 0x0C8D, 0x0C7D, 0x0C6E, 0x0C5F, 0x0C51, 0x0C42, 0x0C34, 0x0C26
+ .hword 0x0C18, 0x0C0A, 0x0BFD, 0x0BEF, 0x0BE2, 0x0BD5, 0x0BC8, 0x0BBB
+ .hword 0x0BAF, 0x0BA2, 0x0B96, 0x0B8A, 0x0B7E, 0x0B72, 0x0B67, 0x0B5B
+ .hword 0x0B50, 0x0B45, 0x0B39, 0x0B2E, 0x0B24, 0x0B19, 0x0B0E, 0x0B04
+ .hword 0x0AF9, 0x0AEF, 0x0AE5, 0x0ADB, 0x0AD1, 0x0AC7, 0x0ABD, 0x0AB4
+ .hword 0x0AAA, 0x0AA1, 0x0A97, 0x0A8E, 0x0A85, 0x0A7C, 0x0A73, 0x0A6A
+ .hword 0x0A61, 0x0A59, 0x0A50, 0x0A47, 0x0A3F, 0x0A37, 0x0A2E, 0x0A26
+ .hword 0x0A1E, 0x0A16, 0x0A0E, 0x0A06, 0x09FE, 0x09F6, 0x09EF, 0x09E7
+ .hword 0x09E0, 0x09D8, 0x09D1, 0x09C9, 0x09C2, 0x09BB, 0x09B4, 0x09AD
+ .hword 0x09A5, 0x099E, 0x0998, 0x0991, 0x098A, 0x0983, 0x097C, 0x0976
+ .hword 0x096F, 0x0969, 0x0962, 0x095C, 0x0955, 0x094F, 0x0949, 0x0943
+ .hword 0x093C, 0x0936, 0x0930, 0x092A, 0x0924, 0x091E, 0x0918, 0x0912
+ .hword 0x090D, 0x0907, 0x0901, 0x08FB, 0x08F6, 0x08F0, 0x08EB, 0x08E5
+ .hword 0x08E0, 0x08DA, 0x08D5, 0x08CF, 0x08CA, 0x08C5, 0x08BF, 0x08BA
+ .hword 0x08B5, 0x08B0, 0x08AB, 0x08A6, 0x08A1, 0x089C, 0x0897, 0x0892
+ .hword 0x088D, 0x0888, 0x0883, 0x087E, 0x087A, 0x0875, 0x0870, 0x086B
+ .hword 0x0867, 0x0862, 0x085E, 0x0859, 0x0855, 0x0850, 0x084C, 0x0847
+ .hword 0x0843, 0x083E, 0x083A, 0x0836, 0x0831, 0x082D, 0x0829, 0x0824
+ .hword 0x0820, 0x081C, 0x0818, 0x0814, 0x0810, 0x080C, 0x0808, 0x0804
+ \ No newline at end of file
diff --git a/libpsn00b/psxspu/makefile b/libpsn00b/psxspu/makefile
new file mode 100644
index 0000000..d6b3604
--- /dev/null
+++ b/libpsn00b/psxspu/makefile
@@ -0,0 +1,34 @@
+PREFIX = mipsel-unknown-elf-
+
+TARGET = ../libpsxspu.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+AFILES = $(notdir $(wildcard ./*.s))
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -g -msoft-float -Wa,--strip-local-absolute
+AFLAGS = -g -msoft-float --strip-local-absolute
+
+CC = $(PREFIX)gcc
+AS = $(PREFIX)as
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(AS) $(AFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+ rm -Rf build $(TARGET)
diff --git a/libpsn00b/psxspu/readme.txt b/libpsn00b/psxspu/readme.txt
new file mode 100644
index 0000000..4cac976
--- /dev/null
+++ b/libpsn00b/psxspu/readme.txt
@@ -0,0 +1,36 @@
+PSX SPU Library, part of PSn00bSDK
+2019 Lameguy64 / Meido-Tek Productions
+
+Licensed under Mozilla Public License
+
+ Open source implementation of the SPU library written mostly in MIPS
+assembly. Currently only supports SPU init, uploading sample data using DMA
+transfer and basic sample playback but is currently lacking a bunch of
+important functions.
+
+ Very work in progress currently.
+
+
+Library developer(s):
+
+ Lameguy64
+
+
+Library header(s):
+
+ psxspu.h
+
+
+Todo list:
+
+ * SPU RAM allocation routines yet to be implemented (heap must only be
+ stored in main RAM and not SPU RAM like in the official SDK).
+
+ * SpuKeyOn() is actually not part of the official library.
+
+ * SPU reverb configuration functions yet to be implemented.
+
+
+Changelog:
+
+ None so far...
diff --git a/libpsn00b/psxspu/spuinit.s b/libpsn00b/psxspu/spuinit.s
new file mode 100644
index 0000000..fa5ec32
--- /dev/null
+++ b/libpsn00b/psxspu/spuinit.s
@@ -0,0 +1,130 @@
+.set noreorder
+.set noat
+
+.include "hwregs_a.h"
+
+.section .data
+
+
+.global SpuInit
+.type SpuInit, @function
+SpuInit:
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lui $v1, IOBASE
+
+ # Stop and mute everything
+
+ sh $0 , SPUCNT($v1) # Clear control settings
+ jal SpuCtrlSync
+ move $a0, $0
+
+ sh $0 , SPU_MASTER_VOL($v1) # Clear master volume
+ sh $0 , SPU_MASTER_VOL+2($v1)
+
+ sh $0 , SPU_REVERB_VOL($v1) # Clear reverb volume
+ sh $0 , SPU_REVERB_VOL+2($v1)
+
+ sh $0 , SPU_CD_VOL($v1) # Clear CD volume
+ sh $0 , SPU_CD_VOL+2($v1)
+
+ sh $0 , SPU_EXT_VOL($v1) # Clear external audio volume
+ sh $0 , SPU_EXT_VOL+2($v1)
+
+ sh $0 , SPU_FM_MODE($v1) # Turn off FM modes
+ sh $0 , SPU_FM_MODE+2($v1)
+
+ sh $0 , SPU_NOISE_MODE($v1) # Turn off noise modes
+ sh $0 , SPU_NOISE_MODE+2($v1)
+
+ sh $0 , SPU_REVERB_ON($v1) # Turn off reverb modes
+ sh $0 , SPU_REVERB_ON+2($v1)
+
+ li $v0, 0xfffe
+ sh $v0, SPU_REVERB_ADDR($v1)
+
+ lui $v0, 0x0200;
+ ori $v0, 0x3fff;
+
+ # Clear all voices
+
+ addiu $a1, $sp, -20
+ sw $0 , 0($a1)
+ sw $0 , 4($a1)
+ sw $0 , 8($a1)
+ sw $0 , 12($a1)
+
+ li $a2, 23
+
+.clear_voices:
+ jal SpuSetVoiceRaw
+ move $a0, $a2
+ addiu $a2, -1
+ bgez $a2, .clear_voices
+ nop
+
+ li $v0, 0xffff # Set all keys to off
+ sh $v0, SPU_KEY_OFF($v1)
+ sh $v0, SPU_KEY_OFF+2($v1)
+
+ li $v0, 0x4 # Set SPU data transfer control
+ sh $v0, SPUDTCNT($v1) # (usually always 0x4)
+
+ lw $v0, DPCR($v1) # Enable DMA channel 4 (SPU DMA)
+ lui $at, 0xb
+ or $v0, $at
+ sw $v0, DPCR($v1)
+
+ li $v0, 0xc000 # Enable SPU
+ sh $v0, SPUCNT($v1)
+ jal SpuCtrlSync
+ move $a0, $v0
+
+ li $v0, 0x3fff # Activate master volume
+ sh $v0, SPU_MASTER_VOL($v1)
+ sh $v0, SPU_MASTER_VOL+2($v1)
+
+ sh $v0, SPU_CD_VOL($v1) # Activate CD volume
+ sh $v0, SPU_CD_VOL+2($v1)
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop
+
+
+# Waits until bits 0-5 of SPUSTAT are equal to SPUCNT
+#
+# Destroys v0, v1, a0
+#
+.global SpuCtrlSync
+.type SpuCtrlSync, @function
+SpuCtrlSync:
+ lui $v1, IOBASE
+ andi $a0, 0x3f
+.ctrl_wait:
+ lhu $v0, SPUSTAT($v1) # Get SPUSTAT value
+ nop
+ andi $v0, 0x3f
+ bne $v0, $a0, .ctrl_wait # Wait until SPUCNT and SPUSTAT are equal
+ nop
+ jr $ra
+ nop
+
+
+# Waits until SPU has finished transfers
+#
+.global SpuWait
+.type SpuWait, @function
+SpuWait:
+ lui $v0, IOBASE
+ lhu $v0, SPUSTAT($v0)
+ nop
+ andi $v0, 0x400
+ bnez $v0, SpuWait
+ nop
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/psxspu/spukeyon.s b/libpsn00b/psxspu/spukeyon.s
new file mode 100644
index 0000000..556f976
--- /dev/null
+++ b/libpsn00b/psxspu/spukeyon.s
@@ -0,0 +1,16 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .data
+
+
+.global SpuKeyOn
+.type SpuKeyOn, @function
+SpuKeyOn:
+ lui $v1, IOBASE
+ li $v0, 1
+ sll $v0, $a0
+ sh $v0, SPU_KEY_ON($v1)
+ jr $ra
+ nop \ No newline at end of file
diff --git a/libpsn00b/psxspu/spureverbon.s b/libpsn00b/psxspu/spureverbon.s
new file mode 100644
index 0000000..852bff3
--- /dev/null
+++ b/libpsn00b/psxspu/spureverbon.s
@@ -0,0 +1,16 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .data
+
+
+.global SpuReverbOn
+.type SpuReverbOn, @function
+SpuReverbOn:
+ lui $v1, IOBASE
+ li $v0, 1
+ sll $v0, $a0
+ sh $v0, SPU_REVERB_ON($v1)
+ jr $ra
+ nop \ No newline at end of file
diff --git a/libpsn00b/psxspu/spusetkey.s b/libpsn00b/psxspu/spusetkey.s
new file mode 100644
index 0000000..1270b2a
--- /dev/null
+++ b/libpsn00b/psxspu/spusetkey.s
@@ -0,0 +1,26 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .data
+
+
+.global SpuSetKey
+.type SpuSetKey, @function
+SpuSetKey:
+ # a0 - 0: key off, 1: key on
+ # a1 - Voice bit mask
+
+ lui $a2, IOBASE
+
+ beqz $a0, .key_off
+ nop
+
+ jr $ra
+ sh $a1, SPU_KEY_ON($v1)
+
+.key_off:
+
+ jr $ra
+ sh $a1, SPU_KEY_OFF($v1)
+ \ No newline at end of file
diff --git a/libpsn00b/psxspu/spusetreverb.s b/libpsn00b/psxspu/spusetreverb.s
new file mode 100644
index 0000000..993b166
--- /dev/null
+++ b/libpsn00b/psxspu/spusetreverb.s
@@ -0,0 +1,24 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .data
+
+
+.global SpuSetReverb
+.type SpuSetReverb, @function
+SpuSetReverb:
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lhu $v0, SPUCNT($v1)
+ nop
+ ori $v0, 0x80 # Enable reverb
+ sh $v0, SPUCNT($v1)
+ jal SpuCtrlSync
+ move $a0, $v0
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ nop \ No newline at end of file
diff --git a/libpsn00b/psxspu/spusetreverbaddr.s b/libpsn00b/psxspu/spusetreverbaddr.s
new file mode 100644
index 0000000..6ddbf44
--- /dev/null
+++ b/libpsn00b/psxspu/spusetreverbaddr.s
@@ -0,0 +1,25 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+
+.section .text
+
+.global SpuSetReverbAddr
+.type SpuSetReverbAddr, @function
+SpuSetReverbAddr:
+ lui $a3, 0x1f80
+ srl $a0, 3
+ sh $a0, SPU_REVERB_ADDR($a3)
+ jr $ra
+ nop
+
+
+.global SpuSetReverbVolume
+.type SpuSetReverbVolume, @function
+SpuSetReverbVolume:
+ lui $a3, 0x1f80
+ sh $a0, SPU_REVERB_VOL($a3)
+ sh $a1, SPU_REVERB_VOL+2($a3)
+ jr $ra
+ nop \ No newline at end of file
diff --git a/libpsn00b/psxspu/spusetvoiceraw.s b/libpsn00b/psxspu/spusetvoiceraw.s
new file mode 100644
index 0000000..43450f6
--- /dev/null
+++ b/libpsn00b/psxspu/spusetvoiceraw.s
@@ -0,0 +1,60 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+
+.set PARAM_L, 0
+.set PARAM_R, 2
+.set PARAM_FREQ, 4
+.set PARAM_ADDR, 6
+.set PARAM_LOOP, 8
+.set PARAM_RES, 10
+.set PARAM_ADSR, 12
+
+
+.section .text
+
+.global SpuSetVoiceRaw
+.type SpuSetVoiceRaw, @function
+SpuSetVoiceRaw:
+
+ # a0 - Voice number
+ # a1 - Address to parameters
+
+ sll $a0, 4
+ addiu $a0, SPU_VOICE_BASE
+
+ lui $v1, IOBASE
+ or $a0, $v1
+
+ lhu $v0, PARAM_L($a1)
+ nop
+ sh $v0, SPU_VOICE_VOL_L($a0)
+
+ lhu $v0, PARAM_R($a1)
+ nop
+ sh $v0, SPU_VOICE_VOL_R($a0)
+
+ lhu $v0, PARAM_FREQ($a1)
+ nop
+ sh $v0, SPU_VOICE_FREQ($a0)
+
+ lhu $v0, PARAM_ADDR($a1)
+ nop
+ sh $v0, SPU_VOICE_ADDR($a0)
+
+ lhu $v0, PARAM_LOOP($a1)
+ nop
+ sh $v0, SPU_VOICE_LOOP($a0)
+
+
+ lw $v0, PARAM_ADSR($a1)
+ nop
+ sh $v0, SPU_VOICE_ADSR_L($a0)
+ srl $v0, 16
+ sh $v0, SPU_VOICE_ADSR_H($a0)
+
+
+ jr $ra
+ nop
+ \ No newline at end of file
diff --git a/libpsn00b/psxspu/transfer.s b/libpsn00b/psxspu/transfer.s
new file mode 100644
index 0000000..aed69dc
--- /dev/null
+++ b/libpsn00b/psxspu/transfer.s
@@ -0,0 +1,107 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+
+.section .text
+
+.global SpuSetTransferMode
+.type SpuSetTransferMode, @function
+SpuSetTransferMode:
+ la $v0, _spu_transfer_mode
+ sb $a0, 0($v0)
+ jr $ra
+ move $v0, $a0
+
+
+.global SpuSetTransferStartAddr
+.type SpuSetTransferStartAddr, @function
+SpuSetTransferStartAddr:
+ li $v0, 0x1000 # Check if value is valid
+ blt $a0, $v0, .bad_value
+ nop
+ li $v0, 0xffff
+ bgt $a0, $v0, .bad_value
+ nop
+
+ la $v1, _spu_transfer_addr
+ srl $v0, $a0, 3 # Set transfer destination address
+ sh $v0, 0($v1)
+
+ jr $ra
+ move $v0, $a0
+
+.bad_value:
+ jr $ra
+ move $v0, $0
+
+
+.global SpuWrite
+.type SpuWrite, @function
+SpuWrite:
+ addiu $sp, -8
+ sw $ra, 0($sp)
+ sw $a0, 4($sp)
+
+ lui $a3, IOBASE
+
+ lhu $v0, SPUCNT($a3) # Set transfer mode to Stop
+ nop
+ andi $v0, 0xffcf
+ sh $v0, SPUCNT($a3)
+ jal SpuCtrlSync
+ move $a0, $v0
+
+ la $v1, _spu_transfer_addr # Set SPU write address
+ lhu $v1, 0($v1)
+ nop
+ sh $v1, SPU_ADDR($a3)
+
+ lhu $v0, SPUCNT($a3) # Set transfer mode to DMA write
+ nop
+ ori $v0, 0x20
+ sh $v0, SPUCNT($a3)
+ #jal SpuCtrlSync # Locks up on most emulators (bit 5 in
+ #move $a0, $v0 # SPUSTAT likely not updating, seems to
+ # be okay to not wait for it on real HW)
+
+ lw $a0, 4($sp)
+
+.dma_wait: # Wait for SPU to be ready for DMA
+ lhu $v0, SPUSTAT($a3)
+ nop
+ andi $v0, 0x400 # Bit 8 in SPUSTAT never changes to 1 on
+ bnez $v0, .dma_wait # emulators so use bit 10 instead
+ nop
+
+ sw $a0, D4_MADR($a3) # Set DMA source address
+
+ li $v0, 0x10 # 16 words per block (64 bytes)
+ addiu $a1, 63 # Add by 63 to ensure all bytes get sent
+ srl $a1, 6 # Equivalent to divide by 64
+ andi $a1, 0xffff
+ sll $a1, 16
+ or $v0, $a1
+ sw $v0, D4_BCR($a3)
+
+ lui $v0, 0x0100 # Commence transfer
+ ori $v0, 0x0201
+ sw $v0, D4_CHCR($a3)
+
+ lw $ra, 0($sp)
+ addiu $sp, 8
+ jr $ra
+ nop
+
+
+.section .data
+
+.global _spu_transfer_mode
+.type _spu_transfer_mode, @object
+_spu_transfer_mode:
+ .word 0x0
+
+.global _spu_transfer_addr
+.type _spu_transfer_addr, @object
+_spu_transfer_addr:
+ .word 0x200 \ No newline at end of file
diff --git a/libpsn00b/readme.txt b/libpsn00b/readme.txt
new file mode 100644
index 0000000..c5fee34
--- /dev/null
+++ b/libpsn00b/readme.txt
@@ -0,0 +1,101 @@
+LibPSn00b, PSn00bSDK software libraries
+2019 Lameguy64 / Meido-Tek Productions
+
+Licensed under Mozilla Public License
+
+LibPSn00b make up the majority of PSn00bSDK as it provides the functions
+necessary for developing software for the PSX. Most libraries, mainly the
+GPU and GTE libraries are written mostly in assembly language.
+
+
+Brief library overview:
+
+ libc - Standard C library. Contains only a small subset of the full
+ standard C library, mostly string and memory manipulation
+ functions.
+
+ psxgpu - GPU library for video and graphics control. Most of the
+ important functions are implemented.
+
+ psxgte - GTE library for GTE accelerated vector transformations. Most
+ important functions are implemented.
+
+ psxapi - Provides access to most of the BIOS functions calls of the
+ PSX BIOS.
+
+ psxetc - Provides some misc functions such as debug font.
+
+ psxspu - SPU library. Basic functions such as hardware init, uploading
+ data to SPU RAM via DMA transfer and playing sound playback
+ are fully working but is currently lacking a number of
+ important functions, especially reverb.
+
+ Each library has its own readme file that contains its changelog, todo
+ list, credits and some additional details of the library.
+
+
+Compiling:
+
+ Compiling the LibPSn00b libraries requires GCC and binutils targetting
+ mipsel-unknown-elf built with libgcc. The path to those binaries must be
+ specified in your PATH environment variable and the binaries must be
+ prefixed by the target architecture (ie. mipsel-unknown-elf-gcc).
+
+ Simply run the Makefile in this directory using make (or gmake if you're
+ in a BSD environment). The Makefile should parse though each library
+ directory and run the makefile in it.
+
+
+Documentation:
+
+ Documentation of all the libraries are found in libn00bref.odf and it features
+ the same formatting as the official library documents. The document can be
+ exported in PDF format for easier viewing with a web browser or PDF viewer.
+
+
+Contributing:
+
+ Contributions are open for this project. Just obey the following rules
+ when making a contribution:
+
+ * If you add new functions to libpsn00b make sure you document them in
+ libn00bref.odf. Documentation using Doxygen is discouraged.
+ * This project desires functions that interact with hardware registers to
+ be written in assembly language. If you decide to write your functions
+ that interact with hardware registers in C make sure you define your
+ register pointers as volatile and they must work properly when compiled
+ with -O2 optimization.
+ * Functions must work flawlessly on both emulators and real hardware.
+ * Don't forget to put your user name in the readme file of the library
+ you've made a contribution on and details of what you've added/modified.
+ * New functions that are not originally in the official SDK must be marked
+ as original code in both the library headers and the libn00bref document.
+
+
+Library to-do list:
+
+ Since the PSn00bSDK project still a work in progress, essential libraries
+ for CD and controllers support are not yet created but are high priority.
+
+ libc - Yet to include a complete C standard function
+
+ psxcd - CD library. Not much progress as getting the CD controller to
+ cooperate has been one heck of a force to be reckoned with.
+ Gave up with my repeated attempts with no success. Absolutely
+ huge props to anyone who can figure out how to use the CD
+ controller properly! -Lameguy64
+
+ psxpad - Pad/tap/gun library. No work has been done on it currently.
+ Supporting the Konami Justifier can be ignored as the way how
+ that lightgun works is pretty crude and likely going to be
+ awful to implement. Namco's Guncon is a lot simpler to
+ implement.
+
+ psxpress - MDEC library. No work has been done on it currently. libpress
+ from the official libraries also contains functions for
+ encoding SPU compatible ADPCM data from raw PCM samples.
+
+ Before implementing CD and controller support a better interrupt handling
+ scheme must be implemented as it would save a lot of trouble. Details
+ regarding this interrupt handler implementation can be found in psxgpu's
+ readme document. \ No newline at end of file