// "fdcdrv0.ask" ver.0.8 copyright(C) 2001 H.Kawai(川合秀実)

segment FDC_Mdl(USE32, PARA);

default(code == FDC_Mdl);

struct FDC_WORK {
	int MC_ptr, MC_free, jmpvec_fdcint /* 0x0008 */;
	char motor, motor2 /* off待ちフラグ */, [2];
	int TimerCmd[8]; // 0x0010
	int timer_cmd0 /* メッセージセット (11 * 4) */, timer_node0, timer_msglen, timer_msg /* 0x0024 */; // 0x0018
	int timer_cmd1 /* 現在時刻セット (7 * 4) */, timer_node1; // 0x0028
	int timer_cmd2 /* 時刻加算 (8 * 4) */, timer_node2, time_add0, time_add4, time_add8; // 0x0030
	int timer_cmd3 /* ベクタセット (10 * 4) */, timer_node3, jmpvec_timer_EIP /* 0x004c */, jmpvec_timer_CS; // 0x0044
	int timer_cmd4 /* タイマー登録 (4 * 4) */, timer_node4; // 0x0054
	int timer_cmd5; // 0x005c
	int timer_cmd6 /* タイマー取り消し (5 * 4) */, timer_node5; // 0x0060
	int timer_cmd7; // 0x0068
	int wait0_0, wait0_4, wait0_8; // モーターONにしてから、アクセスまでのウェイト(0x006c)
	int wait1_0, wait1_4, wait1_8; // 最後のアクセスから、アクセスまでのウェイト(0x0078)
	char cylinder[4];
	int track[20], dosload_phase, dosload_name[12], dosload_addr; // 0x0088
	int dosload_sigtmp, dosload_sigfin, dosload_FAT, dosload_size0, dosload_size1; // 0x00b0
	int TAPI_sendsignalofs, TAPI_sendsignalsel, [52]; // 0x00c4
	// 0x0100〜0x03ff : マイクロコマンドキュー(0.75KB)...192DW
};

void near FDC_Init();
void near FDC_dosload();
void near FDC_loadFAT();
void near FDC_format();
void near FDC_writeIPL();

void far FDC_syscmd()
{
	asmout("include ./inc.asm");

	unsigned int                         all_sel       ==  1 * 8;
	FDC_WORK *work == DS:0;
	int *cmd == FS:EBX;

	PUSHAD();
	AX = CS;
	PUSH(DS);
	AX += 8;
	DS = AX;
nextcmd:
	EAX = *cmd;
	if (EAX == 0)
		goto cmd0000;
	if (EAX == 0x0114)
		goto cmd0114; // FDC_continue
	if (EAX == 0x0118)
		goto cmd0118; // FDC_dosload
	if (EAX == 0x0110)
		goto cmd0110; // FDC_loadFAT
	if (EAX == 0x0108)
		goto cmd0108; // FDC_diskchange
	if (EAX == 0x010c)
		goto cmd010c; // FDC_diskcache1
	if (EAX == 0x0100)
		goto cmd0100; // 初期化
	if (EAX == 0x0104)
		goto cmd0104; // FDC_intのベクタ提供
	if (EAX == 0x011c)
		goto cmd011c; // FDC_format
	if (EAX == 0x0120)
		goto cmd0120; // FDC_writeIPL
	if (EAX == 0x0124)
		goto cmd0124; // FDC motor control

	INT(0x03);

cmd0000:
	POP(DS);
	[SS:ESP + 16] = EBX;
	POPAD();
	return;

cmd0100:
	// 初期化
	PUSH((offset) cmd);
	AL = cmd[4];
	FDC_Init();
	POP((offset) cmd);
	(offset) cmd += 8;
	goto nextcmd;

cmd0104:
	// FDC_intのベクタ提供
	asmout("MOV DWORD PTR FS:[EBX+4],OFFSET FDC_int");
	(short) cmd[8] = CS;
	(offset) cmd += 12;
	goto nextcmd;

cmd0108:
	// FDC_diskchange
	EAX = 0;
	ECX = 20;
	do {
	//	work->track[ECX - 4] = EAX;
		[ECX - 4 + work->track] = EAX;
		ECX -= 4;
	} while (!= 0);
	(offset) cmd += 4;
	goto nextcmd;

cmd010c:
	// FDC_diskcache1
	//	 直接起動ディスクのIPLが読み込んだデーターをキャッシュバッファに転送
	PUSH(DS);
	EAX = all_sel;
	DS = AX;
	EDX = 0x000800;
	ESI = 0x100000;
	ECX = 18 * 1024 / 4;
	do {
		EAX = [DS:EDX];
		EDX += 4;
		[DS:ESI] = EAX;
		ESI += 4;
		ECX--;
	} while (!= 0);
	POP(DS);
	work->track[0] |= 0x03; // track0とtrack1
	(offset) cmd += 4;
	goto nextcmd;

cmd0110:
	// FDC_loadFAT
	PUSH((offset) cmd);
	EDX = cmd[4]; // EDX:完了のシグナル
	ECX = cmd[8]; // ECX:作業中のシグナル
	FDC_loadFAT();
	POP((offset) cmd);
	(offset) cmd += 12;
	goto nextcmd;

cmd0114:
	// FDC_continue
	PUSH((offset) cmd);
	EAX = work->dosload_phase;
	asmout("CALL EAX");
	POP((offset) cmd);
	(offset) cmd += 4;
	goto nextcmd;

cmd0118:
	// FDC_dosload
	PUSH(GS);
	PUSH((offset) cmd);
	asmout("LGS ESI,FWORD PTR FS:[EBX+4]"); // ディレクトリエントリ
	EAX = cmd[12]; // ロードアドレス（４バイトアライン）
	EDX = cmd[16]; // 完了シグナル
	ECX = cmd[20]; // 作業中のシグナル
	FDC_dosload();
	POP((offset) cmd);
	POP(GS);
	(offset) cmd += 24;
	goto nextcmd;

cmd011c:
	// FDC_format
	PUSH((offset) cmd);
	EDX = cmd[4]; // EDX:完了のシグナル
	ECX = cmd[8]; // ECX:作業中のシグナル
	FDC_format();
	POP((offset) cmd);
	(offset) cmd += 12;
	goto nextcmd;

cmd0120:
	// FDC_writeIPL
	PUSH((offset) cmd);
	EDX = cmd[4]; // EDX:完了のシグナル
	ECX = cmd[8]; // ECX:作業中のシグナル
	FDC_writeIPL();
	POP((offset) cmd);
	(offset) cmd += 12;
	goto nextcmd;

cmd0124:
	// FDC motor control
	unsigned int cmd0124_fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	AL = cmd[4];
	EDX = cmd0124_fdc_control;
	work->motor = AL;
	OUT(DX, AL);
	(offset) cmd += 8;
	goto nextcmd;
}

// O6B#で604、O7B#で302、O8B#で151。

// マイクロコマンドフォーマット：
//	・コマンド送信 cmd_ofs, bytes, ..., bytesをアラインする
//	・FDCからのIRQを待つ cmd_ofsのみ。
//	・ステータスリード cmd_ofs, 受信するバイト数、７バイトのステータス情報を格納するアドレス（FDC_WORK内に限定）
//	・ドライブレディー(このコマンドは、モーター回転を保証する)
//	・ドライブ解放（このコマンドが過ぎてから一定時間後にモーターが止まる）
//	・メイクシグナル(メッセージは16bytes固定) ofsのあとにメッセージロング(DW単位)、８バイトベクタ、メッセージ
//	・DMAセット

