// dsp_task.c // // DSP task queue execution / switching // DSPTaskInfo *__DSP_curr_task; BOOL __DSP_rude_task_pending; DSPTaskInfo *__DSP_rude_task; DSPTaskInfo *__DSP_first_task; DSPTaskInfo *__DSP_last_task; DSPTaskInfo *__DSP_tmp_task; void __DSPHandler(__OSInterrupt interrupt, OSContext *context) { u16 tmp; OSContext exceptionContext; u32 mail; // clear DSP interrupt tmp = *(u16 *)0xCC00500A & ~0x0028; tmp |= 0x0080; *(u16 *)0xCC00500A = tmp; OSClearContext(&exceptionContext); OSSetCurrentContext(&exceptionContext); if(__DSP_curr_task == NULL) { OSHalt("__DSPHandler(): No current task! Someone set us up the bomb!\n"); } while(DSPCheckMailFromDSP() == 0) ; mail = DSPReadMailFromDSP(); if(__DSP_curr_task->flags & DSP_TASK_FLAG_CANCEL) { if(mail == 0xDCD10002) // ??? actually this is if((mail + 0x232F0000) == 2) { 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 == TRUE) { if(__DSP_curr_task == __DSP_rude_task) { DSPSendMailToDSP(0xCDD10003); while(DSPCheckMailToDSP() == 0) ; __DSP_rude_task = NULL; __DSP_rude_task_pending = FALSE; if(__DSP_curr_task->res_cb) { __DSP_curr_task->res_cb((void *)__DSP_curr_task); } } else { DSPSendMailToDSP(0xCDD10001); while(DSPCheckMailToDSP() == 0) ; __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() == 0) ; if(__DSP_curr_task->res_cb) { __DSP_curr_task->res_cb(__DSP_curr_task); } } else { DSPSendMailToDSP(0xCDD10001); while(DSPCheckMailToDSP() == 0) ; __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() == 0) ; __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 == TRUE) { if(__DSP_curr_task->done_cb) { __DSP_curr_task->done_cb((void *)__DSP_curr_task); } DSPSendMailToDSP(0xCDD10001); while(DSPCheckMailToDSP() == 0) ; __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() == 0) ; __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() == 0) ; __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() == 0) ; __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: OSHalt("__DSPHandler(): Unknown msg from DSP 0x%08X - task sync failed!\n", mail); } OSClearContext(&exceptionContext); OSSetCurrentContext(context); } void __DSP_exec_task(DSPTaskInfo *curr, DSPTaskInfo *next) { if(next == NULL) { OSHalt("__DSP_exec_task(): NULL task. It is to weep.\n"); } if(curr) { DSPSendMailToDSP(curr->dram_mmem_addr); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(curr->dram_length); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(curr->dram_addr); while(DSPCheckMailToDSP() == 0) ; } else { DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; } DSPSendMailToDSP(next->iram_mmem_addr); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(next->iram_length); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(next->iram_addr); while(DSPCheckMailToDSP() == 0) ; if(next->state == DSP_TASK_STATE_INIT) { DSPSendMailToDSP(next->dsp_init_vector); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; } else { DSPSendMailToDSP(next->dsp_resume_vector); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(next->dram_mmem_addr); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(next->dram_length); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(next->dram_addr); while(DSPCheckMailToDSP() == 0) ; } } void __DSP_boot_task(DSPTaskInfo *task) { u32 mail; if(task == NULL) { OSHalt("__DSP_boot_task(): NULL task!\n"); } while(DSPCheckMailFromDSP() == 0) ; mail = DSPReadMailFromDSP(); if(mail == (addis r0,mail,7f8f, cmplwi r0,feed)) { OSHalt("__DSP_boot_task(): Failed to sync DSP on boot! (0x%08X)\n", mail); } DSPSendMailToDSP(0x80F4A001); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(task->iram_mmem_addr); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0x80F4C002); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(task->iram_addr); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0x80F4A002); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(task->iram_length); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0x80F4B002); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(0x80F4D001); while(DSPCheckMailToDSP() == 0) ; DSPSendMailToDSP(task->dsp_init_vector); while(DSPCheckMailToDSP() == 0) ; #ifdef DEBUG __DSP_debug_printf("DSP is booting task: 0x%08X\n", task); __DSP_debug_printf("__DSP_boot_task() : IRAM MMEM ADDR: 0x%08X\n", task->iram_mmem_addr); __DSP_debug_printf("__DSP_boot_task() : IRAM DSP ADDR : 0x%08X\n", task->iram_addr); __DSP_debug_printf("__DSP_boot_task() : IRAM LENGTH : 0x%08X\n", task->iram_length); __DSP_debug_printf("__DSP_boot_task() : DRAM MMEM ADDR: 0x%08X\n", task->dram_mmem_addr); __DSP_debug_printf("__DSP_boot_task() : Start Vector : 0x%08X\n", task->dsp_init_vector); #endif } void __DSP_insert_task(DSPTaskInfo *task) { if(__DSP_first_task == NULL) { __DSP_first_task = __DSP_last_task = __DSP_curr_task = task; task->next = task->prev = NULL; } else { DSPTaskInfo *temp; for(temp=__DSP_first_task; temp; temp=temp->next) { if(DSPGetTaskPriority(task) < DSPGetTaskPriority(temp)) { task->prev = temp->prev; temp->prev = task; task->next = temp; if(task->prev == NULL) __DSP_first_task = task; else task->prev->next = task; break; } } if(temp == NULL) { __DSP_last_task->next = task; task->next = NULL; task->prev = __DSP_last_task; __DSP_last_task = task; } } } __DSP_add_task, __DSP_remove_task : later, too simple