/*****************************************************************************/
/* リアルタイム・マルチタスクカーネル 「ai-TRON」*/
/* Copyright (C) 2000-2001 by 今井彰彦 */
/*****************************************************************************/
/* 内部構造 */
/* 内部関数は全て_で始まる（ユーザー関数と重複しないため）*/
/* volatileが付くのは_DecWaitCount()または_ExecCyc()で変化する変数のみ */

#ifndef	__ROSCALL__
#define __ROSCALL__	1

/*****************************************************************************/
/* タスク制御構造体 */
/*****************************************************************************/
/* カーネル内部でのタスク制御用構造体 */
/* メモリー効率を上げたい時には、アセンブラーから参照されないメンバーを
　ビットフィールドを使って そのＣＰＵの扱いやすい大きさに納めても良い。
　ただしその時は次のことを覚悟しなければならない。
	プログラムが大きくなる
	速度が落ちる
*/
typedef struct {
		/* 以下３つはアセンブラルーチンから参照 */
		/* 変更時はros*.macを参照のこと */
		FP	exec;		/* （次回）実行アドレス */
#ifdef	__7900__
_far		/* 7900ではスタックはfarで扱う */
#endif
		STACK	*stack;		/* 現在のスタックポインタ */
volatile	ER	ret;		/* このタスクへのシステムコールのリターン値 */
		/* 以下はＣだけで参照 */
volatile	TMO	wait;		/* !=0xf???:時間待ち状態の（残り）待り時間 */
					/* ==0xf???:特殊 */
					/* ==0:あらゆる待ちなし */
volatile	STAT	status;		/* タスク状態:DORMANT/READY/RUN/WAIT/SUSPEND/WAIT-SUSPEND */
		PRI	pri;		/* 現在の優先順位（実行中の優先順位は変更可能）*/
		/* 以下初期のみ設定される項目 */
		FP	exec0;		/* 初期実行アドレス */
		STACK	*stack0;	/* 初期スタックポインタ */
		PRI	pri0;		/* 初期の優先順位（小さい程高）*/
		/* 以下設定によって追加される内容 */
		#if ROS_TSK_WUP_TSK == ROS_ON
		WUPCNT	wupcnt;		/* wup_tsk()キューイングカウント */
		#endif
		#if ROS_TSK_SUS_TSK == ROS_ON
		SUSCNT	suscnt;		/* sus_tsk()キューイングカウント */
		#endif
		#if ROS_TMB_ALL	== ROS_ON
		T_MSG	*tmb;		/* タスク付属メイルボックスリンク先頭アドレス */
		T_MSG	**rcv;		/* rcv_tmb()が返すメイル構造体アドレス変数のアドレス */
		#endif
} TCB;	/* Task Control Block */

/*
・idは_tasks[]の要素番号。必ず0〜_MaxTask-1で連続する。
・この構造体によって管理されるのはユーザータスクのみであり、割り込みタスクは入らない。
  ということは、割り込みタスクの数はシステム上は無制限と言うことになる。
*/
/*****************************************************************************/
/* 周期起動制御構造体 */
/*****************************************************************************/

typedef struct {	/* 周期起動制御構造体 */
		CFP	func;	/* 実行アドレス */
				/* NADRなら定義解除 */
		ATR	act;	/* 実行状態 */
		RELTIM	tim;	/* 周期起動時間 */
				/* task.waitと違って、こちらは連続発行では逃げられないので */
				/* RELTIM分取っておく */
volatile	RELTIM	cnt;	/* 周期起動時間残り時間：tim→0 */
} CYC;

/*****************************************************************************/
/* グローバル変数 */
/*****************************************************************************/
/* スタック:rosstk.h */