void near FDC_MC_ReadStatus()
//	コマンドofs
//	リードするバイト数
//	バッファアドレス
{
	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned int fdc_status == 0x03f4, fdc_data == 0x03f5;

	int *cmd == DS:EBX, cmd_free == EBP;
	char *status_buf == DS:EDI;

	cmd_free += 3;
	(offset) status_buf = cmd[8];
	ECX = cmd[4];
	(offset) cmd += 12;
	EDX = fdc_status;
	do {
		do {
			//	statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0xc0);
		EDX++;
		IN(AL, DX);
		EDX--;
		*status_buf = AL;
		(offset) status_buf++;
		ECX--;
	} while (!= 0);
	asmout("JMP DWORD PTR DS:[EBX]");
}

void near FDC_MC_SendCommand()
//	コマンドofs
//	ライトするバイト数
//	busyチェックマスクバイト、コマンド
{
	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned int fdc_status == 0x03f4, fdc_data == 0x03f5;

	int *cmd == DS:EBX, cmd_free == EBP;
	char *status_buf == DS:EDI;

	EAX = cmd[4];
	// これに1を加え、その後に3を加え、4で割る
	(offset) cmd += 9;
	SHR(EAX, 2);
	EDX = fdc_status;
	/* cmd_free += EAX + 3 */ asmout("LEA EBP,[EBP+EAX+3]");
	do {
		IN(AL, DX);
		AL &= [DS:EBX - 1];
	} while (!= 0);
	ECX = cmd[4 - 9];
	do {
		do {
			//	statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0x80);
		EDX++;
		AL = [DS:EBX];
		(offset) cmd++;
		OUT(DX, AL);
		EDX--;
		ECX--;
	} while (!= 0);
	(offset) cmd += 3;
	(offset) cmd &= 0xfffffffc;
	asmout("JMP DWORD PTR DS:[EBX]");
}

void far FDC_int()
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;
	unsigned short PIC_mastar_OCW2 == 0x0020;

	PUSHAD();
	AX = CS;
	PUSH(DS);
	AX += 8;
	asmout("INC BYTE PTR SS:[0FFFFFFE0H]");
	DS = AX;	
	asmout("INC BYTE PTR SS:[0FFFFFFF0H]");

	AL = 0x66 /* IRQ-06を終了 */;
	OUT(PIC_mastar_OCW2, AL);

	(offset) cmd = work->MC_ptr;
	cmd_free = work->MC_free;

	// FDC_MCを実行中は、CLI();しておくこと
	asmout("CALL DWORD PTR DS:[0008H]"); // jmpvec_fdcint
	// 状態遷移割り込みがあるなら、jmpvec_fdcintを書き換えておけ。その際、cmdとcmd_freeは保存する。

	work->MC_ptr = (offset) cmd;
	work->MC_free = cmd_free;

	asmout("DEC BYTE PTR SS:[0FFFFFFF0H]");
	if (== 0) {
		asmout("CALL FWORD PTR SS:[0FFFFFFF8H]");
	}
	POP(DS);
	POPAD();
	asmout("DEC BYTE PTR SS:[0FFFFFFE0H]");
	if (== 0) {
		asmout("jmp_system_count0");
	}
	IRETD();
}

//	タイマーからの割り込みについては、各自で管理する。


void near FDC_MC_DriveReady()
// ドライブレディー(このコマンドは、モーター回転を保証する)
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号

	ECX = cmd[4];
	asmout("MOV AL,BYTE PTR CS:[FDC_MC_drive_table][ECX]");
	TEST(AL, work->motor);
	if (== 0) {
		// モーターが回っていなかったので、回すことにする
 		AL |= work->motor;
		EDX = fdc_control;
		work->motor = AL;
		OUT(DX, AL);
		// タイマーを使ってwaitする。本当は、ドライブごとにタイマーを使いたいので４本必要。
		AX = DS;
		PUSH(FS);
		FS = AX;
		PUSH(EBX);
		EAX = work->wait0_0;
		ECX = work->wait0_4;
		EDX = work->wait0_8;
		work->time_add0 = EAX;
		work->time_add4 = ECX;
		work->time_add8 = EDX;
		/* work->jmpvec_timer_EIP = */ asmout("MOV DWORD PTR DS:[004CH],OFFSET #timer_int"); 
		EBX = /* (offset) &work->timer_cmd1 */ 0x0028;
		asmout("CALL FWORD PTR DS:[0010H]"); // (work->TimerCmd)();
		POP(EBX);
		POP(FS);
		return; // リターン先で、cmdやcmd_freeを書き戻してくれる。rewindは、コマンドライト時にチェックする
	}
	(offset) cmd += 8;
	cmd_free += 2;
	TEST(AL, work->motor2);
	if (!= 0) {
		// タイマーのキャンセル
		work->motor2 ^= AL; // 指定bitを0にする
		AX = DS;
		PUSH(FS);
		FS = AX;
		PUSH(EBX);
		EBX = /* (offset) &work->timer_cmd6 */ 0x0060;
		asmout("CALL FWORD PTR DS:[0010H]"); // (work->TimerCmd)();
		POP(EBX);
		POP(FS);
	}
	AL = work->motor;
	EDX = fdc_control;
	AL |= [DS:EBX - 4]; // cmd[4 - 8];
	OUT(DX, AL);
	asmout("JMP DWORD PTR DS:[EBX]");

timer_int:
	AX = CS;
	PUSH(DS);
	AX += 8;
	DS = AX;	

	(offset) cmd = work->MC_ptr;
	cmd_free = work->MC_free;

	(offset) cmd += 8;
	cmd_free += 2;

	AL = work->motor;
	EDX = fdc_control;
	AL |= [DS:EBX - 4]; // cmd[4 - 8];
	OUT(DX, AL);

	asmout("CALL DWORD PTR DS:[EBX]");

	work->MC_ptr = (offset) cmd;
	work->MC_free = cmd_free;

	POP(DS);
	CLC();
	asmout("DB 0CBH"); // (far) return;

	asmout("FDC_MC_drive_table DB 010H, 020H, 040H, 080H");
}

void near FDC_MC_DriveOff()
// ドライブ解放（このコマンドが過ぎてから一定時間後にモーターが止まる）
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号

	ECX = cmd[4];
	(offset) cmd += 8;
	cmd_free += 2;
	asmout("MOV AL,BYTE PTR CS:[FDC_MC_drive_table][ECX]");
	work->motor2 |= AL; // 指定bitを1にする
	/* work->timer_msg */ [DS:0x0024] = AL;
	AX = DS;
	PUSH(FS);
	FS = AX;
	PUSH(EBX);
	EAX = work->wait1_0;
	ECX = work->wait1_4;
	EDX = work->wait1_8;
	work->time_add0 = EAX;
	work->time_add4 = ECX;
	work->time_add8 = EDX;
	/* work->jmpvec_timer_EIP = */ asmout("MOV DWORD PTR DS:[004CH],OFFSET #timer_int"); 
	EBX = /* (offset) &work->timer_cmd0 */ 0x0018;
	asmout("CALL FWORD PTR DS:[0010H]"); // (work->TimerCmd)();
	POP(EBX);
	POP(FS);
	asmout("JMP DWORD PTR DS:[EBX]");

timer_int:
	AL = [DS:ESI];
	CX = CS;
	PUSH(DS);
	CX += 8;
	DS = CX;
	work->motor2 ^= AL; // 指定bitを0にする
	AL ^= work->motor; // 指定bitを0にする
	EDX = fdc_control;
	work->motor = AL;
	OUT(DX, AL);
	POP(DS);
	CLC();
	asmout("DB 0CBH"); // (far) return;
}

