/* "init.ask" ver.2.4 copyright(C) 2002 H.Kawai(川合秀実) */

/* プリプロセッサのオプションで、-DPCATか-DTOWNSを指定すること */

#define	MAXWINDOW		80	/* 1024/32 */
#define	CALLFAR0(sel)	DB(0x9a); DD(0); DW((short) sel);

asmout("include ./inc.asm");
asmout("modulelist = 0020H");
asmout("alloclist  = 0120H");
asmout("bootmalloc_adr1 = 01DCH");
asmout("bootmalloc_fre1 = 01E0H");
asmout("FD_motor_init = 01E4H");
asmout("DiskCacheReady = 01E6H");
asmout("V86TaskEntry = 0008H");
asmout("boot_keylock = 001E7H");

/* 64タスクまでの準備はできている */

//	#define	CHECK_TSKPTR	1

segment InitMdl(USE32, PARA);

default(code == InitMdl);

struct LINE_CMD {
	unsigned int cmd_no /* 0x0100 */;
	unsigned int option /* bit6-7:function 00:PSET, 01:AND, 10:OR, 11:XOR */;
	unsigned int x0, y0, x1, y1, color;
};

struct END_CMD {
	unsigned int cmd_no /* 0x0000 */;
};

struct SS0_struct {
	void [32];
	char ring0_count, [3];
	/* void * */ int [4], ring0call[6], [2];
	char cli_count, [3];
	/* void * */ int [4], cli_call[6], [2];
};

void near testmemory();
void near init_areastr();
void near ui32toa();
void near ui8toa();
void near output_string();
void near initmalloc();
void near set_modulesegment();
// void far KeyboardMdl::keyboardInit();
// void far KeyboardMdl::KeyboardIntDrv();
void near get_area();
void near free_area();
void near create_task();
void near get_memory();
void near free_memory();
void near alloc_memory();
void near alloc_tagdir();
void near add_tags();
void near regist_module();
void near search_tag_EAX();
void near delete_directory();
void near delete_binmodule();
void near memcopy16();
void near disable_diskcache();
void near get_virtual();
void near free_virtual();
void near free_memory64();
void near put_int_status_ec();
void near put_int_status();

struct area_man_struct_sub {
	unsigned int size;
	unsigned int addr;
};

struct area_man_struct {
	char res0[8];
	unsigned int use, size0; // 単位はバイト
	void [16];
	area_man_struct_sub data0, data[0];
	/* use < size0 は常に成立する */
	/* data[use]は-1,-1を指す */
	/* data0は番兵0,0 */
};

struct resource_bitmap_struct {
	int len;
	int bitmap[0];
	/* bitmap[len - 4]は0(terminator) */
	/* 全サイズ(bytes) * 8 - 64 [個]の管理ができる */
};

struct GUIGUI_window_struct { // 計32bytes
	int status, win_id_task, signal_base, msgbox;
	int x_size, y_size, x0, y0;
};

struct GUIGUI_work { /* SS:0xffffd000; */
	void [1024];
	area_man_struct linear_man[1024];
	area_man_struct dummy_man[1024];
	void [ 760];
	unsigned int timer_sec4, root_Paddr;
	unsigned int dosload_phase, dosload_work[16];
	unsigned int diskcache_Laddr, diskbuf_Paddr, diskbuf_Laddr;
	unsigned int cacheflags[64 /* 2MB分 */];
	unsigned int track[20 /* 160トラック分 */];
	unsigned int tapiwork_Laddr, tapiwork_Paddr;
	resource_bitmap_struct tapiwork_man[32];
	unsigned int root_size, root_addr;
	unsigned int setvideomode_mode, setvideomode_sig[12];
	unsigned int TAPI_sendmsgofs, TAPI_sendmsgsel;
	unsigned int cmd0100_buf[64];
	unsigned int timer_freq;
	/* 0xffffe000〜0xfffff200 */
	area_man_struct virtual_man[2048];
	GUIGUI_window_struct winlist[1024], [1024], [512];
};

struct TAPI_TSS386 {  /* 全てTL-0 */
	short BackLink, [2];
	int stack0_ESP; short stack0_SS, [2];
	int stack1_ESP; short stack1_SS, [2];
	int stack2_ESP; short stack2_SS, [2];
	int CR3;
	int EIP;
	int EFLAGS;
	int EAX, ECX, EDX, EBX;
	int ESP, EBP, ESI, EDI;
	short ES, [2], CS, [2], SS, [2];
	short DS, [2], FS, [2], GS, [2];
	short LDTR, [2], TaskFlags, IOBitMap;
	/* 合計104bytes */
};

struct TAPI_GlvPrm { /* 計64bytes */
	int run[12];
//	struct Tss near *Pointer;
	int pointer;
	int totalIlv; // +0x10
	int tasks;
	int MinIlv, MaxIlv;
	char flags; /* フラグによっては、Ilvを考慮しない。 */
	/* bit0:Ilv変更フラグ(0で変更あり)、bit1:時分割抑制フラグ(1で抑制)。 */
	void [31];
};

struct TAPI_LlvPrm { // 32bytes
	int run[12];
	int Glv;
	int short_run[12]; /* 0x10〜0x1b  0x1bが-1なら、invalid */
	int Ilv;
};

struct TAPI_TSS {
	TAPI_TSS386 tss386;  /* TL-0ブロック(104bytes) */

	/* system-signal処理のブロック(24bytes) */
	int sysbox_write_free, sysbox_write_ptr, sysbox_write_ptr0, sysbox_write_ptr1;
	int sysbox_read_ptr;
	unsigned char msgbox_status, softint_nest, [2];
		// bit0 : buffer write overrun
		// bit6 : sysbox empty(0:empty)
		// bit7 : msgbox empty(0:empty)

	int set[12], tr[4], run[12], ldt_img; /* TL-1ブロック(48bytes) */
	int fpu_reg_img, sse_reg_img /* for SSE & SSE2 */;
//	TAPI_TSS near *back, near *next;
	int back, next;

	int softint_EIP /* +0x00b0 */; short softint_CS; /* signal処理のブロック(48bytes) */
	short softint_oldCS;
	int softint_oldEIP;
	unsigned char softint_Llv, sysint_Llv /* このフィールドは使わない。softintと共通 */, now_Llv, softint_oldLlv;
	int msgbox_write_free, msgbox_write_ptr, msgbox_write_ptr0, msgbox_write_ptr1;
	int msgbox_eom_code, msgbox_rewind_code, [8];

/*	softint_oldLlvは、スタックにつむと0xffに変化する...で、0xffのときに、ストアされる
	softint_CS == 0のとき、CS:EIPの変化無し
	softint_Llv == 0のとき、Llvの変化無し */

/* TL-2ブロック 32bytes */
//	GlvPrm near *Glv /* +0x00e0 */; /* TapiWorkSelの中のオフセット */
//	LlvPrm near *Llv; /* TapiWorkSelの中のオフセット */
	int Glv, Llv; // 0xe0〜0xe7
	int Ilv, Llv_base; // Inner-level
	int short_run[12]; // +0x00f0
	char flags, [3];  /* Setの再評価要求フラグ */


/* このタスクの全実行時間は、runではない。runは、現在のLlvのrunningタイムを示しているに過ぎない。 */
/* 現在のLlvのLlvPrm.runは無効。 */

};

/* タスクごとの4KBの使い道 */
/*	(最初の1KB)
	TAPI_TSS			0.25KB
	LlvPrm				0.25KB(8lv)
	未使用				 64bytes
	メッセージボックス   64bytes
	FPUレジスタイメージ	108bytes
	システム管理用		 20bytes (+748)
	  tskdir, stack0_size, stack0_addr, stack3_size, stack3_addr
		↑これらは、リニアアドレスをはがすために記憶している。今は一続きなのでstack3は使っていない。
	未使用(SSE用)		0.25KB
	(残りの3KB)
	msgbuf				0.50KB
	sysbuf				0.50KB
	ldt_img				1.00KB
	slot_img			1.00KB
*/

/* リニアアドレスマップ */
/*	0MB〜1MB : 20bitメモリ空間と対応
	1MB〜3MB : ディスクキャッシュ管理用
	3MB〜4MB : プロテクトメモリチェック
				20bitメモリからの転送用マップ領域

	4.5MB〜20MB : 第一リニアアドレス
	20MB〜64MB : 第二リニアアドレス
*/

/* 物理アドレスマップ */
/* 	0MB〜1MB : 20bitメモリ
	1MB〜0x267fff : ディスクキャッシュ
	2.41MB〜 : フリー
*/

struct GUIGUI_codeheader { /* 32bytes */
	void [8]; /* for jmp-vector */
	char signature[8]; /* 'GUIGUI00' */
	int stack3_size, stack3_reserve, [8];
	/* reverveのbit0:
		0:reserve、stackの順
		1:stack、reserveの順(通常) */
};

struct ModuleList {
	unsigned char name[8];
	unsigned int size, addr;
};

void far Init()
/* 進入条件：
   DS == syswork_seg, GS == IDT&GDT_seg (どちらもセレクタではないことに注意が必要) */
{
	segment InitMdl == CS;
	/* セレクタ番号 */
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int GAPI_sel     ==  4 * 8, GAPIwork_sel  ==  5 * 8;
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;
	unsigned int timerint_sel == 10 * 8, timerdata_sel == 11 * 8;
	unsigned int tapi_sel     == 12 * 8, tapiwork_sel  == 13 * 8;
	unsigned int pdepte_sel   == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int root_sel     == 16 * 8, tmp_sel       == 17 * 8;
	unsigned int papi_sel     == 18 * 8, papiwork_sel  == 19 * 8;
	unsigned int VRAM_sel     == 20 * 8;
	unsigned int decode_sel   == 22 * 8, decowork_sel  == 23 * 8;
	unsigned int fdcdrive_sel == 28 * 8, fdcwork_sel   == 29 * 8;
	unsigned int diskbuf_sel  == 30 * 8, textbuf_sel   == 31 * 8;
	unsigned int freegdt_sel  == 32 * 8;

	/* modulelistからのオフセット */
	unsigned int alloclist == 16 * 16;
	unsigned int syswork_ent   ==  0 * 16, init_ent     ==  1 * 16;
	unsigned int GAPI_ent      ==  2 * 16, keyint_ent   ==  3 * 16;
	unsigned int timerint_ent  ==  4 * 16, tapi_ent     ==  5 * 16;
	unsigned int decode_ent    ==  6 * 16, fdc_ent      ==  7 * 16;
	unsigned int bootseg_ent   ==  8 * 16, stack000_ent ==  9 * 16;
	unsigned int                           winman0_ent  == 11 * 16;
	unsigned int pokon0_ent    == 12 * 16;
	unsigned int ankfont0_ent  == 14 * 16;
	unsigned int PDEPTE_ent    ==  0 * 16 + alloclist;
	unsigned int IDTGDT_ent    ==  1 * 16 + alloclist;
	unsigned int ankfont_ent   ==  2 * 16 + alloclist;
	unsigned int stack_ent     ==  3 * 16 + alloclist;
	unsigned int keydata_ent   ==  4 * 16 + alloclist;
	unsigned int gapidata_ent  ==  5 * 16 + alloclist;
	unsigned int timerdata_ent ==  6 * 16 + alloclist;
	unsigned int tapiwork_ent  ==  7 * 16 + alloclist;
	unsigned int decowork_ent  ==  8 * 16 + alloclist;
	unsigned int fdcwork_ent   ==  9 * 16 + alloclist;
	unsigned int papiwork_ent  == 10 * 16 + alloclist;
//	unsigned int textbuf_ent   == 11 * 16 + alloclist;
//	unsigned int userbin_ent   == 12 * 16 + alloclist;
	unsigned int empty_ent     == 13 * 16 + alloclist;
//	unsigned int empty00_ent   == 16 * 16 + alloclist;
//	unsigned int empty01_ent   == 17 * 16 + alloclist;
//	unsigned int empty02_ent   == 18 * 16 + alloclist;

	unsigned short *VGA_mode == DS:0x10;

	SS0_struct *stack_ESP0 == /* SS:(- sizeof (SS0_struct)) */ SS:0xffffffc0;

	/* GDTを作るための関数を用意した方がいいかもしれない
	   GS:EBXに書き込む。EDXはベース、ECXはサイズ、AXはアクセスライト
	   GS:EBX以外は破壊 */

	EAX = 0xc092 /* unit:page, use32, lv0, RW */;
	ECX = 0; /* 0は0x100000000を意味する */
	EDX = 0x00000000;
	EBX = 384 /* IDTの分 */ + all_sel;
	set_modulesegment();

	EAX = 0x4092 /* unit:byte, use32, lv0, RW */;
	ECX = 0x00010000; /* 64KB */
	EDX = 0x000a0000;
	EBX = 384 /* IDTの分 */ + VRAM_sel;
	set_modulesegment();

	/* tapiコールの支障にならないように、ダミーセレクタを作る */
	EAX = 0xc092 /* unit:page, use32, lv0, RW */;
	ECX = 0; /* 0は0x100000000を意味する */
	EDX = 0x00000000;
	EBX = 384 /* IDTの分 */ + tapiwork_sel;
	set_modulesegment();

	ModuleList *modulelist0 == /* DS:(2 * 16) */ DS:32;
	ModuleList *modulelist == DS:EBX;

//	asmout("PUSH DWORD PTR DS:[bootmalloc_fre1]");
	/* 再初期化のために元の値を保存 */

	(offset) modulelist = 32 + ankfont_ent; /* (offset) &modulelist0[stack_ent]; */
	do {
		ECX = modulelist->size;
		if (ECX != 0) {
			if (modulelist->addr == 0xffffffff) {
				PUSH(EBX);
				initmalloc();
				POP(EBX);
				modulelist->addr = EAX;
			}
		}
		EBX += sizeof (ModuleList);
		EAX = (int) modulelist->name[0];
	} while (EAX != 0);

	unsigned short *seg_table == CS:EDI;
	asmout("MOV EDI,OFFSET Init_segment_table");
	EAX = seg_table[0];
	do {
		ESI = seg_table[2];
	//	EAX = seg_table[0];
		ECX = [DS:ESI+0x08] /* .size */;
		EDX = [DS:ESI+0x0c] /* .base */;
		EBX = seg_table[4];
		(offset) seg_table += 6;
		EBX += 48 * 8 /* IDTの分 */;
		PUSH((offset) seg_table);
		if (AL == 0x96 /* stack */)
			EDX += ECX;
		set_modulesegment();
		POP((offset) seg_table);
		EAX = seg_table[0];
	} while (EAX != 0);

	#if (defined(CHECK_TSKPTR))
		EAX = /* modulelist[tapiwork_ent].base */ [DS:32 + tapiwork_ent + 0x0c];
		EAX += 0x000c;
		asmout("MOV DR0,EAX");
		EAX = 0;
		asmout("MOV DR6,EAX");
		asmout("MOV EAX,1000000010B+1101B*10000H");
			/* GE = G0 = 1; LEN0 = 3 (DW); RW0 = 01 (write only); */
		asmout("MOV DR7,EAX");
	#endif

	#if 0
		EAX = /* modulelist[tapiwork_ent].base */ [DS:32 + tapiwork_ent + 0x0c];
		EAX += 28;
		asmout("MOV DR0,EAX");
		EAX = 0;
		asmout("MOV DR6,EAX");
		asmout("MOV EAX,1000000010B+1101B*10000H");
			/* GE = G0 = 1; LEN0 = 3 (DW); RW0 = 01 (write only); */
		asmout("MOV DR7,EAX");
	#endif

	#if 0
		EAX = 0x480000 + 0x2d20 + 28;
		asmout("MOV DR0,EAX");
		EAX = 0;
		asmout("MOV DR6,EAX");
		asmout("MOV EAX,1000000010B+1101B*10000H");
			/* GE = G0 = 1; LEN0 = 3 (DW); RW0 = 01 (write only); */
		asmout("MOV DR7,EAX");
	#endif


	/* スタックも切り替わっていない。 */
	/* システムスタックを押し上げて、メモリ、TAPIwork、GDTの管理ブロックを作る。 */

	POP(ECX); /* 再初期化のための値 */

	EAX = stack_sel;
	EDX = 0;
	SS = EAX;
	ESP = /* (offset) stack_ESP0 */ 0xffffd000; /* スタックの初期化 */
	EDX -= 0x80; /* EDX = 0xffffff80; */
	(int) stack_ESP0->ring0_count = EDX /* 0xffffff80 */;
	(int) stack_ESP0->cli_count   = EDX /* 0xffffff80 */;

	PUSH(ECX); /* 再初期化のための値 */

	GUIGUI_work *work == SS:0xffffd000;
	area_man_struct *areastrEBP == SS:EBP;
//	EDX = 0;
	EAX = 0;
//	EDX--;
	EDX += 0x7f; /* EDX = 0xffffffff; */
	/* EBP = (offset) work->virtual_man; */ LEA(EBP, (int) work->virtual_man);
	ECX = 2048 - 40;
	init_areastr();
//	/* EBP = (offset) work->mem24_man; */ LEA(EBP, (int) work->mem24_man);
//	ECX = 512 - 40;
//	init_areastr();
//	/* EBP = (offset) work->mem20_man; */ LEA(EBP, (int) work->mem20_man);
///	ECX = 512 - 40;
//	init_areastr();
	/* EBP = (offset) work->linear_man; */ LEA(EBP, (int) work->linear_man);
	ECX = 1024 - 40;
	init_areastr();

	/* フォントロード */
	PUSH((int) all_sel);
	ESI = [DS:32 + ankfont0_ent + 0x0c];
	EDX = [DS:32 + ankfont_ent + 0x0c]; /* ロードアドレス */
	POP(DS);
	EAX = 0;
	ECX = 0x20 * 16 / 4;
	do {
		[DS:EDX] = EAX;
		EDX += 4;
		ECX--;
	} while (!= 0);
	ECX = 0x60 * 16 / 4;
//	EDX += 0x20 * 16;
	do {
		EAX = [DS:ESI];
		ESI += 4;
		[DS:EDX] = EAX;
		EDX += 4;
		ECX--;
	} while (!= 0);

	PUSH((int) pdepte_sel);
	ECX = 0;
	POP(DS);
	(int) [DS:ECX + 0x000] /*  0〜 3MB */ = 0x2000;
	(int) [DS:ECX + 0x004] /*  4〜 7MB */ = 0x4000;
	(int) [DS:ECX + 0x008] /*  8〜11MB */ = 0x5000;
	(int) [DS:ECX + 0x00c] /* 12〜15MB */ = 0x6000;
	(int) [DS:ECX + 0x010] /* 16〜19MB */ = 0x7000;
	(int) [DS:0xe00] = 0x3000;

	DL = [ES:ECX + 0x001c + 2 /* eflags[2] */];

	PUSH(SS);
//	ECX = 0;
	ESI = 0x0108;
	POP(FS);

	/* PAPI初期化 */
	PUSH((int) ECX /* eoc */);
	PUSH(ECX);
	PUSH(ECX);
	PUSH(ECX);
	PUSH(0x0100 /* init cmd */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 20 - 4;

	#if (defined(PCAT))
		EAX = 0x07 /* present, R/W, user */;
		TEST(DL, 0x04);
		if (!= 0)
			EAX |= 0x10 /* VRAMはキャッシュしない(PCD=1) */;

	//	ECX = 0;
	//	PUSH((int) ECX /* eoc */);

		/* mapping BIOS (for VESA call) (0x000c0000〜0x000fffff) */
		/* mapping high memory (0x00100000〜0x002fffff) */

		PUSH((int) ECX /* addr64(high) */);
		PUSH((int) 0x000c0000 /* addr64(low) */);
		PUSH((int) ECX /* offset64(high) */);
		PUSH((int) ECX /* offset64(low) */);
		PUSH((int) ECX /* pageset */);
		PUSH((int) 0x000c0000 /* linear */);
		PUSH((int) 2304 * 1024 /* size(128K + 2M) */);
		PUSH((int) 0x0007 /* opt(present, R/W, user) */);
		PUSH((int) ESI /* cmd(mapping) */);

		/* mapping VRAM (0x000a0000〜0x000bffff) */

		PUSH((int) ECX /* addr64(high) */);
		PUSH((int) 0x000a0000 /* addr64(low) */);
		PUSH((int) ECX /* offset64(high) */);
		PUSH((int) ECX /* offset64(low) */);
		PUSH((int) ECX /* pageset */);
		PUSH((int) 0x000a0000 /* linear */);
		PUSH((int) 128 * 1024 /* size */);
		PUSH((int) EAX /* opt(PCD, present, R/W, user) */);
		PUSH((int) ESI /* cmd(mapping) */);

		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 76;
	#endif
	#if (defined(TOWNS))
		IN(AX, 0x0030); /* CPU識別レジスタ */
		AL &= 0x07;
		CMP(AL, 0x03);
		EBX = 0x80100000;
		if (==) /* i386SX */
			EBX = 0x00b00000;
		TEST(DL, 0x04);
		EAX = 0x07 /* present, R/W, user */;
		if (!= 0)
			EAX |= 0x10 /* VRAMはキャッシュしない(PCD=1) */;

	//	ECX = 0;
	//	PUSH((int) ECX /* eoc */);

		/* mapping VRAM (0x80100000〜0x80180000) */

		PUSH((int) ECX /* addr64(high) */);
		PUSH((int) EBX /* addr64(low) */);
		PUSH((int) ECX /* offset64(high) */);
		PUSH((int) ECX /* offset64(low) */);
		PUSH((int) ECX /* pageset */);
		PUSH((int) 0xe0000000 /* linear */);
		PUSH((int) 512 * 1024 /* size */);
		PUSH((int) EAX /* opt(PCD, present, R/W, user) */);
		PUSH((int) ESI /* cmd(mapping) */);

		/* mapping high memory (0x00100000〜0x002fffff) */

		PUSH((int) ECX /* addr64(high) */);
		PUSH((int) 0x00100000 /* addr64(low) */);
		PUSH((int) ECX /* offset64(high) */);
		PUSH((int) ECX /* offset64(low) */);
		PUSH((int) ECX /* pageset */);
		PUSH((int) 0x00100000 /* linear */);
		PUSH((int) 2048 * 1024 /* size(2M) */);
		PUSH((int) 0x0007 /* opt(present, R/W, user) */);
		PUSH((int) ESI /* cmd(mapping) */);

		/* mapping RAM (0x000a0000〜0x000bffff) */

		PUSH((int) ECX /* addr64(high) */);
		PUSH((int) 0x000a0000 /* addr64(low) */);
		PUSH((int) ECX /* offset64(high) */);
		PUSH((int) ECX /* offset64(low) */);
		PUSH((int) ECX /* pageset */);
		PUSH((int) 0x000a0000 /* linear */);
		PUSH((int) 128 * 1024 /* size */);
		PUSH((int) 0x0007 /* opt(present, R/W, user) */);
		PUSH((int) ESI /* cmd(mapping) */);
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 112;
	#endif

	PUSH((int) syswork_sel);
	POP(ES);
	PUSH(SS /* stack_sel */);
	POP(DS);

//	EAX = (int) [ES:0x000c /* addr1 */];
//	ECX = (int) [ES:0x0010 /* free1 */];
	asmout("MOV EAX,DWORD PTR ES:[bootmalloc_adr1]");
	asmout("MOV ECX,DWORD PTR ES:[bootmalloc_fre1]");
	free_memory(); /* フリーメモリの登録 */

//	asmout("POP DWORD PTR ES:[bootmalloc_fre1]");
	/* 再初期化のため */

	#if (defined(TOWNS))
		EAX = 640 * 1024;
		ECX = 128 * 1024;
		free_memory();
	#endif

//	EAX = 0x1000; /* 余った0x800は、ワークエリアかもしくはGlvに。 */
//	ECX = (int) [ES:32 + tapiwork_ent + 0x08]; /* tapiwork_ent.size */
//	ECX -= EAX;
//	/* ESI = (offset) work->tapiwork_man; */ LEA(ESI, (int) work->tapiwork_man);
//	free_area(); /* tapiworkの空き領域 */

//	EAX = freegdt_sel;
//	ECX = (int) [ES:32 + IDTGDT_ent + 0x08]; /* IDTGDT_ent.size */
//	ECX -= EAX;
//	ECX -= 0x30 * 8; /* IDTの分を引く */
//	/* ESI = (offset) work->gdt_man; */ LEA(ESI, (int) work->gdt_man);
//	free_area(); /* 未使用のGDTの登録 */

	EAX = 0;
	LEA(EBP, work->tapiwork_man.bitmap[0]);
//	EAX = 0xffffffff;
	EAX--;
	ECX = 32 - 4;
	(int) [SS:EBP - 4 /* len */] = ECX;
	do {
		[SS:EBP] = EAX;
		EBP += 4;
		ECX -= 4;
	} while (!= 0);

	EAX = 0x80000000;
	ECX = 0x7ffffffe; /* 8TB弱 */
	/* ESI = (offset) work->virtual_man; */ LEA(ESI, (int) work->virtual_man);
	free_area();

	EAX = 0x00480000;
	ECX = 0x00f80000; /* 4.5MB〜20MB */
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	free_area();

	/* work->winlistを初期化する */
	/* EBP = (offset) work->winlist; */ LEA(EBP, (int) work->winlist);
	EAX = 0;
	ECX = MAXWINDOW * 32 / 4;
	do {
		[SS:EBP] = EAX;
		EBP += 4;
		ECX--;
	} while (!= 0);

//	/* font-module設定 */
//	EAX = ankfont_sel;
//	ES = AX;
//	(int) [ES:0x0000] = 8;
//	(int) [ES:0x0004] = 16;

	/* IDT設定 */

	EAX = idtgdt_sel;
	GS = EAX;
	DS = EAX;

	unsigned char *idt_table == CS:EDI;
	unsigned short *idt_table2 == CS:EDI;
	asmout("MOV EDI,OFFSET Init_idt_table");
	EBX = idt_table[1];
	EBX *= 8;
	EDX = 0;
	EBP = 0;
	do {
		AX = idt_table2[2];
		CX = idt_table2[4];
		DH = idt_table[0];
		(offset) idt_table += 6;
		(short) [DS:EBX + 0] = AX;
		(short) [DS:EBX + 4] = DX;
		(short) [DS:EBX + 2] = CX;
		(short) [DS:EBX + 6] = BP /* == 0 */;
		EBX = idt_table[1];
		EBX *= 8;
	} while (!= 0);

//	AX = SS; FS = AX;
	PUSH((int) 0); /* eoc */
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x0120 /* TAPI_INT07のベクタを要求 */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	POP(EDX);
	EBX = 0x0038 /* int07 */;
	POP(EAX);
	POP(ECX);
//	POP(EDX);
	(short) [DS:EBX + 0] = AX;
	(unsigned int) EAX >>= 16;
	(short) [DS:EBX + 2] = CX;
	(short) [DS:EBX + 4] = 0x8f00;
	(short) [DS:EBX + 6] = AX;

//	PUSH((int) 0); /* eoc */
	#if (defined(PCAT))
		PUSH(EAX);
		PUSH(EAX);
		PUSH((int) 0x0128 /* MouseIntDrvのベクタを要求 */);
	#endif
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x0124 /* KeyboardIntDrvのベクタを要求 */);
	EBX = ESP;
	CALLFAR0(keyint_sel);
	POP(EDX);
	EBX = 0x0108 /* int21 */;
	POP(EAX);
	POP(ECX);
	(short) [DS:EBX + 0] = AX;
	(unsigned int) EAX >>= 16;
	(short) [DS:EBX + 2] = CX;
	(short) [DS:EBX + 4] = 0x8e00;
	(short) [DS:EBX + 6] = AX;
	#if (defined(PCAT))
		POP(EDX);
	//	EBX = 0x0160 /* int2c */;
		BL = 0x60;
		POP(EAX);
		POP(ECX);
		(short) [DS:EBX + 0] = AX;
		(unsigned int) EAX >>= 16;
		(short) [DS:EBX + 2] = CX;
		(short) [DS:EBX + 4] = 0x8e00;
		(short) [DS:EBX + 6] = AX;
	#endif
//	POP(EDX);

//	PUSH((int) 0); /* eoc */
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x0104 /* FDC_intのベクタを要求 */);
	EBX = ESP;
	CALLFAR0(fdcdrive_sel);
	POP(EDX);
	EBX = 0x0130 /* int26 */;
	POP(EAX);
	POP(ECX);
//	POP(EDX);
	(short) [DS:EBX + 0] = AX;
	(unsigned int) EAX >>= 16;
	(short) [DS:EBX + 2] = CX;
	(short) [DS:EBX + 4] = 0x8e00;
	(short) [DS:EBX + 6] = AX;

//	PUSH((int) 0); /* eoc */
	PUSH((int) 0x0100 /* keyboardInit */);
	EBX = ESP;
	CALLFAR0(keyint_sel);
//	ESP += 8 - 4;

//	PUSH((int) 0); /* eoc */
//	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x0108 /* Keydecode_Mainへのベクタ取得 */);
	PUSH((int) 0x0100 /* Keydecode_Init */);
	EBX = ESP;
	CALLFAR0(decode_sel);
	POP(EAX);
	EBX = ESP;
	(int) [SS:ESP] = 0x0110; /* connect Decoder */
	CALLFAR0(keyint_sel);
//	ESP += 16 - 4;

	/* Page Fault Handler */

//	PUSH((int) 0); /* eoc */
//	PUSH(EAX);
//	PUSH(EAX);
//	PUSH((int) 0x0104 /* PageFaultHandlerへのベクタ取得 */);
	(int) [SS:ESP] = 0x0104 /* PageFaultHandlerへのベクタ取得 */;
	EBX = ESP;
	CALLFAR0(papi_sel);
	POP(ECX);
	EBX = 0x0070 /* int0e */;
	POP(EAX /*  */);
	POP(ECX);
	(short) [DS:EBX + 0] = AX;
	(unsigned int) EAX >>= 16;
	(short) [DS:EBX + 2] = CX;
	(short) [DS:EBX + 4] = 0x8e00;
	(short) [DS:EBX + 6] = AX;

	/* PIC初期化 */

	#if (defined(PCAT))
		AL = 0x11; /* ICW1 (edge trigger) */
		OUT(0x20, AL); /* master */
		NOP();
		OUT(0xa0, AL); /* slave */
		AL = 0x20; /* ICW2(int-no.) */
		OUT(0x21, AL); /* master */
		AL = 0x28; /* ICW2(int-no.) */
		OUT(0xa1, AL); /* slave */
		AL = 0x04; /* ICW3 slaveがつながっているIRQのbitを1にする(bit2 = 1) */
		OUT(0x21, AL); /* master */
		AL = 0x02; /* ICW3 slaveはmasterの何番に接続されているか(IRQ 02) */
		OUT(0xa1, AL); /* slave */
		AL = 0x01; /* ICW4(non-buf. mode) */
		OUT(0x21, AL); /* master */
		AL = 0x01; /* ICW4(non-buf. mode) */
		OUT(0xa1, AL); /* slave */
		AL = 0xb9; /* OCW1 keyboardとslaveとFDCだけを許可 10111001 */
		OUT(0x21, AL); /* master */
		AL = 0xef; /* OCW1  mouseだけ許可 11101111b */
		OUT(0xa1, AL); /* slave */
		AL = 0x4a; /* OCW3 IRR読み込み 特殊マスクモードリセット 01001010 */
		OUT(0x20, AL); /* master */
		AL = 0x4b; /* OCW3 ISR読み込み 特殊マスクモードリセット 01001011 */
		OUT(0xa0, AL); /* slave */
	#endif
	#if (defined(TOWNS))
		AL = 0x19; /* ICW1 (level trigger) */
		OUT(0x00, AL); /* master */
		NOP();
		OUT(0x10, AL); /* slave */
		AL = 0x20; /* ICW2(int-no.) */
		OUT(0x02, AL); /* master */
		AL = 0x28; /* ICW2(int-no.) */
		OUT(0x12, AL); /* slave */
		AL = 0x80; /* ICW3 slaveがつながっているIRQのbitを1にする(bit7 = 1) */
		OUT(0x02, AL); /* master */
		AL = 0x07; /* ICW3 slaveはmasterの何番に接続されているか(IRQ 07) */
		OUT(0x12, AL); /* slave */
		AL = 0x1d; /* ICW4(buf.-master mode) */
		OUT(0x02, AL); /* master */
		AL = 0x09; /* ICW4(buf.-slave mode) */
		OUT(0x12, AL); /* slave */
		AL = 0x3d; /* OCW1 keyboardとslaveとFDCだけを許可 00111101 */
		OUT(0x02, AL); /* master */
		AL = 0xff; /* OCW1 全てマスク */
		OUT(0x12, AL); /* slave */
		AL = 0x4a; /* OCW3 IRR読み込み 特殊マスクモードリセット 01001010 */
		OUT(0x00, AL); /* master */
		AL = 0x4b; /* OCW3 ISR読み込み 特殊マスクモードリセット 01001011 */
		OUT(0x10, AL); /* slave */
	#endif

	STI(); // IF = 1;

	/* フォントロード for debug */
	#if (defined(BOCHS))
		PUSH((int) 0x0000);
		PUSH((int) 7 * 8 /* ankfont-sel */);
		PUSH((int) 0x0000 /* offset */);
		PUSH((int) 0x1000 /* to */);
		PUSH((int) 0x0100 /* len */);
		PUSH((int) 0x0001 /* type */);
		PUSH((int) 0x0000 /* opt */);
		PUSH((int) 0x0104 /* loadfont(gapi cmd) */);
		EBX = ESP;
	//	PUSH(SS);
	//	POP(FS);
		CALLFAR0(GAPI_sel);
		ESP += 32;
	#endif

	/* キーボード初期化とプロテクトメモリ初期化をやる */
	/* 平行して、FDD初期化もできる。 */

//	PUSH((int) 0); /* eoc */
	PUSH((int) 0x0104 /* KeyboardReset */);
	EBX = ESP;
	CALLFAR0(keyint_sel);
//	ESP += 8 - 4;

	/* tapiworkのためのメモリ空間を確保 */
	PUSH(SS);
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	POP(DS);
	ECX = 64 * 4096; /* 256KB */
	get_area();
//	if (ZF == 1)
//		INT(0x03); /* ありえない！ */
	work->tapiwork_Laddr = EAX;
	EDX = EAX;

	/* 共通部分の4KBだけメモリを割り当ててやる */
//	EAX = pdepte_sel;
	ECX = 4096;
//	DS = AX;
	get_memory();
