/* "VGADRV0.ASK" for TOWNS ver.1.2 copyright(C) 2002 川合秀実, I.Tak. */

/* TWVSW is... TOWNS Vertial Screen Width! */
#define TWVSW 	1024	/* must be multiple of 8 */

#if (TWVSW & (TWVSW - 1))	/* TWVSW is not 0 nor power of 2. */
	#undef  TWVSWlog2
	#define IMUL_TWVSW(reg)		IMUL(reg, TWVSW);
	#define CRTC28	0x803f
#else
	#define TWVSWlog2 10		/* log2(TWVSW) */
	#define IMUL_TWVSW(reg)		reg *= TWVSW;
	#define CRTC28	0x800f
#endif

segment GapiMdl(USE32, PARA);

default(code == GapiMdl);

struct WORK_SUB {
	unsigned int scr_x0, scr_width, scr_y0, scr_height;
};

struct GAPI_WORK {
	signed int mx, my, mx0, my0, mx1, my1;
	int cursor_addr, pattern_addr;
//	int backup_addr;
//	int p, q, b;
	unsigned int lockcount, mouselock; /* +32 */
	char mouseflag, maskflag, mouseline, V86flag;
//	int mouseline, masktype;
//	int taskcount, nextcount;
	int VGA_mode;
	short V86CS, V86SS, [4], [8];
	int backup_buf[320]; /* +64 */
	int mouse_pattern[2560 /* 0x0a00 */]; /* +0x0180 */
	WORK_SUB worksub;
	void [1136];
	/* 以上4KB */
};

void far GAPI_entry()
/* 必ず、EFLAGS.IF == 1で呼ぶこと */
{
	goto syscmd;
	ORG(0x0008);
	ORG(0x0010);
	asmout("DD OFFSET #syscmd, 0, 0, 0");
	DD(4096); /* 初期化時に必要なワークエリアサイズ */
	DD(0); /* 最大ローカルスタック消費量 */
	ORG(0x0040);
syscmd:
	GAPI_WORK *work == ES:0x0000;

	int all_sel == 1 * 8;
	int *cmd == FS:EBX;

	asmout("#GAPI_accesslock EQU GAPI_accesslock");
	asmout("#GAPI_mouse EQU GAPI_mouse");
	asmout("#GAPI_line EQU GAPI_line");
	asmout("#GAPI_fontwrite EQU GAPI_fontwrite");
	asmout("#GAPI_init EQU GAPI_init");
	asmout("#GAPI_VGA640 EQU GAPI_VGA640");
	asmout("#GAPI_resetdevice EQU GAPI_resetdevice");
	asmout("#GAPI_error EQU GAPI_error");
	asmout("#GAPI_putbox EQU GAPI_putbox");
	asmout("#GAPI_lineardots EQU GAPI_lineardots");
	asmout("#GAPI_points EQU GAPI_points");

	PUSH(DS);
	PUSH(ES);
	PUSHAD();
	EAX = all_sel;
	MOV(ECX, CS);
	DS = EAX;
	ECX += 8;
	ES = ECX;

asmout("next_command:");

	EAX = cmd[0];
	if (EAX == 0x0184)
		goto GAPI_accesslock;
	if (EAX == 0x0101)
		goto GAPI_fontwrite;
	if (EAX == 0x0108)
		goto GAPI_putbox;
	if (EAX == 0x0100)
		goto GAPI_line;
	if (EAX == 0x010c)
		goto GAPI_lineardots;
	if (EAX == 0x0110)
		goto GAPI_points;
	if (EAX == 0x0180)
		goto GAPI_mouse;
	if (EAX == 0x0010)
		goto GAPI_init;
	if (EAX == 0x001c)
		goto GAPI_resetdevice;
	if (EAX == 0x0104)
		goto fontload;
//	if (EAX == 0x0108)
//		goto allocarea; /* cmd, opt, size, (addr) */
	if (EAX == 0x0140)
		goto font_attr; /* cmd, opt, type, (param0), (param1), (param2), (param3) */

	if (EAX != 0)
		goto GAPI_error;

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

fontload:
	/* cmd, opt, type, len, to, from */
	PUSH(DS);
	asmout("LDS ESI,FWORD PTR FS:[EBX+20]");
	EAX = cmd[ 8]; /* type */
	ECX = cmd[12]; /* len */
	EDI = cmd[16]; /* to */
	(offset) cmd += 28;
	if (EAX <= 2) {
		LEA(ECX, [ECX * 2]);
		if (!=)
			ECX *= 2;
		do {
			EAX = [DS:ESI];
			ESI += 4;
			[ES:EDI] = EAX;
			EDI += 4;
			ECX--;
		} while (!= 0);
		POP(DS);
		asmout("JMP next_command");
	}
	if (EAX <= 4) {
		/* EAX == 3:4bit color 8x16 */
		/* EAX == 4:4bit color 8x8 */
		LEA(ECX, [ECX * 8]);
		if (!=)
			ECX *= 2;
		do {
			EDX = [DS:ESI]; /* 8dots */
			ESI += 4;
			AH = DH;
			AL = DH;
			(unsigned char) AH >>= 4;
			EAX <<= 16;
			AH = DL;
			AL = DL;
			(unsigned char) AH >>= 4;
			EAX &= 0x0f0f0f0f;
			[ES:EDI] = EAX;
			(unsigned int) EDX >>= 16;
			AH = DH;
			AL = DH;
			(unsigned char) AH >>= 4;
			EAX <<= 16;
			AH = DL;
			AL = DL;
			(unsigned char) AH >>= 4;
			EAX &= 0x0f0f0f0f;
			[ES:EDI + 4] = EAX;
			EDI += 8;
			ECX--;
		} while (!= 0);
		POP(DS);
		asmout("JMP next_command");
	}
	INT(0x03);

font_attr:
	/* cmd, opt, type, (param0), (param1), (param2), (param3) */
	EAX = cmd[ 8]; /* type */
	asmout("MOV AL,BYTE PTR CS:[#font_attr_table][EAX-1]");
	(char) cmd[12] = AL;
	(offset) cmd += 28;
	asmout("JMP next_command");
font_attr_table:
	DB(4 /*  16bytes/font (8x16 mono) */);
	DB(3 /*   8bytes/font (8x 8 mono half height) */);
	DB(7 /* 128bytes/font (8x16 4bit color) */);
	DB(6 /*  64bytes/font (8x 8 4bit color half height) */);
}

/* マウスには非表示カウントというのがある
   これが0からnon-0になったときや、non-0から0になったときに、描画・待避を行なう */

void near GAPI_fontwrite()
{
	/* 8x16のフォントを描画(背景色付き) */

	int *cmd == FS:EBX;

	/* opt	bit0:full higth/half height
			bit1-7:	0000000 mono font col&bcol
					0000001 4bit color font
	*/

	if ((unsigned) cmd[4] >= 2)
		goto opt2;
	EAX = cmd[ 8]; /* x */
	ESI = cmd[12]; /* y */
	TEST(AL, 0x03);
	if (!= 0)
		goto error; /* 4の倍数以外はまだサポートしてない */

	IMUL_TWVSW(ESI);
	ESI += EAX;

	int *font == ES:EDI;
	EAX = (unsigned char) cmd[20]; /* bgcolor */
	EDX = EAX;
	EAX <<= 8;
	EDX |= EAX;
	EAX = EDX;
	EDX <<= 16;
	EAX |= EDX;
	PUSH(EAX);

	EAX = (unsigned char) cmd[16]; /* color */
	EDX = EAX;
	EAX <<= 8;
	EDX |= EAX;
	EAX = EDX;
	EDX <<= 16;
	EAX |= EDX;
	POP(EDX);
	EBP = EAX;

	/* EBP:col, EDX:bgcol */
	PUSH(EBP); // 1111
	EAX = EBP; ECX = EDX; EAX &= 0x00ffffff; ECX &= 0xff000000; EAX |= ECX; PUSH(EAX); // 1110
	EAX = EBP; ECX = EDX; EAX &= 0xff00ffff; ECX &= 0x00ff0000; EAX |= ECX; PUSH(EAX); // 1101
	EAX = EBP; ECX = EDX; EAX &= 0x0000ffff; ECX &= 0xffff0000; EAX |= ECX; PUSH(EAX); // 1100
	EAX = EBP; ECX = EDX; EAX &= 0xffff00ff; ECX &= 0x0000ff00; EAX |= ECX; PUSH(EAX); // 1011
	EAX = EBP; ECX = EDX; EAX &= 0x00ff00ff; ECX &= 0xff00ff00; EAX |= ECX; PUSH(EAX); // 1010
	EAX = EBP; ECX = EDX; EAX &= 0xff0000ff; ECX &= 0x00ffff00; EAX |= ECX; PUSH(EAX); // 1001
	EAX = EBP; ECX = EDX; EAX &= 0x000000ff; ECX &= 0xffffff00; EAX |= ECX; PUSH(EAX); // 1000
	EAX = EBP; ECX = EDX; EAX &= 0xffffff00; ECX &= 0x000000ff; EAX |= ECX; PUSH(EAX); // 0111
	EAX = EBP; ECX = EDX; EAX &= 0x00ffff00; ECX &= 0xff0000ff; EAX |= ECX; PUSH(EAX); // 0110
	EAX = EBP; ECX = EDX; EAX &= 0xff00ff00; ECX &= 0x00ff00ff; EAX |= ECX; PUSH(EAX); // 0101
	EAX = EBP; ECX = EDX; EAX &= 0x0000ff00; ECX &= 0xffff00ff; EAX |= ECX; PUSH(EAX); // 0100
	EAX = EBP; ECX = EDX; EAX &= 0xffff0000; ECX &= 0x0000ffff; EAX |= ECX; PUSH(EAX); // 0011
	EAX = EBP; ECX = EDX; EAX &= 0x00ff0000; ECX &= 0xff00ffff; EAX |= ECX; PUSH(EAX); // 0010
	EAX = EBP; ECX = EDX; EAX &= 0xff000000; ECX &= 0x00ffffff; EAX |= ECX; PUSH(EAX); // 0001
	PUSH(EDX); // 0000

//	ES = [FS:EBX + 28];
	/* fontsizeチェックはしなくなった。その方が速い。
	   チェックが必要なら、上位ルーチンでやる。 */

	int *string == FS:EBP;
	ECX = cmd[32]; // length

	if (cmd[4] != 0)
		goto opt1;

	LEA((offset) string, [EBX + 36]);
//	LEA(EBX, [EBX + ECX * 4 + 36]);

	do {
		PUSH(ECX);
		(offset) font = *string;
		(offset) string += 4;
		ECX = 4;
		do {
			EBX = *font; /* 4lines */
			(offset) font += 4;
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 0] = EAX;
			ESI += TWVSW * 4;
			ECX--;
		} while (!= 0);
		POP(ECX);
		ESI -= TWVSW * 16 - 8;
		ECX--;
	} while (!= 0);
	ESP += 64;
	(offset) cmd = (offset) string;