void near FDC_MC_MakeSignal()
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	ECX = cmd[4];
	/* ESI = (offset) cmd + 16 */ asmout("LEA ESI,[EBX+16]");
	/* EAX = (offset) cmd + ECX * 4 + 16 */ asmout("LEA EAX,[EBX+ECX*4+16]");
	/* cmd_free += 4 + ECX */ asmout("LEA EBP,[EBP+ECX+4]");
	PUSH(EAX);
	PUSH(cmd_free);
	asmout("CALL FWORD PTR DS:[EBX+8]");
	POP(cmd_free);
	POP((offset) cmd);
	asmout("JMP DWORD PTR DS:[EBX]");
}

void near FDC_MC_Finish()
{
	int *cmd == DS:EBX, cmd_free == EBP;

	(offset) cmd = 0x0100;
	cmd_free = 192;

//	ライトポインタも初期化
//	状態遷移割り込みを使うなら、それも設定

	return;
}

void near FDC_MC_WaitFdcInt()
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	EAX = cmd[4];
	work->jmpvec_fdcint = EAX;

	(offset) cmd += 4;
	cmd_free++;

	return;
}

void near FDC_MC_ReadData()
{
	unsigned short DMA_address == 0x0004, DMA_counter == 0x0005, DMA_mode == 0x000b;
	unsigned short DMA_singlemask == 0x000a, DMA_addrhigh == 0x0081;

	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned int fdc_status == 0x03f4, fdc_data == 0x03f5;

	int *cmd == DS:EBX, cmd_free == EBP;
	char *status_buf == DS:EDI;

	// DMA設定
	AL = 0x06; // demand-mode, addr-inc., write, ch2
	OUT(DMA_mode, AL);
	EAX = cmd[4];
	OUT(DMA_counter, AL);
	SHR(EAX, 8);
	OUT(DMA_counter, AL);
	EAX = cmd[8];
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_addrhigh, AL);
	AL = 0x02; // ch2のマスクをクリア
	OUT(DMA_singlemask, AL);

	// コマンド送信
	CL = [DS:EBX + 12];
	(offset) cmd += 13;

	EDX = fdc_status;
	do {
		IN(AL, DX);
		AL &= CL;
	} while (!= 0);

	ECX = 7;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0x80);
		EDX++;
		AL = [DS:EBX];
		(offset) cmd++;
		OUT(DX, AL);
		EDX--;
		ECX--;
	} while (!= 0);

	do {
		IN(AL, DX);
		AL &= 0xc0;
	} while (AL != 0x80);
	EDX++;
	AL = 0x01; // GAP2 ・・・ 分からないので適当
	OUT(DX, AL);
	EDX--;

	do {
		IN(AL, DX);
		AL &= 0xc0;
	} while (AL != 0x80);
	EDX++;
	AL = 0xff; // データー長 ・・・ 分からないので適当
	OUT(DX, AL);
	EDX--;

	// fdc_int待ち
//	work->jmpvec_fdcint = EAX;
	asmout("MOV DWORD PTR DS:[0008H],OFFSET #fdcint");
	return;

fdcint:
	// リザルトステータス受信
	(offset) status_buf = cmd[0];
	(offset) cmd += 4;
	cmd_free += 6;
	ECX = 7;
	EDX = fdc_status;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0xc0);
		EDX++;
		IN(AL, DX);
		EDX--;
		*status_buf = AL;
		(offset) status_buf++;
		ECX--;
	} while (!= 0);

	AL = 0x06; // ch2のマスクをセット
	OUT(DMA_singlemask, AL);

	asmout("JMP DWORD PTR DS:[EBX]");
}

void near FDC_MC_WriteID()
{
	unsigned short DMA_address == 0x0004, DMA_counter == 0x0005, DMA_mode == 0x000b;
	unsigned short DMA_singlemask == 0x000a, DMA_addrhigh == 0x0081;

	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned int fdc_status == 0x03f4, fdc_data == 0x03f5;

	int *cmd == DS:EBX, cmd_free == EBP;
	char *status_buf == DS:EDI;

	// DMA設定
	AL = 0x0a; // demand-mode, addr-inc., read, ch2
	OUT(DMA_mode, AL);
	EAX = cmd[4];
	OUT(DMA_counter, AL);
	SHR(EAX, 8);
	OUT(DMA_counter, AL);
	EAX = cmd[8];
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_addrhigh, AL);
	AL = 0x02; // ch2のマスクをクリア
	OUT(DMA_singlemask, AL);

	// コマンド送信
	CL = [DS:EBX + 12];
	(offset) cmd += 13;

	EDX = fdc_status;
	do {
		IN(AL, DX);
		AL &= CL;
	} while (!= 0);

	ECX = 6;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0x80);
		EDX++;
		AL = [DS:EBX];
		(offset) cmd++;
		OUT(DX, AL);
		EDX--;
		ECX--;
	} while (!= 0);
	(offset) cmd++;

	// fdc_int待ち
//	work->jmpvec_fdcint = EAX;
	asmout("MOV DWORD PTR DS:[0008H],OFFSET #fdcint");
	return;

fdcint:
	// リザルトステータス受信
	(offset) status_buf = cmd[0];
	(offset) cmd += 4;
	cmd_free += 6;
	ECX = 7;
	EDX = fdc_status;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0xc0);
		EDX++;
		IN(AL, DX);
		EDX--;
		*status_buf = AL;
		(offset) status_buf++;
		ECX--;
	} while (!= 0);

	AL = 0x06; // ch2のマスクをセット
	OUT(DMA_singlemask, AL);

	asmout("JMP DWORD PTR DS:[EBX]");
}

void near FDC_MC_WriteData()
{
	unsigned short DMA_address == 0x0004, DMA_counter == 0x0005, DMA_mode == 0x000b;
	unsigned short DMA_singlemask == 0x000a, DMA_addrhigh == 0x0081;

	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned int fdc_status == 0x03f4, fdc_data == 0x03f5;

	int *cmd == DS:EBX, cmd_free == EBP;
	char *status_buf == DS:EDI;

	// DMA設定
	AL = 0x0a; // demand-mode, addr-inc., read, ch2
	OUT(DMA_mode, AL);
	EAX = cmd[4];
	OUT(DMA_counter, AL);
	SHR(EAX, 8);
	OUT(DMA_counter, AL);
	EAX = cmd[8];
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_address, AL);
	SHR(EAX, 8);
	OUT(DMA_addrhigh, AL);
	AL = 0x02; // ch2のマスクをクリア
	OUT(DMA_singlemask, AL);

	// コマンド送信
	CL = [DS:EBX + 12];
	(offset) cmd += 13;

	EDX = fdc_status;
	do {
		IN(AL, DX);
		AL &= CL;
	} while (!= 0);

	ECX = 7;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0x80);
		EDX++;
		AL = [DS:EBX];
		(offset) cmd++;
		OUT(DX, AL);
		EDX--;
		ECX--;
	} while (!= 0);

	do {
		IN(AL, DX);
		AL &= 0xc0;
	} while (AL != 0x80);
	EDX++;
	AL = 18; // GAP2 ・・・ 分からないので適当
	OUT(DX, AL);
	EDX--;

	do {
		IN(AL, DX);
		AL &= 0xc0;
	} while (AL != 0x80);
	EDX++;
	AL = 0xff; // データー長 ・・・ 分からないので適当
	OUT(DX, AL);
	EDX--;

	// fdc_int待ち
