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 */