extern	STACK	_AllStack_[];		/* 全スタック本体 */
extern	STACK	*_TimStack;		/* 同ポインタ */
extern	STACK	*_SysStack;		/* システムスタックポインタ */
#if ROS_CYC_ALL	== ROS_ON
extern	STACK	*_CycStack;		/* 同ポインタ */
#endif
extern	STACK	*_UsrStack;		/* ユーザースタックポインタ(cre_tskで変化) */
extern	STACK	*_UsrStack0;		/* 初期ユーザースタックポインタ */

/*---------------------------------------------------------------------------*/
/* カーネル:ros.c */

extern	TCB	_tasks[];	/* タスク制御構造体 */
extern	TID	_MaxTask;	/* 登録中タスク数 */
extern	TCB	*_MyTsk;	/* 実行中タスク制御構造体アドレス */
extern	TID	_MyID;		/* 実行中タスクID */

#if ROS_TSK_VWAI_TSK == ROS_ON
extern	volatile TMO _vwai_cnt;		/* vwai_tsk()での待時間 */
#endif
extern	MODE	_fdispatch;	/* ディスパッチするかどうか */

#if ROS_SYS_CHK_DSP == ROS_ON || ROS_SYS_CHK_DSP == ROS_ON
extern	DSPCNT	_req_cnt;	/* vreq_dsp()の要求回数 */
#endif

#if ROS_SYS_EXT_ROS == ROS_ON
#include <setjmp.h>
/* vext_ros()でROS()を抜けるための情報を記録する構造体 */
extern	jmp_buf _ext_ros_jbuf;
#endif

/*---------------------------------------------------------------------------*/
/* 起動キュー:rdyque.c */

extern	TID	_Que[];	/* タスク起動キュー */

/*---------------------------------------------------------------------------*/
/* 周期起動:cyc.c */

#if ROS_CYC_ALL	== ROS_ON
extern	CYC	_cyctsk[];	/* 周期起動制御構造体 */
#endif

/*---------------------------------------------------------------------------*/
/* １ビットイベントフラグ:flag.c */

extern	EVENTFLG	_BitEventFlag;
extern	TID		_WaitBitEventFlag[];

/*---------------------------------------------------------------------------*/
/* セマフォ:sema.c */

extern	SEMA	_Semaphore[];		/* セマフォ本体 */
extern	TID	_WaitSemaphore[];	/* ここに入っているのはタスク番号そのもの */

/*****************************************************************************/
/* システム定数 */
/*****************************************************************************/
/* 起動キュー */

#define	EOQ	NO_TSK		/* タスク起動キューリストの最後を示す */
				/* kernelでも参照しているので注意 */
/*---------------------------------------------------------------------------*/
/* 全体 */

/* 待ち時間の特殊値 */
/* 以下のものは、wai_tsk()ではない。
　 下位８ビットが待ちリストでの次タスク番号を示している。
　 待ちは自タスクのみであり、従って、複数の待ちが同時に起こることはない。
　 だから、ワークエリアの共用が出来る（省メモリ）。 */
#define	TMO_TID		0x00ff		/* .waitからタスクIDを取り出すための&値 */
#define	TMO_WAI_FLG	0xf000		/* 現在.waitは(c)wai_flg()リストで使用中 */
#define	TMO_WAI_TMB	0xf200		/* 現在メイル待ち中(.wait下位８ビットは未使用) */
#define	TMO_WAI_SEM	0xf300		/* 現在.waitはセマフォ待ちリストで使用中 */

#define	TMO_INI_START	0xff00		/* タスクの一番最初の起動の印（sta_tsk()直後の起動待ち時）*/
					/* kernelでも参照しているので変更時は注意 */
/*---------------------------------------------------------------------------*/
/* タスク管理・タスク付属同期 */

#define	MD_RSM_TSK	0	/* rsm_tsk()である */
#define	MD_FRSM_TSK	1	/* frsm_tsk()である */

/*---------------------------------------------------------------------------*/
/* １ビットイベントフラグ */

