.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