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


/****************************************************************************** 
* NORTiオブジェクトモニタ・サンプル(PC9801,IBM-PC,FMR,ROM)              * 
*                                                                             * 
*  File name : nomon.c                                                        * 
*  Copyright (c) Miyazaki System Planning Office. 1991-1995                   * 
*                                                                             * 
*  Compile : cl /c /A? /Ox nomon.c   (MS-C 5.1/6.0/7.0)                       * 
*            tcc -c -m? nomon.c      (TC 2.0, TC++ 1.0)                       * 
*            bcc -c -m? -O2 nomon.c  (BC++ 3.x)                               * 
*                                                                             * 
* 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-20 Ver1.21                                                            * 
******************************************************************************/ 
 
#if 0 
 
・下記のマクロを定義することで、コンパイルを制御できます。 
 
  CLKS=? ・・・ システムクロック・モニタ数(0〜1,デフォルト1) 
  RDQS=? ・・・ レディキュー・モニタ数    (0〜1,デフォルト1) 
  TSKS=? ・・・ タスク・モニタ数          (0〜 ,デフォルト6) 
  FLGS=? ・・・ イベントフラグ・モニタ数  (0〜 ,デフォルト2) 
  SEMS=? ・・・ セマフォ・モニタ数        (0〜 ,デフォルト2) 
  MBXS=? ・・・ メイルボックス・モニタ数  (0〜 ,デフォルト2) 
  MPLS=? ・・・ メモリプール・モニタ数    (0〜 ,デフォルト2) 
 
  TIM=? ・・・・ オブジェクトモニタ用タイマハンドラ周期(0〜,MSEC単位,デフォルト1) 
  ROM ・・・・・・ 画面出力しない(ROM化等) 
  NOSPL ・・・・ PC9801で画面分割しない 
 
 (例) cl /c /Ox /DTSKS=14 /DFLGS=0 /DSEMS=0 /DMBXS=0 /DMPLS=0 /DROM nomon.c 
      tcc -c    -DTSKS=14 -DFLGS=0 -DSEMS=0 -DMBXS=0 -DMPLS=0 -DROM nomon.c 
 
・画面出力の形式 
 
CLK  RDQ1 TSK1 TSK2 TSK3 TSK4 TSK5 TSK6 FLG1 FLG2 SEM1 SEM2 MBX1 MBX2 MPL1 MPL2 
.... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... 
.... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... 
 
・オブジェクトモニタバッファの形式 
 
  extern B NEAR monbuf[]; ・・・・・ ASCIIZ文字列の配列 
 
  monbuf+0x00 'CLK  .... .... ',0 
        +0x10 'RDQ1 .... .... ',0 
        +0x20 'TSK1 .... .... ',0 
        +0x30 'TSK2 .... .... ',0 
        +0x40 'TSK3 .... .... ',0 
          : 
        +0xf0 'MPL2 .... .... ',0,0 
 
#endif 
 
#ifdef	M_I86	/* MS-C */ 
#include  
#include  
#include  
#include  
#endif 
 
#ifdef	__TURBOC__ 
#include  
#include  
#include  
#endif 
 
#if (defined(_MCC68K)||defined(__TID__)||defined(__CPU__)) 
#include 			  /* ICC */		/* Hitachi C */ 
#undef	ROM 
#define	ROM 
#endif 
 
#ifdef	LSI_C80 
#include  
#undef	ROM 
#define	ROM 
#endif 
 
#define	NOMON_C 
#include "norti.h" 
#include "nosys.h" 
 
#ifdef	M_I86 
#pragma check_stack(off)	/* MS-C スタックチェックなし */ 
#endif 
 
#ifndef	NULL 
#define	NULL		0		/* NULLポインタ */ 
#endif 
 
/* モニタする個数の定義 */ 
 
#ifndef	CLKS 
#define	CLKS		1		/* システムクロック・モニタ数 */ 
#endif 
#ifndef	RDQS 
#define	RDQS		1		/* レディキュー・モニタ数 */ 
#endif 
#ifndef	TSKS 
#define	TSKS		6		/* タスク・モニタ数 */ 
#endif 
#ifndef	FLGS 
#define	FLGS		2		/* イベントフラグ・モニタ数 */ 
#endif 
#ifndef	SEMS 
#define	SEMS		2		/* セマフォ・モニタ数 */ 
#endif 
#ifndef	MBXS 
#define	MBXS		2		/* メイルボックス・モニタ数 */ 
#endif 
#ifndef	MPLS 
#define	MPLS		2		/* メモリプール・モニタ数 */ 
#endif 
 
