aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-06-23 07:42:16 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2019-06-23 07:42:16 +0800
commit7be9178c0f9b0e698a305ecc5c0c41fcc596a4fc (patch)
treee98c627e1da5c764563774b89b0c06d7ac5ad0a4 /libpsn00b/psxgpu
parentae9e545c3ed33d39ce21ae13ceb8337fa34901b8 (diff)
downloadpsn00bsdk-7be9178c0f9b0e698a305ecc5c0c41fcc596a4fc.tar.gz
LibPSn00b officially v0.10b, added psxsio library, better DrawSync() and VSync(), better reference manual.
Diffstat (limited to 'libpsn00b/psxgpu')
-rw-r--r--libpsn00b/psxgpu/dmacallback.s191
-rw-r--r--libpsn00b/psxgpu/drawotag.s14
-rw-r--r--libpsn00b/psxgpu/drawprim.s40
-rw-r--r--libpsn00b/psxgpu/drawsync.s49
-rw-r--r--libpsn00b/psxgpu/drawsynccallback.s103
-rw-r--r--libpsn00b/psxgpu/getinterruptcallback.s17
-rw-r--r--libpsn00b/psxgpu/interruptcallback.s48
-rw-r--r--libpsn00b/psxgpu/loadimage.s4
-rw-r--r--libpsn00b/psxgpu/putdispenv.s60
-rw-r--r--libpsn00b/psxgpu/putdrawenv.s12
-rw-r--r--libpsn00b/psxgpu/readme.txt34
-rw-r--r--libpsn00b/psxgpu/resetgraph.s459
-rw-r--r--libpsn00b/psxgpu/setvideomode.s6
-rw-r--r--libpsn00b/psxgpu/vsynccallback.s2
14 files changed, 799 insertions, 240 deletions
diff --git a/libpsn00b/psxgpu/dmacallback.s b/libpsn00b/psxgpu/dmacallback.s
new file mode 100644
index 0000000..b2f86cf
--- /dev/null
+++ b/libpsn00b/psxgpu/dmacallback.s
@@ -0,0 +1,191 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+.global DMACallback
+.type DMACallback, @function
+DMACallback:
+
+ # a0 - DMA channel
+ # a1 - Callback function
+
+ addiu $sp, -8
+ sw $ra, 0($sp)
+
+ beqz $a1, .Lremove_cb # Remove callback if function is NULL
+ nop
+
+ addiu $sp, -8 # Install IRQ handler for DMA handler
+ sw $a0, 0($sp) # if not set installed yet
+ sw $a1, 4($sp)
+
+ jal GetInterruptCallback
+ li $a0, 3
+
+ bnez $v0, .Lskip_install
+ nop
+
+ la $a1, _dma_handler
+ jal InterruptCallback
+ li $a0, 3
+
+.Lskip_install:
+
+ lw $a0, 0($sp)
+ lw $a1, 4($sp)
+ addiu $sp, 8
+
+ la $v0, _dma_func_table
+ sll $v1, $a0, 2
+ addu $v0, $v1
+ lw $v1, 0($v0)
+ sw $a1, 0($v0)
+ sw $v1, 4($sp)
+
+ lui $a2, IOBASE
+
+ lw $v0, DICR($a2) # Enable DMA interrupt
+ lui $v1, 0x1
+ sll $v1, $a0
+ or $v0, $v1
+ lui $v1, 0x80
+ or $v0, $v1
+ sw $v0, DICR($a2)
+
+ b .Lskip_remove
+ nop
+
+.Lremove_cb:
+
+ la $v0, _dma_func_table # Set callback address
+ sll $v1, $a0, 2
+ addu $v0, $v1
+ lw $v1, 0($v0)
+ sw $a1, 0($v0)
+ sw $v1, 4($sp)
+
+ lui $a2, IOBASE # Disable DMA interrupt
+ lw $v0, DICR($a2)
+ lui $v1, 0x1
+ sll $v1, $a0
+ .set noat
+ addiu $at, $0, -1
+ xor $v1, $at
+ and $v0, $v1
+ lui $v1, 0x7f00
+ xor $v1, $at
+ and $v0, $v1
+ .set at
+ sw $v0, DICR($a2)
+
+ jal _dma_has_cb # Check if callbacks are present
+ nop
+ bnez $v0, .Lskip_remove
+ nop
+ sw $0 , DICR($a2)
+
+ jal GetInterruptCallback # Check if callback is the DMA handler
+ li $a0, 3
+ la $v1, _dma_handler
+ bne $v0, $v1, .Lskip_remove
+ nop
+
+ li $a0, 3
+ jal InterruptCallback
+ move $a1, $0
+
+.Lskip_remove:
+
+ lw $ra, 0($sp)
+ lw $v0, 4($sp)
+ jr $ra
+ addiu $sp, 8
+
+
+.type _dma_has_cb, @function
+_dma_has_cb:
+
+ la $v1, _dma_func_table
+ li $t0, 6
+
+.Lscan_loop:
+
+ lw $v0, 0($v1)
+ addiu $v1, 4
+ bnez $v0, .Lhas_cb
+ nop
+
+ bgtz $t0, .Lscan_loop
+ addiu $t0, -1
+
+ jr $ra
+ move $v0, $0
+
+.Lhas_cb:
+
+ jr $ra
+ li $v0, 1
+
+
+.type _dma_handler, @function
+_dma_handler:
+
+ addiu $sp, -12
+ sw $ra, 0($sp)
+ sw $s0, 4($sp)
+ sw $s1, 8($sp)
+
+ move $s0, $0
+ la $s1, _dma_func_table
+
+.Lhandler_loop:
+
+ lui $a0, IOBASE
+ lw $v0, DICR($a0)
+ li $v1, 24
+ addu $v1, $s0
+ srl $v0, $v1
+ andi $v0, 0x1
+
+ lw $v1, 0($s1)
+
+ beqz $v0, .Lno_irq
+ addiu $s1, 4
+
+ beqz $v1, .Lno_irq
+ nop
+
+ jalr $v1
+ nop
+
+.Lno_irq:
+
+ blt $s0, 6, .Lhandler_loop
+ addi $s0, 1
+
+ lui $a0, IOBASE
+ lw $v0, DICR($a0)
+ nop
+ sw $v0, DICR($a0)
+
+ lw $ra, 0($sp)
+ lw $s0, 4($sp)
+ lw $s1, 8($sp)
+
+ jr $ra
+ addiu $sp, -12
+
+
+.section .data
+
+_dma_func_table:
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ \ No newline at end of file
diff --git a/libpsn00b/psxgpu/drawotag.s b/libpsn00b/psxgpu/drawotag.s
index 8a5ff0c..ba771fc 100644
--- a/libpsn00b/psxgpu/drawotag.s
+++ b/libpsn00b/psxgpu/drawotag.s
@@ -13,20 +13,20 @@ DrawOTag:
lui $a3, 0x1f80 # I/O segment base
-.gpu_wait: # Wait for GPU to be ready for commands & DMA
+ lui $v0, 0x0400 # Set DMA direction to CPUtoGPU
+ ori $v0, 0x2
+ sw $v0, GP1($a3)
+
+.Lgpu_wait: # Wait for GPU to be ready for commands & DMA
jal ReadGPUstat
nop
srl $v0, 26
andi $v0, 1
- beqz $v0, .gpu_wait
+ beqz $v0, .Lgpu_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)
+ sw $0 , D2_BCR($a3)
lui $v0, 0x0100 # Begin OT transfer!
ori $v0, 0x0401
diff --git a/libpsn00b/psxgpu/drawprim.s b/libpsn00b/psxgpu/drawprim.s
new file mode 100644
index 0000000..a216720
--- /dev/null
+++ b/libpsn00b/psxgpu/drawprim.s
@@ -0,0 +1,40 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.text
+
+.global DrawPrim
+.type DrawPrim, @function
+DrawPrim:
+
+ addiu $sp, -8
+ sw $ra, 0($sp)
+ sw $s0, 4($sp)
+
+ move $s0, $a0 # Wait for GPU to complete
+ jal DrawSync
+ move $a0, $0
+
+ lui $a3, IOBASE
+ lui $v0, 0x0400 # Set transfer direction to off
+ sw $v0, GP1($a3)
+
+ move $a0, $s0
+ lbu $a1, 3($a0) # Get length of primitive packet
+ addiu $a0, 4
+
+.Ltransfer_loop:
+ lw $v0, 0($a0)
+ addiu $a0, 4
+ sw $v0, GP0($a3)
+ bgtz $a1, .Ltransfer_loop
+ addiu $a1, -1
+
+ jal DrawSync
+ move $a0, $0
+
+ lw $ra, 0($sp)
+ lw $s0, 4($sp)
+ jr $ra
+ addiu $sp, 8 \ No newline at end of file
diff --git a/libpsn00b/psxgpu/drawsync.s b/libpsn00b/psxgpu/drawsync.s
index 149519d..66d37e2 100644
--- a/libpsn00b/psxgpu/drawsync.s
+++ b/libpsn00b/psxgpu/drawsync.s
@@ -8,19 +8,60 @@
.global DrawSync
.type DrawSync, @function
DrawSync:
+
+ bnez $a0, .Lgetwords
+ lui $a0, IOBASE
+
addiu $sp, -4
sw $ra, 0($sp)
-.gpu_wait: # Wait for GPU to be ready for commands and DMA
+ jal ReadGPUstat # Check if DMA enabled
+ nop
+ srl $v0, 29
+ andi $v0, 0x3
+
+ beqz $v0, .Lsimple_wait
+ nop
+
+.Ldma_wait:
+ lw $v0, D2_CHCR
+ nop
+ srl $v0, 24
+ andi $v0, 0x1
+ bnez $v0, .Ldma_wait
+ nop
+
+.Lgpu_wait:
jal ReadGPUstat
nop
- srl $v0, 0x1a
+ srl $v0, 26
andi $v0, 0x5
- li $v1, 5
- bne $v0, $v1, .gpu_wait
+ bne $v0, 5, .Lgpu_wait
+ nop
+
+ b .Lexit
nop
+
+.Lsimple_wait: # Wait for GPU to be ready for next DMA
+ jal ReadGPUstat
+ nop
+ srl $v0, 28
+ andi $v0, 0x1
+ beqz $v0, .Lsimple_wait
+ nop
+
+.Lexit:
lw $ra, 0($sp)
addiu $sp, 4
jr $ra
nop
+
+.Lgetwords:
+
+ lw $v0, D2_BCR($a0)
+ nop
+
+ jr $ra
+ srl $v0, 16
+ \ No newline at end of file
diff --git a/libpsn00b/psxgpu/drawsynccallback.s b/libpsn00b/psxgpu/drawsynccallback.s
new file mode 100644
index 0000000..c1e28fe
--- /dev/null
+++ b/libpsn00b/psxgpu/drawsynccallback.s
@@ -0,0 +1,103 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.text
+
+.global DrawSyncCallback
+.type DrawSyncCallback, @function
+DrawSyncCallback:
+
+ addiu $sp, -8
+ sw $ra, 0($sp)
+ sw $a0, 4($sp)
+
+ jal EnterCriticalSection
+ nop
+
+ beqz $a0, .Luninstall
+ nop
+ la $a1, _drawsync_handler
+ jal DMACallback
+ li $a0, 2
+ b .Lcontinue
+ nop
+
+.Luninstall:
+
+ move $a1, $0
+ jal DMACallback
+ li $a0, 2
+
+.Lcontinue:
+
+ lw $a0, 4($sp)
+ la $v1, _drawsync_func
+ lw $v0, 0($v1)
+ sw $a0, 0($v1)
+ sw $v0, 4($sp)
+
+.Lexit:
+
+ jal ExitCriticalSection
+ nop
+
+ lw $ra, 0($sp)
+ lw $v0, 4($sp)
+ jr $ra
+ addiu $sp, 8
+
+
+.type _drawsync_handler, @function
+_drawsync_handler:
+
+.Ldma_wait:
+
+ la $v0, _drawsync_func
+ lw $v0, 0($v0)
+ nop
+ beqz $v0, .Lskip
+ nop
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ lw $v0, D2_CHCR($a0)
+ nop
+ srl $v0, 24
+ andi $v0, 0x1
+
+ bnez $v0, .Ldma_wait
+ nop
+
+.Lgpu_wait:
+ jal ReadGPUstat
+ nop
+ srl $v0, 28
+ andi $v0, 0x1
+ beqz $v0, .Lgpu_wait
+ nop
+
+ la $v1, _drawsync_func
+ lw $v1, 0($v1)
+
+ lui $v0, 0x0400 # Set DMA direction to off
+ sw $v0, GP1($a0)
+
+ jalr $v1
+ nop
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+
+.Lskip:
+
+ jr $ra
+ nop
+
+
+.data
+
+_drawsync_func:
+ .word 0
+ \ No newline at end of file
diff --git a/libpsn00b/psxgpu/getinterruptcallback.s b/libpsn00b/psxgpu/getinterruptcallback.s
new file mode 100644
index 0000000..b465567
--- /dev/null
+++ b/libpsn00b/psxgpu/getinterruptcallback.s
@@ -0,0 +1,17 @@
+.set noreorder
+
+.section .text
+
+.global GetInterruptCallback
+.type GetInterruptCallback, @function
+GetInterruptCallback:
+
+ # a0 - Interrupt number
+
+ la $a1, _irq_func_table
+ sll $a0, 2
+ addu $a1, $a0
+
+ jr $ra
+ lw $v0, 0($a1)
+ \ No newline at end of file
diff --git a/libpsn00b/psxgpu/interruptcallback.s b/libpsn00b/psxgpu/interruptcallback.s
new file mode 100644
index 0000000..8e912d8
--- /dev/null
+++ b/libpsn00b/psxgpu/interruptcallback.s
@@ -0,0 +1,48 @@
+.set noreorder
+
+.include "hwregs_a.h"
+
+.section .text
+
+.global InterruptCallback
+.type InterruptCallback, @function
+InterruptCallback:
+
+ # a0 - Interrupt number
+ # a1 - Callback function
+
+ lui $a2, IOBASE
+
+ beqz $a1, .Ldisable_irq
+ nop
+
+ lw $v0, IMASK($a2) # Enable interrupt mask
+ li $v1, 1
+ sll $v1, $a0
+ or $v0, $v1
+
+ b .Lcont
+ sw $v0, IMASK($a2)
+
+.Ldisable_irq:
+
+.set noat
+ lw $v0, IMASK($a2) # Disable interrupt mask
+ li $v1, 1
+ sll $v1, $a0
+ addiu $at, $0 , -1
+ xor $v1, $at
+.set at
+ and $v0, $v1
+ sw $v0, IMASK($a2)
+
+.Lcont:
+
+ la $a2, _irq_func_table # Get address to IRQ function table
+
+ sll $v1, $a0, 2 # Compute the slot
+ addu $v1, $a2, $v1
+ lw $v0, 0($v1) # Get old handler address
+
+ jr $ra # Return and set new IRQ handler
+ sw $a1, 0($v1)
diff --git a/libpsn00b/psxgpu/loadimage.s b/libpsn00b/psxgpu/loadimage.s
index 2376b31..4a3b4e0 100644
--- a/libpsn00b/psxgpu/loadimage.s
+++ b/libpsn00b/psxgpu/loadimage.s
@@ -19,7 +19,7 @@ LoadImage:
lui $s0, 0x1f80 # Set I/O segment base address
-.gpu_wait: # Wait for GPU to be ready for commands and DMA
+.Lgpu_wait: # Wait for GPU to be ready for commands and DMA
jal ReadGPUstat
nop
srl $v0, 0x1a
@@ -27,7 +27,7 @@ LoadImage:
li $v1, 5
#srl $v0, 28
#andi $v0, 1
- bne $v0, $v1, .gpu_wait
+ bne $v0, $v1, .Lgpu_wait
nop
lui $v0, 0x400 # Set DMA direction to off
diff --git a/libpsn00b/psxgpu/putdispenv.s b/libpsn00b/psxgpu/putdispenv.s
index 0993e5c..4baa20e 100644
--- a/libpsn00b/psxgpu/putdispenv.s
+++ b/libpsn00b/psxgpu/putdispenv.s
@@ -32,53 +32,53 @@ PutDispEnv:
move $a1, $0 # To use as mode value
- bgt $a2, 560, .mode_640
+ bgt $a2, 560, .Lmode_640
nop
- bgt $a2, 400, .mode_512
+ bgt $a2, 400, .Lmode_512
nop
- bgt $a2, 352, .mode_384
+ bgt $a2, 352, .Lmode_384
nop
- bgt $a2, 280, .mode_320
+ bgt $a2, 280, .Lmode_320
nop
.set noat
-.mode_256:
+.Lmode_256:
li $at, 10
mult $at, $v1
li $a2, 0x24e
sll $v0, 2
add $a2, $v0
- b .mode_end
+ b .Lmode_end
li $v1, 0xa00
-.mode_320:
+.Lmode_320:
li $at, 8
mult $at, $v1
li $a2, 0x258
ori $a1, 0x01
sll $v0, 2
add $a2, $v0
- b .mode_end
+ b .Lmode_end
li $v1, 0xa00
-.mode_384:
+.Lmode_384:
li $at, 7
mult $at, $v1
li $a2, 0x21b
ori $a1, 0x64
sll $v0, 2
add $a2, $v0
- b .mode_end
+ b .Lmode_end
li $v1, 0xa80
-.mode_512:
+.Lmode_512:
li $at, 5
mult $at, $v1
li $a2, 0x267
ori $a1, 0x02
sll $v0, 2
add $a2, $v0
- b .mode_end
+ b .Lmode_end
li $v1, 0xa00
-.mode_640:
+.Lmode_640:
li $at, 4
mult $at, $v1
li $a2, 0x26c
@@ -86,15 +86,15 @@ PutDispEnv:
sll $v0, 2
add $a2, $v0
li $v1, 0xa00
-.mode_end:
+.Lmode_end:
.set at
mflo $v0
- bnez $v0, .no_default # Check if screen with is non zero
+ bnez $v0, .Lno_default # Check if screen with is non zero
nop
move $v0, $v1 # Use default if screen width is 0
-.no_default:
+.Lno_default:
addu $v0, $a2 # Apply horizontal display coordinates
sll $v0, 12
@@ -108,19 +108,19 @@ PutDispEnv:
lh $v0, DISP_dh($a0)
li $a2, 0x10
- ble $v0, 256, .mode_low
+ ble $v0, 256, .Lmode_low
nop
-.mode_high:
+.Lmode_high:
ori $a1, 0x04
-.mode_low:
+.Lmode_low:
lh $v0, DISP_sy($a0)
lh $v1, DISP_sh($a0)
add $a2, $v0
- bnez $v1, .no_default_vert
+ bnez $v1, .Lno_default_vert
nop
li $v1, 0xf0
-.no_default_vert:
+.Lno_default_vert:
add $v1, $a2
and $a2, 0x3ff
sll $v1, 10
@@ -134,28 +134,28 @@ PutDispEnv:
la $v0, _gpu_standard
lbu $v0, 0($v0)
nop
- beqz $v0, .config_ntsc
+ beqz $v0, .Lconfig_ntsc
nop
-.config_pal:
+.Lconfig_pal:
ori $a1, 0x08
-.config_ntsc:
+.Lconfig_ntsc:
lbu $v0, DISP_inter($a0)
lbu $v1, DISP_isrgb24($a0)
- beqz $v0, .no_inter
+ beqz $v0, .Lno_inter
nop
or $a1, 0x20
-.no_inter:
- beqz $v1, .no_rgb24
+.Lno_inter:
+ beqz $v1, .Lno_rgb24
nop
or $a1, 0x10
-.no_rgb24:
+.Lno_rgb24:
lbu $v0, DISP_inter($a0)
nop
- beqz $v0, .no_reverse
+ beqz $v0, .Lno_reverse
nop
or $a1, 0x80
-.no_reverse:
+.Lno_reverse:
lui $v0, 0x800 # Apply mode
or $a1, $v0
diff --git a/libpsn00b/psxgpu/putdrawenv.s b/libpsn00b/psxgpu/putdrawenv.s
index 69af437..c0d5676 100644
--- a/libpsn00b/psxgpu/putdrawenv.s
+++ b/libpsn00b/psxgpu/putdrawenv.s
@@ -97,7 +97,7 @@ PutDrawEnv:
lbu $v0, DRAW_isbg($a0)
nop
- beqz $v0, .no_fillVRAM
+ beqz $v0, .Lno_fillVRAM
nop
lw $v0, DRAW_isbg($a0) # FillVRAM
@@ -110,7 +110,7 @@ PutDrawEnv:
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
+ blt $v0, 511, .Lno_overflow # don't accept a height of 512
nop
li $v0, 511
@@ -118,19 +118,19 @@ PutDrawEnv:
andi $v1, 0xffff
or $v1, $v0
-.no_overflow:
+.Lno_overflow:
sw $v1, 28($a1) # 7
li $v0, 0x07ffffff # Packet header (length+terminator)
sw $v0, 0($a1)
-.no_fillVRAM:
+.Lno_fillVRAM:
-.gpu_wait: # Wait for GPU to become ready for commands and DMA
+.Lgpu_wait: # Wait for GPU to become ready for commands and DMA
jal ReadGPUstat
nop
srl $v0, 26
andi $v0, 1
- beqz $v0, .gpu_wait
+ beqz $v0, .Lgpu_wait
nop
jal DrawOTag
diff --git a/libpsn00b/psxgpu/readme.txt b/libpsn00b/psxgpu/readme.txt
index 0d44e72..8fe439b 100644
--- a/libpsn00b/psxgpu/readme.txt
+++ b/libpsn00b/psxgpu/readme.txt
@@ -23,39 +23,7 @@ Library header(s):
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.
-
- * (old) 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.
+ implemented (but should be trivial).
* StoreImage() equivalent yet to be implemented.
-
-
-Changelog:
-
- 05-23-2019 by Lameguy64:
-
- * Got custom exit handler set using SetCustomExitFromException() (BIOS
- function B(19h)) working. Currently used to acknowledge VSync IRQ but
- actual VSync handling is still done with events and needs to be
- transferred to the custom exit handler. At least it lets BIOS
- controller functions to work now. See doc/dev notes.txt for details
- on how this handler behaves.
-
- * Made stack usage a lot less wasteful in ResetGraph() (you only need
- to allocate N words on stack based on N arguments of the function
- being called.
diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s
index 189b1ad..ff0b353 100644
--- a/libpsn00b/psxgpu/resetgraph.s
+++ b/libpsn00b/psxgpu/resetgraph.s
@@ -1,5 +1,4 @@
.set noreorder
-.set noat
.include "hwregs_a.h"
@@ -16,21 +15,7 @@ ResetGraph:
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
+ bnez $v0, .Lskip_hook_init
nop
lui $a3, 0x1f80 # Base address for I/O
@@ -40,48 +25,51 @@ ResetGraph:
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)
- addiu $sp, -16
- addiu $sp, 16
-
- la $v1, _vsync_event_desc # Save event descriptor
- sw $v0, 0($v1)
-
- move $a0, $v0
- jal EnableEvent # Enable the opened event
- addiu $sp, -4
- addiu $sp, 4
-
+ sw $0 , IMASK($a3) # Clear IRQ settings
+
la $v0, _hooks_installed # Set installed flag
li $v1, 0x1
sb $v1, 0($v0)
- la $v0, _vsync_counter # Clear VSync counter
+ la $v0, _vsync_cb_func # Clear VSync callback function
sw $0 , 0($v0)
- la $v0, _vsync_callback_func # Clear callback function
- sw $0 , 0($v0)
-
- la $a0, _custom_exit
+ la $a1, _vsync_irq_callback # Install VSync interrupt callback
+ jal InterruptCallback
+ li $a0, 0
+
+ la $a0, _custom_exit # Set custom exit handler
jal SetCustomExitFromException
addiu $sp, -4
addiu $sp, 4
+ move $a0, $0
+ jal ChangeClearPAD # Disable VSync IRQ auto ack
+ addiu $sp, -4
+ addiu $sp, 4
+
+ li $a0, 3
+ move $a1, $0
+ jal ChangeClearRCnt # Remove RCnt timer IRQ auto ack
+ addiu $sp, -8
+ addiu $sp, 8
+
+ jal _96_remove # Remove CD handling left by the BIOS
+ nop
+
+ la $a0, resetgraph_msg
+ move $a1, $0
+ move $a2, $0
+ la $a1, _irq_func_table
+ la $a2, _custom_exit
+ jal printf
+ addiu $sp, -16
+ addiu $sp, 16
+
jal ExitCriticalSection # Re-enable interrupts
nop
-
-.skip_hook_init:
+
+.Lskip_hook_init:
lui $a3, 0x1f80
@@ -89,42 +77,40 @@ ResetGraph:
lui $v1, 0x0010
and $v0, $v1
la $v1, _gpu_standard
- beqz $v0, .not_pal
+ beqz $v0, .Lnot_pal
sw $0 , 0($v1)
li $v0, 1
sw $v0, 0($v1)
-.not_pal:
+.Lnot_pal:
- lw $a0, 4($sp) # Get argument value
+ lw $a0, 4($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
+
+ beq $a0, 1, .Lgpu_init_1
nop
- li $at, 3
- beq $a0, $at, .gpu_init_3
+ beq $a0, 3, .Lgpu_init_3
nop
sw $0 , GP1($a3) # Reset the GPU
- b .init_done
+ b .Linit_done
nop
-.gpu_init_1:
+.Lgpu_init_1:
sw $0 , D2_CHCR($a3) # Stop any DMA
-.gpu_init_3:
+.Lgpu_init_3:
li $v0, 0x1 # Reset the command buffer
sw $v0, GP1($a3)
-.init_done:
+.Linit_done:
lw $ra, 0($sp)
lw $a0, 4($sp) # Return
@@ -132,147 +118,312 @@ ResetGraph:
addiu $sp, 8
-.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)
+.global VSync # VSync function
+.type VSync, @function
+VSync:
+
+ addiu $sp, -12
+ sw $ra, 0($sp)
+ sw $s0, 4($sp)
+
+ lui $a3, IOBASE # Get GPU status (for interlace sync)
+ lw $s0, GP1($a3)
+
+.Lhwait_loop: # Get Hblank time
+ lw $v0, T1_CNT($a3)
+ nop
+ lw $v1, T1_CNT($a3)
nop
- andi $v0, $v0, 0x1
- beqz $v0, .exit
+ bne $v0, $v1, .Lhwait_loop
nop
+
+ la $a3, _vsync_lasthblank # Calculate Hblank time since last
+ lw $v1, 0($a3)
+ nop
+ subu $v0, $v1
+ andi $v0, 0xffff
+
+ beq $a0, 1, .Lhblank_exit # Return Hblank time only, no VSync
+ sw $v0, 8($sp) # Stored as return value
+
+ bgez $a0, .Lvsync # Vsync if argument is 0 and up
+ nop
+
+ la $v0, _vsync_rcnt # Return VSync count only
+ lw $v0, 0($v0)
+ nop
+ b .Lvsync_exit
+ sw $v0, 8($sp)
+
+.Lvsync:
- lw $v1, ISTAT($at)
+ bnez $a0, .Lnot_zero
nop
- andi $v0, $v1, 0x1
- beqz $v0, .exit
+ li $a0, 1
+
+.Lnot_zero:
+
+ la $v0, _vsync_rcnt # Call vsync sub function (with timeout)
+ lw $v0, 0($v0)
+ addiu $a1, $a0, 1
+ jal _vsync_sub
+ addu $a0, $v0, $a0
+
+ lui $v0, 0x40
+ and $v0, $s0, $v0
+ beqz $v0, .Lhblank_exit
+ nop
+
+ lui $a3, IOBASE # Interlace wait logic
+
+ lw $v0, GP1($a3)
+ nop
+ xor $v0, $s0, $v0
+ bltz $v0, .Lhblank_exit
+ lui $a0, 0x8000
+
+.Linterlace_wait:
+ lw $v0, GP1($a3)
+ nop
+ xor $v0, $s0, $v0
+ and $v0, $a0
+ beqz $v0, .Linterlace_wait
nop
- #xori $v1, $v1, 0x1 # Acknowledge the IRQ
- #sw $v1, ISTAT($at) # Commented out as it breaks BIOS pads
+.Lhblank_exit: # Set current Hblank as last value
- la $v1, _vsync_counter # Increment VSync counter
- lw $v0, 0($v1)
+ la $a2, _vsync_lasthblank
+
+.Lhwait2_loop:
+ lw $v0, T1_CNT($a3)
+ nop
+ lw $v1, T1_CNT($a3)
+ sw $v0, 0($a2)
+ bne $v0, $v1, .Lhwait2_loop
nop
- addiu $v0, 1
- sw $v0, 0($v1)
- la $v0, _vsync_callback_func # Check if a callback function is set
+.Lvsync_exit:
+
+ lw $ra, 0($sp)
+ lw $s0, 4($sp)
+ lw $v0, 8($sp)
+ jr $ra
+ addiu $sp, 12
+
+
+.type _vsync_sub, @function
+_vsync_sub:
+
+ # a0 - VSync destination count
+ # a1 - Timeout ratio (number of vsyncs to wait relative to vsync count)
+
+ addiu $sp, -4
+ sw $ra, 0($sp)
+
+ sll $a1, 15 # Timeout counter
+
+ la $v0, _vsync_rcnt
lw $v0, 0($v0)
nop
- beqz $v0, .exit
+ bge $v0, $a0, .Lvsync_sub_exit
nop
+
+.Lvsync_wait:
- addiu $sp, -0x20 # Save return address
- sw $ra, 28($sp)
-
- jalr $v0 # Execute user function
+ addiu $a1, -1
+
+ la $v1, 0xffffffff
+ bne $a1, $v1, .Lnot_timeout
nop
- lw $ra, 28($sp) # Restore previous return address
- addiu $sp, 0x20
+ la $a0, vsynctimeout_msg
+ jal puts
+ addiu $sp, -8
+
+ jal ChangeClearPAD
+ move $a0, $0
+
+ li $a0, 3
+ jal ChangeClearRCnt
+ move $a1, $0
+
+ addiu $sp, 8
+ b .Lvsync_sub_exit
+ li $v0, -1
+
+.Lnot_timeout:
-.exit:
- jr $ra
+ la $v0, _vsync_rcnt
+ lw $v0, 0($v0)
+ nop
+ blt $v0, $a0, .Lvsync_wait
nop
+
+.Lvsync_sub_exit:
+
+ lw $ra, 0($sp)
+ addiu $sp, 4
+ jr $ra
+ move $v0, $0
-.global _vsync_func_2
-.type _vsync_func_2, @function
-_vsync_func_2:
- lui $at, 0x1f80 # Check if there's a VSync IRQ
- lw $v0, IMASK($at)
- nop
- andi $v0, $v0, 0x1
- beqz $v0, .exit_2
+.type _vsync_irq_callback, @function
+_vsync_irq_callback:
+
+ lui $a0, IOBASE
+
+ la $v1, _vsync_rcnt # Increment VSync root counter
+ lw $v0, 0($v1)
nop
+ addiu $v0, 1
+ sw $v0, 0($v1)
- lw $v1, ISTAT($at)
+ la $v0, _vsync_cb_func # Check if a callback function is set
+ lw $v0, 0($v0)
nop
- andi $v0, $v1, 0x1
- beqz $v0, .exit_2
+ beqz $v0, .Lno_callback
nop
- xori $v1, $v1, 0x1 # Acknowledge the IRQ
- sw $v1, ISTAT($at)
-
-.exit_2:
+ addiu $sp, -4 # Save return address
+ sw $ra, 0($sp)
+ jalr $v0 # Execute user callback function
+ nop
+ lw $ra, 0($sp) # Restore previous return address
+ addiu $sp, 4
- j ReturnFromException
+ lui $a0, IOBASE
+
+.Lno_callback:
+
+ jr $ra
nop
+
+# Global ISR handler of PSn00bSDK
-.global VSync # VSync function
-.type VSync, @function
-VSync:
- addiu $sp, -4
- sw $ra, 0($sp)
+.set at
+
+.type _global_isr, @function
+_global_isr:
+
+ lui $a0, IOBASE # Get IRQ status
+
+.Lisr_loop:
- la $a1, _vsync_counter
- lw $v0, 0($a1)
+ lui $a0, IOBASE # Get IRQ status
+ lw $v0, IMASK($a0)
nop
-.loop:
- lw $v1, 0($a1)
+
+ srl $v0, $s1 # Check IRQ mask bit if set
+ andi $v0, 0x1
+
+ beqz $v0, .Lno_irq # Don't execute callback if IRQ not enabled
nop
- beq $v0, $v1, .loop
+
+ lw $v0, ISTAT($a0)
nop
-
- la $v0, _gpu_current_field # Get last field value
- lbu $v1, 0($v0)
-.wait_field: # Wait for field bit to change
- jal ReadGPUstat
+ srl $v0, $s1 # Check IRQ status bit if set
+ andi $v0, 0x1
+ beqz $v0, .Lno_irq # Don't execute callback if no IRQ
nop
- srl $v0, 31
- beq $v0, $v1, .wait_field
+
+ lw $v1, 0($s0) # Load IRQ callback function
+ nop
+
+ lw $v0, ISTAT($a0) # Acknowledge the IRQ (by writing a 0 bit)
+ li $a1, 1
+ sll $a1, $s1
+ addiu $a2, $0 , -1
+ xor $a1, $a2
+ sw $a1, ISTAT($a0)
+
+ beqz $v1, .Lno_irq # Don't execute if callback is not set
nop
- la $v1, _gpu_current_field # Store new field value
- sb $v0, 0($v1)
-
- lw $ra, 0($sp)
- addiu $sp, 4
- jr $ra
+ jalr $v1 # Call interrupt handler
nop
+
+.Lno_irq:
+
+ addiu $s0, 4
+
+ blt $s1, 11, .Lisr_loop
+ addiu $s1, 1
+ j ReturnFromException
+ nop
+
.section .data
-.global library_credits
-.type library_credits, @object
-library_credits:
- .string "psxgpu programs by Lameguy64"
+# VSync root counter
+.type _vsync_rcnt, @object
+_vsync_rcnt:
+ .word 0
+
+.type _vsync_lasthblank, @object
+_vsync_lasthblank:
+ .word 0
+
+.comm _vsync_cb_func, 4, 4
+
+.comm _gpu_standard, 4, 4
+.comm _gpu_current_field, 4, 4
+.comm _hooks_installed, 4, 4
+# Global ISR callback table
+
+.global _irq_func_table
+.type _irq_func_table, @object
+_irq_func_table:
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+
+# Global ISR hook structure
.type _custom_exit, @object
_custom_exit:
- .word _vsync_func_2 # pc
- .word _vsync_stack # sp
- .word 0 # fp
- .word 0 # s0
- .word 0 # s1
- .word 0 # s2
- .word 0 # s3
- .word 0 # s4
- .word 0 # s5
- .word 0 # s6
- .word 0 # s7
- .word _gp # gp
-
- .fill 60
-_vsync_stack:
+ .word _global_isr # pc
+ .word _custom_exit_stack # sp
+ .word 0 # fp
+ .word _irq_func_table # s0
+ .word 0 # s1
+ .word 0 # s2
+ .word 0 # s3
+ .word 0 # s4
+ .word 0 # s5
+ .word 0 # s6
+ .word 0 # s7
+ .word _gp # gp
+
+# Global ISR stack
+ .fill 124
+_custom_exit_stack:
.fill 4
-.type _vsync_counter, @object
-_vsync_counter:
- .word 0
-
-.comm _vsync_callback_func, 4, 4
-.comm _vsync_event_desc, 4, 4
+
+.type vsynctimeout_msg, @object
+vsynctimeout_msg:
+ .asciiz "VSync: timeout\n"
-.comm _gpu_standard, 4, 4
-.comm _gpu_current_field, 4, 4
-.comm _hooks_installed, 4, 4
+.type resetgraph_msg, @object
+resetgraph_msg:
+ .asciiz "ResetGraph:itb=%08x,ehk=%08x\n"
+
+.global psxgpu_credits
+.type psxgpu_credits, @object
+psxgpu_credits:
+ .ascii "psxgpu programs by Lameguy64\n"
+ .asciiz "2019 PSn00bSDK Project / Meido-Tek Productions\n"
+ \ No newline at end of file
diff --git a/libpsn00b/psxgpu/setvideomode.s b/libpsn00b/psxgpu/setvideomode.s
index 718a4dd..4395f0a 100644
--- a/libpsn00b/psxgpu/setvideomode.s
+++ b/libpsn00b/psxgpu/setvideomode.s
@@ -30,13 +30,13 @@ SetVideoMode:
andi $a1, 0xf7 # Mask off PAL bit
la $v0, _gpu_standard
- beqz $a0, .set_done
+ beqz $a0, .Lset_done
sw $0 , 0($v0)
li $v1, 1
sw $v1, 0($v0)
- b .set_done
+ b .Lset_done
or $a1, 0x8
-.set_done:
+.Lset_done:
lui $v0, 0x800 # Apply new mode
or $a1, $v0
diff --git a/libpsn00b/psxgpu/vsynccallback.s b/libpsn00b/psxgpu/vsynccallback.s
index 1f96bbc..4be29c8 100644
--- a/libpsn00b/psxgpu/vsynccallback.s
+++ b/libpsn00b/psxgpu/vsynccallback.s
@@ -12,7 +12,7 @@ VSyncCallback:
sw $a0, 4($sp)
lw $a0, 4($sp)
- la $v0, _vsync_callback_func
+ la $v0, _vsync_cb_func
sw $a0, 0($v0)
jal ExitCriticalSection