//	AX = CS;
//	AX += 8;
//	ES = AX;

	asmout("JMP next_command");

opt1:
	/* half height */
	LEA((offset) string, [EBX + 36]);
//	LEA(EBX, [EBX + ECX * 4 + 36]);

	do {
		PUSH(ECX);
		(offset) font = *string;
		(offset) string += 4;
		ECX = 2;
		do {
			EBX = *font; /* 4lines */
			(offset) font += 4;
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 0] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			EDX = EBX;
			(unsigned int) EBX /= 16;
			EDX &= 0x0f;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 4] = EAX;

			EAX = [SS:ESP + EDX * 4 + 4];
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 0] = EAX;
			ESI += TWVSW * 4;
			ECX--;
		} while (!= 0);
		POP(ECX);
		ESI -= TWVSW * 8 - 8;
		ECX--;
	} while (!= 0);
	ESP += 64;
	(offset) cmd = (offset) string;
	asmout("JMP next_command");

opt2:
	EAX = cmd[ 8]; /* x */
	ESI = cmd[12]; /* y */
	TEST(AL, 0x03);
	if (!= 0)
		goto error; /* 4の倍数以外はまだサポートしてない */

	IMUL_TWVSW(ESI);
	ESI += EAX;

//	int *font == ES:EDI;
//	int *string == FS:EBP;
	ECX = cmd[32]; // length

	if (cmd[4] != 2)
		goto opt3;

	LEA((offset) string, [EBX + 36]);
//	LEA(EBX, [EBX + ECX * 4 + 36]);

	do {
		PUSH(ECX);
		(offset) font = *string;
		(offset) string += 4;
		ECX = 4;
		do {
			EAX = font[ 0]; /* 4dots */
			EDX = font[ 4];
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 4] = EDX;
			EAX = font[ 8]; /* 4dots */
			EDX = font[12];
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 4] = EDX;
			EAX = font[16]; /* 4dots */
			EDX = font[20];
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 4] = EDX;
			EAX = font[24]; /* 4dots */
			EDX = font[28];
			(offset) font += 32;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 4] = EDX;
			ESI += TWVSW * 4;
			ECX--;
		} while (!= 0);
		POP(ECX);
		ESI -= TWVSW * 16 - 8;
		ECX--;
	} while (!= 0);
	(offset) cmd = (offset) string;
	asmout("JMP next_command");

opt3:
	/* half height */
	LEA((offset) string, [EBX + 36]);
//	LEA(EBX, [EBX + ECX * 4 + 36]);

	do {
		PUSH(ECX);
		(offset) font = *string;
		(offset) string += 4;
		ECX = 2;
		do {
			EAX = font[ 0]; /* 4dots */
			EDX = font[ 4];
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  0 + 4] = EDX;
			EAX = font[ 8]; /* 4dots */
			EDX = font[12];
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  1 + 4] = EDX;
			EAX = font[16]; /* 4dots */
			EDX = font[20];
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  2 + 4] = EDX;
			EAX = font[24]; /* 4dots */
			EDX = font[28];
			(offset) font += 32;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 0] = EAX;
			[DS:ESI + 0xe0000000 + TWVSW *  3 + 4] = EDX;
			ESI += TWVSW * 4;
			ECX--;
		} while (!= 0);
		POP(ECX);
		ESI -= TWVSW * 8 - 8;
		ECX--;
	} while (!= 0);
	(offset) cmd = (offset) string;
	asmout("JMP next_command");

error:
	INT(0x03);
}

void near GAPI_line()
{
	int *cmd == FS:EBX;

	EAX = cmd[4]; /* opt */
	TEST(EAX, 0xffffff0f);
	if (!= 0)
		goto error;

	EAX &= 0x0030;
	if (== 0)
		goto line;

	if (EAX == 0x0020) {
		/* boxfill */
		EBP = cmd[20]; /* y1 */
		ESI = cmd[12]; /* y0 */
		EBP -= ESI;
		IMUL_TWVSW(ESI);
boxfill:
		EDX = cmd[ 8]; /* x0 */
		EDI = cmd[16]; /* x1 */
	//	ESI += EDX + 0xe0000000;
		LEA(ESI, [ESI + EDX + 0xe0000000]);
		EDI++;
		CL = cmd[ 4]; /* opt */
		AL = cmd[24]; /* color */
		CL &= 0xc0;
		AH = AL;
		EDI -= EDX;
		EDX = (unsigned short) AX;
		EAX <<= 16;
		/* EDI : x方向のサイズ(バイト数) */
		/* EBP : y方向のサイズ(ドット数 - 1) */
		/* ESI : VRAM上のアドレス */
		EBP++;
		EAX |= EDX;
		/* 少し工夫した描画ルーチン */
		/* 縦に描いていく */
		PUSH((offset) cmd);
		if (CL == 0) {
			if ((unsigned) EBP >= 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						ECX = EBP;
						EBX = ESI;
						ECX -= 8;
						if ((unsigned) >= 0) {
							do {
								[DS:ESI + TWVSW * 0] = AL;
								[DS:ESI + TWVSW * 1] = AL;
								[DS:ESI + TWVSW * 2] = AL;
								[DS:ESI + TWVSW * 3] = AL;
								[DS:ESI + TWVSW * 4] = AL;
								[DS:ESI + TWVSW * 5] = AL;
								[DS:ESI + TWVSW * 6] = AL;
								[DS:ESI + TWVSW * 7] = AL;
								ESI += TWVSW * 8;
								ECX -= 8;
							} while ((unsigned) > 0);
						}
						ECX += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] = AL;
								ESI += TWVSW;
								ECX--;
							} while (!= 0);
						}
						EDI--;
						LEA(ESI, [EBX + 1]);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				EDI -= 4;
				if ((unsigned) >= 0) {
					do {
						ECX = EBP;
						EBX = ESI;
						ECX -= 8;
						if ((unsigned) >= 0) {
							do {
								[DS:ESI + TWVSW * 0] = EAX;
								[DS:ESI + TWVSW * 1] = EAX;
								[DS:ESI + TWVSW * 2] = EAX;
								[DS:ESI + TWVSW * 3] = EAX;
								[DS:ESI + TWVSW * 4] = EAX;
								[DS:ESI + TWVSW * 5] = EAX;
								[DS:ESI + TWVSW * 6] = EAX;
								[DS:ESI + TWVSW * 7] = EAX;
								ESI += TWVSW * 8;
								ECX -= 8;
							} while ((unsigned) > 0);
						}
						ECX += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] = EAX;
								ESI += TWVSW;
								ECX--;
							} while (!= 0);
						}
						EDI -= 4;
						LEA(ESI, [EBX + 4]);
					} while ((unsigned) >= 0);
				}
				EDI += 4;
				if (!= 0) {
					/* 手抜き */
					do {
						ECX = EBP;
						EBX = ESI;
						ECX -= 8;
						if ((unsigned) >= 0) {
							do {
								[DS:ESI + TWVSW * 0] = AL;
								[DS:ESI + TWVSW * 1] = AL;
								[DS:ESI + TWVSW * 2] = AL;
								[DS:ESI + TWVSW * 3] = AL;
								[DS:ESI + TWVSW * 4] = AL;
								[DS:ESI + TWVSW * 5] = AL;
								[DS:ESI + TWVSW * 6] = AL;
								[DS:ESI + TWVSW * 7] = AL;
								ESI += TWVSW * 8;
								ECX -= 8;
							} while ((unsigned) > 0);
						}
						ECX += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] = AL;
								ESI += TWVSW;
								ECX--;
							} while (!= 0);
						}
						EDI--;
						LEA(ESI, [EBX + 1]);
					} while (!= 0);
				}
				POP((offset) cmd);
				(offset) cmd += 28;
				asmout("JMP next_command");
			}
		//	if ((unsigned) EBP < 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						ECX = EBP;
						EBX = ESI;
						do {
							[DS:ESI           ] = AL;
							ESI += TWVSW;
							ECX--;
						} while (!= 0);
						EDI--;
						LEA(ESI, [EBX + 1]);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				do {
					PUSH(EDI);
					EBX = ESI;
					EDI -= 32;
					if ((unsigned) >= 0) {
						do {
							[DS:ESI     ] = EAX;
							[DS:ESI +  4] = EAX;
							[DS:ESI +  8] = EAX;
							[DS:ESI + 12] = EAX;
							[DS:ESI + 16] = EAX;
							[DS:ESI + 20] = EAX;
							[DS:ESI + 24] = EAX;
							[DS:ESI + 28] = EAX;
							ESI += 32;
							EDI -= 32;
						} while ((unsigned) >= 0);
					}
					EDI += 32 - 4;
					if ((signed) >= 0) {
						do {
							[DS:ESI] = EAX;
							ESI += 4;
							EDI -= 4;
						} while ((unsigned) >= 0);
					}
					EDI += 4;
					if (!= 0) {
						do {
							[DS:ESI] = AL;
							ESI++;
							EDI--;
						} while (!= 0);
					}
					LEA(ESI, [EBX + TWVSW]);
					POP(EDI);
					EBP--;
				} while (!= 0);
				POP((offset) cmd);
				(offset) cmd += 28;
				asmout("JMP next_command");
	//		}
		}
		if (CL == 0xc0) { /* xor */
			if ((unsigned) EBP >= 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] ^= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						LEA(ESI, [EBX + 1]);
						POP(EBP);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				EDI -= 4;
				if ((unsigned) >= 0) {
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								ECX = [DS:ESI + TWVSW * 0];	EDX = [DS:ESI + TWVSW * 1];
								ECX ^= EAX;					EDX ^= EAX;
								[DS:ESI + TWVSW * 0] = ECX;	[DS:ESI + TWVSW * 1] = EDX;
								ECX = [DS:ESI + TWVSW * 2];	EDX = [DS:ESI + TWVSW * 3];
								ECX ^= EAX;					EDX ^= EAX;
								[DS:ESI + TWVSW * 2] = ECX;	[DS:ESI + TWVSW * 3] = EDX;
								ECX = [DS:ESI + TWVSW * 4];	EDX = [DS:ESI + TWVSW * 5];
								ECX ^= EAX;					EDX ^= EAX;
								[DS:ESI + TWVSW * 4] = ECX;	[DS:ESI + TWVSW * 5] = EDX;
								ECX = [DS:ESI + TWVSW * 6];	EDX = [DS:ESI + TWVSW * 7];
								ECX ^= EAX;					EDX ^= EAX;
								[DS:ESI + TWVSW * 6] = ECX;	[DS:ESI + TWVSW * 7] = EDX;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] ^= EAX;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						POP(EBP);
						EDI -= 4;
						LEA(ESI, [EBX + 4]);
					} while ((unsigned) >= 0);
				}
				EDI += 4;
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL ^= AL;					DL ^= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] ^= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						POP(EBP);
						LEA(ESI, [EBX + 1]);
					} while (!= 0);
				}
				POP((offset) cmd);
				(offset) cmd += 28;
				asmout("JMP next_command");
			}
		//	if ((unsigned) EBP < 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						ECX = EBP;
						EBX = ESI;
						do {
							[DS:ESI           ] ^= AL;
							ESI += TWVSW;
							ECX--;
						} while (!= 0);
						EDI--;
						LEA(ESI, [EBX + 1]);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				do {
					PUSH(EDI);
					EBX = ESI;
					EDI -= 32;
					if ((unsigned) >= 0) {
						do {
							ECX = [DS:ESI     ];	EDX = [DS:ESI +  4];
							ECX ^= EAX;				EDX ^= EAX;
							[DS:ESI     ] = ECX;	[DS:ESI +  4] = EDX;
							ECX = [DS:ESI +  8];	EDX = [DS:ESI + 12];
							ECX ^= EAX;				EDX ^= EAX;
							[DS:ESI +  8] = ECX;	[DS:ESI + 12] = EDX;
							ECX = [DS:ESI + 16];	EDX = [DS:ESI + 20];
							ECX ^= EAX;				EDX ^= EAX;
							[DS:ESI + 16] = ECX;	[DS:ESI + 20] = EDX;
							ECX = [DS:ESI + 24];	EDX = [DS:ESI + 28];
							ECX ^= EAX;				EDX ^= EAX;
							[DS:ESI + 24] = ECX;	[DS:ESI + 28] = EDX;
							ESI += 32;
							EDI -= 32;
						} while ((unsigned) >= 0);
					}
					EDI += 32 - 4;
					if ((signed) >= 0) {
						do {
							[DS:ESI] ^= EAX;
							ESI += 4;
							EDI -= 4;
						} while ((unsigned) >= 0);
					}
					EDI += 4;
					if (!= 0) {
						do {
							[DS:ESI] ^= AL;
							ESI++;
							EDI--;
						} while (!= 0);
					}
					LEA(ESI, [EBX + TWVSW]);
					POP(EDI);
					EBP--;
				} while (!= 0);
				POP((offset) cmd);
				(offset) cmd += 28;
				asmout("JMP next_command");
	//		}
		}
		if (CL == 0x40) { /* and */
	//		if ((unsigned) EBP >= 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] &= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						LEA(ESI, [EBX + 1]);
						POP(EBP);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				EDI -= 4;
				if ((unsigned) >= 0) {
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								ECX = [DS:ESI + TWVSW * 0];	EDX = [DS:ESI + TWVSW * 1];
								ECX &= EAX;					EDX &= EAX;
								[DS:ESI + TWVSW * 0] = ECX;	[DS:ESI + TWVSW * 1] = EDX;
								ECX = [DS:ESI + TWVSW * 2];	EDX = [DS:ESI + TWVSW * 3];
								ECX &= EAX;					EDX &= EAX;
								[DS:ESI + TWVSW * 2] = ECX;	[DS:ESI + TWVSW * 3] = EDX;
								ECX = [DS:ESI + TWVSW * 4];	EDX = [DS:ESI + TWVSW * 5];
								ECX &= EAX;					EDX &= EAX;
								[DS:ESI + TWVSW * 4] = ECX;	[DS:ESI + TWVSW * 5] = EDX;
								ECX = [DS:ESI + TWVSW * 6];	EDX = [DS:ESI + TWVSW * 7];
								ECX &= EAX;					EDX &= EAX;
								[DS:ESI + TWVSW * 6] = ECX;	[DS:ESI + TWVSW * 7] = EDX;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] &= EAX;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						POP(EBP);
						EDI -= 4;
						LEA(ESI, [EBX + 4]);
					} while ((unsigned) >= 0);
				}
				EDI += 4;
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL &= AL;					DL &= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] &= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						POP(EBP);
						LEA(ESI, [EBX + 1]);
					} while (!= 0);
				}
	//		}
			POP((offset) cmd);
			(offset) cmd += 28;
			asmout("JMP next_command");
		}
