www.pudn.com > norti2.0 > NOKNL.C


/****************************************************************************** 
* μITRON仕様OS NORTiカーネル                                     * 
*                                                                             * 
*  File name : noknl.c                                                        * 
*  Copyright (c) Miyazaki System Planning Office. 1991-1995                   * 
*                                                                             * 
* 91-10-25 TRCOM Version                                                      * 
* 92-02-16 Ver1.00                                                            * 
* 92-08-20 Ver1.10                                                            * 
* 93-01-18 Ver1.11                                                            * 
* 93-02-17 Ver1.12                                                            * 
* 93-05-16 Ver1.13β                                                          * 
* 94-01-05 Ver1.14                                                            * 
* 95-06-15 Ver1.20                                                            * 
* 95-09-12 Ver1.21                                                            * 
******************************************************************************/ 
 
#define NOKNL_C 
#include "norti.h" 
#include "nosys.h" 
 
/* コンパイルスイッチ */ 
 
#ifdef	ALL						/* 全てコンパイル */ 
#define	STA_TSK 
#define	CRE_TSK 
#define	XCRE_TSK 
#define	EXT_TSK 
#define	TER_TSK 
#define	CHG_PRI 
#define	ROT_RDQ 
#define	REL_WAI 
#define	GET_TID 
#define	VGET_TID 
#define	TSK_STS 
#define	SUS_TSK 
#define	RSM_TSK 
#define	FRSM_TSK 
#define	SLP_TSK 
#define	WAI_TSK 
#define	CAN_WUP 
#define	VCAN_WUP 
#define	SET_WFLG 
#define	CLR_WFLG 
#define	WAI_WFLG 
#define	POL_WFLG 
#define	FLG_STS 
#define	SET_FLG 
#define	CLR_FLG 
#define	WAI_FLG 
#define	CWAI_FLG 
#define	POL_FLG 
#define	CPOL_FLG 
#define	SIG_SEM 
#define	WAI_SEM 
#define	PREQ_SEM 
#define	SEM_STS 
#define	SND_MSG 
#define	RCV_MSG 
#define	PRCV_MSG 
#define	MBX_STS 
#define	CHG_IMS 
#define	IMS_STS 
#define	GET_BLK 
#define	PGET_BLK 
#define	REL_BLK 
#define	MPL_STS 
#define	SET_TIM 
#define	GET_TIM 
#define	DEF_CYC 
#define	ACT_CYC 
#define	CYH_STS 
#define	DEF_ALM 
#define	ALH_STS 
#define	GET_VER 
#endif 
 
/* 静的エラーチェックのレベル */ 
 
#ifndef	ERC 
#define	ERC			1			/*(0:無し,1:有り,2:E_CTXもチェック)*/ 
#endif 
 
/* 多重割込み対応 */ 
 
#ifndef	NEST 
#if (defined(NORTi80)||defined(NORTiZ80)) 
#define	NEST		0			/* NORTi/80,Z80 は 割込みネスト無し */ 
#else 
#define	NEST		1			/* その他は 割込みネスト有り */ 
#endif 
#endif 
 
/* システムクロックのビット数(16,32,48)*/ 
 
#ifndef	CLKBITS 
#if (defined(NORTi80)||defined(NORTiZ80)) 
#define	CLKBITS		16			/* NORTi/80,Z80 は 16 ビット */ 
#else 
#define	CLKBITS		48			/* その他は 48 ビット */ 
#endif 
#endif 
 
/* 処理系の差異の調整 */ 
 
#ifdef	M_I86 
#pragma check_stack(off)		/* MS-C スタックチェックなし */ 
#endif 
 
#ifndef	_MSC_VER				/* MS-C 6.0, BORLAND-C 以外では */ 
#ifndef	__BORLANDC__ 
#define	_fastcall	/**/		/* _fastcall 指定を無効化 */ 
#endif 
#endif 
 
#ifdef	LSI_C80					/* LSIC-80 では */ 
#pragma optimize time			/* 実行速度重視 */ 
#define	noauto		static		/* auto にすると負担な変数を static にする */ 
#endif 
#ifndef	noauto					/* それ以外では */ 
#define	noauto		/**/		/* 同指定を無効化 */ 
#define	nonrec		/**/		/* 非再帰関数指定を無効化 */ 
#endif 
 
#ifndef	__TID__					/* ICC 以外では */ 
#define	C_task	 	/**/		/* C_task 無効化 */ 
#endif 
 
#ifndef	NULL 
#define	NULL		0			/* NULLポインタ */ 
#endif 
 
/* カーネル内部関数プロトタイプ */ 
 
ER NEAR dispatch(void); 
void NEAR _fastcall del_que(T_TCB NEAR *); 
void NEAR _fastcall add_que(T_RDQ NEAR *, T_TCB NEAR *); 
void NEAR _fastcall chg_que(T_RDQ NEAR *, T_TCB NEAR *); 
void NEAR _fastcall ins_reltim(T_TMR NEAR *); 
void NEAR _fastcall ins_abstim(T_TMR NEAR *); 
UINT NEAR _fastcall tst_wflg(UINT NEAR *, UINT, UINT); 
 
/* アセンブラのカーネル内部関数プロトタイプ */ 
 
ER NEAR ctxswitch(void);		/* コンテキスト切替え */ 
void NEAR init_ctx(T_CTX FAR *);/* タスク起動時のコンテキスト初期化 */ 
void NEAR set_imask(void);		/* システムコ−ル入口での割込マスク */ 
ER NEAR ret_imask(void);		/* システムコ−ル出口での割込マスク復元 */ 
void NEAR ope_imask(void);		/* タイマ処理中の割込マスク一時解除 */ 
 
#ifdef	LSI_C80					/* LSIC-80 では */ 
#include  
#define set_imask()	di()		/* set_imask() を直接 DI 命令で行う */ 
#endif 
 
#ifdef	__TID__ 
#pragma language=extended 
#if ((__TID__&0x7f00)==0x1700)	/* ICC Z80 でも同様 */ 
#include  
#define set_imask()	disable_interrupt() 
#endif 
#endif 
 
#if	!NEST						/* 割込みネスト無しなら */ 
#define ope_imask()	/**/		/* ope_imask() を行わない */ 
#endif 
 
/****************************************************************************** 
*                                                                             * 
*                                システム起動                                 * 
*                                                                             * 
******************************************************************************/ 
#ifdef	STA_TSK 
 
#ifdef	OLDVER 
INT near cdecl TSKCNT;			/* 起動されたタスク数(旧仕様)*/ 
#endif 
 
/****************************************/ 
/* システム初期化                       */ 
/****************************************/ 
 
static void NEAR _fastcall memclr(void NEAR *p, UH n) 
{ 
	B NEAR *cp = (B NEAR *)p; 
 
	while (n-- != 0) 
		*cp++ = 0; 
} 
 
#if defined(NORTiPPC) 
void NEAR nonrec c_sysini(B *stktop, T_CTX *ctx) 
#elif defined(NORTi86) 
void NEAR c_sysini(int stktop, T_CTX ctx) 
#else 
void NEAR nonrec c_sysini(B *stktop, T_CTX ctx) 
#endif 
{ 
	T_TCB NEAR *tcb; 
	T_MPL NEAR *mpl; 
	T_TMR NEAR *tmr; 
	INT i; 
	B FAR *p; 
 
	/* スタックの初期設定 */ 
 
  #ifdef NORTiPPC 
	CTX = *ctx;							/* タスク起動用のコンテキスト保存 */ 
	p = (B FAR *)ctx; 
  #else 
	CTX = ctx;							/* タスク起動用のコンテキスト保存 */ 
	p = (B FAR *)&ctx; 
  #endif 
 
	p -= sizeof (T_CTX) * 4;			/* アイドルタスクのスタック確保 */ 
	ISP = p; 
	p -= istksz;						/* 割込みハンドラのスタック確保 */ 
	USP = p; 
  #ifdef NORTi86 
	STKLEN = (UH)((W)p) - stktop;		/* 残りのユーザスタックサイズ */ 
  #else 
	STKLEN = p - stktop;				/* 残りのユーザスタックサイズ */ 
  #endif 
 
	/* TCBの初期化 */ 
 
	tcb = &TCB[TSKID_MIN]; 
	for (i = TSKID_MIN; i <= tskid_max; i++, tcb++) 
		memclr(pTCB[i] = tcb, sizeof (T_TCB)); 
 
	/* イベントフラグの初期化 */ 
 
	for (i = FLGID_MIN; i <= flgid_max; i++) 
		memclr(&FLG[i], sizeof (T_FLG)); 
 
	/* セマフォの初期化 */ 
 
	for (i = SEMID_MIN; i <= semid_max; i++) 
		memclr(&SEM[i], sizeof (T_SEM)); 
 
	/* メイルボックスの初期化 */ 
 
	for (i = MBXID_MIN; i <= mbxid_max; i++) 
		memclr(&MBX[i], sizeof (T_MBX)); 
 
	/* メモリプールの初期化 */ 
 
	mpl = &MPL[MPLID_MIN]; 
	for (i = MPLID_MIN; i <= mplid_max; i++, mpl++) 
		memclr(pMPL[i] = mpl, sizeof (T_MPL)); 
 
	/* レディキューの初期化 */ 
 
	for (i = 0; i <= tpri_max + 1; i++) 
		memclr(&RDQ[i], sizeof (T_RDQ)); 
 
	/* タイマの初期化 */ 
 
	memclr(&SYSCLK, sizeof SYSCLK); 
	memclr(TMQ, sizeof TMQ); 
 
	tmr = &CYH[CYHNO_MIN]; 
	for (i = CYHNO_MIN; i <= cyhno_max; i++, tmr++) 
	{	memclr(pCYH[i] = tmr, sizeof (T_TMR)); 
		tmr->que = &SYSCLK; 
	} 
 
	tmr = &ALH[ALHNO_MIN]; 
	for (i = ALHNO_MIN; i <= alhno_max; i++, tmr++) 
	{	memclr(pALH[i] = tmr, sizeof (T_TMR)); 
		tmr->que = &SYSCLK; 
	} 
 
	/* sysstaまでディスパッチ禁止するため割込ネスト1 */ 
 
	INEST = -1; 
 
	/* その他変数の初期化 */ 
 
	DELAY = 0; 
	NOWPRI = 0; 
	SYSER = E_OK; 
	IDLE_LOOP_CNT = 0; 
  #ifdef OLDVER 
	TSKCNT = 0; 
  #endif 
} 
 