//	if (ZF == 1)
//		INT(0x03); /* ありえない！ */
	work->tapiwork_Paddr = EAX;

	EBX = 0;
	PUSH((int) EBX /* eoc */);
	PUSH((int) EBX /* addr64(high) */);
	PUSH((int) EAX /* addr64(low) */);
	PUSH((int) EBX /* offset64(high) */);
	PUSH((int) EBX /* offset64(low) */);
	PUSH((int) EBX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0x0007 /* opt(present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 40;

	PUSH(GS);
	EBX = 384 + tapiwork_sel;
	PUSH((int) idtgdt_sel);
	ECX = 64 * 4096;
//	EDX = work->tapiwork_Laddr;
	POP(GS);
	EAX = 0x4092 /* lv0, Read/Write, use32 */;
	set_modulesegment();
	POP(GS);

//	AX = SS; FS = AX;

	/* Timer, TAPIを起動 */
//	PUSHFD();
	CLI();
//	PUSH(0 /* eoc */);
//	PUSH(EAX /* reserve */);
	PUSH(EAX /* reserve */);
	PUSH(0 /* init */);
	PUSH(4 /* special */);
	EBX = ESP;
	CALLFAR0(timerint_sel);
//	ESP += 20 - 4;

//	PUSH(0 /* eoc */);
	ESP -= 24 - 20 + 4;
	PUSH(8 /* intハンドラ情報要求 */);
	PUSH(4);
	EBX = ESP;
	CALLFAR0(timerint_sel);
	EAX = [SS:ESP + 8]; /* EAXにオフセット */
//	ESP += 36 - 4;
	PUSH((int) idtgdt_sel);
	EBX = 0x20 * 8;
	POP(DS);
	(short) [DS:EBX + 0] = AX;
	(unsigned int) EAX >>= 16;
	(short) [DS:EBX + 4] = 0x8e00;
	(short) [DS:EBX + 2] = 10 * 8;
	(short) [DS:EBX + 6] = AX;
//	POPFD();
	STI();

//	PUSH(0 /* eoc */);
//	ESP -= 32;
	PUSH(4 /* 一般情報要求 */);
	PUSH(4);
	EBX = ESP;
	CALLFAR0(timerint_sel);
	EAX = [SS:ESP + 36]; /* 割り込み周波数[Hz] */
	ECX = [SS:ESP + 28]; /* 割り込み周期[2^-32sec] */
	ESP += 44 - 4;
	work->timer_freq = EAX;
	work->timer_sec4 = ECX;

//	PUSH((int) 0 /* eoc */);
	PUSH((int) 0x0108 /* init */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
//	ESP += 8 - 4;
	POP(EAX);

	PUSH((int) syswork_sel);
	POP(DS);

//	PUSH((int) 0);
	#if (defined(PCAT))
		asmout("MOV AL,BYTE PTR DS:[FD_motor_init]");
		/* 0x0c(全モーター停止、ドライブ0選択)か0x1c(drv0のモーター回転、他は停止、ドライブ0選択) */
		PUSH(EAX);
	#endif
	#if (defined(TOWNS))
		PUSH((int) 0x0301 /* 全モーター停止、ドライブ0選択 */);
	#endif
	PUSH((int) 0x0100 /* 初期化 */);
	EBX = ESP;
	CALLFAR0(fdcdrive_sel);
	ESP += 12;

	/* PIT2の初期化、消音 */
//	PUSHFD();
	CLI();
	#if (defined(PCAT))
		IN(AL, 0x0061);
		AL &= 0x0d;
		AL |= 0x01;
		OUT(0x0061, AL);
		AL = 0xb6;
		OUT(0x0043, AL);
		EAX = 0;
		OUT(0x0042, AL);
		NOP();
		OUT(0x0042, AL);
	#endif
	#if (defined(TOWNS))
		IN(AL, 0x0060);
		AL >>= 2;
		AL &= 0x03;
		OUT(0x0060, AL);
		AL = 0xb6;
		OUT(0x0046, AL);
		EAX = 0;
		OUT(0x0044, AL);
		NOP();
		OUT(0x0044, AL);
	#endif
//	POPFD();
	STI();

	/* root作成 */
	/*	+0000 : header
		+0200 : tag-buf. area-struct
		+0400 : root-tags
		+0600 : directorys(for root)
		+0800 : task-tags
		+0a00 : directorys(for task)

		+0c00 : init-tags(task directory)
		+0e00 : directorys(for init)
	*/
	ECX = 32 * 1024; /* 32KB */
	alloc_memory();
	if (ZF == 1)
		INT(0x03);
	work->root_size = ECX;
	work->root_addr = EDX;
	work->root_Paddr = EAX;
	PUSH((int) idtgdt_sel);
	EBX = 384 /* IDTの分 */ + root_sel;
	POP(GS);
	EAX = 0x4092; /* lv0, Read/Write, use32 */
	set_modulesegment();
	PUSH((int) root_sel);
	ESI = 512;
	POP(DS);
	EDX = 0;
	EAX = 0;
	EDX--;
	ECX = 512 - 40;
	area_man_struct *root_areastr == DS:ESI;
	root_areastr->use = EAX;
	root_areastr->size0 = ECX;
	root_areastr->data0.size = EAX;
	root_areastr->data0.addr = EAX;
	root_areastr->data[0].size = EDX;
	root_areastr->data[0].addr = EDX;
	EAX = 1024;
	ECX = 1024 * 31;
	free_area();

	ECX = 512; /* tag用の領域 */
	ESI = 512; /* allocator */
	alloc_tagdir();
	PUSH(CS);
	asmout("MOV EBX,OFFSET #rootdir");
	POP(GS);
	add_tags(); /* GS:EBXをDS:EDIへ。EDIは保存される。EAX, ECX, EDXは破壊 */
	/* "link to directory"タグを見つけると、自動的にアロケートする */
	/* ここでは、EDI = 1024と分かっているので、EDIを保存しない */

	ECX = 512; /* tag用の領域 */
//	ESI = 512; /* allocator */
	alloc_tagdir(); /* EDI = 2048 */
	asmout("MOV EBX,OFFSET #tasksdir");
	add_tags(); /* GS:EBXをDS:EDIへ。EDIは保存される。EAX, ECX, EDXは破壊 */
	/* "link to directory"タグを見つけると、自動的にアロケートする */
	EBX = 1024;
	regist_module(); /* EBXのディレクトリにEDIのモジュール(タグディレクトリ)を接続する */

	ECX = 512; /* tag用の領域 */
//	ESI = 512; /* allocator */
	alloc_tagdir(); /* EDI = 3072 */
	asmout("MOV EBX,OFFSET #gapidata_mdl");
	add_tags(); /* GS:EBXをDS:EDIへ。EDIは保存される。EAX, ECX, EDXは破壊 */
	EBX = 1024;
	regist_module(); /* EBXのディレクトリにEDIのモジュール(タグディレクトリ)を接続する */

	/* GAPIのフォント領域管理(暫定) */
	area_man_struct *gapifontarea == DS:ESI;
	(offset) gapifontarea = 0x0c00;
	PUSH((int) GAPIwork_sel);
	EDX = 0;
	POP(DS);
	EAX = 0;
	EDX--;
	ECX = 1024 - 40;
	gapifontarea->use = EAX;
	gapifontarea->size0 = ECX;
	gapifontarea->data0.size = EAX;
	gapifontarea->data0.addr = EAX;
	gapifontarea->data[0].size = EDX;
	gapifontarea->data[0].addr = EDX;
	EAX = 612 * 1024; /* 最初の4KBはワーク。次の4KBはANK。次の608KBはOSASK共通フォント。 */
	ECX = 92 * 1024;
	free_area();

	PUSH((int) syswork_sel);
	PUSH(SS /* stack_sel */);
	POP(ES); /* = stack_sel; */
	POP(GS); /* = syswork_sel; */

	/* 自分自身のタスク情報を構築する */
	EDX = 0;
	PUSH((int) EDX);
	PUSH((int) EDX /* stack3の物理アドレス(確保していなければ0xffffffff) */);
	PUSH((int) EDX /* stack3のサイズ */);
	PUSH((int) EDX /* stack0の物理アドレス(high) */);
	PUSH((int) [GS:32 + stack_ent + 0x0c] /* stack0の物理アドレス(確保していなければ0xffffffff) */);
	PUSH((int) [GS:32 + stack_ent + 0x08] /* stack_ent.size */ /* stack0のサイズ */);
	PUSH((int) 0xffffffff /* タスクディレクトリ(high) */);
	PUSH((int) 0xffffffff /* タスクディレクトリ(low) */);
//	ESP -= 8;
	PUSH(EAX);
	PUSH(EAX);
	PUSH(EDX);
	PUSH(EDX);
	PUSH(EDX);
	PUSH((int) [GS:32 + init_ent + 12]);
	PUSH((int) [GS:32 + init_ent +  8]);
	EBX = ESP;
	/* ES:EBXからの16バイトがパラメーター(コードサイズ、コードロード物理アドレス、ヘッダパラメーター) */
	/* そのあとの8バイトがリザーブ。 */
	/* そのあとの4バイトはtskdir。linear領域に付いては、連続一枚にする。 */
	/* code, stack0, stack3 */
	/* stack0は必ず必要。stack3はヘッダパラメーターを読めば必要かどうかが判断できる */
	/*	{
			int codesize, codeaddr[8], header[8], reserve[8];
			int tskdir[8], stack0size, stack0addr[8], stack3size, stack3addr[8];
		}; // total 60bytes
	*/
	create_task();
	ESP += 60;

	/* このタスクのLlvを定義し、TskPointerを設定し、TRへ代入する。 */

	TAPI_TSS *tss == DS:ESI;
	TAPI_LlvPrm *tss_Llv0 == DS:ESI + 256, *tss_Llv1 == DS:ESI + 256 + 32, *tss_Llv2 == DS:ESI + 256 + 64;
	TAPI_GlvPrm *glevel == DS:0x0100;

	PUSH((int) tapiwork_sel);
	(offset) tss = EBP;
//	EDX = 0;
	POP(DS);

	LEA(EAX, (int) *tss_Llv1); // Llv1
	tss->Glv = /* (offset) glevel[4 * 64] */ 0x0200; // Glvは0x100〜0x800
	tss->Llv = EAX;
	tss->Ilv = EDX /* 0 */;
	tss->flags = DL /* 0 */;
	(char) tss->short_run[11] = 0xff;

	tss_Llv1->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
	(char) tss_Llv1->short_run[11] = 0xff;
	tss_Llv1->Ilv = EDX /* 0 */;

	/* ローカルレベルを少し下げて、また上がる */
	/* 未知(TAPIかも???)のバグ回避(2001.08.01) */
	tss_Llv2->Glv = /* (offset) glevel[12 * 64] */ 0x0400;
	(char) tss_Llv2->short_run[11] = 0xff;
	tss_Llv2->Ilv = 11932; // 10msec.

	(int) [DS:EDX + 0x000c /* TskPointer */] = (offset) tss;
	(int) [DS:EDX + 0x001c /* GlvNow */] = /* (offset) glevel[4 * 64] */ 0x0200;

	LTR((short) tss->tr[0]);
	LLDT((short) tss->tss386.LDTR);
	tss->back = (offset) tss;
	tss->next = (offset) tss;

	TAPI_GlvPrm *glv == DS:EAX;

	LEA((offset) glv, (int) glevel[4 * 64]);
	glv->pointer = (offset) tss;
	glv->tasks = 1;
//	glv->MinIlv = 0;
//	glv->MaxIlv = 0xffffffff;
	glv->flags = 0x02; /* 時分割抑制モード */

	LEA((offset) glv, (int) glevel[12 * 64]);
//	glv->pointer = 0;
	glv->tasks = EDX /* 0 */;
	glv->MinIlv = EDX /* 0 */;
	glv->MaxIlv = 0xffffffff;
	glv->flags = DL /* = 0x00 */; /* 時分割モード */

//	glevel[26 * 64].pointer = 0; /* idle task */
//	glevel[26 * 64].tasks = 0;
//	glevel[26 * 64].MinIlv = 0;
//	glevel[26 * 64].MaxIlv = 0xffffffff;
	glevel[26 * 64].flags = 0x02; /* 時分割抑制モード */

//	glevel[27 * 64].pointer = 0; /* sleep level */
//	glevel[27 * 64].tasks = 0;
//	glevel[27 * 64].MinIlv = 0;
//	glevel[27 * 64].MaxIlv = 0xffffffff;
	glevel[27 * 64].flags = 0x02; /* 時分割抑制モード */

	/* 自分自身のsoftint設定 */
	(offset) tss = [DS:EDX + 0x000c /* TskPointer */];
//	LEA(EAX, [(offset) tss + 0x0120 /* Llv1 */]);
//	tss->softint_Llv = EAX;
	tss->softint_Llv = 0x01;
//	tss->softint_mode = 0;

//	GUIGUI_task_struct *tasklist == SS:EBP;

	/* アイドルタスク生成 */
//	EAX = 0;
//	EDX = 0;
//	EAX--;
	LEA(EAX, [EDX - 1]);
	PUSH((int) EDX);
	PUSH((int) EDX /* stack3の物理アドレス(確保していなければ0xffffffff) */);
	PUSH((int) EDX /* stack3のサイズ */);
	PUSH((int) EAX);
	PUSH((int) EAX /* stack0の物理アドレス(確保していなければ0xffffffff) */);
	PUSH((int) EAX /* stack0のサイズ(自動設定なら0xffffffff) */);
	PUSH((int) EAX);
	PUSH((int) EAX /* タスクディレクトリ */);
	ESP -= 8;
	PUSH(EDX);
	PUSH(EDX);
	PUSH(EDX);
	PUSH((int) [GS:32 + init_ent + 12]);
	PUSH((int) [GS:32 + init_ent +  8]);
	EBX = ESP;
	create_task();
	ESP += 60;
//	EAX = tapiwork_sel;
	(offset) tss = EBP;
//	DS = AX;
	asmout("MOV DWORD PTR DS:[ESI+32],OFFSET IdleTask");
	EAX = tss->tss386.stack0_ESP;
	ECX = (int) tss->tss386.stack0_SS;
	tss->tss386.ESP = EAX;
	(int) tss->tss386.SS = ECX;
//	EDX = 0;
	tss->tss386.CS = CS;
	(int) tss->tss386.ES = EDX;
	(int) tss->tss386.DS = EDX;
	(int) tss->tss386.FS = EDX;
	(int) tss->tss386.GS = EDX;
	tss_Llv1->Glv = /* (offset) glevel[26 * 64] */ 0x0780;
	(char) tss_Llv1->short_run[11] = 0xff;
//	tss_Llv1->Ilv = 11932; // 10msec.
//	tss_Llv2->Glv = /* (offset) glevel[26 * 64] */ 0x0780;
//	(char) tss_Llv2->short_run[11] = 0xff;
//	tss_Llv2->Ilv = 11932; // 10msec.
//	LEA(EDI, [tss_Llv1]);
//	EDI = 1;
	PUSH((int) EDX /* 0 */);
	PUSH((int) 1 /* Llv */);
	PUSH((offset) tss);
	PUSH((int) 0x0104 /* TAPI_RegisterTask_ChangeLlv */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16 - 4;

//!!!!

	/* winman0 */
//	EDX = 0;
	PUSH((int) all_sel);
//	EAX--;
//	EAX = 0;
	LEA(EAX, [EDX - 1]);
	POP(DS);
	EBX = [GS:32 + winman0_ent + 12];
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* stack3の物理アドレス(確保していなければ0xffffffff) */);
	PUSH(EAX /* (int) 0xffffffff */ /* stack3のサイズ(自動設定なら0xffffffff) */);
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* stack0の物理アドレス(確保していなければ0xffffffff) */);
	PUSH(EAX /* (int) 0xffffffff */ /* stack0のサイズ(自動設定なら0xffffffff) */);
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* タスクディレクトリ */);
	ESP -= 8;
	PUSH((int) [DS:EBX + 20]);
	PUSH((int) [DS:EBX + 16]);
	PUSH((int) 0);
	PUSH((int) EBX);
	PUSH((int) [GS:32 + winman0_ent +  8]);
	EBX = ESP;
	create_task(); /* 0x3000 */
	ESP += 60;
	PUSH((int) tapiwork_sel);
	(offset) tss = EBP /* tasklist->tskptr */;
	POP(DS);
	tss_Llv1->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
	(char) tss_Llv1->short_run[11] = 0xff;
	tss_Llv1->Ilv = /* 0 */ EDX;
	tss_Llv2->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
	(char) tss_Llv2->short_run[11] = 0xff;
	tss_Llv2->Ilv = /* 0 */ EDX;
//	PUSH((int) /* 0 */ EDX);
	PUSH((int) 1 /* Llv */);
	PUSH((offset) tss);
	PUSH((int) 0x0104 /* TAPI_RegisterTask_ChangeLlv */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16 - 4;

	/* pokon0 */
	PUSH((int) all_sel);
//	EDX = 0;
//	EAX = 0;
//	EAX--;
	LEA(EAX, [EDX - 1]);
	POP(DS);
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* stack3の物理アドレス(確保していなければ0xffffffff) */);
	PUSH(EAX /* (int) 0xffffffff */ /* stack3のサイズ(自動設定なら0xffffffff) */);
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* stack0の物理アドレス(確保していなければ0xffffffff) */);
	PUSH(EAX /* (int) 0xffffffff */ /* stack0のサイズ(自動設定なら0xffffffff) */);
	PUSH(EAX);
	PUSH(EAX /* (int) 0xffffffff */ /* タスクディレクトリ */);
	ESP -= 8;
//	EBX = 32 + pokon0_ent + 8;
	EAX = [GS:32 + pokon0_ent + 12];
	PUSH((int) [DS:EAX + 20]);
	PUSH((int) [DS:EAX + 16]);
	PUSH((int) 0);
	PUSH(EAX);
	PUSH((int) [GS:32 + pokon0_ent +  8]);
	EBX = ESP;
	create_task(); /* 0x4000 */
	ESP += 60;
	PUSH((int) tapiwork_sel);
	(offset) tss = EBP;
	POP(DS);
	tss_Llv1->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
	(char) tss_Llv1->short_run[11] = 0xff;
	tss_Llv1->Ilv = EDX /* 0 */;
	tss_Llv2->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
	(char) tss_Llv2->short_run[11] = 0xff;
	tss_Llv2->Ilv = EDX /* 0 */;