//	work->jmpvec_fdcint = EAX;
	asmout("MOV DWORD PTR DS:[0008H],OFFSET #fdcint");
	return;

fdcint:
	// リザルトステータス受信
	(offset) status_buf = cmd[0];
	(offset) cmd += 4;
	cmd_free += 6;
	ECX = 7;
	EDX = fdc_status;
	do {
		do {
			// statusのbit6が1で、bit7が1になるのを待つ。
			IN(AL, DX);
			AL &= 0xc0;
		} while (AL != 0xc0);
		EDX++;
		IN(AL, DX);
		EDX--;
		*status_buf = AL;
		(offset) status_buf++;
		ECX--;
	} while (!= 0);

	AL = 0x06; // ch2のマスクをセット
	OUT(DMA_singlemask, AL);

	asmout("JMP DWORD PTR DS:[EBX]");
}

void near FDC_Init()
// ワークエリアの初期化
{
	FDC_WORK *work == DS:0;
	unsigned int tapi_sel == 12 * 8;
	unsigned int fdc_control == 0x03f2; // bit7-4はmotor制御(1でON)、bit3はDMA許可、bit2はFDCリセット(0でリセット)、bit1-0はドライブ番号
	unsigned short DMA_singlemask_master == 0x00c0, DMA_mode_master == 0x00d6, DMA_singlemask == 0x000a;

	PUSH(EAX);
	AL = 0xc0;
	OUT(DMA_mode_master, AL); // ch0をカスケードモードに
	/* AL = 0x00 */ EAX = 0;
	OUT(DMA_singlemask_master, AL); // slaveのDMAを許可

	AL = 0x06; // ch2のマスクをセット
	OUT(DMA_singlemask, AL);

	work->MC_ptr = 0x0100;
//	work->jmpvec_fdcint = 0xffffffff;
//	AL = 0x0c; // 全モーター停止、ドライブ0選択
//	AL = 0x1c; // drv0のモーター回転、他は停止、ドライブ0選択
	POP(EAX);
	EDX = fdc_control;
	work->motor = AL;
	OUT(DX, AL);
	work->motor2 = 0;

	asmout("MOV DWORD PTR DS:[0010H],0 ; OFFSET TimerSysCmd"); // TimerCmd
	asmout("MOV DWORD PTR DS:[0014H],10*8");

	work->timer_cmd6 = 2 * 4 /* GetNode */;
	work->timer_cmd7 = 0;

	AX = DS;
	PUSH(FS);
	FS = AX;
	EBX = /* (offset) &work->timer_cmd6 */ 0x0060;
	asmout("CALL FWORD PTR DS:[0010H]"); // (work->TimerCmd)();
	EAX = work->timer_node5;
	work->timer_cmd0 = 11 * 4 /* メッセージセット */;
	work->timer_node0 = EAX;
	work->timer_msglen = 1;
	work->timer_msg = 0;
	work->timer_cmd1 = 7 * 4 /* 現在時刻セット */;
	work->timer_node1 = EAX;
	work->timer_cmd2 = 8 * 4 /* 時刻加算 */;
	work->timer_node2 = EAX;
	work->timer_cmd3 = 10 * 4 /* ベクタセット */;
	work->timer_node3 = EAX;
	work->jmpvec_timer_CS = 28 * 8;
	work->timer_cmd4 = 4 * 4 /* タイマー登録 */;
	work->timer_node4 = EAX;
	work->timer_cmd5 = 0;
	work->timer_cmd6 = 5 * 4 /*タイマー取り消し */;
	EAX = 0;
	CX = SS;
	FS = CX;
	PUSH(0 /* eoc */);
	ESP -= 32;
	PUSH(4 /* 一般情報要求 */);
	PUSH(4);
	EBX = ESP;
	asmout("CALL FWORD PTR DS:[0010H]"); // (work->TimerCmd)();
	ECX = [SS:ESP + 36]; // 割り込み周波数[Hz]
	ESP += 44;
	POP(FS);
	work->wait0_0 = ECX;
	ECX *= 3;
	work->wait0_4 = EAX;
	work->wait0_8 = EAX;
	work->wait1_0 = ECX;
	work->wait1_4 = EAX;
	work->wait1_8 = EAX;

	work->cylinder[0] = 0xf0;
	work->cylinder[1] = 0xf0;
	work->cylinder[2] = 0xf0;
	work->cylinder[3] = 0xf0;
	work->dosload_phase = EAX;

	PUSH(FS);
	PUSH((int) 0);
	PUSH(EAX);
	PUSH(EAX);
	PUSH((int) 0x011c);
	AX = SS;
	EBX = ESP;
	FS = AX;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	POP(EAX);
	POP(work->TAPI_sendsignalofs);
	POP(work->TAPI_sendsignalsel);
	POP(EAX);
	POP(FS);
	return;
}

void near FDC_MC_test4()
// EDX:ロードする物理アドレス, ECX:シグナル番号
// AH:side番号(0 or 1), AL:シリンダー番号
// 1trackロード for DOS(64KB境界に注意しているので効率アップ)
// このバージョンではシークの必要があるときだけシークする
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	PUSHAD();
	CX = CS;
	PUSH(DS);
	CX += 8;
	DS = CX;
	PUSHFD();
	CLI();

	(offset) cmd = work->MC_ptr;
	if ((unsigned) (offset) cmd == 0x0100) {
		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveReady");
		cmd[ 4] = 0;
		(offset) cmd += 8;
		CL = AH;
		AH <<= 2;
		if (AL != work->cylinder[0]) {
			asmout("MOV DWORD PTR DS:[EBX],OFFSET FDC_MC_SendCommand");
			cmd[ 4] = 2;
			cmd[ 8] = 0x00000711; // 11, 07 /* seek0 */, 00, 00
			if (AL != 0) {
				cmd[ 4] = 3;
				cmd[ 8] = 0x00000f11; // 11, 0f /* seek */, 00, 00
				[DS:EBX + 11] = AL; // C
				[DS:EBX + 10] = AH; // H
			}
			asmout("MOV DWORD PTR DS:[EBX+12],OFFSET FDC_MC_WaitFdcInt");
			asmout("MOV DWORD PTR DS:[EBX+16],OFFSET FDC_MC_SendCommand");
			cmd[20] = 1;
			cmd[24] = 0x00000810; // 10, 08 /* sense int status */, 00, 00
			asmout("MOV DWORD PTR DS:[EBX+28],OFFSET FDC_MC_ReadStatus");
			cmd[32] = 2;
			cmd[36] = 0x000000f8;
			(offset) cmd += 40;
			work->cylinder[0] = AL;
		}

		XCHG(AL, AH);
		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_ReadData");
		cmd[ 4] = 1024 * 9 - 1;
		cmd[ 8] = EDX;
		cmd[12] = 0x00004611; // 11, 46 /* read data */, 00, 00
		cmd[16] = 0x12020100; // 00(H), 01(R), 02(N), 12(EOT)
		[DS:EBX + 14] = AX;
		[DS:EBX + 16] = CL;
		cmd[20] = 0x00f8;
		(offset) cmd += 24;

		EDI = EDX;
		EDI &= 0xffff0000;
		EDI += 0x00010000;
		EDI -= EDX;

		if ((unsigned) EDI < 9 * 1024) {
			EDI--;
			CH = 1;
			asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_ReadData");
			cmd[ 4 - 24] = EDI;
			EDI++;
			EDI /= 2;
			ECX += EDI; // CHに加算
			EDX += 9 * 1024;
			EDI = EDX;
			EDX &= 0xffff0000;
			EDI &= 0x0000ffff;
			EDI--;
			cmd[ 4] = EDI;
			cmd[ 8] = EDX;
			cmd[12] = 0x00004611; // 11, 46 /* read data */, 00, 00
			cmd[16] = 0x12020100; // 00(H), 01(R), 02(N), 12(EOT)
			[DS:EBX + 14] = AX;
			[DS:EBX + 16] = CX;
			cmd[20] = 0x00f8;
			(offset) cmd += 24;
		}

		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveOff");
		cmd[ 4] = 0;
		asmout("MOV DWORD PTR DS:[EBX+ 8],OFFSET FDC_MC_MakeSignal");
		cmd[12] = 2;
		EAX = work->TAPI_sendsignalofs;
		ECX = work->TAPI_sendsignalsel;
		cmd[16] = EAX;
		cmd[20] = ECX;
		EAX = [SS:ESP + 32];
		cmd[24] = 0x1241;
		cmd[28] = EAX;
		asmout("MOV DWORD PTR DS:[EBX+32],OFFSET FDC_MC_Finish");

		(offset) cmd = 0x100;
		asmout("CALL DWORD PTR DS:[EBX]");
		work->MC_ptr = (offset) cmd;
		work->MC_free = cmd_free;
	}

	POPFD(); // 0

	POP(DS); // 4
	POPAD(); // 8
	return;
}

