www.pudn.com > norti2.0 > NOINT.C
/****************************************************************************** * NORTi/86 インターバル割込みハンドラ・サンプル(PC9801,IBM-PC,FMR) * * * * File name : noint.c * * Copyright (c) Miyazaki System Planning Office. 1991-1995 * * * * Compile : cl /c /A? /Ox noint.c (MS-C 5.1/6.0/7.0) * * tcc -c -m? noint.c (TC 2.0, TC++ 1.0) * * bcc -c -m? -O2 noint.c (BC++ 3.x) * * * * PC9801,IBM-PC,FMR を自動機種判別して動作します。 * * CodeView 等のマルチタスクに対応しないデバッガを使う場合は、デバッガの * * メモリセットコマンド等で、変数 CodeView を 1 にセットしてください。 * * * * 91-10-25 TRCOM Version (inthdr.c) * * 92-02-16 Ver1.00 * * 92-04-30 Ver1.10β * * 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 * ******************************************************************************/ #include#include #include #include #include #include "norti.h" /* 処理系の差異の調整 */ #ifdef M_I86 /* MS-C の場合 */ #define enable _enable /* 関数名変更 */ #define disable _disable #define setvect _dos_setvect #define getvect _dos_getvect #pragma check_stack(off) /* スタックチェックなし */ #endif #ifndef _MSC_VER /* MS-C 6.0, BORLAND-C 以外では */ #ifndef __BORLANDC__ #define _fastcall pascal /* _fastcall 指定を pascal に変更 */ #endif #endif /* 割込みベクタの型 */ #ifdef __TURBOC__ typedef void interrupt (*VECT)(void); #elif (_MSC_VER>=700) typedef void (interrupt far cdecl *VECT)(); #else typedef void (interrupt far cdecl *VECT)(void); #endif /* 共通の定義 */ #define IRN_MAX 15 /* IR 番号最大値 */ /* 機種依存の定義(PC9801)*/ #define INT_IR0_98 0x08 /* IR0 割込みベクタ番号 */ #define INT_IR8_98 0x10 /* IR8 割込みベクタ番号 */ #define INT_TMR_98 0x08 /* タイマ割込みベクタ番号 */ #define I8259_98 0x00 /* 割込みコントローラ */ #define I8259_IMR_98 0x02 #define I8259S_98 0x08 /* スレーブ割込みコントローラ */ #define I8259S_IMR_98 0x0a #define I8253_0_98 0x71 /* タイマカウンタ#0 */ #define I8253_CR_98 0x77 /* タイマモード/コントロールレジスタ */ /* 機種依存の定義(IBM-PC)*/ #define INT_IR0_IBM 0x08 #define INT_IR8_IBM 0x70 #define INT_TMR_IBM 0x08 #define I8259_IBM 0x20 #define I8259_IMR_IBM 0x21 #define I8259S_IBM 0xa0 #define I8259S_IMR_IBM 0xa1 #define I8253_0_IBM 0x40 #define I8253_CR_IBM 0x43 /* 機種依存の定義(FMR)*/ #define INT_IR0_FMR 0x40 #define INT_IR8_FMR 0x48 #define INT_TMR_FMR 0x40 #define I8259_FMR 0x00 #define I8259_IMR_FMR 0x02 #define I8259S_FMR 0x10 #define I8259S_IMR_FMR 0x12 #define I8253_0_FMR 0x40 #define I8253_CR_FMR 0x46 /* 外部変数 */ UB near cdecl CodeView = 0; UINT near INT_IR0 = INT_IR0_98; UINT near INT_IR8 = INT_IR8_98; UINT near INT_TMR = INT_TMR_98; INT near I8259 = I8259_98; INT near I8259_IMR = I8259_IMR_98; INT near I8259S = I8259S_98; INT near I8259S_IMR = I8259S_IMR_98; INT near I8253_0 = I8253_0_98; INT near I8253_CR = I8253_CR_98; /* 内部変数 */ static BOOL near PC9801_; /* PC9801判定フラグ */ static BOOL near IBM_PC_; /* IBM-PC判定フラグ */ static BOOL near FMR_; /* FMR-70/60/50判定フラグ */ static VECT near bios_tmr; /* BIOSタイマ割込みルーチンアドレス */ static UB near use_mask[2]; /* 使用する割込みの割込みマスク */ static UB near mask_bak[2]; /* 割込みマスク待避 */ /* マスクパターン */ static UB near masks[16] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static UB near neg_masks[16] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; /* 内部関数 */ INTHDR inthdr_98(void); /* インターバル割込みハンドラ(PC9801)*/ INTHDR inthdr_ibm(void); /* インターバル割込みハンドラ(IBM-PC)*/ INTHDR inthdr_fmr(void); /* インターバル割込みハンドラ(FMR)*/ /***************************************************************************** * 割込み初期化(ユーザ定義カーネル内部関数) * * 形式 intini(); * * 解説 カーネルの初期化ルーチン(sysini)から割込み禁止状態で呼び出されます。 * このパソコン用の例題では機種判別を行っていますが、ROM 化では割込みコ * ントローラ等の初期化を行うとよいでしょう。 ******************************************************************************/ void far cdecl intini(void) { static BOOL judged = FALSE; if (!judged) { judged = TRUE; judgepc(); /* パソコン機種判別 */ /* IBM-PC の場合 */ if (IBM_PC_) { INT_IR0 = INT_IR0_IBM; INT_IR8 = INT_IR8_IBM; INT_TMR = INT_TMR_IBM; I8259 = I8259_IBM; I8259_IMR = I8259_IMR_IBM; I8259S = I8259S_IBM; I8259S_IMR = I8259S_IMR_IBM; I8253_0 = I8253_0_IBM; I8253_CR = I8253_CR_IBM; } /* FMR の場合 */ else if (FMR_) { INT_IR0 = INT_IR0_FMR; INT_IR8 = INT_IR8_FMR; INT_TMR = INT_TMR_FMR; I8259 = I8259_FMR; I8259_IMR = I8259_IMR_FMR; I8259S = I8259S_FMR; I8259S_IMR = I8259S_IMR_FMR; I8253_0 = I8253_0_FMR; I8253_CR = I8253_CR_FMR; } } } /***************************************************************************** * 割込みハンドラを定義する(ユーザ定義システムコール) * * 形式 ercd = def_int(intno, inthdr); * * UINT intno; 割込みベクタ番号 * INTHDRP inthdr; 割込みハンドラアドレス * ER ercd; エラーコード * * 解説 intno に対応する割込みベクタテーブルに、inthdr を設定します。 * * (注) 排他制御なしに、getvect, setvect(DOSファンクション)を実行します。 ******************************************************************************/ ER pascal def_int(UINT intno, INTHDRP inthdr) { static VECT oldvec[IRN_MAX+1]; /* 元の割込みベクタ */ UINT psw; UINT i; UB FAR *p; /* ベクタ番号→割込み番号(0〜) */ if (intno < INT_IR8) i = intno - INT_IR0; else i = intno - INT_IR8 + 8; /* エラーチェック */ if (i > IRN_MAX) return E_PAR; /* CPU割込み禁止 */ psw = vdis_psw(); /* 定義解除の場合 */ /* 元の割込みベクタ復元 */ if (inthdr == (INTHDRP)NADR) { if (oldvec[i] != NULL) setvect(intno, oldvec[i]); if (i < 8) use_mask[0] &= neg_masks[i]; else use_mask[1] &= neg_masks[i]; } /* 定義の場合 */ /* 元の割込みベクタ保存してから、新しい割込みベクタ設定 */ else { if (oldvec[i] == NULL) oldvec[i] = getvect(intno); p = (UB FAR *)((W)inthdr); while (*p != 0x9a && *p != 0x0e) /* CALLF または PUSH CS 命令さがす */ p++; setvect(intno, (VECT)((W)p)); if (i < 8) use_mask[0] |= masks[i]; else use_mask[1] |= masks[i]; } /* CPU割込み禁止戻す */ vset_psw(psw); return E_OK; } /***************************************************************************** * 割込みを禁止する(ユーザ定義システムコール) * * 形式 ercd = dis_int(intno); * * UINT intno; 割込み許可番号(= 割込みベクタ番号) * ER ercd; エラーコード * * 解説 intno に対応する割込みコントローラの割込みマスクをセットします。 ******************************************************************************/ ER pascal dis_int(UINT intno) { UINT psw; UINT i; /* ベクタ番号→割込み番号(0〜) */ if (intno < INT_IR8) i = intno - INT_IR0; else i = intno - INT_IR8 + 8; /* エラーチェック */ if (i > IRN_MAX) return E_PAR; /* CPU割込み禁止 */ psw = vdis_psw(); /* 0〜7なら、マスタ割込みコントローラのマスクセット */ if (i < 8) outp(I8259_IMR, inp(I8259_IMR) | masks[i]); /* 8〜15なら、スレーブ割込みコントローラのマスクセット */ else outp(I8259S_IMR, inp(I8259S_IMR) | masks[i]); /* CPU割込み禁止戻す */ vset_psw(psw); return E_OK; } /***************************************************************************** * 割込みを許可する(ユーザ定義システムコール) * * 形式 ercd = ena_int(intno); * * UINT intno; 割込みベクタ番号 * ER ercd; エラーコード * * 解説 intno に対応する割込みコントローラの割込みマスクをクリアします。 ******************************************************************************/ ER pascal ena_int(UINT intno) { UINT psw; UINT i; /* ベクタ番号→割込み番号(0〜) */ if (intno < INT_IR8) i = intno - INT_IR0; else i = intno - INT_IR8 + 8; /* エラーチェック */ if (i > IRN_MAX) return E_PAR; /* CPU割込み禁止 */ psw = vdis_psw(); /* 0〜7なら、マスタ割込みコントローラのマスククリア */ if (i < 8) outp(I8259_IMR, inp(I8259_IMR) & neg_masks[i]); /* 8〜15なら、スレーブ割込みコントローラのマスククリア */ else outp(I8259S_IMR, inp(I8259S_IMR) & neg_masks[i]); /* CPU割込み禁止戻す */ vset_psw(psw); return E_OK; } /***************************************************************************** * 割込みコントローラ割込みマスク(ユーザ定義カーネル内部関数) * * 形式 vdis_pic(); * * 解説 割込みコントローラ対応カーネルから割込み禁止状態で呼び出されます。 * 割込みコントローラの、割込みハンドラで使用している全割込みマスクをセッ * トします。 * 割込みコントローラ対応カーネルを使わない場合は、定義不要です。 ******************************************************************************/ void far pascal vdis_pic(void) { UB c; /* マスタ割込みコントローラ */ c = (UB)inp(I8259_IMR); outp(I8259_IMR, c | use_mask[0]); mask_bak[0] = (UB)(c & use_mask[0]); /* スレーブ割込みコントローラ */ if (use_mask[1] != 0) { c = (UB)inp(I8259S_IMR); outp(I8259S_IMR, c | use_mask[1]); mask_bak[1] = (UB)(c & use_mask[1]); } } /***************************************************************************** * 割込みコントローラ割込みマスク解除(ユーザ定義カーネル内部関数) * * 形式 vena_pic(); * * 解説 割込みコントローラ対応カーネルから割込み禁止状態で呼び出されます。 * vdis_pic で禁止した割込みマスクを復元します。 * 割込みコントローラ対応カーネルを使わない場合は、定義不要です。 ******************************************************************************/ void far pascal vena_pic(void) { UB c; /* マスタ割込みコントローラ */ c = (UB)inp(I8259_IMR); c &= ~use_mask[0]; outp(I8259_IMR, c | mask_bak[0]); /* スレーブ割込みコントローラ */ if (use_mask[1] != 0) { c = (UB)inp(I8259S_IMR); c &= ~use_mask[1]; outp(I8259S_IMR, c | mask_bak[1]); } } /***************************************************************************** * 機種判別 * * 入力ポート 20H, 21H のデータにより機種を判別し、内部フラグ PC9801_, IBM_PC_, * FMR_ のいずれかをセットします。 * 判別できた場合は、戻値に TRUE を返します。 * 判別できない場合は、それらしい機種をセットして、戻値に FALSE を返します。 * * ポート 機種 内容 記事 * --------------------------------------------------------------------------- * 20H READ IBM-PC 8259割込要求レジスタ 全割込要求 FFH は有り得ない * 21H READ IBM-PC 8259割込マスクレジスタ 全割込マスク FFH は有り得ない * --------------------------------------------------------------------------- * 20H READ FMR リセット要因レジスタ 2度読めば要因 b7,b1,b0 = 0 のはず * 21H READ FMR 空き FFH のはず * --------------------------------------------------------------------------- * 20H READ PC9801 空き(WRITEはカレンダ時計) FFH のはず * 21H READ PC9801 空き 不明(FFHまたはイメージ) * * 判定結果は、ispc9801, isibmpc, isfmr 関数により参照できます。 ******************************************************************************/ BOOL cdecl judgepc(void) { UB p20, p21; BOOL ok = FALSE; p20 = (UB)inp(0x20); p20 = (UB)inp(0x20); /* 二度読み */ p21 = (UB)inp(0x21); if (p20 != 0xff && p21 != 0xff) { IBM_PC_ = TRUE; ok = TRUE; } else if ((p20 & ~0x7c) == 0x00) { FMR_ = TRUE; if (p21 == 0xff) ok = TRUE; } else { PC9801_ = TRUE; if (p20 == 0xff) ok = TRUE; } #ifdef MSG if (!ok) printf("\a""Unknown PC!! %02X %02X\n", p20, p21); #endif return ok; } BOOL cdecl ispc9801(void) { return PC9801_; } BOOL cdecl isibmpc(void) { return IBM_PC_; } BOOL cdecl isfmr(void) { return FMR_; } /***************************************************************************** * インターバルタイマ起動 * * 機種判別結果に基づいて、インターバル割込み用のタイマを起動します。 * 周期を MSEC マクロの値により求め、タイマカウンタの時定数を設定します。 * なお、IBM-PC と FMR ではこのタイマを BIOS が使っていることを考慮する必要が * あります。 * MSG というマクロを定義すれば、起動情報を printf します。 ******************************************************************************/ void cdecl intsta(void) { W tc; #ifdef MSG B *pctype; if (IBM_PC_) pctype = "IBM-PC"; else if (FMR_) pctype = "FMR"; else pctype = "PC9801"; printf("%s inthdr is defined. (Hook INT %02XH, Interval %dms)\n", pctype, INT_TMR, MSEC); #endif dis_int(INT_TMR); /* 割込みコントローラマスク */ /* CTRL-C でタイマ終了できるように */ atexit(intext); /* exitにタイマ終了関数を登録 */ signal(SIGINT, exit); /* CTRL-Cでexit */ /* 割込みチェインの準備 */ bios_tmr = getvect(INT_TMR); /* タイマ割込み起動(IBM-PC)*/ if (isibmpc()) { def_int(INT_TMR, inthdr_ibm); /* タイマ割込みベクタ設定 */ outp(I8253_CR, 0x36); /* カウンタ#0をモード3で使用 */ tc = (119318L * MSEC) / 100; /* 時定数を求める */ outp(I8253_0, (int)tc); /* 時定数下位 */ outp(I8253_0, (int)tc >> 8); /* 時定数上位 */ } /* タイマ割込み起動(FMR)*/ else if (isfmr()) { def_int(INT_TMR, inthdr_fmr); /* タイマ割込みベクタ設定 */ outp(I8253_CR, 0x36); /* カウンタ#0をモード3で使用 */ #if (MSEC!=10) /* 10msec周期なら変更不要 */ tc = (3072L * MSEC) / 10; /* 時定数を求める */ outp(I8253_0, (int)tc); /* 時定数下位 */ outp(I8253_0, (int)tc >> 8); /* 時定数上位 */ #endif } /* タイマ割込み起動(PC9801)*/ else { def_int(INT_TMR, inthdr_98); /* タイマ割込みベクタ設定 */ outp(I8253_CR, 0x36); /* カウンタ#0をモード3で使用 */ if (*(B far *)0x00500001L & 0x80) /* BIOSワークエリアを参照 */ tc = (19968L * MSEC) / 10; /* 8MHz系の時定数を求める */ else tc = (24576L * MSEC) / 10; /* 10MHz系の時定数を求める */ outp(I8253_0, (int)tc); /* 時定数下位 */ outp(I8253_0, (int)tc >> 8); /* 時定数上位 */ } ena_int(INT_TMR); /* 割込みコントローラマスク解除 */ } /***************************************************************************** * インターバルタイマ起動(CodeView対応) * * CodeView フラグ をセットする他は、intsta 関数と同じです。 * intsta 関数の方を使用しておき、デバッガのコマンドで、実行時に CodeView フ * ラグをセットしても構いません。 * このフラグがセットされた場合は、ユーザコード外でのインターバル割込みで何 * も実行しません。 * すなわち、CodeView を実行中に、インターバル割込みによるタスク切り換えが発 * 生しないので、マルチタスク非対応デバッガとの排他制御の問題が回避できます。 * ただし、DOS や BIOS や子プロセスの実行中にも、インターバル割込みが無視さ * れるので、あくまでデバッグ用の機能です。 ******************************************************************************/ void cdecl intsta2(void) { CodeView = 1; intsta(); } /***************************************************************************** * インターバルタイマ終了 * * インターバルタイマ割込みを停止させ、タイマを既定の状態に戻します。 * intsta 関数で atexit してあるので、ユーザが特に呼び出す必要はありません。 * * デバッガを用いている場合、タイマ割込みを止めずにデバッガを終了すると暴走し * てしまいます。PATRNER では、G=exit で本関数を実行させ、タイマ割込みを止め * て終了することができます。 ******************************************************************************/ void cdecl intext(void) { dis_int(INT_TMR); /* 割込みコントローラマスク */ def_int(INT_TMR, (INTHDRP)NADR);/* タイマ割込みベクタ復元 */ /* IBM-PC の場合 */ if (isibmpc()) { outp(I8253_CR, 0x36); /* カウンタ#0はモード3のまま */ outp(I8253_0, 0); /* 時定数を元に戻す */ outp(I8253_0, 0); ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ } /* FMR の場合 */ else if (isfmr()) { #if (MSEC!=10) /* 10msec周期の場合復元不要 */ outp(I8253_CR, 0x36); /* カウンタ#0はモード3のまま */ outp(I8253_0, 3072); /* 時定数を元に戻す */ outp(I8253_0, 3072 >> 8); #endif ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ } /* PC9801 の場合 */ else { outp(I8253_CR, 0x30); /* カウンタ#0をモード0に戻す */ } } /***************************************************************************** * インターバル割込みハンドラ(PC9801) * * PC9801 のタイマは、インターバルタイマ設定 BIOS を利用しなければ、通常は空い * ています。マルチタスク下でこの BIOS 機能を使う必要はないので、BIOS のことは * 考慮していません。 ******************************************************************************/ INTHDR inthdr_98(void) { #ifdef NOCV ent_int(); /* 割込みハンドラ開始 */ #else if (ent_int2() != 0 /* プログラムの外にいて */ && CodeView != 0) /* CodeView フラグ立っている場合は */ { outp(I8259, 0x20); /* EOI のみ発行して */ ret_int(); /* 割込みハンドラ終了 */ } #endif dis_int(INT_TMR); /* 割込みコントローラマスク */ outp(I8259, 0x20); /* 先にEOI発行 */ enable(); /* 多重割込み許可 */ intent(); /* インターバルタイマ処理 */ disable(); /* 多重割込み禁止 */ ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ ret_int(); /* 割込みハンドラ終了 */ } /***************************************************************************** * インターバル割込みハンドラ(IBM-PC) * * IBM-PC のタイマは、BIOS で、約 54.93msec 周期の割込みを常時発生させるために * 使われています。そこで、54.93msec に1回、BIOS のタイマ割込み処理を呼び出し * て BIOS の機能を維持します。 * BIOSのタイマ割込みでは、FDD のモータを止める等の処理を行っています。 ******************************************************************************/ static void near ibm_bios_tmr(void) { static UH near cnt; if ((cnt += MSEC*100) >= 5493) /* 54.93msecに1回 */ { cnt -= 5493; (*bios_tmr)(); /* BIOSタイマ割込み処理を実行 */ } else /* 元の処理を実行しない場合は */ outp(I8259, 0x20); /* EIO発行 */ } INTHDR inthdr_ibm(void) { #ifdef NOCV ent_int(); /* 割込みハンドラ開始 */ #else if (ent_int2() != 0 /* プログラムの外にいて */ && CodeView != 0) /* CodeView フラグ立っている場合は */ { ibm_bios_tmr(); /* BIOS タイマ処理のみ実行して */ ret_int(); /* 割込みハンドラ終了 */ } #endif ibm_bios_tmr(); /* BIOS タイマ処理 */ dis_int(INT_TMR); /* 割込みコントローラマスク */ enable(); /* 多重割込み許可 */ intent(); /* インターバルタイマ処理 */ disable(); /* 多重割込み禁止 */ ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ ret_int(); /* 割込みハンドラ終了 */ } #if 0 static void near inthdr_ibm_(int cs) { static UH near cnt = 0; dis_int(INT_TMR); /* 割込みコントローラマスク */ if ((cnt += MSEC*100) >= 5493) /* 54.93msecに1回 */ { cnt -= 5493; (*bios_tmr)(); /* BIOSタイマ割込み処理を実行 */ dis_int(INT_TMR); /* 割込みコントローラマスク */ } else /* 元の処理を実行しない場合は */ outp(I8259, 0x20); /* EIO発行 */ enable(); if (cs == 0 || CodeView == 0) intent(); /* インターバルタイマ処理 */ disable(); ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ } INTHDR inthdr_ibm(void) { #ifdef NOCV ent_int(); inthdr_ibm_(0); #else inthdr_ibm_(ent_int2()); #endif ret_int(); } #endif /***************************************************************************** * インターバル割込みハンドラ(FMR) * * FMR のタイマは、IBM-PC と同じように、10msec 周期の割込みを常時発生させるた * めに使われています。そこで10msecに1回、BIOS のタイマ割込み処理を呼び出して * BIOS の機能を維持します。 ******************************************************************************/ static void near fmr_bios_tmr(void) { #if (MSEC==10) (*bios_tmr)(); #else static UH near cnt; if ((cnt += MSEC*100) >= 1000) /* 10msecに1回 */ { cnt -= 1000; (*bios_tmr)(); /* BIOSタイマ割込み処理を実行 */ } else /* 元の処理を実行しない場合は */ { outp(0x60, ((inp(0x60)>>2)&0x07)|0x80); outp(I8259, 0x20); /* 割込制御レジスタ操作してEIO発行 */ } #endif } INTHDR inthdr_fmr(void) { #ifdef NOCV ent_int(); /* 割込みハンドラ開始 */ #else if (ent_int2() != 0 /* プログラムの外にいて */ && CodeView != 0) /* CodeView フラグ立っている場合は */ { fmr_bios_tmr(); /* BIOS タイマ処理のみ実行して */ ret_int(); /* 割込みハンドラ終了 */ } #endif fmr_bios_tmr(); /* BIOS タイマ処理 */ dis_int(INT_TMR); /* 割込みコントローラマスク */ enable(); /* 多重割込み許可 */ intent(); /* インターバルタイマ処理 */ disable(); /* 多重割込み禁止 */ ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ ret_int(); /* 割込みハンドラ終了 */ } #if 0 static void near inthdr_fmr_(int cs) { static UH near cnt = 0; dis_int(INT_TMR); /* 割込みコントローラマスク */ if ((cnt += MSEC*100) >= 1000) /* 10msecに1回 */ { cnt -= 1000; (*bios_tmr)(); /* BIOSタイマ割込み処理を実行 */ dis_int(INT_TMR); /* 割込みコントローラ再マスク */ } else /* 元の処理を実行しない場合は */ { outp(0x60, ((inp(0x60)>>2)&0x07)|0x80); outp(I8259, 0x20); /* 割込制御レジスタ操作してEIO発行 */ } enable(); if (cs == 0 || CodeView == 0) intent(); /* インターバルタイマ処理 */ disable(); ena_int(INT_TMR); /* 割込みコントローラのマスク解除 */ } INTHDR inthdr_fmr(void) { #ifdef NOCV ent_int(); inthdr_fmr_(0); #else inthdr_fmr_(ent_int2()); #endif ret_int(); } #endif /* end */