summaryrefslogtreecommitdiff
path: root/src/Dolphin/dsp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Dolphin/dsp')
-rw-r--r--src/Dolphin/dsp/dsp.c145
-rw-r--r--src/Dolphin/dsp/dsp_debug.c5
-rw-r--r--src/Dolphin/dsp/dsp_task.c389
3 files changed, 539 insertions, 0 deletions
diff --git a/src/Dolphin/dsp/dsp.c b/src/Dolphin/dsp/dsp.c
new file mode 100644
index 0000000..cab7a39
--- /dev/null
+++ b/src/Dolphin/dsp/dsp.c
@@ -0,0 +1,145 @@
+#include "dolphin/dsp.h"
+#include "dolphin/os.h"
+
+#include "dolphin/dsp_regs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char* __DSPVersion =
+ "<< Dolphin SDK - DSP\trelease build: Sep 5 2002 05:35:13 (0x2301) >>";
+
+static s32 __DSP_init_flag = 0;
+extern DSPTaskInfo* __DSP_tmp_task;
+extern DSPTaskInfo* __DSP_last_task;
+extern DSPTaskInfo* __DSP_first_task;
+extern DSPTaskInfo* __DSP_curr_task;
+
+extern void __DSPHandler(__OSInterrupt, OSContext*);
+extern void __DSP_debug_printf(const char* fmt, ...);
+extern void __DSP_boot_task(DSPTaskInfo* task);
+
+u32 DSPCheckMailToDSP(void) { return (__DSPRegs[0] >> 0xF) & 1; }
+
+u32 DSPCheckMailFromDSP(void) { return (__DSPRegs[2] >> 0xF) & 1; }
+
+u32 DSPReadMailFromDSP() {
+ u16 reg1;
+ u16 reg2;
+ reg1 = __DSPRegs[2];
+ reg2 = __DSPRegs[3];
+ return reg1 << 16 | reg2;
+}
+
+void DSPSendMailToDSP(u32 mail) {
+ __DSPRegs[0] = mail >> 16;
+ __DSPRegs[1] = mail;
+}
+
+void DSPInit(void) {
+ u32 oldInt;
+ u16 reg;
+ __DSP_debug_printf("DSPInit(): Build Date: %s %s\n", "Sep 5 2002", "05:35:13");
+
+ if (__DSP_init_flag == 1) {
+ return;
+ }
+ OSRegisterVersion(__DSPVersion);
+ oldInt = OSDisableInterrupts();
+ __OSSetInterruptHandler(7, __DSPHandler);
+ __OSUnmaskInterrupts(0x1000000);
+ reg = __DSPRegs[5];
+ reg = (reg & ~0xA8) | 0x800;
+ __DSPRegs[5] = reg;
+ reg = __DSPRegs[5];
+ reg = reg & ~0xAC;
+ __DSPRegs[5] = reg;
+ __DSP_tmp_task = 0;
+ __DSP_curr_task = 0;
+ __DSP_last_task = 0;
+ __DSP_first_task = 0;
+ __DSP_init_flag = 1;
+ OSRestoreInterrupts(oldInt);
+}
+
+void DSPReset(void) {
+ u16 reg;
+ u32 oldInt;
+ oldInt = OSDisableInterrupts();
+ reg = __DSPRegs[5];
+ __DSPRegs[5] = (reg & ~0xA8) | 0x801;
+ __DSP_init_flag = 0;
+ OSRestoreInterrupts(oldInt);
+}
+
+void DSPHalt(void) {
+ u16 reg;
+ u32 oldInt;
+ oldInt = OSDisableInterrupts();
+ reg = __DSPRegs[5];
+ __DSPRegs[5] = (reg & ~0xA8) | 4;
+ OSRestoreInterrupts(oldInt);
+}
+
+u32 DSPGetDMAStatus(void) { return __DSPRegs[5] & 0x200; }
+
+#ifdef FULL_FRANK
+DSPTaskInfo* DSPAddTask(DSPTaskInfo* task) {
+ u32 oldInt;
+ oldInt = OSDisableInterrupts();
+ __DSP_insert_task(task);
+ task->state = 0;
+ task->flags = 1;
+ OSRestoreInterrupts(oldInt);
+ if (task == __DSP_first_task) {
+ __DSP_boot_task(task);
+ }
+
+ return task;
+}
+#else
+#pragma push
+#include "__ppc_eabi_linker.h"
+/* clang-format off */
+#pragma optimization_level 0
+#pragma optimizewithasm off
+extern void __DSP_insert_task(DSPTaskInfo* task);
+asm DSPTaskInfo* DSPAddTask(DSPTaskInfo* task) {
+ nofralloc
+ mflr r0
+ stw r0, 4(r1)
+ stwu r1, -0x18(r1)
+ stw r31, 0x14(r1)
+ stw r30, 0x10(r1)
+ mr r30, r3
+ bl OSDisableInterrupts
+ addi r31, r3, 0
+ addi r3, r30, 0
+ bl __DSP_insert_task
+ li r0, 0
+ stw r0, 0(r30)
+ li r0, 1
+ addi r3, r31, 0
+ stw r0, 8(r30)
+ bl OSRestoreInterrupts
+ lwz r0, __DSP_first_task
+ cmplw r30, r0
+ bne lbl_8036FBB4
+ mr r3, r30
+ bl __DSP_boot_task
+lbl_8036FBB4:
+ mr r3, r30
+ lwz r0, 0x1c(r1)
+ lwz r31, 0x14(r1)
+ lwz r30, 0x10(r1)
+ addi r1, r1, 0x18
+ mtlr r0
+ blr
+}
+#pragma pop
+#endif
+/* clang-format on */
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/Dolphin/dsp/dsp_debug.c b/src/Dolphin/dsp/dsp_debug.c
new file mode 100644
index 0000000..22455a3
--- /dev/null
+++ b/src/Dolphin/dsp/dsp_debug.c
@@ -0,0 +1,5 @@
+#include "types.h"
+
+void __DSP_debug_printf(const char* fmt, ...) {
+ // UNUSED(fmt);
+}
diff --git a/src/Dolphin/dsp/dsp_task.c b/src/Dolphin/dsp/dsp_task.c
new file mode 100644
index 0000000..2fe7f15
--- /dev/null
+++ b/src/Dolphin/dsp/dsp_task.c
@@ -0,0 +1,389 @@
+#include "dolphin/dsp.h"
+#include "dolphin/dsp_regs.h"
+
+DSPTaskInfo* __DSP_curr_task;
+DSPTaskInfo* __DSP_first_task;
+DSPTaskInfo* __DSP_last_task;
+DSPTaskInfo* __DSP_tmp_task;
+DSPTaskInfo* __DSP_rude_task;
+
+BOOL __DSP_rude_task_pending;
+
+void __DSPHandler(__OSInterrupt, OSContext* context) {
+ DSPTaskInfo* tmp_task;
+ OSContext exceptionContext;
+ u16 tmp;
+ u32 mail;
+
+ tmp = __DSPRegs[5];
+ tmp = (u16)(tmp & ~0x28) | 0x80;
+ __DSPRegs[5] = tmp;
+
+ OSClearContext(&exceptionContext);
+ OSSetCurrentContext(&exceptionContext);
+
+ while (!DSPCheckMailFromDSP())
+ ;
+ mail = DSPReadMailFromDSP();
+
+ if ((__DSP_curr_task->flags & DSP_TASK_FLAG_CANCEL) && (mail == 0xDCD10002)) {
+ mail = 0xDCD10003;
+ }
+
+ switch (mail) {
+ case 0xDCD10000:
+ __DSP_curr_task->state = DSP_TASK_STATE_RUN;
+
+ if (__DSP_curr_task->init_cb) {
+ (*(__DSP_curr_task->init_cb))((void*)(__DSP_curr_task));
+ }
+ break;
+ case 0xDCD10001:
+ __DSP_curr_task->state = DSP_TASK_STATE_RUN;
+ if (__DSP_curr_task->res_cb) {
+ (*(__DSP_curr_task->res_cb))((void*)(__DSP_curr_task));
+ }
+ break;
+ case 0xDCD10002:
+ if (__DSP_rude_task_pending) {
+
+ if (__DSP_curr_task == __DSP_rude_task) {
+ DSPSendMailToDSP(0xCDD10003);
+ while (DSPCheckMailToDSP()) {
+ }
+
+ __DSP_rude_task = NULL;
+ __DSP_rude_task_pending = FALSE;
+
+ if (__DSP_curr_task->res_cb) {
+ (*(__DSP_curr_task->res_cb))((void*)(__DSP_curr_task));
+ }
+
+ break;
+ } else {
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP())
+ ;
+ __DSP_exec_task(__DSP_curr_task, __DSP_rude_task);
+
+ __DSP_curr_task->state = DSP_TASK_STATE_YIELD;
+ __DSP_curr_task = __DSP_rude_task;
+
+ __DSP_rude_task = NULL;
+ __DSP_rude_task_pending = FALSE;
+
+ break;
+ }
+ }
+
+ if (__DSP_curr_task->next == NULL) {
+
+ if (__DSP_curr_task == __DSP_first_task) {
+
+ DSPSendMailToDSP(0xCDD10003);
+ while (DSPCheckMailToDSP())
+ ;
+
+ if (__DSP_curr_task->res_cb) {
+ (*(__DSP_curr_task->res_cb))((void*)(__DSP_curr_task));
+ }
+
+ } else {
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP()) {
+ }
+
+ __DSP_exec_task(__DSP_curr_task, __DSP_first_task);
+
+ __DSP_curr_task->state = DSP_TASK_STATE_YIELD;
+ __DSP_curr_task = __DSP_first_task;
+ }
+
+ } else {
+
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP()) {
+ }
+
+ __DSP_exec_task(__DSP_curr_task, __DSP_curr_task->next);
+
+ __DSP_curr_task->state = DSP_TASK_STATE_YIELD;
+ __DSP_curr_task = __DSP_curr_task->next;
+ }
+ break;
+ case 0xDCD10003:
+ if (__DSP_rude_task_pending) {
+
+ if (__DSP_curr_task->done_cb) {
+ (*(__DSP_curr_task->done_cb))((void*)(__DSP_curr_task));
+ }
+
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP())
+ ;
+
+ __DSP_exec_task(NULL, __DSP_rude_task);
+
+ __DSP_remove_task(__DSP_curr_task);
+ __DSP_curr_task = __DSP_rude_task;
+
+ __DSP_rude_task = NULL;
+ __DSP_rude_task_pending = FALSE;
+
+ break;
+ }
+
+ if (__DSP_curr_task->next == NULL) {
+
+ if (__DSP_curr_task == __DSP_first_task) {
+
+ if (__DSP_curr_task->done_cb) {
+ (*(__DSP_curr_task->done_cb))((void*)(__DSP_curr_task));
+ }
+
+ DSPSendMailToDSP(0xCDD10002);
+ while (DSPCheckMailToDSP())
+ ;
+
+ __DSP_curr_task->state = DSP_TASK_STATE_DONE;
+
+ __DSP_remove_task(__DSP_curr_task);
+
+ } else {
+
+ if (__DSP_curr_task->done_cb) {
+ (*(__DSP_curr_task->done_cb))((void*)(__DSP_curr_task));
+ }
+
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP())
+ ;
+
+ __DSP_curr_task->state = DSP_TASK_STATE_DONE;
+ __DSP_exec_task(NULL, __DSP_first_task);
+
+ __DSP_curr_task = __DSP_first_task;
+ __DSP_remove_task(__DSP_last_task);
+ }
+
+ } else {
+ if (__DSP_curr_task->done_cb) {
+ (*(__DSP_curr_task->done_cb))((void*)(__DSP_curr_task));
+ }
+ DSPSendMailToDSP(0xCDD10001);
+ while (DSPCheckMailToDSP())
+ ;
+
+ __DSP_curr_task->state = DSP_TASK_STATE_DONE;
+ __DSP_exec_task(NULL, __DSP_curr_task->next);
+
+ __DSP_curr_task = __DSP_curr_task->next;
+ __DSP_remove_task(__DSP_curr_task->prev);
+ }
+ break;
+
+ case 0xDCD10004:
+
+ if (__DSP_curr_task->req_cb) {
+ (*(__DSP_curr_task->req_cb))((void*)(__DSP_curr_task));
+ }
+ break;
+ default:
+ break;
+ }
+ OSClearContext(&exceptionContext);
+ OSSetCurrentContext(context);
+}
+
+void __DSP_exec_task(DSPTaskInfo* curr, DSPTaskInfo* next) {
+ if (curr) {
+ DSPSendMailToDSP((u32)(curr->dram_mmem_addr));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(curr->dram_length));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(curr->dram_addr));
+ while (DSPCheckMailToDSP())
+ ;
+ } else {
+
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ }
+
+ DSPSendMailToDSP((u32)(next->iram_mmem_addr));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(next->iram_length));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(next->iram_addr));
+ while (DSPCheckMailToDSP())
+ ;
+
+ if (DSP_TASK_STATE_INIT == next->state) {
+ DSPSendMailToDSP((u32)(next->dsp_init_vector));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(0));
+ while (DSPCheckMailToDSP())
+ ;
+ } else {
+ DSPSendMailToDSP((u32)(next->dsp_resume_vector));
+ while (DSPCheckMailToDSP())
+ ;
+ DSPSendMailToDSP((u32)(next->dram_mmem_addr));
+ while (DSPCheckMailToDSP())
+ ;
+
+ DSPSendMailToDSP((u32)(next->dram_length));
+ while (DSPCheckMailToDSP())
+ ;
+
+ DSPSendMailToDSP((u32)(next->dram_addr));
+ while (DSPCheckMailToDSP())
+ ;
+ }
+}
+
+
+#define MSG_BASE 0x80F30000
+void __DSP_boot_task(DSPTaskInfo* task) {
+
+ volatile u32 mail;
+
+ while (!DSPCheckMailFromDSP())
+ ;
+
+ mail = DSPReadMailFromDSP();
+
+ DSPSendMailToDSP(MSG_BASE | 0xA001);
+ while (DSPCheckMailToDSP()) {
+ }
+ DSPSendMailToDSP((u32)(task->iram_mmem_addr));
+ while (DSPCheckMailToDSP()) {
+ }
+
+ DSPSendMailToDSP(MSG_BASE | 0xC002);
+ while (DSPCheckMailToDSP()) {
+ }
+ DSPSendMailToDSP((u32)(task->iram_addr & 0xffff));
+ while (DSPCheckMailToDSP()) {
+ }
+
+ DSPSendMailToDSP(MSG_BASE | 0xA002);
+ while (DSPCheckMailToDSP()) {
+ }
+ DSPSendMailToDSP(task->iram_length);
+ while (DSPCheckMailToDSP()) {
+ }
+
+ DSPSendMailToDSP(MSG_BASE | 0xB002);
+ while (DSPCheckMailToDSP()) {
+ }
+ DSPSendMailToDSP(0x00000000);
+ while (DSPCheckMailToDSP()) {
+ }
+
+ DSPSendMailToDSP(MSG_BASE | 0xD001);
+ while (DSPCheckMailToDSP()) {
+ }
+ DSPSendMailToDSP((u32)(0xffff & task->dsp_init_vector));
+ while (DSPCheckMailToDSP()) {
+ }
+
+ __DSP_debug_printf("DSP is booting task: 0x%08X\n", task);
+ __DSP_debug_printf("__DSP_boot_task() : IRAM MMEM ADDR: 0x%08X\n", (u32)(task->iram_mmem_addr));
+ __DSP_debug_printf("__DSP_boot_task() : IRAM DSP ADDR : 0x%08X\n", (u32)(task->iram_addr));
+ __DSP_debug_printf("__DSP_boot_task() : IRAM LENGTH : 0x%08X\n", (u32)(task->iram_length));
+ __DSP_debug_printf("__DSP_boot_task() : DRAM MMEM ADDR: 0x%08X\n", (u32)(task->dram_length));
+ __DSP_debug_printf("__DSP_boot_task() : Start Vector : 0x%08X\n", (u32)(task->dsp_init_vector));
+}
+
+void __DSP_insert_task(DSPTaskInfo* task) {
+
+ DSPTaskInfo* temp;
+
+ if (__DSP_first_task == NULL) {
+ __DSP_first_task = __DSP_last_task = __DSP_curr_task = task;
+ task->next = task->prev = NULL;
+ } else {
+ temp = __DSP_first_task;
+
+ while (temp) {
+ if (task->priority < temp->priority) {
+ task->prev = temp->prev;
+ temp->prev = task;
+ task->next = temp;
+ if (task->prev == NULL) {
+ __DSP_first_task = task;
+ } else {
+ (task->prev)->next = task;
+ }
+ break;
+ }
+ temp = temp->next;
+ }
+
+ if (temp == NULL) {
+ __DSP_last_task->next = task;
+ task->next = NULL;
+ task->prev = __DSP_last_task;
+ __DSP_last_task = task;
+ }
+ }
+}
+
+void __DSP_add_task(DSPTaskInfo* task) {
+ if (__DSP_last_task == NULL) {
+ __DSP_first_task = __DSP_last_task = __DSP_curr_task = task;
+ task->next = task->prev = NULL;
+ } else {
+ __DSP_last_task->next = task;
+ task->next = NULL;
+ task->prev = __DSP_last_task;
+ __DSP_last_task = task;
+ }
+
+ task->state = DSP_TASK_STATE_INIT;
+
+ __DSP_debug_printf("__DSP_add_task() : Added task : 0x%08X\n", task);
+}
+
+void __DSP_remove_task(DSPTaskInfo* task) {
+
+ task->flags = DSP_TASK_FLAG_CLEARALL;
+ task->state = DSP_TASK_STATE_DONE;
+
+ if (__DSP_first_task == task) {
+ if (task->next) {
+ __DSP_first_task = (task->next);
+ task->next->prev = NULL;
+ } else {
+ __DSP_first_task = __DSP_last_task = __DSP_curr_task = NULL;
+ }
+ } else if (__DSP_last_task == task) {
+ __DSP_last_task = (task->prev);
+ task->prev->next = NULL;
+ __DSP_curr_task = __DSP_first_task;
+
+ } else {
+ __DSP_curr_task = task->next;
+ task->prev->next = task->next;
+ task->next->prev = task->prev;
+ }
+}