update DI disc code
[libogc.git] / libogc / dsp.c
blob88071a4cc763de6643d0bc7be020d6e6dd2113e8
1 /*-------------------------------------------------------------
3 dsp.c -- DSP subsystem
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
29 -------------------------------------------------------------*/
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include "asm.h"
35 #include "processor.h"
36 #include "irq.h"
37 #include "dsp.h"
39 //#define _DSP_DEBUG
41 // DSPCR bits
42 #define DSPCR_DSPRESET 0x0800 // Reset DSP
43 #define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set
44 #define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW)
45 #define DSPCR_DSPINT 0x0080 // * interrupt active (RWC)
46 #define DSPCR_ARINTMSK 0x0040
47 #define DSPCR_ARINT 0x0020
48 #define DSPCR_AIINTMSK 0x0010
49 #define DSPCR_AIINT 0x0008
50 #define DSPCR_HALT 0x0004 // halt DSP
51 #define DSPCR_PIINT 0x0002 // assert DSP PI interrupt
52 #define DSPCR_RES 0x0001 // reset DSP
54 #define _SHIFTL(v, s, w) \
55 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
56 #define _SHIFTR(v, s, w) \
57 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
59 static u32 __dsp_inited = FALSE;
60 static u32 __dsp_rudetask_pend = FALSE;
61 static DSPCallback __dsp_intcb = NULL;
62 static dsptask_t *__dsp_currtask,*__dsp_lasttask,*__dsp_firsttask,*__dsp_rudetask,*tmp_task;
64 static vu16* const _dspReg = (u16*)0xCC005000;
66 static void __dsp_inserttask(dsptask_t *task)
68 dsptask_t *t;
70 if(!__dsp_firsttask) {
71 __dsp_currtask = task;
72 __dsp_lasttask = task;
73 __dsp_firsttask = task;
74 task->next = NULL;
75 task->prev = NULL;
76 return;
79 t = __dsp_firsttask;
80 while(t) {
81 if(task->prio<t->prio) {
82 task->prev = t->prev;
83 t->prev = task;
84 task->next = t;
85 if(!task->prev) {
86 __dsp_firsttask = task;
87 break;
88 } else {
89 task->prev->next = task;
90 break;
93 t = t->next;
95 if(t) return;
97 __dsp_lasttask->next = task;
98 task->next = NULL;
99 task->prev = __dsp_lasttask;
100 __dsp_lasttask = task;
103 static void __dsp_removetask(dsptask_t *task)
105 task->flags = DSPTASK_CLEARALL;
106 task->state = DSPTASK_DONE;
107 if(__dsp_firsttask==task) {
108 if(task->next) {
109 __dsp_firsttask = task->next;
110 __dsp_firsttask->prev = NULL;
111 return;
113 __dsp_currtask = NULL;
114 __dsp_lasttask = NULL;
115 __dsp_firsttask = NULL;
116 return;
118 if(__dsp_lasttask==task) {
119 __dsp_lasttask = task->prev;
120 __dsp_lasttask->next = NULL;
121 __dsp_currtask = __dsp_firsttask;
122 return;
124 __dsp_currtask = __dsp_currtask->next;
127 static void __dsp_boottask(dsptask_t *task)
129 u32 mail;
130 #ifdef _DSP_DEBUG
131 printf("__dsp_boottask(%p)\n",task);
132 #endif
133 while(!DSP_CheckMailFrom());
134 mail = DSP_ReadMailFrom();
135 #ifdef _DSP_DEBUG
136 if(mail!=0x8071FEED) { //if the overflow calculation applies here too, this should be the value which the dsp should deliver on succesfull sync.
137 printf("__dsp_boottask(): failed to sync DSP on boot (%08x)\n",mail);
139 #endif
140 DSP_SendMailTo(0x80F3A001);
141 while(DSP_CheckMailTo());
142 DSP_SendMailTo((u32)task->iram_maddr);
143 while(DSP_CheckMailTo());
144 DSP_SendMailTo(0x80F3C002);
145 while(DSP_CheckMailTo());
146 DSP_SendMailTo((task->iram_addr&0xffff));
147 while(DSP_CheckMailTo());
148 DSP_SendMailTo(0x80F3A002);
149 while(DSP_CheckMailTo());
150 DSP_SendMailTo(task->iram_len);
151 while(DSP_CheckMailTo());
152 DSP_SendMailTo(0x80F3B002);
153 while(DSP_CheckMailTo());
154 DSP_SendMailTo(0);
155 while(DSP_CheckMailTo());
156 DSP_SendMailTo(0x80F3D001);
157 while(DSP_CheckMailTo());
158 DSP_SendMailTo(task->init_vec);
159 while(DSP_CheckMailTo());
162 static void __dsp_exectask(dsptask_t *exec,dsptask_t *hire)
164 #ifdef _DSP_DEBUG
165 printf("__dsp_exectask(%p,%p)\n",exec,hire);
166 #endif
167 if(!exec) {
168 DSP_SendMailTo(0);
169 while(DSP_CheckMailTo());
170 DSP_SendMailTo(0);
171 while(DSP_CheckMailTo());
172 DSP_SendMailTo(0);
173 while(DSP_CheckMailTo());
174 } else {
175 DSP_SendMailTo((u32)exec->dram_maddr);
176 while(DSP_CheckMailTo());
177 DSP_SendMailTo(exec->dram_len);
178 while(DSP_CheckMailTo());
179 DSP_SendMailTo(exec->dram_addr);
180 while(DSP_CheckMailTo());
183 DSP_SendMailTo((u32)hire->iram_maddr);
184 while(DSP_CheckMailTo());
185 DSP_SendMailTo(hire->iram_len);
186 while(DSP_CheckMailTo());
187 DSP_SendMailTo(hire->iram_addr);
188 while(DSP_CheckMailTo());
189 if(hire->state==DSPTASK_INIT) {
190 DSP_SendMailTo(hire->init_vec);
191 while(DSP_CheckMailTo());
192 DSP_SendMailTo(0);
193 while(DSP_CheckMailTo());
194 DSP_SendMailTo(0);
195 while(DSP_CheckMailTo());
196 DSP_SendMailTo(0);
197 while(DSP_CheckMailTo());
198 return;
201 DSP_SendMailTo(hire->resume_vec);
202 while(DSP_CheckMailTo());
204 DSP_SendMailTo((u32)hire->dram_maddr);
205 while(DSP_CheckMailTo());
206 DSP_SendMailTo(hire->dram_len);
207 while(DSP_CheckMailTo());
208 DSP_SendMailTo(hire->dram_addr);
209 while(DSP_CheckMailTo());
212 static void __dsp_def_taskcb()
214 u32 mail;
215 #ifdef _DSP_DEBUG
216 printf("__dsp_def_taskcb()\n");
217 #endif
218 while(!DSP_CheckMailFrom());
220 mail = DSP_ReadMailFrom();
221 #ifdef _DSP_DEBUG
222 printf("__dsp_def_taskcb(mail = 0x%08x)\n",mail);
223 #endif
224 if(__dsp_currtask->flags&DSPTASK_CANCEL) {
225 if(mail==0xDCD10002) mail = 0xDCD10003;
228 switch(mail) {
229 case 0xDCD10000:
230 __dsp_currtask->state = DSPTASK_RUN;
231 if(__dsp_currtask->init_cb) __dsp_currtask->init_cb(__dsp_currtask);
232 break;
233 case 0xDCD10001:
234 __dsp_currtask->state = DSPTASK_RUN;
235 if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask);
236 break;
237 case 0xDCD10002:
238 if(__dsp_rudetask_pend==TRUE) {
239 if(__dsp_rudetask==__dsp_currtask) {
240 DSP_SendMailTo(0xCDD10003);
241 while(DSP_CheckMailTo());
243 __dsp_rudetask = NULL;
244 __dsp_rudetask_pend = FALSE;
245 if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask);
246 } else {
247 DSP_SendMailTo(0xCDD10001);
248 while(DSP_CheckMailTo());
250 __dsp_exectask(__dsp_currtask,__dsp_rudetask);
251 __dsp_currtask->flags = DSPTASK_YIELD;
252 __dsp_currtask = __dsp_rudetask;
253 __dsp_rudetask = NULL;
254 __dsp_rudetask_pend = FALSE;
256 } else if(__dsp_currtask->next==NULL) {
257 if(__dsp_firsttask==__dsp_currtask) {
258 DSP_SendMailTo(0xCDD10003);
259 while(DSP_CheckMailTo());
261 if(__dsp_currtask->res_cb) __dsp_currtask->res_cb(__dsp_currtask);
262 } else {
263 DSP_SendMailTo(0xCDD10001);
264 while(DSP_CheckMailTo());
266 __dsp_exectask(__dsp_currtask,__dsp_firsttask);
267 __dsp_currtask->state = DSPTASK_YIELD;
268 __dsp_currtask = __dsp_firsttask;
270 } else {
271 DSP_SendMailTo(0xCDD10001);
272 while(DSP_CheckMailTo());
274 __dsp_exectask(__dsp_currtask,__dsp_currtask->next);
275 __dsp_currtask->state = DSPTASK_YIELD;
276 __dsp_currtask = __dsp_currtask->next;
278 break;
279 case 0xDCD10003:
280 if(__dsp_rudetask_pend==TRUE) {
281 if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask);
282 DSP_SendMailTo(0xCDD10001);
283 while(DSP_CheckMailTo());
285 __dsp_exectask(NULL,__dsp_rudetask);
286 __dsp_removetask(__dsp_currtask);
288 __dsp_currtask = __dsp_rudetask;
289 __dsp_rudetask_pend = FALSE;
290 __dsp_rudetask = NULL;
291 } else if(__dsp_currtask->next==NULL) {
292 if(__dsp_firsttask==__dsp_currtask) {
293 if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask);
294 DSP_SendMailTo(0xCDD10002);
295 while(DSP_CheckMailTo());
297 __dsp_currtask->state = DSPTASK_DONE;
298 __dsp_removetask(__dsp_currtask);
300 } else {
301 if(__dsp_currtask->done_cb) __dsp_currtask->done_cb(__dsp_currtask);
303 DSP_SendMailTo(0xCDD10001);
304 while(DSP_CheckMailTo());
306 __dsp_currtask->state = DSPTASK_DONE;
307 __dsp_exectask(NULL,__dsp_firsttask);
308 __dsp_currtask = __dsp_firsttask;
309 __dsp_removetask(__dsp_lasttask);
311 break;
312 case 0xDCD10004:
313 if(__dsp_currtask->req_cb) __dsp_currtask->req_cb(__dsp_currtask);
314 break;
319 static void __dsp_inthandler(u32 nIrq,void *pCtx)
321 _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT))|DSPCR_DSPINT;
322 if(__dsp_intcb) __dsp_intcb();
325 void DSP_Init()
327 u32 level;
328 #ifdef _DSP_DEBUG
329 printf("DSP_Init()\n");
330 #endif
331 _CPU_ISR_Disable(level);
332 if(__dsp_inited==FALSE) {
333 __dsp_intcb= __dsp_def_taskcb;
335 IRQ_Request(IRQ_DSP_DSP,__dsp_inthandler,NULL);
336 __UnmaskIrq(IRQMASK(IRQ_DSP_DSP));
338 _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_DSPRESET;
339 _dspReg[5] = (_dspReg[5]&~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT));
341 __dsp_currtask = NULL;
342 __dsp_firsttask = NULL;
343 __dsp_lasttask = NULL;
344 tmp_task = NULL;
345 __dsp_inited = TRUE;
347 _CPU_ISR_Restore(level);
350 DSPCallback DSP_RegisterCallback(DSPCallback usr_cb)
352 u32 level;
353 DSPCallback ret;
354 #ifdef _DSP_DEBUG
355 printf("DSP_RegisterCallback()\n");
356 #endif
357 _CPU_ISR_Disable(level);
358 ret = __dsp_intcb;
359 if(usr_cb)
360 __dsp_intcb = usr_cb;
361 else
362 __dsp_intcb = __dsp_def_taskcb;
363 _CPU_ISR_Restore(level);
365 return ret;
368 u32 DSP_CheckMailTo()
370 u32 sent_mail;
371 sent_mail = _SHIFTR(_dspReg[0],15,1);
372 #ifdef _DSP_DEBUG
373 printf("DSP_CheckMailTo(%02x)\n",sent_mail);
374 #endif
375 return sent_mail;
378 u32 DSP_CheckMailFrom()
380 u32 has_mail;
381 has_mail = _SHIFTR(_dspReg[2],15,1);
382 #ifdef _DSP_DEBUG
383 printf("DSP_CheckMailFrom(%02x)\n",has_mail);
384 #endif
385 return has_mail;
388 u32 DSP_ReadMailFrom()
390 u32 mail;
391 mail = (_SHIFTL(_dspReg[2],16,16)|(_dspReg[3]&0xffff));
392 #ifdef _DSP_DEBUG
393 printf("DSP_ReadMailFrom(%08x)\n",mail);
394 #endif
395 return mail;
398 void DSP_SendMailTo(u32 mail)
400 #ifdef _DSP_DEBUG
401 printf("DSP_SendMailTo(%08x)\n",mail);
402 #endif
403 _dspReg[0] = _SHIFTR(mail,16,16);
404 _dspReg[1] = (mail&0xffff);
407 u32 DSP_ReadCPUtoDSP()
409 u32 cpu_dsp;
410 cpu_dsp = (_SHIFTL(_dspReg[0],16,16)|(_dspReg[1]&0xffff));
411 #ifdef _DSP_DEBUG
412 printf("DSP_ReadCPUtoDSP(%08x)\n",cpu_dsp);
413 #endif
414 return cpu_dsp;
417 void DSP_AssertInt()
419 u32 level;
420 #ifdef _DSP_DEBUG
421 printf("DSP_AssertInt()\n");
422 #endif
423 _CPU_ISR_Disable(level);
424 _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_PIINT;
425 _CPU_ISR_Restore(level);
428 void DSP_Reset()
430 u16 old;
431 u32 level;
433 _CPU_ISR_Disable(level);
434 old = _dspReg[5];
435 _dspReg[5] = (old&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|(DSPCR_DSPRESET|DSPCR_RES);
436 _CPU_ISR_Restore(level);
439 void DSP_Halt()
441 u32 level,old;
443 _CPU_ISR_Disable(level);
444 old = _dspReg[5];
445 _dspReg[5] = (old&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT))|DSPCR_HALT;
446 _CPU_ISR_Restore(level);
449 void DSP_Unhalt()
451 u32 level;
453 _CPU_ISR_Disable(level);
454 _dspReg[5] = (_dspReg[5]&~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT|DSPCR_HALT));
455 _CPU_ISR_Restore(level);
458 u32 DSP_GetDMAStatus()
460 return _dspReg[5]&DSPCR_DSPDMA;
463 dsptask_t* DSP_AddTask(dsptask_t *task)
465 u32 level;
466 #ifdef _DSP_DEBUG
467 printf("DSP_AddTask(%p)\n",task);
468 #endif
469 _CPU_ISR_Disable(level);
470 __dsp_inserttask(task);
471 task->state = DSPTASK_INIT;
472 task->flags = DSPTASK_ATTACH;
473 _CPU_ISR_Restore(level);
475 if(__dsp_firsttask==task) __dsp_boottask(task);
476 return task;
479 void DSP_CancelTask(dsptask_t *task)
481 u32 level;
483 _CPU_ISR_Disable(level);
484 task->flags |= DSPTASK_CANCEL;
485 _CPU_ISR_Restore(level);
488 dsptask_t* DSP_AssertTask(dsptask_t *task)
490 u32 level;
491 dsptask_t *ret = NULL;
493 _CPU_ISR_Disable(level);
494 if(task==__dsp_currtask) {
495 __dsp_rudetask = task;
496 __dsp_rudetask_pend = TRUE;
497 ret = task;
498 } else {
499 if(task->prio<__dsp_currtask->prio) {
500 __dsp_rudetask = task;
501 __dsp_rudetask_pend = TRUE;
502 if(__dsp_currtask->state==DSPTASK_RUN)
503 _dspReg[5] = ((_dspReg[5]&~(DSPCR_DSPINT|DSPCR_ARINT|DSPCR_AIINT))|DSPCR_PIINT);
505 ret = task;
508 _CPU_ISR_Restore(level);
510 return ret;