//	PUSH((int) EDX /* 0 */);
	PUSH((int) 1 /* Llv */);
	PUSH((offset) tss);
	PUSH((int) 0x0104 /* TAPI_RegisterTask_ChangeLlv */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16 - 4;

	#if (defined(PCAT))
		/* v86タスク生成 */
		ECX = 4096; /* 4KB */
	//	/* ESI = (offset) work->mem20_man; */ LEA(ESI, (int) work->mem20_man);
	//	AX = SS;
	//	DS = AX;
	//	get_area(); /* 本来はZFによるエラーチェックが必要 */
	//	/* EBPを破壊しないこと */
	//	if (ZF == 1 /* error */) {
	//		INT(0x03);
	//	}

	//	PUSH((int) 0);
		PUSH(EDX); /* ダミー */
		PUSH((int) 2 /* mem20 */);
		PUSH(EDX);
		PUSH((int) EDX /* 0 */);
		PUSH((int) 0x0114);
		EBX = ESP;
		CALLFAR0(papi_sel);
		EAX = [SS:ESP + 16];
		ESP += 24 - 4;

	//	EDX = 0;
		PUSH(EDX);
		PUSH((int) EDX /* stack3の物理アドレス(確保していなければ0xffffffff) */);
		PUSH((int) EDX /* stack3のサイズ(自動設定なら0xffffffff) */);
		PUSH(EDX);
		PUSH((int) EAX /* stack0の物理アドレス(確保していなければ0xffffffff) */);
		PUSH((int) ECX /* stack0のサイズ(自動設定なら0xffffffff) */);
		PUSH((int) 0xffffffff);
		PUSH((int) 0xffffffff /* タスクディレクトリ */);
	//	ESP -= 8;
		PUSH(EDX);
		PUSH(EDX);
	//	EBX = 32 + init_ent + 8;
		PUSH((int) EDX);
		PUSH((int) EDX);
		PUSH((int) 0);
		PUSH((int) [GS:32 + init_ent + 12]);
		PUSH((int) [GS:32 + init_ent +  8]);
		EBX = ESP;
		create_task(); /* 0x5000 */
		ESP += 60;
		PUSH((int) tapiwork_sel);
		(offset) tss = EBP; 
		POP(DS);
	//	tss->tss386.IOBitMap = 0x0100;
		tss_Llv1->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
		(char) tss_Llv1->short_run[11] = 0xff;
		tss_Llv1->Ilv = EDX /* 0 */;
		tss_Llv2->Glv = /* (offset) glevel[4 * 64] */ 0x0200;
		(char) tss_Llv2->short_run[11] = 0xff;
		tss_Llv2->Ilv = EDX /* 0 */;
	//	PUSH((int) EDX /* 0 */);
		PUSH((int) EDX /* 0 */ /* Llv */);
		PUSH((offset) tss);
		PUSH((int) 0x0104 /* TAPI_RegisterTask_ChangeLlv */);
		EBX = ESP;
		CALLFAR0(tapi_sel);
		ESP += 16 - 4;
	#endif

//	PUSH((int) EDX /* 0 */);
	PUSH((int) 0x0010); /* 画面初期化要請 */
	#if (defined(VMWARE))
		PUSH((int) 1 /* to_winman0 */); /* for VM ware */
	#else
		PUSH((int) [GS:0x0014 /* to_winman0 */]);
	#endif
	PUSH((int) 0x0018); /* fromboot */
	PUSH((int) 0x7f000003);
	PUSH((int) 0x3240 + 4);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 28 - 4;

//!!!

//	PUSH((int) 0); /* eoc */
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x011c /* TAPI_SingnalMessageTimerベクタ要求 */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	POP(EAX);
	POP(work->TAPI_sendmsgofs);
	POP(work->TAPI_sendmsgsel);
//	POP(EAX);

#if 0
	/* cacheflags, track初期化 */
	EAX = 0;
	ECX = 16 + 5; /* (64 + 20) / 4 */
	LEA(EBP, work->cacheflags[ 0]);
	do {
		[SS:EBP] = EAX;
		EBP += 4;
		ECX--;
	} while (!= 0);

	PUSH(DS);

	PUSH(SS);
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	POP(DS);
	ECX = 0x00200000; /* 2MB */
	get_area();
	work->diskcache_Laddr = EAX;

	#if (defined(PCAT))
		ECX = 12 * 1024; /* 12KB */
		/* ESI = (offset) work->mem24_man; */ LEA(ESI, (int) work->mem24_man);
		get_area();
		if (ZF == 1) {
			/* ESI = (offset) work->mem20_man; */ LEA(ESI, (int) work->mem20_man);
			get_area();
		}
	#endif

	#if (defined(TOWNS))
		ECX = 8 * 1024; /* 8KB */
		get_memory();
	#endif

	work->diskbuf_Paddr = EAX;
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	get_area();
	PUSH((int) pdepte_sel);
	EDX = EAX;
	POP(DS);
	work->diskbuf_Laddr = EAX;
	EAX = 0x07;
	EAX |= work->diskbuf_Paddr;
	mapping();

	POP(DS);
#endif

	#if (defined(PCAT))
	//	PUSH((int) 0); /* eoc */
		PUSH((int) 4);
		PUSH((int) 0x1241); /* initタスクに1dwのメッセージ */
		PUSH(work->TAPI_sendmsgsel);
		PUSH(work->TAPI_sendmsgofs);
		PUSH((int) 0x0114 /* SetFinishSignal */);
		EBX = ESP;
		CALLFAR0(keyint_sel); /* KeyboardResetが終わるのを待つ */
		ESP += 24;

	//	EAX = 0;
	//	PUSH(EAX); /* eoc */
	//	PUSH(EAX); /* signals */
	//	PUSH(EAX); /* delta-nest(割り込みを使わないから、nestは変更しない), Llv(Llv0-sleep) */
	//	PUSH((int) 0x010c); /* TAPI_AddNestSleep */
	//	EBX = ESP;
	//	CALLFAR0(tapi_sel);
	//	ESP += 16;
	#endif

	#if (defined(TOWNS))
		IN(AX, 0x0030); /* CPU識別レジスタ */
		PUSH(DS);
		AL &= 0x07;
		if (AL != 0x03) {
			/* i386DX, i486, Pentium */
			EBX = 0x00100000;
			EBP = 15;
		//	EBX = 0x00300000;
		//	EBP = 13;
			testmemory();

			ECX = 0;
			PUSH((int) ECX);
			PUSH((int) ECX);
			PUSH((int) 0x80000101);
			PUSH((int) ECX);
			PUSH((int) ECX);
			PUSH((int) 0x0114);
			EBX = ESP;
			CALLFAR0(papi_sel);
			EAX = [SS:ESP + 16];
			ESP += 24;
			if (EAX != 0 /* (unsigned) work->mem24_man.data[0].size >= 0x00e00000 */) {
				/* 14MB以上 */
				EBX = 0x01000000;
				EBP = 1024 - 16;
				testmemory();
			}
		} else {
			/* i386SX */
			EBX = 0x00100000;
			EBP = 9;
		//	EBX = 0x00300000;
		//	EBP = 7;
			testmemory();
		}
		POP(DS);
		ECX = 0;
	//	PUSH((int) ECX);
		PUSH((int) 0x80000001);
		PUSH((int) 160 * 9 * 1024 /* for debug */ /* 160 * 8 * 1024 : TOWNS */);
		PUSH((int) ECX);
		PUSH((int) 0x0114);
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 20;

	//	ECX = 160 * 8 * 1024;
	//	work->mem24_man.data[0].size -= ECX;
	//	work->mem24_man.data[0].addr += ECX;

		/* ローディング開始 */
		PUSH((int) 0);
	//	PUSH((int) 0x0108 /* FDC_diskchange */);
	//	EBX = ESP;
	//	CALLFAR0(fdcdrive_sel);
	//	ESP += 8 - 4;
		/* このルーチンは古すぎる。PC/AT用のを参考に書き直せ */
	//	/* GSの値はおかしいので代入せよ */
	//	asmout("TEST BYTE PTR GS:[DiskCacheReady],01H");
	//	if (!= 0) {
	//		PUSH((int) 0);
	//		PUSH((int) 0x0301 /* FDD motor off */);
	//		PUSH((int) 0x0124 /* FDC motorcontrol */);
	//		PUSH((int) 0x010c /* FDC_diskcache1 */);
	//		EBX = ESP;
	//	//	CALLFAR0(fdcdrive_sel);
	//		ESP += 16;
	//	}
	//	PUSH((int) 0);
		PUSH((int) 12 /* 作業中のシグナル */);
		PUSH((int) 16 /* 完了シグナル */);
		PUSH((int) 0x0110 /* FDC_loadFAT */);
		PUSH((int) 0x0108 /* FDC_diskchange */);
		EBX = ESP;
		CALLFAR0(fdcdrive_sel);
		ESP += 20;
	#endif

	int *msg == GS:ESI;
	unsigned int msgdw == EDI;

	PUSH((int) 0x0024); // msgboxリードセレクタ
	(offset) msg = 0;
	POP(GS);

	/* ループ不変条件：FS == SS */
	/* DS, ESは不定値をとってよい */
	for (;;) {
		msgdw = 0;
		do {
			EAX = msg[0];
			if (EAX == 0) {	// terminate
				break;
			} else if (EAX == 1) {	// rewind
				msgdw += msg[4];
				(offset) msg = 0;
				continue;
			} else if (EAX == 2) { // mouse
			//	EAX = msg[4];
			//	mousetest();
			//	INT(0x03);
				(offset) msg += 8;
				msgdw += 2; /* 処理したコマンド数 */
			} else if (EAX == 4) {
				#if (defined(PCAT))
					/* キーボード初期化完了 */
					(offset) msg += 4;
					msgdw++;
					PUSH((offset) msg);
					PUSH(msgdw);

					PUSH((int) 0); /* eoc */
					PUSH((int) 0x0120 /* MouseEnable */);
					PUSH((int) 0x011c /* MouseReset */);
					PUSH((int) 0x0118 /* KeyEnableA20 */);
					EBX = ESP;
					CALLFAR0(keyint_sel);
					ESP += 16 - 4;

				//	PUSH((int) 0); /* eoc */
					PUSH((int) syswork_sel);
					POP(DS);
					asmout("MOVZX EAX,BYTE PTR DS:[boot_keylock]");
					PUSH(EAX); /* Lock Status */
					PUSH((int) 0x0104 /* Keydecode_setlock */);
					EBX = ESP;
					CALLFAR0(decode_sel);
					ESP += 12 - 4;

				//	PUSH((int) 0); /* eoc */
					PUSH((int) 8);
					PUSH((int) 0x1241); /* initタスクに1dwのメッセージ */
					PUSH(work->TAPI_sendmsgsel);
					PUSH(work->TAPI_sendmsgofs);
					PUSH((int) 0x0114 /* SetFinishSignal */);
					EBX = ESP;
					CALLFAR0(keyint_sel); /* KeyEnableA20が終わるのを待つ */
					ESP += 24;

					POP(msgdw);
					POP((offset) msg);
				#endif
			} else if (EAX == 8) { /* A20有効化完了 */
				#if (defined(PCAT))
					(offset) msg += 4;
					msgdw++;
				//	PUSH(DS);
					PUSH((offset) msg);
					PUSH(msgdw);

					PUSH((int) all_sel);
					EAX = 0xaa55aa55;
					EDX = 0x55aa55aa;
					POP(DS);

					/* A20のテスト */
					ESI = 0;
					EBX = 0x100000;
					ECX = [DS:ESI];
					[DS:EBX] = EDX;
					[DS:ESI] = EAX;
					CMP(EAX,[DS:EBX]);
					[DS:ESI] = ECX;
					if (==) {
						INT(0x03); /* A20エラー */
					}

					EBX = 0x00100000;
					EBP = 15;
				//	EBX = 0x00300000;
				//	EBP = 13;
					testmemory();

					ECX = 0;
					PUSH((int) ECX);
					PUSH((int) ECX);
					PUSH((int) 0x80000101);
					PUSH((int) ECX);
					PUSH((int) ECX);
					PUSH((int) 0x0114);
					EBX = ESP;
					CALLFAR0(papi_sel);
					EAX = [SS:ESP + 16];
					ESP += 24 - 4;
					if (EAX != 0 /* (unsigned) work->mem24_man.data[0].size >= 0x00e00000 */) {
						/* 14MB以上 */
						EBX = 0x01000000;
						EBP = 3 * 1024 - 16;
						testmemory();
					}

					ECX = 0;
				//	PUSH((int) ECX);
					PUSH((int) 0x80000001);
					PUSH((int) 160 * 9 * 1024);
					PUSH((int) ECX);
					PUSH((int) 0x0114);
					EBX = ESP;
					CALLFAR0(papi_sel);
					ESP += 20;

				//	ECX = 160 * 9 * 1024;
				//	work->mem24_man.data[0].size -= ECX;
				//	work->mem24_man.data[0].addr += ECX;

/*
	ページング空間はモジュールをなしていて、
	PDEの最初のページは、PTEのオフセットになっている
*/

					/* ローディング開始 */

					PUSH((int) syswork_sel);
					POP(DS);
					PUSH((int) 0);
					PUSH((int) 0x0108 /* FDC_diskchange */);
					EBX = ESP;
					CALLFAR0(fdcdrive_sel);
				//	ESP += 8 - 4;
					POP(EAX);
skip_cleardiskcache:
					asmout("TEST BYTE PTR DS:[DiskCacheReady],01H");
				//	PUSH((int) 0);
					if (!= 0) {
						PUSH((int) 0x0c /* FDD motor off */);
						PUSH((int) 0x0124 /* FDC motercontrol */);
						PUSH((int) 0x010c /* FDC_diskcache1 */);
						EBX = ESP;
						CALLFAR0(fdcdrive_sel); /* 未知のバグ回避(2001.08.01) */
						ESP += 16 - 4;
					}
					asmout("TEST BYTE PTR DS:[DiskCacheReady],02H");
					if (!= 0) {
						/* プリロードしておいた領域を開放(28KB) */
						EAX = 0x001000;
						ECX = 0x007000;
						free_memory(); /* フリーメモリの登録 */

						/* ローカルレベルを少し下げて、また上がる */
						/* 未知(TAPIかも???)のバグ回避(2001.08.01) */
					//	PUSH((int) 0);
						PUSH((int) 1 /* Llv */);
						PUSH((int) 0x1000 /* init task */);
						PUSH((int) 0x0100 /* TAPI_ChangeLlv */);
						PUSH((int) 2 /* Llv */);
						PUSH((int) 0x1000 /* init task */);
						PUSH((int) 0x0100 /* TAPI_ChangeLlv */);
						EBX = ESP;
						CALLFAR0(tapi_sel);
						ESP += 24;
					}
				//	PUSH((int) 0);
					PUSH((int) 12 /* 作業中のシグナル */);
					PUSH((int) 16 /* 完了シグナル */);
					PUSH((int) 0x0110 /* FDC_loadFAT */);
					EBX = ESP;
					CALLFAR0(fdcdrive_sel);
					ESP += 16;

					POP(msgdw);
					POP((offset) msg);
				//	POP(DS);
				#endif
			} else if (EAX == 12) {
				(offset) msg += 4;
				msgdw++;
			//	dosload_nextphase();
				PUSH((int) 0);
				PUSH((int) 0x0114 /* FDC_continue */);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 8;
			} else if (EAX == 16) { /* FATロード完了 */
				(offset) msg += 4;
				msgdw++;
				goto next0;
			} else if ((unsigned) EAX >= 0xffffff00) {
				/* リセットや再起動要求・・・無視 */
				(offset) msg += 4;
				msgdw++;
			} else {
				INT(0x03);
			}
		} while (msgdw < 8);

		EAX = 0;
		PUSH(EAX); /* eoc */
		PUSH(msgdw); /* signals */
		PUSH(EAX); /* delta-nest(割り込みを使わないから、nestは変更しない), Llv0(sleep) */
		PUSH((int) 0x010c); /* TAPI_AddNestSleep */
		EBX = ESP;
		CALLFAR0(tapi_sel);
		ESP += 16;
	}
next0:

	PUSH((int) 0); /* eoc */
	PUSH(msgdw); /* signals */
	PUSH((int) 0xff00); /* delta-nest(割り込みを使わないから、nestは変更しない), Llv nochange */
	PUSH((int) 0x010c); /* TAPI_AddNestSleep */

	PUSH((int) 99); /* break wait */
	PUSH((int) 0x7f000001);
	PUSH((int) 0x4240 + 2);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 32;

	PUSH((offset) msg);
	PUSH(GS);
	PUSH(ES);
	PUSH(DS);
	PUSHAD();

	/* root転送 */
	/* リニアアドレス空間も取り直す(サイズが大きくなるから) */
	PUSH(work->root_Paddr);
	PUSH(work->root_addr);
	PUSH(work->root_size);
	ECX = 512 * 512; /* 256KB */
	alloc_memory();
	if (ZF == 1)
		INT(0x03);
	work->root_size = ECX;
	work->root_addr = EDX;
	work->root_Paddr = EAX;
	PUSH((int) idtgdt_sel);
	EBX = 384 /* IDTの分 */ + root_sel;
	POP(GS);
	EAX = 0x4092; /* lv0, Read/Write, use32 */
	CLI();
	set_modulesegment();
	ESI = [SS:ESP + 4];
	EDI = work->root_addr;
	EBP = [SS:ESP + 0];
	PUSH((int) all_sel);
	POP(DS);
	memcopy16();
	STI();
	EAX = [SS:ESP + 0];
	ECX = work->root_size;
	ECX -= EAX;
	if (!= 0) {
		PUSH((int) root_sel);
		ESI = 512;
		POP(DS);
		free_area();
	}
	POP(ECX);
	POP(EDX);
	PUSH((int) 0 /* eoc */);
	PUSH((int) 0 /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0 /* opt */);
	PUSH((int) 0x010c /* cmd(unmapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 24;
	POP(EAX);
	free_memory();

	PUSH((int) syswork_sel);
	POP(ES);
	PUSH((int) all_sel);
	POP(DS);

#if 1
	/* pdepte */
//	PUSH((int) syswork_sel);
//	POP(ES);
	EDI = 32 + PDEPTE_ent;
	PUSH((int) [ES:EDI + 0x0c]);
	ECX = 4096 * 67; /* 268KB(256MB) 下も連動 */
	PUSH((int) [ES:EDI + 0x08]);
	alloc_memory();
	if (ZF == 1)
		INT(0x03);
	[ES:EDI + 0x08] = ECX;
	[ES:EDI + 0x0c] = EAX;
	EDI = EDX;
	PUSH(EAX);

PUSH(EDI);
PUSH(ECX);
EAX = 0;
do {
	[DS:EDI] = EAX;
	EDI += 4;
	ECX -= 4;
} while ((unsigned) > 0);
POP(ECX);
POP(EDI);

	EBX = 384 /* IDTの分 */ + pdepte_sel;
	EAX = 0x4092; /* lv0, Read/Write, use32 */
	CLI();
	set_modulesegment();
	EAX = [SS:ESP];
	EAX += 0x2007;
	LEA(EBX, [EDI + 4]);
	EDX = 0x4000;
	ECX = 67 - 4; /* 上と連動(さらに下とも連動) */
	(int) [DS:EDI + 0x0000] = 0x2000; [DS:EDI + 0x1000] = EAX; EAX += 4096;
	(int) [DS:EDI + 0x0e00] = 0x3000; [DS:EDI + 0x1e00] = EAX; EAX += 4096;
	do {
		[DS:EBX] = EDX;
		[DS:EBX + 0x1000] = EAX;
		EBX += 4;
		EDX += 0x1000;
		EAX += 0x1000;
		ECX--;
	} while (!= 0);
	ESI = [SS:ESP + 8];
	EBP = [SS:ESP + 4]; /* old size */
	ESI += 0x2000;
	EDI += 0x2000;
	EBP -= 0x2000;
	memcopy16();
	POP(EAX);
	ECX = CR3;
	EAX += 4096;
	ECX &= 0xfff;
	EAX |= ECX;
	PUSH((int) tapiwork_sel);
	CR3 = EAX;
	POP(DS);

	#if (defined(PCAT))
		ECX = 0x501c;
	//	[DS:ECX /* (0x501c) V86 task CR3 */] = EAX;
	#endif
	#if (defined(TOWNS))
		ECX = 0x401c;
	//	[DS:ECX /* (0x401c) pokon0 task CR3 */] = EAX;
	#endif
	do {
		[DS:ECX] = EAX;
		CH -= 0x10;
	} while (!= 0);

#if 0
	ECX = 0x101c /* init task CR3 */;
	[DS:ECX /* init task CR3 */] = EAX;
	CH += 0x10;
	[DS:ECX /* (0x201c) idle task CR3 */] = EAX;
	CH += 0x10;
	[DS:ECX /* (0x301c) winman0 task CR3 */] = EAX;
	CH += 0x10;
	[DS:ECX /* (0x401c) pokon0 task CR3 */] = EAX;
	#if (defined(PCAT))
		[DS:ECX /* (0x501c) V86 task CR3 */] = EAX;
	#endif
#endif

	STI();
	PUSH(SS);
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	POP(DS);
	EAX = 20 * 0x00100000; /* 20MB */
	ECX = 236 * 0x00100000; /* (256 - 20) * 1MB (上と連動) */
	free_area();
	POP(ECX);
	POP(EAX);
	PUSH((int) all_sel);
	POP(DS);
	free_memory();
#endif

	/* その他 */
	asmout("MOV ESI,OFFSET #movemodule_list");
	EDI = [CS:ESI];
	do {
		ECX = [ES:EDI + 0x08];
		PUSH(ESI);
		PUSH((int) [ES:EDI + 0x0c]);
		PUSH(ECX);
		ECX += [CS:ESI + 8]; /* 増量サイズ */
		alloc_memory();
		if (ZF == 1)
			INT(0x03);
		[ES:EDI + 0x0c] = EAX;
		EDI = EDX;
		EBX = [CS:ESI + 4];
#if 1
		if (EBX == 384 + GAPIwork_sel) {
			/* EAXにある物理アドレスをどうにかしてタグディレクトリに書き込む */
			/* rootからgapidataを探す */
			/* link-to tagを探す */
			PUSH(DS);
			PUSHAD();
			EAX = root_sel;
			ESI = 1024 /* rootdir */ + 16;
			DS = AX;
			EAX = 0xffe00040;
		//	ESI += 16;
			search_tag_EAX();
			if (ZF == 0) /* dir-link-to:タグが見付からない */
				INT(0x03);
			EBX = [DS:ESI + 16];
			EBX += 16;
			for (;;) {
				ESI = [DS:EBX];
				if (ESI == 0xffffffff)
					INT(0x03); /* 見付からない！(terminator検出) */
				ESI += 16;
				EAX = 0xffe00000; /* nameタグ */
				search_tag_EAX();
				if (ZF == 0) /* nameタグが見付からない */
					INT(0x03);
				if ((unsigned) (int) [DS:ESI +  4] == 16) {
					if ((unsigned) (int) [DS:ESI +  8] == 0x69706167) {
						if ((unsigned) (int) [DS:ESI + 12] == 0x61746164)
							break;
					}
				}
				EBX += 4;
			}
			EAX = 0xffe00003; /* link-to:タグ */
			search_tag_EAX();
			if (ZF == 0) /* タグが見付からない */
				INT(0x03);
			EAX = [SS:ESP + 28];
			[DS:ESI + 24] = EAX;
			POPAD();
			POP(DS);
		}
#endif
	//	EAX = idtgdt_sel;
	//	GS = AX;
		EAX = 0x4092; /* lv0, Read/Write, use32 */
		if (EBX == 384 + stack_sel) {
			EAX = 0x0c096; /* lv0, stack, use32 */
			EDX += ECX;
		}
		CLI();
		set_modulesegment();
		ESI = [SS:ESP + 4];
		EBP = [SS:ESP + 0]; /* 旧サイズ */
		memcopy16();
//		ESI = [SS:ESP + 8];
//		if ((unsigned) (int) [CS:ESI + 4] == 384 + idtgdt_sel) {
//			EDI -= 4096;
//			PUSH(EDI);
//			PUSH(383 * 0x10000);
//			asmout("LIDT FWORD PTR SS:[ESP][2]");
//			EDI += 384;
//			(int) [SS:ESP] = 4095 - 384;
//			[SS:ESP + 4] = EDI;
//			asmout("LGDT FWORD PTR SS:[ESP][2]");
//			ESP += 8;
//		}
	//	AX = DS;
	//	CX = ES;
		MOV(EDX, FS);
		MOV(EBX, GS);
		MOV(EBP, SS);
	//	DS = AX;
	//	ES = CX;
		FS = EDX;
		GS = EBX;
		SS = EBP;
		STI();
		POP(ECX);
		POP(EAX);
		free_memory();
		POP(ESI);
		ESI += 12;
		EDI = [CS:ESI];
	} while (EDI != 0);
//	POPAD();
//	POP(DS);
//	POP(ES);
//	POP(GS);

#if 1
	/* stack0/3を転送 */
//	PUSH(GS);
//	PUSH(ES);
//	PUSH(DS);
//	PUSHAD();
	PUSH((int) tapiwork_sel);
	POP(ES);
	asmout("MOV ESI,OFFSET #movestack");
	EAX = [CS:ESI];
	do {
		PUSH(ESI);
		PUSH((int) [CS:ESI + 8]);
		PUSH((int) [CS:ESI + 4]);
	//	PUSH(EAX);
		ECX = root_sel;
		DS = CX;
		CLI();
		ESI = [ES:EAX /* tskdir */];
		EAX = 0xffe00040; /* directory-link-to tag */
		ESI += 16;
		EBX = 16;
		search_tag_EAX();
		EBX += (int) [DS:ESI + 16]; /* link */
		do {
			ESI = [DS:EBX];
			EBX += 4;
			EAX = 0xffe00000 /* name tag */;
			ESI += 16;
			EDI = ESI;
			search_tag_EAX();
			EAX = [DS:ESI +  4]; /* len */
			ECX = [DS:ESI +  8];
			EDX = [DS:ESI + 12];
			EAX ^= 16;
			ECX ^= 0x63617473; /* 'stac' */
			EDX ^= [SS:ESP]; /* 'k3'   */
			EAX |= ECX;
			EAX |= EDX;
		} while (!= 0);
		ESI = EDI;
		EAX = 0xffe00003; /* standard link-to */
		search_tag_EAX();
		EDX = [DS:ESI + 28];
		EAX = [DS:ESI + 24];
		PUSH(EDX);
		PUSH(EAX);
		ECX = [DS:ESI + 16] /* allocated size */;
		PUSH(ECX); /* allocated size */
		get_memory();
		[DS:ESI + 24] = EAX;
		(int) [DS:ESI + 28] = 0;
		PUSH((int) [DS:ESI +  8]); /* used size */
		PUSH(EAX);

		ECX = 0xfff;
		EBX = [SS:ESP + 12 /* old addr */];
		ECX += [SS:ESP +  8] /* allocated size */;
		EDI = 0x00380000; /* 3.5MB */
		ESI = 0x00300000; /* 3MB */
		ECX &= 0xfffff000;
	//	EAX = [SS:ESP + 0 /* new addr */];
		EBP = 0;

		PUSH((int) EBP /* eoc */);
		PUSH((int) EBP /* addr64(high) */);
		PUSH((int) EAX /* addr64(low) */);
		PUSH((int) EBP /* offset64(high) */);
		PUSH((int) EBP /* offset64(low) */);
		PUSH((int) EBP /* pageset */);
		PUSH((int) EDI /* linear */);
		PUSH((int) ECX /* size */);
		PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
		PUSH((int) 0x0108 /* cmd(mapping) */);

		PUSH((int) EDX /* addr64(high) */);
		PUSH((int) EBX /* addr64(low) */);
		PUSH((int) EBP /* offset64(high) */);
		PUSH((int) EBP /* offset64(low) */);
		PUSH((int) EBP /* pageset */);
		PUSH((int) ESI /* linear */);
		PUSH((int) ECX /* size */);
		PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
		PUSH((int) 0x0108 /* cmd(mapping) */);

		EBX = ESP;
		CALLFAR0(papi_sel);
		ECX = all_sel;
		ESP += 76;
		DS = CX;
		EBP = [SS:ESP + 4 /* used size */];
		memcopy16();
		EBX = [SS:ESP + 24]; /* [CS:ESI + 8] : LDTイメージの位置 */
		DL = [ES:EBX + 4];
		DH = [ES:EBX + 7];
		ECX = [SS:ESP + 4 /* used size */]; /* 全領域をmapしてあると想定 */
		EDX <<= 16;
		ECX += 0xfff;
		DX = [ES:EBX + 2];
		EAX = [SS:ESP + 0 /* new addr */];
		ECX &= 0xfffff000;
		if (BL == 24) {
			/* lv0スタック */
			EDX -= ECX;
		}

		EBP = 0;
		PUSH((int) EBP /* eoc */);
		PUSH((int) EBP /* addr64(high) */);
		PUSH((int) EAX /* addr64(low) */);
		PUSH((int) EBP /* offset64(high) */);
		PUSH((int) EBP /* offset64(low) */);
		PUSH((int) EBP /* pageset */);
		PUSH((int) EDX /* linear */);
		PUSH((int) ECX /* size */);
		PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
		PUSH((int) 0x0108 /* cmd(mapping) */);
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 40;

		STI();
		ECX = [SS:ESP +  8 /* allocated size */];
		EAX = [SS:ESP + 12 /* old addr */];
		EDX = [SS:ESP + 16];
		free_memory64();
		ESP += 28;
		POP(ESI);
		ESI += 12;
		EAX = [CS:ESI];
	} while (EAX != 0);
	POPAD();
	POP(DS);
	POP(ES);
	POP(GS);
#endif
//	for (;;); /* ここだと死なない */
	EAX = 0;
	PUSH(EAX); /* eoc */
	PUSH(EAX); /* signals */
	PUSH(EAX); /* delta-nest(割り込みを使わないから、nestは変更しない), Llv0(sleep) */
	PUSH((int) 0x010c); /* TAPI_AddNestSleep とりあえずスリープ */

/* ここでpokonにメモリ関係の準備が完了したことを通知 */

	PUSH((int) 98); /* refreshed! */
	PUSH((int) 0x7f000001);
	PUSH((int) 0x4240 + 2);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);

	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16 + 16;

	POP((offset) msg);
//	for (;;); /* ここだと死ぬ */
/* 仮説1:ローテーションしないと死ぬ */
/* 仮説2:ディスクキャッシュ制御関係 */

	/* ウィンドウオープンシグナルが来ると、ここに来る */

//	int *msg == GS:ESI;
//	unsigned int msgdw == EDI;

	PUSH((int) 0x0024); // msgboxリードセレクタ
//	(offset) msg = 0;
	POP(GS);

	/* ループ不変条件：FS == SSである */
	for (;;) {
		msgdw = 0;
		do {
			EAX = msg[0];
			if (EAX == 0)	/* terminate */
				break;
			if (EAX == 12) {
				(offset) msg += 4;
				msgdw++;
				PUSH((int) 0);
				PUSH((int) 0x0114 /* FDC_continue */);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 8;
			} else if (EAX == 0x8000) {
				(offset) msg += 4;
				msgdw++;
		cmd8000_2:
				LEA(EBX, work->cmd0100_buf[0]);
				PUSH((int) 0);
				PUSH(SS);
				PUSH(EBX);
				PUSH(0x0118 /* コマンドシグナル間接 */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ESP += 16;
			} else if (EAX == 0x8004) { /* 後続のdwを最後のdwに加算する */
				EAX = msg[4];
				(offset) msg += 8;
				msgdw += 2;
				LEA(EBP, work->cmd0100_buf[0]);
				ECX = [SS:EBP];
				ECX &= 0x000f;
				(int) [SS:EBP + ECX * 4] += EAX;
				goto cmd8000_2;

/*
	0x0100と0x0104はバージョンアップの都合で削除された
*/

			} else if (EAX == 0x0108) {
				/* ローカルレベル設定 */
				/* cmd, tss, Llv番号(1〜7 * 32), Glv(? * 64), Ilv */

				TAPI_TSS *cmd0108_tss == DS:EBX;
				TAPI_LlvPrm *cmd0108_tss_Llv == DS:EBX;

				EAX = tapiwork_sel;
				PUSH(DS);
				DS = AX;
				(offset) cmd0108_tss = msg[ 4];
				EAX = msg[12]; // Glv
				(offset) cmd0108_tss_Llv = cmd0108_tss->Llv_base;
				ECX = msg[16]; // Ilv
				(offset) cmd0108_tss_Llv += msg[ 8]; // Llv
				msgdw += 5;
				(offset) msg += 20;
				cmd0108_tss_Llv->Glv = EAX;
				(char) cmd0108_tss_Llv->short_run[11] = 0xff;
				cmd0108_tss_Llv->Ilv = ECX;
				POP(DS);
			} else if (EAX == 0x010c) {
				/* タスクの起動(起動時のLlvを指定する必要あり) */
				/* cmd, tss, Llv番号(1〜7 * 32) */

				TAPI_TSS *cmd010c_tss == DS:EBX;

				PUSH(FS);
				EAX = tapiwork_sel;
				PUSH(DS);
				DS = AX;
				(offset) cmd010c_tss = msg[ 4];
				EDX = msg[8]; // Llv
				msgdw += 3;
				(offset) msg += 12;
				PUSH(EDI);
				PUSH(ESI);
				EDI = EDX;
			//	EDI = cmd010c_tss->Llv_base;
				ESI = (offset) cmd010c_tss;
			//	EDI += EDX;
				(unsigned int) EDI /= 32;

				PUSH((int) 0);
				PUSH((int) 1 /* Llv */);
				PUSH((offset) tss);
				PUSH((int) 0x0104 /* TAPI_RegisterTask_ChangeLlv */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ESP += 16;
				POP(ESI);
				POP(EDI);
				POP(DS);
				POP(FS);
			} else if (EAX == 0x0110) {
INT(0x03);
#if 0
				/* メモリ解放 */
				/* cmd, ent(ofs) */
				PUSH(DS);
				EAX = syswork_sel;
				EBX = msg[4];
				(offset) msg += 8;
				DS = AX;
				msgdw += 2;
				EDX = 0; /* これらは必要なのか？ */
				ECX = [DS:EBX + 0x08];
				EAX = [DS:EBX + 0x0c];
				ECX += 0x00000fff;
				[DS:EBX + 0x08] = EDX; /* これらは必要なのか？ */
				ECX &= 0xfffff000;
				[DS:EBX + 0x0c] = EDX; /* これらは必要なのか？ */
				free_memory(); /* フリーメモリの登録 */
				POP(DS);
#endif
			} else if (EAX == 0x0114) {
				/* diskキャッシュフラッシュ */
				/* cmd, opt, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[8];
				(offset) msg += 12;
				msgdw += 3;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

			//	disable_diskcache();

				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x0110 /* FDC_loadFAT */);
				PUSH((int) 0x0108 /* FDC_diskchange */);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 20;
			} else if (EAX == 0x0118) {
				/* format(66KB) */
				/* cmd, opt, 完了シグナル(lenはシグナルの第一dwから判断) */

				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x011c /* FDC_format */);

	cmd0118_cmd0124:

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[8];
				(offset) msg += 12;
				msgdw += 3;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 16;
			} else if (EAX == 0x011c) {
				/* システムイメージ転送(66KB) */
				/* cmd, opt, bsc_size, bsc_addr, exe_size, exe_addr,
					完了シグナル(lenはシグナルの第一dwから判断) */
				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x00301000);
				PUSH(msg[16]);
				PUSH((int) 0x00300000);
				PUSH(msg[ 8]);
				PUSH((int) 0x0120 /* FDC_writeIPL */);
				goto cmd0128_cmd011c;
			} else if (EAX == 0x0120) {
				/* destory task */
				EAX = msg[4];
				(offset) msg += 8;
				msgdw += 2;
				ECX = tapiwork_sel;
				PUSH(ES);
				PUSH(DS);
				PUSHAD();
				ES = CX;

				/* 最初に切り離す */
				ESI = EAX;
				TAPI_TSS *cmd0120_tss == ES:ESI;
				int *cmd0120_tss_sysdat == ES:ESI + 748; /* 20バイト */
			//	PUSH((int) cmd0120_tss->tr[0]);
				PUSH((int) 0);
				PUSH(EAX); // tss
				PUSH((int) 0x0110); /* TAPI_DestoryTask */
				EBX = ESP;
				CALLFAR0(tapi_sel);
				EAX = cmd0120_tss->fpu_reg_img;
				ESP += 12;
				EAX -= [ES:0x0024 /* taskFPU */];
				if (== 0)
					[ES:0x0024 /* taskFPU */] = EAX;

				/* 次にリソース解放 */
				EDX = 0;
				ECX = cmd0120_tss_sysdat[ 4 /* stack0_size */];
				EAX = cmd0120_tss_sysdat[ 8 /* stack0_addr(linear) */];
				PUSH((int) EDX /* 0 */ /* eoc */);
				PUSH((int) EDX /* 0 */ /* pageset */);
				PUSH((int) EAX /* linear */);
				PUSH((int) ECX /* size */);
				PUSH((int) EDX /* 0 */ /* opt */);
				PUSH((int) 0x010c /* cmd(unmapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 24;

				PUSH(ESI);
				PUSH((int) stack_sel);
				/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
				POP(DS);
				free_area();
				POP(ESI);

				ECX = cmd0120_tss_sysdat[12 /* stack3_size */];
				if (ECX != 0) {
					EAX = cmd0120_tss_sysdat[16 /* stack3_addr(linear) */];
					PUSH((int) EDX /* 0 */ /* eoc */);
					PUSH((int) EDX /* 0 */ /* pageset */);
					PUSH((int) EAX /* linear */);
					PUSH((int) ECX /* size */);
					PUSH((int) EDX /* 0 */ /* opt */);
					PUSH((int) 0x010c /* cmd(unmapping) */);
					EBX = ESP;
					CALLFAR0(papi_sel);
					ESP += 24;

					PUSH(ESI);
					PUSH((int) stack_sel);
					/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
					POP(DS);
					free_area();
					POP(ESI);
				}
				EAX = work->tapiwork_Laddr;
				EAX += [SS:ESP + 28]; /* tss(EAX) */
				ESI = cmd0120_tss_sysdat[ 0 /* tskdir */];
				PUSH((int) EDX /* 0 */ /* eoc */);
				PUSH((int) EDX /* 0 */ /* pageset */);
				PUSH((int) EAX /* linear */);
				PUSH((int) 4096 /* size */);
				PUSH((int) EDX /* 0 */ /* opt */);
				PUSH((int) 0x010c /* cmd(unmapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 24;

				/* タスクディレクトリ内のモジュールを全て開放 */

			//	PUSH(EDI);
				PUSH(ESI);
				PUSH((int) root_sel);
			//	ESI = cmd0120_tss_sysdat[ 0 /* tskdir */];
				POP(DS);
				ESI += 16;
				EAX = 0xffe00040; /* directory-link-to tag */
				EBX = 16;
				search_tag_EAX();
				EBX += (int) [DS:ESI + 16]; /* link */
				EDI = [DS:EBX];
				EBX += 4;
			//	if (EDI != 0xffffffff) {
					do {
						delete_binmodule(); /* ディレクトリが混ざっていることは想定していない */
						EDI = [DS:EBX];
						EBX += 4;
					} while (EDI != 0xffffffff);
			//	}
				ESI = [SS:ESP + 28 + 4] /* EAX */;
			//	EDI = cmd0120_tss_sysdat[ 0 /* tskdir */];
				POP(EDI);
				delete_directory();
			//	POP(EDI);

				EAX = [SS:ESP + 28] /* EAX */;
				(unsigned int) EAX /= 4096;
				EAX--;
				BTS(work->tapiwork_man.bitmap[0], EAX);
	
				/* 最後に、tss番号をpokon0に通達 */
				/* pokon0は、それに応じてメモリバンクを解放してもいいし、しなくてもいい。 */
				EAX = [SS:ESP + 28]; // EAX
				PUSH((int) 0);
				PUSH(EAX);
				PUSH((int) 0x0080);
				PUSH((int) 0x7f000002);
				PUSH((int) 0x4240 + 3);
				PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ESP += 24;
				POPAD();
				POP(DS);
				POP(ES);
			} else if (EAX == 0x0124) {
				/* format(72KB 512Byets/Sector) */
				/* cmd, opt, 完了シグナル(lenはシグナルの第一dwから判断) */
				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x0128 /* FDC_format2 */);
				goto cmd0118_cmd0124;
			} else if (EAX == 0x0128) {
				/* システムイメージ転送(512bytes/sector) */
				/* cmd, opt, bsc_size, bsc_addr, exe_size, exe_addr,
					完了シグナル(lenはシグナルの第一dwから判断) */
				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x00301000);
				PUSH(msg[16]);
				PUSH((int) 0x00300000);
				PUSH(msg[ 8]);
				PUSH((int) 0x012c /* FDC_writeIPL2 */);

	cmd0128_cmd011c:
				LEA(EBP, work->cmd0100_buf[4]);
				PUSH(ES);
				PUSH(DS);
				PUSH(msg[20]);
				PUSH(msg[16]);
				PUSH(msg[12]);
				PUSH(msg[ 8]);
				ECX = msg[24];
				(offset) msg += 28;
				msgdw += 7;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				/* マッピング */
				EAX = syswork_sel;
			//	ECX = pdepte_sel;
				ES = AX;
			//	DS = CX;
				EAX = [SS:ESP + 4 /* bsc_addr */];
				EDX = 0x00300000; /* 3MB */
			//	EAX |= 0x07;
				ECX = 4096;

				EBX = 0;
				PUSH((int) EBX /* eoc */);
				PUSH((int) EBX /* addr64(high) */);
				PUSH((int) EAX /* addr64(low) */);
				PUSH((int) EBX /* offset64(high) */);
				PUSH((int) EBX /* offset64(low) */);
				PUSH((int) EBX /* pageset */);
				PUSH((int) EDX /* linear */);
				PUSH((int) ECX /* size */);
				PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
				PUSH((int) 0x0108 /* cmd(mapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 40;

				ECX = [SS:ESP +  8 /* exe_size */];
				EAX = [SS:ESP + 12 /* exe_addr */];
				ECX += 0x0fff;
				EDX = 0x00301000; /* 3MB + 4KB */
			//	EAX |= 0x07;
				ECX &= 0xfffff000;

				EBX = 0;
				PUSH((int) EBX /* eoc */);
				PUSH((int) EBX /* addr64(high) */);
				PUSH((int) EAX /* addr64(low) */);
				PUSH((int) EBX /* offset64(high) */);
				PUSH((int) EBX /* offset64(low) */);
				PUSH((int) EBX /* pageset */);
				PUSH((int) EDX /* linear */);
				PUSH((int) ECX /* size */);
				PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
				PUSH((int) 0x0108 /* cmd(mapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 40;

				/* ヘッダ解読 */
				EAX = all_sel;
			//	EDX = [DS:32 + empty00_ent + 0x0c];
			//	EDX = 0x00301000;
				DS = AX;
				EBX = (unsigned short) [DS:EDX + 0x18 /* relocation table pointer */];
				for (;;) {
					EAX = (unsigned short) [DS:EDX + EBX    ];
					ECX = (unsigned short) [DS:EDX + EBX + 2];
					EBX += 4;
					ECX *= 16;
					EAX += ECX;
					if (== 0)
						break;
					(char) [DS:EDX + EAX + 512 + 1] += 0x08;
				}
			//	EAX = [ES:32 + empty00_ent + 0x0c];
			//	ECX = [ES:32 + empty01_ent + 0x0c];
			//	(int) [ES:32 + empty00_ent + 0x0c] = 0x00301000; /* 3MB + 4KB */
			//	(int) [ES:32 + empty01_ent + 0x0c] = 0x00300000; /* 3MB */
				LEA(EBX, [SS:ESP + 24]);
				CALLFAR0(fdcdrive_sel);
			//	[ES:32 + empty00_ent + 0x0c] = EAX;
			//	[ES:32 + empty01_ent + 0x0c] = ECX;
				ESP += 16;
				POP(DS);
				POP(ES);
				ESP += 32;
			} else if (EAX == 0x012c) {
				/* アプリケーションロード(2)
				   cmd, ディレクトリエントリ,
				     完了シグナル(lenはシグナルの第一dwから判断) */

				PUSH(DS);
				EBX = msg[4];

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[8];
				(offset) msg += 12;
				msgdw += 3;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				/* サイズを判定して、malloc */
				EAX = all_sel;
			//	PUSH(msgdw);
				DS = EAX;
			//	PUSH((offset) msg);
				ECX = [DS:EBX + 0x1c]; /* file size */
			//	(int) [SS:EBP - 4] = ECX;
				ECX += 0x00000fff;
				ECX &= 0xfffff000;
				(int) [SS:EBP - 8] = ECX; /* for addr == 0 */
				if (== 0)
					goto skip012c;
				get_memory();
				(int) [SS:EBP - 8] = EAX;
				if (ZF == 1 /* error */) {
					(int) [SS:EBP - 4] = 0xffffffff;
	skip012c:
					POP(DS);
					goto cmd8000_2;
				}
			//	ESI = [SS:ESP + 12]; /* ディレクトリエントリ */

/* 確保したメモリを3MBからの1.5MBにマップする */
//EDX = pdepte_sel;
//ECX += 0xfff;
//DS = DX;
EDX = 0x00300000; /* 3MB */
//ECX &= 0xfffff000;
//EAX |= 0x07;

				PUSH(EBX);
				EBX = 0;
				PUSH((int) EBX /* eoc */);
				PUSH((int) EBX /* addr64(high) */);
				PUSH((int) EAX /* addr64(low) */);
				PUSH((int) EBX /* offset64(high) */);
				PUSH((int) EBX /* offset64(low) */);
				PUSH((int) EBX /* pageset */);
				PUSH((int) EDX /* linear */);
				PUSH((int) ECX /* size */);
				PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
				PUSH((int) 0x0108 /* cmd(mapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 40;
				POP(EBX);

// !!! /* ここにローディングコードを書く */


				PUSH((int) 0);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8004); /* 完了シグナル */
				PUSH(EDX); /* ロードリニアアドレス */
				PUSH(all_sel);
				PUSH(EBX); /* ディレクトリエントリ */
				PUSH((int) 0x0118 /* FDC_dosload */);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 28;
			//	POP((offset) msg);
			//	POP(msgdw);
				POP(DS);
			} else if (EAX == 0x0130) {
				/* アプリケーションタスク生成(タスクプログラムには登録されない) */
				/* cmd, size, addr,
				     完了シグナル(lenはシグナルの第一dwから判断) */
				/* なお、シグナルの最後は、獲得したtssが加算される */
				PUSH(DS);
				EAX = msg[8]; /* addr */
				ESP -= 68; // eocのために4バイト余計にとっている

				/* ここで、ヘッダを読むためだけに、マッピングしてやる */
				/* マップする場所は、0x002ff000(3MB-4KB)。 */
				ECX = 0;
				EDX = 0x002ff000;
				PUSH((int) ECX /* eoc */);
				PUSH((int) ECX /* addr64(high) */);
				PUSH((int) EAX /* addr64(low) */);
				PUSH((int) ECX /* offset64(high) */);
				PUSH((int) ECX /* offset64(low) */);
				PUSH((int) ECX /* pageset */);
				PUSH((int) EDX /* linear */);
				PUSH((int) 4096 /* size */);
				PUSH((int) 0x1007 /* opt(over-map, present, R/W, user) */);
				PUSH((int) 0x0108 /* cmd(mapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 40;
				ECX = all_sel;
				EAX = syswork_sel;
				DS = CX;

				if ((unsigned) (int) [DS:EDX +  8] == 0x47495547 /* 'GUIG' */) {
					if ((unsigned) (int) [DS:EDX + 12] == 0x30304955 /* 'UI00' */) {
						PUSH(ES);
						ES = AX;
						EAX = 0;
						EAX--;
						PUSH(EAX);
						PUSH(EAX /* (int) 0xffffffff */ /* stack3の物理アドレス(確保していなければ0xffffffff) */);
						PUSH(EAX /* (int) 0xffffffff */ /* stack3のサイズ(自動設定なら0xffffffff) */);
						PUSH(EAX);
						PUSH(EAX /* (int) 0xffffffff */ /* stack0の物理アドレス(確保していなければ0xffffffff) */);
						PUSH(EAX /* (int) 0xffffffff */ /* stack0のサイズ(自動設定なら0xffffffff) */);
						PUSH(EAX);
						PUSH(EAX /* (int) 0xffffffff */ /* タスクディレクトリ */);
						ESP -= 8;
						PUSH((int) [DS:EDX + 20]);
						PUSH((int) [DS:EDX + 16]);
						PUSH((int) 0);
						PUSH((int) msg[8]);
						PUSH((int) msg[4]);
						AX = SS;
						EBX = ESP;
						ES = AX;
						create_task();
						LEA(ESP, [SS:ESP + 60]);
						POP(ES);
						if (ZF == 1)
							goto cmd0130_outofresource;
						EDX = EBP;
		cmd0130_not_GUIGUI00:
						ECX = msg[12];
						(offset) msg += 16;
						msgdw += 4;
						[SS:ESP] = ECX;
						LEA(EBP, [SS:ESP + 4]);
						ECX &= 0x000f;
						do {
							EAX = *msg;
							msg += 4;
							[SS:EBP] = EAX;
							EBP += 4;
							msgdw++;
							ECX--;
						} while (!= 0);
						EAX += EDX;
						[SS:EBP] = ECX; /* eoc */
						[SS:EBP - 4] = EAX;
						PUSH(0x0128 /* コマンドシグナル直接(with wait) */);
						EBX = ESP;
						CALLFAR0(tapi_sel);
						ESP += 72; /* 64 + 4 + 4 */
						POP(DS);
						continue;
					}
				}
				EDX = 0;
				goto cmd0130_not_GUIGUI00;
		cmd0130_outofresource:
				INT(0x03);
#if 0
				/* リソース解放 */
				PUSH((offset) msg);
				EDX = pdepte_sel; EAX = 0; DS = DX; EAX--;
				if ((unsigned) (offset) tasklist != EAX) {
					EDX = tasklist->stack0_addr;
					if (EDX != EAX) {
						ECX = tasklist->stack0_size;
						unmapping();
					}
					EDX = tasklist->stack3_addr;
					if (EDX != EAX) {
						ECX = tasklist->stack3_size;
						if (ECX != 0)
							unmapping();
					}
					/* タスクディレクトリ内のモジュールを全て開放 */
					PUSH(EDI);
					EAX = root_sel;
					ESI = tasklist->tskdir;
					DS = AX;
					if (ESI != 0xffffffff) {
						EAX = 0xffe00040; /* directory-link-to tag */
						EBX = 16;
						search_tag_EAX();
						EBX += (int) [DS:ESI + 16]; /* link */
						EDI = [DS:EBX];
						EBX += 4;
						if (EDI != 0xffffffff) {
							do {
								delete_binmodule(); /* ディレクトリが混ざっていることは想定していない */
								EDI = [DS:EBX];
								EBX += 4;
							} while (EDI != 0xffffffff);
						}
						EDI = tasklist->tskdir;
						delete_directory();
					}
					POP(EDI);

					EAX = 0;
					EDX = stack_sel;
					EAX--;
					DS = DX;
					if (tasklist->tskptr != EAX) {
					//	/* ESI = (offset) work->gdt_man; */ LEA(ESI, (int) work->gdt_man);
					//	ECX = 16; /* 2 selectors */
					//	EAX = ...
						/* ESI = (offset) work->tapiwork_man; */ LEA(ESI, (int) work->tapiwork_man);
						ECX = 0x1000; /* 4KB */
						EAX = tasklist->tskptr;
						free_area();
					}
				//	(int) tasklist->name[0] = 0;
					tasklist->tskptr = 0;
				}
				POP((offset) msg);
				EDX = 0;
				goto cmd0130_not_GUIGUI00;
#endif

			} else if (EAX == 0x0134) {
				/* メモリ解放 */
				/* cmd, fileid, size, addr */
				if (msg[4] != 0xffffffff) {
					ECX = msg[8];
					EAX = 0;
					ECX += 0x0fff;
					PUSH((int) EAX /* eoc */);
					ECX &= 0xfffff000;
					EDX = 0x00300000 /* 3MB */;
					PUSH((int) EAX /* addr64(high) */);
					PUSH((int) msg[12] /* addr64(low) */);
					PUSH((int) EAX /* offset64(high) */);
					PUSH((int) EAX /* offset64(low) */);
					PUSH((int) EAX /* pageset */);
					PUSH((int) EDX /* linear */);
					PUSH((int) ECX /* size */);
					PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
					PUSH((int) 0x0108 /* cmd(mapping) */);
					EBX = ESP;
					CALLFAR0(papi_sel);
					ESP += 40 - 4;

				//	PUSH((int) 0);
					PUSH(EDX);
					PUSH(all_sel);
					PUSH((int) msg[4]); /* fileid */
					PUSH((int) 0x0134 /* FDC_doswrite */);
					EBX = ESP;
					CALLFAR0(fdcdrive_sel);
					ESP += 20;
				}
				ECX = msg[8];
				EAX = msg[12];
				(offset) msg += 16;
				ECX += 0x00000fff;
				msgdw += 4;
				ECX &= 0xfffff000;
				free_memory(); /* フリーメモリの登録 */

			} else if (EAX == 0x0138) {
				/* システムイメージ転送(512bytes/sector, LZ圧縮) */
				/* cmd, opt, bsc_size, bsc_addr, exe_size, exe_addr,
					完了シグナル(lenはシグナルの第一dwから判断) */
				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				PUSH((int) 0);
				PUSH((int) 12 /* 作業中のシグナル */);
				PUSH((int) 0x8000 /* 完了シグナル */);
				PUSH((int) 0x00301000);
				PUSH(msg[16]);
				PUSH((int) 0x00300000);
				PUSH(msg[ 8]);
				PUSH((int) 0x0130 /* FDC_writeIPL3 */);
				goto cmd0128_cmd011c;
			} else if (EAX == 0x013c) {
				/* check wb cahce */
				/* cmd, fileid, size, addr, 完了シグナル(lenはシグナルの第一dwから判断) */

				ECX = msg[8];
				EAX = 0;
				ECX += 0x0fff;
				PUSH((int) EAX /* eoc */);
				ECX &= 0xfffff000;
				EDX = 0x00300000 /* 3MB */;
				PUSH((int) EAX /* addr64(high) */);
				PUSH((int) msg[12] /* addr64(low) */);
				PUSH((int) EAX /* offset64(high) */);
				PUSH((int) EAX /* offset64(low) */);
				PUSH((int) EAX /* pageset */);
				PUSH((int) EDX /* linear */);
				PUSH((int) ECX /* size */);
				PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
				PUSH((int) 0x0108 /* cmd(mapping) */);
				EBX = ESP;
				CALLFAR0(papi_sel);
				ESP += 40 - 4;

			//	PUSH((int) 0);
				PUSH(EDX);
				PUSH(all_sel);
				PUSH((int) msg[4]); /* fileid */
				PUSH((int) 0x0134 /* FDC_doswrite */);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 20 - 4;

				(offset) msg += 16;
				msgdw += 4;
				goto cmd0140_directsignal;

			} else if (EAX == 0x0140) {
				/* writeback cache */
				/* cmd, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[4];
				EBX = (offset) msg;
				(offset) msg += 8;
				msgdw += 2;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				PUSH((int) ECX);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8000); /* 完了シグナル */
				PUSH((int) 0x013c);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 16;

			} else if (EAX == 0x0144) {
				/* invalid WB cache */
				/* cmd, 完了シグナル(lenはシグナルの第一dwから判断) */
				PUSH((int) 0);
				PUSH((int) 0x0138);
				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				POP(EAX);

				(offset) msg += 4;
				msgdw++;
			//	PUSH((int) 0);
	cmd0140_directsignal:
				PUSH(GS);
				PUSH((offset) msg);
				PUSH(0x0118 /* コマンドシグナル間接 */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ECX = msg[0];
				ESP += 16;
				ECX &= 0x0f;
				ECX++;
				msgdw += ECX;
				LEA((offset) msg, msg[ECX * 4]);

			} else if (EAX == 0x0148) {
				/* create file */
				/* cmd, ファイル名3dw, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[16];
				EBX = (offset) msg;
				(offset) msg += 20;
				msgdw += 5;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				PUSH((int) ECX); /* file-size:0 */
				PUSH((int) ECX); /* 1980.01.01 */
				PUSH((int) ECX); /* 00:00:00 */
				PUSH((int) ECX);
				PUSH((int) ECX);
				PUSH((int) [GS:EBX + 12]);
				PUSH((int) [GS:EBX + 8]);
				PUSH((int) [GS:EBX + 4]);
				EAX = ESP;
				PUSH((int) ECX);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8000); /* 完了シグナル */
				PUSH(SS);
				PUSH(EAX);
				PUSH((int) 0x0180);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 56;
			} else if (EAX == 0x014c) {
				/* rename file */
				/* cmd, 旧ファイル名3dw, 新ファイル名3dw, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[28];
				EBX = (offset) msg;
				(offset) msg += 32;
				msgdw += 8;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				PUSH((int) [GS:EBX + 24]);
				PUSH((int) [GS:EBX + 20]);
				PUSH((int) [GS:EBX + 16]);
				PUSH((int) [GS:EBX + 12]);
				PUSH((int) [GS:EBX +  8]);
				PUSH((int) [GS:EBX +  4]);
				EAX = ESP;
				PUSH((int) ECX);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8000); /* 完了シグナル */
				PUSH(SS);
				PUSH(EAX);
				PUSH((int) 0x0188);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 48;

			} else if (EAX == 0x0150) {
				/* resize file */
				/* cmd, ファイル名3dw, 新サイズ, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[20];
				EBX = (offset) msg;
				(offset) msg += 24;
				msgdw += 6;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				PUSH((int) [GS:EBX + 12]);
				PUSH((int) [GS:EBX +  8]);
				PUSH((int) [GS:EBX +  4]);
				EAX = ESP;
				PUSH((int) ECX);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8004); /* 完了シグナル */
				PUSH((int) [GS:EBX + 16]); /* new-size */
				PUSH(SS);
				PUSH(EAX);
				PUSH((int) 0x018c);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 40;

			} else if (EAX == 0x0154) {
				/* delete file */
				/* cmd, ファイル名3dw, 完了シグナル(lenはシグナルの第一dwから判断) */

				/* 完了シグナルを受けっとったときのためのバッファを用意 */
				LEA(EBP, work->cmd0100_buf[4]);
				ECX = msg[16];
				EBX = (offset) msg;
				(offset) msg += 20;
				msgdw += 5;
				[SS:EBP - 4] = ECX;
				ECX &= 0x000f;
				do {
					EAX = *msg;
					(offset) msg += 4;
					[SS:EBP] = EAX;
					EBP += 4;
					msgdw++;
					ECX--;
				} while (!= 0);

				PUSH((int) [GS:EBX + 12]);
				PUSH((int) [GS:EBX + 8]);
				PUSH((int) [GS:EBX + 4]);
				EAX = ESP;
				PUSH((int) ECX);
				PUSH((int) 12); /* 作業中のシグナル */
				PUSH((int) 0x8000); /* 完了シグナル */
				PUSH(SS);
				PUSH(EAX);
				PUSH((int) 0x0184);

				EBX = ESP;
				CALLFAR0(fdcdrive_sel);
				ESP += 36;

			} else if (EAX == 0xffffff00) {
system_reset:
				INT(0x03);
			//	asmout("fcall 8*8, KeyResetCPU");
			//	for (;;)
			//		HLT();

			} else if (EAX == 0xffffff01) {
				msg += 4;
				msgdw++;
#if 0
				/* 再初期化(1) */
				PUSH((int) 0);
				PUSH((int) 0x0004);
				PUSH((int) 0x001c); /* 全ウィンドウクローズ */
				PUSH((int) 0x7f000002);
				PUSH((int) 0x3240 + 3);
				PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
			//	PUSH((int) 0x0081); /* 全ウィンドウクローズ */
			//	PUSH((int) 0x7f000001);
			//	PUSH((int) 0x4240 + 2);
			//	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ESP += 40 - 16;
#endif
//				PUSH((int) 0);
//				PUSH((int) 0x0010); /* 画面初期化要請 */
//				PUSH((int) 0x7f000001);
//				PUSH((int) 0x3240 + 2);
//				PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
//				EBX = ESP;
//				CALLFAR0(tapi_sel);
//				ESP += 20;
#if 0
				PUSH(FS);
				CLI();
				EDX = fdcwork_sel;
				FS = DX;
				if ((unsigned) (int) [FS:0 /* MC_ptr */] != 0x100) {
					POP(FS);
					STI();
					break;
				}
				EAX = syswork_sel;
				ECX = idtgdt_sel;
				DS = AX;
				GS = CX;
				AL = [FS:0x000c /* motor */];
				AL &= 0x1c;
				AL |= 0x0c;
				POP(FS);
				asmout("MOV BYTE PTR DS:[FD_motor_init],AL");
			//	asmout("MOV BYTE PTR DS:[FD_cache_init],0");
				asmout("AND BYTE PTR DS:[DiskCacheReady],0FEH");
				EAX = 0;

				EAX--;
				[DS:32 + ankfont_ent   + 0x0c] = EAX;
				[DS:32 + stack_ent     + 0x0c] = EAX;
				[DS:32 + keydata_ent   + 0x0c] = EAX;
				[DS:32 + gapidata_ent  + 0x0c] = EAX;
				[DS:32 + timerdata_ent + 0x0c] = EAX;
			//	[DS:32 + tapiwork_ent  + 0x0c] = EAX;
				[DS:32 + decowork_ent  + 0x0c] = EAX;
				[DS:32 + fdcwork_ent   + 0x0c] = EAX;
				DB(0xea); DD(0); DW(init_sel);
			} else if (EAX == 0xffffff02) {
				/* 再初期化(2) */
				msg += 4;
				msgdw++;
				
				PUSH((int) 0);
				PUSH((int) 0x0010); /* 画面初期化要請 */
				PUSH((int) 0x7f000001);
				PUSH((int) 0x3240 + 2);
				PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
				EBX = ESP;
				CALLFAR0(tapi_sel);
				ESP += 20;
#endif

			} else if (EAX == 1) {	// rewind
				msgdw += msg[4];
				(offset) msg = 0;
			} else {
				INT(0x03);
			}
		} while ((unsigned) msgdw < 8);
		EAX = 0;
		PUSH(EAX); // eoc
		PUSH(msgdw); // signals
		PUSH(EAX); /* delta-nest(割り込みを使わないから、nestは変更しない), Llv0(sleep) */
		PUSH((int) 0x010c); // TAPI_AddNestSleep
		EBX = ESP;
		CALLFAR0(tapi_sel);
		ESP += 16;
	}

	// tasklistへのポインタとmodule_entを与えると、初期化してくれる。
	// tss_workの確保＆初期化(tskptr == -1のときのみ)。
	// stackの確保＆初期化(addr == -1のときのみ)。
	// Llvは全てスリープになり、タスクはLlv0を選択した状態になる。
	// これをAddTskして、Llvチェンジすれば起動できる。
	// tasklistへのポインタさえも-1なら、それも確保してくれる。
	// うーん、面倒見のよいルーチンだ。
	// なお、module_entで示されたコードには、all_selを用いてアクセスする。