/* モニタする個数の合計 */ 
 
#define	TOTAL	(CLKS+RDQS+TSKS+FLGS+SEMS+MBXS+MPLS) 
#if (TOTAL<16) 
#define	OBJS		16		/* 最低16個 */ 
#else 
#define	OBJS		TOTAL 
#endif 
 
/* その他の定義 */ 
 
#ifndef	TIM 
#define	TIM			1		/* タイマハンドラ周期(MSEC単位)*/ 
#endif 
 
/* 定義されている変数 */ 
 
B NEAR cdecl monbuf[(OBJS+1)*16];	/* オブジェクトモニタ・バッファ */ 
 
/* 定義されている関数 */ 
 
TMRHDR montmr(void);			/* オブジェクトモニタ・ハンドラ */ 
void cdecl monext(void);		/* オブジェクトモニタ終了 */ 
void cdecl monsta(void);		/* オブジェクトモニタ起動 */ 
BOOL cdecl set_montsk(ID id);	/* モニタする先頭タスクIDを設定 */ 
BOOL cdecl set_monflg(ID id);	/* モニタする先頭イベントフラグIDを設定 */ 
BOOL cdecl set_monsem(ID id);	/* モニタする先頭セマフォIDを設定 */ 
BOOL cdecl set_monmbx(ID id);	/* モニタする先頭メイルボックスIDを設定 */ 
BOOL cdecl set_monmpl(ID id);	/* モニタする先頭メモリプールIDを設定 */ 
 
/* 直書きするVRAMアドレス(PC9801)*/ 
 
#ifdef	NOSPL 
#define	VRAM_98	0xa0000000L		/* 画面分割しない場合はテキストVRAM先頭 */ 
#else 
#define	VRAM_98	0xa00010a0L		/* 画面分割する場合は裏テキストVRAM */ 
#endif							/*(日本語FEPの使う領域を避けて+0xa0)*/ 
 
/* 内部変数 */ 
 
#ifndef	ROM 
static W NEAR vram = VRAM_98;	/* モニタ画面のVRAMアドレス */ 
static B NEAR videobuf[80*3];	/* 画面出力バッファ */ 
#endif 
static ID NEAR mon_tskid = 1;	/* モニタする先頭タスクID */ 
static ID NEAR mon_flgid = 1;	/* モニタする先頭イベントフラグID */ 
static ID NEAR mon_semid = 1;	/* モニタする先頭セマフォID */ 
static ID NEAR mon_mbxid = 1;	/* モニタする先頭メイルボックスID */ 
static ID NEAR mon_mplid = 1;	/* モニタする先頭メモリプールID */ 
static UB NEAR montmr_cnt;		/* タイマハンドラ内部のカウンタ */ 
 
/* 1桁16進変換マクロ(0〜9,a〜f)*/ 
 
#define	ito1x(p,i) (*(p)=(B)((((i)&15)<10)?('0'+((i)&15)):('a'-10+((i)&15)))) 
 
/* 1桁ID変換マクロ(0〜9,A〜無制限)*/ 
 
#define	ito1id(p,i)	(*(p)=(B)((i<10)?('0'+i):('A'-10+(i)))) 
 
/***************************************************************************** 
* INT型の16進ASCII変換 
* 
******************************************************************************/ 
 
static void NEAR ito04x(B NEAR *p, int i) 
{ 
	ito1x(p++, i>>12); 
	ito1x(p++, i>>8 ); 
	ito1x(p++, i>>4 ); 
	ito1x(p,   i    ); 
} 
 
/***************************************************************************** 
* オブジェクトモニタ・バッファ初期化 
* 
******************************************************************************/ 
 