#endif 
#ifdef	STA_TSK 
/****************************************/ 
/* システム起動                         */ 
/****************************************/ 
 
ER FAR nonrec syssta(void) 
{ 
	TPRI pri; 
 
	/* タスク生成等でエラーだったらシステム起動しない */ 
 
	if (SYSER)							return SYSER; 
 
	/* アイドルタスク設定 */ 
 
	set_imask(); 
	RDQ[0].head = pTCB[0]; 
	TCB[0].sts = S_RDY; 
	TCB[0].pri = pri = tpri_max + 1; 
	add_que(&RDQ[pri], pTCB[0]); 
 
	/* 最初のディスパッチ */ 
 
	INEST = 0;					/* ディスパッチ禁止解除 */ 
  #ifdef NORTiPPC 
	IMASK |= 0x8000; 
  #else 
	IMASK = 0;					/* 割込み禁止解除 */ 
  #endif 
	dispatch(); 
 
	/* アイドルタスク部分(旧仕様)*/ 
 
  #ifdef OLDVER 
	while (TSKCNT != 0)			/* 全タスク終了ならシステム終了 */ 
		IDLE_LOOP_CNT++; 
	INEST = -1; 
	return SYSER; 
  #else 
 
	/* アイドルタスク部分 */ 
 
	for (;;) 
		IDLE_LOOP_CNT++;		/* アイドルループ数カウント */ 
  #endif 
} 
 
#endif 
#ifdef	CRE_TSK 
/****************************************/ 
/* タスクを生成する                     */ 
/****************************************/ 
 
ER FAR nonrec cre_tsk(ID tskid, TASKP stadr, TPRI itskpri, UH stksz) 
{ 
	T_TCB NEAR *tcb; 
	UH i; 
 
	/* 静的エラーチェック */ 
 
	if (tskid > tskid_max)				return SYSER = E_IDOVR; 
	if (itskpri > tpri_max)				return SYSER = E_TPRI; 
	if (stksz > STKLEN)					return SYSER = E_NOMEM; 
	tcb = pTCB[tskid]; 
	if (tcb->tid != 0)					return SYSER = E_EXS; 
 
	/* TCBの初期設定 */ 
 
	tcb->tid = tskid; 
	tcb->pri = tcb->ipri = itskpri; 
	tcb->ipc = stadr; 
	tcb->isp = (T_CTX FAR *)(USP - sizeof CTX); 
 
	/* スタックエリアを確保 */ 
 
	STKLEN -= stksz;				/* 残りスタック長 */ 
	i = stksz; 
	while (i-- != 0) 
		*--USP = (B)tskid;			/* タスクIDで埋めておく */ 
 
  #ifdef NORTi86 
	tcb->stktop = (int)((W)USP);	/* スタック先頭オフセットアドレス保存 */ 
  #else 
	tcb->stktop = USP;				/* スタック先頭アドレス保存 */ 
  #endif 
 
	return E_OK; 
} 
 
#endif 
#ifdef	XCRE_TSK 
/****************************************/ 
/* スタック領域を指定してタスクを生成   */ 
/****************************************/ 
 
ER FAR nonrec xcre_tsk(ID tskid, TASKP stadr, TPRI itskpri, UH stksz, void FAR *stkadr) 
{ 
	T_TCB NEAR *tcb; 
	B FAR *usp; 
	UH i; 
 
	/* 静的エラーチェック */ 
 
	if (tskid > tskid_max)				return SYSER = E_IDOVR; 
	if (itskpri > tpri_max)				return SYSER = E_TPRI; 
	if (stkadr == NULL)					return SYSER = E_NOMEM; 
	tcb = pTCB[tskid]; 
	if (tcb->tid != 0)					return SYSER = E_EXS; 
 
	/* TCBの初期設定 */ 
 
	tcb->tid = tskid; 
	tcb->pri = tcb->ipri = itskpri; 
	tcb->ipc = stadr; 
	usp = (B FAR *)stkadr + stksz; 
	tcb->isp = (T_CTX FAR *)(usp - sizeof CTX); 
 
	/* スタックエリアを確保 */ 
 
	i = stksz; 
	while (i-- != 0) 
		*--usp = (B)tskid;			/* タスクIDで埋めておく */ 
 
  #ifdef NORTi86 
	tcb->stktop = (int)((W)usp);	/* スタック先頭オフセットアドレス保存 */ 
  #else 
	tcb->stktop = usp;				/* スタック先頭アドレス保存 */ 
  #endif 
 
	return E_OK; 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                               タスク管理機能                                * 
*                                                                             * 
******************************************************************************/ 
#ifdef	STA_TSK 
/****************************************/ 
/* タスクを起動する                     */ 
/****************************************/ 
 
ER FAR sta_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	noauto T_CTX FAR *ctx; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	if (tcb->sts != S_DMT) 
	{	ret_imask(); 
		return E_NODMT; 
	} 
 
	/* コンテキストを初期化 */ 
 
	ctx = tcb->sp = tcb->isp; 
	*ctx = CTX; 
  #ifdef NORTi86					/* NORTi/86 のみ */ 
	ctx->stkhqq = tcb->stktop;		/* STKHQQ 値セット */ 
  #endif 
	ctx->pc = tcb->ipc;				/* スタートアドレス設定 */ 
	init_ctx(ctx);					/* アセンブラレベルの初期化処理 */ 
 
	/* TCBを初期化 */ 
 
	tcb->wupcnt = 0; 
	tcb->suscnt = 0; 
	tcb->sts = S_RDY; 
  #ifdef OLDVER 
	TSKCNT++; 
  #endif 
 
	/* レディキューへ繋いでディスパッチ */ 
 
	pri = tcb->pri; 
	add_que(&RDQ[pri], tcb); 
	if (pri < NOWPRI) 
		return dispatch(); 
	return ret_imask(); 
} 
 
#endif 
#ifdef	EXT_TSK 
/****************************************/ 
/* 自タスクを正常終了する               */ 
/****************************************/ 
 
void FAR ext_tsk(void) 
{ 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if (ERC>=2) 
	if (INEST)							{ SYSER = E_CTX; return; } 
  #endif 
 
	/* DORMANTにしレディキューから削除してディスパッチ */ 
 
	set_imask(); 
	tcb = RDQ[0].head; 
	tcb->sts = S_DMT; 
	tcb->pri = tcb->ipri; 
	del_que(tcb); 
  #ifdef OLDVER 
	TSKCNT--; 
  #endif 
 
	dispatch(); 
} 
 
#endif 
#ifdef	TER_TSK 
/****************************************/ 
/* 他タスクを強制的に異常終了させる     */ 
/****************************************/ 
 
ER FAR ter_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return SYSER = E_SELF; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
	if (!INEST && tcb == RDQ[0].head)	return SYSER = E_SELF; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
 
	/* 何らかの待ちならその待ち行列から外す */ 
 
	if (sts & S_QUE) 
		del_que(tcb); 
 
	/* タスク独立部からの場合、RUNだったら遅延ディスパッチ有 */ 
 
	if (INEST && tcb == RDQ[0].head) 
		DELAY = 1; 
 
	/* DORMANTにして終了 */ 
 
	tcb->sts = S_DMT; 
	tcb->pri = tcb->ipri; 
  #ifdef OLDVER 
	TSKCNT--; 
  #endif 
 
	return ret_imask(); 
} 
 
#endif 
#ifdef	CHG_PRI 
/****************************************/ 
/* タスク優先度を変更する               */ 
/****************************************/ 
 