//		if (CL == 0x80) { /* or */
	//		if (EBP >= 8) {
				TEST(ESI, 0x03);
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] |= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						LEA(ESI, [EBX + 1]);
						POP(EBP);
						if (== 0)
							goto line_fin;
						TEST(ESI, 0x03);
					} while (!= 0);
				}
				EDI -= 4;
				if ((unsigned) >= 0) {
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								ECX = [DS:ESI + TWVSW * 0];	EDX = [DS:ESI + TWVSW * 1];
								ECX |= EAX;					EDX |= EAX;
								[DS:ESI + TWVSW * 0] = ECX;	[DS:ESI + TWVSW * 1] = EDX;
								ECX = [DS:ESI + TWVSW * 2];	EDX = [DS:ESI + TWVSW * 3];
								ECX |= EAX;					EDX |= EAX;
								[DS:ESI + TWVSW * 2] = ECX;	[DS:ESI + TWVSW * 3] = EDX;
								ECX = [DS:ESI + TWVSW * 4];	EDX = [DS:ESI + TWVSW * 5];
								ECX |= EAX;					EDX |= EAX;
								[DS:ESI + TWVSW * 4] = ECX;	[DS:ESI + TWVSW * 5] = EDX;
								ECX = [DS:ESI + TWVSW * 6];	EDX = [DS:ESI + TWVSW * 7];
								ECX |= EAX;					EDX |= EAX;
								[DS:ESI + TWVSW * 6] = ECX;	[DS:ESI + TWVSW * 7] = EDX;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] |= EAX;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						POP(EBP);
						EDI -= 4;
						LEA(ESI, [EBX + 4]);
					} while ((unsigned) >= 0);
				}
				EDI += 4;
				if (!= 0) {
					/* 手抜き */
					do {
						PUSH(EBP);
						EBX = ESI;
						EBP -= 8;
						if ((unsigned) >= 0) {
							do {
								CL = [DS:ESI + TWVSW * 0];	DL = [DS:ESI + TWVSW * 1];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 0] = CL;	[DS:ESI + TWVSW * 1] = DL;
								CL = [DS:ESI + TWVSW * 2];	DL = [DS:ESI + TWVSW * 3];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 2] = CL;	[DS:ESI + TWVSW * 3] = DL;
								CL = [DS:ESI + TWVSW * 4];	DL = [DS:ESI + TWVSW * 5];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 4] = CL;	[DS:ESI + TWVSW * 5] = DL;
								CL = [DS:ESI + TWVSW * 6];	DL = [DS:ESI + TWVSW * 7];
								CL |= AL;					DL |= AL;
								[DS:ESI + TWVSW * 6] = CL;	[DS:ESI + TWVSW * 7] = DL;
								ESI += TWVSW * 8;
								EBP -= 8;
							} while ((unsigned) > 0);
						}
						EBP += 8;
						if (!= 0) {
							do {
								[DS:ESI           ] |= AL;
								ESI += TWVSW;
								EBP--;
							} while (!= 0);
						}
						EDI--;
						POP(EBP);
						LEA(ESI, [EBX + 1]);
					} while (!= 0);
				}
	//		}
line_fin:
			POP((offset) cmd);
			(offset) cmd += 28;
			asmout("JMP next_command");
//		}


	}

	/* box */
	EBP = cmd[20]; // y1
	ESI = cmd[12]; // y0
	EBP -= ESI;
	IMUL_TWVSW(ESI);
	if ((unsigned) EBP <= 1)
		goto boxfill;
	PUSH(ESI);
	EDX = cmd[ 8]; // x0
	EDI = cmd[16]; // x1
//	ESI += EDX + 0xe0000000;
	LEA(ESI, [ESI + EDX + 0xe0000000]);
	EDI++;
	CL = cmd[ 4]; // opt
	AL = cmd[24]; // color
	CL &= 0xc0;
	EDI -= EDX;
	/* EDI : x方向のサイズ(バイト数) */
	/* EBP : y方向のサイズ(ドット数 - 1) */
	/* ESI : VRAM上のアドレス */
	EBP--;
	EDX = cmd[20];
	IMUL_TWVSW(EDX);
	EDX += cmd[ 8];
	EDX += 0xe0000000;
	if (CL == 0) { /* pset */
		/* 全く工夫のない描画ルーチン */
		ECX = ESI;
		do {
			[DS:ESI] = AL;
			ESI++;
			[DS:EDX] = AL;
			EDX++;
			EDI--;
		} while (!= 0);
		POP(EDI);
		ECX += TWVSW;
		EDI += cmd[16];
		EDI += 0xe0000000 + TWVSW;
		do {
			[DS:ECX] = AL;
			ECX += TWVSW;
			[DS:EDI] = AL;
			EDI += TWVSW;
			EBP--;
		} while (!= 0);
		(offset) cmd += 28;
		asmout("JMP next_command");
	}
	if (CL == 0xc0) { /* xor */
		/* 全く工夫のない描画ルーチン */
		ECX = ESI;
		do {
			[DS:ESI] ^= AL;
			ESI++;
			[DS:EDX] ^= AL;
			EDX++;
			EDI--;
		} while (!= 0);
		POP(EDI);
		ECX += TWVSW;
		EDI += cmd[16];
		EDI += 0xe0000000 + TWVSW;
		do {
			[DS:ECX] ^= AL;
			ECX += TWVSW;
			[DS:EDI] ^= AL;
			EDI += TWVSW;
			EBP--;
		} while (!= 0);
		(offset) cmd += 28;
		asmout("JMP next_command");
	}
	if (CL == 0x40) { /* and */
		/* 全く工夫のない描画ルーチン */
		ECX = ESI;
		do {
			[DS:ESI] &= AL;
			ESI++;
			[DS:EDX] &= AL;
			EDX++;
			EDI--;
		} while (!= 0);
		POP(EDI);
		ECX += TWVSW;
		EDI += cmd[16];
		EDI += 0xe0000000 + TWVSW;
		do {
			[DS:ECX] &= AL;
			ECX += TWVSW;
			[DS:EDI] &= AL;
			EDI += TWVSW;
			EBP--;
		} while (!= 0);
		(offset) cmd += 28;
		asmout("JMP next_command");
	}