void near FDC_MC_test5()
// EDX:CHRNリストへの物理アドレス, ECX:シグナル番号
// EDI:(bit00-07)N, (bit08-15)SC, (bit16-23)GPL, (bit24-31)D
// AH:side番号(0 or 1), AL:シリンダー番号
// 1 track format
// このバージョンではシークの必要があるときだけシークする
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	PUSHAD();
	CX = CS;
	PUSH(DS);
	CX += 8;
	DS = CX;
	PUSHFD();
	CLI();

	(offset) cmd = work->MC_ptr;
	if ((unsigned) (offset) cmd == 0x0100) {
		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveReady");
		cmd[ 4] = 0;
		(offset) cmd += 8;
		AH <<= 2;
		if (AL != work->cylinder[0]) {
			asmout("MOV DWORD PTR DS:[EBX],OFFSET FDC_MC_SendCommand");
			cmd[ 4] = 2;
			cmd[ 8] = 0x00000711; // 11, 07 /* seek0 */, 00, 00
			if (AL != 0) {
				cmd[ 4] = 3;
				cmd[ 8] = 0x00000f11; // 11, 0f /* seek */, 00, 00
				[DS:EBX + 11] = AL; // C
				[DS:EBX + 10] = AH; // H
			}
			asmout("MOV DWORD PTR DS:[EBX+12],OFFSET FDC_MC_WaitFdcInt");
			asmout("MOV DWORD PTR DS:[EBX+16],OFFSET FDC_MC_SendCommand");
			cmd[20] = 1;
			cmd[24] = 0x00000810; // 10, 08 /* sense int status */, 00, 00
			asmout("MOV DWORD PTR DS:[EBX+28],OFFSET FDC_MC_ReadStatus");
			cmd[32] = 2;
			cmd[36] = 0x000000f8;
			(offset) cmd += 40;
			work->cylinder[0] = AL;
		}

		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_WriteID");
		ECX = EDI;
		ECX /= 64;
		ECX &= 0xfc;
		ECX--;
		cmd[ 4] = ECX;
		cmd[ 8] = EDX;
		cmd[12] = 0x00004d11; // 11, 4d /* write id */, 00, 00
		[DS:EBX + 14] = AH;
		EAX = EDI;
		[DS:EBX + 15] = AL;
		(unsigned int) EAX /= 256;
		cmd[16] = EAX;
		cmd[20] = 0x00f8;
		(offset) cmd += 24;

		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveOff");
		cmd[ 4] = 0;
		asmout("MOV DWORD PTR DS:[EBX+ 8],OFFSET FDC_MC_MakeSignal");
		cmd[12] = 2;
		EAX = work->TAPI_sendsignalofs;
		ECX = work->TAPI_sendsignalsel;
		cmd[16] = EAX;
		cmd[20] = ECX;
		EAX = [SS:ESP + 32];
		cmd[24] = 0x1241;
		cmd[28] = EAX;
		asmout("MOV DWORD PTR DS:[EBX+32],OFFSET FDC_MC_Finish");

		(offset) cmd = 0x100;
		asmout("CALL DWORD PTR DS:[EBX]");
		work->MC_ptr = (offset) cmd;
		work->MC_free = cmd_free;
	}

	POPFD(); // 0

	POP(DS); // 4
	POPAD(); // 8
	return;
}

void near FDC_MC_test6()
// EAX:CHRN, ECX:転送サイズ, EDX:物理アドレス, EDI:シグナル番号
// このバージョンではシークの必要があるときだけシークする
// 64KB境界に差し掛かると誤動作する
{
	FDC_WORK *work == DS:0;
	int *cmd == DS:EBX, cmd_free == EBP;

	PUSHAD();
	BX = CS;
	PUSH(DS);
	BX += 8;
	DS = BX;
	PUSHFD();
	CLI();

	(offset) cmd = work->MC_ptr;
	if ((unsigned) (offset) cmd == 0x0100) {
		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveReady");
		cmd[ 4] = 0;
		(offset) cmd += 8;
		AH <<= 2;
		if (AL != work->cylinder[0]) {
			asmout("MOV DWORD PTR DS:[EBX],OFFSET FDC_MC_SendCommand");
			cmd[ 4] = 2;
			cmd[ 8] = 0x00000711; // 11, 07 /* seek0 */, 00, 00
			if (AL != 0) {
				cmd[ 4] = 3;
				cmd[ 8] = 0x00000f11; // 11, 0f /* seek */, 00, 00
				[DS:EBX + 11] = AL; // C
				[DS:EBX + 10] = AH; // H
			}
			asmout("MOV DWORD PTR DS:[EBX+12],OFFSET FDC_MC_WaitFdcInt");
			asmout("MOV DWORD PTR DS:[EBX+16],OFFSET FDC_MC_SendCommand");
			cmd[20] = 1;
			cmd[24] = 0x00000810; // 10, 08 /* sense int status */, 00, 00
			asmout("MOV DWORD PTR DS:[EBX+28],OFFSET FDC_MC_ReadStatus");
			cmd[32] = 2;
			cmd[36] = 0x000000f8;
			(offset) cmd += 40;
			work->cylinder[0] = AL;
		}

		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_WriteData");
		ECX--;
		cmd[ 4] = ECX;
		ECX++;
		cmd[ 8] = EDX;
		cmd[12] = 0x00004511; // 11, 45 /* write data */, 00, 00
		[DS:EBX + 14] = AH;
		(unsigned char) AH >>= 2;
		[DS:EBX + 15] = AL;
		(unsigned int) EAX /= 256;
		EAX |= 0x7f000000; // EOTは適当
		cmd[16] = EAX;
		cmd[20] = 0x00f8;
		(offset) cmd += 24;

		asmout("MOV DWORD PTR DS:[EBX+ 0],OFFSET FDC_MC_DriveOff");
		cmd[ 4] = 0;
		asmout("MOV DWORD PTR DS:[EBX+ 8],OFFSET FDC_MC_MakeSignal");
		cmd[12] = 2;
		EAX = work->TAPI_sendsignalofs;
		ECX = work->TAPI_sendsignalsel;
		cmd[16] = EAX;
		cmd[20] = ECX;
		EAX = [SS:ESP + 8 /* EDI */];
		cmd[24] = 0x1241;
		cmd[28] = EAX;
		asmout("MOV DWORD PTR DS:[EBX+32],OFFSET FDC_MC_Finish");

		(offset) cmd = 0x100;
		asmout("CALL DWORD PTR DS:[EBX]");
		work->MC_ptr = (offset) cmd;
		work->MC_free = cmd_free;
	}

	POPFD(); // 0

	POP(DS); // 4
	POPAD(); // 8
	return;
}