#define	MD_WAI_FLG	0	/* wai_flg()で待ち */
#define	MD_CWAI_FLG	BIT7	/* cwai_flg()で待ち */
				/* これらを.wait&TMO_TIDのbit7に入れて識別する */
				/* _WaitBitEventFlag[]はTIDなのでそれで納めるため */
#define	GET_WAI_TID	0x7f	/* タスク番号のみを取り出すため */
#define	EOFlag		(TMO_WAI_FLG|NO_TSK)	/* End Of Flag */
				/* _WaitBitEventFlag[]はTIDなのでNO_TSKのみが入る */
/*---------------------------------------------------------------------------*/
/* タスク付属メイル */

#define	MD_RCV_TMB	0	/* rcv_tmb()でメイルを受信する */
#define	MD_PRCV_TMB	1	/* prcv_tmb()でメイルを受信する */

/*---------------------------------------------------------------------------*/
/* セマフォ */

#define	EOSem	(TMO_WAI_SEM|NO_TSK)	/* End Of Semaphore */

/*****************************************************************************/
/* システムコール番号（１６ビット）*/
/*****************************************************************************/
/* 番号が存在しないタスクは_SystemCallでは処理されない＝タスク切り替えがない */
/* 0x00は定義してはいけない（longjmp()のretval(!=0)にするかもしれないから） */
/* このコードはμITRON4.0の機能コードとは異なる */

/* 上位８ビットは状態定義 */
#define	INT_FLG		BIT15	/* 割り込みモードの印（i*()）*/
				/* この時は一部のシステムコールに制約が付く */
				/* これは割り込みタスク内であるかの状態を示すものではない */
				/* kernelでも参照する */
#define	USE_ID		BIT14	/* 第１引数としてidを取るの印 */
/* 以下３つUSE_IDがある時のみ有効 */
#define	DMT_OK		BIT13	/* DORMANT状態も受付可能の印 */
#define	SELF_OK		BIT12	/* tid=_MyIDも受付可能の印 */
#define	ISELF_OK	BIT11	/* INT_FLG時のみtid=_MyIDも受付可能の印 */
/**/
#define	SELF_WAIT	BIT8	/* 自タスク待ち系システムコール */

/* 下位８ビットは機能番号 */
/* ただし、INT_FLG=1のときは同じ関数の割り込み型になる。*/
/* その違いは、以下の通り。
	待ち系システムコールが不可になる
	自己タスク指定が出来なくなる
	タスク切り換えがなくなる
*/
/* タスク管理 */
#define	STA_TSK		(0x03|USE_ID|DMT_OK)
#define	EXT_TSK		(0x04)			/* kernelでも参照している */
#define	TER_TSK		(0x05|USE_ID)
#define	CHG_PRI		(0x06|USE_ID|SELF_OK)
#define	ROT_RDQ		(0x07)
#define	REL_WAI		(0x08|USE_ID|SELF_OK)
/* タスク間同期 */
#define	SUS_TSK		(0x10|USE_ID|SELF_OK)	/* SELF_OKはμITRON4の機能 */
#define	RSM_TSK		(0x11|USE_ID)
#define	FRSM_TSK	(0x12|USE_ID|ISELF_OK)
#define	WAI_TSK		(0x13|SELF_WAIT)
#define	WUP_TSK		(0x14|USE_ID|SELF_OK)	/* SELF_OKはμITRON4の機能 */
/* １ビットイベントフラグ */
#define	SET_FLG		(0x20)
#define	CLR_FLG		(0x21)
#define	WAI_FLG		(0x22|SELF_WAIT)
#define	CWAI_FLG	(0x23|SELF_WAIT)
/* タスク付属メイルボックス */
#define	SND_TMB		(0x28|USE_ID|SELF_OK)
#define	RCV_TMB		(0x29|SELF_WAIT)
/* セマフォ */
#define	SIG_SEM		(0x30)
#define	WAI_SEM		(0x31|SELF_WAIT)
/* システム状態管理 */
#define	CHK_DSP		(0xF0)