static void NEAR init_monbuf(void) 
{ 
	B NEAR *p; 
	INT i; 
 
  #ifndef ROM 
	memset(videobuf, ' ', sizeof videobuf); 
  #endif 
 
	memset(monbuf, '\0', sizeof monbuf); 
	for (i = 0; i < OBJS; i++) 
	{	memset(monbuf + i * 16, ' ', 15); 
	} 
 
	p = monbuf; 
 
  #if CLKS 
	memcpy(p, "CLK", 3); 
	p += 16; 
  #endif 
 
  #if RDQS 
	memcpy(p, "RDQ", 3); 
	p += 16; 
  #endif 
 
  #if TSKS 
	for (i = TSKS; i != 0; i--) 
	{	memcpy(p, "TSK", 3); 
		p += 16; 
	} 
  #endif 
 
  #if FLGS 
	for (i = FLGS; i != 0; i--) 
	{	memcpy(p, "FLG", 3); 
		p += 16; 
	} 
  #endif 
 
  #if SEMS 
	for (i = SEMS; i != 0; i--) 
	{	memcpy(p, "SEM", 3); 
		p += 16; 
	} 
  #endif 
 
  #if MBXS 
	for (i = MBXS; i != 0; i--) 
	{	memcpy(p, "MBX", 3); 
		p += 16; 
	} 
  #endif 
 
  #if MPLS 
	for (i = MPLS; i != 0; i--) 
	{	memcpy(p, "MPL", 3); 
		p += 16; 
	} 
  #endif 
} 
 
#if CLKS 
/***************************************************************************** 
* システムクロック状態モニタ 
* 
* CLK 
* xxxx  システム時刻下位(16進) 
* iiii  時間待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monclk(B NEAR *p) 
{ 
	/* 2行目の出力データ作成 */ 
 
	p += 5; 
	ito04x(p, SYSCLK.ltime); 
 
	/* 3行目の出力データ作成 */ 
 
	p += 5; 
	ito04x(p, SYSCLK.mtime); 
} 
 
#endif 
#if RDQS 
/***************************************************************************** 
* レディキュー状態モニタ 
* 
* RDQ?  ? = 最高優先度 
* iiii  最高優先度の実行待ちタスクIDの並び 
* jjjj  次の優先度の実行待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monrdq(B NEAR *p) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	T_RDQ NEAR *rdq;	/* レディキューへのポインタ */ 
	TPRI pri; 
	INT i, j; 
 
	/* 1行目の出力データ作成 */ 
 
	pri = 1; 
	rdq = &RDQ[1]; 
	while (rdq->qcnt == 0) 
	{	pri++; 
		rdq++; 
	} 
	ito1id(p+3, pri); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, ".... ....", 9); 
 
	/* 2行目の出力データ作成 */ 
 
	j = rdq->qcnt; 
	tcb = rdq->head; 
	for (i = 0; i < 4; i++) 
	{	ito1id(p+i, tcb->tid); 
		if (--j == 0) 
			break; 
		tcb = tcb->next; 
	} 
 
	/* 3行目の出力データ作成 */ 
 
	if (pri < tpri_max) 
	{ 
		p += 5; 
		rdq++; 
		while (rdq->qcnt == 0) 
		{	rdq++; 
		} 
		j = rdq->qcnt; 
		tcb = rdq->head; 
		for (i = 0; i < 4; i++) 
		{	ito1id(p+i, tcb->tid); 
			if (--j == 0) 
				break; 
			tcb = tcb->next; 
		} 
	} 
} 
 
#endif 
#if TSKS 
/***************************************************************************** 
* タスク状態モニタ 
* 
* TSK?  ? = タスクID 
* sssp  sss = タスク状態, p = 優先度(run, rdy 時) 
* xxxx  起床要求カウント等 
******************************************************************************/ 
 