void near FDC_dosload()
// EAX:ロードアドレス(必ず4バイトアライン)
// ECX:作業中のシグナル
// EDX:完了のシグナル
// GS:ESI ファイル名(11bytes)
{
	unsigned int tapi_sel == 12 * 8;
	FDC_WORK *work == DS:0;

	if (work->dosload_phase != 0) {
		INT(0x03);
	}

	// 依頼された値をworkに保存しておく
	work->dosload_addr = EAX;
	work->dosload_sigtmp = ECX;
	work->dosload_sigfin = EDX;
	ECX = 11;
	LEA(EBX, work->dosload_name[0]);
//	if (ESI != 0xffffffff) {
		do {
			AL = [GS:ESI];
			ESI++;
			[DS:EBX] = AL;
			EBX++;
			ECX--;
		} while (!= 0);
//	}
	(char) [DS:EBX] = 0;

	// トラック0のロード
	EAX = work->track[0];
	TEST(AL, 0x01);
	if (== 0) {
		asmout("MOV EAX,OFFSET #pass00");
		work->dosload_phase = EAX;
		EAX = 0x0000; // C:0, H:0
		ECX = work->dosload_sigtmp;
		EDX = 0x100000;
		FDC_MC_test4();
		goto pass99;
pass00:
		work->track[0] |= 0x01;
		EAX = work->track[0];
	}

	// トラック1のロード
	TEST(AL, 0x02);
	if (== 0) {
		asmout("MOV EAX,OFFSET #pass01");
		work->dosload_phase = EAX;
		EAX = 0x0100; // C:0, H:1
		ECX = work->dosload_sigtmp;
		EDX = 0x102400;
		FDC_MC_test4();
		goto pass99;
pass01:
		work->track[0] |= 0x02;
		EAX = work->track[0];
	}

	// ファイルをサーチする
//	if ((unsigned) (char) work->dosload_name[0] == 0)
//		goto pass98;

	EAX = 1 * 8;
	PUSH(ES);
	ES = AX;
	EDI = 0x102600;
	do {
		EAX = [ES:EDI + 0];
		ECX = [ES:EDI + 4];
		EDX = [ES:EDI + 8];
		if (AL == 0)
			break;
		EDX &= 0x00ffffff;
		EAX -= work->dosload_name[0];
		ECX -= work->dosload_name[4];
		EDX -= work->dosload_name[8];
		EAX |= ECX;
		EAX |= EDX;
		if (== 0)
			goto find;
		EDI += 32;
	} while ((unsigned) EDI < 0x104200);
	POP(ES);
	// 見つからなかった
	INT(0x03);
find:
	EAX = (unsigned short) [ES:EDI + 0x1a];
	ECX = [ES:EDI + 0x1c];
	POP(ES);
	work->dosload_FAT = EAX;
	work->dosload_size0 = ECX;
	work->dosload_size1 = ECX;

	// ローディングループ
	if (ECX != 0) {
		for (;;) {
			// FAT番号からトラック番号を求める
		//	EAX = work->dosload_FAT;
			EAX += 31;
			CL = 18;
			EDX = EAX; // 物理アドレスEDX
			DIV(CL); // ALにトラック番号
			EAX &= 0xff;

			BT(work->track[0], EAX);
			if (CF == 0) {
			//	EDX = EAX * 9;
				LEA(EDX, [EAX * 8 + EAX]);
				asmout("MOV ECX,OFFSET #pass02");
				EDX *= 1024;
				work->dosload_phase = ECX;
				(unsigned char) AL >>= 1;
				ECX = work->dosload_sigtmp;
				ADC(AH, 0);
				EDX += 0x100000;
				FDC_MC_test4();
				goto pass99;
pass02:
				// FAT番号からトラック番号を求める
				EAX = work->dosload_FAT;
				EAX += 31;
				CL = 18;
				EDX = EAX; // 物理アドレスEDX
				DIV(CL); // ALにトラック番号
				EAX &= 0xff;

				BTS(work->track[0], EAX);
			}
			PUSH(DS);
			EAX = 1 * 8;
			EDX *= 512;
			ECX = work->dosload_size1;
			EDX += 0x100000;
			ECX -= 512;
			EBX = work->dosload_addr;
			if ((unsigned) <= 0)
				break;
			PUSH(work->dosload_FAT);
			work->dosload_size1 = ECX;
			DS = AX;
			ECX = 512 / 4;
			do {
				EAX = [DS:EDX];
				EDX += 4;
				[DS:EBX] = EAX;
				EBX += 4;
				ECX--;
			} while (!= 0);

			// 次のFAT番号を取得
			POP(EAX);
			EBX = EAX;
			(unsigned int) EAX >>= 1;
			LEA(EBX, [EBX + EAX]);
			AL = [DS:EBX + 0x100200];
			AH = [DS:EBX + 0x100201];
			if (CF == 1)
				EAX >>= 4;
			EAX &= 0x0fff;

			POP(DS);
			work->dosload_addr += 512;
			work->dosload_FAT = EAX;
		}
		ECX += 512;
		if (!= 0) {
			DS = AX;
			do {
				AL = [DS:EDX];
				EDX++;
				[DS:EBX] = AL;
				EBX++;
				ECX--;
			} while (!= 0);
		}
		POP(DS);
	}

pass98:
	work->dosload_phase = 0;
	AX = SS;
	PUSH(FS);
	PUSH((int) 0); // eoc
	PUSH(work->dosload_size0);
	PUSH(work->dosload_sigfin);
	PUSH(0x1242);
	PUSH(0x0114 /* コマンドシグナル直接 */);
	FS = AX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	ESP += 5 * 4;
	POP(FS);
pass99:
	return;
}

void near FDC_format_storeFAT()
// DS:EDXから12bit-FATイメージがあると仮定して、ECXのところにEAXを書き込む
// EAX〜EDXは保存する
{
	unsigned int index == ECX;
	char *FAT == DS:EBX;
	PUSH(index);
	PUSH(EAX);
	LEA(EBX, [EDX + index]);
	index /= 2;
	LEA(EBX, [EBX + index]);
	if (CF == 0) {
		CL = FAT[1];
		CL &= 0xf0;
		AH |= CL;
	} else {
		CL = FAT[0];
		EAX <<= 4;
		CL &= 0x0f;
		AL |= CL;
	}
	FAT[0] = AL;
	FAT[1] = AH;
	POP(EAX);
	POP(index);
	return;
}

