ctr_firmware/trunk/bootrom/build/libraries/os/common/os_alarm.c
nakasima bdb55f2e6a アラームのタイマーAPI変更対応
チックのタイマーチャンネル変更対応。

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_firmware@123 b871894f-2f95-9b40-918c-086798483c85
2008-12-18 06:25:14 +00:00

703 lines
18 KiB
C
Raw Blame History

/*---------------------------------------------------------------------------*
Project: CtrBrom - libraries - OS
File: os_alarm.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 <brom/os.h>
#define osPanic(...) ((void)0)
//----------------------------------------------------------------------
//---- timer number alarm uses
#define OSi_ALARM_TIMER OS_TIMER_1
#ifdef SDK_ARM11
//---- timer interrupt ID
#define OSi_ALARM_IE_TIMER_ID OS_INTR_ID_WATCHDOG
#else // SDK_ARM9
//---- timer interrupt ID
#define OSi_ALARM_IE_TIMER_ID OS_INTR_ID_TIMER1
//---- timer interrupt mask (must be same number with OSi_ALARM_TIMER)
#define OSi_ALARM_IE_TIMER OS_IE_TIMER1
//---- timer control setting for alarm
#define OSi_ALARM_TIMERCONTROL ( REG_OS_TM0CNT_H_E_MASK | REG_OS_TM0CNT_H_I_MASK | OS_TIMER_PRESCALER_64 )
#endif // SDK_ARM9
//---- flag for initialization alarm
static u16 i_osUseAlarm = FALSE;
//---- alarm queue
static struct OSiAlarmQueue i_osAlarmQueue;
u16 i_osIsTimerReserved(int timerNum);
void i_osSetTimerReserved(int timerNum);
void i_osUnsetTimerReserved(int timerNum);
static void i_osSetTimer(OSAlarm *alarm);
static void i_osInsertAlarm(OSAlarm *alarm, OSTick fire);
static void i_osAlarmHandler(void *arg);
void i_osArrangeTimer(void);
/*---------------------------------------------------------------------------*
Name: i_osSetTimer
Description: set Timer
Arguments: alarm pointer to alarm to set timer
Returns: None.
*---------------------------------------------------------------------------*/
static void i_osSetTimer(OSAlarm *alarm)
{
OSTimerCount timerCount;
s64 delta;
OSTick tick = osGetTick();
delta = (s64)(alarm->fire - tick);
//---- let timer be disable
osSetTimerControl(OSi_ALARM_TIMER, 0);
//---- set interrupt callback
osSetInterruptHandler( OSi_ALARM_IE_TIMER_ID, i_osArrangeTimer );
// osEnterTimerCallback(OSi_ALARM_TIMER, i_osAlarmHandler, NULL);
//---- set count and let timer be enable
if (delta < 0)
{
#ifdef SDK_ARM11
timerCount = 1;
#else // SDK_ARM9
// ARM9<4D><39>0xFFFF<46>ݒ<EFBFBD><DD92>֎~
timerCount = (u16)~1;
#endif // SDK_ARM9
}
else if (delta < OS_TICK_LO_LIMIT)
{
#ifdef SDK_ARM11
timerCount = delta;
#else // SDK_ARM9
timerCount = (u16)(~delta);
#endif // SDK_ARM9
}
else
{
#ifdef SDK_ARM11
timerCount = OS_TICK_LO_LIMIT;
#else // SDK_ARM9
timerCount = 0;
#endif // SDK_ARM9
}
//osPrintf( "**i_osSetTimer alarm=%x, fire=%llx time=%llx delta=%lld timeCount=%x \n", alarm, alarm->fire, time, delta, (int)timerCount );
#ifdef SDK_ARM11
osStartTimer(OSi_ALARM_TIMER, timerCount, 0);
#else // SDK_ARM9
osSetTimerCount((OSTimer)OSi_ALARM_TIMER, timerCount);
osSetTimerControl(OSi_ALARM_TIMER, (u16)OSi_ALARM_TIMERCONTROL);
#endif // SDK_ARM9
//---- TIMER IRQ Enable
(void)osEnableInterruptID(OSi_ALARM_IE_TIMER_ID);
}
/*---------------------------------------------------------------------------*
Name: osInitAlarm
Description: Initialize alarm system
Arguments: None.
Returns: None.
*---------------------------------------------------------------------------*/
void osInitAlarm(void)
{
if (!i_osUseAlarm)
{
i_osUseAlarm = TRUE;
//---- check if tick system is available
SDK_ASSERTMSG(osIsTickAvailable(), "osInitAlarm: alarm system needs of tick system.");
//---- OS reserves OSi_ALARM_TIMER
SDK_ASSERT(!i_osIsTimerReserved(OSi_ALARM_TIMER));
i_osSetTimerReserved(OSi_ALARM_TIMER);
#ifdef SDK_ARM11
osDisableTimerReload(OSi_ALARM_TIMER);
#endif // SDK_ARM11
//---- clear alarm list
i_osAlarmQueue.head = NULL;
i_osAlarmQueue.tail = NULL;
//---- TIMER IRQ Disable
(void)osDisableInterruptID(OSi_ALARM_IE_TIMER_ID);
}
}
/*---------------------------------------------------------------------------*
Name: osEndAlarm
Description: end alarm system
Arguments: None
Returns: None
*---------------------------------------------------------------------------*/
void osEndAlarm(void)
{
OSIntrMode enabled;
SDK_ASSERT(i_osUseAlarm);
enabled = osDisableInterrupts();
//---- check if any alarm exists
if (i_osUseAlarm)
{
SDK_ASSERTMSG(!i_osAlarmQueue.head,
"osEndAlarm: Cannot end alarm system while using alarm.");
#ifdef SDK_ARM9
//---- unset timer reservation by OS
SDK_ASSERT(i_osIsTimerReserved(OSi_ALARM_TIMER));
i_osUnsetTimerReserved(OSi_ALARM_TIMER);
#endif // SDK_ARM9
i_osUseAlarm = FALSE;
}
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: osIsAlarmAvailable
Description: check alarm system is available
Arguments: None
Returns: if available, TRUE.
*---------------------------------------------------------------------------*/
BOOL osIsAlarmAvailable(void)
{
return i_osUseAlarm;
}
/*---------------------------------------------------------------------------*
Name: osCreateAlarm
Description: Create alarm
Arguments: alarm pointer to alarm to be initialized
Returns: None.
*---------------------------------------------------------------------------*/
void osCreateAlarm(OSAlarm *alarm)
{
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERT(alarm);
alarm->handler = 0;
alarm->tag = 0;
}
/*---------------------------------------------------------------------------*
Name: i_osInsertAlarm
Description: Insert alarm. Needs to be called interrupts disabled.
Arguments: alarm pointer to alarm to be set
fire tick to fire (only for one shot alarm)
Returns: None.
*---------------------------------------------------------------------------*/
static void i_osInsertAlarm(OSAlarm *alarm, OSTick fire)
{
OSAlarm *prev;
OSAlarm *next;
//---- caluculate next fire for periodic alarm
if (alarm->period > 0)
{
OSTick tick = osGetTick();
fire = alarm->start;
if (alarm->start < tick)
{
fire += alarm->period * ((tick - alarm->start) / alarm->period + 1);
}
}
//---- set tick to fire
alarm->fire = fire;
//---- insert to list
for (next = i_osAlarmQueue.head; next; next = next->next)
{
// if ( next->fire <= fire )
if ((s64)(fire - next->fire) >= 0)
{
continue;
}
//---- insert alarm before 'next'
alarm->prev = next->prev;
next->prev = alarm;
alarm->next = next;
prev = alarm->prev;
if (prev)
{
prev->next = alarm;
}
else
{
i_osAlarmQueue.head = alarm;
i_osSetTimer(alarm);
}
return;
}
//---- insert alarm after tail
alarm->next = 0;
prev = i_osAlarmQueue.tail;
i_osAlarmQueue.tail = alarm;
alarm->prev = prev;
if (prev)
{
prev->next = alarm;
}
else
{
i_osAlarmQueue.head = i_osAlarmQueue.tail = alarm;
i_osSetTimer(alarm);
}
}
/*---------------------------------------------------------------------------*
Name: osSetAlarm
Description: Set alarm as a relative tick
Arguments: alarm pointer to alarm to be set
tick ticks to count before firing
handler alarm handler to be called
arg argument of handler
Returns: None.
*---------------------------------------------------------------------------*/
void osSetAlarm(OSAlarm *alarm, OSTick tick, OSAlarmHandler handler, void *arg)
{
OSIntrMode enabled;
//osPrintf( "**osSetAlarm e=%x alarm=%x tick=%x handler%x\n", enabled, alarm, tick, handler );
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERTMSG(handler, "osSetAlarm: handler must not be NULL.");
if (!alarm || alarm->handler)
{
#ifndef SDK_FINALROM
osPanic("alarm could be already used.");
#else
osPanic("");
#endif
}
enabled = osDisableInterrupts();
//---- clear periodic info
alarm->period = 0;
//---- set handler
alarm->handler = handler;
alarm->arg = arg;
//---- insert alarm
i_osInsertAlarm(alarm, osGetTick() + tick);
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: osSetPeriodicAlarm
Description: set periodic alarm
Arguments: alarm pointer to alarm to be set
start origin of the period in absolute tick
period ticks to count for each period
handler alarm handler to be called
arg argument of handler
Returns: None.
*---------------------------------------------------------------------------*/
void osSetPeriodicAlarm(OSAlarm *alarm, OSTick start, OSTick period, OSAlarmHandler handler,
void *arg)
{
u32 enabled;
//osPrintf( "**SetPeriodicAlarm s=%llx p=%llx\n", start, period );
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERTMSG(handler, "osSetPeriodicAlarm: handler must not be NULL\n");
SDK_ASSERTMSG(period > 0, "osSetPeriodicAlarm: bad period specified.");
if (!alarm || alarm->handler)
{
#ifndef SDK_FINALROM
osPanic("alarm could be already used.");
#else
osPanic("");
#endif
}
enabled = osDisableInterrupts();
//---- set periodic info
alarm->period = period;
alarm->start = start;
//---- set handler
alarm->handler = handler;
alarm->arg = arg;
//---- insert periodic alarm
i_osInsertAlarm(alarm, 0);
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: osCancelAlarm
Description: Cancel alarm
Arguments: alarm pointer to alarm to be canceled
Returns: None.
*---------------------------------------------------------------------------*/
void osCancelAlarm(OSAlarm *alarm)
{
OSAlarm *next;
u32 enabled;
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERT(alarm);
enabled = osDisableInterrupts();
if (alarm->handler == NULL)
{
(void)osRestoreInterrupts(enabled);
return;
}
//---- remove alarm
next = alarm->next;
if (next == NULL)
{
i_osAlarmQueue.tail = alarm->prev;
}
else
{
next->prev = alarm->prev;
}
if (alarm->prev)
{
alarm->prev->next = next;
}
else
{
i_osAlarmQueue.head = next;
if (next)
{
i_osSetTimer(next);
}
}
alarm->handler = NULL;
alarm->period = 0; // not periodic alarm
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: i_osAlarmHandler
Description: handler timer interrupt
Arguments: arg dummy
Returns: None.
*---------------------------------------------------------------------------*/
#include <brom/code32.h>
asm void i_osAlarmHandler( void* arg )
{
INASM_EXTERN( i_osArrangeTimer )
stmfd sp!, {r0, lr} /* <20>R<EFBFBD>[<5B><><EFBFBD>X<EFBFBD>^<5E>b<EFBFBD>N<EFBFBD><4E> 8 <20>o<EFBFBD>C<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD> */
bl i_osArrangeTimer
ldmfd sp!, {r0, lr} /* <20>R<EFBFBD>[<5B><><EFBFBD>X<EFBFBD>^<5E>b<EFBFBD>N<EFBFBD><4E> 8 <20>o<EFBFBD>C<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD> */
bx lr
}
#include <brom/codereset.h>
/*---------------------------------------------------------------------------*
Name: i_osArrangeTimer
Description: handler timer interrupt. called from i_osAlarmHandler
Arguments: None
Returns: None.
*---------------------------------------------------------------------------*/
void i_osArrangeTimer(void)
{
OSTick tick;
OSAlarm *alarm;
OSAlarm *next;
OSAlarmHandler handler;
//---- To be timer-irq Disable
(void)osDisableInterruptID(OSi_ALARM_IE_TIMER_ID);
//---- let timer be disable
osSetTimerControl(OSi_ALARM_TIMER, 0);
#ifdef SDK_ARM9
//---- set check flag timer interrupt
// osSetIrqCheckFlag(OSi_ALARM_IE_TIMER);
#endif // SDK_ARM9
tick = osGetTick();
alarm = i_osAlarmQueue.head;
//osPrintf( "**Arrange alarm=%x time=%llx file=%llx\n", alarm, time, alarm->fire );
//---- no alarm
if (alarm == NULL)
{
return;
}
//---- not reach to time of top alarm
if (tick < alarm->fire)
{
i_osSetTimer(alarm);
return;
}
//---- move next alarm to top
next = alarm->next;
i_osAlarmQueue.head = next;
if (next == NULL)
{
i_osAlarmQueue.tail = NULL;
}
else
{
next->prev = NULL;
}
//---- call user alarm handler
handler = alarm->handler;
if (alarm->period == 0)
{
alarm->handler = NULL;
}
if (handler)
{
(handler) (alarm->arg);
}
//---- if alarm is periodic, re-inter to list
if (alarm->period > 0)
{
alarm->handler = handler;
i_osInsertAlarm(alarm, 0);
}
//---- set timer
if (i_osAlarmQueue.head)
{
i_osSetTimer(i_osAlarmQueue.head);
}
}
/*---------------------------------------------------------------------------*
Name: osSetAlarmTag
Description: set tag which is used osCancelAlarms
Arguments: alarm alarm to be set tag
tag tagNo
Returns: None.
*---------------------------------------------------------------------------*/
void osSetAlarmTag(OSAlarm *alarm, u32 tag)
{
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERT(alarm);
SDK_ASSERTMSG(tag > 0, "osSetAlarmTag: Tag must be >0.");
alarm->tag = tag;
}
/*---------------------------------------------------------------------------*
Name: osCancelAlarms
Description: cancel alarms which have specified tag
Arguments: tag tagNo. to be cancelled. not 0
Returns: None.
*---------------------------------------------------------------------------*/
void osCancelAlarms(u32 tag)
{
u32 enabled;
OSAlarm *alarm;
OSAlarm *next;
SDK_ASSERT(i_osUseAlarm);
SDK_ASSERTMSG(tag > 0, "OSCancelAlarms: Tag must be >0.");
if (tag == 0)
{
return;
}
enabled = osDisableInterrupts();
for (alarm = i_osAlarmQueue.head, next = alarm ? alarm->next : NULL;
alarm; alarm = next, next = alarm ? alarm->next : NULL)
{
if (alarm->tag == tag)
{
//---- cancel alarm
osCancelAlarm(alarm);
}
}
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: osCancelAllAlarms
Description: cancel all alarms
Arguments: None
Returns: None.
*---------------------------------------------------------------------------*/
void osCancelAllAlarms(void)
{
u32 enabled;
OSAlarm *alarm;
OSAlarm *next;
SDK_ASSERT(i_osUseAlarm);
enabled = osDisableInterrupts();
for (alarm = i_osAlarmQueue.head, next = alarm ? alarm->next : NULL;
alarm; alarm = next, next = alarm ? alarm->next : NULL)
{
//---- cancel alarm
osCancelAlarm(alarm);
}
(void)osRestoreInterrupts(enabled);
}
/*---------------------------------------------------------------------------*
Name: i_osGetAlarmQueue
Description: get alarm queue
Arguments: None
Returns: alarm queue.
*---------------------------------------------------------------------------*/
struct OSiAlarmQueue *i_osGetAlarmQueue(void)
{
return &i_osAlarmQueue;
}
//================================================================================
// FOR DEBUG
//================================================================================
/*---------------------------------------------------------------------------*
Name: osGetNumberOfAlarm
Description: get number of alarm
Arguments: None
Returns: number of alarm
*---------------------------------------------------------------------------*/
int osGetNumberOfAlarm(void)
{
OSIntrMode enabled = osDisableInterrupts();
OSAlarm* p = i_osAlarmQueue.head;
int num = 0;
while(p)
{
num ++;
p = p->next;
}
(void)osRestoreInterrupts(enabled);
return num;
}
/*---------------------------------------------------------------------------*
Name: osGetAlarmResource
Description: store resources of alarm to specified pointer
Arguments: resource pointer to store alarm resources
Returns: TRUE ... success (always return this now)
FALSE ... fail
*---------------------------------------------------------------------------*/
BOOL osGetAlarmResource(OSAlarmResource *resource)
{
resource->num = osGetNumberOfAlarm();
return TRUE;
}