//EAX = /* modulelist[timerdata_ent].base */ [DS:32 + timerdata_ent + 0x0c];
//EAX += 0x0004;
//asmout("MOV DR0,EAX");
//EAX = 0;
//asmout("MOV DR6,EAX");
//asmout("MOV EAX,1000000010B+1101B*10000H"); /* GE = G0 = 1; LEN0 = 3 /* DW */; RW0 = 01 (write only) */
//asmout("MOV DR7,EAX");

	// タスク情報
	// コードサイズ、スタックサイズ(lv3)、LDTサイズ
	// エントリポイント
	// 統合入力に関する設定は、GUIGUIとの間で起動後にやる。GUIGUI00では規定されていないため。







	ALIGN(4);
rootdir:
	DD(0xffe00000); DD(12); asmout("DB 'root'");
	DD(0xffe00002); DD(16); DD(0 /* normal-directry */); DD(0);
	DD(0xffe00040); DD(16); DD(20); DD(512 /* ここを自動的に検出 */); DD(0); DD(0);
	DD(0xfff00000); DD(0xffffffff); /* DD(0); DD(0); */
tasksdir:
	DD(0xffe00000); DD(16); asmout("DB 'tasks', 0, 0, 0");
	DD(0xffe00002); DD(16); DD(0 /* normal-directry */); DD(0);
	DD(0xffe00040); DD(16); DD(20); DD(512 /* ここを自動的に検出 */); DD(0); DD(0);
	DD(0xfff00000); DD(0xffffffff); /* DD(0); DD(0); */
gapidata_mdl:
	DD(0xffe00000); DD(16); asmout("DB 'gapidata'");
	DD(0xffe00002); DD(16); DD(1 /* normal-module */); DD(0);
	DD(0xffe00003); DD(32); DD(0xb0000); DD(0); DD(0xb0000); DD(0); DD(0 /* addr */); DD(0);
	DD(0xfff00000); DD(0xffffffff); /* DD(0); DD(0); */

movemodule_list:
//	DD(32 + idtgdt_ent   ); DD(384 /* IDTの分 */ + idtgdt_sel); DD(0);
	DD(32 + ankfont_ent,   384 + ankfont_sel,   0);
	DD(32 + stack_ent,     384 + stack_sel,     0);
	DD(32 + keydata_ent,   384 + keydata_sel,   0);
	DD(32 + gapidata_ent,  384 + GAPIwork_sel,  0xb0000 - 12288);
	DD(32 + timerdata_ent, 384 + timerdata_sel, 0);
	DD(32 + decowork_ent,  384 + decowork_sel,  0);
	DD(32 + fdcwork_ent,   384 + fdcwork_sel,   0);
	DD(32 + papiwork_ent,  384 + papiwork_sel,  0);
	DD(0);

movestack:
	DD(0x2000 + 748); DD(0x0000306b /* 'k0' */); DD(0x2000 + 2048 /* ldt_img */ + 24 /* stack0 */);
	DD(0x3000 + 748); DD(0x0000306b /* 'k0' */); DD(0x3000 + 2048 /* ldt_img */ + 24 /* stack0 */);
//	DD(0x3000 + 748); DD(0x0000336b /* 'k3' */); DD(0x3000 + 2048 /* ldt_img */ +  8 /* stack3 */);
	DD(0x4000 + 748); DD(0x0000306b /* 'k0' */); DD(0x4000 + 2048 /* ldt_img */ + 24 /* stack0 */);
//	DD(0x4000 + 748); DD(0x0000336b /* 'k3' */); DD(0x4000 + 2048 /* ldt_img */ +  8 /* stack3 */);
	DD(0);

	ALIGN(2);
	asmout("Init_segment_table:");
	asmout("DW 04092H, 0*16+modulelist, 3*8"); /* syswork_ent, syswork_sel */
	asmout("DW 0409AH, 2*16+modulelist, 4*8"); /* GAPI_ent, GAPI_sel */
	asmout("DW 04092H, 5*16+alloclist,  5*8"); /* gapidata_ent, gapidata_sel */
	asmout("DW 0C096H, 3*16+alloclist,  6*8"); /* stack_ent, stack_sel */
	asmout("DW 04092H, 2*16+alloclist,  7*8"); /* ankfont_ent, ankfont_sel */
	asmout("DW 0409AH, 3*16+modulelist, 8*8"); /* keyint_ent, keyint_sel */
	asmout("DW 04092H, 4*16+alloclist,  9*8"); /* keydata_ent, keydata_sel */
	asmout("DW 0409AH, 4*16+modulelist,10*8"); /* timerint_ent, timerint_sel */
	asmout("DW 04092H, 6*16+alloclist, 11*8"); /* timerdata_ent, timerdata_sel */
	asmout("DW 0409AH, 5*16+modulelist,12*8"); /* tapi_ent, tapi_sel */
//	asmout("DW 04092H, 7*16+alloclist, 13*8"); /* tapiwork_ent, tapiwork_sel */
	asmout("DW 0409AH, 6*16+modulelist,22*8"); /* decode_ent, decode_sel */
	asmout("DW 04092H, 8*16+alloclist, 23*8"); /* decowork_ent, decowork_sel */
	asmout("DW 0409AH, 7*16+modulelist,28*8"); /* fdc_ent, fdcdrive_sel */
	asmout("DW 04092H, 9*16+alloclist, 29*8"); /* fdcwork_ent, fdcwork_sel */
//	asmout("DW 04092H,10*16+alloclist, 30*8"); /* diskbuf_ent, diskbuf_sel */
//	asmout("DW 04092H,11*16+alloclist, 31*8"); /* textbuf_ent, textbuf_sel */
	asmout("DW 04092H, 1*16+alloclist, 15*8"); /* IDTGDT_ent, idtgdt_sel */
	asmout("DW 04092H, 0*16+alloclist, 14*8"); /* PDEPTE_ent, pdepte_sel */
	asmout("DW 0409AH,15*16+modulelist,18*8"); /* papi_ent, papi_sel */
	asmout("DW 04092H,10*16+alloclist, 19*8"); /* papiwork_ent, papiwork_sel */

	asmout("DW 0");

	ALIGN(2);
	asmout("Init_idt_table:");
	asmout("DW 018FH,OFFSET int01,2*8");
	asmout("DW 028FH,OFFSET int02,2*8");
	asmout("DW 03EFH,OFFSET int03,2*8");
	asmout("DW 068FH,OFFSET int06,2*8");
	asmout("DW 0A8FH,OFFSET int10,2*8");
	asmout("DW 0C8FH,OFFSET int12,2*8");
	asmout("DW 0D8FH,OFFSET int13,2*8");
//	asmout("DW 0E8FH,OFFSET int14,2*8");
	#if (defined(PCAT))
		asmout("DW 278EH,OFFSET int39,2*8");
	#endif
	asmout("DW 0");
}

void near init_areastr()
/* EAX = 0; EDX = -1; ECX = size0;
  area_man_struct *areastrEBP == SS:EBP; */
{
	area_man_struct *areastrEBP == SS:EBP;

	areastrEBP->use = EAX;
	areastrEBP->size0 = ECX;
	areastrEBP->data0.size = EAX;
	areastrEBP->data0.addr = EAX;
	areastrEBP->data[0].size = EDX;
	areastrEBP->data[0].addr = EDX;
	return;
}

void near testmemory()
/* EBXからEBP[MB]をテスト
   DSとreg32を破壊
   リニア空間の3MBから1MBを使用
   EDIは保存される。登録先をセット */
{
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;
	unsigned int pdepte_sel   == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int papi_sel     == 18 * 8;
	do {
		PUSH((int) syswork_sel);
		POP(DS);
		DL = [DS:0x001c + 2 /* eflags[2] */];
		EAX = 0x1003; /* over-mapping, present, R/W, system */
		TEST(DL, 0x04);
		if (!= 0 /* 486 */)
			EAX |= 0x18 /* キャッシュ禁止(PCD = 1, PWT = 1) */;

		ECX = 0x00300000;
		PUSH(FS);
		PUSH(EBX);
		PUSH(SS);
		POP(FS);
		EDX = 0;
		PUSH((int) EDX /* eoc */);
		PUSH((int) EDX /* addr64(high) */);
		PUSH((int) EBX /* addr64(low) */);
		PUSH((int) EDX /* offset64(high) */);
		PUSH((int) EDX /* offset64(low) */);
		PUSH((int) EDX /* pageset */);
		PUSH((int) ECX /* linear(3MB) */);
		PUSH((int) 1024 * 1024 /* size(1MB) */);
		PUSH((int) EAX /* opt */);
		PUSH((int) 0x0108 /* cmd(mapping) */);
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 40;
		POP(EBX);
		POP(FS);

		PUSH((int) all_sel);
	//	ECX = 0x00300000;
		POP(DS);
reloop:
		EAX = 0xaa55aa55;
		EDX = 0x55aa55aa;
		ESI = ECX;
		do {
			int *adr0 == DS:ECX, *adr1 == DS:ECX + 0xffc;
			*adr0 = EAX;
			NOT(*adr0);
			if (EDX != *adr0)
				goto skip;
			NOT(*adr0);
			if (EAX != *adr0)
				goto skip;
			*adr1 = EAX;
			NOT(*adr1);
			if (EDX != *adr1)
				goto skip;
			NOT(*adr1);
			if (EAX != *adr1)
				goto skip;
			ECX += 0x1000;
		} while ((unsigned) ECX < 0x00400000);
		LEA(EAX, [EBX + ESI - 0x00300000]);
		ECX -= ESI;
		LEA(EBX, [EBX + 0x00100000]);
		if (!= 0) {
			free_memory();
		}
reloop2:
		EBP--;
	} while (!= 0);
	asmout("MOV EAX,CR3");
	asmout("MOV CR3,EAX");
	return;
skip:
	PUSH(ECX);
	ECX -= ESI;
	if (!= 0) {
		LEA(EAX, [EBX + ESI - 0x00300000]);
		free_memory();
	}
	POP(ECX);
	asmout("MOV EAX,CR3");
	asmout("MOV CR3,EAX");
	return; /* 高速化のため、ISAホール以外の穴は想定しないことにする */
//	ECX += 0x1000;
//	if ((unsigned) ECX < 0x00400000)
//		goto reloop;
//	EBX += 0x00100000;
//	goto reloop2;
}

void far IdleTask()
{
	#if (!defined(NOHLT))
		for (;;) {
			HLT();
		}
	#else
		for (;;) {
			NOP();
		}
	#endif
}

#if 0

void near get_page()
/* EAXにページアドレス。-1の場合、エラー */
{
	int *work == DS:?, worksize == 64;
	PUSH(ECX);
	ECX = work[0];
	EAX = work[4];
	ECX -= 4096;
	if ((unsigned) > 0) {
		work[0] = ECX;
		work[4] += 4096; /* CF = 0 */
		POP(ECX);
		return;
	}
	if (== 0) {
		PUSH(EAX);
		PUSH(EBX);
		EBX = (offset) work;
		ECX = worksize / 4 - 2;
		do {
			EAX = [DS:EBX + 8];
			ECX--;
			[DS:EBX] = EAX;
			LEA(EBX,[EBX + 4]);
		} while (!= 0);
		POP(EBX);
		POP(EAX);
		POP(ECX);
		return; /* ECXは0になっただけなので、CF = 0 */
	}
	EAX = -1;
	POP(ECX);
	STC();
	return;
	// 最後のブロックは、0,0xffffffff
}

#endif

void near get_area()
/* DS:ESIに管理情報構造体へのポインタ。
   ECXに要求連続サイズ。
   EAXにページアドレス。-1の場合、エラー。 */

/* 構造体の最初の8バイトはリザーブ
   次の8バイトは、使用バイト数と構造体サイズ
   その次の16バイトはリザーブ
   ということで、最初のデーターは+40から */

/* first_fitアルゴリズム
   アクセス競合などは、上位ルーチンで解決しておくこと
   ZF == 1はエラー (EAX == -1) */
{
	area_man_struct *work == DS:ESI;
	area_man_struct_sub *dat == DS:EBX;
	unsigned int req == ECX;
	PUSH((offset) dat);
	/* LEA((offset) dat,[(offset) work->data]); */ LEA((offset) dat, (int) [work->data]);

	if (req > dat->size) {
		do {
			unsigned int next_size == EAX;
			next_size = dat[sizeof (area_man_struct_sub)].size;
			(offset) dat += sizeof (area_man_struct_sub);
		} while (next_size < req);
	}

	EAX = dat->addr;
	if (EAX != 0xffffffff) {
		dat->addr += req;
		dat->size -= req;
		if (== 0) {
			work->use -= sizeof (area_man_struct_sub);
			/* 転送(sizeof (area_man_struct_sub) == 8を仮定) */
			PUSH(ECX);
			PUSH(EAX);
			do {
				EAX = /* (dat + 8)->size */ dat[8].size;
				ECX = /* (dat + 8)->addr */ dat[8].addr;
				dat->size = EAX;
				dat->addr = ECX;
				(offset) dat += 8;
			} while (EAX != 0xffffffff);
			POP(EAX);
			POP(ECX);
			CMP(EAX, 0xffffffff); /* for ZF == 0 */
		}
		/* ここに来るとき、ZF == 0 */
	}
	POP((offset) dat);
	return;
}

void near free_area()
/* DS:ESIに管理情報構造体へのポインタ。 */
/* ECXに解放サイズ。 */
/* EAXにページアドレス。 */
/* 全レジスタ保存 */
/* ２分検索アルゴリズム */
/* アクセス競合などは、上位ルーチンで解決しておくこと */
/* ZF == 1はエラー(管理領域不足) */
{
	area_man_struct *work == DS:ESI;
	area_man_struct_sub *dat == DS:EBX;
	unsigned int dat0 == EDX, dat1 == EDI;
	unsigned int size == ECX, addr == EAX;
	PUSH(dat1);
	dat1 = work->use;
	PUSH(dat0);
	PUSH((offset) dat);
	LEA(dat0, (int) work->data0);
//	dat1 = (offset) work->data[dat1]; // これがうまくコンパイルできない
	LEA(dat1, [dat1 + (offset) work->data]);

	LEA((offset) dat, [dat0 + dat1]);
	(offset) dat /= 2;
	(offset) dat &= 0xfffffff8; // 8バイトアライン
	if ((unsigned) (offset) dat > dat0) {
		for (;;) {
			if (addr < dat->addr) {
				dat1 = (offset) dat;
				(offset) dat += dat0;
				(offset) dat /= 2;
				(offset) dat &= 0xfffffff8; // 8バイトアライン
				if ((unsigned) (offset) dat > dat0)
					continue;
				break;
			}
			/* == はありえない */
			dat0 = (offset) dat;
			(offset) dat += dat1;
			(offset) dat /= 2;
			(offset) dat &= 0xfffffff8; // 8バイトアライン
			if ((unsigned) (offset) dat > dat0)
				continue;
			break;
		}
	}

	/* dat->addr < addr < dat[8]->addr */

	EDI = dat->size;
	LEA(EDX, [addr + size]);
	EDI += dat->addr;
	if (!= 0) {
		/* 上は番兵ではない */
		if (addr == EDI) {
			/* 上との融合は可能 */
			dat->size += size;
			if (EDX == dat[8].addr) {
				/* 下との融合も可能 */
				EDX = dat[8].size;
				dat->size += EDX;
				/* 転送(sizeof (area_man_struct_sub) == 8を仮定) */
				(offset) dat += sizeof (area_man_struct_sub);
				PUSH(ECX);
				PUSH(EAX);
				do {
					EAX = /* (dat + 8)->size */ dat[8].size;
					ECX = /* (dat + 8)->addr */ dat[8].addr;
					dat->size = EAX;
					dat->addr = ECX;
					(offset) dat += 8;
				} while (EAX != 0xffffffff);
				work->use -= sizeof (area_man_struct_sub);
				POP(EAX);
				POP(ECX);
				CMP(addr, 0xffffffff); // for ZF == 0
			}
			POP((offset) dat);
			POP(dat0);
			POP(dat1);
			return;
		}
	}

	if (EDX == dat[8].addr) {
		/* 下との融合は可能 */
		dat[8].size += size; // ZF = 0
		dat[8].addr = addr;
		POP((offset) dat);
		POP(dat0);
		POP(dat1);
		return;
	}

	/* 融合不可能・要挿入 */

	(offset) dat = work->use;
	(offset) dat += sizeof (area_man_struct_sub); 
	if ((unsigned) (offset) dat < work->size0) { /* これが成立しない場合、ZF == 1 */
		work->use = (offset) dat;
		LEA((offset) dat, [/* (offset) dat */ EBX + (offset) work->data]);
	//	PUSH(EDX);
		PUSH(ECX);
		do {
			ECX = /* (dat - 8)->size */ dat[-8].size;
			EDX = /* (dat - 8)->addr */ dat[-8].addr;
			dat->size = ECX;
			dat->addr = EDX;
			(offset) dat -= 8;
		} while (addr < EDX); // 常にZF == 0
		POP(ECX);
	//	POP(EDX);
		/* (dat + 8)->size */ dat[8].size = size;
		/* (dat + 8)->addr */ dat[8].addr = addr;
	}
	POP((offset) dat);
	POP((offset) dat0);
	POP((offset) dat1);
	return;
}

#if 0

void near count_free()
/* DS:ESIに管理情報構造体へのポインタ。 */
/* ECXに合計サイズが返り、EAXに最大サイズが返る */
{
	area_man_struct *work == DS:ESI;
	area_man_struct_sub *dat == DS:EBX;
	PUSH(EBX);
	PUSH(EDX);
	LEA((offset) dat, (int) [work->data]);
	EDX = 0;
	EAX = 0;
	EDX--;
	ECX = 0;
	if (EDX != dat->size) {
		do {
			ECX += dat->size;
			if ((unsigned) EAX <= dat->size)
				EAX = dat->size;
			(offset) dat += sizeof (area_man_struct_sub);
		} while (EDX != dat->size);
	}
	POP(EDX);
	POP(EBX);
	return;
}

#endif

void near get_memory()
/* ECXに要求サイズ */
{
	unsigned int papi_sel     == 18 * 8, papiwork_sel  == 19 * 8;

	PUSH(FS);
	PUSH(EBX);
	MOV(EBX, SS);
	PUSH((int) 0);
	PUSH(ECX); /* ダミー */
	PUSH((int) 0);
	PUSH(ECX);
	PUSH((int) 0);
	PUSH((int) 0x0114);
	FS = EBX;
	EBX = ESP;
	CALLFAR0(papi_sel);
	EAX = [SS:ESP + 16];
	ESP += 24;
	POP(EBX);
	POP(FS);
	return;
}

#if 0
{
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	GUIGUI_work *work == DS:0xffffd000;
	PUSH(DS);
	PUSH(ESI);
	EAX = stack_sel;
	/* ESI = (offset) work->mem32_man; */ LEA(ESI, (int) work->mem32_man);
	DS = AX;
	get_area();
	if (ZF == 0)
		goto fin;
	/* ESI = (offset) work->mem24_man; */ LEA(ESI, (int) work->mem24_man);
	get_area();
	if (ZF == 0)
		goto fin;
	/* ESI = (offset) work->mem20_man; */ LEA(ESI, (int) work->mem20_man);
	get_area();
fin:
	POP(ESI);
	POP(DS);
	return;
}
#endif

void near free_memory()
{
	unsigned int papi_sel     == 18 * 8, papiwork_sel  == 19 * 8;

	PUSH(FS);
	PUSH(EBX);
	MOV(EBX, SS);
	PUSH((int) 0);
	PUSH(EAX);
	PUSH(ECX);
	PUSH((int) 0);
	PUSH((int) 0x0110);
	FS = EBX;
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 20;
	POP(EBX);
	POP(FS);
	return;
}


#if 0
{
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	GUIGUI_work *work == DS:0xffffd000;
	PUSH(DS);
	PUSH(ESI);
	ESI = stack_sel;
	TEST(EAX, 0xff000000);
	DS = SI;
	/* ESI = (offset) work->mem32_man; */ LEA(ESI, (int) work->mem32_man);
	if (!= 0)
		goto free;
	TEST(EAX, 0xfff00000);
	/* ESI = (offset) work->mem24_man; */ LEA(ESI, (int) work->mem24_man);
	if (!= 0)
		goto free;
	/* ESI = (offset) work->mem20_man; */ LEA(ESI, (int) work->mem20_man);
free:
	free_area();
	POP(ESI);
	POP(DS);
	return;
}
#endif

void near get_virtual()
/* ECXに要求サイズ */
/* EDX:EAXに64bitアドレス */
{
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	GUIGUI_work *work == DS:0xffffd000;
	PUSH(DS);
	PUSH(ESI);
	ESI = stack_sel;
	PUSH(ECX);
	DS = ESI;
	ECX += 4095;
	/* ESI = (offset) work->virtual_man; */ LEA(ESI, (int) work->virtual_man);
	(unsigned int) ECX /= 4096;
	get_area();
	EDX = EAX;
	EAX <<= 12;
	(unsigned int) EDX >>= 20;

	/* ここで、PAPIに新規ページであることを通知 */
	/* 新規ページはロードしない */

	POP(ECX);
	POP(ESI);
	POP(DS);
	return;
}

void near free_memory64()
{
	TEST(EDX, EDX);
	asmout("JZ free_memory");
}

void near free_virtual()
/* ECXに開放サイズ */
/* EDX:EAXに64bitアドレス */
{
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int papi_sel     == 18 * 8, papiwork_sel  == 19 * 8;
	GUIGUI_work *work == DS:0xffffd000;

	PUSH(FS);
	PUSH(DS);
	PUSH(ESI);
	ESI = stack_sel;
	PUSH(EBX);
	PUSH(EDX);
	PUSH(ECX);
	PUSH(EAX);
	DS = ESI;
	SHRD(EAX, EDX, 12);
	ECX += 4095;
	/* ESI = (offset) work->virtual_man; */ LEA(ESI, (int) work->virtual_man);
	(unsigned int) ECX /= 4096;
	free_area();

	ESI = 0;
	EAX = [SS:ESP];
	ECX = [SS:ESP + 4];
	EDX = [SS:ESP + 8];
	PUSH((int) ESI /* eoc */);
	PUSH(EDX /* addr64(high) */);
	PUSH(EAX /* addr64(low) */);
	PUSH(ESI /* offset(high) */);
	PUSH(ESI /* offset(low) */);
	PUSH(ESI /* size(high) */);
	PUSH(ECX /* size(low) */);
	PUSH(ESI /* opt */);
	PUSH((int) 0x0118 /* cmd(delete pages) */);
	MOV(ESI, SS);
	EBX = ESP;
	FS = ESI;
	CALLFAR0(papi_sel);
	ESP += 36;

	POP(EAX);
	POP(ECX);
	POP(EDX);
	POP(EBX);
	POP(ESI);
	POP(DS);
	POP(FS);
	return;
}

