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