ER FAR chg_pri(ID tskid, TPRI tskpri) 
{ 
	T_TCB NEAR *tcb; 
 
	if (tskid == TSK_SELF)  goto L1; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
	if (tskpri > tpri_max)				return SYSER = E_TPRI; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
  #endif 
 
	/* 優先度を変更 */ 
 
	if (tskpri == TPRI_INI) 
		tskpri = tcb->ipri; 
	set_imask(); 
	tcb->pri = tskpri; 
 
	/* READYならレディキューを繋ぎ替えてディスパッチ */ 
 
	if (tcb->sts == S_RDY && tcb->suscnt == 0) 
	{	chg_que(&RDQ[tskpri], tcb); 
		return dispatch(); 
	} 
 
	/* READYでなければディスパッチ不要 */ 
 
	return ret_imask(); 
 
	/* 自タスク指定の場合 */ 
L1: 
  #if ERC 
	if (tskpri > tpri_max)				return SYSER = E_TPRI; 
  #endif 
	tcb = RDQ[0].head; 
 
	if (tskpri == TPRI_INI) 
		tskpri = tcb->ipri; 
	set_imask(); 
	tcb->pri = tskpri; 
	chg_que(&RDQ[tskpri], tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	ROT_RDQ 
/****************************************/ 
/* タスクのレディキューを回転する       */ 
/****************************************/ 
 
ER FAR rot_rdq(TPRI tskpri) 
{ 
	T_RDQ NEAR *rdq; 
 
	/* 実行中優先度指定の場合 */ 
 
	if (tskpri == TPRI_RUN) 
	{	set_imask(); 
		rdq = &RDQ[NOWPRI]; 
		rdq->head = (rdq->head)->next; 
	} 
 
	/* 他の優先度の場合 */ 
 
	else 
	{ 
		/* 静的エラーチェック */ 
 
	  #if ERC 
		if (tskpri > tpri_max)			return SYSER = E_TPRI; 
	  #endif 
 
		/* レディキューを回転 */ 
 
		set_imask(); 
		rdq = &RDQ[tskpri]; 
		rdq->head = (rdq->head)->next; 
		if (tskpri > NOWPRI) 
			return ret_imask(); 
	} 
 
	/* ディスパッチ */ 
 
	return dispatch(); 
} 
 
#endif 
#ifdef	REL_WAI 
/****************************************/ 
/* タスクの待ち状態を強制解除する       */ 
/****************************************/ 
 
ER FAR rel_wai(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return E_NOWAI; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
	if (sts == S_RDY) 
	{	ret_imask(); 
		return E_NOWAI; 
	} 
 
	/* 待ち解除タスクへの戻値セット */ 
 
	tcb->sts = S_RDY; 
	tcb->sp->r0 = E_RLWAI; 
 
	/* 何らかの待ちならその待ち行列から外す */ 
 
	if (sts & S_QUE) 
		del_que(tcb); 
 
	/* レディキューへ繋いでディスパッチ */ 
 
	if (tcb->suscnt == 0) 
	{	pri = tcb->pri; 
		add_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	GET_TID 
/****************************************/ 
/* 自タスクのIDを得る                 */ 
/****************************************/ 
 
ER FAR get_tid(ID FAR *p_tskid) 
{ 
	if (INEST) 
		*p_tskid = FALSE; 
	else 
		*p_tskid = RDQ[0].head->tid; 
	return E_OK; 
} 
 
#endif 
#ifdef	VGET_TID 
/****************************************/ 
/* 自タスクのIDを得る(独自)         */ 
/****************************************/ 
 
ID FAR vget_tid(void) 
{ 
	return RDQ[0].head->tid; 
} 
 
#endif 
#ifdef	TSK_STS 
/****************************************/ 
/* タスクの状態を見る                   */ 
/****************************************/ 
 
ER FAR tsk_sts(UINT FAR *p_tskstat, TPRI FAR *p_tskpri, ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
 
	/* 自タスク指定の場合 */ 
 
	if (tskid == TSK_SELF) 
	{	*p_tskpri = NOWPRI; 
		*p_tskstat = TTS_RUN; 
		return E_OK; 
	} 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid > tskid_max)			return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)				return SYSER = E_NOEXS; 
  #endif 
 
	/* TCBを調べる */ 
 
	set_imask(); 
	*p_tskpri = tcb->pri; 
	if (tcb == RDQ[0].head)			*p_tskstat = TTS_RUN; 
	else 
	{	sts = tcb->sts; 
		if (sts == S_DMT)			*p_tskstat = TTS_DMT; 
		else if (tcb->suscnt == 0) 
		{	if (sts == S_RDY)		*p_tskstat = TTS_RDY; 
			else					*p_tskstat = TTS_WAI; 
		} 
		else 
		{	if (sts == S_RDY)		*p_tskstat = TTS_SUS; 
			else					*p_tskstat = TTS_WAS; 
		} 
	} 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                             タスク付属同期機能                              * 
*                                                                             * 
******************************************************************************/ 
#ifdef	SUS_TSK 
/************************************/ 
/* タスクを強制待ち状態へ移行する   */ 
/************************************/ 
 
ER FAR sus_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
	INT suscnt; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return SYSER = E_SELF; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
	if (!INEST && tcb == RDQ[0].head)	return SYSER = E_SELF; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
 
	/* 強制待ち要求回数+1 */ 
 
	suscnt = ++tcb->suscnt; 
	if (suscnt == SUSCNT_MAX+1) 
	{	tcb->suscnt = SUSCNT_MAX; 
		ret_imask(); 
		return E_QOVR; 
	} 
 
	/* READYならレディキューから外す */ 
	/* タスク独立部からの場合、RUNだったら遅延ディスパッチ有 */ 
 
	if (suscnt == 1 && sts == S_RDY) 
	{	del_que(tcb); 
		if (INEST && tcb == RDQ[0].head)	 
			DELAY = 1; 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	RSM_TSK 
/****************************************/ 
/* 強制待ち状態のタスクを再開する       */ 
/****************************************/ 
 
ER FAR rsm_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	noauto UINT sts; 
	TPRI pri; 
	INT suscnt; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return SYSER = E_SELF; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
	if (!INEST && tcb == RDQ[0].head)	return SYSER = E_SELF; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
 
	/* 強制待ち要求回数−1 */ 
 
	suscnt = --tcb->suscnt; 
	if (suscnt == -1) 
	{	tcb->suscnt = 0; 
		ret_imask(); 
		return E_NOSUS; 
	} 
 
	/* READYならレディキューへ繋いでディスパッチ */ 
 
	if (suscnt == 0 && sts == S_RDY) 
	{	pri = tcb->pri; 
		add_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	FRSM_TSK 
/****************************************/ 
/* 強制待ち状態のタスクを強制再開する   */ 
/****************************************/ 
 
ER FAR frsm_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return SYSER = E_SELF; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
	if (!INEST && tcb == RDQ[0].head)	return SYSER = E_SELF; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
	if (tcb->suscnt == 0) 
	{	ret_imask(); 
		return E_NOSUS; 
	} 
 
	/* 強制待ち要求回数クリア */ 
 
	tcb->suscnt = 0; 
 
	/* READYならレディキューへ繋いでディスパッチ */ 
 
	if (sts == S_RDY) 
	{	pri = tcb->pri; 
		add_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	SLP_TSK 
/****************************************/ 
/* タスクを待ち状態へ移行する           */ 
/****************************************/ 
 
ER FAR slp_tsk(void) 
{ 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if (ERC>=2) 
	if (INEST)							return SYSER = E_CTX; 
  #endif 
 
	/* 起床要求あるなら−1して即終了 */ 
 
	set_imask(); 
	tcb = RDQ[0].head; 
	if (tcb->wupcnt != 0) 
	{	tcb->wupcnt--; 
		return ret_imask(); 
	} 
 
	/* 単純待機にしレディキューから外してディスパッチ */ 
 
	tcb->sts = S_SLP; 
	del_que(tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	WAI_TSK 
/****************************************/ 
/* タスクを一定時間待ち状態へ移行する   */ 
/****************************************/ 
 
ER FAR wai_tsk(TMO tmout) 
{ 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if (ERC>=2) 
	if (INEST)							return SYSER = E_CTX; 
  #endif 
 
	/* 起床要求あるなら−1して即終了 */ 
 
	set_imask(); 
	tcb = RDQ[0].head; 
	if (tcb->wupcnt != 0) 
	{	tcb->wupcnt--; 
		return ret_imask(); 
	} 
 
	/* 待ち時間0なら即終了 */ 
 
	if (tmout == 0) 
	{	ret_imask(); 
		return E_TMOUT; 
	} 
 
	/* 永久待ちなら単純待機にしレディキューから外す */ 
 
	if (tmout == TMO_FEVR) 
	{	tcb->sts = S_SLP; 
		del_que(tcb); 
	} 
	 
	/* 時間待ちにしレディキューから外して時間待ちキューに加える */ 
 
	else 
	{	tcb->sts = S_WAI; 
		tmout += SYSCLK.ltime;		/* タイムアウト時刻 */ 
		tcb->ltime = (UH)tmout; 
		chg_que(&TMQ[(UB)tmout], tcb); 
	} 
 
	/* ディスパッチ */ 
 
	return dispatch(); 
} 
 
#endif 
#ifdef	STA_TSK 
/****************************************/ 
/* 待ち状態のタスクを起床する           */ 
/****************************************/ 
 
ER FAR wup_tsk(ID tskid) 
{ 
	T_TCB NEAR *tcb; 
	UINT sts; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (tskid == TSK_SELF)				return SYSER = E_SELF; 
	if (tskid > tskid_max)				return SYSER = E_NOEXS; 
  #endif 
	tcb = pTCB[tskid]; 
  #if ERC 
	if (tcb->tid == 0)					return SYSER = E_NOEXS; 
	if (!INEST && tcb == RDQ[0].head)	return SYSER = E_SELF; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	set_imask(); 
	sts = tcb->sts; 
	if (sts == S_DMT) 
	{	ret_imask(); 
		return E_DMT; 
	} 
 
	/* slp_tsk/wai_tsk中でなければ起床要求+1して即終了 */ 
 
	if (!(sts & (S_SLP|S_WAI))) 
	{	if (++tcb->wupcnt == WUPCNT_MAX+1) 
		{	tcb->wupcnt = WUPCNT_MAX; 
			ret_imask(); 
			return E_QOVR; 
		} 
		goto OK; 
	} 
 
	/* wai_tsk中なら時間待ちキューから外す */ 
 
	if (sts == S_WAI) 
		del_que(tcb); 
 
	/* レディキューへ繋いでディスパッチ */ 
 
	tcb->sts = S_RDY; 
	if (tcb->suscnt == 0) 
	{	pri = tcb->pri; 
		add_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
OK: 
	return ret_imask(); 
} 
 
#endif 
#ifdef	CAN_WUP 
/****************************************/ 
/* タスクの起床要求を無効にする         */ 
/****************************************/ 
 
ER FAR can_wup(INT FAR *p_wupcnt, ID tskid) 
{ 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
	if (tskid == TSK_SELF) 
		tcb = RDQ[0].head; 
	else 
	{ 
	  #if ERC 
		if (tskid > tskid_max)			return SYSER = E_NOEXS; 
	  #endif 
		tcb = pTCB[tskid]; 
	  #if ERC 
		if (tcb->tid == 0)				return SYSER = E_NOEXS; 
	  #endif 
	} 
 
	/* 起床要求をクリア */ 
 
	set_imask(); 
	*p_wupcnt = tcb->wupcnt; 
	tcb->wupcnt = 0; 
	return ret_imask(); 
} 
 
#endif 
#ifdef	VCAN_WUP 
/*****************************************/ 
/* 自タスクの起床要求を無効にする(独自)*/ 
/*****************************************/ 
 
void FAR vcan_wup(void) 
{ 
	RDQ[0].head->wupcnt = 0; 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                   同期・通信機能(1ワードイベントフラグ)                   * 
*                                                                             * 
******************************************************************************/ 
#ifdef	SET_WFLG 
/****************************************/ 
/* 1ワードイベントフラグをセットする   */ 
/****************************************/ 
 
static BOOL NEAR nonrec set_wflg_sub(T_FLG NEAR *flg, UINT setptn) 
{ 
	T_TCB NEAR *tcb; 
	UINT flgptn; 
	INT i; 
	TPRI pri; 
	BOOL disp; 
 
	/* イベントフラグをセット */ 
 
	flg->ptn |= setptn; 
 
	/* 待ちタスク無ければ即終了 */ 
 
	i = flg->qcnt; 
	if (i == 0) 
		return FALSE; 
 
	/* 条件を満たす(複数の)タスクのイベントフラグ待ち解除 */ 
 
	disp = FALSE; 
	for (;;) 
	{	 
		/* 待ち条件を満たすタスクを先頭から検索 */ 
		/* 注:処理時間が待ちタスク数に依存する */ 
 
		tcb = flg->head; 
		for (;;) 
		{	flgptn = tst_wflg(&flg->ptn, tcb->waiptn, tcb->sts); 
			if (flgptn != FALSE) 
				break; 
			if (--i == 0) 
				goto L1; 
			tcb = tcb->next; 
		} 
 
		/* イベントフラグ待ち行列から外しレディキューへ繋ぐ */ 
 
		*tcb->arg = flgptn;		/* 待ち解除時のビットパターン */ 
		tcb->sts = S_RDY; 
		if (tcb->suscnt != 0) 
			del_que(tcb);		/* SUSPENDなら外すだけ */ 
		else 
		{	pri = tcb->pri; 
			if (pri < NOWPRI) 
				disp = TRUE; 
			chg_que(&RDQ[pri], tcb); 
		} 
 
		/* 待ちタスク無しまたは */ 
		/* イベントフラグクリアされたなら終了 */ 
 
		i = flg->qcnt; 
		if (i == 0) 
			break; 
	  #ifdef OLDVER 
		if ((flg->ptn & setptn) == 0) 
	  #else 
		if (flg->ptn == 0) 
	  #endif 
			break; 
	} 
L1: 
	return disp; 
} 
 
ER FAR set_wflg(ID flgid, UINT setptn) 
{ 
	T_FLG NEAR *flg; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 本処理 */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	if (set_wflg_sub(flg, setptn)) 
		return dispatch(); 
	else 
		return ret_imask(); 
} 
 
#endif 
#ifdef	CLR_WFLG 
/****************************************/ 
/* 1ワードイベントフラグをクリアする   */ 
/****************************************/ 
 
ER FAR clr_wflg(ID flgid, UINT clrptn) 
{ 
	UINT NEAR *ptn; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* イベントフラグをクリア */ 
 
	ptn = &FLG[flgid].ptn; 
	set_imask(); 
	*ptn &= clrptn; 
	return ret_imask(); 
} 
 
#endif 
#ifdef	WAI_WFLG 
/****************************************/ 
/* 1ワードイベントフラグを待つ         */ 
/****************************************/ 
 
ER FAR wai_wflg(UINT FAR *p_flgptn, ID flgid, UINT waiptn, UINT wfmode) 
{ 
	T_FLG NEAR *flg; 
	T_TCB NEAR *tcb; 
	UINT ptn; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
	if (waiptn == 0)					return SYSER = E_PAR; 
	if (wfmode & ~(S_ORW|S_CLR))		return SYSER = E_RSMD; 
  #endif 
 
	/* 既に条件満足しているなら即終了 */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	ptn = tst_wflg(&flg->ptn, waiptn, wfmode); 
	if (ptn != FALSE) 
	{	*p_flgptn = ptn; 
		return ret_imask(); 
	} 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* イベントフラグ待ちを設定 */ 
 
	tcb = RDQ[0].head; 
	tcb->sts = S_FLG | wfmode; 
	tcb->waiptn = waiptn; 
	tcb->arg = p_flgptn; 
 
	/* レディキューから外して */ 
	/* イベントフラグ待ち行列へ繋いでディスパッチ */ 
 
	chg_que((T_RDQ NEAR *)flg, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	POL_WFLG 
/****************************************/ 
/* 1ワードイベントフラグを得る         */ 
/****************************************/ 
 
ER FAR pol_wflg(UINT FAR *p_flgptn, ID flgid, UINT waiptn, UINT wfmode) 
{ 
	T_FLG NEAR *flg; 
	UINT ptn; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
	if (waiptn == 0)					return SYSER = E_PAR; 
	if (wfmode & ~(S_ORW|S_CLR))		return SYSER = E_RSMD; 
  #endif 
 
	/* 既に条件満足しているなら即終了 */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	ptn = tst_wflg(&flg->ptn, waiptn, wfmode); 
	if (ptn != FALSE) 
	{	*p_flgptn = ptn; 
		return ret_imask(); 
	} 
 
	/* 満足してなければエラー終了 */ 
 
	ret_imask(); 
	return E_PLFAIL; 
} 
 
#endif 
#ifdef	FLG_STS 
/***************************************************/ 
/* 1ワード/1ビットイベントフラグの状態を参照する */ 
/***************************************************/ 
 
ER FAR flg_sts(ID FAR *p_wtskid, UINT FAR *p_flgptn, ID flgid) 
{ 
	T_FLG NEAR *flg; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* イベントフラグを調べる */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	*p_flgptn = (BOOL)flg->ptn;			/* ビットパターン */ 
	if (flg->qcnt != 0) 
		*p_wtskid = (flg->head)->tid;	/* 先頭待ちタスクID */ 
	else 
		*p_wtskid = FALSE; 
 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                   同期・通信機能(1ビットイベントフラグ)                   * 
*                                                                             * 
******************************************************************************/ 
#ifdef	SET_FLG 
/****************************************/ 
/* 1ビットイベントフラグをセットする   */ 
/****************************************/ 
 
ER FAR set_flg(ID flgid) 
{ 
	T_FLG NEAR *flg; 
	T_TCB NEAR *tcb; 
	TPRI pri; 
	noauto BOOL disp; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* イベントフラグをセット */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	flg->ptn = 1; 
 
	/* 待ちタスク無ければ即終了 */ 
 
	if (flg->qcnt == 0) 
		goto OK; 
 
	/* (複数の)タスクのイベントフラグ待ち解除 */ 
 
	disp = FALSE; 
	for (;;) 
	{ 
		tcb = flg->head; 
 
		/* クリア有りの場合イベントフラグをクリア */ 
 
		if (tcb->sts & S_CLR) 
			flg->ptn = 0; 
 
		/* イベントフラグ待ち行列から外し */ 
		/* レディキューへ繋ぐ */ 
 
		tcb->sts = S_RDY; 
		if (tcb->suscnt != 0)	 
			del_que(tcb);		/* SUSPENDなら外すだけ */ 
		else 
		{	pri = tcb->pri; 
			if (pri < NOWPRI) 
				disp = TRUE; 
			chg_que(&RDQ[pri], tcb); 
		} 
 
		/* 待ちタスク無しまたは */ 
		/* イベントフラグクリアされたら終了 */ 
 
		if (flg->qcnt == 0 || flg->ptn == 0) 
			break; 
	} 
 
	/* ディスパッチ */ 
 
	if (disp) 
		return dispatch(); 
OK: 
	return ret_imask(); 
} 
 
#endif 
#ifdef	CLR_FLG 
/****************************************/ 
/* 1ビットイベントフラグをクリアする   */ 
/****************************************/ 
 
ER FAR clr_flg(ID flgid) 
{ 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* イベントフラグをクリア */ 
 
	FLG[flgid].ptn = 0; 
	return E_OK; 
} 
 
#endif 
#ifdef	WAI_FLG 
/********************************************/ 
/* 1ビットイベントフラグを待つ(クリア無) */ 
/********************************************/ 
 
ER FAR wai_flg(ID flgid) 
{ 
	T_FLG NEAR *flg; 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にイベントフラグセットされているなら即終了 */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	if (flg->ptn != 0) 
		return ret_imask(); 
 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* レディキューから外して */ 
	/* イベントフラグ待ち行列へ繋いでディスパッチ */ 
 
	tcb = RDQ[0].head; 
	tcb->sts = S_FLG; 
	chg_que((T_RDQ NEAR *)flg, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	CWAI_FLG 
/********************************************/ 
/* 1ビットイベントフラグを待つ(クリア有) */ 
/********************************************/ 
 
ER FAR cwai_flg(ID flgid) 
{ 
	T_FLG NEAR *flg; 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にイベントフラグセットされているなら */ 
	/* クリアして即終了 */ 
 
	flg = &FLG[flgid]; 
	set_imask(); 
	if (flg->ptn != 0) 
	{	flg->ptn = 0; 
		return ret_imask(); 
	} 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* レディキューから外して */ 
	/* イベントフラグ待ち行列へ繋いでディスパッチ */ 
 
	tcb = RDQ[0].head; 
	tcb->sts = S_FLG|S_CLR; 
	chg_que((T_RDQ NEAR *)flg, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	POL_FLG 
/********************************************/ 
/* 1ビットイベントフラグを得る(クリア無) */ 
/********************************************/ 
 
ER FAR pol_flg(ID flgid) 
{ 
	UINT NEAR *ptn; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にイベントフラグセットされているなら即終了 */ 
 
	ptn = &FLG[flgid].ptn; 
	if (*ptn != 0) 
		return E_OK; 
 
	/* セットされてなければエラー終了 */ 
 
	return E_PLFAIL; 
} 
 
#endif 
#ifdef	CPOL_FLG 
/********************************************/ 
/* 1ビットイベントフラグを得る(クリア有) */ 
/********************************************/ 
 
ER FAR cpol_flg(ID flgid) 
{ 
	UINT NEAR *ptn; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (flgid > flgid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にイベントフラグセットされているなら */ 
	/* クリアして即終了 */ 
 
	ptn = &FLG[flgid].ptn; 
	set_imask(); 
	if (*ptn != 0) 
	{	*ptn = 0; 
		return ret_imask(); 
	} 
 
	/* セットされてなければエラー終了 */ 
 
	ret_imask(); 
	return E_PLFAIL; 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                          同期・通信機能(セマフォ)                          * 
*                                                                             * 
******************************************************************************/ 
#ifdef	SIG_SEM 
/****************************************/ 
/* セマフォに対する信号操作(V命令)   */ 
/****************************************/ 
 
ER FAR sig_sem(ID semid) 
{ 
	T_SEM NEAR *sem; 
	T_TCB NEAR *tcb; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (semid > semid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 待ちタスク無ければ、セマフォカウント+1して終了 */ 
 
	sem = &SEM[semid]; 
	set_imask(); 
	if (sem->qcnt == 0) 
	{	if (++sem->cnt == SEMCNT_MAX+1) 
		{	sem->cnt = SEMCNT_MAX; 
			ret_imask(); 
			return E_QOVR; 
		} 
		goto OK; 
	} 
 
	/* セマフォ待ち行列から */ 
	/* レディキューへ繋ぎ替えてディスパッチ */ 
 
	tcb = sem->head; 
	tcb->sts = S_RDY; 
	if (tcb->suscnt != 0) 
		del_que(tcb);		/* SUSPENDなら外すだけ */ 
	else 
	{	pri = tcb->pri; 
		chg_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
OK: 
	return ret_imask(); 
} 
 
#endif 
#ifdef	WAI_SEM 
/****************************************/ 
/* セマフォに対する待ち操作(P命令)   */ 
/****************************************/ 
 
ER FAR wai_sem(ID semid) 
{ 
	T_SEM NEAR *sem; 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (semid > semid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* セマフォカウント1以上なら−1して即終了 */ 
 
	sem = &SEM[semid]; 
	set_imask(); 
	if (sem->cnt != 0) 
	{	sem->cnt--; 
		return ret_imask(); 
	} 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* レディキューから外し */ 
	/* セマフォ待ち行列へ繋いでディスパッチ */ 
 
	tcb = RDQ[0].head; 
	tcb->sts = S_SEM; 
	chg_que((T_RDQ NEAR *)sem, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	PREQ_SEM 
/****************************************/ 
/* セマフォ資源を得る                   */ 
/****************************************/ 
 
ER FAR preq_sem(ID semid) 
{ 
	T_SEM NEAR *sem; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (semid > semid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* セマフォカウント1以上なら−1して即終了 */ 
 
	sem = &SEM[semid]; 
	set_imask(); 
	if (sem->cnt != 0) 
	{	sem->cnt--; 
		return ret_imask(); 
	}	 
 
	/* セマフォカウント0ならエラー終了 */ 
 
	ret_imask(); 
	return E_PLFAIL; 
} 
 
#endif 
#ifdef	SEM_STS 
/****************************************/ 
/* セマフォ状態を参照する               */ 
/****************************************/ 
 
ER FAR sem_sts(ID FAR *p_wtskid, INT FAR *p_semcnt, ID semid) 
{ 
	T_SEM NEAR *sem; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (semid > semid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* セマフォを調べる */ 
 
	sem = &SEM[semid]; 
	set_imask(); 
	*p_semcnt = sem->cnt; 
	if (sem->qcnt != 0) 
		*p_wtskid = (sem->head)->tid; 
	else 
		*p_wtskid = FALSE; 
 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                       同期・通信機能(メイルボックス)                       * 
*                                                                             * 
******************************************************************************/ 
#ifdef	SND_MSG 
/****************************************/ 
/* メイルボックスへ送信する             */ 
/****************************************/ 
 
ER FAR snd_msg(ID mbxid, T_MSG FAR *pk_msg) 
{ 
	noauto T_MBX NEAR *mbx; 
	T_TCB NEAR *tcb; 
	T_MSG FAR *endmsg; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mbxid > mbxid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既に他のメッセージ有るなら */ 
	/* メッセージをキューの最後に繋いで即終了 */ 
 
	set_imask(); 
	mbx = &MBX[mbxid]; 
	if (mbx->top != NULL) 
	{	endmsg = mbx->end; 
		mbx->end = pk_msg; 
		endmsg->next = pk_msg; 
		pk_msg->next = NULL; 
		goto OK; 
	} 
 
	/* 他のメッセージも待ちタスクも無ければ */ 
	/* メッセージをキューの先頭に繋いで即終了 */ 
 
	else if (mbx->qcnt == 0) 
	{	mbx->top = pk_msg; 
		mbx->end = pk_msg; 
		pk_msg->next = NULL; 
		goto OK; 
	} 
 
	/* 先頭の待ちタスクにメッセージを渡す */ 
 
	tcb = mbx->head; 
	*(T_MSG FAR * FAR *)tcb->arg = pk_msg; 
 
	/* メッセージ待ち行列から */ 
	/* レディキューへ繋ぎ替えてディスパッチ */ 
 
	tcb->sts = S_RDY; 
	if (tcb->suscnt != 0) 
		del_que(tcb);		/* SUSPENDなら外すだけ */ 
	else 
	{	pri = tcb->pri; 
		chg_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
OK: 
	return ret_imask(); 
} 
 
#endif 
#ifdef	RCV_MSG 
/****************************************/ 
/* メイルボックスからの受信を待つ       */ 
/****************************************/ 
 
ER FAR rcv_msg(T_MSG FAR * FAR *ppk_msg, ID mbxid) 
{ 
	noauto T_MBX NEAR *mbx; 
	noauto T_TCB NEAR *tcb; 
	T_MSG FAR *topmsg; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mbxid > mbxid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にメッセージがあるなら */ 
	/* 先頭のメッセージを引取って即終了 */ 
 
	set_imask(); 
	mbx = &MBX[mbxid]; 
	if (mbx->top != NULL) 
	{	topmsg = mbx->top; 
		mbx->top = topmsg->next; 
		*ppk_msg = topmsg; 
		return ret_imask(); 
	}	 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* メッセージ待ちを設定 */ 
 
	tcb = RDQ[0].head; 
	tcb->sts = S_MBX; 
	tcb->arg = (UINT FAR *)ppk_msg; 
 
	/* レディキューから外し */ 
	/* メッセージ待ち行列へ繋いでディスパッチ */ 
 
	chg_que((T_RDQ NEAR *)mbx, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	PRCV_MSG 
/****************************************/ 
/* メイルボックスから受信する           */ 
/****************************************/ 
 
ER FAR prcv_msg(T_MSG FAR * FAR *ppk_msg, ID mbxid) 
{ 
	noauto T_MBX NEAR *mbx; 
	T_MSG FAR *topmsg; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mbxid > mbxid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にメッセージ有るなら,それを引取って即終了 */ 
 
	set_imask(); 
	mbx = &MBX[mbxid]; 
	if (mbx->top != NULL) 
	{	topmsg = mbx->top; 
		mbx->top = topmsg->next; 
		*ppk_msg = topmsg; 
		return ret_imask(); 
	} 
 
	/* メッセージ無ければエラー終了 */ 
 
	ret_imask(); 
	return E_PLFAIL; 
} 
 
#endif 
#ifdef	MBX_STS 
/****************************************/ 
/* メイルボックス状態を参照する         */ 
/****************************************/ 
 
ER FAR mbx_sts(ID FAR *p_wtskid, T_MSG FAR * FAR *ppk_msg, ID mbxid) 
{ 
	T_MBX NEAR *mbx; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mbxid > mbxid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* メイルボックスを調べる */ 
 
	mbx = &MBX[mbxid]; 
	set_imask(); 
	if (mbx->qcnt != 0) 
	{	*p_wtskid = (mbx->head)->tid; 
		*ppk_msg  = (T_MSG FAR *)NADR; 
	} 
	else 
	{	*p_wtskid = FALSE; 
		if ((*ppk_msg = mbx->top) == NULL) 
			*ppk_msg = (T_MSG FAR *)NADR; 
	} 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                               割込み管理機能                                * 
*                                                                             * 
******************************************************************************/ 
#ifdef	CHG_IMS 
/****************************************/ 
/* 割込みマスクを変更する               */ 
/****************************************/ 
 
ER FAR chg_ims(UINT imask) 
{ 
	set_imask(); 
 
  #if defined(NORTi68K) 
	IMASK = (imask << 8) & 0x0700; 
  #elif defined(NORTiPPC) 
	if (imask) 
		IMASK &= ~0x8000; 
	else 
		IMASK |= 0x8000; 
  #else 
	IMASK = imask; 
  #endif 
 
	if (DELAY) 
		return dispatch(); 
	return ret_imask(); 
} 
 
#endif 
#ifdef	IMS_STS 
/****************************************/ 
/* 割込みマスクを参照する               */ 
/****************************************/ 
 
ER FAR ims_sts(UINT FAR *p_imask) 
{ 
	UINT ims;	 
 
	set_imask(); 
	ims = IMASK; 
	ret_imask(); 
 
  #if defined(NORTi86) 
	ims = (ims != 0); 
  #elif defined(NORTi68K) 
	ims >>= 8; 
  #elif defined(NORTiPPC) 
	ims = ((ims & 0x8000) == 0); 
  #endif 
 
	*p_imask = ims; 
	return E_OK; 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                            メモリプール管理機能                             * 
*                                                                             * 
******************************************************************************/ 
#ifdef	GET_BLK 
/****************************************/ 
/* 固定長メモリブロックの獲得待ちを行う */ 
/****************************************/ 
 
ER FAR get_blk(void FAR * FAR *p_blk, ID mplid) 
{ 
	noauto T_MPL NEAR *mpl; 
	T_TCB NEAR *tcb; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mplid > mplid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にメモリブロックがあるなら */ 
	/* 先頭のメモリブロックを引取って即終了 */ 
 
	set_imask(); 
	mpl = pMPL[mplid]; 
	if (mpl->frbcnt != 0) 
	{	mpl->frbcnt--; 
		*p_blk = mpl->top; 
		mpl->top = *((void FAR * FAR *)(mpl->top)); 
		return ret_imask(); 
	}	 
  #if (ERC>=2) 
	if (INEST) 
	{	ret_imask(); 
		return SYSER = E_CTX; 
	} 
  #endif 
 
	/* メモリブロック待ちを設定 */ 
 
	tcb = RDQ[0].head; 
	tcb->arg = (UINT FAR *)p_blk; 
	tcb->sts = S_MPL; 
 
	/* レディキューから外し */ 
	/* メモリブロック待ち行列へ繋いでディスパッチ */ 
 
	chg_que((T_RDQ NEAR *)mpl, tcb); 
	return dispatch(); 
} 
 
#endif 
#ifdef	PGET_BLK 
/****************************************/ 
/* 固定長メモリブロックを獲得する       */ 
/****************************************/ 
 
ER FAR pget_blk(void FAR * FAR *p_blk, ID mplid) 
{ 
	noauto T_MPL NEAR *mpl; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mplid > mplid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* 既にメモリブロック有るなら,それを引取って即終了 */ 
 
	set_imask(); 
	mpl = pMPL[mplid]; 
	if (mpl->frbcnt != 0) 
	{	mpl->frbcnt--; 
		*p_blk = mpl->top; 
		mpl->top = *((void FAR * FAR *)(mpl->top)); 
		return ret_imask(); 
	} 
 
	/* メモリブロック無ければエラー終了 */ 
 
	ret_imask(); 
	return E_PLFAIL; 
} 
 
#endif 
#ifdef	REL_BLK 
/****************************************/ 
/* 固定長メモリブロックを返却する       */ 
/****************************************/ 
 
ER FAR rel_blk(ID mplid, void FAR * blk) 
{ 
	noauto T_MPL NEAR *mpl; 
	T_TCB NEAR *tcb; 
	TPRI pri; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mplid > mplid_max)				return SYSER = E_NOEXS; 
	if (blk == NULL)					return SYSER = E_ILBLK; 
  #endif 
 
	/* 待ちタスク無ければ */ 
	/* メモリブロックをキューの先頭に繋いで即終了 */ 
 
	set_imask(); 
	mpl = pMPL[mplid]; 
	if (mpl->qcnt == 0) 
	{	mpl->frbcnt++; 
		*(void FAR * FAR *)blk = mpl->top; 
		mpl->top = blk; 
		goto OK; 
	} 
 
	/* 先頭の待ちタスクにメモリブロックを渡す */ 
 
	tcb = mpl->head; 
	*(void FAR * FAR *)tcb->arg = blk; 
 
	/* メモリブロック待ち行列から */ 
	/* レディキューへ繋ぎ替えてディスパッチ */ 
 
	tcb->sts = S_RDY; 
	if (tcb->suscnt != 0) 
		del_que(tcb);		/* SUSPENDなら外すだけ */ 
	else 
	{	pri = tcb->pri; 
		chg_que(&RDQ[pri], tcb); 
		if (pri < NOWPRI) 
			return dispatch(); 
	} 
OK: 
	return ret_imask(); 
} 
 
#endif 
#ifdef	MPL_STS 
/****************************************/ 
/* メモリプールの状態を参照する         */ 
/****************************************/ 
 
ER FAR mpl_sts(ID FAR *p_wtskid, int FAR *p_frbcnt, ID mplid) 
{ 
	T_MPL NEAR *mpl; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (mplid > mplid_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* メイルボックスを調べる */ 
 
	mpl = pMPL[mplid]; 
	set_imask(); 
	if (mpl->qcnt != 0) 
	{	*p_wtskid = (mpl->head)->tid; 
		*p_frbcnt = 0; 
	} 
	else 
	{	*p_frbcnt = mpl->frbcnt; 
		*p_wtskid = FALSE; 
	} 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                        時間管理・タイマハンドラ機能                         * 
*                                                                             * 
******************************************************************************/ 
#ifdef	STA_TSK 
/****************************************/ 
/* インターバルタイマ処理               */ 
/****************************************/ 
 
void FAR nonrec intent(void) 
{ 
	T_RDQ NEAR *tmq; 
	T_TCB NEAR *tcb; 
	T_TCB NEAR *toptcb; 
	T_TCB NEAR *endtcb; 
	TMRHDRP func; 
	UH t; 
	INT qcnt; 
	UINT sts; 
	TPRI pri; 
 
  #if NEST 
	set_imask(); 
  #endif 
 
	/* システム時刻+1 */ 
 
  #if (CLKBITS>32) 
	if ((t = ++SYSCLK.ltime) == 0)	/* 低位+1 */ 
	{	if (++SYSCLK.mtime == 0)	/* 中位へのキャリ */ 
			++SYSCLK.utime;			/* 高位へのキャリ */ 
	} 
  #endif 
 
  #if (CLKBITS<=32)&&(CLKBITS>16) 
	if ((t = ++SYSCLK.ltime) == 0)	/* 低位+1 */ 
		++SYSCLK.mtime;				/* 中位へのキャリ */ 
  #endif 
 
  #if (CLKBITS<=16) 
	t = ++SYSCLK.ltime;				/* 低位+1 */ 
  #endif 
 
	/* 時間待ちキューヘッダを求める */ 
 
	tmq = &TMQ[(UB)t]; 
	qcnt = tmq->qcnt; 
 
	for (;; ope_imask())			/* 1ループ毎に他の割込み受付可 */ 
	{ 
		/* 全部調べたまたは外れたら終了 */ 
	L1: 
		if (qcnt == 0 || tmq->qcnt == 0) 
			break; 
		qcnt--; 
 
		/* 下位時刻不一致なら時間待ちキュー末尾へ回す */ 
 
		tcb = tmq->head; 
		if (t != tcb->ltime) 
		{	tmq->head = tcb->next; 
			goto L1; 
		} 
 
		/* 周期起動ハンドラ/アラームハンドラの場合 */ 
		/* 上位時刻が不一致なら時間待ちキュー末尾へ回す */ 
 
		sts = tcb->sts; 
	  #if (CLKBITS>16) 
		if (sts & S_HDR) 
		{	if (SYSCLK.mtime != ((T_TMR NEAR *)tcb)->mtime 
		  #if (CLKBITS>32) 
				|| SYSCLK.utime != ((T_TMR NEAR *)tcb)->utime 
		  #endif 
				) 
			{	tmq->head = tcb->next; 
				continue; 
			} 
		} 
	  #endif 
 
		/* システムクロックと一致したTCB(タイマ)を外す */ 
 
		tmq->head = toptcb = tcb->next;		/* 次TCBを先頭TCBに */ 
		endtcb = tcb->prev; 
		endtcb->next = toptcb;				/* 末尾TCBの次は先頭TCB */ 
		toptcb->prev = endtcb;				/* 先頭TCBの前は末尾TCB */ 
		tmq->qcnt--; 
 
		/* タスクならレディキューへ繋ぐ */ 
 
		if (!(sts & S_HDR)) 
		{ 
			tcb->sts = S_RDY; 
			tcb->sp->r0 = E_TMOUT;			/* タイムアウト戻値 */ 
			if (tcb->suscnt == 0)			/* SUSPENDを除く */ 
			{	pri = tcb->pri; 
				add_que(&RDQ[pri], tcb); 
				if (pri < NOWPRI) 
					DELAY = 1;				/* 遅延ディスパッチ有 */ 
			} 
			continue; 
		} 
 
		/* タイマハンドラの実行 */ 
 
		if (sts & S_CYC)					/* 周期起動ハンドラの場合 */ 
		{	ins_reltim((T_TMR NEAR *)tcb);	/* タイマ再追加 */ 
			if (!(sts & S_ACT)) 
				continue; 
		} 
		else								/* アラームハンドラの場合 */ 
			tcb->sts = S_DMT;				/* タイマ外れた */ 
 
		func = ((T_TMR NEAR *)tcb)->ipc; 
	  #if NEST 
		ret_imask(); 
		(*func)();							/* タイマハンドラ呼出し */ 
		set_imask(); 
	  #else 
		(*func)(); 
	  #endif 
	  	goto L1; 
	} 
 
  #if NEST 
	ret_imask(); 
  #endif 
} 
 
#endif 
#ifdef	SET_TIM 
/****************************************/ 
/* システムクロックを設定する           */ 
/****************************************/ 
 
ER FAR set_tim(T_TIME time) 
{ 
	set_imask(); 
	SYSCLK.ltime = time.ltime; 
  #if (CLKBITS>16) 
	SYSCLK.mtime = time.mtime; 
  #if (CLKBITS>32) 
	SYSCLK.utime = time.utime; 
  #endif 
  #endif 
	return ret_imask(); 
} 
 
#endif 
#ifdef	GET_TIM 
/****************************************/ 
/* システムクロックの値を読み出す       */ 
/****************************************/ 
 
ER FAR get_tim(T_TIME FAR *p_time) 
{ 
	set_imask(); 
	p_time->ltime = SYSCLK.ltime; 
  #if (CLKBITS>16) 
	p_time->mtime = SYSCLK.mtime; 
  #if (CLKBITS>32) 
	p_time->utime = SYSCLK.utime; 
  #endif 
  #endif 
	return ret_imask(); 
} 
 
#endif 
#ifdef	DEF_CYC 
/****************************************/ 
/* 周期起動ハンドラを定義する           */ 
/****************************************/ 
 
ER FAR def_cyc(HNO cyhno, TMRHDRP cychdr, UINT cyhact, T_TIME cytime) 
{ 
	noauto T_TMR NEAR *tmr; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (cyhno > cyhno_max)				return SYSER = E_PAR; 
	if (cyhact > TCY_ON)				return SYSER = E_RSMD; 
  #endif 
 
	/* 定義済みなら時間待ちキューから削除 */ 
 
	set_imask(); 
	tmr = pCYH[cyhno]; 
	if (tmr->sts != S_DMT) 
		del_que((T_TCB NEAR *)tmr); 
 
	/* NADRなら削除して終了 */ 
 
	if ((tmr->ipc = cychdr) == (TMRHDRP)NADR) 
		tmr->sts = S_DMT; 
 
	/* 時間待ちキューへ追加 */ 
 
	else 
	{	tmr->defltime = cytime.ltime; 
	  #if (CLKBITS>16) 
		tmr->defmtime = cytime.mtime; 
	  #if (CLKBITS>32) 
		tmr->defutime = cytime.utime; 
	  #endif 
	  #endif 
		tmr->sts = S_HDR | S_CYC | cyhact; 
		ins_reltim(tmr); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	ACT_CYC 
/****************************************/ 
/* 周期起動ハンドラの活性制御を行う     */ 
/****************************************/ 
 
ER FAR act_cyc(HNO cyhno, UINT cyhact) 
{ 
	T_TMR NEAR *tmr; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (cyhno > cyhno_max)				return SYSER = E_NOEXS; 
	if (cyhact > (TCY_INI|TCY_ON))		return SYSER = E_RSMD; 
  #endif 
 
	/* 動的エラーチェック */ 
 
	tmr = pCYH[cyhno]; 
	set_imask(); 
	if (tmr->sts == S_DMT) 
	{	ret_imask(); 
		return E_NOEXS; 
	} 
 
	/* 起動有無の設定 */ 
 
	if (cyhact & TCY_ON) 
		tmr->sts |= S_ACT; 
	else 
		tmr->sts &= ~S_ACT; 
 
	/* 初期化の場合 */ 
	/* 時間待ちキューから削除して再追加 */ 
 
	if (cyhact & TCY_INI) 
	{	del_que((T_TCB NEAR *)tmr); 
		ins_reltim(tmr); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	CYH_STS 
/****************************************/ 
/* 周期起動ハンドラの状態を参照する     */ 
/****************************************/ 
 
ER FAR cyh_sts(UINT FAR *p_cyhact, T_TIME FAR *p_lftime, HNO cyhno) 
{ 
	T_TMR NEAR *tmr; 
	UH t; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (cyhno > cyhno_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* ハンドラの状態を調べる */ 
 
	tmr = pCYH[cyhno]; 
	set_imask(); 
	if (tmr->sts == S_DMT) 
	{	ret_imask(); 
		return E_NOEXS; 
	} 
	*p_cyhact = tmr->sts & S_ACT; 
 
	t = (UH)(tmr->ltime - SYSCLK.ltime); 
	p_lftime->ltime = t; 
  #if (CLKBITS>16) 
	t = (UH)((t > tmr->ltime) ? -1: 0); 
	p_lftime->mtime = t += (UH)(tmr->mtime - SYSCLK.mtime); 
  #if (CLKBITS>32) 
	t = (UH)((t > tmr->mtime) ? -1: 0); 
	p_lftime->utime = (UH)(t + tmr->utime - SYSCLK.utime); 
  #endif 
  #endif 
 
	return ret_imask(); 
} 
 
#endif 
#ifdef	DEF_ALM 
/****************************************/ 
/* アラームハンドラを定義する           */ 
/****************************************/ 
 
ER FAR def_alm(HNO alhno, TMRHDRP almhdr, T_TIME time, UINT tmmode) 
{ 
	noauto T_TMR NEAR *tmr; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (alhno > alhno_max)				return SYSER = E_PAR; 
	if (tmmode > TTM_REL)				return SYSER = E_RSMD; 
  #endif 
 
	/* 定義済みなら時間待ちキューから削除 */ 
 
	set_imask(); 
	tmr = pALH[alhno]; 
	if (tmr->sts != S_DMT) 
		del_que((T_TCB NEAR *)tmr); 
 
	/* NADRなら削除して終了 */ 
 
	if ((tmr->ipc = almhdr) == (TMRHDRP)NADR) 
		tmr->sts = S_DMT; 
 
	/* 時間待ちキューへ追加 */ 
 
	else 
	{	tmr->defltime = time.ltime; 
	  #if (CLKBITS>16) 
		tmr->defmtime = time.mtime; 
	  #if (CLKBITS>32) 
		tmr->defutime = time.utime; 
	  #endif 
	  #endif 
		tmr->sts = S_HDR | S_ALM; 
		if (tmmode == TTM_ABS) 
			ins_abstim(tmr); 
		else 
			ins_reltim(tmr); 
	} 
	return ret_imask(); 
} 
 
#endif 
#ifdef	ALH_STS 
/****************************************/ 
/* アラームハンドラの状態を参照する     */ 
/****************************************/ 
 
ER FAR alh_sts(T_TIME FAR *p_lftime, HNO alhno) 
{ 
	T_TMR NEAR *tmr; 
	UH t; 
 
	/* 静的エラーチェック */ 
 
  #if ERC 
	if (alhno > alhno_max)				return SYSER = E_NOEXS; 
  #endif 
 
	/* ハンドラの状態を調べる */ 
 
	tmr = pALH[alhno]; 
	set_imask(); 
	if (tmr->sts == S_DMT) 
	{	ret_imask(); 
		return E_NOEXS; 
	} 
 
	t = (UH)(tmr->ltime - SYSCLK.ltime); 
	p_lftime->ltime = t; 
  #if (CLKBITS>16) 
	t = (UH)((t > tmr->ltime) ? -1: 0); 
	p_lftime->mtime = t += (UH)(tmr->mtime - SYSCLK.mtime); 
  #if (CLKBITS>32) 
	t = (UH)((t > tmr->mtime) ? -1: 0); 
	p_lftime->utime = (UH)(t + tmr->utime - SYSCLK.utime); 
  #endif 
  #endif 
 
	return ret_imask(); 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                              システム管理機能                               * 
*                                                                             * 
******************************************************************************/ 
#ifdef	GET_VER 
/****************************************/ 
/* バージョン番号を得る                 */ 
/****************************************/ 
 
ER FAR get_ver(T_VER FAR *pk_ver) 
{ 
	*pk_ver = NORTI_VER; 
	return E_OK; 
} 
 
#endif 
/****************************************************************************** 
*                                                                             * 
*                                  内部関数                                   * 
*                                                                             * 
******************************************************************************/ 
#ifdef	STA_TSK 
/****************************************/ 
/* ディスパッチ                         */ 
/****************************************/ 
 
ER NEAR nonrec dispatch(void) 
{ 
	/* 割込みハンドラ内または割込みマスク中なら */ 
	/* 遅延ディスパッチ要求を記憶し割込みマスク戻して終了 */ 
 
  #ifdef NORTiPPC 
	if (INEST || !(IMASK & 0x8000)) 
  #else 
	if (INEST || IMASK) 
  #endif 
	{	DELAY = 1; 
		return ret_imask(); 
	} 
 
	/* コンテキスト切替え */ 
 
	DELAY = 0; 
	return ctxswitch(); 
} 
 
#endif 
#ifdef	STA_TSK 
/****************************************/ 
/* スケジューラ                         */ 
/****************************************/ 
 
void NEAR nonrec C_task schedule(void) 
{ 
	T_RDQ NEAR *rdq; 
	T_TCB NEAR *tcb; 
 
	/* 最優先READYタスク選択 */ 
 
	rdq = &RDQ[1]; 
	while (rdq->qcnt == 0) 
		rdq++; 
	tcb = rdq->head; 
	RDQ[0].head = tcb; 
	NOWPRI = tcb->pri; 
} 
 
#endif 
#ifdef	STA_TSK 
/************************************/ 
/* 待ち行列からタスクを削除			*/ 
/************************************/ 
 
void NEAR nonrec _fastcall del_que(T_TCB NEAR *tcb) 
{ 
	T_TCB NEAR *tcb1; 
	T_TCB NEAR *tcb2; 
	T_RDQ NEAR *que; 
 
	/* ヘッダへのポインタを削除TCBから得る */ 
 
	que = (T_RDQ NEAR *)tcb->que; 
 
	/* 待ちタスク数−1 */ 
	/* 他のTCBが有る場合ポインタ繋ぎ替え */ 
 
	if (--que->qcnt != 0) 
	{	tcb1 = tcb->prev;			/* 削除TCBの前TCBを得る */ 
		tcb2 = tcb->next;			/* 削除TCBの次TCBを得る */ 
		tcb1->next = tcb2;			/* 前TCBの次に次TCB */ 
		tcb2->prev = tcb1;			/* 次TCBの前に前TCB */ 
		if (que->head == tcb)		/* 削除TCBが先頭なら */ 
			que->head = tcb2;		/* 次TCBが先頭TCB */ 
	} 
} 
 
#endif 
#ifdef	STA_TSK 
/************************************/ 
/* 待ち行列の末尾へタスクを追加する */ 
/************************************/ 
 
void NEAR nonrec _fastcall add_que(T_RDQ NEAR *que, T_TCB NEAR *tcb) 
{ 
	T_TCB NEAR *tcb1; 
	T_TCB NEAR *tcb2; 
 
	/* ヘッダへのポインタを追加TCBに記憶 */ 
 
	tcb->que = que; 
 
	/* 待ちタスク数+1, 他のTCBが無い場合 */ 
 
	if (que->qcnt++ == 0) 
	{	que->head = tcb;			/* 追加TCBが先頭TCB */ 
		tcb->prev = tcb;			/* 追加TCBの前は追加TCB */ 
		tcb->next = tcb;			/* 追加TCBの次も追加TCB */ 
	} 
 
	/* 他のTCBが有る場合 */ 
 
	else 
	{	tcb1 = que->head;			/* 先頭TCBを得る */ 
		tcb2 = tcb1->prev;			/* 末尾TCBを得る */ 
		tcb->prev = tcb2;			/* 追加TCBの前に末尾TCB */ 
		tcb->next = tcb1;			/* 追加TCBの次に先頭TCB */ 
		tcb1->prev = tcb;			/* 先頭TCBの前に追加TCB */ 
		tcb2->next = tcb;			/* 末尾TCBの次に追加TCB */ 
	} 
} 
 
#endif 
#ifdef	STA_TSK 
/******************************************/ 
/* 待ち行列の繋ぎ替え(del_que+add_que) */ 
/******************************************/ 
 
void NEAR nonrec _fastcall chg_que(T_RDQ NEAR *que, T_TCB NEAR *tcb) 
{ 
	T_TCB NEAR *tcb1; 
	T_TCB NEAR *tcb2; 
	T_RDQ NEAR *que2; 
 
	/* 現ヘッダへのポインタをTCBから得る */ 
 
	que2 = (T_RDQ NEAR *)tcb->que; 
 
	/* 待ちタスク数−1 */ 
	/* 他のTCBが有る場合ポインタ繋ぎ替え */ 
 
	if (--que2->qcnt != 0) 
	{	tcb1 = tcb->prev;			/* 削除TCBの前TCBを得る */ 
		tcb2 = tcb->next;			/* 削除TCBの次TCBを得る */ 
		tcb1->next = tcb2;			/* 前TCBの次に次TCB */ 
		tcb2->prev = tcb1;			/* 次TCBの前に前TCB */ 
		if (que2->head == tcb)		/* 削除TCBが先頭なら */ 
			que2->head = tcb2;		/* 次TCBが先頭TCB */ 
	} 
 
	/* 新ヘッダへのポインタをTCBに記憶 */ 
 
	tcb->que = que; 
 
	/* 待ちタスク数+1, 他のTCBが無い場合 */ 
 
	if (que->qcnt++ == 0) 
	{	que->head = tcb;			/* 追加TCBが先頭TCB */ 
		tcb->prev = tcb;			/* 追加TCBの前は追加TCB */ 
		tcb->next = tcb;			/* 追加TCBの次も追加TCB */ 
	} 
 
	/* 他のTCBが有る場合 */ 
 
	else 
	{	tcb1 = que->head;			/* 先頭TCBを得る */ 
		tcb2 = tcb1->prev;			/* 末尾TCBを得る */ 
		tcb->prev = tcb2;			/* 追加TCBの前に末尾TCB */ 
		tcb->next = tcb1;			/* 追加TCBの次に先頭TCB */ 
		tcb1->prev = tcb;			/* 先頭TCBの前に追加TCB */ 
		tcb2->next = tcb;			/* 末尾TCBの次に追加TCB */ 
	} 
} 
 
#endif 
#ifdef	STA_TSK 
/******************************************************/ 
/* 時間待ちキューへハンドラのタイマを追加(相対時刻) */ 
/******************************************************/ 
 
void NEAR nonrec _fastcall ins_reltim(T_TMR NEAR *tmr) 
{ 
	UH t; 
 
	/* 追加タイマにタイムアウト時刻を設定 */ 
 
  #if (CLKBITS>32) 
	tmr->utime = (UH)(SYSCLK.utime + tmr->defutime);	/* 上位加算 */ 
	tmr->mtime = t = (UH)(SYSCLK.mtime + tmr->defmtime);/* 中位加算 */ 
	if (t < SYSCLK.mtime) 
		tmr->utime++;									/* 上位へのキャリ */ 
	tmr->ltime = t = (UH)(SYSCLK.ltime + tmr->defltime);/* 下位加算 */ 
	if (t < SYSCLK.ltime) 
	{	if (++tmr->mtime == 0)							/* 中位へのキャリ */ 
			++tmr->utime;								/* 上位へのキャリ */ 
	} 
  #endif 
 
  #if (CLKBITS<=32)&&(CLKBITS>16) 
	tmr->mtime = (UH)(SYSCLK.mtime + tmr->defmtime);	/* 中位加算 */ 
	tmr->ltime = t = (UH)(SYSCLK.ltime + tmr->defltime);/* 下位加算 */ 
	if (t < SYSCLK.ltime) 
		++tmr->mtime;									/* 中位へのキャリ */ 
  #endif 
 
  #if (CLKBITS<=16) 
	tmr->ltime = t = (UH)(SYSCLK.ltime + tmr->defltime);/* 下位加算 */ 
  #endif 
 
	/* 時間待ちキューへ追加 */ 
 
	add_que(&TMQ[(UB)t], (T_TCB NEAR *)tmr); 
} 
 
#endif 
#ifdef	DEF_ALM 
/******************************************************/ 
/* 時間待ちキューへハンドラのタイマを追加(絶対時刻) */ 
/******************************************************/ 
 
void NEAR nonrec _fastcall ins_abstim(T_TMR NEAR *tmr) 
{ 
	UH t; 
 
	/* 追加タイマにタイムアウト時刻を設定 */ 
 
  #if (CLKBITS>32) 
	tmr->utime = tmr->defutime; 
  #endif 
  #if (CLKBITS>16) 
	tmr->mtime = tmr->defmtime; 
  #endif 
	tmr->ltime = t = tmr->defltime; 
 
	/* 時間待ちキューへ追加 */ 
 
	add_que(&TMQ[(UB)t], (T_TCB NEAR *)tmr); 
} 
 
#endif 
#ifdef	SET_WFLG 
/********************************************/ 
/* 1ワードイベントフラグの条件満足を調べる */ 
/********************************************/ 
 
UINT NEAR nonrec _fastcall tst_wflg(UINT NEAR *flgptn, UINT waiptn, UINT wfmode) 
{ 
	UINT ptn; 
 
	ptn = *flgptn; 
 
	/* OR待ちの場合のテスト */ 
 
	if (wfmode & S_ORW) 
	{	if ((ptn & waiptn) == 0) 
			return FALSE; 
	} 
 
	/* AND待ちの場合のテスト */ 
 
	else 
	{	if ((ptn & waiptn) != waiptn) 
			return FALSE; 
	} 
 
	/* クリア有の場合、イベントフラグ値をクリア */ 
 
	if (wfmode & S_CLR) 
	{ 
	  #ifdef OLDVER 
		*flgptn = ptn & ~waiptn;	/* 待ちビットのみクリア(旧仕様)*/ 
	  #else 
		*flgptn = 0; 				/* 全部のビットをクリア */ 
	  #endif 
	} 
	return ptn; 
} 
 
#endif 
/* end */