void near alloc_memory()
/* ECXに要求サイズ -> EAX(物理アドレス), EDX(線形アドレス)を返す */
{
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int pdepte_sel   == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int papi_sel     == 18 * 8;
	GUIGUI_work *work == DS:0xffffd000;
	PUSH(DS);
	PUSH(ESI);
	EAX = stack_sel;
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	DS = AX;
	get_area();
	EDX = EAX;
	if (ZF == 1 /* error */)
		goto fin;
	get_memory();
	if (ZF == 1 /* error */) {
		/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
		EAX = EDX;
		free_area();
		goto fin;
	}
	ESI = pdepte_sel;
	DS = SI;

	PUSH(FS);
	PUSH(EBX);
	MOV(EBX, SS);
	FS = EBX;
	EBX = 0;
	PUSH((int) EBX /* eoc */);
	PUSH((int) EBX /* addr64(high) */);
	PUSH((int) EAX /* addr64(low) */);
	PUSH((int) EBX /* offset64(high) */);
	PUSH((int) EBX /* offset64(low) */);
	PUSH((int) EBX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0x0007 /* opt(present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 40;	// ZF = 0
	POP(EBX);
	POP(FS);

//	TEST(ESP, ESP); // ZF = 0
fin:
	POP(ESI);
	POP(DS);
	return;
}

void near alloc_tagdir()
/* ECX, ESIをセット。EDI(== EAX)に返す */
/* ZF == 1でエラー */
{
	get_area();
	if (ZF == 0) {
		EDI = EAX;
		(int) [DS:EAX + 0] = 32;
		(int) [DS:EAX + 4] = ECX; /* allocated */
		(int) [DS:EAX + 16] = 0xfff00000;
		(int) [DS:EAX + 20] = 0xffffffff;
		(int) [DS:EAX + 24] = 0;
		(int) [DS:EAX + 28] = 0;
	}
	return;
}

void near add_tags()
/* GS:EBXをDS:EDIへ。EDIは保存される。EAX, ECX, EDXは破壊 */
/* "link to"タグを見つけると、自動的にアロケートする */
{
	EDX = (int) [DS:EDI];
	ECX = [GS:EBX + 4];
	asmout("LEA EDX,[EDX+EDI-16]");
	ECX /= 4;
	if (CF == 0) {
		do {
			EAX = [GS:EBX];
			if (EAX == 0xffe00040) { /* "link to directory(name-sorted)" */
				ECX = [GS:EBX + 12];
				(int) [DS:EDX     ] = EAX;
				(int) [DS:EDX +  4] = 24;
				(int) [DS:EDX +  8] = 20;
				(int) [DS:EDX + 12] = ECX;
				get_area();
				if (ZF == 1)
					INT(0x03);
				(int) [DS:EDX + 16] = EAX;
				(int) [DS:EDX + 20] = 0;
				(int) [DS:EAX     ] = 20;
				(int) [DS:EAX +  4] = ECX;
				(int) [DS:EAX + 16] = 0xffffffff; /* directory terminator */
			//	(int) [DS:EAX + 20] = 0xffffffff;
				EBX += 24;
				EDX += 24;
			} else {
				do {
					EAX = [GS:EBX];
					EBX += 4;
					[DS:EDX] = EAX;
					EDX += 4;
					ECX--;
				} while (!= 0);
			}
			ECX = [GS:EBX + 4];
			ECX /= 4;
		} while (CF == 0);
	}
	LEA(EAX, [EDX + 16]);
	(int) [DS:EDX +  0] = 0xfff00000;
	(int) [DS:EDX +  4] = 0xffffffff;
	(int) [DS:EDX +  8] = 0;
	(int) [DS:EDX + 12] = 0;
	EDX -= EAX;
	(int) [DS:EDI + 0] = EDX;
	return;
}

void near search_tag_EAX()
/* ZF == 1:検出 */
{
	if (EAX != (int) [DS:ESI]) {
		do {
			ESI += (int) [DS:ESI + 4];
			if (CF == 1)
				goto error;
		} while (EAX != (int) [DS:ESI]);
	}
error:
	return;
}

void near regist_module()
/* EBXのディレクトリにEDIのモジュール(タグディレクトリ)を接続する */
{
	PUSH(ESI);
	/* EBXを解析して、"directory link to"を探す */
	LEA(ESI, [EBX + 16]);
	PUSH(EBX);
	EAX = 0xffe00040;
	search_tag_EAX();
	if (ZF == 0)
		INT(0x03);
	EBX = [DS:ESI + 16];
	EAX = [DS:EBX];
//	asmout("MOV DWORD PTR DS:[EBX+EAX-4],EDI");
	(int) [DS:EBX + EAX - 4] = EDI;
	(int) [DS:EBX + EAX]= 0xffffffff;
//	asmout("MOV DWORD PTR DS:[EBX+EAX],-1");
	EAX += 4;
	(int) [DS:EBX] = EAX;
	(int) [DS:ESI + 8] = EAX;
	POP(EBX);
	POP(ESI);
	return;
}

void near delete_directory()
/* DS:EDIのディレクトリモジュールを削除する */
/* 0xffe00040を検出したら、開放する */
{
	PUSH(ESI);
	/* EBXを解析して、"directory link to"を探す */
	LEA(ESI, [EDI + 16]);
	EAX = 0xffe00040;
	search_tag_EAX();
	if (ZF == 1) {
		do {
			PUSH(ESI);
			EAX = [DS:ESI + 16];
			ECX = [DS:ESI + 12];
			ESI = 512;
			free_area();
			if (ZF == 1)
				goto error;
			POP(ESI);
			EAX = 0xffe00040;
			ESI += [DS:ESI + 4];
			if (CF == 1)
				break;
			search_tag_EAX();
		} while (ZF == 1);
	}
	ESI = 512;
	EAX = EDI;
	ECX = [DS:EDI + 4];
	free_area();
	POP(ESI);
	return;
error:
	INT(0x03);
}

void near delete_binmodule()
/* DS:EDIのバイナリーモジュールを削除する */
/* 0xffe00003を探して、開放する */
{
	PUSH(ESI);
	/* EBXを解析して、"standard link to"を探す */
	LEA(ESI, [EDI + 16]);
	EAX = 0xffe00003;
	search_tag_EAX();
	if (ZF == 1) {
		ECX = [DS:ESI + 16];
		EAX = [DS:ESI + 24];
		EDX = [DS:ESI + 28];
		if (ECX != 0)
			free_memory64();
	}
	ESI = 512;
	EAX = EDI;
	ECX = [DS:EDI + 4];
	free_area();
	POP(ESI);
	return;
error:
	INT(0x03);
}

void near memcopy16()
{
	do {
		EAX = [DS:ESI +  0];
		ECX = [DS:ESI +  4];
		EDX = [DS:ESI +  8];
		EBX = [DS:ESI + 12];
		ESI += 16;
		[DS:EDI +  0] = EAX;
		[DS:EDI +  4] = ECX;
		[DS:EDI +  8] = EDX;
		[DS:EDI + 12] = EBX;
		EDI += 16;
		EBP -= 16;
	} while ((unsigned) > 0);
	return;
}

struct createtask_param {
	unsigned int codesize /* + 0 */, codeaddr[8] /* + 4 */;
	unsigned int header[8] /* +12 */, reserve[8] /* +20 */;
	unsigned int tskdir[8] /* +28 */; /* ここは、rootのリニアアドレスが入っている */
	unsigned int stack0size /* +36 */, stack0addr[8] /* +40 */;
	unsigned int stack3size /* +48 */, stack3addr[8] /* +52 */;
};

void near create_task()
/*	タスクネームは設定しない
	ES:EBX に モジュールパラメーター
	SS:EBP に task_struct */
{
	GUIGUI_work *work == SS:0xffffd000;
//	GUIGUI_task_struct *task == SS:EBP;
	createtask_param *param == ES:EBX;

	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int GAPI_sel     ==  4 * 8, GAPIwork_sel  ==  5 * 8;
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;
	unsigned int timerint_sel == 10 * 8, timerdata_sel == 11 * 8;
	unsigned int tapi_sel     == 12 * 8, tapiwork_sel  == 13 * 8;
	unsigned int pdepte_sel   == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int root_sel     == 16 * 8, tmp_sel       == 17 * 8;
	unsigned int papi_sel     == 18 * 8;
	unsigned int decode_sel   == 22 * 8, decowork_sel  == 23 * 8;
	unsigned int fdcdrive_sel == 28 * 8, fdcwork_sel   == 29 * 8;
	unsigned int diskbuf_sel  == 30 * 8, textbuf_sel   == 31 * 8;
	unsigned int freegdt_sel  == 32 * 8;

	unsigned int alloclist == 16 * 16;
	unsigned int pioneer_ent   ==  10 * 16;

	PUSH(GS);
//	PUSH(ES);
	PUSH(DS);
	PUSHAD();

	EAX = root_sel;
	ESI = 512;
	DS = AX;
	if (param->tskdir[0] == 0xffffffff) {
		ECX = 512; /* 0.5KB */
		alloc_tagdir();
		if (ZF == 1)
			goto error;
		param->tskdir[0] = EDI;
		param->tskdir[4] = 0;
		PUSH(CS);
		asmout("MOV EBX,OFFSET #taskdir");
		POP(GS);
		add_tags();
	}

	PUSH(SS);
	POP(GS);

	/* tssの確保 */
	ECX = 4096; /* 4KB */
	get_memory();
	if (ZF == 1)
		goto error;
#if 0
	ESP -= 72;
	EBP = EAX;
	(int) [SS:ESP +  0] = 0xffe00000; /* module name */
	(int) [SS:ESP +  4] = 12;
	(int) [SS:ESP +  8] = 0x00737374; /* 'tss' */
	(int) [SS:ESP + 12] = 0xffe00002; /* module type */
	(int) [SS:ESP + 16] = 16;
	(int) [SS:ESP + 20] = 1; /* normal module (binary) */
	(int) [SS:ESP + 24] = 0;
	(int) [SS:ESP + 28] = 0xffe00003; /* standard link-to */
	(int) [SS:ESP + 32] = 32;
	(int) [SS:ESP + 36] = ECX;
	(int) [SS:ESP + 40] = 0;
	(int) [SS:ESP + 44] = ECX;
	(int) [SS:ESP + 48] = 0;
	(int) [SS:ESP + 52] = EAX;
	(int) [SS:ESP + 56] = 0;
	(int) [SS:ESP + 60] = 0xffffffff;
	(int) [SS:ESP + 64] = 0xffffffff;
#endif
	EBP = EAX;
	PUSH(EAX); /* +68 */
	PUSH((int) 0xffffffff); /* +64 */
	PUSH((int) 0xffffffff); /* +60 */
	PUSH((int) 0); /* +56 */
	PUSH(EAX); /* +52 */
	PUSH((int) 0); /* +48 */
	PUSH((int) ECX); /* +44 */
	PUSH((int) 0); /* +40 */
	PUSH((int) ECX); /* +36 */
	PUSH((int) 32); /* +32 */
	PUSH((int) 0xffe00003); /* +28 */
	PUSH((int) 0); /* +24 */
	PUSH((int) 1); /* +20 */
	PUSH((int) 16); /* +16 */
	PUSH((int) 0xffe00002); /* +12 */
	PUSH((int) 0x00737374); /* +8 */
	PUSH((int) 12); /* +4 */
	PUSH((int) 0xffe00000); /* +0 */

	ECX = 512;
	alloc_tagdir();
	EBX = ESP;
	add_tags();
	(offset) param = (int) [SS:ESP + 16 /* EBX */ + 72];
	ESP += 72;
	EBX = param->tskdir[0];
	regist_module();

	(offset) param = (int) [SS:ESP + 16 /* EBX */];

	if (param->stack0addr[0] == 0xffffffff) {
		ECX = 4096; /* 4KB */
		get_memory();
		if (ZF == 1)
			goto error;
#if 0
		ESP -= 72;
		(int) [SS:ESP +  0] = 0xffe00000; /* module name */
		(int) [SS:ESP +  4] = 16;
		(int) [SS:ESP +  8] = 0x63617473; /* 'stac' */
		(int) [SS:ESP + 12] = 0x0000306b; /* 'k0'   */
		(int) [SS:ESP + 16] = 0xffe00002; /* module type */
		(int) [SS:ESP + 20] = 16;
		(int) [SS:ESP + 24] = 1; /* normal module (binary) */
		(int) [SS:ESP + 28] = 0;
		(int) [SS:ESP + 32] = 0xffe00003; /* standard link-to */
		(int) [SS:ESP + 36] = 32;
		(int) [SS:ESP + 40] = ECX;
		(int) [SS:ESP + 44] = 0;
		(int) [SS:ESP + 48] = ECX;
		(int) [SS:ESP + 52] = 0;
		param->stack0size = ECX;
		(int) [SS:ESP + 56] = EAX;
		(int) [SS:ESP + 60] = 0;
		param->stack0addr[0] = EAX;
		param->stack0addr[4] = EAX;
		(int) [SS:ESP + 64] = 0xffffffff;
		(int) [SS:ESP + 68] = 0xffffffff;
#endif
		PUSH((int) 0xffffffff); /* +68 */
		PUSH((int) 0xffffffff); /* +64 */
		param->stack0addr[0] = EAX;
		param->stack0addr[4] = EAX;
		PUSH((int) 0); /* +60 */
		PUSH(EAX); /* +56 */
		param->stack0size = ECX;
		PUSH((int) 0); /* +52 */
		PUSH(ECX); /* +48 */
		PUSH((int) 0); /* +44 */
		PUSH(ECX); /* +40 */
		PUSH((int) 32); /* +36 */
		PUSH((int) 0xffe00003); /* +32 */
		PUSH((int) 0); /* +28 */
		PUSH((int) 1); /* +24 */
		PUSH((int) 16); /* +20 */
		PUSH((int) 0xffe00002); /* +16 */
		PUSH((int) 0x0000306b); /* +12 */
		PUSH((int) 0x63617473); /* +8 */
		PUSH((int) 16); /* +4 */
		PUSH((int) 0xffe00000); /* +0 */

		ECX = 512;
		alloc_tagdir();
		EBX = ESP;
		add_tags();
		(offset) param = (int) [SS:ESP + 16 /* EBX */ + 72];
		ESP += 72;
		EBX = param->tskdir[0];
		regist_module();
	}

	(offset) param = (int) [SS:ESP + 16 /* EBX */];
	if (param->stack3addr[0] == 0xffffffff) {
		ECX = param->header[0];
		if (ECX != 0) {
		//	get_memory();
		//	if (ZF == 1)
		//		goto error;
			PUSH(EDX);
			EDX = 0;
			get_virtual();
			ESI = 512;
#if 0
			ESP -= 72;
			(int) [SS:ESP +  0] = 0xffe00000; /* module name */
			(int) [SS:ESP +  4] = 16;
			(int) [SS:ESP +  8] = 0x63617473; /* 'stac' */
			(int) [SS:ESP + 12] = 0x0000336b; /* 'k3'   */
			(int) [SS:ESP + 16] = 0xffe00002; /* module type */
			(int) [SS:ESP + 20] = 16;
			(int) [SS:ESP + 24] = 1; /* normal module (binary) */
			(int) [SS:ESP + 28] = 0;
			(int) [SS:ESP + 32] = 0xffe00003; /* standard link-to */
			(int) [SS:ESP + 36] = 32;
			(int) [SS:ESP + 40] = ECX;
			(int) [SS:ESP + 44] = 0;
			(int) [SS:ESP + 48] = ECX;
			(int) [SS:ESP + 52] = 0;
			param->stack3size = ECX;
			(int) [SS:ESP + 56] = EAX;
			(int) [SS:ESP + 60] = EDX;
			param->stack3addr[0] = EAX;
			param->stack3addr[4] = EDX;
			(int) [SS:ESP + 64] = 0xffffffff;
			(int) [SS:ESP + 68] = 0xffffffff;
#endif
			PUSH((int) 0xffffffff); /* +68 */
			PUSH((int) 0xffffffff); /* +64 */
			param->stack3addr[0] = EAX;
			param->stack3addr[4] = EDX;
			PUSH(EDX); /* +60 */
			PUSH(EAX); /* +56 */
			param->stack3size = ECX;
			PUSH((int) 0); /* +52 */
			PUSH(ECX); /* +48 */
			PUSH((int) 0); /* +44 */
			PUSH(ECX); /* +40 */
			PUSH((int) 32); /* +36 */
			PUSH((int) 0xffe00003); /* +32 */
			PUSH((int) 0); /* +28 */
			PUSH((int) 1); /* +24 */
			PUSH((int) 16); /* +20 */
			PUSH((int) 0xffe00002); /* +16 */
			PUSH((int) 0x0000336b); /* +12 */
			PUSH((int) 0x63617473); /* +8 */
			PUSH((int) 16); /* +4 */
			PUSH((int) 0xffe00000); /* +0 */

			PUSH((int) root_sel);
			ECX = 512;
			POP(DS);
			alloc_tagdir();
			EBX = ESP;
			add_tags();
			(offset) param = (int) [SS:ESP + 16 /* EBX */ + 72 + 4];
			ESP += 72;
			EBX = param->tskdir[0];
			regist_module();
			POP(EDX);
		}
	}

	(offset) param = (int) [SS:ESP + 16 /* EBX */];

	/* code, stack0, stack3 */
	ECX = param->codesize;
	PUSH((int) stack_sel);
	ECX += 0x1fff;
	/* ESI = (offset) work->linear_man; */ LEA(ESI, (int) work->linear_man);
	ECX &= 0xfffff000;
	POP(DS);
	ECX += param->stack0size;
	ECX += param->stack3size;
	ECX += param->header[4];
	ECX &= 0xfffffffe;
	get_area();
	if (ZF == 1)
		goto error;
	PUSH(EAX);
	PUSH(ECX);

	PUSH(EBP);
	LEA(EBP, (int) work->tapiwork_man);
	EAX = 0;
	ESI = EBP;
	ECX = [SS:EBP /* len */];
	do {
		EBP += 4;
	} while (EAX == [SS:EBP]);
	EAX = [SS:EBP];
	EBP -= ESI;
	/* (false) */ if ((unsigned) ECX <= EBP)
		INT(0x03); /* resource error */
	BSF(EAX, EAX);
	LEA(EAX, [EAX + EBP * 8 - 32]);
	BTR(work->tapiwork_man.bitmap[0], EAX);
	EAX++;
	EAX <<= 12;
	[SS:ESP + 8 /* EBP */ + 12] = EAX;
	POP(EBP);

//	EAX -= 0x1000;
	(unsigned int) EAX >>= 8; /* 4096で割って、16倍する */
//	EAX += freegdt_sel - 0x10 /* 0x10 == 0x1000 >> 8 */;
	EAX += 240;

	PUSH(EAX);

	/* mapping */
	EDX = [SS:ESP + 4 + 4]; /* linearの先頭 */
	ECX = param->codesize;
	EAX = param->codeaddr[0];
	ECX += 0x1fff;
	EAX &= 0xfffff000;
	ECX &= 0xfffff000;

	PUSH(FS);
	PUSH(EBX);
	MOV(EBX, SS);
	FS = EBX;
	EBX = 0;
	PUSH((int) EBX /* eoc */);
	PUSH((int) EBX /* addr64(high) */);
	PUSH((int) EAX /* addr64(low) */);
	PUSH((int) EBX /* offset64(high) */);
	PUSH((int) EBX /* offset64(low) */);
	PUSH((int) EBX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0x0007 /* opt(present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 40;
	POP(EBX);
//	POP(FS);

	EDX += ECX;
	EAX = param->stack0addr[0];
	ECX = param->stack0size;

//	PUSH(FS);
	PUSH(EBX);
//	MOV(EBX, SS);
//	FS = EBX;
	EBX = 0;
	PUSH((int) EBX /* eoc */);
	PUSH((int) EBX /* addr64(high) */);
	PUSH((int) EAX /* addr64(low) */);
	PUSH((int) EBX /* offset64(high) */);
	PUSH((int) EBX /* offset64(low) */);
	PUSH((int) EBX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0x0007 /* opt(present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 40;
	POP(EBX);
	POP(FS);

	EAX = param->header[4];
	EDX += ECX;
	if (AL == 0)
		EDX += EAX;
	ECX = param->stack3size;
	if (ECX != 0) {
		EAX = param->stack3addr[0];
		PUSH(FS);
		PUSH(EBP);
		PUSH(EBX);
		EBP = param->stack3addr[4];
		MOV(EBX, SS);
		FS = EBX;
		EBX = 0;
		PUSH((int) EBX /* eoc */);
		PUSH((int) EBP /* addr64(high) */);
		PUSH((int) EAX /* addr64(low) */);
		PUSH((int) EBX /* offset64(high) */);
		PUSH((int) EBX /* offset64(low) */);
		PUSH((int) EBX /* pageset */);
		PUSH((int) EDX /* linear */);
		PUSH((int) ECX /* size */);
		PUSH((int) 0x0007 /* opt(present, R/W, user) */);
		PUSH((int) 0x0108 /* cmd(mapping) */);

#if 0
EBX = [SS:ESP + 8 /* EBP */ + 12 + 40 + 12];
if (EBX == 0xffff)
	INT(0x03);
/* tss:3000 45f000 */
/* tss:4000 480000 */
#endif
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 40;
		POP(EBX);
		POP(EBP);
		POP(FS);
	}
	EDX = work->tapiwork_Laddr;
	EDX += [SS:ESP + 8 /* EBP */ + 12];
//	LEA(EAX, [SS:EBP + 0x07  /* present, R/W, user */]);
//	ECX = 4096;

	PUSH(FS);
	PUSH(EBX);
	MOV(EBX, SS);
	FS = EBX;
	EBX = 0;
	PUSH((int) EBX /* eoc */);
	PUSH((int) EBX /* addr64(high) */);
	PUSH((int) EBP /* addr64(low) */);
	PUSH((int) EBX /* offset64(high) */);
	PUSH((int) EBX /* offset64(low) */);
	PUSH((int) EBX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) 4096 /* size */);
	PUSH((int) 0x0007 /* opt(present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	CALLFAR0(papi_sel);
	ESP += 40;
	POP(EBX);
	POP(FS);

	POP(EAX);

	TAPI_TSS *tss == DS:ESI /* 256bytes */;
	TAPI_LlvPrm *tss_LlvPrm == DS:ESI + 256 /* 256bytes(8Llv) */;
//	TAPI_msgbox *tss_msgbox == DS:ESI + 512 /* 64bytes */;
	int *tss_msg_in == DS:ESI + 576 /* 64bytes */, *fpu_reg == DS:ESI + 640 /* 128bytes */;
	/* 256bytesのリザーブ領域 */
	int *tss_msgbuf == DS:ESI + 1024, *tss_sysbuf == DS:ESI + 1536, *ldt_img == DS:ESI + 2048, *tss_systemslot == DS:ESI + 3072;
	int *tss_sysdat == DS:ESI + 748; /* 20バイト */

	ESI = [SS:ESP + 8 /* EBP */ + 8];
	PUSH((int) tapiwork_sel);
	EDX = 0;
	POP(DS);
	ECX = 0x1000 / 4;
	PUSH(ESI);
	do {
		[DS:ESI] = EDX;
		ESI += 4;
		ECX--;
	} while (!= 0);

//	(offset) tss = [SS:ESP + 8 /* EBP */ + 8];
//	ESI -= 0x1000;
	POP(ESI);

//	if (ESI == 0x3000) {
//		EAX = param[ 4 /* code_addr */];
//		ECX = param[32 /* stack0_addr */];
//		EDX = param[40 /* stack3_addr */];
//		INT(0x03);
//	}

	tss->tr[0] = EAX;
	EAX += 0x0008;
	(int) tss->tss386.LDTR = EAX;
	POP(tss_sysdat[4 /* stack0size */]); /* linearの合計サイズ */
	POP(tss_sysdat[8 /* stack0addr(linear) */]); /* linearの先頭 */
	tss_sysdat[12 /* stack3size */] = 0;
	tss_sysdat[16 /* stack3addr(linear) */] = 0;

//	EAX = tapiwork_sel; DS = AX;

	EAX = CR3;
	tss->tss386.CR3 = EAX;
	(int) tss->tss386.TaskFlags = 0x00800000; // IOBitMap = 128;
	tss->tss386.stack0_ESP = 0xffffffc0;
	(int) tss->tss386.stack0_SS = 0x001c;
//	tss->tss386.EIP = 0;
	tss->tss386.EFLAGS = 0x0202; /* STI */
//	tss->tss386.EAX = 0;
//	tss->tss386.ECX = 0;
//	tss->tss386.EDX = 0;
//	tss->tss386.EBX = 0;
//	tss->tss386.ESP = 0;
//	tss->tss386.EBP = 0;
//	tss->tss386.ESI = 0;
//	tss->tss386.EDI = 0;
//	EAX = 0;
	AL = 0x0f;
	(char) tss->tss386.ES = AL;
	(char) tss->tss386.CS = 0x0007;
	(char) tss->tss386.SS = AL;
	(char) tss->tss386.DS = AL;
	(char) tss->tss386.FS = AL;
	(char) tss->tss386.GS = 0x0027;
//	tss->tss386.ESP = /* 0x0c00 */ 0xffffffc0;

//	tss->set[0] = 0;
//	tss->set[4] = 0;
//	tss->set[8] = 0;
//	tss->run[0] = 0;
//	tss->run[4] = 0;
//	tss->run[8] = 0;
	tss->softint_nest = 0xff; /* 最初はみんなsoftint-disableになっている。 */
	tss->msgbox_rewind_code = 0x01; /* default(ここは、タグで変更可能にしておくべきだろう) */
	tss->softint_Llv = 0xff; /* default(ここも、タグで変更可能にしておくべきだろう) */
	tss->softint_oldLlv = 0xff; /* default */

	LEA(EAX, (int) *tss_LlvPrm);
	tss->Glv = /* (offset) glevel_sleep */ 0x07c0;
	tss->Llv = /* (offset) tss_lv0 */ EAX;
	tss->now_Llv = 0;
	tss->Llv_base = EAX;
//	tss->Ilv = 0;
//	tss->flags = 0;
//	LEA(EAX, (int) *tss_msgbox);
//	tss->msgbox = EAX;
	(char) tss->short_run[11] = 0xff;

	PUSH(ECX);
	ECX = 8;
	do {
		tss_LlvPrm->Glv = /* (offset) glevel_sleep */ 0x07c0;
		(char) tss_LlvPrm->short_run[11] = 0xff;
		(offset) ESI += 32;
		ECX--;
	} while (!= 0);
	POP(ECX);
	ESI -= 256;

	LEA(EAX, *tss_msgbuf);
	tss->msgbox_write_free = 512 / 4 - 2 /* EOSで1。rewind用の予備で1 */;
	tss->msgbox_write_ptr = EAX;
	tss->msgbox_write_ptr0 = EAX;
	EAX += 512 - 4;
	tss->msgbox_write_ptr1 = EAX;
//	tss->msgbox_eom_code = 0;
	tss->msgbox_rewind_code = 1;
//	tss->msgbox_status = 0;

	*tss_msg_in = (offset) tss;

	fpu_reg[0] = 0x037f; // CW(control word)
//	fpu_reg[4] = 0; // SW(status word)
	fpu_reg[8] = 0xffff; // TW(tag word)
	LEA(EAX, [fpu_reg]);
	tss->fpu_reg_img = EAX;

//	(offset) task = (int) [SS:ESP + 8]; /* EBP */

	(offset) param = (int) [SS:ESP + 16 /* EBX */];
	PUSH(work->tapiwork_Laddr);
	PUSH((int) tapiwork_sel);
	POP(GS);

	EAX = param->tskdir[0];
	tss_sysdat[0] = EAX;

	/* ldt:0004 コード */
	EDX = tss_sysdat[ 8];
	EAX = param->codeaddr[0]; /* ページ属性参照のため */
	ECX = param->codesize;
	EAX &= 0xfff;
	PUSH(EDX);
	EDX |= EAX;
	PUSH(ECX);
	LEA(EBX, ldt_img[0x0000]);
	EAX = 0x40fa; /* lv3, Exec/Read, use32 */
	set_modulesegment();
	POP(ECX);
	POP(EDX);
	ECX += 0x1fff;
	(offset) param = (int) [SS:ESP + 16 /* EBX */ + 4];
	ECX &= 0xfffff000;
	EDX += ECX;

	/* ldt:001c lv0スタック */
	ECX = param->stack0size;
//	if (DL == 0x01) {
//		EDX &= 0xffffff80;
//		ECX = 4096;
//		task->stack0_addr = EDX;
//	}
	LEA(EBX, ldt_img[0x0018]);
	EDX += ECX;
	EAX = 0xc096; /* lv0, Stack, use32, page */
	PUSH(EDX);
	set_modulesegment();
	POP(EDX);
	(offset) param = (int) [SS:ESP + 16 /* EBX */ + 4];

	/* ldt:000c データー兼スタック */
	ECX = param->stack3size;
	if (ECX != 0) {
		EAX = param->header[4];
		ECX += EAX;
		if (AL == 0)
			EDX += EAX;
		ECX &= 0xfffffffe;
		LEA(EBX, ldt_img[0x0008]);
		EAX = 0x40f2; /* lv3, Read/Write, use32 */
		set_modulesegment();
	}

	/* ldt:0014 システムコールゲート（統合・・・かつ暫定的なもの） */
//	LEA(EBX, ldt_img[0x0010]);
//	(short) [DS:EBX + 0] = (offset) &GUIGUI_shellcall;
	asmout("MOV EAX,OFFSET GUIGUI_shellcall");
	(short) ldt_img[0x0010 + 0] = AX;
	(short) ldt_img[0x0010 + 2] = (short) init_sel;
	(int) ldt_img[0x0010 + 4] = 0x0000ec00; // call-gate

	/* ldt:0024 msgboxリードセレクタ */
	ECX = tss->msgbox_write_ptr1;
	LEA(EBX, ldt_img[0x0020]);
	EAX = 0x40f0; /* lv3, Read, use32 */
	LEA(EDX, *tss_msgbuf);
	ECX -= tss->msgbox_write_ptr0;
	EDX += (int) [SS:ESP];
	ECX += 4; // rewindの予備の分
	set_modulesegment();

	/* ldt:003c system-slot */
	LEA(EBX, ldt_img[0x0038]);
	ECX = 1024;
	EAX = 0x4092; /* lv0, Read/Write, use32 */
	LEA(EDX, *tss_systemslot);
	EDX += (int) [SS:ESP];
	set_modulesegment();

	/* ldt:00c4 pioneer0 */
	PUSH(DS);
	PUSH((int) syswork_sel);
	POP(DS);
	ECX = [DS:32 + pioneer_ent + 0x08];
	EDX = [DS:32 + pioneer_ent + 0x0c];
	POP(DS);
	LEA(EBX, ldt_img[0x00c0]);
	EAX = 0x40fa; /* lv3, Exec/Read, use32 */
	set_modulesegment();

	/* ldt:00cc sysgg00 */
//	LEA(EBX, ldt_img[0x0010]);
//	(short) [DS:EBX + 0] = (offset) &GUIGUI_shellcall2;
	asmout("MOV EAX,OFFSET GUIGUI_shellcall2");
	(short) ldt_img[0x00c8 + 0] = AX;
	(short) ldt_img[0x00c8 + 2] = (short) init_sel;
	(int) ldt_img[0x00c8 + 4] = 0x0000ec00; // call-gate

	// ldt:0044 GUIGUI-gate
	// ldt:004c GAPI-gate
	// ldt:0054 Timer-gate
	// ldt:005c TAPI-gate

	/* ldt:0100〜07ff ユーザー解放(112個) */

	tss_systemslot[0x0008] = 512; /* slotサイズ */
	tss_systemslot[0x000c] = 0xffffffff; // 使用中(reserve)
	tss_systemslot[0x00c0] = 256;
	tss_systemslot[0x00c4] = 0; /* base */
	tss_systemslot[0x00c8] = 0x1004; /* conv */
	tss_systemslot[0x00d0] = 0; /* terminator */
	LEA(EAX, *tss_msg_in);
	tss_systemslot[0x0148] = EAX;

	/* gdtの設定 */
	EDX = (int) [SS:ESP];
	EAX = idtgdt_sel;
	EDX += (offset) tss;
	EBX = tss->tr[0];
	GS = AX;
	ECX = 128;
	EAX = 0x0089 /* use16, lv0, TSS386 */;
	EBX += 0x0030 * 8; /* IDTの分 */
	set_modulesegment();

	POP(EDX);
	EBX = (int) tss->tss386.LDTR;
//	EDX += (offset) ldt_img;
	/* LEA(EDX, ldt_img[EDX]) */ LEA(EDX, [EDX + ESI + 2048]);
	ECX = 1024;
	EAX = 0x0082 /* use16, lv0, LDT */;
	EBX += 0x0030 * 8; /* IDTの分 */
	set_modulesegment();

	/* stack0の初期化 */
	/* DSを使ってアクセスする */
	SLDT(DX);
	CLI();
	LLDT((short) tss->tss386.LDTR);
	EBX = 0x001c /* stack0 */;
	DS = BX;
	EBX = 0;
	EBP = 0;
	(int) [DS:EBX + 0xffffffe0] = 0xffffff80;
	(int) [DS:EBX + 0xfffffff0] = 0xffffff80;
	EAX = (int) [SS:EBP + 0xffffffe8];
	ECX = (int) [SS:EBP + 0xffffffec];
	(int) [DS:EBX + 0xffffffe8] = EAX;
	(int) [DS:EBX + 0xffffffec] = ECX;
	EAX = (int) [SS:EBP + 0xfffffff8];
	ECX = (int) [SS:EBP + 0xfffffffc];
	(int) [DS:EBX + 0xfffffff8] = EAX;
	(int) [DS:EBX + 0xfffffffc] = ECX;
	#if (VMWARE)
		if (EDX != 0)
			LLDT(DX);
	#else
		LLDT(DX);
	#endif
	STI();
	TEST(ESP, ESP); /* ZF = 0 */

error:
	POPAD();
	POP(DS);
//	POP(ES);
	POP(GS);
	return;

	ALIGN(4);
taskdir:
	DD(0xffe00000); DD(12); asmout("DB 'task'");
	DD(0xffe00002); DD(16); DD(0 /* normal-directry */); DD(0);
	DD(0xffe00040); DD(16); DD(20); DD(512 /* ここを自動的に検出 */); DD(0); DD(0);
	DD(0xfff00000); DD(0xffffffff); /* DD(0); DD(0); */
}

#if 0

void near disable_diskcache()
/* EAX, ECX, EDXを破壊 */
{
	GUIGUI_work *work == SS:0xffffd000;
	PUSH(DS);
	EAX = pdepte_sel;
	DS = AX;
	EAX = 0;
	do {
		BTR(work->cacheflags[0], EAX);
		if (CF == 1) {
			EDX = EAX;
		//	PUSH(EAX);
			EDX *= 4096;
			ECX = 4096;
			EDX += work->diskcache_Laddr;
			unmapping0();
		//	POP(EAX);
		}
		EAX++;
	} while (EAX != 512 /* 2MB分 */);
	POP(DS);

	/* track初期化 */
	EAX = 0;
	LEA(EBP, work->track[0]);
	[SS:EBP +  0] = EAX;
	[SS:EBP +  4] = EAX;
	[SS:EBP +  8] = EAX;
	[SS:EBP + 12] = EAX;
	[SS:EBP + 16] = EAX;
	return;
}

void near dosload_loadtrack()
/* EAXがトラック番号 */
/* ロードアドレスなどは自動設定される */
/* phaseは自動的にインクリメントされる */
{
	GUIGUI_work *work == SS:0xffffd000;
	work->dosload_phase++;

}

void near dosload_nextphase()
{
	GUIGUI_work *work == SS:0xffffd000;
	EBX = work->dosload_phase;

	asmout("dosload_stratphase:");
		/* EBXが引数(EAX〜EDXはパラメーター) */

next_phase:
	#if (defined(PCAT) || defined(TOWNS))
		if (EBX == 1)
			goto phase00001;
		if (EBX == 2)
			goto phase00002;
		if (EBX == 3)
			goto phase00002;
	#endif
	INT(0x03);

phase00001:
	/* load FAT(1) */
	work->dosload_work[0] = EAX; /* signal */
	EAX = 0;
	BTS(work->track[0], EAX);
	asmout("JNC dosload_loadtrack");

phase00002:
	/* load FAT(2) */
	EAX = 1;
	BTS(work->track[0], EAX);
	asmout("JNC dosload_loadtrack");

phase00003:
	PUSH((int) 0); // eoc
	PUSH(work->dosload_work[0]);
	PUSH(0x1241);
	PUSH(0x0114 /* コマンドシグナル直接 */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16;
	return;


}

#endif

void far GUIGUI_shellcall()
{
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int GAPI_sel     ==  4 * 8, GAPIwork_sel  ==  5 * 8;
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;
	unsigned int timerint_sel == 10 * 8, timerdata_sel == 11 * 8;
	unsigned int tapi_sel     == 12 * 8, tapiwork_sel  == 13 * 8;
	unsigned int pdepte_sel   == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int root_sel     == 16 * 8, tmp_sel       == 17 * 8;
	unsigned int papi_sel     == 18 * 8;
	unsigned int decode_sel   == 22 * 8, decowork_sel  == 23 * 8;
	unsigned int fdcdrive_sel == 28 * 8, fdcwork_sel   == 29 * 8;
	unsigned int diskbuf_sel  == 30 * 8, textbuf_sel   == 31 * 8;
	unsigned int freegdt_sel  == 32 * 8;

	int *cmd == GS:EBP;

	/* lv3からの進入の可能性があるので、カウントを増やす。 */
	(char) [SS:0xffffffe0]++;

	if ((unsigned) (offset) EBX == 0xffffffff) {
		if (EAX == 0x0004) {
			EDX = 0x003c; // slot_sel
			PUSH(DS);
			DS = EDX;
			EAX = (int) [DS:ECX    ];
			EDX = (int) [DS:ECX + 8];
			ECX = (int) [DS:ECX + 4];
			POP(DS);
			goto dec_lv0cnt_ret;
		}
		INT(0x03);
	}

	PUSH(DS);
	PUSH(ES);
	PUSH(FS);
	PUSH(GS);
	PUSHAD();
	MOV(EAX, FS);
	MOV(ECX, SS);
	EBP = EBX;
	GS = EAX;
	FS = ECX;

nextcmd:
	EAX = cmd[0];
	if ((unsigned) EAX < 0x0200) {
		if (EAX == 0)
			goto cmd0000; // end of command
		if (EAX == 0x0040)
			goto cmd0040; // close task
		if (EAX == 0x0080)
			goto cmd0080; // user slot define
		if (EAX == 0x0100)
			goto cmd0100; // open window
		if (EAX == 0x0104)
			goto cmd0104; // close window
		if (EAX == 0x0140)
			goto cmd0140; // send access-disabled-signal
		if (EAX == 0x0144)
			goto cmd0144; // send draw-finiched-signal
		INT(0x03);
	}
	if ((unsigned) EAX < 0x0400) {
		if (EAX == 0x0200)
			goto cmd0200; // set soft-int vector
		if (EAX == 0x0204)
			goto cmd0204; // add nest
		if (EAX == 0x0208)
			goto cmd0208; // add nest & return soft-int
		if (EAX == 0x0240)
			goto cmd0240; // set segment
		if (EAX == 0x0300)
			goto cmd0300; // open timer
		if (EAX == 0x0304)
			goto cmd0304; // close timer
		if (EAX == 0x0308)
			goto cmd0308; // regist timer
		if (EAX == 0x030c)
			goto cmd030c; // cancel timer
		if (EAX == 0x0310)
			goto cmd0310; // load time
		if (EAX == 0x0314)
			goto cmd0314; // add time
		if (EAX == 0x0318)
			goto cmd0318; // set timer message
		if (EAX == 0x031c)
			goto cmd031c; // set timer interval
		if (EAX == 0x0320)
			goto cmd0320; // set timer opt81
		if (EAX == 0x0324)
			goto cmd0324; // set timer opt82
		if (EAX == 0x0328)
			goto cmd0328; // get randseed
		INT(0x03);
	}
	if ((unsigned) EAX < 0x0600) {
		if (EAX == 0x0400)
			goto cmd0400; // line
		if (EAX == 0x0404)
			goto cmd0404; // put string
		if (EAX == 0x0408)
			goto cmd0408; /* load font */
		if (EAX == 0x040c)
			goto cmd040c; /* free font */
		if (EAX == 0x0410)
			goto cmd0410; /* make charset */
		if (EAX == 0x0414)
			goto cmd0414; /* put graphic box */
		if (EAX == 0x0418)
			goto cmd0418; /* linear dots */
		if (EAX == 0x041c)
			goto cmd041c; /* points */
		if (EAX == 0x0510)
			goto cmd0510; // define signal
		INT(0x03);
	}
	if ((unsigned) EAX < 0x0800) {
		if (EAX == 0x0600)
			goto cmd0600; // open sound track
		if (EAX == 0x0604)
			goto cmd0604; // close sound track
		if (EAX == 0x0608)
			goto cmd0608; // enable/disable sound track
		if (EAX == 0x060c)
			goto cmd060c; // control sound track
		if (EAX == 0x0700)
			goto cmd0700; /* init handle */ 
		if (EAX == 0x0708)
			goto cmd0708; /* copy handle */ 
		if (EAX == 0x070c)
			goto cmd070c; /* change directory */ 
		if (EAX == 0x0710)
			goto cmd0710; /* create module */ 
		if (EAX == 0x0720)
			goto cmd0720; /* map module */
		if (EAX == 0x0728)
			goto cmd0728; /* read tag */
		if (EAX == 0x0730)
			goto cmd0730; /* tag listing */ 
		if (EAX == 0x0740)
			goto cmd0740; /* resize file */
		INT(0x03);
	}
	if (EAX == 0xffffffff)
		goto cmd0ffffffff;
	INT(0x03);

cmd0000:
	EBX = (offset) cmd;
	EDI = (int) [SS:ESP +  0];
	ESI = (int) [SS:ESP +  4];
	EBP = (int) [SS:ESP +  8];
	EDX = (int) [SS:ESP + 20];
	ECX = (int) [SS:ESP + 24];
	EAX = (int) [SS:ESP + 28];
	GS = (short) [SS:ESP + 32];
	FS = (short) [SS:ESP + 36];
	ES = (short) [SS:ESP + 40];
	DS = (short) [SS:ESP + 44];
	ESP += 48;
dec_lv0cnt_ret:
	CLI();
	(char) [SS:0xffffffe0]--;
	if (!= 0) {
		STI();
		return; // CF = 0, ZF = 0
	}
	TEST(ESP, ESP); // ZF = 0
	PUSHFD();
//	(int) [SS:ESP] |= 0x0200; // IF = 1, ZF == 0
	(char) [SS:ESP + 1] |= 0x02; // IF = 1, ZF == 0
	asmout("jmp_system_count0");

cmd0040:
	// close task
//	(offset) cmd += 8;

	EAX = cmd[4];
	TEST(AL, 0x01);
	if (== 0)
		goto cmd0040_skip;

	/* スロットに含まれるものを検索して、解放する */
	EDX = 0x003c; /* slot_sel */
	LSL(ECX, EDX);
	ES = EDX;
	ECX++;
	ESI = 0;
	(unsigned int) ECX /= 16;
	do {
		EAX = [ES:ESI + 12];
		if (EAX == 0x0100 /* window */) {
		//	GUIGUI_window_struct *cmd0040_win == DS:EDX;
		//	EAX = stack_sel;
		//	(offset) cmd0040_win = (int) [ES:ESI +  8];
		//	DS = EAX;
		//	cmd0040_win->status = 0; // 破棄
			PUSH((int) 0);
			PUSH((int) [ES:ESI +  8]);
			PUSH((int) 0x0024); // close window
			PUSH((int) 0x7f000002);
			PUSH((int) 0x3240 + 3);
			PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
			EBX = ESP;
			CALLFAR0(tapi_sel);
			(char) cmd[6]++; /* クローズ通知数 */
			ESP += 24;
		} else if (EAX == 0x0104) { /* timer */
			EAX = (int) [ES:ESI];
			PUSH((int) 0);
			PUSH(EAX);
			PUSH((int) 0x000c /* FreeNode */);
			PUSH(EAX);
			PUSH((int) 0x0014 /* CancelTimer */);
			EBX = ESP;
			DB(0x9a); DD(0); DW((short) timerint_sel);
			if (CF == 1) {
				INT(0x03);
			}
		//	(char) cmd[6]++; /* クローズ通知数 */
			ESP += 20;
		} else if (EAX == 0x0110) { /* soundtrack */
			EDX = [ES:ESI + 8]; /* system-ID */
			TEST(DL, 0x01);
			if (!= 0) { /* 使用中だったら、消音する */
				PUSHFD();
				CLI();
				#if (defined(PCAT))
					IN(AL, 0x0061);
					AL &= 0x0d;
					AL |= 0x01;
					OUT(0x0061, AL);
				#endif
				#if (defined(TOWNS))
					IN(AL, 0x0060);
					AL >>= 2;
					AL &= 0x03;
					OUT(0x0060, AL);
				#endif
				POPFD();
			}
			EDX &= 0xffffffe;
			PUSH((int) 0);
			PUSH(EDX); // slot
			PUSH((int) 0x0044); // command(close sound track)
			PUSH((int) 0x7f000002);
			PUSH((int) 0x3240 /* winman0 */ + 3);
			PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
			EBX = ESP;
			CALLFAR0(tapi_sel);
			(char) cmd[6]++; /* クローズ通知数 */
			ESP += 24;

// 0108はsubtimer

		} else if (EAX == 0x0118) {
			/* alloced font mark */
			EAX = GAPIwork_sel;
			PUSH(ESI);
			PUSH(ECX);
			ECX = [ES:ESI + 4] /* conv */;
			DS = AX;
			EBX = [ES:ESI + 0] /* max-range */;
			EAX = ECX;
			ECX &= 0x0f;
			EAX &= 0xfffffff0;
		//	EBX <<= CL;
			SHL(EBX, CL);
			ESI = 0x0c00;
			ECX = EBX;
			free_area();
			POP(ECX);
			POP(ESI);
		}
		EAX = 0;
	//	[ES:ESI + 12] = EAX;
		ESI += 16;
		ECX--;
	} while (!= 0);

	EAX = cmd[4];
cmd0040_skip:
	TEST(AL, 0x02);
	if (== 0)
		goto cmd0040_skip2;

	EAX = tapiwork_sel;
	DS = AX;

	// 全てが済んだら、Initタスクにシグナルを送って、
	// 自分はスリープ
//	PUSH((int) 0);
//	PUSH((int) [DS:0x000c]);
//	PUSH((int) 0x0120); // destory task
//	PUSH((int) 0x1240 + 2);
//	AX = SS;
//	ESI = ESP;
//	DS = AX;
//	asmout("fcall 12*8,TAPI_SingnalMessageTimer"); // (not init task...コマンドシグナル...下のとまとめられる)
//	ESP += 20;


	// 本当はベクタを切り離し、メッセージを空にして、スリープ。
	EAX = 0;
	PUSH(EAX); // eoc
	PUSH(EAX); // signals
	PUSH(EAX); // delta-nest, Llv0(sleep)
	PUSH((int) 0x010c); // TAPI_AddNestSleep // きっと、このコマンドは効いていない

	PUSH((int) [DS:0x000c]);
	PUSH((int) 0x0120); // destory task
	PUSH((int) 0x1240 + 2);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);

	EBX = ESP;
	CALLFAR0(tapi_sel);
//	ESP += ??;

	INT(0x03);
cmd0040_skip2:
	(offset) cmd += 8;
	goto nextcmd;

cmd0080:
	// user slot define
	EDX = 0x003c; /* slot_sel */
	ESI = cmd[ 4];
	DS = EDX;
	EAX = cmd[ 8];
	ECX = cmd[12];
	EDX = cmd[16];
	(offset) cmd += 20;
	(int) [DS:ESI     ] = EAX;
	(int) [DS:ESI +  4] = ECX;
	(int) [DS:ESI +  8] = EDX;
//	STR(BX);
//	if (BX == 0x0130)
//		INT(0x03);
	goto nextcmd;

cmd0100:
	PUSH((int) stack_sel);
//	INC((char) [SS:0xfffffff0]); // タスク切り替え抑制
	CLI();
	POP(DS);
	GUIGUI_work *cmd0100_work == DS:0xffffd000;
	GUIGUI_window_struct *cmd0100_win == DS:ESI;
//	(offset) cmd0100_win = (offset) cmd0100_work->winlist;
	LEA((offset) cmd0100_win, (int) cmd0100_work->winlist[0]);
	ECX = MAXWINDOW;
	do {
		if (cmd0100_win->status == 0)
			goto get_free_win_slot;
		(offset) cmd0100_win += sizeof (GUIGUI_window_struct);
		ECX--;
	} while (!= 0);
	// winlist full
	INT(0x03);

get_free_win_slot:
	(char) cmd0100_win->status = 1; // オープン要請中
	STI();
//	DEC((char) [SS:0xfffffff0]); // タスク切り替え抑制解除
//	if (== 0) {
//		PUSH((offset) cmd);
//		asmout("CALL FWORD PTR SS:[0FFFFFFF8H]");
//		EAX = stack_sel;
//		POP((offset) cmd);
//		DS = AX;
//	}
	EDX = cmd[ 4]; // slot-no
	EAX = cmd[ 8]; // user-no
	ECX = cmd[12]; // x-size
	cmd0100_win->win_id_task = EAX;
	cmd0100_win->x_size = ECX;
	EAX = cmd[16]; // y-size
	ECX = cmd[24]; // signal-base
	cmd0100_win->y_size = EAX;
	cmd0100_win->signal_base = ECX;
	(offset) cmd += 28;
//	cmd0100_win->keyfilter = 0x1000;
	EAX = tapiwork_sel;
	ES = AX;
	EAX = [ES:0x000c /* TskPointer */];
	EAX += 0x0240;
	cmd0100_win->msgbox = EAX;
	EAX = 0x003c; /* slot_sel */
	DS = AX;
	(int) [DS:EDX +  8] = (offset) cmd0100_win;
	(int) [DS:EDX + 12] = 0x0100; // window-id mark
	// 最後に、winman0に、window openシグナルを送る
	PUSH((int) 0);
	PUSH((offset) cmd0100_win);
	PUSH((int) 0x0020);
cmd0100_send:
	PUSH((int) 0x7f000002);
	PUSH((int) 0x3240 + 3);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 24;
	goto nextcmd;

cmd0104:
	// close window
	GUIGUI_window_struct *cmd0104_win == DS:ESI;
	EAX = 0x003c; /* slot_sel */
	EDX = cmd[4];
	(offset) cmd += 8;
	DS = EAX;
//	EAX = stack_sel;
	(offset) cmd0104_win = [DS:EDX + 8];
	(int) [DS:EDX + 12] = 0;
//	DS = EAX;
//	cmd0104_win->status = 0; // 破棄
	PUSH((int) 0);
	PUSH((offset) cmd0104_win);
	PUSH((int) 0x0024); // close window
	PUSH((int) 0x7f000002);
	PUSH((int) 0x3240 + 3);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 24;
	goto nextcmd;

cmd0140:
	// 表示禁止シグナル受理
	EAX = 0x003c; /* slot_sel */
	EDX = cmd[ 4]; // slot-no
	DS = AX;
	(offset) cmd += 8;
	PUSH((int) 0);
	PUSH((int) [DS:EDX +  8]);
	PUSH((int) 0x00c0);
	goto cmd0100_send;

cmd0144:
	// 描画完了シグナル受理
	EAX = 0x003c; /* slot_sel */
	EDX = cmd[ 4]; // slot-no
	DS = AX;
	(offset) cmd += 8;
	PUSH((int) 0);
	PUSH((int) [DS:EDX +  8]);
	PUSH((int) 0x00c4);
	goto cmd0100_send;

cmd0200:
	// softint vector 設定
	// 0x0200, EIP, CS, Llv, flgas
	EAX = tapiwork_sel;
	DS = AX;
	TAPI_TSS *cmd0200_tss == DS:ESI;
	(offset) cmd0200_tss = [DS:0x000c /* TskPointer */];
	EAX = cmd[ 4]; // EIP
	ECX = cmd[ 8]; // CS(eom, rewind)
	cmd0200_tss->softint_EIP = EAX;
	(int) cmd0200_tss->softint_CS = ECX;
	AL = cmd[12]; // Llv
	(offset) cmd += 16;
//	cmd0200_tss->softint_mode = AH;

	cmd0200_tss->softint_Llv = AL;
	cmd0200_tss->softint_oldLlv = 0xff;
//	AL = cmd0200_tss->msgbox_status; TEST(AL, 0x80);
//	if (!= 0) {
		// もうメッセージが来ている...いや、ベクタの変更はnestでマスクしてから行うので問題はない
//		INT(0x03); // 未完成
//		EAX = cmd0200_tss->softint_Llv;
//		if ((unsigned) EAX != cmd0200_tss->Llv) {
//			// しかも、現在のレベルとは違う設定
//			INT(0x03);
//		}
//	}
	goto nextcmd;

cmd0204:
	// add nest

//	AL = (char) cmd[8];
//	ECX = cmd[4];
//	DL = (char) cmd[9];
	PUSH((int) 0); // eoc
	PUSH(cmd[4]); // signals
	PUSH(cmd[8]); // delta-nest(割り込みを使わないから、nestは変更しない), Llv
	PUSH((int) 0x010c); // TAPI_AddNestSleep
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16;
	(offset) cmd += 12;
	goto nextcmd;

cmd0208:
	// add nest & ret from softint
	ECX = cmd[4];
	AL = (char) cmd[8];
	(offset) cmd += 12;
	PUSH((int) 0);
	PUSH(EAX);
	PUSH(ECX);
	PUSH((int) 0x0124 /* TAPI_Softint1Ret */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 16;
	goto nextcmd;

cmd0240:
	// set segment
	// opt, selector, ar, limit, offset, base_selector
	EAX = tapiwork_sel;
	EDX = 0x0800;
	DS = AX;
	EDX += [DS:0x0c];
	ECX = EDX;
	EDX += cmd[24]; /* base_selector */
	ECX += cmd[ 8]; /* selector */
	EDX &= 0xfffffff8;
	ECX &= 0xfffffff8;
	AL = [DS:EDX + 4];
	AH = [DS:EDX + 7];
	EAX <<= 16;
	AX = [DS:EDX + 2];
	EAX += cmd[20]; /* offset */
	[DS:ECX + 2] = AX;
	(unsigned int) EAX >>= 16;
	[DS:ECX + 4] = AL;
	[DS:ECX + 7] = AH;
	EAX = cmd[16]; /* limit */
	[DS:ECX + 0] = AX;
	(unsigned int) EAX >>= 16;
	AL |= (char) cmd[13]; /* ar[1] */
	[DS:ECX + 6] = AL;
	AL = cmd[12]; /* ar[0] */
	[DS:ECX + 5] = AL;
	(offset) cmd += 28;
	goto nextcmd;

cmd0300:
	// タイマーノード取得
	EDX = cmd[4];
	(offset) cmd += 8;
	EAX = 0x003c;
	DS = AX;
	ESP -= 20;
	EBX = ESP;
	(int) [SS:ESP     ] = 0x0008 /* GetNode */;
	(int) [SS:ESP +  8] = 0x0000 /* EOC */;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	EAX = (int) [SS:ESP + 4];
	if (CF == 1) {
		INT(0x03);
	}
//	PUSH(ES);
	GUIGUI_work *cmd0300_work == ES:0xffffd000;
	EBX = stack_sel;
	ES = BX;
	ECX = cmd0300_work->TAPI_sendmsgofs;
//	POP(ES);
	(int) [DS:EDX     ] = EAX;
	(int) [DS:EDX + 12] = 0x0104; // timer
	(int) [DS:EDX + 28] = 0x0108; // subtimer
	(int) [DS:EDX + 44] = 0x0108; // subtimer
	(int) [SS:ESP     ] = 0x0028 /* SetCallVectorNode */;
	(int) [SS:ESP +  8] = ECX;
	(int) [SS:ESP + 12] = tapi_sel;
	(int) [SS:ESP + 16] = 0x0000 /* EOC */;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
//	if (CF == 1) {
//		INT(0x03);
//	}
	ESP += 20;
	(char) [DS:EDX +  7] = 0; // メッセージの最初のDW
	goto nextcmd;

cmd0304:
	// タイマーノード返却
	INT(0x03);

cmd0308:
	// タイマー登録
	EDX = cmd[4];
	(offset) cmd += 8;
	PUSH((int) 0x003c);
	POP(DS);
	PUSH((int) 0x0000 /* EOC */);
	ECX = (int) [DS:EDX     ];
	PUSH(ECX);
	PUSH((int) 0x0010 /* SetTimer */);
	PUSH((int) [DS:EDX + 40]);
	PUSH((int) [DS:EDX + 36]);
	PUSH((int) [DS:EDX + 32]);
	PUSH((int) [DS:EDX + 24]);
	PUSH((int) [DS:EDX + 20]);
	PUSH((int) [DS:EDX + 16]);
	PUSH((int) [DS:EDX +  8]);
	PUSH((int) [DS:EDX +  4]);
	PUSH((int) 8);
	PUSH(ECX);
	PUSH((int) 0x002c /* SetMsgDataNode */);
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	if (CF == 1) {
		INT(0x03);
	}
	ESP += 56;
	goto nextcmd;

cmd030c:
	// タイマー解約
	EDX = cmd[4];
	(offset) cmd += 8;
	PUSH((int) 0x003c);
	POP(DS);
	PUSH((int) 0x0000 /* EOC */);
	PUSH((int) [DS:EDX     ]);
	PUSH((int) 0x0014 /* CancelTimer */);
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	if (CF == 1) {
		INT(0x03);
	}
	ESP += 12;
	goto nextcmd;

cmd0310:
	// 現在時刻ロード
	EDX = cmd[4];
	(offset) cmd += 8;
	EAX = 0x003c;
	DS = AX;
	PUSH((int) 0x0000 /* EOC */);
	PUSH((int) [DS:EDX    ]);
	PUSH((int) 0x001c /* SetNowTimeNode */);
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	if (CF == 1) {
		INT(0x03);
	}
	ESP += 12;
	goto nextcmd;

cmd0314:
	// 時間加算
	GUIGUI_work *cmd0314_work == ES:0xffffd000;
	EDX = cmd[ 4];
	ECX = 0;
	EAX = 0x003c;
	PUSH(ECX /* EOC */);
	DS = AX;
	PUSH(ECX);
	PUSH(ECX);
	PUSH(ECX);
	PUSH((int) [DS:EDX    ]);
	PUSH((int) stack_sel);
	POP(ES);
	PUSH((int) 0x0020 /* AddTimeNode */);
	ECX = cmd0314_work->timer_freq; // 1193180;
	EAX = cmd[ 8];
	if (EAX != 0) {
		MUL(ECX);
		EAX <<= 1; // EAXのMSBをCFへ。
	//	(int) [SS:ESP +  8] += EDX + CF;
		ADC((int) [SS:ESP +  8], EDX);
	}
	EAX = cmd[12];
	if (EAX != 0) {
		MUL(ECX);
		(int) [SS:ESP +  8] += EAX;
	//	(int) [SS:ESP + 12] += EDX + CF;
		ADC((int) [SS:ESP + 12], EDX);
	}
	EAX = cmd[16];
	if (EAX != 0) {
		MUL(ECX);
		(int) [SS:ESP + 12] += EAX;
	//	(int) [SS:ESP + 16] += EDX + CF;
		ADC((int) [SS:ESP + 16], EDX);
	}
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
//	if (CF == 1) {
//		INT(0x03);
//	}
	ESP += 24;
	(offset) cmd += 20;
	goto nextcmd;

cmd0318:
	// メッセージ設定
	EAX = 0x003c;
	ECX = cmd[12];
	DS = AX;
	EDX = cmd[ 8];
	ESI = cmd[ 4];
	EAX = [DS:EDX +  8]; // スロット番号
	(offset) cmd += 16;
	(int) [DS:ESI +  4] &= 0x80000000; // 最上位bitを残す
	EAX |= ECX;
	(int) [DS:ESI +  4] |= EAX;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI +  8] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI + 16] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI + 20] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI + 24] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI + 32] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
	ECX--;
	(int) [DS:ESI + 36] = EAX;
	if (== 0)
		goto nextcmd;
	EAX = *cmd;
	(offset) cmd += 4;