//	if (CL == 0x80) { /* or */
		/* 全く工夫のない描画ルーチン */
		ECX = ESI;
		do {
			[DS:ESI] |= AL;
			ESI++;
			[DS:EDX] |= AL;
			EDX++;
			EDI--;
		} while (!= 0);
		POP(EDI);
		ECX += TWVSW;
		EDI += cmd[16];
		EDI += 0xe0000000 + TWVSW;
		do {
			[DS:ECX] |= AL;
			ECX += TWVSW;
			[DS:EDI] |= AL;
			EDI += TWVSW;
			EBP--;
		} while (!= 0);
		(offset) cmd += 28;
		asmout("JMP next_command");
//	}

line:
	(offset) cmd += 28;
	asmout("JMP next_command");

error:
	INT(0x03);
}

void near GAPI_putbox()
{
	/* 256色ブロック転送 */
	/* cmd, opt, x0, y0, xsize, ysize, yskip, ofs, sel */

	/* アラインにはまだ配慮していない */

	int *cmd == FS:EBX;
	unsigned char *p == ES:EDI, *q == DS:ESI;

	PUSH(ES);
	PUSH(EBP);
	asmout("LES EDI,FWORD PTR FS:[EBX+28]");
	ESI = cmd[12]; /* y */
	EBP = TWVSW;
	IMUL_TWVSW(ESI);
	ESI += cmd[ 8]; /* x */
	EBP -= cmd[16]; /* xsize */
	EDX = cmd[20]; /* ysize */
	ESI += 0xe0000000;
	AL = (char) cmd[4];
	TEST(AL, 0x10);
	if (!= 0)
		goto putbox1;
	do {
		ECX = cmd[16]; /* xsize */
		do {
			AL = *p;
			(offset) p++;
			*q = AL;
			(offset) q++;
			ECX--;
		} while (!= 0);
		(offset) p += cmd[24]; /* yskip */
		(offset) q += EBP;
		EDX--;
	} while (!= 0);
	(offset) cmd += 36;
	POP(EBP);
	POP(ES);
	asmout("JMP next_command");

putbox1:
	AH = (char) cmd[36];
	do {
		ECX = cmd[16]; /* xsize */
		do {
			AL = *p;
			(offset) p++;
			if (AH != AL)
				*q = AL;
			(offset) q++;
			ECX--;
		} while (!= 0);
		(offset) p += cmd[24]; /* yskip */
		(offset) q += EBP;
		EDX--;
	} while (!= 0);
	(offset) cmd += 40;
	POP(EBP);
	POP(ES);
	asmout("JMP next_command");
}

void near GAPI_linesub_pset()
/*
	ESI : 初期x
	EDI : 初期y
	EDX : 増分値x
	EBX : 増分値y
	EBP : ループ回数
	EAX : カラー
*/
{
	PUSH(EBP);
	PUSH(EAX);
	ECX = EDI;
	EAX = ESI;
	(unsigned int) ECX >>= 16;
	(unsigned int) EAX >>= 16;
	IMUL_TWVSW(ECX);
	LEA(EBP, [EAX + ECX + 0xe0000000]);
	EAX = 0x00010000;
	ECX = 0xffff0000;
	if (EBX == EAX) {
		if (EDX == EAX)
			goto line_xp1_yp1;
		if ((signed) > )
			goto general;
		if (EDX >= 0)
			goto line_xpd_yp1;
		if (EDX == ECX)
			goto line_xm1_yp1;
		if ((signed) < )
			goto line_xmd_yp1;
	} else if (EBX == ECX) {
		if (EDX == EAX)
			goto line_xp1_ym1;
		if ((signed) > )
			goto general;
		if (EDX >= 0)
			goto line_xpd_ym1;
		if (EDX == ECX)
			goto line_xm1_ym1;
		if ((signed) < )
			goto line_xmd_ym1;
	} else if (EDX == EAX) {
	//	if (EBX == EAX)
	//		goto line_xp1_yp1;
		if ((signed) EBX > EAX)
			goto general;
		if (EBX >= 0)
			goto line_xp1_ypd;
	//	if (EBX == ECX)
	//		goto line_xp1_ym1;
		if ((signed) EBX < ECX)
			goto line_xp1_ymd;
	} else if (EDX == ECX) {
	//	if (EBX == EAX)
	//		goto line_xm1_yp1;
		if ((signed) EBX > EAX)
			goto general;
		if (EBX >= 0)
			goto line_xm1_ypd;
	//	if (EBX == ECX)
	//		goto line_xm1_ym1;
		if ((signed) EBX < ECX)
			goto line_xm1_ymd;
	}

general:
	POP(EAX);
	POP(EBP);
	PUSH(EDX);
	do {
		EDX = EDI;
		ECX = ESI;
		(unsigned int) EDX >>= 16;
		(unsigned int) ECX >>= 16;
		IMUL_TWVSW(EDX);
		ESI += [SS:ESP];
		EDI += EBX;
		(char) [DS:EDX + ECX + 0xe0000000] = AL;
		EBP--;
	} while (!= 0);
	POP(EDX);
	return;

line_xpd_yp1:
	EDI = EBP;
	POP(EAX);
	EBP = TWVSW;
line_xpmd_yp1:
	ESI <<= 16;
	POP(ECX);
	EDX <<= 16;
	do {
		(char) [DS:EDI] = AL;
		ESI += EDX;
		ADC(EDI, EBP);
		ECX--;
	} while (!= 0);
	return;

line_xmd_yp1:
	EDI = EBP;
	POP(EAX);
	EBP = TWVSW - 1;
	goto line_xpmd_yp1;

#if 0
	ESI <<= 16;
	POP(ECX);
	EDX <<= 16;
	do {
		(char) [DS:EDI] = AL;
		ESI += EDX;
		ADC(EDI, TWVSW - 1); /* CF == 1なら+TWVSW, CF == 0なら+TWVSW - 1 */
		ECX--;
	} while (!= 0);
	return;
#endif

line_xpd_ym1:
	EDI = EBP;
	POP(EAX);
	EBP = 0 - TWVSW;
	goto line_xpmd_yp1;

#if 0
	ESI <<= 16;
	POP(ECX);
	EDX <<= 16;
	do {
		(char) [DS:EDI] = AL;
		ESI += EDX;
		ADC(EDI, 0 - TWVSW);
		ECX--;
	} while (!= 0);
	return;
#endif

line_xmd_ym1:
	EDI = EBP;
	POP(EAX);
	EBP = 0 - TWVSW - 1;
	goto line_xpmd_yp1;

#if 0
	ESI <<= 16;
	POP(ECX);
	EDX <<= 16;
	do {
		(char) [DS:EDI] = AL;
		ESI += EDX;
		ADC(EDI, 0 - TWVSW - 1); /* CF == 1なら-TWVSW, CF == 0なら-TWVSW - 1 */
		ECX--;
	} while (!= 0);
	return;
#endif

line_xp1_ypd:
	ESI = EBP;
	POP(EAX);
	EDI <<= 16;
	POP(ECX);
	EBX <<= 16;
	do {
		EDI += EBX;
		SBB(EDX, EDX); /* CF == 0ならEDX = 0, CF == 1ならEDX = -1 */
		(char) [DS:ESI] = AL;
		EDX &= TWVSW;
	//	ESI++;
	//	ESI += EDX;
		ECX--;
		LEA(ESI, [ESI + EDX + 1]);
	} while (!= 0);
	return;

line_xp1_ymd:
	ESI = EBP;
	POP(EAX);
	EDI <<= 16;
	POP(ECX);
	EBX <<= 16;
	do {
		EDX = 0;
		EDI += EBX;
		ADC(EDX, 0xffffffff); /* CF == 0ならEDX = -1, CF == 1ならEDX = 0 */
		(char) [DS:ESI] = AL;
		EDX &= 0 - TWVSW;
	//	ESI++;
	//	ESI += EDX;
		ECX--;
		LEA(ESI, [ESI + EDX + 1]);
	} while (!= 0);
	return;

line_xm1_ypd:
	ESI = EBP;
	POP(EAX);
	EDI <<= 16;
	POP(ECX);
	EBX <<= 16;
	do {
		EDI += EBX;
		SBB(EDX, EDX); /* CF == 0ならEDX = 0, CF == 1ならEDX = -1 */
		(char) [DS:ESI] = AL;
		EDX &= TWVSW;
	//	ESI--;
	//	ESI += EDX;
		ECX--;
		LEA(ESI, [ESI + EDX - 1]);
	} while (!= 0);
	return;

line_xm1_ymd:
	ESI = EBP;
	POP(EAX);
	EDI <<= 16;
	POP(ECX);
	EBX <<= 16;
	do {
		EDX = 0;
		EDI += EBX;
		ADC(EDX, 0xffffffff); /* CF == 0ならEDX = -1, CF == 1ならEDX = 0 */
		(char) [DS:ESI] = AL;
		EDX &= 0 - TWVSW;
	//	ESI--;
	//	ESI += EDX;
		ECX--;
		LEA(ESI, [ESI + EDX - 1]);
	} while (!= 0);
	return;

line_xp1_yp1:
	EDX = TWVSW + 1;
line_x1_y1:
	POP(EAX);
	ESI = EBP;
	POP(ECX);
	do {
		(char) [DS:ESI] = AL;
		ESI += EDX;
		ECX--;
	} while (!= 0);
	return;

line_xp1_ym1:
	EDX = 1 - TWVSW;
	goto line_x1_y1;

line_xm1_yp1:
	EDX = TWVSW - 1;
	goto line_x1_y1;

line_xm1_ym1:
	EDX = 0 - TWVSW - 1;
	goto line_x1_y1;
}

