diff options
| author | PikalaxALT <pikalaxalt@gmail.com> | 2020-06-20 09:19:42 -0400 | 
|---|---|---|
| committer | PikalaxALT <pikalaxalt@gmail.com> | 2020-06-20 09:19:42 -0400 | 
| commit | a16371f513daf21948e372a3955f4cfa0d89a141 (patch) | |
| tree | 7029add9f3cd169307e1023a4b0ae7552b9afeff /arm7/lib | |
| parent | 1386f29730b42a640fde1d568255dc10be4ac759 (diff) | |
| parent | 0c8b5417cee5ff73f9db4b691c7549e82fdc30bd (diff) | |
Merge branch 'pikalax_work' of github.com:PikalaxALT/pokediamond into pikalax_work
Diffstat (limited to 'arm7/lib')
| -rw-r--r-- | arm7/lib/include/MI_memory.h | 10 | ||||
| -rw-r--r-- | arm7/lib/include/OS_alarm.h | 9 | ||||
| -rw-r--r-- | arm7/lib/include/OS_context.h | 4 | ||||
| -rw-r--r-- | arm7/lib/include/OS_mutex.h | 9 | ||||
| -rw-r--r-- | arm7/lib/include/OS_thread.h | 29 | ||||
| -rw-r--r-- | arm7/lib/include/consts.h | 1 | ||||
| -rw-r--r-- | arm7/lib/include/systemWork.h | 7 | ||||
| -rw-r--r-- | arm7/lib/src/OS_thread.c | 597 | 
8 files changed, 666 insertions, 0 deletions
| diff --git a/arm7/lib/include/MI_memory.h b/arm7/lib/include/MI_memory.h index cb0c53fc..53398ec5 100644 --- a/arm7/lib/include/MI_memory.h +++ b/arm7/lib/include/MI_memory.h @@ -12,4 +12,14 @@ void MIi_CpuCopyFast(register u32 * src, register u32 * dst, register u32 size);  void MI_CpuFill8(register u8 value, register u8 * dst, register u32 size);  void MI_CpuCopy8(register u8 * src, register u8 * dst, register u32 size); +static inline void MI_CpuFill32(void *dest, u32 data, u32 size) +{ +    MIi_CpuClear32(data, dest, size); +} + +static inline void MI_CpuClear32(void *dest, u32 size) +{ +    MI_CpuFill32(dest, 0, size); +} +  #endif diff --git a/arm7/lib/include/OS_alarm.h b/arm7/lib/include/OS_alarm.h new file mode 100644 index 00000000..8ae89e97 --- /dev/null +++ b/arm7/lib/include/OS_alarm.h @@ -0,0 +1,9 @@ +#ifndef POKEDIAMOND_ARM7_OS_ALARM_H +#define POKEDIAMOND_ARM7_OS_ALARM_H + +#include "nitro/OS_alarm_shared.h" + +void OS_CreateAlarm(OSAlarm *alarm); +void OS_SetAlarm(OSAlarm *alarm, OSTick tick, OSAlarmHandler handler, void *arg); + +#endif //POKEDIAMOND_ARM7_OS_ALARM_H diff --git a/arm7/lib/include/OS_context.h b/arm7/lib/include/OS_context.h index 7819e29c..b01ccb8b 100644 --- a/arm7/lib/include/OS_context.h +++ b/arm7/lib/include/OS_context.h @@ -13,4 +13,8 @@ typedef struct OSContext      u32 sp_svc;  } OSContext; +extern u32 OS_SaveContext(OSContext *context); +extern void OS_LoadContext(OSContext *context); +extern void OS_InitContext(OSContext *context, u32 func, u32 stack); +  #endif //POKEDIAMOND_ARM7_OS_CONTEXT_H diff --git a/arm7/lib/include/OS_mutex.h b/arm7/lib/include/OS_mutex.h new file mode 100644 index 00000000..b41ac9f8 --- /dev/null +++ b/arm7/lib/include/OS_mutex.h @@ -0,0 +1,9 @@ +#ifndef POKEDIAMOND_ARM7_OS_MUTEX_H +#define POKEDIAMOND_ARM7_OS_MUTEX_H + +#include "OS_context.h" +#include "nitro/OS_mutex_shared.h" + +void OSi_UnlockAllMutex(OSThread * thread); + +#endif //POKEDIAMOND_ARM7_OS_MUTEX_H diff --git a/arm7/lib/include/OS_thread.h b/arm7/lib/include/OS_thread.h index 04e4fdcb..b1d3a01b 100644 --- a/arm7/lib/include/OS_thread.h +++ b/arm7/lib/include/OS_thread.h @@ -4,4 +4,33 @@  #include "OS_context.h"  #include "nitro/OS_thread_shared.h" +static s32 OSi_GetUnusedThreadId(void); +static void OSi_InsertLinkToQueue(OSThreadQueue *queue, OSThread *thread); +static OSThread *OSi_RemoveLinkFromQueue(OSThreadQueue *queue); +static OSThread *OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue *queue, OSThread *thread); +OSMutex *OSi_RemoveMutexLinkFromQueue(OSMutexQueue *queue); +static void OSi_InsertThreadToList(OSThread *thread); +static void OSi_RemoveThreadFromList(OSThread *thread); +static void OSi_RescheduleThread(void); +void OS_InitThread(void); +void OS_CreateThread(OSThread *thread, void (*func) (void *), void *arg, void *stack, u32 stackSize, u32 prio); +void OS_ExitThread(void); +static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg); +static void OSi_ExitThread(void *arg); +static void OSi_ExitThread_Destroy(void); +void OS_JoinThread(OSThread *thread); +BOOL OS_IsThreadTerminated(const OSThread *thread); +void OS_SleepThread(OSThreadQueue *queue); +void OS_WakeupThread(OSThreadQueue *queue); +void OS_WakeupThreadDirect(OSThread *thread); +OSThread *OS_SelectThread(void); +void OS_RescheduleThread(void); +BOOL OS_SetThreadPriority(OSThread *thread, u32 prio); +void OS_Sleep(u32 msec); +static void OSi_SleepAlarmCallback(void *arg); +OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback); +u32 OS_DisableScheduler(void); +u32 OS_EnableScheduler(void); +void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor); +  #endif //POKEDIAMOND_ARM7_OS_THREAD_H diff --git a/arm7/lib/include/consts.h b/arm7/lib/include/consts.h index 966b5a4b..a6c4c393 100644 --- a/arm7/lib/include/consts.h +++ b/arm7/lib/include/consts.h @@ -4,5 +4,6 @@  #include "nitro/consts_shared.h"  #include "mmap.h"  #include "registers.h" +#include "systemWork.h"  #endif //POKEDIAMOND_ARM7_CONSTS_H diff --git a/arm7/lib/include/systemWork.h b/arm7/lib/include/systemWork.h new file mode 100644 index 00000000..95a17845 --- /dev/null +++ b/arm7/lib/include/systemWork.h @@ -0,0 +1,7 @@ +#ifndef POKEDIAMOND_ARM7_SYSTEMWORK_H +#define POKEDIAMOND_ARM7_SYSTEMWORK_H + +#include "OS_context.h" +#include "nitro/OS_systemWork_shared.h" + +#endif //POKEDIAMOND_ARM7_SYSTEMWORK_H diff --git a/arm7/lib/src/OS_thread.c b/arm7/lib/src/OS_thread.c new file mode 100644 index 00000000..be3f611d --- /dev/null +++ b/arm7/lib/src/OS_thread.c @@ -0,0 +1,597 @@ +#include "OS_thread.h" +#include "function_target.h" +#include "OS_system.h" +#include "consts.h" +#include "OS_terminate_proc.h" +#include "OS_mutex.h" +#include "OS_alarm.h" +#include "OS_context.h" +#include "nitro/OS_systemWork_shared.h" +#include "MI_memory.h" + +extern void SDK_SYS_STACKSIZE(void); +extern void SDK_IRQ_STACKSIZE(void); + +u32 OSi_RescheduleCount = 0; + +void *OSi_StackForDestructor = NULL; + +OSThreadInfo OSi_ThreadInfo; + +BOOL OSi_IsThreadInitialized = FALSE; + +OSThread **OSi_CurrentThreadPtr = NULL; + +void *OSi_SystemCallbackInSwitchThread = NULL; + +static s32 OSi_ThreadIdCount = 0; + +OSThread OSi_LauncherThread; +OSThread OSi_IdleThread; + +ARM_FUNC static s32 OSi_GetUnusedThreadId(void) +{ +    return ++OSi_ThreadIdCount; +} + +ARM_FUNC static void OSi_InsertLinkToQueue(OSThreadQueue *queue, OSThread *thread) +{ +    OSThread *next = queue->head; + +    while (next && next->priority <= thread->priority) +    { +        if (next == thread) +            return; +        next = next->link.next; +    } + +    if (!next) +    { +        OSThread *prev = queue->tail; + +        if (!prev) +        { +            queue->head = thread; +        } +        else +        { +            prev->link.next = thread; +        } + +        thread->link.prev = prev; +        thread->link.next = NULL; +        queue->tail = thread; +    } +    else +    { +        OSThread *prev = next->link.prev; + +        if (!prev) +        { +            queue->head = thread; +        } +        else +        { +            prev->link.next = thread; +        } + +        thread->link.prev = prev; +        thread->link.next = next; +        next->link.prev = thread; +    } +} + +ARM_FUNC static OSThread *OSi_RemoveLinkFromQueue(OSThreadQueue *queue) +{ +    OSThread *thread = queue->head; + +    if (thread) +    { +        OSThread *next = thread->link.next; + +        queue->head = next; + +        if (next) +        { +            next->link.prev = NULL; +        } +        else +        { +            queue->tail = NULL; +            thread->queue = NULL; +        } +    } + +    return thread; +} + +ARM_FUNC static OSThread *OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue *queue, OSThread *thread) +{ +    OSThread *queueHead = queue->head; + +    while (queueHead) +    { +        OSThread *next = queueHead->link.next; + +        if (queueHead == thread) +        { +            OSThread *prev = queueHead->link.prev; + +            if (queue->head == queueHead) +            { +                queue->head = next; +            } +            else +            { +                prev->link.next = next; +            } + +            if (queue->tail == queueHead) +            { +                queue->tail = prev; +            } +            else +            { +                next->link.prev = prev; +            } + +            break; +        } + +        queueHead = next; +    } + +    return queueHead; +} + +ARM_FUNC OSMutex *OSi_RemoveMutexLinkFromQueue(OSMutexQueue *queue) +{ +    OSMutex *mutexHead = queue->head; + +    if (mutexHead) +    { +        OSMutex *next = mutexHead->link.next; + +        queue->head = next; + +        if (next) +        { +            next->link.prev = NULL; +        } +        else +        { +            queue->tail = NULL; +        } +    } + +    return mutexHead; +} + +ARM_FUNC static void OSi_InsertThreadToList(OSThread *thread) +{ +    OSThread *t = OSi_ThreadInfo.list; +    OSThread *pre = NULL; + +    while(t && t->priority < thread->priority) +    { +        pre = t; +        t = t->next; +    } + +    if (!pre) +    { +        thread->next = OSi_ThreadInfo.list; +        OSi_ThreadInfo.list = thread; +    } +    else +    { +        thread->next = pre->next; +        pre->next = thread; +    } +} + +ARM_FUNC static void OSi_RemoveThreadFromList(OSThread *thread) +{ +    OSThread *t = OSi_ThreadInfo.list; +    OSThread *pre = NULL; + +    while (t && t != thread) +    { +        pre = t; +        t = t-> next; +    } + +    if (!pre) +    { +        OSi_ThreadInfo.list = thread->next; +    } +    else +    { +        pre->next = thread->next; +    } +} + +ARM_FUNC static void OSi_RescheduleThread(void) +{ +    if (OSi_RescheduleCount <= 0) +    { +        OSThreadInfo *info = &OSi_ThreadInfo; +        if (info->irqDepth > 0 || OS_GetProcMode() == OS_PROCMODE_IRQ) +        { +            info->isNeedRescheduling = TRUE; +        } +        else +        { +            OSThread *currentThread = OSi_GetCurrentThread(); +            OSThread *nextThread = OS_SelectThread(); + +            if (currentThread == nextThread || !nextThread) +                return; + +            if (currentThread->state != OS_THREAD_STATE_TERMINATED +                && OS_SaveContext(¤tThread->context)) +                return; + +            if (OSi_SystemCallbackInSwitchThread) +            { +                ((OSSwitchThreadCallback)OSi_SystemCallbackInSwitchThread) (currentThread, nextThread); +            } + +            if (info->switchCallback) +            { +                ((OSSwitchThreadCallback)info->switchCallback) (currentThread, nextThread); +            } + +            OS_SetCurrentThread(nextThread); + +            OS_LoadContext(&nextThread->context); +        } +    } +} + +ARM_FUNC void OS_InitThread(void) +{ +    if (OSi_IsThreadInitialized) +        return; +    OSi_IsThreadInitialized = TRUE; + +    OSi_CurrentThreadPtr = &(OSi_ThreadInfo.current); + +    OSi_LauncherThread.priority = OS_THREAD_LAUNCHER_PRIORITY; +    OSi_LauncherThread.id = 0; +    OSi_LauncherThread.state = OS_THREAD_STATE_READY; +    OSi_LauncherThread.next = NULL; + +    OSi_LauncherThread.profiler = NULL; + +    OSi_ThreadInfo.list = &OSi_LauncherThread; + +    OS_SetCurrentThread(&OSi_LauncherThread); + +    void *stackLo = (((s32)SDK_SYS_STACKSIZE) <= 0) ? +                    (void *)((u32)HW_WRAM - (s32)SDK_SYS_STACKSIZE) : +                    (void *)((u32)(HW_PRV_WRAM_IRQ_STACK_END - (s32)SDK_IRQ_STACKSIZE) - (s32)SDK_SYS_STACKSIZE); + +    OSi_LauncherThread.stackBottom = (u32)(HW_PRV_WRAM_IRQ_STACK_END - (s32)SDK_IRQ_STACKSIZE); +    OSi_LauncherThread.stackTop = (u32)stackLo; +    OSi_LauncherThread.stackWarningOffset = 0; + +    //checksums +    *(u32 *)(OSi_LauncherThread.stackBottom - sizeof(u32)) = 0xd73bfdf7UL; +    *(u32 *)OSi_LauncherThread.stackTop = 0xfbdd37bbUL; + +    OS_InitThreadQueue(&OSi_LauncherThread.joinQueue); + +    OSi_ThreadInfo.isNeedRescheduling = FALSE; +    OSi_ThreadInfo.irqDepth = 0; + +    OS_GetSystemWork()->threadinfo_subp = &OSi_ThreadInfo; + +    (void)OS_SetSwitchThreadCallback(NULL); +} + +ARM_FUNC void OS_CreateThread(OSThread *thread, void (*func) (void *), void *arg, void *stack, u32 stackSize, u32 prio) +{ +    OSIntrMode enable = OS_DisableInterrupts(); + +    s32 index = OSi_GetUnusedThreadId(); + +    thread->priority = prio; +    thread->id = (u32)index; +    thread->state = OS_THREAD_STATE_WAITING; + +    thread->profiler = NULL; + +    OSi_InsertThreadToList(thread); + +    thread->stackBottom = (u32)stack; +    thread->stackTop = (u32)stack - stackSize; +    thread->stackWarningOffset = 0; + +    *(u32 *)(thread->stackBottom - sizeof(u32)) = 0xd73bfdf7UL; +    *(u32 *)thread->stackTop = 0xfbdd37bbUL; + +    OS_InitThreadQueue(&thread->joinQueue); + +    OS_InitContext(&thread->context, (u32)func, (u32)stack - 4); + +    thread->context.r[0] = (u32)arg; +    thread->context.lr = (u32)OS_ExitThread; + +    MI_CpuClear32((void *)((u32)stack - stackSize + 4), stackSize - 8); + +    thread->mutex = NULL; +    thread->mutexQueue.head = NULL; +    thread->mutexQueue.tail = NULL; + +    OS_SetThreadDestructor(thread, NULL); + +    thread->queue = NULL; +    thread->link.prev = thread->link.next = NULL; + +    MI_CpuClear32(&thread->specific[0], sizeof(void *) * OS_THREAD_SPECIFIC_MAX); + +    thread->alarmForSleep = NULL; + +    (void)OS_RestoreInterrupts(enable); +} + +ARM_FUNC void OS_ExitThread(void) +{ +    (void)OS_DisableInterrupts(); +    OSi_ExitThread_ArgSpecified(OS_GetCurrentThread(), 0); +} + +ARM_FUNC static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg) +{ +    if (OSi_StackForDestructor) +    { +        OS_InitContext(&thread->context, (u32)OSi_ExitThread, (u32)OSi_StackForDestructor); +        thread->context.r[0] = (u32)arg; +        thread->context.cpsr |= HW_PSR_DISABLE_IRQ; +        thread->state = OS_THREAD_STATE_READY; +        OS_LoadContext(&thread->context); +    } +    else +    { +        OSi_ExitThread(arg); +    } +} + +ARM_FUNC static void OSi_ExitThread(void *arg) +{ +    OSThread *currentThread = OSi_GetCurrentThread(); +    OSThreadDestructor destructor = currentThread->destructor; + +    if (destructor) +    { +        currentThread->destructor = NULL; +        destructor(arg); +        (void)OS_DisableInterrupts(); +    } + +    OSi_ExitThread_Destroy(); +} + +ARM_FUNC static void OSi_ExitThread_Destroy(void) +{ +    OSThread *currentThread = OSi_GetCurrentThread(); +    (void)OS_DisableScheduler(); + +    OSi_UnlockAllMutex(currentThread); + +    if (currentThread->queue) +    { +        (void)OSi_RemoveSpecifiedLinkFromQueue(currentThread->queue, currentThread); +    } + +    OSi_RemoveThreadFromList(currentThread); + +    currentThread->state = OS_THREAD_STATE_TERMINATED; + +    OS_WakeupThread(¤tThread->joinQueue); + +    (void)OS_EnableScheduler(); + +    OS_RescheduleThread(); + +    OS_Terminate(); +} + +ARM_FUNC void OS_JoinThread(OSThread *thread) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); + +    if (thread->state != OS_THREAD_STATE_TERMINATED) +    { +        OS_SleepThread(&thread->joinQueue); +    } + +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC BOOL OS_IsThreadTerminated(const OSThread *thread) +{ +    return (thread->state == OS_THREAD_STATE_TERMINATED) ? TRUE : FALSE; +} + +ARM_FUNC void OS_SleepThread(OSThreadQueue *queue) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); +    OSThread *currentThread = OSi_GetCurrentThread(); + +    if (queue) +    { +        currentThread->queue = queue; +        OSi_InsertLinkToQueue(queue, currentThread); +    } + +    currentThread->state = OS_THREAD_STATE_WAITING; +    OSi_RescheduleThread(); + +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC void OS_WakeupThread(OSThreadQueue *queue) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); + +    if (queue->head) +    { +        while (queue->head) +        { +            OSThread *thread = OSi_RemoveLinkFromQueue(queue); + +            thread->state = OS_THREAD_STATE_READY; +            thread->queue = NULL; +            thread->link.prev = thread->link.next = NULL; +        } + +        OS_InitThreadQueue(queue); +        OSi_RescheduleThread(); +    } + +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC void OS_WakeupThreadDirect(OSThread *thread) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); + +    thread->state = OS_THREAD_STATE_READY; +    OSi_RescheduleThread(); + +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC OSThread *OS_SelectThread(void) +{ +    OSThread *thread = OSi_ThreadInfo.list; + +    while (thread && !OS_IsThreadRunnable(thread)) +    { +        thread = thread->next; +    } + +    return thread; +} + +ARM_FUNC void OS_RescheduleThread(void) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); +    OSi_RescheduleThread(); +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC BOOL OS_SetThreadPriority(OSThread *thread, u32 prio) +{ +    OSThread *t = OSi_ThreadInfo.list; +    OSThread *pre = NULL; +    OSIntrMode enabled = OS_DisableInterrupts(); + +    while (t && t != thread) +    { +        pre = t; +        t = t->next; +    } + +    if (!t || t == &OSi_IdleThread) +    { +        (void)OS_RestoreInterrupts(enabled); +        return FALSE; +    } + +    if (t->priority != prio) +    { +        if (!pre) +        { +            OSi_ThreadInfo.list = thread->next; +        } +        else +        { +            pre->next = thread->next; +        } + +        thread->priority = prio; +        OSi_InsertThreadToList(thread); + +        OSi_RescheduleThread(); +    } + +    (void)OS_RestoreInterrupts(enabled); + +    return TRUE; +} + +ARM_FUNC void OS_Sleep(u32 msec) +{ +    OSAlarm alarm; + +    OS_CreateAlarm(&alarm); +    OSThread *volatile p_thread = OSi_GetCurrentThread(); +    OSIntrMode enabled = OS_DisableInterrupts(); + +    p_thread->alarmForSleep = &alarm; + +    OS_SetAlarm(&alarm, OS_MilliSecondsToTicks(msec), &OSi_SleepAlarmCallback, +                (void*)&p_thread); +    while (p_thread != NULL) +    { +        OS_SleepThread(NULL); +    } +    (void)OS_RestoreInterrupts(enabled); +} + +ARM_FUNC static void OSi_SleepAlarmCallback(void *arg) +{ +    OSThread **pp_thread = (OSThread **)arg; +    OSThread *p_thread = *pp_thread; +    *pp_thread = NULL; + +    p_thread->alarmForSleep = NULL; + +    OS_WakeupThreadDirect(p_thread); +} + +ARM_FUNC OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); +    OSSwitchThreadCallback prev = OSi_ThreadInfo.switchCallback; +    OSi_ThreadInfo.switchCallback = callback; + +    (void)OS_RestoreInterrupts(enabled); +    return prev; +} + +ARM_FUNC u32 OS_DisableScheduler(void) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); +    u32 count; + +    if (OSi_RescheduleCount < (u32)-1) +    { +        count = OSi_RescheduleCount++; +    } +    (void)OS_RestoreInterrupts(enabled); + +    return count; +} + +ARM_FUNC u32 OS_EnableScheduler(void) +{ +    OSIntrMode enabled = OS_DisableInterrupts(); +    u32 count = 0; + +    if (OSi_RescheduleCount > 0) +    { +        count = OSi_RescheduleCount--; +    } +    (void)OS_RestoreInterrupts(enabled); + +    return count; +} + +ARM_FUNC void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor) +{ +    thread->destructor = dtor; +} | 