//	ECX--;
	(int) [DS:ESI + 40] = EAX;
//	if (== 0)
//		goto cmd0318_fin;
	goto nextcmd;

cmd031c:
	// インターバル間隔設定
	GUIGUI_work *cmd031c_work == ES:0xffffd000;
	ECX = 0x003c;
	EAX = cmd[ 8];
	DS = CX;
	ECX = stack_sel;
	ESI = cmd[ 4];
	ES = CX;
	EAX |= cmd[12];
	(char) [DS:ESI +  7] &= 0x7f; // 単発モード
	EAX |= cmd[16];
	if (!= 0) {
		EAX = 0;
		(char) [DS:ESI +  7] |= 0x80; // 連続モード
		(int) [DS:ESI + 32] = EAX;
		(int) [DS:ESI + 36] = EAX;
		(int) [DS:ESI + 40] = EAX;
		ECX = cmd031c_work->timer_freq; // 1193180;
		EAX = cmd[ 8];
		if (EAX != 0) {
			MUL(ECX);
			EAX <<= 1; // EAXのMSBをCFへ。
		//	(int) [DS:ESI + 32] += EDX + CF;
			ADC((int) [DS:ESI + 32], EDX);
		}
		EAX = cmd[12];
		if (EAX != 0) {
			MUL(ECX);
			(int) [DS:ESI + 32] += EAX;
		//	(int) [DS:ESI + 36] += EDX + CF;
			ADC((int) [DS:ESI + 36], EDX);
		}
		EAX = cmd[16];
		if (EAX != 0) {
			MUL(ECX);
			(int) [DS:ESI + 36] += EAX;
		//	(int) [DS:ESI + 40] += EDX + CF;
			ADC((int) [DS:ESI + 40], EDX);
		}
	}
	(offset) cmd += 20;
	goto nextcmd;

cmd0320:
	// set timer opt81
	// cmd, slot0, slot1, time0, time1, time2
	GUIGUI_work *cmd0320_work == ES:0xffffd000;
	PUSH((int) stack_sel);
	PUSH((int) 0x003c);
	ECX = 0;
	POP(DS); /* == 0x003c */
	POP(ES); /* == stack_sel */
	ESI = cmd[ 4];
	EDI = cmd[ 8];
	PUSH(ECX /* EOC */);
	PUSH(ECX);
	PUSH(ECX);
	PUSH(ECX);
	PUSH((int) [DS:EDI]);
	PUSH((int) [DS:ESI]);
	PUSH((int) 0x0034 /* AddTimeNode2 */);
	ECX = cmd0320_work->timer_freq; // 1193180;
	EAX = cmd[12];
	if (EAX != 0) {
		MUL(ECX);
		EAX <<= 1; // EAXのMSBをCFへ。
	//	(int) [SS:ESP + 12] += EDX + CF;
		ADC((int) [SS:ESP + 12], EDX);
	}
	EAX = cmd[16];
	if (EAX != 0) {
		MUL(ECX);
		(int) [SS:ESP + 12] += EAX;
	//	(int) [SS:ESP + 16] += EDX + CF;
		ADC((int) [SS:ESP + 16], EDX);
	}
	EAX = cmd[20];
	if (EAX != 0) {
		MUL(ECX);
		(int) [SS:ESP + 16] += EAX;
	//	(int) [SS:ESP + 20] += EDX + CF;
		ADC((int) [SS:ESP + 20], EDX);
	}
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
//	if (CF == 1) {
//		INT(0x03);
//	}
	ESP += 28;
	(offset) cmd += 24;
	goto nextcmd;

cmd0324:
	// set timer opt82
	// cmd, slot0, slot1, time0, time1, time2
	GUIGUI_work *cmd0324_work == ES:0xffffd000;
	PUSH((int) stack_sel);
	PUSH((int) 0x003c);
	ECX = 0;
	POP(DS); /* == 0x003c */
	POP(ES); /* == stack_sel */
	ESI = cmd[ 4];
	EDI = cmd[ 8];
	PUSH(ECX /* EOC */);
	PUSH(ECX);
	PUSH(ECX);
	PUSH(ECX);
	PUSH((int) [DS:EDI]);
	PUSH((int) [DS:ESI]);
	PUSH((int) 0x0024 /* SubTimeNode */);
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	ESP += 12;
	EBX = cmd0324_work->timer_sec4;
	POP(EAX);
	MUL(EBX);
	cmd[12] = EAX;
	POP(EAX);
	cmd[16] = EDX;
	cmd[20] = ECX;
	if (EAX != 0) {
		MUL(EBX);
		cmd[16] += EAX;
		ADC(cmd[20], EDX);
	}
	POP(EAX);
	if (EAX != 0) {
		MUL(EBX);
		cmd[20] += EAX;
	}
	POP(ECX);
	(offset) cmd += 24;
	goto nextcmd;

cmd0328:
	/* getrandseed */
	/* TimerSC_SetNowTimeコマンドを使うのでタイマーはいらない */
	ECX = 0;
	PUSH(ECX /* EOC */);
	PUSH(ECX);
	PUSH(ECX);
	PUSH(ECX);
	PUSH((int) 0x0018 /* TimerSC_SetNowTime */);
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	POP(EBX);
	POP(EAX);
	POP(ECX);
	XCHG(AH, AL); /* かき回し */
	POP(EDX);
	EAX ^= ECX;
	POP(EBX);
	EAX ^= EDX;
	cmd[4] = EAX;
	(offset) cmd += 8;
	goto nextcmd;

cmd0400:
	// relative line & box
	GUIGUI_window_struct *cmd0400_win == DS:ESI;
	int *cmd0400_stack == SS:ESP;
	EDX = cmd[ 8];
	ESP -= 76;
	if (EDX != 0) {
		EAX = 0x003c; // slot_sel
		ECX = stack_sel;
		ES = AX;
		DS = CX;
		(offset) cmd0400_win = (int) [ES:EDX + 8];
	}
	LEA(EAX, cmd0400_stack[68]);
	cmd0400_stack[ 0] = 0x0184; // accesslock
	cmd0400_stack[ 4] = 0; // priority/handle
	cmd0400_stack[ 8] = 0; // opt(lock/bitset)
	cmd0400_stack[28] = EAX;
	EAX = cmd[ 4];
	cmd0400_stack[32] = 0x0100; // line
	cmd0400_stack[36] = EAX;
	EAX = cmd[12];
	ECX = cmd[16];
	if (EDX != 0) {
		EAX += cmd0400_win->x0;
		ECX += cmd0400_win->y0;
	}
	cmd0400_stack[40] = EAX;
	cmd0400_stack[44] = ECX;
	cmd0400_stack[12] = EAX;
	cmd0400_stack[16] = ECX;
	EAX = cmd[20];
	ECX = cmd[24];
	if (EDX != 0) {
		EAX += cmd0400_win->x0;
		ECX += cmd0400_win->y0;
	}
	cmd0400_stack[48] = EAX;
	cmd0400_stack[52] = ECX;
	EAX++;
	ECX++;
	cmd0400_stack[20] = EAX;
	cmd0400_stack[24] = ECX;
	if (EAX < cmd0400_stack[12]) {
		EDX = cmd0400_stack[12];
		cmd0400_stack[12] = EAX;
		cmd0400_stack[20] = EDX;
	}
	if (ECX < cmd0400_stack[16]) {
		EAX = cmd0400_stack[16];
		cmd0400_stack[16] = ECX;
		cmd0400_stack[24] = EAX;
	}
	EAX = cmd[28];
	(offset) cmd += 32;
	cmd0400_stack[56] = EAX;
	cmd0400_stack[60] = 0x0184; // accesslock
	cmd0400_stack[64] = 0; // priority/handle
	cmd0400_stack[68] = 1; // opt(unlock/bitmode)
	cmd0400_stack[72] = 0; // eoc
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	ESP += 76;
	goto nextcmd;

cmd0404:
	// 文字表示
	GUIGUI_window_struct *cmd0404_win == ES:ESI;
	int *cmd0404_stack == SS:ESP + 8;
	PUSH((int) 0x003c); // slot_sel
	PUSH((int) stack_sel);
	ESI = cmd[36]; /* length */
	POP(ES);
	LEA(EAX, [ESI * 4 + 84]);
	POP(DS);
	EDI = ESP;
	ESP -= EAX;
	ECX = 0;
	PUSH((offset) cmd);
	PUSH(EDI); /* old ESP */
	EAX = cmd[ 4];
	cmd0404_stack[ 0] = 0x0184; // accesslock
	cmd0404_stack[ 4] = ECX; // priority/handle
	cmd0404_stack[ 8] = ECX; // opt(lock/bitset)
	cmd0404_stack[32] = 0x0101; // put fonts
	EAX &= 0x03;
	EDX = cmd[ 8];
	cmd0404_stack[36] = EAX; // opt
	EAX = cmd[12];
	ECX = cmd[16];
	if (EDX != 0) {
		PUSH(ESI);
		(offset) cmd0404_win = (int) [DS:EDX + 8];
		EAX += cmd0404_win->x0;
		ECX += cmd0404_win->y0;
		POP(ESI);
	}
	cmd0404_stack[40] = EAX; // x0
	cmd0404_stack[44] = ECX; // y0
	cmd0404_stack[12] = EAX;
	cmd0404_stack[16] = ECX;
	ECX += 16; /* ハーフハイトならこの半分でいいのだが、判定が面倒なので一律16ドット */
	cmd0404_stack[24] = ECX;
	EDX = cmd[20];
	ECX = cmd[24];
	cmd0404_stack[48] = EDX; // color
	cmd0404_stack[52] = ECX; // color
//	cmd0404_stack[56] = 0; // dummy
//	cmd0404_stack[60] = ankfont_sel; // font_sel
	EDI = cmd[28]; /* charset */
//	ESI = cmd[36];
	EDX = cmd[32]; /* base */
	asmout("LES EBX,GS:[EBP+40]");
	LEA(EAX, [EAX + ESI * 8]);
	cmd0404_stack[20] = EAX;
	EAX = cmd[ 4]; /* opt */
	LEA(EBP, cmd0404_stack[68]);
	AH &= 0x30;
	cmd0404_stack[64] = ESI; // length
	if (== 0)
		goto cmd0404_dword;
	if (AH == 0x10)
		goto cmd0404_byte;
	if (AH == 0x20)
		goto cmd0404_word;

cmd0404_qword:
	do {
		/* EBX, EBP, ESI, EDI */
		EAX = (int) [ES:EBX];
		EBX += 8;
		EAX += EDX;
		/* local fontcode を global fontaddr に変換する */
		PUSH(EDX);
		PUSH(EDI);
nextfont2_q:
		EAX -= [DS:EDI + 4 /* base */];
		if ((unsigned) < 0)
			goto nextfont_q;
		if ((unsigned) EAX >= [DS:EDI + 0] /* range */)
			goto nextfont_q;
		ECX = [DS:EDI + 8 /* conv */];
		EDX = ECX;
		ECX &= 0x0f;
		EDX &= 0xfffffff0;
		SHL(EAX, CL);
		POP(EDI);
		EAX += EDX;
		POP(EDX);
		(int) [SS:EBP] = EAX;
		EBP += 4;
		ESI--;
	} while (!= 0);

cmd0404_final:
	(int) [SS:EBP +  0] = 0x0184; // accesslock
	(int) [SS:EBP +  4] = /* 0 */ ESI; // priority/handle
	(int) [SS:EBP +  8] = 1; // opt(unlock/bitmode)
	(int) [SS:EBP + 12] = /* 0 */ ESI; // eoc
	EBP += 8;
	cmd0404_stack[28] = EBP;
	LEA(EBX, [SS:ESP + 8]);
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	POP(EDI);
	POP((offset) cmd);
	ESP = EDI;
	(offset) cmd += 48;
	goto nextcmd;

nextfont_q:
	EAX += [DS:EDI + 4 /* base */];
	EDI += 16;
	goto nextfont2_q;


cmd0404_dword:
	do {
		/* EBX, EBP, ESI, EDI */
		EAX = (int) [ES:EBX];
		EBX += 4;
		EAX += EDX;

		/* local fontcode を global fontaddr に変換する */
		PUSH(EDX);
		PUSH(EDI);
nextfont2_d:
		EAX -= [DS:EDI + 4 /* base */];
		if ((unsigned) < 0)
			goto nextfont_d;
		if ((unsigned) EAX >= [DS:EDI + 0] /* range */)
			goto nextfont_d;
		ECX = [DS:EDI + 8 /* conv */];
		EDX = ECX;
		ECX &= 0x0f;
		EDX &= 0xfffffff0;
		SHL(EAX, CL);
		POP(EDI);
		EAX += EDX;
		POP(EDX);
		(int) [SS:EBP] = EAX;
		EBP += 4;
		ESI--;
	} while (!= 0);
	goto cmd0404_final;

nextfont_d:
	EAX += [DS:EDI + 4 /* base */];
	EDI += 16;
	goto nextfont2_d;

cmd0404_word:
	do {
		/* EBX, EBP, ESI, EDI */
		EAX = (unsigned short) [ES:EBX];
		EBX += 2;
		EAX += EDX;

		/* local fontcode を global fontaddr に変換する */
		PUSH(EDX);
		PUSH(EDI);
nextfont2_w:
		EAX -= [DS:EDI + 4 /* base */];
		if ((unsigned) < 0)
			goto nextfont_w;
		if ((unsigned) EAX >= [DS:EDI + 0] /* range */)
			goto nextfont_w;
		ECX = [DS:EDI + 8 /* conv */];
		EDX = ECX;
		ECX &= 0x0f;
		EDX &= 0xfffffff0;
		SHL(EAX, CL);
		POP(EDI);
		EAX += EDX;
		POP(EDX);
		(int) [SS:EBP] = EAX;
		EBP += 4;
		ESI--;
	} while (!= 0);
	goto cmd0404_final;

nextfont_w:
	EAX += [DS:EDI + 4 /* base */];
	EDI += 16;
	goto nextfont2_w;

cmd0404_byte:
	do {
		/* EBX, EBP, ESI, EDI */
		EAX = (unsigned char) [ES:EBX];
		EBX++;
		EAX += EDX;

		/* local fontcode を global fontaddr に変換する */
		PUSH(EDX);
		PUSH(EDI);
nextfont2_b:
		EAX -= [DS:EDI + 4 /* base */];
		if ((unsigned) < 0)
			goto nextfont_b;
		if ((unsigned) EAX >= [DS:EDI + 0] /* range */)
			goto nextfont_b;
		ECX = [DS:EDI + 8 /* conv */];
		EDX = ECX;
		ECX &= 0x0f;
		EDX &= 0xfffffff0;
		SHL(EAX, CL);
		POP(EDI);
		EAX += EDX;
		POP(EDX);
		(int) [SS:EBP] = EAX;
		EBP += 4;
		ESI--;
	} while (!= 0);
	goto cmd0404_final;

nextfont_b:
	EAX += [DS:EDI + 4 /* base */];
	EDI += 16;
	goto nextfont2_b;

cmd0408:
	/* load font */
    /* cmd, opt(type), slot, len, from */
    /* optのbit31を0x01にすると、カスタムコード(80000000はネーム)。 */
	EAX = 0x003c; /* slot_sel */
	EDX = cmd[8]; /* slot */
	ES = AX;
	EAX = cmd[4]; /* opt */
	if ((signed) EAX > 0) {

		/* アトリビュートを取得して、サイズを確定 */
		ECX = 0;
		PUSH(ECX); /* eoc */
		PUSH(ECX);
		PUSH(ECX);
		PUSH(ECX);
		PUSH(ECX);
		PUSH(EAX); /* type */
		PUSH(ECX);
		PUSH((int) 0x0140 /* get font attr */);
		EBX = ESP;
		DB(0x9a); DD(0); DW((short) GAPI_sel);
		ECX = [SS:ESP + 12]; /* CL == bits/font */
		ESP += 32;
		PUSH(ECX);
		EAX = GAPIwork_sel;
		EBX = cmd[12]; /* len */
		ESI = 0x0c00;
		if (CL == 0x03) {
			EBX++;
			EBX &= 0xfffffffe;
		}
		[ES:EDX +  0] = EBX;

		/* 領域確保 */
		SHL(EBX, CL);
		DS = AX;
		ECX = EBX;
		get_area();
		if (ZF == 1)
			INT(0x03);

		/* 転送コマンド実行 */
		PUSH((int) 0);
		PUSH(cmd[20] /* from (sel) */);
		PUSH(cmd[16] /* from (ofs) */);
		PUSH(EAX /* to */);
		PUSH(cmd[12] /* len */);
		PUSH(cmd[4] /* type */);
		PUSH((int) 0 /* opt */);
		PUSH((int) 0x0104 /* load font */);
		(offset) cmd += 24;
		AL |= [SS:ESP + 32];
		(int) [ES:EDX + 12] = 0x0118; /* alloced font mark */
		[ES:EDX +  4] = EAX;
		EBX = ESP;
		DB(0x9a); DD(0); DW((short) GAPI_sel);
		ESP += 32 + 4;
		goto nextcmd;
	}

	PUSH(EAX);
	EAX &= 0x0fffffff;
	(offset) cmd += 12;

	if (EAX == 0x00ffffff)
		goto skip;
	if (EAX == 0x00000001) {
		/* 8x16dot mono ANK */
		(int) [ES:EDX +  0] = 256 /* max-range */;
		(int) [ES:EDX +  4] = 0x1004; /* conv */
	//	(int) [ES:EDX + 12] = 0x0114; /* overlink font mark */
	} else if (EAX == 0x00000002) {
		/* 8x8dot mono half-ANK */
		(int) [ES:EDX +  0] = 512 /* max-range */;
		(int) [ES:EDX +  4] = 0x1003; /* conv */
	//	(int) [ES:EDX + 12] = 0x0114; /* overlink font mark */
#if 0
	} else if (EAX == 0x00000011) {
		/* 8x16dot mono gg00jpn0 */
		(int) [ES:EDX +  0] = 0x3cf4 /* max-range (15604文字-半角単位) */;
		(int) [ES:EDX +  4] = 0x2004; /* conv */
	//	(int) [ES:EDX + 12] = 0x0114; /* overlink font mark */
	} else if (EAX == 0x00000012) {
		/* 8x8dot mono half-gg00jpn0 */
		(int) [ES:EDX +  0] = 0x79e8 /* max-range (31208文字-半角単位) */;
		(int) [ES:EDX +  4] = 0x2003; /* conv */
	//	(int) [ES:EDX + 12] = 0x0114; /* overlink font mark */
#endif
	} else {
		INT(0x03);
	}
	(int) [ES:EDX + 12] = 0x0114; /* overlink font mark */
skip:
	POP(EAX);
	TEST(EAX, 0x40000000);
	if (== 0)
		goto nextcmd;

	/* winman0にシグナルを送る */
	EBX = tapiwork_sel;
	DS = EBX;
	PUSH((int) 0);
	PUSH(cmd[4]);
	PUSH(cmd[0]);
	PUSH((int) [DS:0x000c] /* tss */);
	PUSH(EAX);
	PUSH((int) 0x0048);
	PUSH((int) 0x7f000005);
	PUSH((int) 0x3240 /* winman0 */ + 6);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	(offset) cmd += 8;
	ESP += 36;
	goto nextcmd;

cmd040c:
	/* free font */
	/* cmd, opt, slot */
	EAX = 0x003c;
	EDX = cmd[8];
	ES = AX;
	(offset) cmd += 12;
	if ((unsigned) (int) [ES:EDX + 12] == 0x0118) {
		EAX = GAPIwork_sel;
		DS = AX;
		ECX = [ES:EDX + 4] /* conv */;
		EBX = [ES:EDX + 0] /* max-range */;
		EAX = ECX;
		ECX &= 0x0f;
		EAX &= 0xfffffff0;
	//	EBX <<= CL;
		SHL(EBX, CL);
		ESI = 0x0c00;
		ECX = EBX;
		free_area();
	}
	(int) [ES:EDX + 12] = 0;
	goto nextcmd;

cmd0410:
	/* make charset */
	/* cmd, opt, slot(charset), slot(font), range, from, to */
	EAX = 0x003c;
	EDX = cmd[ 8]; /* charset */
	ES = AX;
	EBX = cmd[12]; /* font */
	ECX = cmd[16]; /* range */
	TEST(BL, 0x0f);
	if (== 0) {
		[ES:EDX + 0] = ECX;
		if (ECX != 0) {
			EAX = cmd[24]; /* to */
			ESI = cmd[20]; /* from */
			ECX = [ES:EBX + 4]; /* conv */
			[ES:EDX + 4] = EAX;
			EAX = ECX;
			ECX &= 0x0f;
			SHL(ESI, CL);
			EAX += ESI;
			[ES:EDX + 8] = EAX;
		}
		(offset) cmd += 28;
		goto nextcmd;
	}
	if (EBX == 0x0021 /* フルハイト・文字セット01 */) {
		[ES:EDX +  0] = ECX;
		[ES:EDX + 16] = ECX; /* ダミー */
		[ES:EDX + 32] = ECX; /* ダミー */
		[ES:EDX + 48] = ECX; /* ダミー */
		EAX = cmd[24]; /* to */
		ESI = cmd[20]; /* from */ /* これは0であるべき */
		ECX = 0x2004; /* conv */
		[ES:EDX +  4] = EAX;
		[ES:EDX + 20] = EAX;
		[ES:EDX + 36] = EAX;
		[ES:EDX + 52] = EAX;
		EAX = ECX;
	//	ECX &= 0x0f;
	//	SHL(ESI, CL);
	//	EAX += ESI;
		[ES:EDX +  8] = EAX;
	//	[ES:EDX + 24] = EAX;
	//	[ES:EDX + 40] = EAX;
	//	[ES:EDX + 56] = EAX;
		(offset) cmd += 28;
		goto nextcmd;
	}
	if (EBX == 0x0031 /* ハーフハイト・文字セット01 */) {
		[ES:EDX +  0] = ECX;
		[ES:EDX + 16] = ECX; /* ダミー */
		[ES:EDX + 32] = ECX; /* ダミー */
		[ES:EDX + 48] = ECX; /* ダミー */
		EAX = cmd[24]; /* to */
		ESI = cmd[20]; /* from */ /* これは0であるべき */
		ECX = 0x2003; /* conv */
		[ES:EDX +  4] = EAX;
		[ES:EDX + 20] = EAX;
		[ES:EDX + 36] = EAX;
		[ES:EDX + 52] = EAX;
		EAX = ECX;
	//	ECX &= 0x0f;
	//	SHL(ESI, CL);
	//	EAX += ESI;
		[ES:EDX +  8] = EAX;
	//	[ES:EDX + 24] = EAX;
	//	[ES:EDX + 40] = EAX;
	//	[ES:EDX + 56] = EAX;
		(offset) cmd += 28;
		goto nextcmd;
	}