void near FDC_format()
// ECX:作業中のシグナル
// EDX:完了のシグナル
{
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int tapi_sel == 12 * 8;

	FDC_WORK *work == DS:0;

	if (work->dosload_phase != 0) {
		INT(0x03);
	}

	// 依頼された値をworkに保存しておく
	work->dosload_sigtmp = ECX;
	work->dosload_sigfin = EDX;

//	unsigned int track == work->dosload_FAT;

	/* track */ work->dosload_FAT = 0;
	do {
		asmout("MOV EAX,OFFSET #pass00");
		work->dosload_phase = EAX;
		ECX = /* track */ work->dosload_FAT;
		PUSH(DS);
		EAX = ECX;
		EDX = all_sel;
		AH = AL;
		DS = DX;
		(unsigned char) AL /= 2;
		AH &= 0x01;
		if ((unsigned) ECX < 2)
			goto dos;
		if ((unsigned) ECX < 8) {
			// 2〜7
			PUSH(EAX); // トラック間スキューをかける
			EAX = ECX;
			BL = 11;
			DIV(BL);
			EDX = (unsigned char) AH;
			POP(EAX);
			EDX <<= 16;
			EAX |= 0x03700000;
			EDI = 0x00300b03;
			ECX = 11;
		} else {
dos:
			PUSH(EAX); // トラック間スキューをかける
			EAX = ECX;
			BL = 19; // 20
			DIV(BL);
			EDX = (unsigned char) AH;
			POP(EAX);
			EDX <<= 16;
			EAX |= 0x02010000;
		//	EDI = 0x00301402;
		//	ECX = 20;
			EDI = 0x004c1302;
			ECX = 19;
		}
		EAX += EDX; // スキューファクター加算
		EDX = 0x100000;
		do {
			[DS:EDX] = EAX;
			EDX += 4;
			EAX += 0x00010000;
			EBX = EAX;
			EBX &= 0x00ff0000;
			if (EBX == 0x007b0000) {
				EAX &= 0xff00ffff;
				EAX |= 0x00700000;
			} else if (EBX == 0x00140000) {
				EAX &= 0xff00ffff;
				EAX |= 0x00010000;
			}
			ECX--;
		} while (!= 0);
		POP(DS);
		ECX = work->dosload_sigtmp;
		EDX = 0x100000;
		FDC_MC_test5();
		goto pass99;
pass00:
		EAX = /* track */ work->dosload_FAT;
		EAX++;
		/* track */ work->dosload_FAT = EAX;
	} while ((unsigned) EAX < 160);

	// ここでライトしなければいけないのは、FATだけ。
	PUSH(DS);
	EAX = all_sel;
	EDX = 0x100200;
	DS = AX;

	EAX = 0;
	ECX = 512 * 32 / 4;
	do {
		[DS:EDX] = EAX;
		EDX += 4;
		ECX--;
	} while (!= 0);

	EDX = 0x100200;
	ECX = 0;
	EAX = 0xff0;
	FDC_format_storeFAT();
	ECX++;
	EAX = 0xfff;
	FDC_format_storeFAT();

	// 2〜4は空き

	// 特殊フォーマット部分を不良セクタ扱いに
	ECX = 5;
	EAX = 0xff7; 
	do {
		FDC_format_storeFAT();
		ECX++;
	} while ((unsigned) ECX < 113 /* 5 + 36 * 3 */);

	// FATコピー
	EBX = 0x101400;
	ECX = 512 * 9 / 4;
	do {
		EAX = [DS:EDX];
		EDX += 4;
		[DS:EBX] = EAX;
		EBX += 4;
		ECX--;
	} while (!= 0);

	POP(DS);

	// 0x100200〜0x1041ffのイメージを
	// CHR:0-0-02〜0-1-15に書き込む

	asmout("MOV EAX,OFFSET #pass01");
	work->dosload_phase = EAX;
	EAX = 0x02020000; // CHRN(NRHC)
	ECX = 512 * 17;
	EDX = 0x100200;
	EDI = work->dosload_sigtmp;
	FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
	goto pass99;
pass01:
	asmout("MOV EAX,OFFSET #pass02");
	work->dosload_phase = EAX;
	EAX = 0x02010100; // CHRN(NRHC)
	ECX = 512 * 15;
	EDX = 0x102400;
	EDI = work->dosload_sigtmp;
	FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
	goto pass99;
pass02:


	EAX = 0;
	ECX = 20;
	do {
	//	work->track[ECX - 4] = EAX;
		[ECX - 4 + work->track] = EAX;
		ECX -= 4;
	} while (!= 0);

	work->dosload_phase = 0;
	AX = SS;
	PUSH(FS);
	PUSH((int) 0); // eoc
	PUSH(work->dosload_sigfin);
	PUSH(0x1241);
	PUSH(0x0114 /* コマンドシグナル直接 */);
	FS = AX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	ESP += 4 * 4;
	POP(FS);
pass99:
	return;
}