void near GAPI_linesub_xor()
/*
	ESI : 初期x
	EDI : 初期y
	EDX : 増分値x
	EBX : 増分値y
	EBP : ループ回数
	EAX : カラー
*/
{
	PUSH(EDX);
	do {
		EDX = EDI;
		ECX = ESI;
		(unsigned int) EDX >>= 16;
		(unsigned int) ECX >>= 16;
		IMUL_TWVSW(EDX);
		ESI += [SS:ESP];
		EDI += EBX;
		(char) [DS:EDX + ECX + 0xe0000000] ^= AL;
		EBP--;
	} while (!= 0);
	POP(EDX);
	return;
}

void near GAPI_linesub_or()
/*
	ESI : 初期x
	EDI : 初期y
	EDX : 増分値x
	EBX : 増分値y
	EBP : ループ回数
	EAX : カラー
*/
{
	PUSH(EDX);
	do {
		EDX = EDI;
		ECX = ESI;
		(unsigned int) EDX >>= 16;
		(unsigned int) ECX >>= 16;
		IMUL_TWVSW(EDX);
		ESI += [SS:ESP];
		EDI += EBX;
		(char) [DS:EDX + ECX + 0xe0000000] |= AL;
		EBP--;
	} while (!= 0);
	POP(EDX);
	return;
}

void near GAPI_linesub_and()
/*
	ESI : 初期x
	EDI : 初期y
	EDX : 増分値x
	EBX : 増分値y
	EBP : ループ回数
	EAX : カラー
*/
{
	PUSH(EDX);
	do {
		EDX = EDI;
		ECX = ESI;
		(unsigned int) EDX >>= 16;
		(unsigned int) ECX >>= 16;
		IMUL_TWVSW(EDX);
		ESI += [SS:ESP];
		EDI += EBX;
		(char) [DS:EDX + ECX + 0xe0000000] &= AL;
		EBP--;
	} while (!= 0);
	POP(EDX);
	return;
}

void near GAPI_lineardots()
{
	/* 斜め線を引くためなどに使う(等間隔で点を打つこともできる) */
	/* cmd, opt, x0, y0, sx, sy, lines, ofs, sel */
	/* sxとsyは利用していない */

	/* データーの形式 */
	/* x0, y0, dx, dy, dots, color */
	/* x0, y0, dx, dyは固定少数点 */

	int *cmd == FS:EBX;
	int *dat == ES:EAX;

	PUSH(ES);
	PUSH(EBP);
	ECX = cmd[ 4];
	EBP = cmd[24];
	ECX >>= 6;
	asmout("LES EAX,FWORD PTR FS:[EBX+28]");
	PUSH((offset) cmd);
	ESI = cmd[ 8];
	EDI = cmd[12];
	if (== 0) {
		do {
			PUSH(ESI);
			EDX = dat[ 8]; /* dx */
			PUSH(EDI);
			EBX = dat[12]; /* dy */
			PUSH(EBP);
			ESI <<= 16;
			EDI <<= 16;
			PUSH((offset) dat);
			ESI += dat[ 0]; /* x0 */
			EDI += dat[ 4]; /* y0 */
			EBP = dat[16]; /* dots */
			EAX = dat[20]; /* color */
			GAPI_linesub_pset();
			POP((offset) dat);
			POP(EBP);
			(offset) dat += 24;
			POP(EDI);
			EBP--;
			POP(ESI);
		} while (!= 0);
		POP((offset) cmd);
		POP(EBP);
		(offset) cmd += 36;
		POP(ES);
		asmout("JMP next_command");
	}
	ECX--;
	if (== 0) {
		do {
			PUSH(ESI);
			EDX = dat[ 8]; /* dx */
			PUSH(EDI);
			EBX = dat[12]; /* dy */
			PUSH(EBP);
			ESI <<= 16;
			EDI <<= 16;
			PUSH((offset) dat);
			ESI += dat[ 0]; /* x0 */
			EDI += dat[ 4]; /* y0 */
			EBP = dat[16]; /* dots */
			EAX = dat[20]; /* color */
			GAPI_linesub_and();
			POP((offset) dat);
			POP(EBP);
			(offset) dat += 24;
			POP(EDI);
			EBP--;
			POP(ESI);
		} while (!= 0);
		POP((offset) cmd);
		POP(EBP);
		(offset) cmd += 36;
		POP(ES);
		asmout("JMP next_command");
	}
	ECX--;
	if (== 0) {
		do {
			PUSH(ESI);
			EDX = dat[ 8]; /* dx */
			PUSH(EDI);
			EBX = dat[12]; /* dy */
			PUSH(EBP);
			ESI <<= 16;
			EDI <<= 16;
			PUSH((offset) dat);
			ESI += dat[ 0]; /* x0 */
			EDI += dat[ 4]; /* y0 */
			EBP = dat[16]; /* dots */
			EAX = dat[20]; /* color */
			GAPI_linesub_or();
			POP((offset) dat);
			POP(EBP);
			(offset) dat += 24;
			POP(EDI);
			EBP--;
			POP(ESI);
		} while (!= 0);
		POP((offset) cmd);
		POP(EBP);
		(offset) cmd += 36;
		POP(ES);
		asmout("JMP next_command");
	}
//	ECX--;
//	if (== 0) {
		do {
			PUSH(ESI);
			EDX = dat[ 8]; /* dx */
			PUSH(EDI);
			EBX = dat[12]; /* dy */
			PUSH(EBP);
			ESI <<= 16;
			EDI <<= 16;
			PUSH((offset) dat);
			ESI += dat[ 0]; /* x0 */
			EDI += dat[ 4]; /* y0 */
			EBP = dat[16]; /* dots */
			EAX = dat[20]; /* color */
			GAPI_linesub_xor();
			POP((offset) dat);
			POP(EBP);
			(offset) dat += 24;
			POP(EDI);
			EBP--;
			POP(ESI);
		} while (!= 0);
		POP((offset) cmd);
		POP(EBP);
		(offset) cmd += 36;
		POP(ES);
		asmout("JMP next_command");
//	}
}

void near GAPI_points()
{
	/* 点を打つ */
	/* cmd, opt, x0, y0, sx, sy, lines, ofs, sel */
	/* sxとsyは利用していない */

	/* データーの形式 */
	/* x0, y0, color */

	int *cmd == FS:EBX;
	int *dat == ES:EDX;

	PUSH(ES);
	EAX = cmd[ 4];
	ECX = cmd[24];
	asmout("LES EDX,FWORD PTR FS:[EBX+28]");
	ESI = cmd[ 8];
	EDI = cmd[12];
	(offset) cmd += 36;
	PUSH(ESI);
	EAX >>= 6;
	PUSH(EDI);
	if (== 0) {
		do {
			ESI += dat[0]; /* x0 */
			EDI += dat[4]; /* y0 */
			EAX = dat[8]; /* color */
			IMUL_TWVSW(EDI);
			(offset) dat += 12;
			(char) [DS:EDI + ESI + 0xe0000000] = AL;
			ECX--;
			ESI = [SS:ESP + 4];
			EDI = [SS:ESP + 0];
		} while (!= 0);
		POP(EAX);
		POP(ECX);
		POP(ES);
		asmout("JMP next_command");
	}
	EAX--;
	if (== 0) {
		do {
			ESI += dat[0]; /* x0 */
			EDI += dat[4]; /* y0 */
			EAX = dat[8]; /* color */
			IMUL_TWVSW(EDI);
			(offset) dat += 12;
			(char) [DS:EDI + ESI + 0xe0000000] &= AL;
			ECX--;
			ESI = [SS:ESP + 4];
			EDI = [SS:ESP + 0];
		} while (!= 0);
		POP(EAX);
		POP(ECX);
		POP(ES);
		asmout("JMP next_command");
	}
	EAX--;
	if (== 0) {
		do {
			ESI += dat[0]; /* x0 */
			EDI += dat[4]; /* y0 */
			EAX = dat[8]; /* color */
			IMUL_TWVSW(EDI);
			(offset) dat += 12;
			(char) [DS:EDI + ESI + 0xe0000000] |= AL;
			ECX--;
			ESI = [SS:ESP + 4];
			EDI = [SS:ESP + 0];
		} while (!= 0);
		POP(EAX);
		POP(ECX);
		POP(ES);
		asmout("JMP next_command");
	}
//	EAX--;
//	if (== 0) {
		do {
			ESI += dat[0]; /* x0 */
			EDI += dat[4]; /* y0 */
			EAX = dat[8]; /* color */
			IMUL_TWVSW(EDI);
			(offset) dat += 12;
			(char) [DS:EDI + ESI + 0xe0000000] ^= AL;
			ECX--;
			ESI = [SS:ESP + 4];
			EDI = [SS:ESP + 0];
		} while (!= 0);
		POP(EAX);
		POP(ECX);
		POP(ES);
		asmout("JMP next_command");
//	}
}

void near GAPI_removemouse();
void near GAPI_putmouse();
void near GAPI_clippingmouse();

void near GAPI_mouse()
/* option:bit0  直接指定(0)/間接指定(1)
   option:bit5,4  16x16(00)/32x31(01)
   option:bit7,6  マスクパターンありのモノクロ(00),マスクパターンありのカラー(10)
   option:bit9,8  カーソルパターンストア(00),カーソル表示(01),カーソル消去(10),カーソル移動(11)
     01,11では、カーソル座標を指定する。このコマンドでは、マウスカーソルは一つしか制御できない。
     デフォルトでは、マウスカーソルと他のグラフィックコマンドとの関係を解消したりもしない。 */
{
	int *cmd == FS:EBX;
	GAPI_WORK *work == ES:0x0000;

	cmd[4] = 0xffffffff; /* コマンド終了 */
	EAX = cmd[8];
	CLI();
	TEST(AH, 0x02);
	if (!= 0) {
		/* カーソルを消す */
		if (work->mouseflag != 0) {
			GAPI_removemouse(); /* remove mouse (mouseflag = 0) */
			EAX = cmd[8];
		}
		TEST(AH, 0x01);
		if (== 0)
			work->mx1 = 0x80000000; /* 非表示モード */
	}
	TEST(AH, 0x01);
	if (!= 0) {
		/* カーソルを描く */
		ECX = cmd[12];
		EDX = cmd[16];
		work->mx = ECX;
		work->my = EDX;
		if (work->lockcount == 0) {
			GAPI_clippingmouse(); /* mx0, my0, mx1, my1を設定 */
			GAPI_putmouse(); /* put mouse (mouseflag = 1) */
		} else {
			work->mouselock = 0x80000000;
		}
		STI();
		(offset) cmd += 20;
		asmout("JMP next_command");
	}
	STI();
	(offset) cmd += 12;
	asmout("JMP next_command");
}