cmd0414:
	/* ブロック転送 */
	/* cmd, opt(1), window, x0, y0, xsize, ysize, yskip, ofs, sel */
	GUIGUI_window_struct *cmd0414_win == DS:ESI;
	int *cmd0414_stack == SS:ESP;
	EAX = 0x003c; // slot_sel
	ECX = stack_sel;
	ES = AX;
	DS = CX;
	PUSH((int) 0);
	PUSH((int) 1); // opt(unlock/bitmode)
	EBX = ESP;
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock

	AL = cmd[ 4];
	TEST(AL, 0x10);
	if (!= 0)
		PUSH(cmd[40]);
	PUSH(cmd[36]);
	PUSH(cmd[32]);
	PUSH(cmd[28]);
	PUSH(cmd[24]);
	PUSH(cmd[20]);
	EDX = cmd[ 8];
	EAX = cmd[12];
	ECX = cmd[16];
	if (EDX != 0) {
		(offset) cmd0414_win = (int) [ES:EDX + 8];
		EAX += cmd0414_win->x0;
		ECX += cmd0414_win->y0;
	}
	PUSH(ECX);
	PUSH(EAX);
	PUSH(cmd[ 4]);
	PUSH((int) 0x0108);

	PUSH(EBX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH((int) 0); // opt(lock/bitset)
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock
	EAX = cmd[20];
	ECX = cmd[24];
	(int) [SS:ESP + 20] += EAX;
	(int) [SS:ESP + 24] += ECX;

	EBX = ESP;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	DL = cmd[ 4];
	TEST(DL, 0x10);
	if (!= 0) {
		(offset) cmd += 4;
		POP(EAX);
	}
	(offset) cmd += 40;
	ESP += 84;
	goto nextcmd;

cmd0418:
	// linear dots
	/* cmd, opt, window, x0, y0, xsize, ysize, lines, ofs, sel */
	GUIGUI_window_struct *cmd0418_win == DS:ESI;
	EAX = 0x003c; // slot_sel
	ECX = stack_sel;
	ES = AX;
	DS = CX;
	PUSH((int) 0);
	PUSH((int) 1); // opt(unlock/bitmode)
	EBX = ESP;
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock

	PUSH(cmd[36]); /* sel */
	PUSH(cmd[32]); /* ofs */
	PUSH(cmd[28]); /* lines */
	PUSH(cmd[24]); /* ysize */
	PUSH(cmd[20]); /* xsize */
	EDX = cmd[ 8]; /* win */
	EAX = cmd[12]; /* x0 */
	ECX = cmd[16]; /* y0 */
	if (EDX != 0) {
		(offset) cmd0418_win = (int) [ES:EDX + 8];
		EAX += cmd0418_win->x0;
		ECX += cmd0418_win->y0;
	}
	PUSH(ECX);
	PUSH(EAX);
	PUSH(cmd[ 4]);
	PUSH((int) 0x010c);

	PUSH(EBX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH((int) 0); // opt(lock/bitset)
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock
	EAX = cmd[20];
	ECX = cmd[24];
	(offset) cmd += 40;
	(int) [SS:ESP + 20] += EAX;
	(int) [SS:ESP + 24] += ECX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	ESP += 84;
	goto nextcmd;

cmd041c:
	// points
	/* cmd, opt, window, x0, y0, xsize, ysize, lines, ofs, sel */
	GUIGUI_window_struct *cmd041c_win == DS:ESI;
	PUSH((int) 0x003c); // slot_sel
	PUSH((int) stack_sel);
	POP(DS); /* == stack_sel */
	POP(ES); /* == 0x003c */
	PUSH((int) 0);
	PUSH((int) 1); // opt(unlock/bitmode)
	EBX = ESP;
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock

	PUSH(cmd[36]); /* sel */
	PUSH(cmd[32]); /* ofs */
	PUSH(cmd[28]); /* lines */
	PUSH(cmd[24]); /* ysize */
	PUSH(cmd[20]); /* xsize */
	EDX = cmd[ 8]; /* win */
	EAX = cmd[12]; /* x0 */
	ECX = cmd[16]; /* y0 */
	if (EDX != 0) {
		(offset) cmd041c_win = (int) [ES:EDX + 8];
		EAX += cmd041c_win->x0;
		ECX += cmd041c_win->y0;
	}
	PUSH(ECX);
	PUSH(EAX);
	PUSH(cmd[ 4]);
	PUSH((int) 0x0110);

	PUSH(EBX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH(ECX);
	PUSH(EAX);
	PUSH((int) 0); // opt(lock/bitset)
	PUSH((int) 0); // priority/handle
	PUSH((int) 0x0184); // accesslock
	EAX = cmd[20];
	ECX = cmd[24];
	(offset) cmd += 40;
	(int) [SS:ESP + 20] += EAX;
	(int) [SS:ESP + 24] += ECX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	ESP += 84;
	goto nextcmd;

cmd0510:
	// define signal
	// cmd, opt, default[12](dev, code, win), msgbox, len, signal[8], far *purpose
	// 16 * 256 = 4KB(最大3dw)
//	PUSH(SS);
	PUSH((int) 0x003c /* slot_sel */);
	EDX = cmd[16]; // win slot
	POP(DS); /* == 0x003c */
//	POP(DS); /* == SS */
	EAX = (int) [DS:EDX + 8]; // win

	// ウィンドウ連動デバイス指定(to winman0)
	PUSH((int) 0);
	PUSH(cmd[32]); // signal
	PUSH(cmd[28]); // signal
	PUSH(cmd[24]); // len
	PUSH(cmd[12]); // code
	PUSH(cmd[ 8]); // device
	PUSH((int) 0 /* signalbox...0ならwindowと同じ */);
	PUSH(EAX);
	PUSH(cmd[ 4]); // opt(bit31が0だと、purposeはなし)
	PUSH((int) 0x002c); // signal設定
	PUSH((int) 0x7f000009);
	PUSH((int) 0x3240 + 10);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 52;
	(offset) cmd += 44;
	goto nextcmd;

cmd0600:
	// サウンド初期化(トラックオープンコマンド送信)
	// opt(track-no), reserve
	// track-noはslotにする
	PUSH((int) 0x003c); // slot_sel
	EDX = cmd[4];
	POP(DS);
	TEST(DL, 0x01);
	if (== 0) {
		PUSH((int) tapiwork_sel);
		(int) [DS:EDX + 12] = 0x0110; /* sound track mark */
		POP(ES);
		PUSH((int) 0); // eoc
		PUSH((int) 0); // reserve1
		PUSH(cmd[8]); // reserve0
		PUSH((int) 0x00c0); // signal-base
		PUSH((int) [ES:0x000c]); // tss
		PUSH(EDX); // slot
		PUSH((int) 0x0040); // command(open sound track)
		PUSH((int) 0x7f000006);
		PUSH((int) 0x3240 /* winman0 */ + 7);
		PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
		EBX = ESP;
		CALLFAR0(tapi_sel);
		ESP += 40;

		// ここで出したシグナルの返答をpioneer0に処理させるのは、
		// 概念上、大きな問題である。しかし、ぐいぐい01まで改正できない。...いや、システムシグナルで改正できる
	
		(offset) cmd += 12;
		goto nextcmd;
	}
	EDX &= 0xfffffff0; // pioneer0経由で受け取ったwinman0からのシグナル
	EAX = cmd[8];
	(offset) cmd += 12;
	ECX = 0;
	(int) [DS:EDX + 8] = EAX; // bit0は、0(disable)
	(int) [DS:EDX + 0] = ECX; // 無音
	(int) [DS:EDX + 4] = ECX; // 無音
	goto nextcmd;

cmd0604:
	// サウンド終了(close sound)
	// opt(track-no)
	PUSH((int) 0x003c); // slot_sel
	EDX = cmd[4];
	POP(DS);
	EDX = [DS:EDX + 8]; /* system-ID */
	TEST(DL, 0x01);
	if (!= 0) { /* 使用中だったら、消音する */
		PUSHFD();
		CLI();
		#if (defined(PCAT))
			IN(AL, 0x0061);
			AL &= 0x0d;
			AL |= 0x01;
			OUT(0x0061, AL);
		#endif
		#if (defined(TOWNS))
			IN(AL, 0x0060);
			AL >>= 2;
			AL &= 0x03;
			OUT(0x0060, AL);
		#endif
		POPFD();
	}
	EDX &= 0xffffffe;
	PUSH((int) 0);
	PUSH(EDX); // slot
	PUSH((int) 0x0044); // command(close sound track)
	PUSH((int) 0x7f000002);
	PUSH((int) 0x3240 /* winman0 */ + 3);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 24;
	goto nextcmd;

cmd0608:
	// enable/disable sound track
	// opt(track-no) : bit0 は enbale-bit
	// track-noはslotにする
	PUSH((int) 0x003c); // slot_sel
	EDX = cmd[4];
	(offset) cmd += 8;
	POP(DS);
	ECX = EDX;
	EDX &= 0xfffffff0;
	CL &= 0x01;
	if (!= 0) {
		(char) [DS:EDX + 8] |= 0x01;
		EAX = [DS:EDX + 0];
		goto cmd0608_enable;
	}
	INT(0x03); // 無音にして、disable受理を伝える

//	goto nextcmd;

cmd060c:
	/* 周期指定(0:で消音) */
	/* 2e-32sec単位 */
	/* 440.000014Hz (9761289) O4A */
	/* opt(track-no), time */
	PUSH((int) 0x003c); /* slot_sel */
	EDX = cmd[4];
	POP(DS);
	EAX = cmd[8];
	CL = [DS:EDX + 8];
	(offset) cmd += 12;
	TEST(CL, 0x01);
	[DS:EDX + 0] = EAX;
	if (!= 0) {
cmd0608_enable:
		if (EAX == 0) {
			PUSHFD();
			CLI();
			#if (defined(PCAT))
				IN(AL, 0x0061);
				AL &= 0x0d;
				AL |= 0x01;
			//	AL &= 0x0e;
			//	AL |= 0x02;
				OUT(0x0061, AL);
			#endif
			#if (defined(TOWNS))
				IN(AL, 0x0060);
				AL >>= 2;
				AL &= 0x03;
				OUT(0x0060, AL);
			#endif
			POPFD();
			goto nextcmd;
		}
		/* 音を出す */
		#if (defined(PCAT))
			ECX = 1193180;
		#endif
		#if (defined(TOWNS))
			ECX = 307200;
		#endif
		MUL(ECX);
		(unsigned int) EAX >>= 31; /* EAXのMSBをLSBへ */
	//	ECX = EAX + EDX;
		LEA(ECX, [EAX + EDX]);
		if ((unsigned) ECX >= 0x10000)
			ECX = 0; // 18.201Hz
		PUSHFD();
		CLI();
		#if (defined(PCAT))
			AL = 0xb6 /* 10110110B */;
			OUT(0x0043, AL);
			AL = CL;
			OUT(0x0042, AL);
			AL = CH;
			OUT(0x0042, AL);
			NOP();
			IN(AL, 0x0061);
			AL &= 0x0f;
			AL |= 0x03;
			OUT(0x0061, AL);
		#endif
		#if (defined(TOWNS))
			AL = 0xb6 /* 10110110B */;
			OUT(0x0046, AL);
			AL = CL;
			OUT(0x0044, AL);
			AL = CH;
			OUT(0x0044, AL);
			NOP();
			IN(AL, 0x0060);
			AL >>= 2;
			AL &= 0x07;
			AL |= 0x04;
			OUT(0x0060, AL);
		#endif
		POPFD();
	}
	goto nextcmd;

cmd0700:
	/* ファイルハンドル初期化 */
	/* cmd, opt, slot */
	PUSH((int) 0x003c); /* slot_sel */
	PUSH((int) tapiwork_sel);
	POP(DS);
	POP(ES);
	EAX = cmd[4];
	EDX = cmd[8]; /* slot */
	(offset) cmd += 12;
	if (EAX == 4 /* タスクディレクトリ */) {
		ESI = [DS:0x000c /* tskptr */];
		int *cmd0700_tss_sysdat == DS:ESI + 748; /* 20バイト */
		EAX = cmd0700_tss_sysdat[0]; /* tskdir */
		[ES:EDX + 0] = EAX;
		goto nextcmd;
	}
	if (EAX == 12 /* マシンディレクトリ */) {
cmd0700_machine:
		EAX = 0;
		EAX--;
		[ES:EDX + 0] = EAX;
		goto nextcmd;
	}
	if (EAX == 8 /* ユーザーディレクトリ */)
		goto cmd0700_machine;
	if (EAX == 64 /* ルート(仮) */) {
		(int) [ES:EDX + 0] = 1024;
		goto nextcmd;
	}
	if ((unsigned) EAX >= 0x00e0 /* ダイアログ等を出して選択させる */) {
		/* サブコマンドが継続している */
		/* サブコマンドには、細かい属性が書かれている */
		/* 完了すると、シグナルが来る */
		/* pokon0にシグナルを送る */
		/* 0x7f000006, sig, task, slot, bytes, ofs, sel */
		PUSH((int) 0);
		PUSH(cmd[8] /* sel */);
		PUSH(cmd[4] /* ofs */);
		PUSH(cmd[0] /* bytes */);
		PUSH(EDX /* slot */);
		PUSH((int) [DS:0x000c /* tskptr */]);
		PUSH((int) 0x0084 /* fileselect */);
		PUSH((int) 0x7f000006);
		PUSH((int) 0x4240 /* pokon0 */ + 7);
		PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
		(offset) cmd += 12;
		EBX = ESP;
		CALLFAR0(tapi_sel);
		ESP += 40;
		goto nextcmd;
	}
	INT(0x03);

cmd0708:
	/* コピーハンドル */
	/* cmd, opt, slot(dest), slot(src) */
	PUSH((int) 0x003c); /* slot_sel */
	POP(DS);
	ECX = cmd[12];
	EDX = cmd[ 8]; /* slot */
	(offset) cmd += 16;
	EAX = [DS:ECX + 0];
	[DS:EDX + 0] = EAX;
	goto nextcmd;

cmd070c:
	/* ディレクトリ移動 */
	/* cmd, opt, slot, bytes, ofs, sel */
	/* 完了した場合も見付からない場合も、シグナルで知らせる */

	PUSH((int) tapiwork_sel);
	POP(DS);

	/* 0x7f000006, sig, task, slot, bytes, ofs, sel */
	PUSH((int) 0);
	PUSH(cmd[20] /* sel */);
	PUSH(cmd[16] /* ofs */);
	PUSH(cmd[12] /* bytes */);
	PUSH(cmd[ 8] /* slot */);
	PUSH((int) [DS:0x000c /* tskptr */]);
	PUSH((int) 0x0088 /* steppath */);
	PUSH((int) 0x7f000006);
	PUSH((int) 0x4240 /* pokon0 */ + 7);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	(offset) cmd += 24;
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 40;
	goto nextcmd;

#if 0

cmd070c:
	/* ディレクトリ移動 */
	/* cmd, opt, slot, tag0, tag1, ..., -1 */
	/* 見付からない場合、optのbit0が1なら、bit0がクリアされる
		optのbit0が最初から0だったら、エラー */
	EAX = 0x003c; /* slot_sel */
	ECX = root_sel;
	EDX = cmd[8];
	ES = AX;
	DS = CX;
	ESI = [ES:EDX + 0];
	PUSH(EDX);
	EAX = 0xffe00040;
	ESI += 16;
	search_tag_EAX();
	EBX = [DS:ESI + 16];
	EBX += 16;
	ESI = [DS:EBX];
	(offset) cmd += 12;
	if (ESI != 0xffffffff) {
		PUSH((offset) cmd);
		do {
			ESI += 16;
			(offset) cmd = [SS:ESP];
			PUSH(ESI);
			EAX = cmd[0];
			do {
				ESI = [SS:ESP];
				search_tag_EAX();
				ECX = cmd[4];
				if (ZF == 0) /* そのタグすら見付からない */
					goto cmd070c_next;
				if (ECX != [DS:ESI + 4])
					goto cmd070c_next; /* 長さが違う */
				(offset) cmd += 8;
				ESI += 8;
				ECX -= 8;
				if (!= 0) {
					do {
						EAX = *cmd;
						cmd += 4;
						if (EAX != [DS:ESI])
							goto cmd070c_next;
						ESI += 4;
						ECX -= 4;
					} while (!= 0);
				}
				EAX = cmd[0];
			} while (EAX != 0xffffffff);

			/* 見つけた */
			EAX = [DS:EBX];
			POP(ESI); /* ESP += 4;の代わり */
			POP(EBX /* old cmd + 12 */);
			POP(EDX);
			(offset) cmd += 4;
			asmout("TEST BYTE PTR GS:[EBX-8],02H");
			if (!= 0)
				goto nextcmd;
			[ES:EDX + 0] = EAX;
			goto nextcmd;

cmd070c_next:
			EBX += 4;
			POP(EAX); /* old ESI */
			ESI = [DS:EBX];
		} while (ESI != 0xffffffff);
	}
	/* 見付からなかった */
	POP((offset) cmd) /* old cmd + 12 */;
	EAX = cmd[-8];
	POP(ECX); /* old EDX */
	TEST(AL, 0x01);
	if (== 0) {
		INT(0x03); /* 見付からなかった */
	}
	EAX &= 0xfffffffe;
	cmd[-8] = EAX;
	do {
		(offset) cmd += cmd[4];
	} while (cmd[0] != 0xffffffff);
	(offset) cmd += 4;
	goto nextcmd;

#endif

cmd0710:
	/* create new module */
	/* cmd, opt, slot(dir), slot(module), tag-dir alloc-size, tag0, tag1, ..., -1 */
	ESP -= 512;
	PUSH((int) 0x003c); /* slot_sel */
	POP(ES);
	EAX = cmd[ 8]; /* slot(dir) */
	ECX = cmd[12]; /* slot(module) */
	EDX = cmd[16]; /* tagdir allocsize */
	TEST(ECX, ECX);
	EAX = [ES:EAX + 0];
	[SS:ESP + 496] = EAX;
	AX = GS;
	[SS:ESP + 500] = ECX;
	[SS:ESP + 504] = EDX;
	[SS:ESP + 508] = EAX;
	DS = AX;
	LEA(ESI, [SS:EBP + 20]);
	EBP = ESP;
	EAX = [DS:ESI];
	do {
		ECX = [DS:ESI + 4];
		[SS:EBP] = EAX;
		[SS:EBP + 4] = ECX;
		if (EAX == 0xffe00003)
			goto cmd0710_ffe00003;
		ESI += 8;
		EBP += 8;
		ECX -= 8;
		if (!= 0) {
			do {
				EAX = [DS:ESI];
				ESI += 4;
				[SS:EBP] = EAX;
				EBP += 4;
				ECX -= 4;
			} while (!= 0);
		}
cmd0710_next:
		EAX = [DS:ESI];
	} while (EAX != 0xffffffff);
	PUSH((int) root_sel);
	[SS:EBP] = EAX;
	POP(DS);
	[SS:EBP + 4] = EAX;
	ECX = [SS:ESP + 504];
	LEA(EBP, [ESI + 4]);
	ESI = 512;
	alloc_tagdir();
	EBX = ESP;
	PUSH(SS);
	POP(GS);
	add_tags();
	GS = [SS:ESP + 508];
	EDX = [SS:ESP + 500];
	EBX = [SS:ESP + 496];
	if (EDX != 0)
		[ES:EDX + 0] = EDI;
	regist_module();
	ESP += 512;
	goto nextcmd;

cmd0710_ffe00003:
	ECX = [DS:ESI + 16]; /* allocsize */
	get_memory(); /* EAXを返す */
	if (ZF == 1)
		INT(0x03);
	[SS:EBP + 16] = ECX;
	[SS:EBP + 24] = EAX;
	EAX = [DS:ESI +  8]; /* usedsize */
	ESI += 32;
	[SS:EBP +  8] = EAX;
	EBP += 32;
	goto cmd0710_next;

cmd0720:
	/* map module */
	PUSH((int) tapiwork_sel);
	ECX = cmd[20]; /* opt(sel) */
	POP(DS);
	ECX &= 0x0000fff8;
	ESI = [DS:0x000c] /* tskptr */;
	EAX = cmd[8]; /* slot */
	int *cmd0710_tss_ldt == DS:ESI + 2048;
	asmout("LEA ECX,[ECX+ESI+2048]");
	DL = [DS:ECX + 4];
	DH = [DS:ECX + 7];
	EDX <<= 16;
	DX = [DS:ECX + 2];
	PUSH((int) 0x003c /* slot_sel */);
	POP(DS);
	ESI = [DS:EAX + 0];
	PUSH((int) root_sel);
	ESI += 16;
	POP(DS);
	EAX = 0xffe00003;
	search_tag_EAX();
	EAX = [DS:ESI + 24 /* 先頭物理アドレス */];
	EDI = [DS:ESI + 28];

//	[DS:ESI + 16 /* モジュールサイズ */];
	EAX += cmd[24] /* ofs & attr */;
	ADC(EDI, 0);
	EDX += cmd[16] /* linear addr ofs */;
	ECX = EAX;
	EAX &= 0xfffff000;
	ECX &= 0x00001fff;
	ECX |= 0x00001000;

	EBX = 0;
//	if (EBX != [DS:ESI + 16] /* モジュールサイズ */) {
		PUSH((int) EBX /* eoc */);
		PUSH((int) EDI /* addr64(high) */);
		PUSH((int) EAX /* addr64(low) */);
		PUSH((int) EBX /* offset64(high) */);
		PUSH((int) EBX /* offset64(low) */);
		PUSH((int) EBX /* pageset */);
		PUSH((int) EDX /* linear */);

EDI = cmd[24]; /* ofs */
EAX = cmd[12];
EDI &= 0xfffff000;
EBX = [DS:ESI + 16 /* モジュールサイズ */];
EBX -= EDI;
if ((unsigned) < 0)
	EBX = 0;
if ((unsigned) EAX > EBX)
	EAX = EBX;
EAX += 0xfff;
EAX &= 0xfffff000;
if (== 0) {
	ESP += 28;
	(offset) cmd += 28;
	goto nextcmd;
}
PUSH(EAX);

	//	PUSH((int) cmd[12] /* size */);
		PUSH((int) ECX /* opt(over-mapping, present, R/W, user) */);
		PUSH((int) 0x0108 /* cmd(mapping) */);
		EBX = ESP;
		CALLFAR0(papi_sel);
		ESP += 40;
//	}

	(offset) cmd += 28;
	goto nextcmd;

cmd0728:
	/* read tag */
	/* cmd, opt, slot(not dir), bufsize, bufptr(far) */
	/* optが 0xffffff00より大きければ、カスタムフォーマット */
	/* 02:モジュールタイプコード(8バイト)のみ */
	/* 03:モジュールサイズ(16バイト)のみ */
	EAX = 0x003c; /* slot_sel */
	ECX = root_sel;
	EDX = cmd[8];
	EBX = cmd[4];
	ES = AX;
	DS = CX;
	ESI = [ES:EDX + 0];
	asmout("LES EDI,FWORD PTR GS:[EBP+16]");
	ESI += 16;
	(offset) cmd += 24;
	if (EBX == 0xffffff03) {
		EAX = 0xffe00003;
		search_tag_EAX();
		if (ZF == 0)
			INT(0x03);
		EAX = [DS:ESI +  8];
		ECX = [DS:ESI + 12];
		EDX = [DS:ESI + 16];
		EBX = [DS:ESI + 20];
		[ES:EDI +  0] = EAX;
		[ES:EDI +  4] = ECX;
		[ES:EDI +  8] = EDX;
		[ES:EDI + 12] = EBX;
		goto nextcmd;
	}
	if (EBX == 0xffffff02) {
		EAX = 0xffe00002;
		search_tag_EAX();
		if (ZF == 0)
			INT(0x03);
		EAX = [DS:ESI +  8];
		ECX = [DS:ESI + 12];
		[ES:EDI +  0] = EAX;
		[ES:EDI +  4] = ECX;
		goto nextcmd;
	}
	INT(0x03);

cmd0730:
	/* tag listing */
	/* cmd, opt, slot(dir), bufsize, bufptr(far) */
	/* optが 0xffffff00より大きければ、カスタムフォーマット */
	/* 00:モジュールネームのみ */
	EAX = 0x003c; /* slot_sel */
	ECX = root_sel;
	EDX = cmd[8];
	ES = AX;
	DS = CX;
	ESI = [ES:EDX + 0];
	EAX = 0xffe00040;
	ESI += 16;
	search_tag_EAX();
	EBX = [DS:ESI + 16];
	EBX += 16;
	ESI = [DS:EBX];
	asmout("LES EDI,FWORD PTR GS:[EBP+16]");
	(offset) cmd += 24;
	if (ESI != 0xffffffff) {
		do {
			EBX += 4;
			ESI += 16;
			EAX = 0xffe00000 /* name */;
			search_tag_EAX();
			ECX = [DS:ESI + 4];
			if (ZF == 0) /* そのタグすら見付からない */
				INT(0x03);
			ECX -= 4;
			ESI += 8;
			[ES:EDI] = ECX;
			EDI += 4;
			ECX -= 4;
			if (!= 0) {
				do {
					EAX = [DS:ESI];
					ESI += 4;
					[ES:EDI] = EAX;
					EDI += 4;
					ECX -= 4;
				} while ((unsigned) > 0);
			}
			ESI = [DS:EBX];
		} while (ESI != 0xffffffff);
	}
	(int) [ES:EDI] = 0;
	goto nextcmd;

cmd0740:
	/* resize file */
	/* cmd, opt, slot, new-size(bytes), siglen(1), sig */

	PUSH((int) tapiwork_sel);
	POP(DS);
	EDX = cmd[ 8];

	/* 0x7f000006, cmd, virtualmodule, new-size, task, sig, slot */
	PUSH((int) 0);
	PUSH(EDX);
	PUSH(cmd[20] /* sig */);
	PUSH((int) [DS:0x000c /* tskptr */]);

	PUSH((int) 0x003c /* slot_sel */);
	POP(DS);

	PUSH(cmd[12] /* new-size */);
	PUSH((int) [DS:EDX]);
	PUSH((int) 0x008d);
	PUSH((int) 0x7f000006);
	PUSH((int) 0x4240 /* pokon0 */ + 7);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */);
	(offset) cmd += 24;
	EBX = ESP;
	CALLFAR0(tapi_sel);
	ESP += 40;
	goto nextcmd;


cmd0ffffffff:
	// magic command

	ESP -= 512;
	(int) [SS:ESP     ] = 0x0101;
	EAX = cmd[ 4];
	EAX *= 16;
	EAX += 4096;
	(int) [SS:ESP +  4] = 0;
	(int) [SS:ESP +  8] = 0;
	(int) [SS:ESP + 12] = 0;
	(int) [SS:ESP + 16] = 15;
	(int) [SS:ESP + 20] = 0;
	(int) [SS:ESP + 24] = 0;
//	(int) [SS:ESP + 28] = ankfont_sel;
	(int) [SS:ESP + 32] = 1;
	(int) [SS:ESP + 36] = EAX;
	(int) [SS:ESP + 40] = 0x0000;

	EBX = ESP;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	ESP += 512;

#if 0
	/*	システムタイマーノードの状況確認 */
	EAX = 0x003c; /* slot_sel */
	DS = AX;
	ECX = (int) [DS:0x01c0];
	EAX = timerdata_sel;
	DS = AX;
	EAX = (int) [DS:ECX + 56];
	INT(0x03);
#endif

	(offset) cmd += 20;
	goto nextcmd;
}

void far GUIGUI_shellcall2()
{
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int GAPI_sel     ==  4 * 8, GAPIwork_sel  ==  5 * 8;
	unsigned int stack_sel    ==  6 * 8, ankfont_sel   ==  7 * 8;
	unsigned int keyint_sel   ==  8 * 8, keydata_sel   ==  9 * 8;
	unsigned int timerint_sel == 10 * 8, timerdata_sel == 11 * 8;
	unsigned int tapi_sel     == 12 * 8, tapiwork_sel  == 13 * 8;
	unsigned int tss386_0_sel == 14 * 8, idtgdt_sel    == 15 * 8;
	unsigned int root_sel     == 16 * 8, tmp_sel       == 17 * 8;
	unsigned int papi_sel     == 18 * 8, papiwork_sel  == 19 * 8;
	unsigned int decode_sel   == 22 * 8, decowork_sel  == 23 * 8;
	unsigned int fdcdrive_sel == 28 * 8, fdcwork_sel   == 29 * 8;
	unsigned int diskbuf_sel  == 30 * 8, textbuf_sel   == 31 * 8;
	unsigned int freegdt_sel  == 32 * 8;
	unsigned int bootseg_ent   ==  8 * 16, stack000_ent ==  9 * 16;

	int *cmd == FS:EBX;

	/* lv3からの進入の可能性があるので、カウントを増やす。 */
	(char) [SS:0xffffffe0]++;

	PUSH(DS);
	PUSH(ES);
	PUSHAD();

nextcmd:
	EAX = cmd[0];
	if (EAX == 0)
		goto cmd0000;
	if (EAX == 0x0010)
		goto cmd0010; /* システムオープン */
	if (EAX == 0x0020)
		goto cmd0020; /* send signal */
	if (EAX == 0x0028)
		goto cmd0028; /* get window param(暫定コマンド) */
	if (EAX == 0x002c)
		goto cmd002c; /* put window param(暫定コマンド) */
//	if (EAX == 0x0030)
//		goto cmd0030; /* define signal direct */
	if (EAX == 0x0034)
		goto cmd0034; /* report memory status */
	if (EAX == 0x0040)
		goto cmd0040; /* ファイルリストの転送：削除されたものは送らない */
	if (EAX == 0x0050)
		goto cmd0050; /* GAPIへのダイレクトコマンド */
	if (EAX == 0x0054)
		goto cmd0054; /* setvideomode */
	if (EAX == 0x0060)
		goto cmd0060; /* keymosへのダイレクトコマンド */
	if (EAX == 0x0064)
		goto cmd0064; /* timerへのダイレクトコマンド */
	if (EAX == 0x0068)
		goto cmd0068; /* decodeへのダイレクトコマンド */
	if (EAX == 0x006c)
		goto cmd006c; /* TAPIへのダイレクトコマンド */
	if (EAX == 0x0070)
		goto cmd0070; /* 仮想モジュール生成 */
	if (EAX == 0x0074)
		goto cmd0074; /* 仮想モジュール削除 */
	if (EAX == 0x0078)
		goto cmd0078; /* 他タスク書き込み */
	if (EAX == 0x007c)
		goto cmd007c; /* gapidataのハンドル取得 */
	if (EAX == 0x0080)
		goto cmd0080; /* slotを使わないmapping */
	if (EAX == 0x0084)
		goto cmd0084; /* メモリ獲得 */
	if (EAX == 0x8010)
		goto cmd8010;
	INT(0x03);

cmd0000:
	EDI = (int) [SS:ESP +  0];
	ESI = (int) [SS:ESP +  4];
	EBP = (int) [SS:ESP +  8];
	EDX = (int) [SS:ESP + 20];
	ECX = (int) [SS:ESP + 24];
	EAX = (int) [SS:ESP + 28];
	ES = (short) [SS:ESP + 32];
	DS = (short) [SS:ESP + 36];
	ESP += 40;
dec_lv0cnt_ret:
	CLI();
	(char) [SS:0xffffffe0]--;
	if (!= 0) {
		STI();
		return; // CF = 0, ZF = 0
	}
	TEST(ESP, ESP); // ZF = 0
	PUSHFD();
	(int) [SS:ESP] |= 0x0200; // IF = 1, ZF == 0
	asmout("jmp_system_count0");

cmd0010:
	// システムオープン
	// とりあえず、なにもしない
	// パラメーター３dw
	(offset) cmd += 16;
	goto nextcmd;

cmd0020:
	// send signal
	// cmd, opt(length), data...
	// optの最上位bitを1にすると、dataをそのまま出力
	(offset) cmd += 8;
	PUSH((int) 0);
	PUSH(FS);
	PUSH((offset) cmd);
	PUSH((int) 0x0118 /* コマンドシグナル間接 */);
	AX = SS;
	EBX = ESP;
	FS = AX;
	CALLFAR0(tapi_sel);
//	asmout("LFS EBX,FWORD PTR SS:[ESP+4]");
	LFS(EBX, [SS:ESP + 4]);
	ESP += 16;
	ECX = cmd[-4];
	ECX &= 0x0f;
	LEA(EBX, [EBX + ECX * 4]);
	goto nextcmd;

cmd0028:
	// get window param(暫定コマンド)
	// cmd, opt, winhandle, offset, selector
	GUIGUI_window_struct *cmd0028_win == ES:EDX;
	EAX = stack_sel;
	(offset) cmd0028_win = cmd[8]; // winhandle
	ES = AX;
//	DS:ESI = cmd[12];
	LDS(ESI, [FS:EBX + 12]);
	ECX = 8;
	do {
		EAX = [ES:EDX];
		EDX += 4;
		[DS:ESI] = EAX;
		ESI += 4;
		ECX--;
	} while (!= 0);
	(offset) cmd += 20;
	goto nextcmd;

cmd002c:
	// put window param(暫定コマンド)
	// cmd, opt, winhandle, offset, selector

	GUIGUI_window_struct *cmd002c_win == ES:EDX;
	EAX = stack_sel;
	(offset) cmd002c_win = cmd[8]; // winhandle
	ES = AX;
//	DS:ESI = cmd[12];
	LDS(ESI, [FS:EBX + 12]);
	ECX = 8;
	do {
		EAX = [DS:ESI];
		ESI += 4;
		[ES:EDX] = EAX;
		EDX += 4;
		ECX--;
	} while (!= 0);
	(offset) cmd += 20;
	goto nextcmd;

cmd0034:
	/* report memory status */
	/*	+04 : opt
		+08 : mem20(all, free, max, blocks)
		+18 : mem24(all, free, max, blocks)
		+28 : mem32(all, free, max, blocks) */
	ECX = 0;
	PUSH((int) ECX);
	ESP -= 16 * 3;
	PUSH((int) 0x800000ff);
	PUSH(ECX);
	PUSH(ECX);
	PUSH((int) 0x0114);
	PUSH(FS);
	PUSH((offset) cmd);
	LEA(EBX, [SS:ESP + 8]);
	PUSH(SS);
	POP(FS);
	CALLFAR0(papi_sel);
	POP((offset) cmd);
	POP(FS);
	(offset) cmd += 8;
	ESP += 16;
//	ECX = 4 * 3;
	ECX += 4 * 3;
	do {
		POP(*cmd);
		(offset) cmd += 4;
		ECX--;
	} while (!= 0);
	POP(EAX);
	goto nextcmd;

cmd0040:
	/* ファイルリストの転送：削除されたものは送らない */
	ECX = cmd[4];
	PUSH((int) all_sel);
	ECX -= 2; // 最初の1つはリザーブ、最後の一つはNULL専用
	LES(EDI, [FS:EBX + 8]);
	POP(DS);
	#if (defined(PCAT))
		ESI = 0x102600;
	#endif
	#if (defined(TOWNS))
		ESI = 0x101400;
	#endif
	(offset) cmd += 32;
	EDI += 16;
	do {
		EAX = [DS:ESI + 0];
		#if (defined(PCAT))
			if (ESI == 0x104200)
				break;
		#endif
		#if (defined(TOWNS))
			if (ESI == 0x102c00)
				break;
		#endif
		if (AL == 0)
			break;
		if (AL == 0xe5) {
			ESI += 32;
				continue;
		}
		EDX = [DS:ESI + 4];
		[ES:EDI +  0] = ESI;
		[ES:EDI +  4] = EAX;
		EAX = [DS:ESI + 8];
		[ES:EDI +  8] = EDX;
		[ES:EDI + 12] = EAX;
		ESI += 32;
		EDI += 16;
		ECX--;
	} while (!= 0);
	EAX = 0;
	[ES:EDI +  0] = EAX;
	[ES:EDI +  4] = EAX;
	[ES:EDI +  8] = EAX;
	[ES:EDI + 12] = EAX;
	goto nextcmd;

cmd0050:
	// GAPIへのダイレクトコマンド
	PUSH((offset) cmd);
	(offset) cmd += 8;
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	POP((offset) cmd);
	(offset) cmd += cmd[4];
	goto nextcmd;

cmd0054:
	// setvideomode
	// opt, mode, sig0(送り先と長さ), sig1, sig2
	#if (defined(PCAT))
		EAX = syswork_sel;
		ECX = stack_sel;
		DS = AX;
		ES = CX;
		GUIGUI_work *cmd0054_work == ES:0xffffd000;
		TAPI_TSS *cmd0054_tss == DS:ESI;
		EAX = tapiwork_sel;
		ECX = (int) [DS:32 + bootseg_ent  + 12];
		EDX = (int) [DS:32 + stack000_ent + 12];
		DS = AX;
		(offset) cmd0054_tss = 0x5000 /* cmd0054_work->tasklist[128].tskptr */;
		asmout("MOV DWORD PTR DS:[ESI+32],OFFSET V86TaskEntry");
		(unsigned int) ECX >>= 4; // bootseg_ent
		(unsigned int) EDX >>= 4; // stack000_ent
		(int) cmd0054_tss->tss386.SS = EDX;
		(int) cmd0054_tss->tss386.CS = ECX;
		EAX = cmd[8]; // mode
		cmd0054_tss->tss386.EFLAGS = 0x00020202; /* STI&VM=1 */
		if (AH == 0)
			cmd0054_tss->tss386.EAX = EAX;
		else {
			cmd0054_tss->tss386.EAX = 0x4f02;
			cmd0054_tss->tss386.EBX = EAX;
		}

		// signalをstack_sel(== ES)に保存
		cmd0054_work->setvideomode_mode = EAX;
		EAX = cmd[12];
		ECX = cmd[16];
		EDX = cmd[20];
		cmd0054_work->setvideomode_sig[0] = EAX;
		cmd0054_work->setvideomode_sig[4] = ECX;
		cmd0054_work->setvideomode_sig[8] = EDX;

		(offset) cmd += 24;

		PUSH(FS);
		PUSH((offset) cmd);
		PUSH((int) 0);
		PUSH((int) 1 /* Llv */);
		PUSH((offset) cmd0054_tss);
		PUSH((int) 0x0100 /* TAPI_ChangeLlv */);
		EBX = ESP;
		PUSH(SS);
		POP(FS);
		CALLFAR0(tapi_sel);
		ESP += 16;
		POP((offset) cmd);
		POP(FS);
		goto nextcmd;
	#endif
	#if (defined(TOWNS))
		INT(0x03);
	#endif

cmd0060:
	/* keymosへのダイレクトコマンド */
	PUSH((offset) cmd);
	(offset) cmd += 8;
	DB(0x9a); DD(0); DW((short) keyint_sel);
	POP((offset) cmd);
	(offset) cmd += cmd[4];
	goto nextcmd;

cmd0064:
	/* timerへのダイレクトコマンド */
	PUSH((offset) cmd);
	(offset) cmd += 8;
	DB(0x9a); DD(0); DW((short) timerint_sel);
	POP((offset) cmd);
	(offset) cmd += cmd[4];
	goto nextcmd;

cmd0068:
	/* decodeへのダイレクトコマンド */
	PUSH((offset) cmd);
	(offset) cmd += 8;
	DB(0x9a); DD(0); DW((short) decode_sel);
	POP((offset) cmd);
	(offset) cmd += cmd[4];
	goto nextcmd;

cmd006c:
	/* TAPIへのダイレクトコマンド */
	PUSH((offset) cmd);
	(offset) cmd += 8;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	POP((offset) cmd);
	(offset) cmd += cmd[4];
	goto nextcmd;

cmd0070:
	/* 仮想モジュール生成 */
	PUSH((int) root_sel);
	ESI = 512;
	POP(DS);
	ECX = 512; /* 0.5KB */
	alloc_tagdir();
	ECX = cmd[ 8];
	LEA(EAX, [ECX + 0xfff]);
	EAX &= 0xfffff000;
	EDX = 0;
	(int) [DS:EDI +  0] = 64;
	(int) [DS:EDI + 16] = 0xffe00003; /* standard link-to */
	(int) [DS:EDI + 20] = 32;
	(int) [DS:EDI + 24] = ECX; /* used */
	(int) [DS:EDI + 28] = EDX;
	(int) [DS:EDI + 32] = EAX; /* allocated */
	(int) [DS:EDI + 36] = EDX;
	EAX = cmd[16];
	ECX = cmd[20];
	cmd[12] = EDI;
	(offset) cmd += 24;
	(int) [DS:EDI + 40] = EAX;
	(int) [DS:EDI + 44] = ECX;
	(int) [DS:EDI + 48] = 0xfff00000;
	(int) [DS:EDI + 52] = 0xffffffff;
	(int) [DS:EDI + 56] = EDX;
	(int) [DS:EDI + 60] = EDX;
	goto nextcmd;

cmd0074:
	/* 仮想モジュール削除 */
	/* cmd, opt, addr(cmd0070で[12]に返された値) */
	PUSH((int) root_sel);
	ESI = 512;
	POP(DS);
	EAX = cmd[8];
	(offset) cmd += 12;
	ECX = [DS:EAX + 4]; /* tag-dir allcated size */
	free_area();
	goto nextcmd;

cmd0078:
	/* デバッグ用コマンドの転送先が逆バージョン */
	ECX = cmd[8]; // bytes
	LES(EDI, [FS:EBX + 24]);
	CLI();
	SLDT(DX);
	LLDT((short) [FS:EBX + 22]);
	LDS(ESI, [FS:EBX + 16]);
	LLDT(DX);
	(offset) cmd += 32;
	do {
		AL = [ES:EDI];
		EDI++;
		[DS:ESI] = AL;
		ESI++;
		ECX--;
	} while (!= 0);
	STI();
	goto nextcmd;

cmd007c:
	/* gapidataへのハンドル獲得 */
	/* opt, slot */
	PUSH((int) root_sel);
	PUSH((int) 0x003c); /* slot_sel */
	EDX = cmd[8];
	POP(ES);
	POP(DS);
	ESI = 1024 /* rootdir */ + 16;
	EAX = 0xffe00040;
//	ESI += 16;
	search_tag_EAX();
	PUSH((offset) cmd);
	EBX = [DS:ESI + 16];
	EBX += 16;
	for (;;) {
		ESI = [DS:EBX];
		if (ESI == 0xffffffff)
			INT(0x03); /* 見付からない！(terminator検出) */
		ESI += 16;
		EAX = 0xffe00000; /* nameタグ */
		search_tag_EAX();
	//	if (ZF == 0) /* nameタグが見付からない */
	//		INT(0x03);
		if ((unsigned) (int) [DS:ESI +  4] == 16) {
			if ((unsigned) (int) [DS:ESI +  8] == 0x69706167) {
				if ((unsigned) (int) [DS:ESI + 12] == 0x61746164)
					break;
			}
		}
		EBX += 4;
	}
	EAX = [DS:EBX];
	[ES:EDX + 0] = EAX;
	POP((offset) cmd);
	(offset) cmd += 12;
	goto nextcmd;

cmd0080:
	/* slotを使わないmapping */
	/* size, addr, ofs  */
	PUSH((int) tapiwork_sel);
	POP(DS);
	EAX = [DS:0x000c] /* tskptr */;
	EAX += 2048 + 0x0008; /* sel:0x000c */
//	int *cmd0080_tss_ldt == DS:ESI + 2048;
//	asmout("LEA ECX,[ECX+ESI+2048]");
	DL = [DS:EAX + 4];
	DH = [DS:EAX + 7];
	EDX <<= 16;
	DX = [DS:EAX + 2];

	EDX += cmd[12]; /* ofs */
	ECX = cmd[ 4]; /* size */
	EAX = 0;
	ECX += 0x00000fff;
	PUSH(FS);
	PUSH((offset) cmd);
	ECX &= 0xfffff000;
	PUSH((int) EAX /* eoc */);
	PUSH((int) EAX /* addr64(high) */);
	PUSH((int) cmd[ 8] /* addr64(low) */);
	PUSH((int) EAX /* offset64(high) */);
	PUSH((int) EAX /* offset64(low) */);
	PUSH((int) EAX /* pageset */);
	PUSH((int) EDX /* linear */);
	PUSH((int) ECX /* size */);
	PUSH((int) 0x1007 /* opt(over-mapping, present, R/W, user) */);
	PUSH((int) 0x0108 /* cmd(mapping) */);
	EBX = ESP;
	PUSH(SS);
	POP(FS);
	CALLFAR0(papi_sel);
	ESP += 40;
	POP((offset) cmd);
	POP(FS);
	(offset) cmd += 16;
	goto nextcmd;

cmd0084:
	/* メモリ獲得 */
	/* cmd, size, [addr] */
	/* 本当は排他制御をしなければいけないのに、面倒なのでやっていない */
	ECX = cmd[4];
	ECX += 0x00000fff;
	ECX &= 0xfffff000;
	get_memory(); /* EAXを返す */
	if (ZF != 0)
		EAX = 0xffffffff;
	cmd[8] = EAX;
	(offset) cmd += 12;
	goto nextcmd;

cmd8010:
	// デバッグ用コマンド
	ECX = cmd[8]; // bytes
	LES(EDI, [FS:EBX + 24]);
	CLI();
	SLDT(DX);
	LLDT((short) [FS:EBX + 22]);
	LDS(ESI, [FS:EBX + 16]);
	LLDT(DX);
	(offset) cmd += 32;
	do {
		AL = [DS:ESI];
		ESI++;
		[ES:EDI] = AL;
		EDI++;
		ECX--;
	} while (!= 0);
	STI();
	goto nextcmd;
}

void near output_string()
/* 512バイトくらいスタック領域にとっておけば、必ず足りる。 */
/* 最高でも100文字しかないから */
/* GS:ESIにストリング('\0'がターミネータ) */
/* (EAX, ECX), color(DL, DH) */
{
	struct GAPI_FONT_WRITE_CMD {
		unsigned int cmd_no /* 0x0101 */;
		unsigned int option /* 0x00:モノクロフォント, BGCあり, 0x10:モノクロフォント, BGCなし, pset */;
		unsigned int x, y, color, bgcolor;
		void near *fnt;
		unsigned short fntsel, [2];
		unsigned int length, string[0]; // キャラクターオフセット列 
	};
	unsigned int ankfont_sel == 7 * 8;
	unsigned int GAPI_sel     ==  4 * 8, GAPIwork_sel  ==  5 * 8;

	PUSH(FS);
	PUSHAD();
	ESP -= 512;
	EBX = ESP;
	GAPI_FONT_WRITE_CMD *cmd == SS:ESP;

	cmd->cmd_no = 0x0101;
	cmd->option = 0x0000;
	cmd->x = EAX;
	cmd->y = ECX;
	// EAX = (unsigned char) DL; // MOVZX
	MOVZX(EAX,DL);
	// ECX = (unsigned char) DH; // MOVZX
	MOVZX(ECX,DH);
	cmd->color   = EAX;
	cmd->bgcolor = ECX;
//	cmd->fnt = 0;
//	(int) cmd->fntsel = ankfont_sel;
	unsigned char *s == GS:ESI;
	unsigned int *t == SS:EBP, len == ECX, chr == EAX;
	// (offset) t = (offset) cmd->string;
	LEA(EBP, [SS:ESP + 36]); 
	len = 0;

	chr = *s; /* MOVZX */
	(offset) s++;
	chr *= 16;
	do {
		chr += 4096;
		len++;
		*t = chr;
		(offset) t += 4;
		chr = *s; /* MOVZX */
		(offset) s++;
		chr *= 16;
	} while (!= 0);

	cmd->length = len;
	// (int) [cmd->string + len * 4] = 0x0000;
//	asmout("MOV DWORD PTR SS:[ESP+36+ECX*4],0");
	*t = chr;

	PUSH(SS);
	POP(FS);
	DB(0x9a); DD(0); DW((short) GAPI_sel);
	ESP += 512;
	POPAD();
	POP(FS);
	return;
}

void near ui8toa()
/*  ALを[DS:ESI]へ */
{
	unsigned char *s == DS:ESI;
	PUSH(EAX);
	AH = AL;
	AL >>= 4;
	EAX &= 0x0f0f;
	if ((unsigned) AL > 9)
		AL += /* 'A' - '0' - 0x0a */ 0x41 - 0x30 - 0x0a;
	if ((unsigned) AH > 9)
		AH += /* 'A' - '0' - 0x0a */ 0x41 - 0x30 - 0x0a;
	EAX += /* '00' */ 0x3030;
	s[0] = AL;
	s[1] = AH;
	POP(EAX);
	return;
}


void near ui16toa()
/*  AXを[DS:ESI]へ */
{
	XCHG(AH, AL);
	ui8toa();
	ESI += 2;
	XCHG(AH, AL);
	ui8toa();
	ESI -= 2;
	return;
}

void near ui32toa()
/* EAXを[DS:ESI]へ */
{
	ROR(EAX, 16); /* 上位と下位を交換 */
	ui16toa();
	ESI += 4;
	ROL(EAX, 16); /* 上位と下位を交換 */
	ui16toa();
	ESI -= 4;
	return;
}

void far int10()
{
	PUSHAD();
	ESI = InitMdl::"INT 0x0A Invalid TSS\0";
	goto put_int_status_ec;
}

void far int12()
{
	PUSHAD();
	ESI = InitMdl::"INT 0x0C Stack Protect\0";
	goto put_int_status_ec;
}

void far int02()
{
	PUSH(EAX); // ダミーのエラーコード
	PUSHAD();
	ESI = InitMdl::"INT 0x02 Non Maskable Interrupt\0";
	#if (defined(TOWNS))
		EDX = 0x0602;
		AL = 0xb2; /* NMI ACK */
		OUT(DX, AL);	
	#endif
	goto put_int_status;
}

void far int13()
{
	unsigned int                         all_sel       ==  1 * 8;

	PUSHAD();
	EAX = [SS:ESP + 32 + 4 + 8] /* EFLAGS */;
	TEST(EAX, 0x00020000);
	if (== 0) {
		ESI = InitMdl::"INT 0x0D General Protect\0";
		goto put_int_status_ec;
	}

	#if (defined(PCAT))
		ECX = (unsigned short) [SS:ESP + 32 + 8]; // CS
		EAX = (unsigned short) [SS:ESP + 32 + 4]; // IP
	//	PUSH(DS);
		ECX *= 16;
		PUSH((int) all_sel);
		EAX += ECX;
		POP(DS);
		CL = [DS:EAX]; // 命令フェッチ

		// seg:を判定してない

		// とりあえず、STIやCLIは全て無視。
	//	if (CL == 0x67)
	//		goto op_adrsiz;
		if (CL == 0x66)
			goto op_opsiz;
		if (CL == 0xfa)
			goto skip1byte;
		if (CL == 0xfb)
			goto skip1byte;
		if (CL == 0xcd)	// INT(n)
			goto op_int_n;
	//	if (CL == 0xcc)
	//		goto op_int_3;
		if (CL == 0xcf)
			goto op_iret;
		if (CL == 0xec)
			goto op_inbDX;
		if (CL == 0xed)
			goto op_inwDX;
		if (CL == 0xee)
			goto op_outbDX;
		if (CL == 0xef)
			goto op_outwDX;
		if (CL == 0xe4)
			goto op_inbIb;
		if (CL == 0xe5)
			goto op_inwIb;
		if (CL == 0xe6)
			goto op_outbIb;
		if (CL == 0xe7)
			goto op_outwIb;
		if (CL == 0x9c)
			goto op_pushf;
		if (CL == 0x9d)
			goto op_popf;
	//	if (CL == 0x6c)
	//		goto op_insb;
	//	if (CL == 0x6d)
	//		goto op_insw;
		if (CL == 0x6e)
			goto op_outsb;
		if (CL == 0x6f)
			goto op_outsw;
		if (CL == 0xf3)
			goto op_rep;
		if (CL == 0x2e)
			goto op_CS;
		if (CL == 0x36)
			goto op_SS;
	//	if (CL == 0x3e)
	//		goto op_DS;
		if (CL == 0x26)
			goto op_ES;
	#endif
	INT(0x03);

#if (defined(PCAT))
op_adrsiz:
	CL = [DS:EAX + 1]; // 命令フェッチ
/*	if (CL == 0x66)
		goto op_adrsiz_opsiz;
	if (CL == 0x6c)
		goto op_adrsiz_insb;
	if (CL == 0x6d)
		goto op_adrsiz_insw;
	if (CL == 0x6e)
		goto op_adrsiz_outsb;
	if (CL == 0x6f)
		goto op_adrsiz_outsw;
*/	INT(0x03);

op_opsiz:
	CL = [DS:EAX + 1]; // 命令フェッチ
	if (CL == 0xed)
		goto op_indDX;
	if (CL == 0xef)
		goto op_outdDX;
	if (CL == 0xe5)
		goto op_indIb;
	if (CL == 0xe7)
		goto op_outdIb;
	if (CL == 0x9c)
		goto op_pushfd;
	if (CL == 0x9d)
		goto op_popfd;
//	if (CL == 0x6d)
//		goto op_insd;
//	if (CL == 0x6f)
//		goto op_outsd;
	INT(0x03);

op_rep:
	CL = [DS:EAX + 1]; // 命令フェッチ
/*	if (CL == 0x67)
		goto op_rep_adrsiz;
	if (CL == 0x66)
		goto op_rep_opsiz;
	if (CL == 0x6c)
		goto op_rep_insb;
	if (CL == 0x6d)
		goto op_rep_insw;
*/	if (CL == 0x6e)
		goto op_rep_outsb;
	if (CL == 0x6f)
		goto op_rep_outsw;
	if (CL == 0x2e)
		goto op_rep_CS;
	if (CL == 0x36)
		goto op_rep_SS;
//	if (CL == 0x3e)
//		goto op_rep_DS;
	if (CL == 0x26)
		goto op_rep_ES;
	INT(0x03);

op_CS:
	CL = [DS:EAX + 1]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_CS_outsb;
	if (CL == 0x6f)
		goto op_CS_outsw;
	INT(0x03);

op_ES:
	CL = [DS:EAX + 1]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_ES_outsb;
	if (CL == 0x6f)
		goto op_ES_outsw;
	INT(0x03);

op_SS:
	CL = [DS:EAX + 1]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_SS_outsb;
	if (CL == 0x6f)
		goto op_SS_outsw;
	INT(0x03);

op_rep_adrsiz:
	CL = [DS:EAX + 2]; // 命令フェッチ
/*	if (CL == 0x66)
		goto op_rep_adrsiz_opsiz;
	if (CL == 0x6c)
		goto op_rep_adrsiz_insb;
	if (CL == 0x6d)
		goto op_rep_adrsiz_insw;
	if (CL == 0x6e)
		goto op_rep_adrsiz_outsb;
	if (CL == 0x6f)
		goto op_rep_adrsiz_outsw;
*/	INT(0x03);

op_adrsiz_opsiz:
	CL = [DS:EAX + 2]; // 命令フェッチ
/*	if (CL == 0x6d)
		goto op_adrsiz_insd;
	if (CL == 0x6f)
		goto op_adrsiz_outsd;
*/	INT(0x03);

op_rep_adrsiz_opsiz:
	CL = [DS:EAX + 3]; // 命令フェッチ
/*	if (CL == 0x6d)
		goto op_rep_adrsiz_insd;
	if (CL == 0x6f)
		goto op_rep_adrsiz_outsd;
*/	INT(0x03);

op_rep_CS:
	CL = [DS:EAX + 2]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_rep_CS_outsb;
	if (CL == 0x6f)
		goto op_rep_CS_outsw;
	INT(0x03);

op_rep_SS:
	CL = [DS:EAX + 2]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_rep_SS_outsb;
	if (CL == 0x6f)
		goto op_rep_SS_outsw;
	INT(0x03);

op_rep_ES:
	CL = [DS:EAX + 2]; // 命令フェッチ
	if (CL == 0x6e)
		goto op_rep_ES_outsb;
	if (CL == 0x6f)
		goto op_rep_ES_outsw;
	INT(0x03);

skip1byte:
	(int) [SS:ESP + 32 + 4]++; // EIP
//	POP(EAX); // skip old DS
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_int_n:
	EBX = (unsigned char) [DS:EAX + 1]; // fetch n
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	AX = [SS:ESP + 32 + 4]; // IP
	ESI += EDI;
	AX += 2;
	CX = [SS:ESP + 32 + 8]; // CS
	(short) [DS:ESI - 6] = AX;
	asmout("MOV EAX,DS:[EBX*4]");
	BX = [SS:ESP + 32 + 12]; // FLAGS
	(short) [DS:ESI - 4] = CX;
	(short) [SS:ESP + 32 + 4] /* IP */ = AX;
	(short) [DS:ESI - 2] = BX;
	(unsigned int) EAX >>= 16;
	(short) [SS:ESP + 32 + 16] -= 6; // SP
	[SS:ESP + 32 + 8] /* CS */ = EAX;
//	POP(EAX); // skip old DS
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_inbDX:
	EDX = (short) [SS:ESP + 20 /* EDX */];
	IN(AL, DX);
	[SS:ESP + 28 /* EAX */] = AL;
	// 必要なら、ここでlogをとる
#if 0
	if (EDX == 0x03da) {
		(char) [SS:ESP + 28 /* EAX */] ^= 0x09;
	}

	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x44626e69 /* 'inbD' */;
	(int) [SS:ESP + 20] = 0x20202058 /* 'X   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d584420 /* ' DX=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 20 /* EDX */ + 80];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 80;
#endif
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_inwDX:
	EDX = [SS:ESP + 20 /* EDX */];
	IN(AX, DX);
	[SS:ESP + 28 /* EAX */] = AX;
	// 必要なら、ここでlogをとる
#if 0
	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x44776e69 /* 'inwD' */;
	(int) [SS:ESP + 20] = 0x20202058 /* 'X   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d584420 /* ' DX=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 20 /* EDX */ + 80];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 80;
