summaryrefslogtreecommitdiff
path: root/rsp/rspboot.s
diff options
context:
space:
mode:
Diffstat (limited to 'rsp/rspboot.s')
-rw-r--r--rsp/rspboot.s127
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