static void NEAR montsk(B NEAR *p, ID id) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	INT c; 
 
	/* 1行目の出力データ作成 */ 
 
	ito1id(p+3, id); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, "rdy  ....", 9); 
 
	/* タスク未生成の場合 */ 
 
	tcb = pTCB[id]; 
	if (id > tskid_max || tcb->tid == 0) 
	{	p[0] = 'n'; p[1] = 'o'; p[2] = 'n'; 
		return; 
	} 
 
	/* 2,3行目の出力データ作成(SUSPENDの場合) */ 
 
	if ((c = tcb->suscnt) != 0) 
	{ 
		switch (tcb->sts) 
		{ 
		case S_DMT: 
			p[0] = 'd'; p[1] = 'm'; p[2] = 't'; 
			break; 
 
		case S_RDY: 
			p[0] = 's'; p[1] = 'u'; p[2] = 's'; 
			ito04x(p+5, c);			/* 強制待ち要求カウント */ 
			break; 
 
		default: 
			p[0] = 'w'; p[1] = 'a'; p[2] = 's'; 
			ito04x(p+5, c);			/* 強制待ち要求カウント */ 
			break; 
		} 
	} 
 
	/* 2,3行目の出力データ作成(SUSPENDでない場合) */ 
 
	else 
	{ 
		switch (tcb->sts) 
		{ 
		case S_DMT: 
			p[0] = 'd'; p[1] = 'm'; p[2] = 't'; 
			break; 
 
		case S_SLP: 
			p[0] = 's'; p[1] = 'l'; p[2] = 'p'; 
			break; 
 
		case S_WAI: 
			p[0] = 'w'; p[1] = 'a'; p[2] = 'i'; 
			break; 
 
		case S_MPL: 
			p[0] = 'm'; p[1] = 'p'; p[2] = 'l'; 
			break; 
 
		case S_SEM: 
			p[0] = 's'; p[1] = 'e'; p[2] = 'm'; 
			break; 
 
		case S_MBX: 
			p[0] = 'm'; p[1] = 'b'; p[2] = 'x'; 
			break; 
 
		case S_RDY: 
			if (tcb == RDQ[0].head) 
			{	p[1] = 'u'; p[2] = 'n'; 
			} 
			ito1id(p+3, tcb->pri);		/* 優先度 */ 
			if ((c = tcb->wupcnt) != 0) 
				ito04x(p+5, c);			/* 起床要求カウント */ 
			break; 
 
		default: 
			p[0] = 'f'; p[1] = 'l'; p[2] = 'g'; 
			ito04x(p+5, tcb->waiptn);	/* 待ちパターン */ 
			break; 
		} 
	} 
} 
 
#endif 
#if FLGS 
/***************************************************************************** 
* イベントフラグ状態モニタ 
* 
* FLG?  ? = イベントフラグID 
* xxxx  イベントフラグパターン 
* iiii  イベントフラグ待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monflg(B NEAR *p, ID id) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	T_FLG NEAR *flg;	/* イベントフラグへのポインタ */ 
	INT i, j, c; 
 
	/* 1行目の出力データ作成 */ 
 
	ito1id(p+3, id); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, ".... ....", 9); 
 
	/* 2行目の出力データ作成 */ 
 
	if (id > flgid_max) 
	{	memcpy(p, "non ", 4); 
		return; 
	} 
	flg = &FLG[id]; 
 
	if ((c = (INT)flg->ptn) != 0) 
		ito04x(p, c);				/* イベントフラグ値 */ 
 
	/* 3行目の出力データ作成 */ 
 
	p += 5; 
	if ((j = flg->qcnt) != 0) 
	{	tcb = flg->head; 
		for (i = 0; i < 4; i++) 
		{	ito1id(p+i, tcb->tid); 
			if (--j == 0) 
				break; 
			tcb = tcb->next; 
		} 
	} 
} 
 
#endif 
#if SEMS 
/***************************************************************************** 
* セマフォ状態モニタ 
* 
* SEM?  ? = セマフォID 
* xxxx  セマフォカウント値 
* iiii  セマフォ待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monsem(B NEAR *p, ID id) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	T_SEM NEAR *sem;	/* セマフォへのポインタ */ 
	INT i, j, c; 
 
	/* 1行目の出力データ作成 */ 
 
	ito1id(p+3, id); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, ".... ....", 9); 
 
	/* 2行目の出力データ作成 */ 
 
	if (id > semid_max) 
	{	memcpy(p, "non ", 4); 
		return; 
	} 
	sem = &SEM[id]; 
 
	if ((c = sem->cnt) != 0) 
		ito04x(p, c);			/* セマフォカウント値 */ 
 
	/* 3行目の出力データ作成 */ 
 
	p += 5; 
	if ((j = sem->qcnt) != 0) 
	{	tcb = sem->head; 
		for (i = 0; i < 4; i++) 
		{	ito1id(p+i, tcb->tid); 
			if (--j == 0) 
				break; 
			tcb = tcb->next; 
		} 
	} 
} 
 
#endif 
#if MBXS 
/***************************************************************************** 
* メールボックス状態モニタ 
* 
* MBX?  ? = メールボックスID 
* xxxx  メッセージの並び(先頭ニブルのみ) 
* iiii  メッセージ待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monmbx(B NEAR *p, ID id) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	T_MBX NEAR *mbx;	/* メールボックスへのポインタ */ 
	T_MSG FAR *msg;		/* メッセージへのポインタ */ 
	INT i, j; 
 
	/* 1行目の出力データ作成 */ 
 
	ito1id(p+3, id); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, ".... ....", 9); 
 
	/* 2行目の出力データ作成 */ 
 
	if (id > mbxid_max) 
	{	memcpy(p, "non ", 4); 
		return; 
	} 
	mbx = &MBX[id]; 
 
	i = 0; 
	msg = mbx->top; 
	while (msg != NULL) 
	{	ito1x(p+i, msg->msgcont[0]); 
		if (++i == 4) 
			break; 
		msg = msg->next; 
	} 
 
	/* 3行目の出力データ作成 */ 
 
	p += 5; 
	if ((j = mbx->qcnt) != 0) 
	{	tcb = mbx->head; 
		for (i = 0; i < 4; i++) 
		{	ito1id(p+i, tcb->tid); 
			if (--j == 0) 
				break; 
			tcb = tcb->next; 
		} 
	} 
} 
 
