diff options
Diffstat (limited to 'src/Dolphin/dsp')
-rw-r--r-- | src/Dolphin/dsp/dsp.c | 145 | ||||
-rw-r--r-- | src/Dolphin/dsp/dsp_debug.c | 5 | ||||
-rw-r--r-- | src/Dolphin/dsp/dsp_task.c | 389 |
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; + } +} |