diff options
Diffstat (limited to 'rsp/rspboot.s')
| -rw-r--r-- | rsp/rspboot.s | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/rsp/rspboot.s b/rsp/rspboot.s new file mode 100644 index 000000000..b3dc968d4 --- /dev/null +++ b/rsp/rspboot.s @@ -0,0 +1,127 @@ +/** + * @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 |