#endif 
#if MPLS 
/***************************************************************************** 
* メモリプール状態モニタ 
* 
* MPL?  ? = メモリプールID 
* xxxx  空きブロック数 
* iiii  メモリ待ちタスクIDの並び 
******************************************************************************/ 
 
static void NEAR monmpl(B NEAR *p, ID id) 
{ 
	T_TCB NEAR *tcb;	/* TCBへのポインタ */ 
	T_MPL NEAR *mpl;	/* メモリプールへのポインタ */ 
	INT i, j, c; 
 
	/* 1行目の出力データ作成 */ 
 
	ito1id(p+3, id); 
 
	/* 2,3行目の初期化 */ 
 
	p += 5; 
	memcpy(p, ".... ....", 9); 
 
	/* 2行目の出力データ作成 */ 
 
	if (id > mplid_max) 
	{	memcpy(p, "non ", 4); 
		return; 
	} 
	mpl = pMPL[id]; 
 
	if ((c = mpl->frbcnt) != 0) 
		ito04x(p, c);			/* 空きブロック数 */ 
 
	/* 3行目の出力データ作成 */ 
 
	p += 5; 
	if ((j = mpl->qcnt) != 0) 
	{	tcb = mpl->head; 
		for (i = 0; i < 4; i++) 
		{	ito1id(p+i, tcb->tid); 
			if (--j == 0) 
				break; 
			tcb = tcb->next; 
		} 
	} 
} 
 
#endif 
#ifndef ROM 
/***************************************************************************** 
* オブジェクトモニタ出力データ編集(FMR,IBM-PC) 
* 
* モニタ結果を画面へ出力する並びに変換する。 
******************************************************************************/ 
 
static void NEAR putmon_videobuf(void) 
{ 
	INT i; 
	B NEAR *p1; 
	B NEAR *p2; 
 
	p1 = videobuf; 
	p2 = monbuf; 
 
	for (i = 0; i < 80/5; i++) 
	{ 
		memcpy(p1,      p2,    5); 
		memcpy(p1+80,   p2+5,  5); 
		memcpy(p1+80*2, p2+10, 5); 
		p1 += 5; 
		p2 += 16; 
	} 
} 
 
/***************************************************************************** 
* オブジェクトモニタ画面出力(PC9801) 
* 
******************************************************************************/ 
 
static void NEAR putmon_98(void) 
{ 
	INT i; 
	UB NEAR *p; 
	H FAR *v; 
 
	/* 0回目は出力しない */ 
 
	if (montmr_cnt == 0) 
	{	montmr_cnt = 1; 
		return; 
	} 
 
	/* 1回目でモニタ結果出力(VRAM直書き)*/ 
 
	p = (UB NEAR *)monbuf; 
	v = (H FAR *)vram; 
 
	for (i = 0; i < 80/5; i++) 
	{ 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v   = *p++; 
		v += 80 - 4; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v   = *p++; 
		v += 80 - 4; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v++ = *p++; 
		*v   = *p++; 
		v -= 80 * 2 - 1; 
		p++; 
	} 
	montmr_cnt = 0; 
} 
 
/***************************************************************************** 
* オブジェクトモニタ画面出力(FMR) 
* 
* コンソールBIOSの負荷が重いため1行ずつ分けて出力する。 
******************************************************************************/ 
 
