diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-06-23 07:42:16 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-06-23 07:42:16 +0800 |
| commit | 7be9178c0f9b0e698a305ecc5c0c41fcc596a4fc (patch) | |
| tree | e98c627e1da5c764563774b89b0c06d7ac5ad0a4 /libpsn00b/psxgpu | |
| parent | ae9e545c3ed33d39ce21ae13ceb8337fa34901b8 (diff) | |
| download | psn00bsdk-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.s | 191 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/drawotag.s | 14 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/drawprim.s | 40 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/drawsync.s | 49 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/drawsynccallback.s | 103 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/getinterruptcallback.s | 17 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/interruptcallback.s | 48 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/loadimage.s | 4 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/putdispenv.s | 60 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/putdrawenv.s | 12 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/readme.txt | 34 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/resetgraph.s | 459 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/setvideomode.s | 6 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/vsynccallback.s | 2 |
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 |
