mirror of
https://github.com/zeldaret/oot
synced 2026-08-04 09:09:22 -04:00
da4a1f661c
* [rsp] Introduce microcode build process, disassemble and build both rspboot versions * Suggested changes * Check-in tool for generating armips.cpp from upstream sources, regen armips.cpp against a newer commit * License armips_gen.py, add notice that armips.cpp is automatically generated * Qualify comment with X105 * Clarify the assumed purpose of rspboot releasing SP_SEMAPHORE
128 lines
4.0 KiB
ArmAsm
128 lines
4.0 KiB
ArmAsm
/**
|
|
* @file rspboot.s
|
|
*
|
|
* This RSP microcode program acts as a loader for other microcodes. This ucode:
|
|
* - (Optionally) Waits for the RDP to go idle
|
|
* - Loads a ucode's .data section to the start of DMEM
|
|
* - Loads a ucode's .text section to RSPBOOT_ENTRYPOINT
|
|
* - Jumps to the loaded ucode
|
|
*
|
|
* Along the way it also checks whether the task scheduler running on the CPU has
|
|
* requested a yield and, if so, halts the RSP.
|
|
*/
|
|
.rsp
|
|
#include "rcp.h"
|
|
#include "sptask.h"
|
|
#include "rspboot.h"
|
|
|
|
// $1 is expected to contain the OSTask pointer by many ucodes
|
|
OSTask_reg equ $1
|
|
|
|
.create CODE_FILE, IMEM_START_VA
|
|
|
|
entry:
|
|
j start
|
|
addi OSTask_reg, $zero, OSTASK_ADDR
|
|
|
|
load_ucode_text_and_enter:
|
|
// Read the ucode .text DRAM address from the OSTask
|
|
lw $2, OS_TASK_OFF_UCODE(OSTask_reg)
|
|
// Always DMA as much as will fit in IMEM to RSPBOOT_ENTRYPOINT
|
|
addi $3, $zero, (IMEM_SIZE - (RSPBOOT_ENTRYPOINT - IMEM_START)) - 1
|
|
addi $7, $zero, RSPBOOT_ENTRYPOINT
|
|
// Start the DMA, assuming it's not busy having waited for it while
|
|
// loading the ucode .data
|
|
mtc0 $7, SP_MEM_ADDR
|
|
mtc0 $2, SP_DRAM_ADDR
|
|
mtc0 $3, SP_RD_LEN
|
|
// Wait for .text to load
|
|
@@while_dma_busy:
|
|
mfc0 $4, SP_DMA_BUSY
|
|
bnez $4, @@while_dma_busy
|
|
nop
|
|
// Check yield one more time
|
|
jal check_yield
|
|
nop
|
|
// Release the semaphore just in case a prior task or the CPU failed to release it
|
|
// and jump to the ucode that was loaded
|
|
jr $7
|
|
mtc0 $zero, SP_SEMAPHORE
|
|
|
|
check_yield:
|
|
// Check the YIELD bit in SP_STATUS: if it is set enter yield_break,
|
|
// otherwise return
|
|
mfc0 $8, SP_STATUS
|
|
andi $8, $8, SP_STATUS_YIELD
|
|
bnez $8, yield_break
|
|
nop
|
|
// No need to yield, return to caller
|
|
jr $ra
|
|
yield_break:
|
|
// Release the semaphore (note this happens even if there is no yield as it
|
|
// is in the delay slot of the above instruction)
|
|
mtc0 $zero, SP_SEMAPHORE
|
|
// Update the RSP status to signal task complete and yielded, clear the
|
|
// yield request
|
|
li $8, (SP_SET_TASKDONE | SP_SET_YIELDED | SP_CLR_YIELD)
|
|
mtc0 $8, SP_STATUS
|
|
// Halt the RSP
|
|
break
|
|
nop
|
|
|
|
// Everything up to here needs to end before RSPBOOT_ENTRYPOINT so it's not overwritten by the .text loader
|
|
.if . > RSPBOOT_ENTRYPOINT_VA
|
|
.error "Not enough reserved IMEM for .text bootstrapper"
|
|
.endif
|
|
|
|
start:
|
|
// Check the DP_WAIT flag, if not set branch straight to loading ucode .data
|
|
lw $2, OS_TASK_OFF_FLAGS(OSTask_reg)
|
|
andi $2, $2, OS_TASK_DP_WAIT
|
|
beqz $2, load_ucode_data
|
|
nop
|
|
// If the flag is set, we need to wait for the RDP to become idle just in case
|
|
// it's still reading commands from DMEM in XBUS mode. First check if we need
|
|
// to yield to another task.
|
|
jal check_yield
|
|
nop
|
|
// Now poll RDP DMA busy
|
|
mfc0 $2, DPC_STATUS
|
|
andi $2, $2, DPC_STATUS_DMA_BUSY
|
|
// If the RDP is still busy, check yield again. This will return to the same
|
|
// return address as the above jal since $ra has not been clobbered since then.
|
|
bgtz $2, check_yield
|
|
nop
|
|
load_ucode_data:
|
|
// Load the DRAM address and size of the ucode .data from the OSTask
|
|
lw $2, OS_TASK_OFF_UDATA(OSTask_reg)
|
|
lw $3, OS_TASK_OFF_UDATA_SZ(OSTask_reg)
|
|
addi $3, $3, -1
|
|
// Wait for a DMA slot to free
|
|
@@while_dma_full:
|
|
mfc0 $30, SP_DMA_FULL
|
|
bnez $30, @@while_dma_full
|
|
nop
|
|
// Submit the DMA transfer for the ucode .data, targeting the start of DMEM
|
|
mtc0 $zero, SP_MEM_ADDR
|
|
mtc0 $2, SP_DRAM_ADDR
|
|
mtc0 $3, SP_RD_LEN
|
|
// Wait for the transfer to complete
|
|
@@while_dma_busy:
|
|
mfc0 $4, SP_DMA_BUSY
|
|
bnez $4, @@while_dma_busy
|
|
nop
|
|
// Check whether we need to yield, does not return if we do
|
|
jal check_yield
|
|
nop
|
|
// Jump to ucode .text loader
|
|
j load_ucode_text_and_enter
|
|
nop
|
|
|
|
.align 0x10
|
|
|
|
.if . > IMEM_END_VA
|
|
.error "Not enough room in IMEM"
|
|
.endif
|
|
|
|
.close
|