static void NEAR putmon_fmr(void) 
{ 
	union REGS regs; 
	UINT rowcol; 
	UB cursts, i; 
 
	/* 0回目は出力しない */ 
 
	if ((i = montmr_cnt) == 0) 
	{	montmr_cnt = 1; 
		return; 
	} 
 
	/* 1回目は出力データ編集 */ 
 
	if (i == 1) 
	{	putmon_videobuf(); 
		montmr_cnt = 2; 
		return; 
	} 
 
	/* 2〜4回目でモニタ結果出力 */ 
 
	i -= 2; 
 
	/* カーソル状態,位置読み取り */ 
 
	regs.h.ah = 0x0c; 
	int86(0x91, ®s, ®s); 
	cursts = regs.h.al; 
 
	regs.h.ah = 0x0e; 
	int86(0x91, ®s, ®s); 
	rowcol = regs.x.dx; 
 
	/* カーソル消す */ 
 
	regs.h.ah = 0x0b; 
	regs.h.al = 1; 
	int86(0x91, ®s, ®s); 
 
	/* カーソル移動 */ 
 
	regs.h.ah = 0x0d; 
	regs.h.dh = (UB)(i + 1); 
	regs.h.dl = 1; 
	int86(0x91, ®s, ®s); 
 
	/* 文字列出力 */ 
 
	regs.h.ah = 0x1e; 
	regs.x.cx = 80; 
	regs.x.di = (UINT)videobuf + i * 80; 
	int86(0x91, ®s, ®s); 
 
	/* カーソル状態,位置復元 */ 
 
	regs.h.ah = 0x0d; 
	regs.x.dx = rowcol; 
	int86(0x91, ®s, ®s); 
 
	regs.h.ah = 0x0b; 
	regs.h.al = cursts; 
	int86(0x91, ®s, ®s); 
 
	if (++montmr_cnt > 4) 
		montmr_cnt = 0; 
} 
 
/***************************************************************************** 
* オブジェクトモニタ画面出力(IBM-PC) 
* 
* ビデオBIOSの負荷が重いため1行ずつ分けて出力する。 
******************************************************************************/ 
 
/* bpでBIOSに渡すので int86,int86x が使えない */ 
 
static UB int10_func13[] = 
{	0x55,            /* PUSH    BP        */ 
	0x8b,0xec,       /* MOV     BP,SP     */ 
	0xb8,0x00,0x13,  /* MOV     AX,1300H  */ 
	0xb7,0x00,       /* MOV     BH,0      */ 
	0xb3,0x07,       /* MOV     BL,7      */ 
	0xb9,0x50,0x00,  /* MOV     CX,80     */ 
	0x8a,0x76,0x06,  /* MOV     DH,[BP+6] */ 
	0xb2,0x00,       /* MOV     DL,0      */ 
	0x8b,0x6e,0x08,  /* MOV     BP,[BP+8] */ 
	0x1e,            /* PUSH    DS        */ 
	0x07,            /* POP     ES        */ 
	0xcd,0x10,       /* INT     10H       */ 
	0x5d,            /* POP     BP        */ 
	0xcb,            /* RETF              */ 
}; 
typedef int (FAR *FP_HH)(H, H); 
static FP_HH int10_func13p = (FP_HH)((W)int10_func13); 
 
static void NEAR putmon_ibm(void) 
{ 
	UB i; 
 
	/* 0回目は出力しない */ 
 
	if ((i = montmr_cnt) == 0) 
	{	montmr_cnt = 1; 
		return; 
	} 
 
	/* 1回目は出力データ編集 */ 
 
	if (i == 1) 
	{	putmon_videobuf(); 
		montmr_cnt = 2; 
		return; 
	} 
 
	/* 2〜4回目でモニタ結果出力 */ 
 
	i -= 2; 
	(*int10_func13p)(i, (H)(videobuf + 80 * (H)i)); 
 
	if (++montmr_cnt > 4) 
		montmr_cnt = 0; 
} 
 
/***************************************************************************** 
* DOSエクステンダ(EXE286)上で実行中か 
* 
******************************************************************************/ 
 
static BOOL isEXE286(void) 
{ 
	static BOOL exe286 = -1; 
 
	/* 未判定の場合 */ 
 
	if (exe286 == -1) 
	{ 
		B FAR *p1 = (B FAR *)0x400000L;	/* BIOS ワークエリア */ 
		B FAR *p2 = (B FAR *)0x380400L;	/* EXE286 では p1 と同じアドレス */ 
		UH i = 0x200;					/* 200H バイトも比較すれば十分 */ 
		do 
		{	if (*p1++ != *p2++) 
				return exe286 = FALSE; 
		} while (--i != 0); 
		return exe286 = TRUE; 
	} 
 
	/* 判定済みの場合 */ 
 
	return exe286; 
} 
 
/***************************************************************************** 
* セグメントディスクリプタを作成する 
* 
******************************************************************************/ 
 