void near GAPI_init_sub();

void near GAPI_init()
{
	int all_sel == 1 * 8;
	int *cmd == FS:EBX;

	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 12;

	GAPI_WORK *work == DS:0x0000, *workES == ES:0x0000;

	unsigned char *cursor0 == CS:ESI; // [y][x]
	int *cursor_buf == DS:EDI; // [x][y]

	AX = ES;
	asmout("MOV ESI,OFFSET #mouse_cursor");
	DS = AX;
	LEA((offset) cursor_buf, work->mouse_pattern[0]);
	EDX = 0;

	CLI();

	ECX = 16;
	do {
		/* 1loop当たり、1line */
		DL = cursor0[ 0];
		DL |= cursor0[32];
		EDX >>= 4;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[32];
		EAX =~ EAX;
		EDX >>= 4;
		cursor_buf[  0] = EAX;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[ 0];
		EAX &= 0x0f0f0f0f;
		DL |= cursor0[32];
		cursor_buf[  4] = EAX;
		EDX &= 0x0f;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[32];
		EAX =~ EAX;
		EDX &= 0x0f;
		cursor_buf[128] = EAX;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[ 1];
		EAX &= 0x0f0f0f0f;
		DL |= cursor0[33];
		cursor_buf[132] = EAX;
		EDX >>= 4;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[33];
		EAX =~ EAX;
		EDX >>= 4;
		cursor_buf[256] = EAX;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[ 1];
		EAX &= 0x0f0f0f0f;
		DL |= cursor0[33];
		cursor_buf[260] = EAX;
		EDX &= 0x0f;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		DL = cursor0[33];
		EAX =~ EAX;
		EDX &= 0x0f;
		cursor_buf[384] = EAX;
		asmout("MOV EAX,DWORD PTR CS:[#table][EDX*4]");
		cursor_buf[512] = 0xffffffff;
		EAX &= 0x0f0f0f0f;
		(offset) cursor0 += 2;
		cursor_buf[388] = EAX;
		cursor_buf[516] = 0;
		(offset) cursor_buf += 8;
		ECX--;
	} while (!= 0);

	/* ずらしパターンの用意 */
	int *base == DS:ESI, *shift == DS:EDI;
	LEA((offset) base,  work->mouse_pattern[  0]);
	LEA((offset) shift, work->mouse_pattern[640]);
	EBP = 3;

	PUSH(EBX);
	do {
		ECX = 32;
		do {
			EAX = base[  0];
			EDX = EAX;
			EAX *= 256;
			TEST(ECX, 1);
			EBX = base[128];
			if (== 0)
				EAX |= 0xff;
			shift[0] = EAX;
			EAX = EBX;
			SHLD(EBX, EDX, 8);
			EDX = base[256];
			shift[128] = EBX;
			EBX = EDX;
			SHLD(EDX, EAX, 8);
			EAX = base[384];
			shift[256] = EDX;
			EDX = EAX;
			SHLD(EAX, EBX, 8);
			EBX = base[512];
			shift[384] = EAX;
			SHLD(EBX, EDX, 8);
			(offset) base += 4;
			shift[512] = EBX;
			(offset) shift += 4;
			ECX--;
		} while (!= 0);
		(offset) base  += 512;
		(offset) shift += 512;
		EBP--;
	} while (!= 0);
	POP(EBX);

	EAX = all_sel;
	work->mx1 = 0x80000000; /* 非表示 */
//	work->backup_addr = 0xa0000 + 800 * 600 / 8; /* 画面外 */
//	work->taskcount = /* 0 */ ECX;
	work->lockcount = /* 0 */ ECX;
	work->mouselock = /* 0 */ ECX;
	work->VGA_mode = /* 0 */ ECX;
	work->mouseflag = /* 0 */ CL;
//	ECX++;
//	work->nextcount = /* 1 */ ECX;
/*
	EAX = syswork_sel;
	DS = AX;
	EAX = [DS:32 + bootseg_ent + 12];
	ECX = [DS:32 + stack000_ent + 12];
	(unsigned int) EAX >>= 4; // bootseg_ent
	(unsigned int) ECX >>= 4; // stack000_ent
	workES->V86CS = AX;
	workES->V86SS = CX;
*/

	STI();
//	EBP++; // EBP = 1;
	DS = EAX;
	asmout("JMP next_command");

	/* デフォルトマウスカーソルパターン(16x16, mono) */
	ALIGN(4);
mouse_cursor:
	asmout("DB 11000000B,00000000B");
	asmout("DB 10100000B,00000000B");
	asmout("DB 10010000B,00000000B");
	asmout("DB 10001000B,00000000B");
	asmout("DB 10000100B,00000000B");
	asmout("DB 10000010B,00000000B");
	asmout("DB 10000001B,00000000B");
	asmout("DB 10000000B,10000000B");
	asmout("DB 10000011B,00000000B");
	asmout("DB 10000100B,00000000B");
	asmout("DB 10100010B,00000000B");
	asmout("DB 11010010B,00000000B");
	asmout("DB 00001001B,00000000B");
	asmout("DB 00001001B,00000000B");
	asmout("DB 00000100B,10000000B");
	asmout("DB 00000011B,00000000B");

	asmout("DB 00000000B,00000000B");
	asmout("DB 01000000B,00000000B");
	asmout("DB 01100000B,00000000B");
	asmout("DB 01110000B,00000000B");
	asmout("DB 01111000B,00000000B");
	asmout("DB 01111100B,00000000B");
	asmout("DB 01111110B,00000000B");
	asmout("DB 01111111B,00000000B");
	asmout("DB 01111100B,00000000B");
	asmout("DB 01111000B,00000000B");
	asmout("DB 01011100B,00000000B");
	asmout("DB 00001100B,00000000B");
	asmout("DB 00000110B,00000000B");
	asmout("DB 00000110B,00000000B");
	asmout("DB 00000011B,00000000B");
	asmout("DB 00000000B,00000000B");
table:
	DD(0x00000000); DD(0xff000000); DD(0x00ff0000); DD(0xffff0000);
	DD(0x0000ff00); DD(0xff00ff00); DD(0x00ffff00); DD(0xffffff00);
	DD(0x000000ff); DD(0xff0000ff); DD(0x00ff00ff); DD(0xffff00ff);
	DD(0x0000ffff); DD(0xff00ffff); DD(0x00ffffff); DD(0xffffffff);
}

void near GAPI_resetdevice()
{
	asmout("#GAPI_VGA640 EQU GAPI_VGA640");

	GAPI_WORK *work == ES:0x0000;
	int *cmd == FS:EBX;

	if (cmd[8] == 0x0020)
		goto GAPI_VGA640;

	/* パレット初期化 */
	unsigned char *pt == CS:ESI;
	asmout("MOV ESI,OFFSET #palette_table");
	CLI();
	EDX = 0xfd90;
	CL = 0;
	do {
		AL = CL;
		OUT(DX, AL);
		EDX += 2;
		AL = pt[2]; // blue
		OUT(DX, AL);
		EDX += 2;
		AL = pt[0]; // red
		OUT(DX, AL);
		EDX += 2;
		AL = pt[1]; // green
		OUT(DX, AL);
		EDX -= 6;
		CL++;
		(offset) pt += 3;
	} while ((unsigned) CL < 16);

	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 12;
	asmout("JMP next_command");

palette_table: /* Red, Green, Blue */
	/* 0:黒, 7:暗い灰色, 8:明るい灰色, 6:バックの色, 15:白 */

	asmout("DB 000H, 000H, 000H,   084H, 000H, 000H,   000H, 084H, 000H,   084H, 084H, 000H");
	asmout("DB 000H, 000H, 084H,   084H, 000H, 084H,   000H, 084H, 084H,   084H, 084H, 084H");
	asmout("DB 0C6H, 0C6H, 0C6H,   0FFH, 000H, 000H,   000H, 0FFH, 000H,   0FFH, 0FFH, 000H");
	asmout("DB 000H, 000H, 0FFH,   0FFH, 000H, 0FFH,   000H, 0FFH, 0FFH,   0FFH, 0FFH, 0FFH");
}

/*
void near GAPI_setmode()
// 001c, 0020, priority, mode(00, 12, 92, 6a, ea, 0102, 8102)
{
      0004 : デバイスリセット（ハードウェアコネクト）


}

void near GAPI_disconnect()
{

}
*/

void near GAPI_error()
{
	INT(0x03);
}

