
#include <ultra64.h>

#include "def.h"
#include "message.h"

#include "main.h"
#include "util.h"
#include "dmacopy.h"
#include "code_entry.h"

u64 bootStack[STACKSIZE/sizeof(u64)];

static void idle(void *);

// ｽﾚｯﾄﾞ構造体の定義
static OSThread idleThread;
static OSThread mainThread;

// ｽﾚｯﾄﾞｽﾀｯｸの定義
static u64 idleThreadStack[STACKSIZE/sizeof(u64)];
static u64 mainThreadStack[STACKSIZE/sizeof(u64)];

// ｱｲﾄﾞﾙﾌｧﾝｸ
static void defaultIdleFunc() {}
static void (*idleFunc)() = defaultIdleFunc;

// ｾｸﾞﾒﾝﾄを参照
MSegDecl(boot)
MSegDecl(code)
MSegDecl(code_entry)

//------------------------------------ メインスレッドを停止
void stopMainThread()
{
	osStopThread(&mainThread);
}

//------------------------------------ ｱｲﾄﾞﾙﾌｧﾝｸｦｾｯﾃｲ
void setIdleFunc(void *func)
{
	idleFunc = (void (*)())func;
}

//------------------------------------ ﾌﾞｰﾄ
void boot(void)
{
	// osｲﾆｼｬﾗｲｽﾞ,
	osInitialize();

	// idleｽﾚｯﾄﾞ作成とｽﾀｰﾄ
	osCreateThread(&idleThread,IDLE_THREAD_ID, idle, (void *)0, (idleThreadStack+STACKSIZE/sizeof(u64)), IDLE_THREAD_PRI);
	osStartThread(&idleThread);
}

//------------------------------------ ﾌﾞｰﾄ2
static void boot2(void *arg)
{
	CODE_ENTRY *entry = (CODE_ENTRY *)_bootSegmentEnd;

	auRomDataRead((u32)_code_entrySegmentRomStart, entry,
		(u32)_code_entrySegmentRomEnd - (u32)_code_entrySegmentRomStart);

	ExpandGZip(_codeSegmentRomStart, entry->start,
		(u32)_codeSegmentRomEnd - (u32)_codeSegmentRomStart);

	bzero(entry->bssStart, (u32)entry->bssEnd - (u32)entry->bssStart);

	entry->entry(arg);
}

//-------------------------------- ｱｲﾄﾞﾘﾝｸﾞ
static void idle(void *arg)
{
	// piﾏﾈｰｼﾞｬの起動
	osCreatePiManager((OSPri)OS_PRIORITY_PIMGR, &PiMessageQ, PiMessages, NUM_PI_MSGS);

#ifdef USE_USB
        {
            int i;
            osUsbInit();
            for (i=0; i<10000000; i++);
        }
#endif

	// ﾒｲﾝﾌﾚｰﾑの起動
	osCreateThread(&mainThread, MAIN_THREAD_ID, boot2, arg,
		(mainThreadStack + STACKSIZE / sizeof(u64)), MAIN_THREAD_PRI);
	osStartThread(&mainThread);

	// ｱｲﾄﾞﾘﾝｸﾞﾙｰﾌﾟ( ｱｲﾄﾞﾙｽﾚｯﾄﾞはﾌﾟﾗｲｵﾘﾃｨが低いので各ﾌﾚｰﾑの終了後このﾙｰﾌﾟを使用しているｹｰｽが多い )
	for(;;) {
		idleFunc();
	}
}
