summaryrefslogtreecommitdiff
path: root/arm9/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arm9/lib')
-rw-r--r--arm9/lib/.gitignore3
-rw-r--r--arm9/lib/include/MI_memory.h14
-rw-r--r--arm9/lib/include/OS_alarm.h5
-rw-r--r--arm9/lib/include/OS_arena.h27
-rw-r--r--arm9/lib/include/OS_context.h4
-rw-r--r--arm9/lib/include/OS_mutex.h2
-rw-r--r--arm9/lib/include/OS_reset.h5
-rw-r--r--arm9/lib/include/OS_thread.h59
-rw-r--r--arm9/lib/include/OS_tick.h6
-rw-r--r--arm9/lib/include/consts.h9
-rw-r--r--arm9/lib/include/mmap.h13
-rw-r--r--arm9/lib/src/OS_init.c1
-rw-r--r--arm9/lib/src/OS_reset.c45
-rw-r--r--arm9/lib/src/OS_thread.c720
14 files changed, 855 insertions, 58 deletions
diff --git a/arm9/lib/.gitignore b/arm9/lib/.gitignore
new file mode 100644
index 00000000..f64bee72
--- /dev/null
+++ b/arm9/lib/.gitignore
@@ -0,0 +1,3 @@
+libsyscall.a
+
+syscall/*.o
diff --git a/arm9/lib/include/MI_memory.h b/arm9/lib/include/MI_memory.h
index 0ebb3560..bf6c0ca5 100644
--- a/arm9/lib/include/MI_memory.h
+++ b/arm9/lib/include/MI_memory.h
@@ -1,6 +1,8 @@
#ifndef NITRO_MI_MEMORY_H_
#define NITRO_MI_MEMORY_H_
+#include "nitro/types.h"
+
void MI_CpuFill8(void *dest, u8 data, u32 size);
void MI_CpuCopy8(void const *src, void *dest, u32 size);
static inline void MI_CpuClear8(void *dest, u32 size) {
@@ -8,4 +10,16 @@ static inline void MI_CpuClear8(void *dest, u32 size) {
}
void MIi_CpuCopy16(const void *src, void *dst, u32 size);
+void MIi_CpuClear32(u32 data, void *destp, 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 //NITRO_MI_MEMORY_H_
diff --git a/arm9/lib/include/OS_alarm.h b/arm9/lib/include/OS_alarm.h
index d6b0c210..a9734d1b 100644
--- a/arm9/lib/include/OS_alarm.h
+++ b/arm9/lib/include/OS_alarm.h
@@ -3,6 +3,7 @@
#include "nitro/types.h"
#include "OS_thread.h"
+#include "OS_tick.h"
typedef void (*OSAlarmHandler) (void *);
@@ -20,4 +21,8 @@ struct OSiAlarm
OSTick start;
};
+void OS_CancelAlarm(OSAlarm *alarm);
+void OS_CreateAlarm(OSAlarm *alarm);
+void OS_SetAlarm(OSAlarm *alarm, OSTick tick, OSAlarmHandler handler, void *arg);
+
#endif //POKEDIAMOND_OS_ALARM_H
diff --git a/arm9/lib/include/OS_arena.h b/arm9/lib/include/OS_arena.h
index 7608835a..a26cf3bd 100644
--- a/arm9/lib/include/OS_arena.h
+++ b/arm9/lib/include/OS_arena.h
@@ -1,27 +1,8 @@
-#ifndef POKEDIAMOND_OS_ARENA_H
-#define POKEDIAMOND_OS_ARENA_H
+#ifndef POKEDIAMOND_ARM9_OS_ARENA_H
+#define POKEDIAMOND_ARM9_OS_ARENA_H
#include "nitro/types.h"
-
-typedef enum {
- OS_ARENA_MAIN = 0,
- OS_ARENA_MAIN_SUBPRIV = 1,
- OS_ARENA_MAINEX = 2,
- OS_ARENA_ITCM = 3,
- OS_ARENA_DTCM = 4,
- OS_ARENA_SHARED = 5,
- OS_ARENA_WRAM_MAIN = 6,
- OS_ARENA_WRAM_SUB = 7,
- OS_ARENA_WRAM_SUBPRIV = 8,
- OS_ARENA_MAX = 9
-} OSArenaId;
-
-typedef struct {
- void* lo[OS_ARENA_MAX];
- void* hi[OS_ARENA_MAX];
- u16 initialized;
- u8 padding[2];
-} OSArenaInfo;
+#include "nitro/OS_arena_shared.h"
void OS_InitArena(void);
void OS_InitArenaEx(void);
@@ -34,4 +15,4 @@ void OS_SetArenaLo(OSArenaId id, void *newLo);
void* OS_AllocFromArenaLo(OSArenaId id, u32 size, u32 align);
void* OS_AllocFromArenaHi(OSArenaId id, u32 size, u32 align);
-#endif //POKEDIAMOND_OS_ARENA_H
+#endif //POKEDIAMOND_ARM9_OS_ARENA_H
diff --git a/arm9/lib/include/OS_context.h b/arm9/lib/include/OS_context.h
index cded1acb..7a58a2b1 100644
--- a/arm9/lib/include/OS_context.h
+++ b/arm9/lib/include/OS_context.h
@@ -15,4 +15,8 @@ typedef struct OSContext
CPContext cp_context;
} 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_OS_CONTEXT_H
diff --git a/arm9/lib/include/OS_mutex.h b/arm9/lib/include/OS_mutex.h
index a2cdff23..0fc261a4 100644
--- a/arm9/lib/include/OS_mutex.h
+++ b/arm9/lib/include/OS_mutex.h
@@ -11,4 +11,6 @@ struct OSMutex {
OSMutexLink link;
};
+void OSi_UnlockAllMutex(OSThread * thread);
+
#endif //POKEDIAMOND_OS_MUTEX_H
diff --git a/arm9/lib/include/OS_reset.h b/arm9/lib/include/OS_reset.h
index fd918370..cb7680d1 100644
--- a/arm9/lib/include/OS_reset.h
+++ b/arm9/lib/include/OS_reset.h
@@ -16,10 +16,11 @@ void OS_InitReset(void);
static void OSi_CommonCallback(PXIFifoTag tag, u32 data, BOOL err);
static void OSi_SendToPxi(u16 data);
void OS_ResetSystem(u32 parameter);
+static void OSi_DoResetSystem(void);
void OSi_DoBoot(void);
static void OSi_CpuClear32(register u32 data, register void *destp, register u32 size);
-void OSi_ReloadRomData(void);
-void OSi_ReadCardRom32(u32 src, void *dst, s32 len);
+static void OSi_ReloadRomData(void);
+static void OSi_ReadCardRom32(u32 src, void *dst, s32 len);
static inline u32 OS_GetResetParameter(void)
{
diff --git a/arm9/lib/include/OS_thread.h b/arm9/lib/include/OS_thread.h
index bf62e66b..a80a3b96 100644
--- a/arm9/lib/include/OS_thread.h
+++ b/arm9/lib/include/OS_thread.h
@@ -52,6 +52,8 @@ typedef enum {
OS_THREAD_STATE_TERMINATED = 2
} OSThreadState;
+typedef void (*OSSwitchThreadCallback) (OSThread *from, OSThread *to);
+
typedef void (*OSThreadDestructor) (void *);
struct _OSThread
@@ -83,14 +85,67 @@ struct _OSThread
u32 systemErrno;
};
+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);
+void OS_InitThread(void);
+BOOL OS_IsThreadAvailable(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_DestroyThread(OSThread *thread);
+static void OSi_CancelThreadAlarmForSleep(OSThread *thread);
+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);
+void OS_YieldThread(void);
+BOOL OS_SetThreadPriority(OSThread *thread, u32 prio);
+u32 OS_GetThreadPriority(const OSThread *thread);
+void OS_Sleep(u32 msec);
+static void OSi_SleepAlarmCallback(void *arg);
+OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback);
+static void OSi_IdleThreadProc(void *);
+u32 OS_DisableScheduler(void);
+u32 OS_EnableScheduler(void);
+void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor);
+
extern OSThreadInfo OSi_ThreadInfo;
-void OS_SleepThread(OSThreadQueue * queue);
-void OS_WakeupThread(OSThreadQueue * queue);
+static inline OSThreadInfo *OS_GetThreadInfo(void)
+{
+ return &OSi_ThreadInfo;
+}
+
+static inline BOOL OS_IsThreadRunnable(const OSThread *thread)
+{
+ return thread->state == OS_THREAD_STATE_READY;
+}
static inline void OS_InitThreadQueue(OSThreadQueue * queue)
{
queue->head = queue->tail = NULL;
}
+static inline OSThread *OS_GetCurrentThread(void)
+{
+ return OS_GetThreadInfo()->current;
+}
+
+static inline void OS_SetCurrentThread(OSThread *thread)
+{
+ OS_GetThreadInfo()->current = thread;
+}
+
+#define OSi_GetCurrentThread() (*OSi_CurrentThreadPtr)
+
#endif //POKEDIAMOND_OS_THREAD_H
diff --git a/arm9/lib/include/OS_tick.h b/arm9/lib/include/OS_tick.h
index fb4ce7e6..f1c7145d 100644
--- a/arm9/lib/include/OS_tick.h
+++ b/arm9/lib/include/OS_tick.h
@@ -1,8 +1,12 @@
#ifndef POKEDIAMOND_OS_TICK_H
#define POKEDIAMOND_OS_TICK_H
-#include "nitro/types.h"
+#include "consts.h"
typedef u64 OSTick;
+#define OS_SYSTEM_CLOCK HW_SYSTEM_CLOCK
+
+#define OS_MilliSecondsToTicks(msec) ((OSTick)(((OS_SYSTEM_CLOCK/1000) * (u64)(msec)) / 64))
+
#endif //POKEDIAMOND_OS_TICK_H
diff --git a/arm9/lib/include/consts.h b/arm9/lib/include/consts.h
index 6c83bce8..c09e8cd9 100644
--- a/arm9/lib/include/consts.h
+++ b/arm9/lib/include/consts.h
@@ -27,6 +27,8 @@
#define HW_C6_PR_2GB 0x3c
#define HW_C6_PR_4GB 0x3e
+#define HW_SYSTEM_CLOCK 33514000
+
#define PXI_PROC_ARM7 0x01
#define OSi_CONSOLE_NOT_DETECT 0xffffffff
@@ -36,9 +38,14 @@
#define OS_CONSOLE_SIZE_MASK 0x00000003
#define OS_CONSOLE_SIZE_4MB 0x00000001
+#define OS_THREAD_LAUNCHER_PRIORITY 0x10
+#define OS_THREAD_PRIORITY_MIN 0x00
+#define OS_THREAD_PRIORITY_MAX 0x1F
+
+#define OS_THREAD_SPECIFIC_MAX 0x03
+
#define OSi_TCM_REGION_BASE_MASK 0xfffff000
-#define OSi_GetArenaInfo() (*(OSArenaInfo*)HW_ARENA_INFO_BUF)
#define OSi_TRUNC(n, a) (((u32) (n)) & ~((a) - 1))
#define OSi_ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1))
diff --git a/arm9/lib/include/mmap.h b/arm9/lib/include/mmap.h
index 8f9d8dcd..d0e73aec 100644
--- a/arm9/lib/include/mmap.h
+++ b/arm9/lib/include/mmap.h
@@ -1,15 +1,12 @@
-#ifndef NITRO_MMAP_H
-#define NITRO_MMAP_H
+#ifndef POKEDIAMOND_ARM9_MMAP_H
+#define POKEDIAMOND_ARM9_MMAP_H
#include "nitro/types.h"
+#include "nitro/mmap_shared.h"
extern u32 SDK_AUTOLOAD_DTCM_START[];
-#define HW_MAIN_MEM 0x02000000
-#define HW_MAIN_MEM_SIZE 0x00400000
#define HW_MAIN_MEM_EX_SIZE 0x00800000
-#define HW_MAIN_MEM_MAIN_SIZE 0x003E0000
-#define HW_MAIN_MEM_SHARED_SIZE 0x00001000
#define HW_MAIN_MEM_DEBUGGER_OFFSET 0x00700000
#define HW_ITCM_IMAGE 0x01000000
@@ -31,11 +28,9 @@ extern u32 SDK_AUTOLOAD_DTCM_START[];
#define HW_RESET_PARAMETER_BUF (HW_MAIN_MEM + 0x007ffc20)
#define HW_ROM_BASE_OFFSET_BUF (HW_MAIN_MEM + 0x007ffc2c)
#define HW_WM_BOOT_BUF (HW_MAIN_MEM + 0x007ffc40)
-#define HW_ARENA_INFO_BUF (HW_MAIN_MEM + 0x007ffda0) // Arena data structure
#define HW_ROM_HEADER_BUF (HW_MAIN_MEM + 0x007ffe00) // ROM registration area data buffer
#define HW_RED_RESERVED (HW_MAIN_MEM + 0x007ff800) // Some kind of reserved data for shared memory
#define HW_MAIN_MEM_SYSTEM (HW_MAIN_MEM + 0x007ffc00)
-#define HW_MAIN_MEM_MAIN_END (HW_MAIN_MEM + HW_MAIN_MEM_MAIN_SIZE)
#define HW_MAIN_MEM_EX_END (HW_MAIN_MEM + HW_MAIN_MEM_EX_SIZE)
#define HW_MAIN_MEM_SHARED (HW_MAIN_MEM_EX_END - HW_MAIN_MEM_SHARED_SIZE)
#define HW_DTCM_SVC_STACK_END (HW_DTCM + 0x00003fc0)
@@ -115,4 +110,4 @@ typedef struct {
#define OS_GetSystemWork() ((OSSystemWork *)HW_MAIN_MEM_SYSTEM)
-#endif \ No newline at end of file
+#endif //POKEDIAMOND_ARM9_MMAP_H \ No newline at end of file
diff --git a/arm9/lib/src/OS_init.c b/arm9/lib/src/OS_init.c
index e1c7e63a..f919f521 100644
--- a/arm9/lib/src/OS_init.c
+++ b/arm9/lib/src/OS_init.c
@@ -10,7 +10,6 @@ extern void OS_InitException(void);
extern void MI_Init(void);
extern void OS_InitVAlarm(void);
extern void OSi_InitVramExclusive(void);
-extern void OS_InitThread(void);
extern void CTRDG_Init(void);
extern void CARD_Init(void);
extern void PM_Init(void);
diff --git a/arm9/lib/src/OS_reset.c b/arm9/lib/src/OS_reset.c
index b7bf5f0b..0857bf0b 100644
--- a/arm9/lib/src/OS_reset.c
+++ b/arm9/lib/src/OS_reset.c
@@ -23,7 +23,6 @@ extern void DC_StoreAll(void);
extern void DC_InvalidateAll(void);
extern void IC_InvalidateAll(void);
extern void DC_WaitWriteBufferEmpty(void);
-extern void OSi_DoResetSystem(void); //in itcm, should technically be in this file
ARM_FUNC void OS_InitReset(void) {
if (OSi_IsInitReset) {
@@ -64,10 +63,19 @@ ARM_FUNC void OS_ResetSystem(u32 parameter) {
(void)OS_ResetRequestIrqMask((u32)~0);
*(u32 *)HW_RESET_PARAMETER_BUF = parameter;
OSi_SendToPxi(OS_PXI_COMMAND_RESET);
- OSi_DoResetSystem(); //oh boy this is in itcm, that's gonna be fun to deal with Kappa
+ OSi_DoResetSystem();
}
#pragma section ITCM begin
+ARM_FUNC static void OSi_DoResetSystem(void)
+{
+ while (!OSi_IsResetOccurred) { }
+
+ reg_OS_IME = 0;
+ OSi_ReloadRomData();
+ OSi_DoBoot();
+}
+
ARM_FUNC asm void OSi_DoBoot(void)
{
mov ip, #0x04000000
@@ -127,22 +135,7 @@ _01FF8284:
bx lr
}
-enum
-{
- CARD_MASTER_SELECT_ROM = 0x0,
- CARD_MASTER_ENABLE = 0x80,
- CARD_CMD_READ_PAGE = 0xb7,
- CARD_CTRL_CMD_MASK = 0x07000000,
- CARD_CTRL_CMD_PAGE = 0x01000000,
- CARD_CTRL_READ = 0x00000000,
- CARD_CTRL_RESET_HI = 0x20000000,
- CARD_CTRL_START = 0x80000000,
- CARD_CTRL_READY = 0x00800000,
- CARD_ENUM_END
-};
-
-
-ARM_FUNC void OSi_ReloadRomData(void)
+ARM_FUNC static void OSi_ReloadRomData(void)
{
u32 header = (u32)HW_ROM_HEADER_BUF;
const u32 rom_base = *(u32 *)HW_ROM_BASE_OFFSET_BUF;
@@ -182,7 +175,21 @@ ARM_FUNC void OSi_ReloadRomData(void)
OSi_ReadCardRom32(src_arm7, (void *)dst_arm7, (s32)len_arm7);
}
-ARM_FUNC void OSi_ReadCardRom32(u32 src, void *dst, s32 len) //should be static, can't mark as such
+enum
+{
+ CARD_MASTER_SELECT_ROM = 0x0,
+ CARD_MASTER_ENABLE = 0x80,
+ CARD_CMD_READ_PAGE = 0xb7,
+ CARD_CTRL_CMD_MASK = 0x07000000,
+ CARD_CTRL_CMD_PAGE = 0x01000000,
+ CARD_CTRL_READ = 0x00000000,
+ CARD_CTRL_RESET_HI = 0x20000000,
+ CARD_CTRL_START = 0x80000000,
+ CARD_CTRL_READY = 0x00800000,
+ CARD_ENUM_END
+};
+
+ARM_FUNC static void OSi_ReadCardRom32(u32 src, void *dst, s32 len)
{
vu32 *const hdr_GAME_BUF = (vu32 *)(HW_ROM_HEADER_BUF + 0x60);
diff --git a/arm9/lib/src/OS_thread.c b/arm9/lib/src/OS_thread.c
new file mode 100644
index 00000000..2ecde69a
--- /dev/null
+++ b/arm9/lib/src/OS_thread.c
@@ -0,0 +1,720 @@
+#include "function_target.h"
+#include "MI_memory.h"
+#include "OS_thread.h"
+#include "OS_mutex.h"
+#include "OS_alarm.h"
+#include "OS_system.h"
+#include "OS_context.h"
+#include "OS_terminate_proc.h"
+#include "consts.h"
+
+extern void SDK_SYS_STACKSIZE(void);
+extern void SDK_IRQ_STACKSIZE(void);
+
+extern void SDK_SECTION_ARENA_DTCM_START(void);
+
+static s32 OSi_ThreadIdCount = 0;
+
+u32 OSi_RescheduleCount = 0;
+
+void *OSi_StackForDestructor = NULL;
+
+BOOL OSi_IsThreadInitialized = FALSE;
+
+OSThreadInfo OSi_ThreadInfo;
+
+OSThread **OSi_CurrentThreadPtr = NULL;
+
+void *OSi_SystemCallbackInSwitchThread = NULL;
+
+OSThread OSi_LauncherThread;
+OSThread OSi_IdleThread;
+
+u32 OSi_IdleThreadStack[50];
+
+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(&currentThread->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)SDK_SECTION_ARENA_DTCM_START - (s32)SDK_SYS_STACKSIZE) :
+ (void *)((u32)(HW_DTCM_SVC_STACK - (s32)SDK_IRQ_STACKSIZE) - (s32)SDK_SYS_STACKSIZE);
+
+ OSi_LauncherThread.stackBottom = (u32)(HW_DTCM_SVC_STACK - (s32)SDK_IRQ_STACKSIZE);
+ OSi_LauncherThread.stackTop = (u32)stackLo;
+ OSi_LauncherThread.stackWarningOffset = 0;
+
+ //checksums
+ *(u32 *)(OSi_LauncherThread.stackBottom - sizeof(u32)) = 0xfddb597dUL;
+ *(u32 *)OSi_LauncherThread.stackTop = 0x7bf9dd5bUL;
+
+ OS_InitThreadQueue(&OSi_LauncherThread.joinQueue);
+
+ OSi_ThreadInfo.isNeedRescheduling = FALSE;
+ OSi_ThreadInfo.irqDepth = 0;
+
+ OS_GetSystemWork()->threadinfo_mainp = &OSi_ThreadInfo;
+
+ (void)OS_SetSwitchThreadCallback(NULL);
+
+ OS_CreateThread(&OSi_IdleThread, OSi_IdleThreadProc, NULL,
+ OSi_IdleThreadStack + 50, 200, OS_THREAD_PRIORITY_MAX);
+
+ OSi_IdleThread.priority = OS_THREAD_PRIORITY_MAX + 1;
+ OSi_IdleThread.state = OS_THREAD_STATE_READY;
+}
+
+ARM_FUNC asm BOOL OS_IsThreadAvailable(void)
+{
+ ldr r0, =OSi_IsThreadInitialized
+ ldr r0, [r0, #0]
+ bx lr
+}
+
+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)) = 0xfddb597dUL;
+ *(u32 *)thread->stackTop = 0x7bf9dd5bUL;
+
+ 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(&currentThread->joinQueue);
+
+ (void)OS_EnableScheduler();
+
+ OS_RescheduleThread();
+
+ OS_Terminate();
+}
+
+ARM_FUNC void OS_DestroyThread(OSThread *thread)
+{
+ OSIntrMode enabled = OS_DisableInterrupts();
+
+ if (OS_GetCurrentThread() == thread)
+ {
+ OSi_ExitThread_Destroy();
+ }
+
+ (void)OS_DisableScheduler();
+
+ OSi_UnlockAllMutex(thread);
+
+ OSi_CancelThreadAlarmForSleep(thread);
+
+ if (thread->queue)
+ {
+ (void)OSi_RemoveSpecifiedLinkFromQueue(thread->queue, thread);
+ }
+
+ OSi_RemoveThreadFromList(thread);
+
+ thread->state = OS_THREAD_STATE_TERMINATED;
+
+ OS_WakeupThread(&thread->joinQueue);
+
+ (void)OS_EnableScheduler();
+ (void)OS_RestoreInterrupts(enabled);
+
+ OS_RescheduleThread();
+}
+
+ARM_FUNC static void OSi_CancelThreadAlarmForSleep(OSThread *thread)
+{
+ OSAlarm *alarm = thread->alarmForSleep;
+
+ if (alarm)
+ {
+ OS_CancelAlarm(alarm);
+ }
+}
+
+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 void OS_YieldThread(void)
+{
+ OSThread *current = OS_GetCurrentThread();
+ OSThread *pre = NULL;
+ OSThread *lastThread = NULL;
+ s32 samePriorityThread = 0;
+ OSIntrMode enabled = OS_DisableInterrupts();
+
+ OSThread *t = OSi_ThreadInfo.list;
+ OSThread *tPre = NULL;
+
+ while (t)
+ {
+ if (t == current)
+ {
+ pre = tPre;
+ }
+
+ if (current->priority == t->priority)
+ {
+ lastThread = t;
+ samePriorityThread++;
+ }
+
+ tPre = t;
+ t = t->next;
+ }
+
+ if (samePriorityThread <= 1 || lastThread == current)
+ {
+ (void)OS_RestoreInterrupts(enabled);
+ return;
+ }
+
+ if (!pre)
+ {
+ OSi_ThreadInfo.list = current->next;
+ }
+ else
+ {
+ pre->next = current->next;
+ }
+
+ current->next = lastThread->next;
+ lastThread->next = current;
+
+ 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 u32 OS_GetThreadPriority(const OSThread *thread)
+{
+ return thread->priority;
+}
+
+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 static void OSi_IdleThreadProc(void *)
+{
+ (void)OS_EnableInterrupts();
+ while (1)
+ {
+ OS_Halt();
+ }
+}
+
+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;
+}