void near GAPI_VGA640()
/* ハードウェア別特別コマンド(0x001c, pri, 0x0020, mode) */
{
	GAPI_WORK *work == ES:0x0000;
	GAPI_WORK *work_DS == DS:0x0000;
	int all_sel == 1 * 8;
	int *cmd == FS:EBX;
	WORK_SUB *wsub == ES:EDI;

	LEA((offset) wsub, (int) [work_DS->worksub]);
	EAX = 0;
	wsub->scr_x0 = EAX;
	wsub->scr_y0 = EAX;
	EAX--;

	cmd[ 4] = /* 0xffffffff*/ EAX; /* 終了 */
	EAX = cmd[12];
	(offset) cmd += 16;

	short *param == DS:ESI;
//	(offset) param = (offset) &param640;
	#if (defined(TWSCRL1))
		ECX = 640;
	#else
		ECX = 640 - 7; /* スクロール判定の都合のため */
	#endif
	EDX = 480 - 15 /* 前もってmouseの大きさの分を引いてある */;
		/* マウスのy方向のクリッピングができるようになったら、この措置は不要 */
	asmout("MOV ESI,OFFSET #param640");
	if (EAX != 0) {
	//	asmout("ADD ESI,#param768 - #param640");
		DB(0x83, 0xc6);
		asmout("DB #param768 - #param640");
		ECX -= 640 - 768;	/* 128を足すのは3バイト無駄(なるほど、うまい!) */
		EDX += 512 - 480;
	}
	wsub->scr_width  = ECX;
	wsub->scr_height = EDX;

//	AX = CS;
//	DS = AX;
	PUSH(CS);
	POP(DS);

	/* CRTC */
	EDX = 0x0440;
	CLI();
	CL = 0;
	do {
cl4in:
		AL = CL;
		OUT(DX, AL);
		DL = 0x42;
		AX = *param;
		(offset) param += 2;
		OUT(DX, AX);
		CL++;
		DL = 0x40;
		if (CL == 2)
			goto cl4;
	} while (CL < 0x20);

	/* プライオリティーレジスタ */
//	EDX = 0x0448;
	DL = 0x48;
	AL = 0x00;
	OUT(DX, AL);
	DL = 0x4a;
	AL = 0x0a;
	OUT(DX, AL);
	DL = 0x48;
	AL = 0x01;
	OUT(DX, AL);
	DL = 0x4a;
	AL = 0x18;
	OUT(DX, AL);

	/* CRT出力コントロールレジスタ */
	EDX = 0xfda0;
	AL = 0x08;
	OUT(DX, AL);

	STI();
//	EAX = all_sel;
//	DS = AX;
	PUSH(all_sel);
	POP(DS);
	asmout("JMP next_command");

cl4:
	CL = 4;
	goto cl4in;

	ALIGN(4);

param640:
	/* CRTC */
	DW(0x0060,    0x02c0,                 0x031f,    0x0000, 0x0004, 0x0000);
	DW(0x0419,    0x008a, 0x030a, 0x008a, 0x030a,    0x0046, 0x0406, 0x0046);
	DW(0x0406,    0x0000, 0x008a, 0x0000, TWVSW / 8, 0x0000, 0x008a, 0x0000);
	DW(TWVSW / 8, 0x0058, 0x0001, 0x0000, CRTC28,    0x0002, 0x0000, 0x0192);

param768:
	/* CRTC */
	DW(0x0060,    0x0338,                 0x0397,    0x0000, 0x0004, 0x0000);
	DW(0x0433,    0x008a, 0x038a, 0x008a, 0x038a,    0x0034, 0x0434, 0x0034);
	DW(0x0434,    0x0000, 0x008a, 0x0000, TWVSW / 8, 0x0000, 0x008a, 0x0000);
	DW(TWVSW / 8, 0x0058, 0x0001, 0x0000, CRTC28,    0x0000, 0x0000, 0x0192);
}

void near GAPI_accesslock()
/* opt bit0  0:Lock 1:Unlock
       bit1  Lock時のオプション   0:nearポインタあり 1:なし
             Unlock時のオプション 0:範囲指定なし 1:あり
       bit8-31  Unlock-opt */
{
	int *cmd == FS:EBX;
	GAPI_WORK *work == ES:0x0000;

	EAX = cmd[8]; // opt
	if (AL == 0)
		goto lock_bitset;
	if (AL == 0x02)
		goto lock_bitnoset;
	if (AL == 0x01)
		goto unlock_optbit;
	if (AL == 0x03)
		goto unlock_area;
	INT(0x03);

lock_bitset:
	EAX = cmd[12]; // x0
	ECX = cmd[16]; // y0
	ESI = cmd[20]; // x1
	EDI = cmd[24]; // y1
	EBP = cmd[28]; // ofs
	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 32;
	CLI();
	work->lockcount++;
	if ((signed) EAX /* x0 */ < work->mx1) {
		if ((signed) ECX /* y0 */ < work->my1) {
			if ((signed) ESI /* x1 */ > work->mx0) {
				if ((signed) EDI /* y1 */ > work->my0) {
					if (work->mouseflag != 0) {
						GAPI_removemouse(); // remove mouse (mouseflag = 0)
					}
					work->mouselock++;
					(char) [FS:EBP + 1] |= 0x01; // mouse
				}
			}
		}
	}
	STI();
	asmout("JMP next_command");

lock_bitnoset:
	EAX = cmd[12]; // x0
	ECX = cmd[16]; // y0
	ESI = cmd[20]; // x1
	EDI = cmd[24]; // y1
	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 28;
	CLI();
	work->lockcount++;
	if ((signed) EAX /* x0 */ < work->mx1) {
		if ((signed) ECX /* y0 */ < work->my1) {
			if ((signed) ESI /* x1 */ > work->mx0) {
				if ((signed) EDI /* y1 */ > work->my0) {
					if (work->mouseflag != 0) {
						GAPI_removemouse(); // remove mouse (mouseflag = 0)
					}
					work->mouselock++;
				}
			}
		}
	}
	STI();
	asmout("JMP next_command");

unlock_optbit:
	CLI();
	work->lockcount--;
	if (!= 0) {
		TEST(AH, 0x01);
		if (!= 0) {
			work->mouselock--;
			if (== 0) {
				/* マウスを移動させる時に、mouselockが0x80000000にされるので、
				   マウスが非表示中に移動すると、これは成立しなくなる。 */
				GAPI_putmouse(); /* put mouse (mouseflag = 1) */
				/* mx1をチェックしなくていいのか？ */
			}
		}
		STI();
		cmd[4] = 0xffffffff; /* 終了 */
		(offset) cmd += 12;
		asmout("JMP next_command");
	}
	work->mouselock = 0;
	if (work->mx1 != 0x80000000 /* mx1がこの値の時は、非表示を意味する */) {
		if (work->mouseflag == 0 /* mouse erased */) {
			GAPI_clippingmouse(); /* mx0, my0, mx1, my1を設定 */
			GAPI_putmouse(); /* put mouse (mouseflag = 1) */
		}
	}
	STI();
	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 12;
	asmout("JMP next_command");

unlock_area:
	EAX = cmd[12]; // x0
	ECX = cmd[16]; // y0
	ESI = cmd[20]; // x1
	EDI = cmd[24]; // y1
	CLI();
	work->lockcount--;
	if (!= 0) {
		if ((signed) EAX /* x0 */ < work->mx1) {
			if ((signed) ECX /* y0 */ < work->my1) {
				if ((signed) ESI /* x1 */ > work->mx0) {
					if ((signed) EDI /* y1 */ > work->my0) {
						work->mouselock--;
						if (== 0) {
							/* マウスを移動させる時に、mouselockが0にされるので、
							   マウスが一時消去中に移動すると、これは成立しなくなる。
							   マウスが非表示中は最初のmx1の比較が成立しない */
							GAPI_putmouse(); /* put mouse (mouseflag = 1) */
						}
					}
				}
			}
		}
		STI();
		cmd[4] = 0xffffffff; /* 終了 */
		(offset) cmd += 28;
		asmout("JMP next_command");
	}
	work->mouselock = 0;
	if (work->mx1 != 0x80000000 /* mx1がこの値の時は、非表示を意味する */) {
		if (work->mouseflag == 0 /* mouse erased */) {
			GAPI_clippingmouse(); /* mx0, my0, mx1, my1を設定 */
			GAPI_putmouse(); /* put mouse (mouseflag = 1) */
		}
	}
	STI();
	cmd[4] = 0xffffffff; /* 終了 */
	(offset) cmd += 28;
	asmout("JMP next_command");
}

void near GAPI_mouse_drawsub16()
/* DS:ESIからy方向に64バイトを、ES:EDXへ転送。 */
/* 同時にES:ESIを描画 */
/* ただし、どちらもVRAM内のアドレス。 */
/* EAX, ECXのみ破壊。 */
{
	int *b == ES:EDX, *p == DS:ESI, *q == ES:EDI;
	EAX = p[TWVSW *  0]; ECX = p[TWVSW *  1]; b[ 0] = EAX; b[ 4] = ECX;
	EAX &= q[  0]; ECX &= q[  8]; EAX ^= q[  4]; ECX ^= q[ 12];
	p[TWVSW *  0] = EAX; p[TWVSW *  1] = ECX;
	EAX = p[TWVSW *  2]; ECX = p[TWVSW *  3]; b[ 8] = EAX; b[12] = ECX;
	EAX &= q[ 16]; ECX &= q[ 24]; EAX ^= q[ 20]; ECX ^= q[ 28];
	p[TWVSW *  2] = EAX; p[TWVSW *  3] = ECX;
	EAX = p[TWVSW *  4]; ECX = p[TWVSW *  5]; b[16] = EAX; b[20] = ECX;
	EAX &= q[ 32]; ECX &= q[ 40]; EAX ^= q[ 36]; ECX ^= q[ 44];
	p[TWVSW *  4] = EAX; p[TWVSW *  5] = ECX;
	EAX = p[TWVSW *  6]; ECX = p[TWVSW *  7]; b[24] = EAX; b[28] = ECX;
	EAX &= q[ 48]; ECX &= q[ 56]; EAX ^= q[ 52]; ECX ^= q[ 60];
	p[TWVSW *  6] = EAX; p[TWVSW *  7] = ECX;
	EAX = p[TWVSW *  8]; ECX = p[TWVSW *  9]; b[32] = EAX; b[36] = ECX;
	EAX &= q[ 64]; ECX &= q[ 72]; EAX ^= q[ 68]; ECX ^= q[ 76];
	p[TWVSW *  8] = EAX; p[TWVSW *  9] = ECX;
	EAX = p[TWVSW * 10]; ECX = p[TWVSW * 11]; b[40] = EAX; b[44] = ECX;
	EAX &= q[ 80]; ECX &= q[ 88]; EAX ^= q[ 84]; ECX ^= q[ 92];
	p[TWVSW * 10] = EAX; p[TWVSW * 11] = ECX;
	EAX = p[TWVSW * 12]; ECX = p[TWVSW * 13]; b[48] = EAX; b[52] = ECX;
	EAX &= q[ 96]; ECX &= q[104]; EAX ^= q[100]; ECX ^= q[108];
	p[TWVSW * 12] = EAX; p[TWVSW * 13] = ECX;
	EAX = p[TWVSW * 14]; ECX = p[TWVSW * 15]; b[56] = EAX; b[60] = ECX;
	EAX &= q[112]; ECX &= q[120]; EAX ^= q[116]; ECX ^= q[124];
	p[TWVSW * 14] = EAX; p[TWVSW * 15] = ECX;
	return;
}