void near FDC_writeIPL()
// ECX:作業中のシグナル
// EDX:完了のシグナル
{
	unsigned int                         all_sel       ==  1 * 8;
	unsigned int init_sel     ==  2 * 8, syswork_sel   ==  3 * 8;
	unsigned int tapi_sel == 12 * 8;

	unsigned int alloclist == 16 * 16;
//	unsigned int userbin_ent   == 12 * 16 + alloclist;
	unsigned int empty00_ent   == 16 * 16 + alloclist; // OSASK.EXE
	unsigned int empty01_ent   == 17 * 16 + alloclist; // OSASKBS0.BIN

	FDC_WORK *work == DS:0;

	if (work->dosload_phase != 0) {
		INT(0x03);
	}

//	unsigned int track == work->dosload_FAT;

	// 依頼された値をworkに保存しておく
	work->dosload_sigtmp = ECX;
	work->dosload_sigfin = EDX;

	EAX = syswork_sel;
	ECX = all_sel;
	PUSH(DS);
	PUSH(ES);
	ES = AX;
	DS = CX;
	EDX = [ES:32 + empty01_ent + 0x0c];
	EBX = 0x100000;
	ECX = 512 / 4;
	do {
		EAX = [DS:EDX];
		EDX += 4;
		[DS:EBX] = EAX;
		EBX += 4;
		ECX--;
	} while (!= 0);
	EDX = [ES:32 + empty00_ent + 0x0c];
	EBX = 0x101000;
	EDX += 512; // ヘッダを読み飛ばす
	ECX = [ES:32 + empty00_ent + 0x08];
	ECX += 1024 - 512 - 1;
	ECX &= 0xfffffc00; // KB単位に切り上げ
	(unsigned int) ECX /= 4;
	do {
		EAX = [DS:EDX];
		EDX += 4;
		[DS:EBX] = EAX;
		EBX += 4;
		ECX--;
	} while (!= 0);
	ECX = [ES:32 + empty00_ent + 0x08];
	ECX += 1024 - 512 - 1;
	ECX &= 0xfffffc00; // KB単位に切り上げ
	EAX = ECX;
	(unsigned int) ECX /= 256;
	ECX += 18 * 4;
	(short) [DS:0x100020] = CX;
	POP(ES);
	POP(DS);

	work->dosload_size0 = EAX;

	// IPL
	asmout("MOV EAX,OFFSET #pass00");
	work->dosload_phase = EAX;
	EAX = 0x02010000; // CHRN(NRHC)
	ECX = 512;
	EDX = 0x100000;
	EDI = work->dosload_sigtmp;
	FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
	goto pass99;
pass00:
	PUSH(DS);
	EAX = all_sel;
	DS = AX;
	AL = [DS:0x1001fc];
	POP(DS);
	TEST(AL, 1);
	if (!= 0)
		goto format4K;

	// track:02
	asmout("MOV EAX,OFFSET #pass01");
	work->dosload_phase = EAX;
	EAX = 0x03700001; // CHRN(NRHC)
	ECX = 1024 * 11;
	work->dosload_size0 -= ECX;
	if ((unsigned) < 0)
		ECX += work->dosload_size0;
	EDX = 0x101000;
	EDI = work->dosload_sigtmp;
	FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
	goto pass99;
pass01:
	if ((signed) work->dosload_size0 > 0) {
		// track:03
		asmout("MOV EAX,OFFSET #pass02");
		work->dosload_phase = EAX;
		EAX = 0x03700101; // CHRN(NRHC)
		ECX = 1024 * 11;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x103c00;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass02:
	if ((signed) work->dosload_size0 > 0) {
		// track:04
		asmout("MOV EAX,OFFSET #pass03");
		work->dosload_phase = EAX;
		EAX = 0x03700002; // CHRN(NRHC)
		ECX = 1024 * 11;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x106800;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass03:
	if ((signed) work->dosload_size0 > 0) {
		// track:05
		asmout("MOV EAX,OFFSET #pass04");
		work->dosload_phase = EAX;
		EAX = 0x03700102; // CHRN(NRHC)
		ECX = 1024 * 11;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x109400;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass04:
	if ((signed) work->dosload_size0 > 0) {
		// track:06
		asmout("MOV EAX,OFFSET #pass05");
		work->dosload_phase = EAX;
		EAX = 0x03700003; // CHRN(NRHC)
		ECX = 1024 * 11;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x10c000;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass05:
	if ((signed) work->dosload_size0 > 0) {
		// track:07
		asmout("MOV EAX,OFFSET #pass05_2");
		work->dosload_phase = EAX;
		EAX = 0x03700103; // CHRN(NRHC)
		ECX = 1024 * 5;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x10ec00;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass05_2:
	if ((signed) work->dosload_size0 > 0) {
		// track:07
		asmout("MOV EAX,OFFSET #pass06");
		work->dosload_phase = EAX;
		EAX = 0x03750103; // CHRN(NRHC)
		ECX = 1024 * 6;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x110000;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass06:
	EAX = 0;
	ECX = 20;
	do {
	//	work->track[ECX - 4] = EAX;
		[ECX - 4 + work->track] = EAX;
		ECX -= 4;
	} while (!= 0);

	work->dosload_phase = 0;
	AX = SS;
	PUSH(FS);
	PUSH((int) 0); // eoc
	PUSH(work->dosload_sigfin);
	PUSH(0x1241);
	PUSH(0x0114 /* コマンドシグナル直接 */);
	FS = AX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	ESP += 4 * 4;
	POP(FS);
pass99:
	return;

format4K:
	/* track */ work->dosload_FAT = 2;
	do {
		asmout("MOV EAX,OFFSET #pass90");
		work->dosload_phase = EAX;
		ECX = /* track */ work->dosload_FAT;
		PUSH(DS);
		EAX = ECX;
		EDX = all_sel;
		AH = AL;
		DS = DX;
		(unsigned char) AL /= 2;
		AH &= 0x01;

		// 2〜5
		PUSH(EAX); // トラック間スキューをかける
		EAX = ECX;
		BL = 3;
		DIV(BL);
		EDX = (unsigned char) AH;
		POP(EAX);
		EDX <<= 16;
		EAX |= 0x057c0000;
		EDI = 0x00050305;
		ECX = 3;

		EAX += EDX; // スキューファクター加算
		EDX = 0x100400;
		do {
			[DS:EDX] = EAX;
			EDX += 4;
			EAX += 0x00010000;
			EBX = EAX;
			EBX &= 0x00ff0000;
			if (EBX == 0x007f0000)
				EAX &= 0xff7cffff;
			ECX--;
		} while (!= 0);
		POP(DS);
		ECX = work->dosload_sigtmp;
		EDX = 0x100400;
		FDC_MC_test5();
		goto pass99;
pass90:
		EAX = /* track */ work->dosload_FAT;
		EAX++;
		/* track */ work->dosload_FAT = EAX;
	} while ((unsigned) EAX < 6);

	// track:02
	asmout("MOV EAX,OFFSET #pass91");
	work->dosload_phase = EAX;
	EAX = 0x057c0001; // CHRN(NRHC)
	ECX = 1024 * 12;
	work->dosload_size0 -= ECX;
	if ((unsigned) < 0)
		ECX += work->dosload_size0;
	EDX = 0x101000;
	EDI = work->dosload_sigtmp;
	FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
	goto pass99;
pass91:
	if ((signed) work->dosload_size0 > 0) {
		// track:03
		asmout("MOV EAX,OFFSET #pass92");
		work->dosload_phase = EAX;
		EAX = 0x057c0101; // CHRN(NRHC)
		ECX = 1024 * 12;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x104000;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass92:
	if ((signed) work->dosload_size0 > 0) {
		// track:04
		asmout("MOV EAX,OFFSET #pass93");
		work->dosload_phase = EAX;
		EAX = 0x057c0002; // CHRN(NRHC)
		ECX = 1024 * 12;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x107000;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
pass93:
	if ((signed) work->dosload_size0 > 0) {
		// track:05
		asmout("MOV EAX,OFFSET #pass04");
		work->dosload_phase = EAX;
		EAX = 0x057c0102; // CHRN(NRHC)
		ECX = 1024 * 12;
		work->dosload_size0 -= ECX;
		if ((unsigned) < 0)
			ECX += work->dosload_size0;
		EDX = 0x10a000;
		EDI = work->dosload_sigtmp;
		FDC_MC_test6(); // トラック、64KB境界をまたがないことが前提
		goto pass99;
	}
	goto pass04;
}

void near FDC_loadFAT()
// ECX:作業中のシグナル
// EDX:完了のシグナル
{
	unsigned int tapi_sel == 12 * 8;
	FDC_WORK *work == DS:0;

	if (work->dosload_phase != 0) {
		INT(0x03);
	}

	// 依頼された値をworkに保存しておく
	work->dosload_sigtmp = ECX;
	work->dosload_sigfin = EDX;

//	EAX = 0;
//	ECX = 20;
//	do {
//	//	work->track[ECX - 4] = EAX;
//		[ECX - 4 + work->track] = EAX;
//		ECX -= 4;
//	} while (!= 0);

	// トラック0のロード
	EAX = work->track[0];
	TEST(AL, 0x01);
	if (== 0) {
		asmout("MOV EAX,OFFSET #pass00");
		work->dosload_phase = EAX;
		EAX = 0x0000; // C:0, H:0
		ECX = work->dosload_sigtmp;
		EDX = 0x100000;
		FDC_MC_test4();
		goto pass99;
pass00:
	//	work->track[0] |= 0x01;
		EAX = work->track[0];
	}

	// トラック1のロード
	TEST(AL, 0x02);
	if (== 0) {
		asmout("MOV EAX,OFFSET #pass01");
		work->dosload_phase = EAX;
		EAX = 0x0100; // C:0, H:1
		ECX = work->dosload_sigtmp;
		EDX = 0x102400;
		FDC_MC_test4();
		goto pass99;
pass01:
	//	work->track[0] |= 0x02;
	//	EAX = work->track[0];
	}
	work->track[0] |= 0x03;
	work->dosload_phase = 0;

	AX = SS;
	PUSH(FS);
	PUSH((int) 0); // eoc
	PUSH(work->dosload_sigfin);
	PUSH(0x1241);
	PUSH(0x0114 /* コマンドシグナル直接 */);
	FS = AX;
	EBX = ESP;
	DB(0x9a); DD(0); DW((short) tapi_sel);
	ESP += 4 * 4;
	POP(FS);
pass99:
	return;
}
