/*---------------------------------------------------------------------------* Project: CtrBrom - libraries - OS File: os_tick.c Copyright 2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: $ $Rev$ $Author$ *---------------------------------------------------------------------------*/ #include //---------------------------------------------------------------------- #ifdef SDK_ARM9 //---- timer interrupt mask (must be same number with OSi_TICK_TIMER) #define OSi_TICK_IE_TIMER (OS_IE_TIMER0 << OSi_TICK_TIMER) //---- timer control setting for tick #define OSi_TICK_TIMERCONTROL ( REG_OS_TM0CNT_H_E_MASK | REG_OS_TM0CNT_H_I_MASK | OS_TIMER_PRESCALER_64 ) #ifdef OS_TICK_USE_2TIMERS #define OSi_TICK_TIMERCONTROL_H ( REG_OS_TM1CNT_H_E_MASK | REG_OS_TM1CNT_H_I_MASK | REG_OS_TM1CNT_H_CH_MASK ) #endif // OS_TICK_USE_2TIMERS #endif // SDK_ARM9 //---- flag for initialization tick static u16 i_osUseTick = FALSE; //---- tick counter vu64 i_osTickCounter; //---- flag for need to re-set timer BOOL i_osNeedResetTimer = FALSE; extern u16 i_osIsTimerReserved(int timerNum); extern void i_osSetTimerReserved(int timerNum); static void i_osCountUpTick(void); /*---------------------------------------------------------------------------* Name: osInitTick Description: initialize 'tick system' Arguments: None Returns: None *---------------------------------------------------------------------------*/ void osInitTick(void) { if (!i_osUseTick) { i_osUseTick = TRUE; //---- disable timer interrupt osDisableInterruptID(OSi_TICK_IE_TIMER_ID); osInitInterrupt(); osInitTimer(); i_osTickCounter = 0; //---- OS reserves OSi_TICK_TIMER timer SDK_ASSERT(!i_osIsTimerReserved(OSi_TICK_TIMER)); i_osSetTimerReserved(OSi_TICK_TIMER); #ifdef SDK_ARM11 osStopTimer(OSi_TICK_TIMER); osEnableTimerReload(OSi_TICK_TIMER); osStartTimer(OSi_TICK_TIMER, OS_TICK_LO_MASK, OS_TICK_PRESCALE); #else // SDK_ARM9 //---- setting timer osSetTimerControl(OSi_TICK_TIMER, 0); #ifdef OS_TICK_USE_2TIMERS osSetTimerControl(OSi_TICK_TIMER_H, 0); osSetTimerCount(OSi_TICK_TIMER_H, (u16)0); osSetTimerControl(OSi_TICK_TIMER_H, (u16)OSi_TICK_TIMERCONTROL_H); #endif // OS_TICK_USE_2TIMERS osSetTimerCount(OSi_TICK_TIMER, (u16)0); osSetTimerControl(OSi_TICK_TIMER, (u16)OSi_TICK_TIMERCONTROL); #endif // SDK_ARM9 //---- set interrupt callback osSetInterruptHandler( OSi_TICK_IE_TIMER_ID, i_osCountUpTick ); //---- enable timer interrupt osEnableInterruptID(OSi_TICK_IE_TIMER_ID); //---- need to reset i_osNeedResetTimer = FALSE; } } /*---------------------------------------------------------------------------* Name: osIsTickAvailable Description: check tick system is available Arguments: None Returns: if available, TRUE. *---------------------------------------------------------------------------*/ BOOL osIsTickAvailable(void) { return i_osUseTick; } /*---------------------------------------------------------------------------* Name: i_osCountUpTick Description: timer interrupt handle. Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void i_osCountUpTick(void) { i_osTickCounter++; //---- setting for timer if (i_osNeedResetTimer) { #ifdef SDK_ARM11 osStopTimer(OSi_TICK_TIMER); osStartTimer(OSi_TICK_TIMER, OS_TICK_LO_MASK, OS_TICK_PRESCALE); #else // SDK_ARM9 osSetTimerControl(OSi_TICK_TIMER, 0); #ifdef OS_TICK_USE_2TIMERS osSetTimerControl(OSi_TICK_TIMER_H, 0); osSetTimerCount(OSi_TICK_TIMER_H, (u16)0); osSetTimerControl(OSi_TICK_TIMER_H, (u16)OSi_TICK_TIMERCONTROL_H); #endif // OS_TICK_USE_2TIMERS osSetTimerCount((OSTimer)OSi_TICK_TIMER, (u16)0); osSetTimerControl(OSi_TICK_TIMER, (u16)OSi_TICK_TIMERCONTROL); #endif // SDK_ARM9 i_osNeedResetTimer = FALSE; } #ifdef OS_TICK_USE_2TIMERS osIsInterruptPendingID((OSIntrID)(OSi_TICK_IE_TIMER_ID-1)); #endif // OS_TICK_USE_2TIMERS // これはやらなくても、毎回コールバックがかかるから問題ない? // //---- reset callback // OSi_EnterTimerCallback(OSi_TICK_TIMER, (void (*)(void *))i_osCountUpTick, 0); } /*---------------------------------------------------------------------------* Name: osGetTick Description: get tick value Arguments: None Returns: tick value *---------------------------------------------------------------------------*/ u64 osGetTick(void) { u32 countL; u64 countH; OSIntrMode prev = osDisableInterrupts(); SDK_ASSERT(i_osUseTick); #ifndef OS_TICK_USE_2TIMERS countL = osGetTimerCount(OSi_TICK_TIMER); #else // OS_TICK_USE_2TIMERS { u32 countM; countM = osGetTimerCount(OSi_TICK_TIMER_H); countL = osGetTimerCount(OSi_TICK_TIMER); if (osIsInterruptPendingID((OSIntrID)(OSi_TICK_IE_TIMER_ID-1)) && // OSi_TICK_TIMERオーバーフロー対策 !(countL & OS_TICK_LO_MSB) ) { countM++; } countL |= countM << 16; } #endif // OS_TICK_USE_2TIMERS #ifdef SDK_ARM11 // ARM11はダウンカウンタ、ARM9はアップカウンタの違いはここで補正される countL = OS_TICK_LO_MASK - countL; #endif // SDK_ARM11 countH = i_osTickCounter; //---- check if timer interrupt bit is on if (osIsInterruptPendingID(OSi_TICK_IE_TIMER_ID) && // countLが0xFFFFFFFFで直後に割り込み要求が来た場合の対策 !(countL & OS_TICK_LO_MSB) ) { countH++; } countH <<= OS_TICK_HI_SHIFT; (void)osRestoreInterrupts(prev); return countH | countL; } /*---------------------------------------------------------------------------* Name: osGetTickLo Description: get tick value (only u16 part) Arguments: None Returns: tick value (only u16 part) *---------------------------------------------------------------------------*/ #ifndef OS_TICK_USE_2TIMERS // OS_TICK_USE_2TIMERS 有効時は正常値を取得できない OSTimerCount osGetTickLo(void) { SDK_ASSERT(OSi_UseTick); return osGetTimerCount(OSi_TICK_TIMER); } #endif // OS_TICK_USE_2TIMERS /*---------------------------------------------------------------------------* Name: i_osSetTick Description: set tick value Arguments: count value of tick to be set OS_TICK_USE_2TIMERS 有効時はLOタイマーの オーバーフローでHIタイマーがカウントアップするため、 count = 0 以外では正常に動作しない Returns: None *---------------------------------------------------------------------------*/ #ifndef OS_TICK_USE_2TIMERS void i_osSetTick(u64 count) { OSIntrMode prev; SDK_ASSERT(i_osUseTick); prev = osDisableInterrupts(); i_osNeedResetTimer = TRUE; i_osTickCounter = (u64)(count >> OS_TICK_HI_SHIFT); #ifdef SDK_ARM11 osStopTimer(OSi_TICK_TIMER); osClearInterruptPendingID(OSi_TICK_IE_TIMER_ID); osStartTimer(OSi_TICK_TIMER, (u32)(count & OS_TICK_LO_MASK), OS_TICK_PRESCALE); #else // SDK_ARM9 osSetTimerControl(OSi_TICK_TIMER, 0); #ifdef OS_TICK_USE_2TIMERS osSetTimerControl(OSi_TICK_TIMER_H, 0); #endif // OS_TICK_USE_2TIMERS osClearInterruptPendingID(OSi_TICK_IE_TIMER_ID); #ifdef OS_TICK_USE_2TIMERS osSetTimerCount(OSi_TICK_TIMER_H, (u16)0); osSetTimerControl(OSi_TICK_TIMER_H, (u16)OSi_TICK_TIMERCONTROL_H); #endif // OS_TICK_USE_2TIMERS osSetTimerCount(OSi_TICK_TIMER, (u16)(count & OS_TICK_LO_MASK)); osSetTimerControl(OSi_TICK_TIMER, (u16)OSi_TICK_TIMERCONTROL); #endif // SDK_ARM9 (void)osRestoreInterrupts(prev); } #endif // OS_TICK_USE_2TIMERS