void near GAPI_mouse_erasesub16()
{
	int *b == ES:EDI, *p == DS:ESI;
	EAX = b[ 0]; ECX = b[ 4]; p[TWVSW *  0] = EAX; p[TWVSW *  1] = ECX;
	EAX = b[ 8]; ECX = b[12]; p[TWVSW *  2] = EAX; p[TWVSW *  3] = ECX;
	EAX = b[16]; ECX = b[20]; p[TWVSW *  4] = EAX; p[TWVSW *  5] = ECX;
	EAX = b[24]; ECX = b[28]; p[TWVSW *  6] = EAX; p[TWVSW *  7] = ECX;
	EAX = b[32]; ECX = b[36]; p[TWVSW *  8] = EAX; p[TWVSW *  9] = ECX;
	EAX = b[40]; ECX = b[44]; p[TWVSW * 10] = EAX; p[TWVSW * 11] = ECX;
	EAX = b[48]; ECX = b[52]; p[TWVSW * 12] = EAX; p[TWVSW * 13] = ECX;
	EAX = b[56]; ECX = b[60]; p[TWVSW * 14] = EAX; p[TWVSW * 15] = ECX;
	return;
}

void near GAPI_putmouse()
/* 破壊レジスタ：EAX, ECX, EDX, ESI, EDI */
{
	GAPI_WORK *work == ES:0x0000;
	int *b /* backup */ == ES:EDX, *p /* cursor */ == DS:ESI, *q /* pattern */ == ES:EDI;
	unsigned char maskflag == BL;

	PUSH(EBX);
	maskflag = work->maskflag; /* 1のbitは書かない */
	work->mouseflag = 1;
	(offset) p = work->cursor_addr;
	LEA((offset) b, work->backup_buf[0]);
	(offset) q = work->pattern_addr; /* ANDパターンとXORパターンのセット */
	TEST(maskflag, 0x01);
	if (== 0)
		GAPI_mouse_drawsub16();
	(offset) p +=   4;
	(offset) b +=  64;
	(offset) q += 128;
	TEST(maskflag, 0x02);
	if (== 0)
		GAPI_mouse_drawsub16();
	(offset) p +=   4;
	(offset) b +=  64;
	(offset) q += 128;
	TEST(maskflag, 0x04);
	if (== 0)
		GAPI_mouse_drawsub16();
	(offset) p +=   4;
	(offset) b +=  64;
	(offset) q += 128;
	TEST(maskflag, 0x08);
	if (== 0)
		GAPI_mouse_drawsub16();
	(offset) p +=   4;
	(offset) b +=  64;
	(offset) q += 128;
	TEST(maskflag, 0x10);
	POP(EBX);
//	if (== 0)
//		GAPI_mouse_drawsub16();
	asmout("JZ GAPI_mouse_drawsub16");
	return;
}

void near GAPI_removemouse()
/* 破壊レジスタ：EAX, ECX, EDX, ESI, EDI */
{
	GAPI_WORK *work == ES:0x0000;
	int *b /* backup */ == ES:EDI, *p /* cursor */ == DS:ESI;
	unsigned char maskflag == DL;

	maskflag = work->maskflag; /* 1のbitは書かない */
	work->mouseflag = 0;
	(offset) p = work->cursor_addr;
	LEA((offset) b, work->backup_buf[0]);
	TEST(maskflag, 0x01);
	if (== 0)
		GAPI_mouse_erasesub16();
	(offset) p +=   4;
	(offset) b +=  64;
	TEST(maskflag, 0x02);
	if (== 0)
		GAPI_mouse_erasesub16();
	(offset) p +=   4;
	(offset) b +=  64;
	TEST(maskflag, 0x04);
	if (== 0)
		GAPI_mouse_erasesub16();
	(offset) p +=   4;
	(offset) b +=  64;
	TEST(maskflag, 0x08);
	if (== 0)
		GAPI_mouse_erasesub16();
	(offset) p +=   4;
	(offset) b +=  64;
	TEST(maskflag, 0x10);
//	if (== 0)
//		GAPI_mouse_erasesub16();
	asmout("JZ GAPI_mouse_erasesub16");
	return;
}

void near GAPI_clippingmouse()
/* VRAMに15ライン以上の余裕を仮定＆パターンの上部が欠けることもありえない */
/* (EAX, EBP) : 共に符号付き整数 */
/* EBX以外を破壊 */
{
	GAPI_WORK *work == ES:0x0000;
	char *p == DS:EDI /* カーソルアドレス */, *q == ES:EAX;
	char maskflag == CL;
	signed int x == ESI, y == EBP, mouseline == EDX;

	mouseline = 16;
	maskflag = 0;
	x = work->mx;
	y = work->my;
	(offset) q = x;
	x &= /* ~0x03 */ 0xfffffffc;
	work->my0 = y;
	y += 16;
	work->mx0 = x;
	x += 20;
	work->my1 = y;
	y -= 16;
	TEST(/* (char) (offset) q */ AL, 0x03);
	/* (false) */ if (== 0) {
		x -= 4;
		maskflag = 0x10;
	}
	work->mx1 = x;
	x = (offset) q;
	(offset) q &= 0x03;
	(offset) q *= 128;
	(offset) q *= 5;
	/* (false) */ if (x < 0) {
		work->mx0 = 0;
		maskflag |= 0x01;
		if (x < 0 - 4) {
			maskflag |= 0x03;
			if (x < 0 - 8) {
				maskflag |= 0x07;
				if (x < 0 - 12) {
					maskflag |= 0x0f;
				}
			}
		}
	} else /* (false) */ if (x >= TWVSW - 16) {
		work->mx1 = TWVSW;
		maskflag |= 0x10;
		if (x >= TWVSW - 12) {
			maskflag |= 0x18;
			if (x >= TWVSW - 8) {
				maskflag |= 0x1c;
				if (x >= TWVSW - 4) {
					maskflag |= 0x1e;
				}
			}
		}
	}
	PUSH(x);
	x &= /* ~0x03 */ 0xfffffffc;
	x += 0xe0000000;
//	/* (false) */ if (y < 0) {
//			work->my0 = 0;
//			mouseline += y;
//			(offset) q -= y;
//			y = 0;
//			(offset) p = 0;
//			goto skip_imul;
//	}
//	/* (false) */ if (y > 600 - 16) {
//			mouseline = 600;
//			work->my1 = mouseline;
//			mouseline -= y;
//	}
//	IMUL((offset) p, y, 100);
	(offset) p = y;
	IMUL_TWVSW((offset) p);
skip_imul:
	work->maskflag = maskflag;
	work->mouseline = mouseline;
	(offset) q += /* (offset) &work->mouse_pattern */ 384;
	(offset) p += x;
	work->pattern_addr = (offset) q;
	work->cursor_addr = (offset) p;

	/* 自動スクロールルーチン by I.Tak. 2001.11.25 */
	/* (註)川合が勝手に一部改正している */

	/* by I.Tak. since 2001.10.07(Sun) */
	/* 2001.11.01(Thu) v0.2   For the first time works well in ASKA. */
	/* 2001.11.18(Sun) v0.3   Corrected X-pos and if statement. */
	/* 2001.11.24(Sat) v0.4   one-dot horizonal and vertical scroll. */
	/* 2001.11.28(Wed) v0.4.1 1dot-scroll became optional. Optimized.*/

	unsigned int vx == ESI, vy == EBP; /* vectors */
	unsigned int sx == ECX, sy == EAX; /* screen positons */
	unsigned int haj == ESI;
	WORK_SUB *wsub == ES:EDI;
	GAPI_WORK *work_DS == DS:0x0000;

	/* Calc. Vectors */
	LEA((offset) wsub, (int) [work_DS->worksub]);
	POP(vx); /* mouse x */
	sx = wsub->scr_x0;
	sy = wsub->scr_y0;
	vx -= sx;
	if ((unsigned) >= 0) {
		vx -= wsub->scr_width;
		/* vx = (vx < 0) ? 0 : vx + 1; */
		SBB(EDX, EDX);
		NOT(EDX);
		vx &= EDX;
		vx -= EDX;
	}
	vy -= sy;
	if ((unsigned) >= 0) {
	//	vy += 15;
		vy -= wsub->scr_height;
		/* vy = (vy < 0) ? 0 : vy + 1; */
		SBB(EDX, EDX);
		NOT(EDX);
		vy &= EDX;
		vy -= EDX;
	}

	/* Scroll Part */
	sy += vy;
	vy |= vx;
	if (!= 0) {
		sx += vx;
		wsub->scr_y0 = sy;
		wsub->scr_x0 = sx;
		#if (defined(TWSCRL1))
			/* From now EBP, ESI(== vx, vy) can be destroyed. */
			EBP = sx;
			haj = sx;
			#if (defined(TWVSWlog2))
				EBP <<= 32 - TWVSWlog2;
				haj &= 7;
				SHRD(EBP, sy, 32 - TWVSWlog2 + 3); /* FA = yyyyyyyy:yxxxxxxxb */
			#else
				IMUL(sy, TWVSW / 8);
				EBP /= 8;
				haj &= 7;
				EBP + = sy; /* FA = yyyyyyyy:yxxxxxxxb */
		 	#endif
			NEG(haj);
			EDX = 0x0440;
			haj += 0x8a;
			            AL =  18; OUT(DX,  AL); /* HAJ0 */
			DL = 0x42; EAX = haj; OUT(DX, EAX);
			DL = 0x40;  AL =  22; OUT(DX,  AL); /* HAJ1 */
			DL = 0x42; EAX = haj; OUT(DX, EAX);
			DL = 0x40;  AL =  17; OUT(DX,  AL); /* FA0 */
			DL = 0x42; EAX = EBP; OUT(DX, EAX);
			DL = 0x40;  AL =  21; OUT(DX,  AL); /* FA1 */
			DL = 0x42; EAX = EBP; OUT(DX, EAX);
		#else
			#if (defined(TWVSWlog2))
				sx <<= 32 - TWVSWlog2;
				EDX = 0x0440;
				SHRD(sx, sy, 32 - TWVSWlog2 + 3); /* FA = yyyyyyyy:yxxxxxxxb */
			#else
				IMUL(sy, TWVSW / 8);
				sx /= 8;
				EDX = 0x440;
				sx += sy; /* FA = yyyyyyyy:yxxxxxxxb */
			#endif
			            AL = 17; OUT(DX,  AL); /* FA0 */
			DL = 0x42; EAX = sx; OUT(DX, EAX);
			DL = 0x40;  AL = 21; OUT(DX,  AL); /* FA1 */
			DL = 0x42; EAX = sx; OUT(DX, EAX);
		#endif
	}

	return;
}
