/*
 *  TOPPERS/JSP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Just Standard Profile Kernel
 * 
 *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 *  Copyright (C) 2009 Akira Ujio
 *
 *  上記著作権者は，以下の (1)〜(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 * 
 *  @(#) $Id: cpu_config.c,v 1.8 2003/12/24 07:24:40 honda Exp $
 */

/*
 *	プロセッサ依存モジュール（iphone用）
 */

#include "jsp_kernel.h"
#include "check.h"
#include "task.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h> 
#include <unistd.h>

/*
*	ToppersのThread IDの保存用
*	このThread IDに対してSignalを生成する
*/
pthread_t thread_id;

/*
*	CPU Lock状態でのシグナルマスクを保存
*	sense_lock()で使用される
*/
IMS locked_ims=0;

/*
*	多重割り込み対応のために割り込みネストレベルを保存
*	多重割り込みされた割り込み処理ではdispatch処理を保留する
*/
static int nest_level = 0;

/*
*	割り込み処理のときにTRUEになる
*	sense_context() でContextか割り込みかを判断するのに使用する
*/
BOOL interrupt_flg = FALSE;


/*
*   ディスパッチ処理
*/
void
dispatch()
{
	if (	enadsp && (!runtsk || (runtsk != schedtsk
						&& setjmp(runtsk->tskctxb.env) == 0))) 
	{
		while (!(runtsk = schedtsk)) 
		{
				sigset_t waitmask;
				sigemptyset(&waitmask);
				sigsuspend(&waitmask);
			}
			longjmp(runtsk->tskctxb.env, 1);
	}
	else
		calltex();
}


/*
 *  現在のコンテキストを捨ててディスパッチ
 *
 *  exit_and_dispatch は，CPUロック状態で呼び出さなければならない．
 */
static void initial_create_tasks(TCB *);
void
exit_and_dispatch() 
{                   
	static BOOL bFirst = TRUE;
	
	if( bFirst )
	{
		/*
		*	初回のみタスクのスタックやコンテキストを生成する
		*/
		bFirst = FALSE;
		t_unlock_cpu();
		initial_create_tasks( &tcb_table[0] );
	}
    runtsk = 0;
	dispatch();
}



/*
 *  プロセッサ依存の初期化
 */


extern void kernel_start();

void
cpu_initialize()
{
	int i;
	TCB *tcb;
	
	/*
	*	TCBのスタックサイズを０に初期化する 
	*/
	for(i=0;i<TNUM_TSK;++i)
	{
		tcb = &tcb_table[i];
		tcb->tskctxb.stksize = 0;
	}
	
	/*
	*	CPU Lock状態にして、そのときのシグナルマスクを保存する
	*/
	t_lock_cpu();
	sigprocmask(SIG_SETMASK,0,&locked_ims); 
	
	/*
	*	ToppersのThread IDを保存する
	*/
	thread_id = pthread_self();

}

/*
 *  プロセッサ依存の終了処理
 */
void
cpu_terminate()
{
}

/*
 * タスク起動ルーチン
 *
 */



/*
*	タイマーを生成するスレッド
* iphone のSIGALRMはthread IDを指定しない限り、Cocoa(Main Thread)に食われてしまう。
* よって苦肉の策でSIGALRM用のThreadを生成し、ToppersJSP Threadに対して
* のみSIGALRMを発行する
*/
void
timer_polling(void)
{
	for(;;)
	{
		usleep(10000);
		pthread_kill( thread_id, SIGALRM);
	}
}

/*
*	Cocoa(Main Thread)からToppersJSPに対して割り込みを起こす
*/
void
itron_interrupt(int intno)
{
	pthread_kill( thread_id, intno);	
}

/*
*	Toppers JSP for iPhoneを起動する
*	Program Entry(main.mのmain()関数) の関数入り口で呼ぶこと
*	Toppers用のThreadが生成され、Cocoa(Main Thread)と切り離される
*/
void
jsp_for_iphone_start(void)
{	
	pthread_t t;
	
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	
//	struct sched_param priority;
//	priority.sched_priority = 50;
//	pthread_attr_setschedparam(&attr, &priority);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_create(&t, &attr, (void *)kernel_start, NULL);
	pthread_attr_destroy(&attr);
	//pthread_join(t, NULL);
}

/*
*	初回起動時、各タスクのスタックを確保する
*	cfg.exeで自動生成されるスタックはすべて無視され、新たにThreadスタックから確保される
*	最低MINSIGSTKSZ(32kB)は確保される。iPhone OSのThreadは512kBなので、
*	これを超えるスタックサイズが必要な場合はThread生成時にスタックサイズを指定する必要がある
*/
static void
initial_create_tasks(TCB *tcb)
{
	static int nTaskReady=1;
	
	/*
	*	スタックはJSP ThreadのStackから強制的に取得される
	*	生成後はsetjmpでスタックの状態が記憶される
	*/
	volatile int tsk_stack[MINSIGSTKSZ/sizeof(int)];
	tsk_stack[0] = 0;
	tcb->tskctxb.stksize += MINSIGSTKSZ;
	
	if( tcb->tskctxb.stksize < tcb->tinib->stksz )
	{
		/*
		*	まだスタックサイズが足りないときはもう一度
		*/
		initial_create_tasks( tcb );
	}
	
	if( setjmp( tcb->tskctxb.env) == 0 )
	{
		/*
		*	スタート状態のコンテキストを保存する
		*	タスク起動時はstart_envのコンテキストを使用することになる
		*/
		memcpy( &tcb->tskctxb.start_env, &tcb->tskctxb.env, sizeof(jmp_buf) );
		
		/*
		*	すべてのタスクに対してスタックを確保する
		*/
		if( nTaskReady < TNUM_TSK )
		{
			++nTaskReady;
			initial_create_tasks( &tcb_table[INDEX_TSK(nTaskReady)] );
		}
		
		/*
		*	ここの処理はすべてタスクのスタックをとり終えたときにくる
		*/
		
		/*
		*	はじめから起動するタスクがない場合はここで待つ
		*/
		while (!(runtsk = schedtsk)) {
			sigset_t waitmask;
			sigemptyset(&waitmask);
			sigsuspend(&waitmask);
		}
		
		/*
		*	一番最初のタスクにジャンプする
		*/
		longjmp( runtsk->tskctxb.env, 1);
	}
	else
	{
		/*
		*	タスクスタート。レッツゴー
		*/
		(*runtsk->tinib->task)(runtsk->tinib->exinf);
		
		ext_tsk();
	}
}

/*
*	割り込みの入り口処理
*	CPU Lockをした後、割り込みフラグをTRUEにしネストレベルを１上げる
*/
void prologue_isr(void)
{
	i_lock_cpu();
	interrupt_flg = TRUE;
	++nest_level;
	i_unlock_cpu();
}

/*
*	割り込み出口処理
*	CPU Lockをした後、ネストレベルを１下げる
*	もしネストレベルが０になったら（他の割り込み処理がない状態）要求に応じてdispatchをする
*/
void epilogue_isr(void)
{
	i_lock_cpu();
	--nest_level;
	if( nest_level == 0 )
	{
		interrupt_flg = FALSE;
		if(_kernel_reqflg)
		{
			_kernel_reqflg=FALSE;
			dispatch();
		}
	}
	i_unlock_cpu();
}