static void FAR *EXE286SegAbsolute(W absaddr, UH size) 
{ 
	union REGS regs; 
 
	regs.x.ax = 0xfe30; 
	regs.x.si = (H)(absaddr >> 16); 
	regs.x.bx = 0; 
	regs.x.cx = size - 1; 
	regs.h.dl = 0x92; 
	intdos(®s, ®s); 
	return (void FAR *)(((W)regs.x.ax << 16) + (H)absaddr); 
} 
 
/***************************************************************************** 
* 画面分割(PC9801) 
* 
* CRT BIOS の「複数の表示領域の設定」機能を用いて、画面の上部複数行に裏テキス 
* トVRAM を表示させる。(これは日本語FEPが用いている手法と同じ) 
******************************************************************************/ 
 
static void NEAR splitvram(int rows)	/* rows = 分割行数(0で分割解除)*/ 
{ 
	H FAR *p; 
	H buf[4]; 
	union REGS regs; 
 
	if ((UH)vram < 0x1000) 
		return;						/* 裏VRAMでなければNOP */ 
 
	if (isEXE286())					/* EXE286上で実行中の場合 */ 
	{	p = (H FAR *)vram;			/* CRT-BIOSパラメータはVRAM上に取る */ 
		buf[0] = p[0];				/* (リアルモードのメモリが欲しいため)*/ 
		buf[1] = p[1];				/* 破壊するVRAM内容を保存 */ 
		buf[2] = p[2]; 
		buf[3] = p[3]; 
		regs.x.bx = (UH)(VRAM_98 >> 16); 
	} 
	else 
	{	p = buf;		 
		regs.x.bx = (H)((W)p >> 16); 
	} 
	regs.x.cx = (H)((W)p); 
	regs.h.ah = 0x0f; 
 
	if (rows != 0) 
	{	p[0] = (H)vram;				/* 領域0のVRAMオフセット */ 
		p[1] = (H)rows;				/* 領域0の行数 */ 
		p[2] = (H)(rows * 160);		/* 領域1のVRAMオフセット */ 
		p[3] = (H)(25 - rows);		/* 領域1の行数 */ 
		regs.x.dx = 2; 
	} 
	else 
	{	p[0] = 0;					/* 領域0のVRAMオフセット */ 
		p[1] = 25;					/* 領域0の行数 */ 
		regs.x.dx = 1; 
	} 
	int86(0x18, ®s, ®s); 
 
	if (p != buf)		 
	{	p[0] = buf[0];				/* 破壊したVRAM内容を復元 */ 
		p[1] = buf[1]; 
		p[2] = buf[2]; 
		p[3] = buf[3]; 
	} 
} 
 
#endif /* !ROM */ 
/***************************************************************************** 
* オブジェクトモニタ終了 
* 
* montmr 周期起動タイマハンドラを非活性化する。 
* monsta 関数で atexit してある。 
******************************************************************************/ 
 
void cdecl monext(void) 
{ 
  #if TIM 
	act_cyc(0, TCY_OFF); 
  #endif 
 
  #ifndef ROM 
	if (ispc9801())					/* PC9801の場合 */ 
		splitvram(0);				/* 画面分割解除 */ 
  #endif 
} 
 
/***************************************************************************** 
* オブジェクトモニタ・ハンドラ 
* 
* 各モニタ処理関数を呼び出して、結果を画面に出力する。 
* このハンドラは、インターバル割込内で呼び出される非タスクの処理。 
******************************************************************************/ 
 
TMRHDR montmr(void) 
{ 
	INT i, max; 
	B NEAR *p; 
	UINT psw; 
 
	psw = vdis_psw();			/* 割込み禁止 */ 
 
	if (montmr_cnt == 0) 
	{ 
		p = monbuf; 
 
	  #if CLKS 
		monclk(p); 
		p += 16; 
	  #endif 
 
	  #if RDQS 
		monrdq(p); 
		p += 16; 
	  #endif 
 
	  #if TSKS 
		max = mon_tskid + TSKS; 
		for (i = mon_tskid; i < max; i++) 
		{	montsk(p, i); 
			p += 16; 
		} 
	  #endif 
 
	  #if FLGS 
		max = mon_flgid + FLGS; 
		for (i = mon_flgid; i < max; i++) 
		{	monflg(p, i); 
			p += 16; 
		} 
	  #endif 
 
	  #if SEMS 
		max = mon_semid + SEMS; 
		for (i = mon_semid; i < max; i++) 
		{	monsem(p, i); 
			p += 16; 
		} 
	  #endif 
 
	  #if MBXS 
		max = mon_mbxid + MBXS; 
		for (i = mon_mbxid; i < max; i++) 
		{	monmbx(p, i); 
			p += 16; 
		} 
	  #endif 
 
	  #if MPLS 
		max = mon_mplid + MPLS; 
		for (i = mon_mplid; i < max; i++) 
		{	monmpl(p, i); 
			p += 16; 
		} 
	  #endif 
	} 
 
	/* 画面出力 */ 
 
  #ifndef ROM 
	if (ispc9801()) 
		putmon_98(); 
	else if (isfmr()) 
		putmon_fmr(); 
	else if (isibmpc()) 
		putmon_ibm(); 
  #endif 
 
	vset_psw(psw);				/* 割込み禁止戻す */ 
 
	ret_tmr(); 
} 
 
