aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu
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/psxgpu
downloadpsn00bsdk-f3e040230772f978540a71aea43dfde200992922.tar.gz
First commit
Diffstat (limited to 'libpsn00b/psxgpu')
-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
19 files changed, 1087 insertions, 0 deletions
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
+