/* 非常に簡単な処理でμITRON4に対応出来るものだけ入れている */
/* SUS_TSK/WUP_TSKはエラーチェックを外すだけでＯＫ */
/*****************************************************************************/
/* 内部関数プロトタイプ宣言 */

#ifdef	__cplusplus
extern	"C" {
#endif
/* デバッグ用 */
#if DEBUG >= 1
void	debug(char *str,...);
void	check_sp(void);
void	sp_print(void);
void	sp_all(void);
void	DumpStack(void);
#endif
#if DEBUG >= 2
void	print_tcb(TID );
void	DumpQue(void);
void	DumpSemaphoreLink(void);
void	DumpEventFlagLink(void);
void	DumpMailLink(void);
#endif
#if DEBUG != 0
void InitDebug(int ,int ,int ,int 
	#if ROS_CYC_ALL	== ROS_ON
	,int 
	#endif
);
char	*ErrorName(ER );
void	DumpStackMain(void);
#ifdef __H8__
void	RSprint(char *);
#endif
#endif

/* 起動キュー制御関数 */
void		_InitQue(void);
ROS_BOOL	_DelIDQue(TID );
void		_SetIDQue(TID );
void		_RotateQue(PRI );

/* カーネル */
void		_SetStack(void);
void		_ROS(void);
volatile void	_TaskDispatcher(void);
ROS_BOOL	_DelWaitLink(TID,TID);
ER		_SyscallEnding(ER ,TCB *,TID ,FN);
ER		_SystemCallMain(FN ,va_list);
void		_TaskCheck(void);
int		_DispatchWorkSet(void);
void		_DecWaitCount(void);
#ifdef	__DOSV__
void		_SaveDataSegment(void);
#endif

/* 以下、２つはＣからは呼び出されない */
void	_TimerDecWaitCount(void);
#if ROS_CYC_ALL	== ROS_ON
void	_TimerExecCyc(void);
#endif

/* タスク制御 */
ER	_sta_tsk(TCB *);
ER	_chg_pri(TCB *,PRI );
ER	_rot_rdq(PRI );
ER	_rel_wai(TCB *,MODE);

/* タスク付属同期 */
#if ROS_TSK_SUS_TSK == ROS_ON
ER	_sus_tsk(TCB *);
#if ROS_TSK_RSM_TSK == ROS_ON
ER	_rsm_tsk(TCB *,MODE );
#endif
#endif
#if ROS_TSK_WUP_TSK == ROS_ON
ER	_wup_tsk(TCB *);
#endif

/* １ビットイベントフラグ */
#if ROS_FLG_ALL == ROS_ON
void	_InitEventFlag(void);
void	_DelEventFlagLink(TID );
ER	_set_flg(FID );
ER	_clr_flg(FID );
ER	_wai_flg(TCB *,FID ,MODE );
#endif

/* タスク付属メイル */
#if ROS_TMB_ALL == ROS_ON
void	_DelMailLink(TID);
ER	_snd_tmb(TCB *,T_MSG *,MODE);
ER	_rcv_tmb(TCB *,T_MSG **,MODE);
#endif

/* セマフォ */
#if ROS_SEM_ALL == ROS_ON
void	_InitSemaphore(SEMA );
void	_DelSemaphoreLink(TID);
ER	_sig_sem(SID ,TID *);
ER	_wai_sem(TCB *,SID );
#endif

/* 周期起動 */
#if ROS_CYC_ALL	== ROS_ON
void	_ExecCyc(void);
void	_InitCyc(void);
#endif

/* システム状態管理 */
#if ROS_SYS_CHK_DSP == ROS_ON
ER	_chk_dsp(void);
#endif

/* 割り込み基本関数 */
void	_DINT(void);
void	_EINT(void);
#ifdef	__cplusplus
}
#endif

/*****************************************************************************/

#endif	/* __ROSCALL__ */

/*****************************************************************************/
