1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - libraries - OS
3 File: os_interrupt.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-11-06#$
14 $Rev: 9229 $
15 $Author: yada $
16
17 *---------------------------------------------------------------------------*/
18 #include <nitro/hw/common/armArch.h>
19
20 #ifdef SDK_NITRO
21 #include <nitro/os/common/interrupt.h>
22 #else
23 #include <twl/os/common/interrupt.h>
24 #endif
25
26 #include <nitro/os/common/system.h>
27
28 /*---------------------------------------------------------------------------*
29 Name: OS_InitIrqTable
30
31 Description: initialize IRQ handler table
32
33 Arguments: None
34
35 Returns: None
36 *---------------------------------------------------------------------------*/
37 extern OSThreadQueue OSi_IrqThreadQueue;
38
OS_InitIrqTable(void)39 void OS_InitIrqTable(void)
40 {
41 //---- initialize thread queue for irq
42 OS_InitThreadQueue(&OSi_IrqThreadQueue);
43
44 #ifdef SDK_ARM7
45 //---- clear VBlank counter
46 OSi_SetVBlankCount(0);
47 #endif
48 }
49
50 /*---------------------------------------------------------------------------*
51 Name: OS_SetIrqFunction
52
53 Description: set IRQ handler function
54
55 Arguments: intrBit IRQ mask bit
56 function funtion to set
57
58 Returns: None
59 *---------------------------------------------------------------------------*/
OS_SetIrqFunction(OSIrqMask intrBit,OSIrqFunction function)60 void OS_SetIrqFunction(OSIrqMask intrBit, OSIrqFunction function)
61 {
62 int i;
63 OSIrqCallbackInfo *info;
64
65 for (i = 0; i < OS_IRQ_TABLE_MAX; i++)
66 {
67 if (intrBit & 1)
68 {
69 info = NULL;
70
71 // ---- if dma(0-3)
72 if (REG_OS_IE_D0_SHIFT <= i && i <= REG_OS_IE_D3_SHIFT)
73 {
74 info = &OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT];
75 }
76 #ifdef SDK_TWL
77 // ---- if new dma(0-3)
78 else if (REG_OS_IE_ND0_SHIFT <= i && i <= REG_OS_IE_ND3_SHIFT)
79 {
80 info = &OSi_IrqCallbackInfo[i - REG_OS_IE_ND0_SHIFT + OSi_IRQCALLBACK_NO_NDMA0];
81 }
82 #endif
83 // ---- if timer(0-3)
84 else if (REG_OS_IE_T0_SHIFT <= i && i <= REG_OS_IE_T3_SHIFT)
85 {
86 info = &OSi_IrqCallbackInfo[i - REG_OS_IE_T0_SHIFT + OSi_IRQCALLBACK_NO_TIMER0];
87 }
88 #ifdef SDK_ARM7
89 // ---- if vblank
90 else if (REG_OS_IE_VB_SHIFT == i)
91 {
92 info = &OSi_IrqCallbackInfo[OSi_IRQCALLBACK_NO_VBLANK];
93 }
94 #endif
95 //---- other interrupt
96 else
97 {
98 OS_IRQTable[i] = function;
99 }
100
101 if (info)
102 {
103 info->func = (void (*)(void *))function;
104 info->arg = 0;
105 info->enable = TRUE;
106 }
107
108 }
109 intrBit >>= 1;
110 }
111 }
112
113 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_SetIrqFunctionEx(OSIrqMask intrBit,OSIrqFunction function)114 void OS_SetIrqFunctionEx(OSIrqMask intrBit, OSIrqFunction function)
115 {
116 int i;
117 OSIrqCallbackInfo *info = NULL;
118
119 for (i = 0; i < OS_IRQ_TABLE2_MAX; i++)
120 {
121 if (intrBit & 1)
122 {
123 info = NULL;
124 OS_IRQTable2[i] = function;
125
126 if (info)
127 {
128 info->func = (void (*)(void *))function;
129 info->arg = 0;
130 info->enable = TRUE;
131 }
132
133 }
134 intrBit >>= 1;
135 }
136 }
137 #endif // defined(SDK_TWL) && defined(SDK_ARM7)
138
139 /*---------------------------------------------------------------------------*
140 Name: OS_GetIrqFunction
141
142 Description: get IRQ handler function
143
144 Arguments: intrBit IRQ mask bit
145
146 Returns: None
147 *---------------------------------------------------------------------------*/
OS_GetIrqFunction(OSIrqMask intrBit)148 OSIrqFunction OS_GetIrqFunction(OSIrqMask intrBit)
149 {
150 int i;
151 OSIrqFunction *funcPtr = &OS_IRQTable[0];
152
153 for (i = 0; i < OS_IRQ_TABLE_MAX; i++)
154 {
155 if (intrBit & 1)
156 {
157 //---- if dma(0-3)
158 if (REG_OS_IE_D0_SHIFT <= i && i <= REG_OS_IE_D3_SHIFT)
159 {
160 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT].func;
161 }
162 #ifdef TWL_SDK
163 //---- if ndma(0-3)
164 else if (REG_OS_IE_ND0_SHIFT <= i && i <= REG_OS_IE_ND3_SHIFT)
165 {
166 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_D0_SHIFT +
167 OSi_IRQCALLBACK_NO_NDMA0].func;
168 }
169 #endif
170 //---- if timer(0-3)
171 else if (REG_OS_IE_T0_SHIFT <= i && i <= REG_OS_IE_T3_SHIFT)
172 {
173 return (void (*)(void))OSi_IrqCallbackInfo[i - REG_OS_IE_T0_SHIFT +
174 OSi_IRQCALLBACK_NO_TIMER0].func;
175 }
176 #ifdef SDK_ARM7
177 else if (REG_OS_IE_VB_SHIFT == i)
178 {
179 return (void (*)(void))OSi_IrqCallbackInfo[OSi_IRQCALLBACK_NO_VBLANK].func;
180 }
181 #endif
182
183 //---- other interrupt
184 return *funcPtr;
185 }
186 intrBit >>= 1;
187 funcPtr++;
188 }
189 return 0;
190 }
191
192 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_GetIrqFunctionEx(OSIrqMask intrBit)193 OSIrqFunction OS_GetIrqFunctionEx(OSIrqMask intrBit)
194 {
195 int i;
196 OSIrqFunction *funcPtr = &OS_IRQTable2[0]; // skip IE part
197
198 for (i = 0; i < OS_IRQ_TABLE2_MAX; i++)
199 {
200 if (intrBit & 1)
201 {
202 return *funcPtr;
203 }
204 intrBit >>= 1;
205 funcPtr++;
206 }
207 return 0;
208 }
209 #endif // defined(SDK_TWL) && defined(SDK_ARM7)
210
211
212 /*---------------------------------------------------------------------------*
213 Name: OSi_EnterDmaCallback
214
215 Description: enter dma callback handler and arg
216
217 Arguments: dmaNo dma number to set callback
218 callback callback for dma interrupt
219 arg its argument
220
221 Returns: None
222 *---------------------------------------------------------------------------*/
OSi_EnterDmaCallback(u32 dmaNo,void (* callback)(void *),void * arg)223 void OSi_EnterDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg)
224 {
225 OSIrqMask imask = (1UL << (REG_OS_IE_D0_SHIFT + dmaNo));
226
227 //---- enter callback
228 OSi_IrqCallbackInfo[dmaNo].func = callback;
229 OSi_IrqCallbackInfo[dmaNo].arg = arg;
230
231 //---- remember IRQ mask bit
232 OSi_IrqCallbackInfo[dmaNo].enable = OS_EnableIrqMask(imask) & imask;
233 }
234
235 /*---------------------------------------------------------------------------*
236 Name: OSi_EnterNDmaCallback
237
238 Description: enter new dma callback handler and arg
239
240 Arguments: dmaNo dma number to set callback
241 callback callback for dma interrupt
242 arg its argument
243
244 Returns: None
245 *---------------------------------------------------------------------------*/
246 #ifdef SDK_TWL
247 #include <twl/ltdmain_begin.h>
248 static void OSi_EnterNDmaCallback_ltdmain(u32 dmaNo, void (*callback) (void *), void *arg);
OSi_EnterNDmaCallback_ltdmain(u32 dmaNo,void (* callback)(void *),void * arg)249 static void OSi_EnterNDmaCallback_ltdmain(u32 dmaNo, void (*callback) (void *), void *arg)
250 {
251 OSIrqMask imask = (1UL << (REG_OS_IE_ND0_SHIFT + dmaNo));
252
253 //---- enter callback
254 OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].func = callback;
255 OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].arg = arg;
256
257 //---- remember IRQ mask bit
258 OSi_IrqCallbackInfo[dmaNo + OSi_IRQCALLBACK_NO_NDMA0].enable = OS_EnableIrqMask(imask) & imask;
259 }
260 #include <twl/ltdmain_end.h>
261 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OSi_EnterNDmaCallback(u32 dmaNo,void (* callback)(void *),void * arg)262 void OSi_EnterNDmaCallback(u32 dmaNo, void (*callback) (void *), void *arg)
263 {
264 OSi_EnterNDmaCallback_ltdmain(dmaNo, callback, arg);
265 }
266 #endif
267
268 /*---------------------------------------------------------------------------*
269 Name: OSi_EnterTimerCallback
270
271 Description: enter timer callback handler and arg
272
273 Arguments: timerNo timer number to set callback
274 callback callback for timer interrupt
275 arg its argument
276
277 Returns: None
278 *---------------------------------------------------------------------------*/
OSi_EnterTimerCallback(u32 timerNo,void (* callback)(void *),void * arg)279 void OSi_EnterTimerCallback(u32 timerNo, void (*callback) (void *), void *arg)
280 {
281 OSIrqMask imask = (1UL << (REG_OS_IE_T0_SHIFT + timerNo));
282
283 //---- enter callback
284 OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].func = callback;
285 OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].arg = arg;
286
287 //---- remember IRQ mask bit (force to be ENABLE)
288 (void)OS_EnableIrqMask(imask);
289 OSi_IrqCallbackInfo[timerNo + OSi_IRQCALLBACK_NO_TIMER0].enable = TRUE;
290 }
291
292 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
293 #include <nitro/itcm_begin.h>
294 #endif
295 //================================================================================
296 // IrqMask
297 //================================================================================
298 /*---------------------------------------------------------------------------*
299 Name: OS_SetIrqMask
300
301 Description: set irq factor
302
303 Arguments: intr irq factor
304
305 Returns: previous factors
306 *---------------------------------------------------------------------------*/
OS_SetIrqMask(OSIrqMask intr)307 OSIrqMask OS_SetIrqMask(OSIrqMask intr)
308 {
309 BOOL ime = OS_DisableIrq(); // IME disable
310 OSIrqMask prep = reg_OS_IE;
311 reg_OS_IE = intr;
312 (void)OS_RestoreIrq(ime);
313 return prep;
314 }
315
316
317 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_SetIrqMaskEx(OSIrqMask intr)318 OSIrqMask OS_SetIrqMaskEx(OSIrqMask intr)
319 {
320 BOOL ime = OS_DisableIrq(); // IME disable
321 OSIrqMask prep = reg_OS_IE2;
322 reg_OS_IE2 = (u16)intr;
323 (void)OS_RestoreIrq(ime);
324 return prep;
325 }
326 #endif
327
328 /*---------------------------------------------------------------------------*
329 Name: OS_EnableIrqMask
330
331 Description: set specified irq factor
332
333 Arguments: intr irq factor
334
335 Returns: previous factors
336 *---------------------------------------------------------------------------*/
OS_EnableIrqMask(OSIrqMask intr)337 OSIrqMask OS_EnableIrqMask(OSIrqMask intr)
338 {
339 BOOL ime = OS_DisableIrq(); // IME disable
340 OSIrqMask prep = reg_OS_IE;
341 reg_OS_IE = prep | intr;
342 (void)OS_RestoreIrq(ime);
343 return prep;
344 }
345
346 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_EnableIrqMaskEx(OSIrqMask intr)347 OSIrqMask OS_EnableIrqMaskEx(OSIrqMask intr)
348 {
349 BOOL ime = OS_DisableIrq(); // IME disable
350 OSIrqMask prep = reg_OS_IE2;
351 reg_OS_IE2 = (u16)(prep | intr);
352 (void)OS_RestoreIrq(ime);
353 return prep;
354 }
355 #endif
356
357 /*---------------------------------------------------------------------------*
358 Name: OS_DisableIrqMask
359
360 Description: unset specified irq factor
361
362 Arguments: intr irq factor
363
364 Returns: previous factors
365 *---------------------------------------------------------------------------*/
OS_DisableIrqMask(OSIrqMask intr)366 OSIrqMask OS_DisableIrqMask(OSIrqMask intr)
367 {
368 BOOL ime = OS_DisableIrq(); // IME disable
369 OSIrqMask prep = reg_OS_IE;
370 reg_OS_IE = prep & ~intr;
371 (void)OS_RestoreIrq(ime);
372 return prep;
373 }
374
375 #if defined(SDK_TWL) & defined(SDK_ARM7)
OS_DisableIrqMaskEx(OSIrqMask intr)376 OSIrqMask OS_DisableIrqMaskEx(OSIrqMask intr)
377 {
378 BOOL ime = OS_DisableIrq(); // IME disable
379 OSIrqMask prep = reg_OS_IE2;
380 reg_OS_IE2 = (u16)(prep & ~intr);
381 (void)OS_RestoreIrq(ime);
382 return prep;
383 }
384 #endif
385
386 /*---------------------------------------------------------------------------*
387 Name: OS_ResetRequestIrqMask
388
389 Description: reset IF bit
390 (setting bit causes to clear bit for interrupt)
391
392 Arguments: intr irq factor
393
394 Returns: previous factors
395 *---------------------------------------------------------------------------*/
OS_ResetRequestIrqMask(OSIrqMask intr)396 OSIrqMask OS_ResetRequestIrqMask(OSIrqMask intr)
397 {
398 BOOL ime = OS_DisableIrq(); // IME disable
399 OSIrqMask prep = reg_OS_IF;
400 reg_OS_IF = intr;
401 (void)OS_RestoreIrq(ime);
402 return prep;
403 }
404
405 #if defined(SDK_TWL) && defined(SDK_ARM7)
OS_ResetRequestIrqMaskEx(OSIrqMask intr)406 OSIrqMask OS_ResetRequestIrqMaskEx(OSIrqMask intr)
407 {
408 BOOL ime = OS_DisableIrq(); // IME disable
409 OSIrqMask prep = reg_OS_IF2;
410 reg_OS_IF2 = (u16)intr;
411 (void)OS_RestoreIrq(ime);
412 return prep;
413 }
414 #endif
415
416 #if defined(SDK_TCM_APPLY) && defined(SDK_ARM9)
417 #include <nitro/itcm_end.h>
418 #endif
419
420
421
422 //================================================================================
423 // IRQ STACK CHECKER
424 //================================================================================
425 extern unsigned long SDK_IRQ_STACKSIZE[];
426 #define OSi_IRQ_STACKSIZE ((int)SDK_IRQ_STACKSIZE)
427
428 //---- defs for irq stack
429 #ifdef SDK_ARM9
430 # define OSi_IRQ_STACK_TOP (HW_DTCM_SVC_STACK - ((s32)SDK_IRQ_STACKSIZE))
431 # define OSi_IRQ_STACK_BOTTOM HW_DTCM_SVC_STACK
432 #else
433 # define OSi_IRQ_STACK_TOP (HW_PRV_WRAM_IRQ_STACK_END - ((s32)SDK_IRQ_STACKSIZE))
434 # define OSi_IRQ_STACK_BOTTOM HW_PRV_WRAM_IRQ_STACK_END
435 #endif
436
437 //---- Stack CheckNumber
438 #ifdef SDK_ARM9
439 # define OSi_IRQ_STACK_CHECKNUM_BOTTOM 0xfddb597dUL
440 # define OSi_IRQ_STACK_CHECKNUM_TOP 0x7bf9dd5bUL
441 # define OSi_IRQ_STACK_CHECKNUM_WARN 0x597dfbd9UL
442 #else
443 # define OSi_IRQ_STACK_CHECKNUM_BOTTOM 0xd73bfdf7UL
444 # define OSi_IRQ_STACK_CHECKNUM_TOP 0xfbdd37bbUL
445 # define OSi_IRQ_STACK_CHECKNUM_WARN 0xbdf7db3dUL
446 #endif
447
448 static u32 OSi_IrqStackWarningOffset = 0;
449
450 /*---------------------------------------------------------------------------*
451 Name: OS_SetIrqStackChecker
452
453 Description: set irq stack check number to irq stack
454
455 Arguments: None
456
457 Returns: None
458 *---------------------------------------------------------------------------*/
OS_SetIrqStackChecker(void)459 void OS_SetIrqStackChecker(void)
460 {
461 *(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32)) = OSi_IRQ_STACK_CHECKNUM_BOTTOM;
462 *(u32 *)(OSi_IRQ_STACK_TOP) = OSi_IRQ_STACK_CHECKNUM_TOP;
463 }
464
465 /*---------------------------------------------------------------------------*
466 Name: OS_SetIrqStackWarningOffset
467
468 Description: Set warning level for irq stack
469
470 Arguments: offset : offset from stack top. must be multiple of 4
471
472 Returns: None
473 *---------------------------------------------------------------------------*/
OS_SetIrqStackWarningOffset(u32 offset)474 void OS_SetIrqStackWarningOffset(u32 offset)
475 {
476 SDK_ASSERTMSG((offset & 3) == 0, "Offset must be aligned by 4");
477 SDK_ASSERTMSG(offset > 0, "Cannot set warning level to stack top.");
478 SDK_ASSERTMSG(offset < ((u32)SDK_IRQ_STACKSIZE), "Cannot set warning level over stack bottom.");
479
480 //---- remember warning offset
481 OSi_IrqStackWarningOffset = offset;
482
483 //---- set Stack CheckNum
484 if (offset != 0)
485 {
486 *(u32 *)(OSi_IRQ_STACK_TOP + offset) = OSi_IRQ_STACK_CHECKNUM_WARN;
487 }
488 }
489
490
491 /*---------------------------------------------------------------------------*
492 Name: OS_GetIrqStackStatus
493
494 Description: check irq stack. check each CheckNUM.
495 return result.
496
497 Arguments: None
498
499 Returns: 0 (OS_STACK_NO_ERROR) no error
500 OS_STACK_OVERFLOW overflow
501 OS_STACK_ABOUT_TO_OVERFLOW about to overflow
502 OS_STACK_UNDERFLOW underflow
503 *---------------------------------------------------------------------------*/
OS_GetIrqStackStatus(void)504 OSStackStatus OS_GetIrqStackStatus(void)
505 {
506 //OS_Printf("CHECK OF %x\n", (*(u32 *)(OSi_IRQ_STACK_TOP) ) );
507 //OS_Printf("CHECK AO %x\n", (*(u32 *)(OSi_IRQ_STACK_TOP + OSi_IrqStackWarningOffset) ) );
508 //OS_Printf("CHECK UF %x\n", (*(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32))) );
509
510 //OS_Printf(" - OF %x\n", OSi_IRQ_STACK_CHECKNUM_TOP);
511 //OS_Printf(" - AO %x\n", OSi_IRQ_STACK_CHECKNUM_WARN);
512 //OS_Printf(" - UF %x\n", OSi_IRQ_STACK_CHECKNUM_BOTTOM);
513
514 //---- Check if overflow
515 if (*(u32 *)(OSi_IRQ_STACK_TOP) != OSi_IRQ_STACK_CHECKNUM_TOP)
516 {
517 return OS_STACK_OVERFLOW;
518 }
519 //---- Check if about to overflow
520 else if (OSi_IrqStackWarningOffset
521 && *(u32 *)(OSi_IRQ_STACK_TOP + OSi_IrqStackWarningOffset) !=
522 OSi_IRQ_STACK_CHECKNUM_WARN)
523 {
524 return OS_STACK_ABOUT_TO_OVERFLOW;
525 }
526 //---- Check if underFlow
527 else if (*(u32 *)(OSi_IRQ_STACK_BOTTOM - sizeof(u32)) != OSi_IRQ_STACK_CHECKNUM_BOTTOM)
528 {
529 return OS_STACK_UNDERFLOW;
530 }
531 //---- No Error, return.
532 else
533 {
534 return OS_STACK_NO_ERROR;
535 }
536 }
537
538 /*---------------------------------------------------------------------------*
539 Name: OSi_CheckIrqStack
540
541 Description: check irq stack. check each CheckNUM.
542 if changed, display warning and halt.
543
544 Arguments: file file name displayed when stack overflow
545 line line number displayed when stack overflow
546
547 Returns: None
548 ( if error occurred, never return )
549 *---------------------------------------------------------------------------*/
550 static char *OSi_CheckIrqStack_mesg[] = {
551 "overflow", "about to overflow", "underflow"
552 };
553
554 #ifndef SDK_FINALROM
555 #ifndef SDK_NO_MESSAGE
OSi_CheckIrqStack(char * file,int line)556 void OSi_CheckIrqStack(char *file, int line)
557 {
558 OSStackStatus st = OS_GetIrqStackStatus();
559
560 if (st == OS_STACK_NO_ERROR)
561 {
562 return;
563 }
564
565 OSi_Panic(file, line, "irq stack %s.\nirq stack area: %08x-%08x, warning offset: %x",
566 OSi_CheckIrqStack_mesg[(int)st - 1],
567 OSi_IRQ_STACK_TOP, OSi_IRQ_STACK_BOTTOM, OSi_IrqStackWarningOffset);
568 // Never return
569 }
570 #endif
571 #endif
572