#endif
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_indDX:
	EDX = [SS:ESP + 20 /* EDX */];
	IN(EAX, DX);
	[SS:ESP + 28 /* EAX */] = EAX;
	// 必要なら、ここでlogをとる
#if 0
	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x44646e69 /* 'indD' */;
	(int) [SS:ESP + 20] = 0x20202058 /* 'X   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d584420 /* ' DX=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 20 /* EDX */ + 80];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 80;
#endif
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outbDX:
	EAX = [SS:ESP + 28 /* EAX */];
	EDX = [SS:ESP + 20 /* EDX */];
	OUT(DX, AL);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outwDX:
	EAX = [SS:ESP + 28 /* EAX */];
	EDX = [SS:ESP + 20 /* EDX */];
	OUT(DX, AX);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outdDX:
	EAX = [SS:ESP + 28 /* EAX */];
	EDX = [SS:ESP + 20 /* EDX */];
	OUT(DX, EAX);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_pushf:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	AX = [SS:ESP + 32 + 12]; // FLAGS
	(short) [DS:ESI + EDI - 2] = AX;
	(short) [SS:ESP + 32 + 16] -= 2; // SP
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_popf:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	AX = (short) [DS:ESI + EDI];
	(short) [SS:ESP + 32 + 16] += 2; // SP
	AX &= 0x8fff;
	[SS:ESP + 32 + 12] = AX; // FLAGS
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_inbIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	IN(AL, DX);
	[SS:ESP + 28 /* EAX */] = AL;
	// 必要なら、ここでlogをとる
#if 0
	PUSH(EDX);
	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x49626e69 /* 'inbI' */;
	(int) [SS:ESP + 20] = 0x20202062 /* 'b   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d624920 /* ' Ib=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 80 /* Ib */];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 84;
#endif
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_inwIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	IN(AX, DX);
	[SS:ESP + 28 /* EAX */] = AX;
	// 必要なら、ここでlogをとる
#if 0
	PUSH(EDX);
	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x49776e69 /* 'inwI' */;
	(int) [SS:ESP + 20] = 0x20202062 /* 'b   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d624920 /* ' Ib=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 80 /* Ib */];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 84;
#endif
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_indIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	IN(EAX, DX);
	[SS:ESP + 28 /* EAX */] = EAX;
	// 必要なら、ここでlogをとる
#if 0
	PUSH(EDX);
	ESP -= 80;
	AX = SS;
	DS = AX;
	GS = AX;
	ESI = ESP;
	EAX = (unsigned short) [SS:ESP + 32 + 8 + 80]; // CS
	ui16toa();
	(char) [SS:ESP + 4] = 0x3a /* ':' */;
	LEA(ESI, [SS:ESP + 5]);
	EAX = (unsigned short) [SS:ESP + 32 + 4 + 80]; // IP
	(int) [SS:ESP + 12] = 0x20202020 /* '    ' */;
	ui32toa();
	(int) [SS:ESP + 16] = 0x49646e69 /* 'indI' */;
	(int) [SS:ESP + 20] = 0x20202062 /* 'b   ' */;
	(int) [SS:ESP + 24] = 0x3d584145 /* 'EAX=' */;
	LEA(ESI, [SS:ESP + 28]);
	EAX = [SS:ESP + 28 /* EAX */ + 80];
	ui32toa();
	(int) [SS:ESP + 32] = 0x3d624920 /* ' Ib=' */;
	LEA(ESI, [SS:ESP + 36]);
	EAX = [SS:ESP + 80 /* Ib */];
	ui16toa();
	(char) [SS:ESP + 40] = 0;
	ESI = ESP;
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();
	ESP += 84;
#endif
	(int) [SS:ESP + 32 + 4] += 3; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_iret:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	ESI += EDI;
	AX = (short) [DS:ESI    ]; // IP
	ECX = (unsigned short) [DS:ESI + 2]; // CS
	DX = (short) [DS:ESI + 4]; // FLAGS
	(short) [SS:ESP + 32 + 16] += 6; // SP
	DX &= 0x8fff;
	(short) [SS:ESP + 32 + 4] = AX; // IP
	[SS:ESP + 32 + 8] = ECX; // CS
	[SS:ESP + 32 + 12] = DX; // FLAGS
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outbIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	EAX = [SS:ESP + 28 /* EAX */];
	OUT(DX, AL);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outwIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	EAX = [SS:ESP + 28 /* EAX */];
	OUT(DX, AX);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outdIb:
	EDX = (unsigned char) [DS:EAX + 1]; // fetch Ib
	EAX = [SS:ESP + 28 /* EAX */];
	OUT(DX, EAX);
	// 必要なら、ここでlogをとる
	(int) [SS:ESP + 32 + 4] += 3; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_pushfd:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	EAX = [SS:ESP + 32 + 12]; // EFLAGS
	(int) [DS:ESI + EDI - 4] = EAX;
	(short) [SS:ESP + 32 + 16] -= 4; // SP
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_popfd:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // SS
	ESI = (unsigned short) [SS:ESP + 32 + 16]; // SP
	EDI *= 16;
	EAX = (int) [DS:ESI + EDI];
	(short) [SS:ESP + 32 + 16] += 4; // SP
	[SS:ESP + 32 + 12] = AX; // FLAGS
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 28]; // DS
op_seg_outsb:
	ESI = (unsigned short) [SS:ESP + 4]; // SI
	EDI *= 16;
	asmout("TEST BYTE PTR SS:[ESP+32+13],04H");
	EDX = (int) [SS:ESP + 20 /* EDX */];
	AL  = (char) [DS:ESI + EDI];
	ECX = 1;
	OUT(DX, AL);
	// 必要なら、ここでlogをとる
	if (!= 0)
		ECX =- ECX;
	(unsigned short) [SS:ESP + 4 /* SI */] += CX;
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 28]; // DS
op_seg_outsw:
	ESI = (unsigned short) [SS:ESP + 4]; // SI
	EDI *= 16;
	asmout("TEST BYTE PTR SS:[ESP+32+13],04H");
	EDX = (int) [SS:ESP + 20 /* EDX */];
	AX  = (short) [DS:ESI + EDI];
	ECX = 2;
	OUT(DX, AX);
	// 必要なら、ここでlogをとる
	if (!= 0)
		ECX =- ECX;
	(unsigned short) [SS:ESP + 4 /* SI */] += CX;
	(int) [SS:ESP + 32 + 4]++; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_CS_outsb:
	EDI = (unsigned short) [SS:ESP + 32 +  8]; // CS
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsb;

op_SS_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsb;

op_ES_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 24]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsb;

op_CS_outsw:
	EDI = (unsigned short) [SS:ESP + 32 +  8]; // CS
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsw;

op_SS_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsw;

op_ES_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 24]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_seg_outsw;

op_rep_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 28]; // DS
op_rep_seg_outsb:
	ESI = (unsigned short) [SS:ESP + 4]; // SI
	EDI *= 16;
	ECX = (unsigned short) [SS:ESP + 24]; // CX
	asmout("TEST BYTE PTR SS:[ESP+32+13],04H");
	EDX = (int) [SS:ESP + 20 /* EDX */];
	if (== 0) {
		do {
			AL  = (char) [DS:ESI + EDI];
			ESI++;
			OUT(DX, AL);
			ESI &= 0xffff;
			ECX--;
		} while (!= 0);
	} else {
		do {
			AL  = (char) [DS:ESI + EDI];
			ESI--;
			OUT(DX, AL);
			ESI &= 0xffff;
			ECX--;
		} while (!= 0);
	}
	(unsigned short) [SS:ESP + 4 /* SI */] = SI;
	(unsigned short) [SS:ESP + 24 /* CX */] = CX;
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_rep_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 28]; // DS
op_rep_seg_outsw:
	ESI = (unsigned short) [SS:ESP + 4]; // SI
	EDI *= 16;
	ECX = (unsigned short) [SS:ESP + 24]; // CX
	asmout("TEST BYTE PTR SS:[ESP+32+13],04H");
	EDX = (int) [SS:ESP + 20 /* EDX */];
	if (== 0) {
		do {
			AX  = (short) [DS:ESI + EDI];
			ESI += 2;
			OUT(DX, AL);
			ESI &= 0xffff;
			ECX--;
		} while (!= 0);
	} else {
		do {
			AX  = (short) [DS:ESI + EDI];
			ESI -= 2;
			OUT(DX, AL);
			ESI &= 0xffff;
			ECX--;
		} while (!= 0);
	}
	(unsigned short) [SS:ESP + 4 /* SI */] = SI;
	(unsigned short) [SS:ESP + 24 /* CX */] = CX;
	(int) [SS:ESP + 32 + 4] += 2; // EIP
	POPAD();
	ESP += 4; // skip EC
	IRETD();

op_rep_CS_outsb:
	EDI = (unsigned short) [SS:ESP + 32 +  8]; // CS
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsb;

op_rep_SS_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsb;

op_rep_ES_outsb:
	EDI = (unsigned short) [SS:ESP + 32 + 24]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsb;

op_rep_CS_outsw:
	EDI = (unsigned short) [SS:ESP + 32 +  8]; // CS
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsw;

op_rep_SS_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 20]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsw;

op_rep_ES_outsw:
	EDI = (unsigned short) [SS:ESP + 32 + 24]; // ES
	(int) [SS:ESP + 32 + 4]++; // EIP
	goto op_rep_seg_outsw;

#endif

//op_int_3:
//	INT(0x03);
}

/*
void far int14()
{
	PUSHAD();
	ESI = InitMdl::"INT 0x0E Page Protect\0";
}
*/

void near put_int_status_ec()
// エラーコードあり(フラグを表示していない)
{
	PUSH(DS);
	PUSH(GS);
	PUSH(CS);
	POP(GS);
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();

	// 12345678901234567890123456789012345678901
	// CS:EIP = 1234:56789ABC     EC = 12345678
	PUSH(SS);
	PUSH(SS);
	POP(DS);
	POP(GS);
	ESP -= 84;
	EBP = ESP;
	asmout("MOV DWORD PTR SS:[EBP][00],'C'+'S'*100h+':'*10000h+'E'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][04],'I'+'P'*100h+' '*10000h+'='*1000000h");
	asmout("MOV BYTE PTR SS:[EBP][08],' '");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 32 + 4 + 4];
	// ESI = EBP + 9;
	LEA(ESI, [EBP + 9]);
	ui16toa();
	asmout("MOV BYTE PTR SS:[EBP][13],':'");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 32 + 4];
	// ESI = EBP + 14;
	LEA(ESI, [EBP+14]);
	ui32toa();
	asmout("MOV WORD PTR SS:[EBP][22],' '+' '*100h");
	asmout("MOV DWORD PTR SS:[EBP][24],' '+' '*100h+' '*10000h+'E'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][28],'C'+' '*100h+'='*10000h+' '*1000000h");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 32];
	// ESI = EBP + 32;
	LEA(ESI,[EBP+32]);
	ui32toa();
	asmout("MOV BYTE PTR SS:[EBP][40],0");
	// CS:EIP, ECを表示したあとにput_int_status2へ
}

void near put_int_status2()
{
	unsigned int tapiwork_sel  == 13 * 8;

//	EBP = ESP;
	ESI = EBP;
	EAX = 0;
	ECX = 16;
	EDX = 0x000f;
	output_string();

	asmout("MOV DWORD PTR SS:[EBP][00],'E'+'A'*100h+'X'*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][04],'='+' '*100h+'0'*10000h+'1'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][08],'2'+'3'*100h+'4'*10000h+'5'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][12],'6'+'7'*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][16],' '+' '*100h+' '*10000h+'E'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][20],'C'+'X'*100h+' '*10000h+'='*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][24],' '+'0'*100h+'1'*10000h+'2'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][28],'3'+'4'*100h+'5'*10000h+'6'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][32],'7'+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][36],' '+' '*100h+'E'*10000h+'D'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][40],'X'+' '*100h+'='*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][44],'0'+'1'*100h+'2'*10000h+'3'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][48],'4'+'5'*100h+'6'*10000h+'7'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][52],' '+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][56],' '+'E'*100h+'B'*10000h+'X'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][60],' '+'='*100h+' '*10000h+'0'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][64],'1'+'2'*100h+'3'*10000h+'4'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][68],'5'+'6'*100h+'7'*10000h+000*1000000h");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 28];
	// ESI = EBP +  6;
	asmout("LEA ESI,[EBP+6]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 24];
	// ESI = EBP + 25;
	asmout("LEA ESI,[EBP+25]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 20];
	// ESI = EBP + 44;
	asmout("LEA ESI,[EBP+44]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 16];
	// ESI = EBP + 63;
	asmout("LEA ESI,[EBP+63]");
	ui32toa();
	ESI = EBP;
	EAX = 0;
	ECX = 16 * 2;
	EDX = 0x000f;
	output_string();

	asmout("MOV DWORD PTR SS:[EBP][00],'E'+'S'*100h+'P'*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][04],'='+' '*100h+'0'*10000h+'1'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][08],'2'+'3'*100h+'4'*10000h+'5'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][12],'6'+'7'*100h+' '*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][16],' '+' '*100h+' '*10000h+'E'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][20],'B'+'P'*100h+' '*10000h+'='*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][24],' '+'0'*100h+'1'*10000h+'2'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][28],'3'+'4'*100h+'5'*10000h+'6'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][32],'7'+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][36],' '+' '*100h+'E'*10000h+'S'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][40],'I'+' '*100h+'='*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][44],'0'+'1'*100h+'2'*10000h+'3'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][48],'4'+'5'*100h+'6'*10000h+'7'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][52],' '+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][56],' '+'E'*100h+'D'*10000h+'I'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][60],' '+'='*100h+' '*10000h+'0'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][64],'1'+'2'*100h+'3'*10000h+'4'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][68],'5'+'6'*100h+'7'*10000h+000*1000000h");
	// EAX = EBP + 84 + 8 + 32 + 16;
	asmout("LEA EAX,[EBP+84+8+32+16]");
	// ESI = EBP +  6;
	asmout("LEA ESI,[EBP+6]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 +  8];
	// ESI = EBP + 25;
	asmout("LEA ESI,[EBP+25]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 +  4];
	// ESI = EBP + 44;
	asmout("LEA ESI,[EBP+44]");
	ui32toa();
	EAX = /* (int) */ [SS:EBP + 84 + 8 +  0];
	// ESI = EBP + 63;
	asmout("LEA ESI,[EBP+63]");
	ui32toa();
	ESI = EBP;
	EAX = 0;
	ECX = 16 * 3;
	EDX = 0x000f;
	output_string();

	asmout("MOV DWORD PTR SS:[EBP][00],'t'+'s'*100h+'s'*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][04],'='+' '*100h+'0'*10000h+'1'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][08],'2'+'3'*100h+'4'*10000h+'5'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][12],'6'+'7'*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][16],' '+' '*100h+' '*10000h+'T'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][20],'R'+' '*100h+' '*10000h+'='*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][24],' '+'0'*100h+'1'*10000h+'2'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][28],'3'+'4'*100h+'5'*10000h+'6'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][32],'7'+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][36],' '+' '*100h+'E'*10000h+'S'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][40],'I'+' '*100h+'='*10000h+' '*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][44],'0'+'1'*100h+'2'*10000h+'3'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][48],'4'+'5'*100h+'6'*10000h+'7'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][52],' '+' '*100h+' '*10000h+' '*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][56],' '+'E'*100h+'D'*10000h+'I'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][60],' '+'='*100h+' '*10000h+'0'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][64],'1'+'2'*100h+'3'*10000h+'4'*1000000h");
//	asmout("MOV DWORD PTR SS:[EBP][68],'5'+'6'*100h+'7'*10000h+000*1000000h");
	PUSH(DS);
	EAX = tapiwork_sel;
	DS = AX;
	EAX = (int) [DS:0x000c];
	POP(DS);
	// ESI = EBP +  6;
	asmout("LEA ESI,[EBP+6]");
	ui32toa();
	EAX = 0;
	STR(AX);
	// ESI = EBP + 25;
	asmout("LEA ESI,[EBP+25]");
	ui32toa();
	(char) [SS:EBP + 33] = 0;

//	EAX = /* (int) */ [SS:ESP + 84 + 8 +  4];
//	// ESI = ESP + 44;
//	asmout("LEA ESI,[ESP+44]");
//	ui32toa();
//	EAX = /* (int) */ [SS:ESP + 84 + 8 +  0];
//	// ESI = ESP + 63;
//	asmout("LEA ESI,[ESP+63]");
//	ui32toa();
	ESI = EBP;
	EAX = 0;
	ECX = 16 * 4;
	EDX = 0x000f;
	output_string();

	#if (!defined(NOHLT))
		for (;;)
			HLT(); // もしマルチタスクに対応したら、これはやめて、該当タスクをスリープにするだけにする
	#else
		for (;;)
			NOP();
	#endif
}

void far int01()
{
	unsigned int tapiwork_sel  == 13 * 8;

	PUSH(EAX); // ダミーのエラーコード
	PUSHAD();
/*	PUSH(DS);
	EAX = 0x0058;
	DS = AX;
	EAX = [DS:4];
	POP(DS);
	if (EAX != 0)
		goto no_trap;
*/	CX = [SS:ESP + 32 + 4 + 4]; // CS
	EAX = [SS:ESP + 32 + 4]; // EIP
	#if (defined(CHECK_TSKPTR))
		PUSH(DS);
		PUSH(EAX);
		EAX = tapiwork_sel;
		DS = AX;
		EAX = [DS:0x000c];
		TEST(EAX, 0xfff);
		POP(EAX);
		POP(DS);
		if (!= 0)
			goto trap;
		goto no_trap;
	#endif
	#if 0
		PUSH(DS);
		PUSH(EAX);
		EAX = tapiwork_sel;
		DS = AX;
		EAX = [DS:28];
		TEST(EAX, 0xfffff03f);
		POP(EAX);
		POP(DS);
		if (!= 0)
			goto trap;
		goto no_trap;
	#endif
	#if 0
		PUSH(DS);
		PUSH(ECX);
		PUSH(EAX);
		SLDT(CX);
		EAX = 0x118;
		LLDT(AX);
		EAX = 0x001c;
		DS = AX;
		EAX = [DS:0xfffffffc];
		LLDT(CX);
		CMP(EAX, 0x0060);
		POP(EAX);
		POP(ECX);
		POP(DS);
		if (!=)
			goto trap;
		goto no_trap;
	#endif

	#if 0
	if (CX == 0x0010) {
		if (EAX == 0x11a7)
			goto no_trap;
	//	if (EAX == 0x0404)
	//		goto no_trap;
	} else if (CX == 0x0060) {
		if (EAX == 0x08b2)
			goto no_trap;
		if (EAX == 0x09f0) {
			if ((unsigned) ESI < 512)
				goto no_trap;
		}
	}
	#endif
	#if 0
		if (CX == 0x00c7) {
			if (EAX == 0x026e)
				goto no_trap;
			if (EAX == 0x1335) {
				if (ESI <= 0x002c)
					goto no_trap;
			}
		}
	#endif
trap:
	ESI = InitMdl::"INT 0x01 Debug Fault\0";
	asmout("JMP put_int_status");
no_trap:
	POPAD();
	POP(EAX);
	IRETD();
}


void far int03()
{
	unsigned int syswork_sel  ==  3 * 8;
	unsigned int stack_sel    ==  6 * 8;
	unsigned int tapi_sel     == 12 * 8, tapiwork_sel  == 13 * 8;

	PUSH(EAX); // ダミーのエラーコード
	PUSHAD();
	EAX = [SS:ESP + 32 + 4 + 8] /* EFLAGS */;
	TEST(EAX, 0x00020000);
	if (== 0) {
	//	PUSH(FS);
	//	EAX = syswork_sel; FS = AX;
	//	// 640x480x4bit モードにする
	//	asmout("MOV EBX, offset mode0x12_800"); // ASKAはアセンブララベルとの連携がとれないのでasmoutにしている。
	//	asmout("fcall 4*8, 0");
	//	asmout("MOV EBX, offset mode0x12_800"); // ASKAはアセンブララベルとの連携がとれないのでasmoutにしている。
	//	(char) [FS:EBX] = 0xff;
	//	asmout("fcall 4*8, 0");
	//	POP(FS);
#if 0
PUSH(DS);
EAX = 14 * 8;
DS = AX;
asmout("MOV EAX,DR0");
EAX >>= 20;
EAX &= 0xffc;
EBX = [DS:EAX];
asmout("MOV EAX,DR0");
EAX >>= 10;
EAX &= 0xffc;
EBX += EAX; /* これは正しいアドレス */
EDX = [DS:EBX];
ESI = 0x2000;
EDX &= 0xfffff001;
ECX = 16 * 1024;
do {
	EAX = [DS:ESI];
	EAX &= 0xfffff001;
	if (EAX == EDX) {
		if (ESI != EBX)
			break;
	}
	ESI += 4;
	ECX--;
} while (!= 0);
POP(DS);
asmout("MOV EDX,DR0");
[SS:ESP + 28] = ESI;
[SS:ESP + 24] = EDX;
#endif
		ESI = InitMdl::"INT 0x03 Break Point\0";
		goto put_int_status;
	}

#if (defined(PCAT))

	// from V86モード

	// CS:EIPが所定の位置にあるかどうかを確認
//	CX = [SS:ESP + 32 + 8]; // CS
//	EAX = [SS:ESP + 32 + 4]; // EIP

	// シグナルを送って、自分はスリープ

	PUSH(FS);
	PUSH((int) stack_sel);
	POP(FS);
	// 横のドット数を800にする、ラッチ初期化領域の初期設定...
	// などのために、GAPIの初期化コマンドを実行...こんなことは、winman0がやる

	// 最後にシグナルを起こす
	GUIGUI_work *work == FS:0xffffd000;
	EAX = 0;
	EBX = [SS:ESP + 4 + 28 /* EAX */];
	PUSH(EAX /* eoc */);
	PUSH(EAX /* Llv(0) */);
	PUSH((int) 0x5000 /* work->tasklist[128].tskptr */);
	PUSH((int) 0x0100 /* TAPI_ChangeLlv */); // 自身のスリープ
	if ((unsigned) work->setvideomode_mode > 0xff) {
		if (BX != 0x004f)
			EAX++;
	}
	PUSH(EAX /* error-code */);
	PUSH(work->setvideomode_sig[8]);
	PUSH(work->setvideomode_sig[4]);
	PUSH(work->setvideomode_sig[0]);
	PUSH((int) 0x0128 /* コマンドシグナル直接(with wait) */); // シグナル発生
	EBX = ESP;
	PUSH(SS);
	POP(FS);
	CALLFAR0(tapi_sel);
//	ESP += 36;
//	POP(FS);

#endif

	INT(0x03);
}

void far int06()
{
	PUSH(EAX); // ダミーのエラーコード
	PUSHAD();
	ESI = InitMdl::"INT 0x06 Invalid Opecode\0";
}

void near put_int_status()
// エラーコードなし(フラグを表示していない)
{
	PUSH(DS);
	PUSH(GS);
	PUSH(CS);
	POP(GS);
	EAX = 0;
	ECX = 0;
	EDX = 0x000f;
	output_string();

	// 12345678901234567890123
	// CS:EIP = 1234:56789ABC
	ESP -= 84;
	AX = SS;
	EBP = ESP;
	DS = AX;
	GS = AX;
	asmout("MOV DWORD PTR SS:[EBP][00],'C'+'S'*100h+':'*10000h+'E'*1000000h");
	asmout("MOV DWORD PTR SS:[EBP][04],'I'+'P'*100h+' '*10000h+'='*1000000h");
	asmout("MOV BYTE PTR SS:[EBP][08],' '");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 32 + 4 + 4];
	// ESI = EBP + 9;
	asmout("LEA ESI,[EBP+9]");
	ui16toa();
	asmout("MOV BYTE PTR SS:[EBP][13],':'");
	EAX = /* (int) */ [SS:EBP + 84 + 8 + 32 + 4];
	// ESI = EBP + 14;
	asmout("LEA ESI,[EBP+14]");
	ui32toa();
	asmout("MOV BYTE PTR SS:[EBP][22],0");
//	ESI = EBP;
//	EAX = 0;
//	ECX = 16;
//	EDX = 0x000f;
//	output_string();
	// CS:EIP, ECを表示したあとにput_int_status2へ
	// goto put_int_status2;
	asmout("JMP put_int_status2");
}

#if (defined(PCAT))

void far int39()
{
	/* ノイズにより不完全割り込みが発生したと判断 */
	/* IRRをクリアするために、PICを再初期化 */
	PUSH(EAX);
	IN(AL, 0x21); /* master IMR */
	PUSH(EAX);
	AL = 0x11; /* ICW1 (edge trigger) */
	OUT(0x20, AL); /* master */
	AL = 0x20; /* ICW2(int-no.) */
	OUT(0x21, AL); /* master */
	AL = 0x04; /* ICW3 slaveがつながっているIRQのbitを1にする(bit2 = 1) */
	OUT(0x21, AL); /* master */
	AL = 0x01; /* ICW4(non-buf. mode) */
	OUT(0x21, AL); /* master */
	POP(EAX);
	OUT(0x21, AL); /* OCW1 (IMR復帰) */
	AL = 0x4a; /* OCW3 IRR読み込み 特殊マスクモードリセット 01001010 */
	OUT(0x20, AL); /* master */
	POP(EAX);
	IRETD();

#if 0
	PUSH(EAX); /* ダミーのエラーコード */
	PUSHAD();
	EAX = 0;
	ESI = InitMdl::"INT 0x27 IRQ7\0";
	IN(AL, 0x0020);
	(int) [SS:ESP + 32] = EAX;
	asmout("JMP put_int_status_ec");
#endif
}

#endif

void near initmalloc()
// DS == SysWork_sel, ECXにバイト数 → EAXに物理アドレス
{
	// unsigned int addr0 == [DS:0x04], free0 == [DS:0x08];
	// unsigned int addr1 == [DS:0x0c], free1 == [DS:0x10];

	// free1 -= ECX;
	asmout("SUB DWORD PTR DS:[bootmalloc_fre1],ECX");
	if ((unsigned) >= 0) {
		// EAX = addr1;
		// EAX += free1;
		asmout("MOV EAX,DWORD PTR DS:[bootmalloc_adr1]");
		asmout("ADD EAX,DWORD PTR DS:[bootmalloc_fre1]");
		return;
	}
	// free1 += ECX; // 元に戻す
//	// free0 -= ECX;
//	asmout("ADD DWORD PTR DS:[010h],ECX");
//	asmout("SUB DWORD PTR DS:[008h],ECX");
//	if ((unsigned) >= 0) {
//	//	EAX = addr0;
//	//	EAX += free0;
//		asmout("MOV EAX,DWORD PTR DS:[004h]");
//		asmout("ADD EAX,DWORD PTR DS:[008h]");
//		return;
//	}
	INT(0x03);
}

#if 1
void near set_modulesegment()
/* AL, AH = access_right
   ECX = size, EDX = base
   GS:EBX = DT-entry */
/* sizeは0xfffff000以下である */
{
	struct DescriptTbl {
		unsigned short limit1;
		unsigned short base1;
		unsigned char base2;
		unsigned char access_right1;
		unsigned char limit2_access_right2;
		unsigned char base3;
	};

	DescriptTbl *DT == GS:EBX;
	unsigned int size == ECX, base == EDX;

	size--;
	DT->access_right1 = AL;
	TEST(AL, 0x10);
	if (!= 0) { /* S = 1 */
		if (size > 0xfffff) {
			AH |= 0x80; /* page単位に補正 */
		//	size &= 0xfffff000;
		}
		AL &= 0x1e;
		TEST(AH, 0x80);
		if (!= 0) {
			size /= 4096; /* ページ単位に補正(0〜0xffffe) */
			if (AL == 0x16) {
				size ^= 0x000fffff; /* 0→0xfffff, 1→0xffffe */
				size--; /* 0→0xffffe, 1→0xffffd */
			}
		}
	}

	DT->base1 = DX /* base */;
	base >>= 16;
	DT->limit1 = CX /* size */;
	size >>= 16;
	DT->base2 = DL /* base */;
	CL |= AH;
	DT->limit2_access_right2 = CL /* size */;
	DT->base3 = DH /* base */;
//	ESP -= 8;
//	asmout("SGDT FWORD PTR SS:[ESP]");
//	asmout("LGDT FWORD PTR SS:[ESP]");
//	ESP += 8;
	return;
}
#endif

#if 0
void near set_modulesegment()
/* AL, AH = access_right
   ECX = size, EDX = base
   GS:EBX = DT-entry */
{
	struct DescriptTbl {
		unsigned short limit1;
		unsigned short base1;
		unsigned char base2;
		unsigned char access_right1;
		unsigned char limit2_access_right2;
		unsigned char base3;
	};

	DescriptTbl *DT == GS:EBX;
	unsigned int size == ECX, base == EDX;

	size--;
	DT->access_right1 = AL;
	TEST(AH, 0x80);
	if (!= 0) {
		AL &= 0x1e;
		size /= 4096; // ページ単位に補正
		if (AL == 0x16) {
			size =~ size; /* 0→0xfffff, 1→0xfffffe */
			size--;
			size &= 0x000fffff;
		}
	}
	DT->base1 = DX /* base */;
	base >>= 16;
	DT->limit1 = CX /* size */;
	size >>= 16;
	DT->base2 = DL /* base */;
	CL |= AH;
	DT->limit2_access_right2 = CL /* size */;
	DT->base3 = DH /* base */;
//	ESP -= 8;
//	asmout("SGDT FWORD PTR SS:[ESP]");
//	asmout("LGDT FWORD PTR SS:[ESP]");
//	ESP += 8;
	return;
}
#endif

// 物理メモリを要求
// リニアアドレス空間を要求
// GDTにマッピングを要求
// LDTにマッピングを要求
// IDTはCPUx32,I/Ox16=48エントリーしか使わない。384Bytes。
// GDTとIDTは統合。
// IDTがないと割込み制御ができない。
// 割込み制御ができないと、マウスの動きを取得できない。
// PICを制御。キーボードとマウスの制御。
// まず、一般割り込みルーチン規定が必要。