/***************************************************************************** 
* オブジェクトモニタ起動 
* 
* montmr 関数を周期起動タイマハンドラとして定義、活性化する。 
* 本関数の2回目以降の呼び出しでは、活性化のみ行う。 
* ハンドラ番号には、システム予約の0を用いている。 
******************************************************************************/ 
 
void cdecl monsta(void) 
{ 
	static UB init = 0;					/* 初期化済みフラグ */ 
	static T_TIME time = { TIM, 0, 0 };	/* 周期 */ 
  #ifndef ROM 
	W absadr; 
  #endif 
 
	/* 未初期化の場合 */ 
 
	if (!init) 
	{ 
		init_monbuf(); 
	  #if TIM 
		def_cyc(0, montmr, TCY_ON, time); 
      #endif 
		init = 1; 
      #ifndef ROM 
		judgepc(); 
		atexit(monext); 
		if (ispc9801() && isEXE286()) 
		{	absadr = ((vram >> 12) & 0xf0000L) + (UH)vram; 
			vram = (W)EXE286SegAbsolute(absadr, 0); 
		} 
      #endif 
	} 
 
	/* 初期化済の場合(2回目以降の呼出)*/ 
 
  #if TIM 
	else 
		act_cyc(0, TCY_ON); 
  #endif 
 
	/* 共通の処理 */ 
 
	montmr_cnt = 0; 
 
  #ifndef ROM 
	if (ispc9801())					/* PC9801の場合 */ 
		splitvram(3);				/* 画面上3行に裏テキスト分割 */ 
  #endif 
} 
 
/***************************************************************************** 
* モニタする先頭タスクIDを設定 
* 
******************************************************************************/ 
 
BOOL cdecl set_montsk(ID id) 
{ 
	if (id < 1 || id > tskid_max) 
		return FALSE; 
  #if TSKS 
	mon_tskid = id; 
	return TRUE; 
  #else 
	return FALSE; 
  #endif 
} 
 
/***************************************************************************** 
* モニタする先頭イベントフラグIDを設定 
* 
******************************************************************************/ 
 
BOOL cdecl set_monflg(ID id) 
{ 
	if (id < 1 || id > flgid_max) 
		return FALSE; 
  #if FLGS 
	mon_flgid = id; 
	return TRUE; 
  #else 
	return FALSE; 
  #endif 
} 
 
/***************************************************************************** 
* モニタする先頭セマフォIDを設定 
* 
******************************************************************************/ 
 
BOOL cdecl set_monsem(ID id) 
{ 
	if (id < 1 || id > semid_max) 
		return FALSE; 
  #if SEMS 
	mon_semid = id; 
	return TRUE; 
  #else 
	return FALSE; 
  #endif 
} 
 
/***************************************************************************** 
* モニタする先頭メイルボックスIDを設定 
* 
******************************************************************************/ 
 
BOOL cdecl set_monmbx(ID id) 
{ 
	if (id < 1 || id > mbxid_max) 
		return FALSE; 
  #if MBXS 
	mon_mbxid = id; 
	return TRUE; 
  #else 
	return FALSE; 
  #endif 
} 
 
/***************************************************************************** 
* モニタする先頭メモリプールIDを設定 
* 
******************************************************************************/ 
 
BOOL cdecl set_monmpl(ID id) 
{ 
	if (id < 1 || id > mplid_max) 
		return FALSE; 
  #if MPLS 
	mon_mplid = id; 
	return TRUE; 
  #else 
	return FALSE; 
  #endif 
} 
 
/* end */