/*******************************************************************************/
/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas             */
/*                                                                             */
#include "types.h"
#include "video.h"
#include "debug.h"

u8     *r8[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
u8     *r16[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
u8     *r32[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
u8     *rseg[] = { "ds", "es", "fs", "gs", "ss", "cs", "ip" };

/*******************************************************************************/
/* Efface un breakpoint sur une adresse */
void cleardebugreg(u8 * address)
{
	for (u8 i = 0; i < 4; i++)
		if (getdebugreg(i) == address)
			setdebugreg(i, 0x0, DBG_CLEAR);
}

/*******************************************************************************/
/* Permet de manipuler dr0-dr7 pour mettre en place des breakpoints */

u8     *getdebugreg(u8 number)
{
	u8     *address;
	if (number == 0)
	      asm("mov %%dr0,%%eax; mov %%eax,%[address]":[address]
		    "=m"
		    (address)::);
	else if (number == 1)
	      asm("mov %%dr1,%%eax; movl %%eax,%[address]":[address]
		    "=m"
		    (address)::);
	else if (number == 2)
	      asm("mov %%dr2,%%eax; movl %%eax,%[address]":[address]
		    "=m"
		    (address)::);
	else if (number == 3)
	      asm("mov %%dr0,%%eax; movl %%eax,%[address]":[address]
		    "=m"
		    (address)::);
	return address;
}

/*******************************************************************************/
/* Permet de manipuler dr0-dr7 pour mettre en place des breakpoints */

void setdebugreg(u8 number, u8 * address, u8 type)
{
	u32     dr7 = 0;
      asm("movl %%dr7,%%eax; mov %%eax,%[dr7]":[dr7] "=m"(dr7)::);
	if (type == DBG_WRITE || type == DBG_READWRITE)
		dr7 |= 0x3 << 8;
	if (type != DBG_CLEAR)
		dr7 |= 0x3 << (number << 1);
	else
		dr7 &= ~(0x3 << (number << 1));
	dr7 &= ~(0x3 << (16 + (number << 2)));
	dr7 |= type << (16 + (number << 2));
	dr7 &= ~(0x3 << (16 + ((number << 2) + 2)));
      asm("movl %[dr7],%%eax; mov %%eax,%%dr7"::[dr7] "m"(dr7):);
	if (number == 0)
	      asm("movl %[address],%%eax; mov %%eax,%%dr0"::[address] "m"(address):);
	else if (number == 1)
	      asm("movl %[address],%%eax; mov %%eax,%%dr1"::[address] "m"(address):);
	else if (number == 2)
	      asm("movl %[address],%%eax; mov %%eax,%%dr2"::[address] "m"(address):);
	else if (number == 3)
	      asm("movl %[address],%%eax; mov %%eax,%%dr3"::[address] "m"(address):);
	else
		return;
}

/*******************************************************************************/
/* Fonctions de déboguage */

u16 decodeModSM(bool show, u8 * a, u8 * op, u16 order, u32 Gsz, u32 Esz)
{
	u32     len = 0;
	u32     reg = 0;
	u32     scale = 0;
	u8     *b = a;
	u8     *E, *G, *indx, *base, *disp = "\0";
	u8      ebuf[32] = { 0 };

	setG();

	if (Esz)
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[bx+si]";
				break;
			case 0x01:
				E = "[bx+di]";
				break;
			case 0x02:
				E = "[bp+si]";
				break;
			case 0x03:
				E = "[bp+di]";
				break;
			case 0x04:
				E = "[si]";
				break;
			case 0x05:
				E = "[di]";
				break;
			case 0x06:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x07:
				E = "[bx]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x44:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x84:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0xc0:
				E = "al";
				break;
			case 0xc1:
				E = "cl";
				break;
			case 0xc2:
				E = "dl";
				break;
			case 0xc3:
				E = "bl";
				break;
			case 0xc4:
				E = "ah";
				break;
			case 0xc5:
				E = "ch";
				break;
			case 0xc6:
				E = "dh";
				break;
			case 0xc7:
				E = "bh";
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}
	else
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[eax]";
				break;
			case 0x01:
				E = "[ecx]";
				break;
			case 0x02:
				E = "[edx]";
				break;
			case 0x03:
				E = "[ebx]";
				break;
			case 0x04:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s]", base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s]", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i]", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s]", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i]", base, indx,
						 scale);
				}
				E = ebuf;
				break;
			case 0x05:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x06:
				E = "[esi]";
				break;
			case 0x07:
				E = "[edi]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x44:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x84:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u32 *)++ b);
				b += 3;
				E = ebuf;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0xc0:
				E = Esz == 1 ? "ax" : "eax";
				break;
			case 0xc1:
				E = Esz == 1 ? "cx" : "ecx";
				break;
			case 0xc2:
				E = Esz == 1 ? "dx" : "edx";
				break;
			case 0xc3:
				E = Esz == 1 ? "bx" : "ebx";
				break;
			case 0xc4:
				E = Esz == 1 ? "sp" : "esp";
				break;
			case 0xc5:
				E = Esz == 1 ? "bp" : "ebp";
				break;
			case 0xc6:
				E = Esz == 1 ? "si" : "esi";
				break;
			case 0xc7:
				E = Esz == 1 ? "di" : "edi";
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}

	if (order)
	{
		snprintf(op, opBufSz, "%s", E);
		len = strlen(op);
		if (Gsz)
		{
			snprintf(op + len, opBufSz - len, ", %s", G);
		}
	}
	else
	{
		snprintf(op, opBufSz, "%s, ", G);
		len = strlen(op);
		snprintf(op + len, opBufSz - len, "%s", E);
	}
	return b - a;
}

u32 decodeModSM_float(bool show, u8 * a, u8 * op, u32 order, u32 Gsz,
		      u32 Esz)
{
	u32     len = 0;
	u32     reg = 0;
	u32     scale = 0;
	u8     *b = a;
	u8     *E, *G, *indx, *base, *disp = "\0";
	u8      ebuf[32] = { 0 };

	setG();

	if (Esz)
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[bx+si]";
				break;
			case 0x01:
				E = "[bx+di]";
				break;
			case 0x02:
				E = "[bp+si]";
				break;
			case 0x03:
				E = "[bp+di]";
				break;
			case 0x04:
				E = "[si]";
				break;
			case 0x05:
				E = "[di]";
				break;
			case 0x06:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x07:
				E = "[bx]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x44:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x84:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0xc0:
				E = "st(0)";
				break;
			case 0xc1:
				E = "st(1)";
				break;
			case 0xc2:
				E = "st(2)";
				break;
			case 0xc3:
				E = "st(3)";
				break;
			case 0xc4:
				E = "st(4)";
				break;
			case 0xc5:
				E = "st(5)";
				break;
			case 0xc6:
				E = "st(6)";
				break;
			case 0xc7:
				E = "st(7)";
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}
	else
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[eax]";
				break;
			case 0x01:
				E = "[ecx]";
				break;
			case 0x02:
				E = "[edx]";
				break;
			case 0x03:
				E = "[ebx]";
				break;
			case 0x04:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s]", base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s]", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i]", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s]", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i]", base, indx,
						 scale);
				}
				E = ebuf;
				break;
			case 0x05:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x06:
				E = "[esi]";
				break;
			case 0x07:
				E = "[edi]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x44:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x84:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u32 *)++ b);
				b += 3;
				E = ebuf;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0xc0:
				E = "st(0)";
				break;
			case 0xc1:
				E = "st(1)";
				break;
			case 0xc2:
				E = "st(2)";
				break;
			case 0xc3:
				E = "st(3)";
				break;
			case 0xc4:
				E = "st(4)";
				break;
			case 0xc5:
				E = "st(5)";
				break;
			case 0xc6:
				E = "st(6)";
				break;
			case 0xc7:
				E = "st(7)";
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}

	if (order)
	{
		snprintf(op, opBufSz, "%s", E);
		len = strlen(op);
		if (Gsz)
		{
			snprintf(op + len, opBufSz - len, ", %s", G);
		}
	}
	else
	{
		snprintf(op, opBufSz, "%s, ", G);
		len = strlen(op);
		snprintf(op + len, opBufSz - len, "%s", E);
	}
	return b - a;
}

u32 decodeModSM_memonly(bool show, u8 * a, u8 * op, u32 order, u32 Gsz,
			u32 Esz)
{
	u32     len = 0;
	u32     reg = 0;
	u32     scale = 0;
	u8     *b = a;
	u8     *E, *G, *indx, *base, *disp = "\0";
	u8      ebuf[32] = { 0 };

	setG();

	if (Esz)
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[bx+si]";
				break;
			case 0x01:
				E = "[bx+di]";
				break;
			case 0x02:
				E = "[bp+si]";
				break;
			case 0x03:
				E = "[bp+di]";
				break;
			case 0x04:
				E = "[si]";
				break;
			case 0x05:
				E = "[di]";
				break;
			case 0x06:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x07:
				E = "[bx]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x44:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[bx+si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[bx+di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[bp+si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[bp+di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x84:
				snprintf(ebuf, sizeof(ebuf), "[si+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[di+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[bp+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[bx+%x]",
					 *(u16 *)++ b);
				E = ebuf;
				++b;
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}
	else
	{
		switch (*b & 0xc7)
		{
			case 0x00:
				E = "[eax]";
				break;
			case 0x01:
				E = "[ecx]";
				break;
			case 0x02:
				E = "[edx]";
				break;
			case 0x03:
				E = "[ebx]";
				break;
			case 0x04:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s]", base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s]", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i]", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s]", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i]", base, indx,
						 scale);
				}
				E = ebuf;
				break;
			case 0x05:
				snprintf(ebuf, sizeof(ebuf), "ds:%x",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x06:
				E = "[esi]";
				break;
			case 0x07:
				E = "[edi]";
				break;
			case 0x40:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x41:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x42:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x43:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u8 *)++ b);
				E = ebuf;
			case 0x44:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x45:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x46:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x47:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u8 *)++ b);
				E = ebuf;
				break;
			case 0x80:
				snprintf(ebuf, sizeof(ebuf), "[eax+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x81:
				snprintf(ebuf, sizeof(ebuf), "[ecx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				break;
			case 0x82:
				snprintf(ebuf, sizeof(ebuf), "[edx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x83:
				snprintf(ebuf, sizeof(ebuf), "[ebx+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x84:
				++b;
				decodeSIB();
				if (!indx)
				{
					snprintf(ebuf, sizeof(ebuf), "[%s",
						 base);
				}
				else if (!base)
				{
					if (!scale)
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s", indx);
					}
					else
					{
						snprintf(ebuf,
							 sizeof(ebuf),
							 "[%s*%i", indx,
							 scale);
					}
				}
				else if (!scale)
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s", base, indx);
				}
				else
				{
					snprintf(ebuf, sizeof(ebuf),
						 "[%s+%s*%i", base, indx,
						 scale);
				}
				len = strlen(ebuf);
				snprintf(ebuf + len, sizeof(ebuf) - len,
					 "+%x]", *(u32 *)++ b);
				b += 3;
				E = ebuf;
				break;
			case 0x85:
				snprintf(ebuf, sizeof(ebuf), "[ebp+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x86:
				snprintf(ebuf, sizeof(ebuf), "[esi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			case 0x87:
				snprintf(ebuf, sizeof(ebuf), "[edi+%x]",
					 *(u32 *)++ b);
				E = ebuf;
				b += 3;
				break;
			default:
				if (show)
					print("Invalid Mod R/M byte.");
				return 1000;
		}
	}

	if (order)
	{
		snprintf(op, opBufSz, "%s", E);
		len = strlen(op);
		if (Gsz)
		{
			snprintf(op + len, opBufSz - len, ", %s", G);
		}
	}
	else
	{
		snprintf(op, opBufSz, "%s, ", G);
		len = strlen(op);
		snprintf(op + len, opBufSz - len, "%s", E);
	}
	return b - a;
}

/*******************************************************************************/
/* Décode une adresse mémoire au format intel */

u32 disasm(u8 * a, u8 * string, bool show)
{
	u8     *f_entry;
	u16     entry;
	u8     *b = a;
	u32     len = 0;
	u32     flip_addr_sz = 0;
	u32     flip_imm_sz = 0;
	u32     EG = 1;
	u32     B = 1;
	u8     *s, *prefix, *seg_oride = "\0";
	u8      op1[opBufSz] = { 0 };

	if (*b == 0xf3)
	{
		prefix = "rep";
		++b;
	}
	else if (*b == 0xf2)
	{
		prefix = "repnz";
		++b;
	}
	else if (*b == 0xf0)
	{
		prefix = "lock";
		++b;
	}

	if (*b == 0x67)
	{
		flip_addr_sz = 1;
		++b;
	}
	if (*b == 0x66)
	{
		flip_imm_sz = 1;
		++b;
	}

	switch (*b)
	{
		case 0x2e:
			seg_oride = "cs";
			++b;
			break;
		case 0x36:
			seg_oride = "ss";
			++b;
			break;
		case 0x3e:
			seg_oride = "ds";
			++b;
			break;
		case 0x26:
			seg_oride = "es";
			++b;
			break;
		case 0x64:
			seg_oride = "fs";
			++b;
			break;
		case 0x65:
			seg_oride = "gs";
			++b;
	}

	if (*b == 0x0f)
	{

		if (show)
			print("Extended opcodes not implimented.\r\n");
		return 1000;

	}
	else
	{

		switch (*b)
		{
			case 0x00:
				s = "add";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x01:
				s = "add";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x02:
				s = "add";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x03:
				s = "add";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x04:
				s = "add";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x05:
				s = "add";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x06:
				s = "push    es";
				break;
			case 0x07:
				s = "pop     es";
				break;
			case 0x08:
				s = "or";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x09:
				s = "or";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x0a:
				s = "or";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x0b:
				s = "or";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x0c:
				s = "or";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x0d:
				s = "or";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x0e:
				s = "push    cs";
				break;
			case 0x10:
				s = "adc";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x11:
				s = "adc";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x12:
				s = "adc";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x13:
				s = "adc";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x14:
				s = "adc";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x15:
				s = "adc";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x16:
				s = "push    ss";
				break;
			case 0x17:
				s = "pop     ss";
				break;
			case 0x18:
				s = "sbb";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x19:
				s = "sbb";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x1a:
				s = "sbb";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x1b:
				s = "sbb";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x1c:
				s = "sbb";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x1d:
				s = "sbb";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x1e:
				s = "push    ds";
				break;
			case 0x1f:
				s = "pop     ds";
				break;
			case 0x20:
				s = "and";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x21:
				s = "and";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x22:
				s = "and";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x23:
				s = "and";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x24:
				s = "and";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x25:
				s = "and";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x27:
				s = "daa";
				break;
			case 0x28:
				s = "sub";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x29:
				s = "sub";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x2a:
				s = "sub";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x2b:
				s = "sub";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x2c:
				s = "sub";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x2d:
				s = "sub";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x2f:
				s = "das";
				break;
			case 0x30:
				s = "xor";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x31:
				s = "xor";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x32:
				s = "xor";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x33:
				s = "xor";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x34:
				s = "xor";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x35:
				s = "xor";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x37:
				s = "aaa";
				break;
			case 0x38:
				s = "cmp";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x39:
				s = "cmp";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x3a:
				s = "cmp";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x3b:
				s = "cmp";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x3c:
				s = "cmp";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0x3d:
				s = "cmp";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x3f:
				s = "aas";
				break;
			case 0x40:
				s = flip_imm_sz ? "inc     ax" :
					"inc     eax";
				break;
			case 0x41:
				s = flip_imm_sz ? "inc     cx" :
					"inc     ecx";
				break;
			case 0x42:
				s = flip_imm_sz ? "inc     dx" :
					"inc     edx";
				break;
			case 0x43:
				s = flip_imm_sz ? "inc     bx" :
					"inc     ebx";
				break;
			case 0x44:
				s = flip_imm_sz ? "inc     sp" :
					"inc     esp";
				break;
			case 0x45:
				s = flip_imm_sz ? "inc     bp" :
					"inc     ebp";
				break;
			case 0x46:
				s = flip_imm_sz ? "inc     si" :
					"inc     esi";
				break;
			case 0x47:
				s = flip_imm_sz ? "inc     di" :
					"inc     edi";
				break;
			case 0x48:
				s = flip_imm_sz ? "dec     ax" :
					"dec     eax";
				break;
			case 0x49:
				s = flip_imm_sz ? "dec     cx" :
					"dec     ecx";
				break;
			case 0x4a:
				s = flip_imm_sz ? "dec     dx" :
					"dec     edx";
				break;
			case 0x4b:
				s = flip_imm_sz ? "dec     bx" :
					"dec     ebx";
				break;
			case 0x4c:
				s = flip_imm_sz ? "dec     sp" :
					"dec     esp";
				break;
			case 0x4d:
				s = flip_imm_sz ? "dec     bp" :
					"dec     ebp";
				break;
			case 0x4e:
				s = flip_imm_sz ? "dec     si" :
					"dec     esi";
				break;
			case 0x4f:
				s = flip_imm_sz ? "dec     di" :
					"dec     edi";
				break;
			case 0x50:
				s = flip_imm_sz ? "push    ax" :
					"push    eax";
				break;
			case 0x51:
				s = flip_imm_sz ? "push    cx" :
					"push    ecx";
				break;
			case 0x52:
				s = flip_imm_sz ? "push    dx" :
					"push    edx";
				break;
			case 0x53:
				s = flip_imm_sz ? "push    bx" :
					"push    ebx";
				break;
			case 0x54:
				s = flip_imm_sz ? "push    sp" :
					"push    esp";
				break;
			case 0x55:
				s = flip_imm_sz ? "push    bp" :
					"push    ebp";
				break;
			case 0x56:
				s = flip_imm_sz ? "push    si" :
					"push    esi";
				break;
			case 0x57:
				s = flip_imm_sz ? "push    di" :
					"push    edi";
				break;
			case 0x58:
				s = flip_imm_sz ? "pop     ax" :
					"pop     eax";
				break;
			case 0x59:
				s = flip_imm_sz ? "pop     cx" :
					"pop     ecx";
				break;
			case 0x5a:
				s = flip_imm_sz ? "pop     dx" :
					"pop     edx";
				break;
			case 0x5b:
				s = flip_imm_sz ? "pop     bx" :
					"pop     ebx";
				break;
			case 0x5c:
				s = flip_imm_sz ? "pop     sp" :
					"pop     esp";
				break;
			case 0x5d:
				s = flip_imm_sz ? "pop     bp" :
					"pop     ebp";
				break;
			case 0x5e:
				s = flip_imm_sz ? "pop     si" :
					"pop     esi";
				break;
			case 0x5f:
				s = flip_imm_sz ? "pop     di" :
					"pop     edi";
				break;
			case 0x60:
				s = flip_imm_sz ? "pushaw" : "pusha";
				break;
			case 0x61:
				s = flip_imm_sz ? "popaw" : "popa";
				break;
			case 0x63:
				s = "arpl";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x68:
				s = "push";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1), "%x",
						 *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1), "%x",
						 *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x69:
				s = "imul";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				len = strlen(op1);
				if (flip_imm_sz)
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x6a:
				s = "push";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) *b);
			case 0x6b:
				s = "imul";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0x6c:
				s = flip_addr_sz ?
					"ins     bytes ptr es:[di], dx" :
					"insb";
				break;
			case 0x6d:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"ins     word ptr es:[di], dx"
						:
						"ins     dword ptr es:[di], dx";
				}
				else
				{
					s = flip_imm_sz ? "insw" : "insd";
				}
				break;
			case 0x6e:
				s = flip_addr_sz ?
					"outs    dx, byte ptr [si]" :
					"outsb";
				break;
			case 0x6f:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"outs    dx, word ptr [si]"
						:
						"outs    dx, dword ptr [si]";
				}
				else
				{
					s = flip_imm_sz ? "outsw" :
						"outsd";
				}
				break;
			case 0x70:
				s = "jo";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x71:
				s = "jno";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x72:
				s = "jb";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x73:
				s = "jnb";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x74:
				s = "jz";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x75:
				s = "jnz";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x76:
				s = "jbe";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x77:
				s = "ja";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x78:
				s = "js";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x79:
				s = "jns";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x7a:
				s = "jp";
				++b;
				break;
			case 0x7b:
				s = "jnp";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x7c:
				s = "jl";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x7d:
				s = "jnl";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x7e:
				s = "jle";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x7f:
				s = "jnle";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0x80:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "add";
						break;
					case 1:
						s = "or";
						break;
					case 2:
						s = "adc";
						break;
					case 3:
						s = "sbb";
						break;
					case 4:
						s = "and";
						break;
					case 5:
						s = "sub";
						break;
					case 6:
						s = "xor";
						break;
					case 7:
						s = "cmp";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0x81:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "add";
						break;
					case 1:
						s = "or";
						break;
					case 2:
						s = "adc";
						break;
					case 3:
						s = "sbb";
						break;
					case 4:
						s = "and";
						break;
					case 5:
						s = "sub";
						break;
					case 6:
						s = "xor";
						break;
					case 7:
						s = "cmp";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				if (flip_imm_sz)
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0x82:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "add";
						break;
					case 1:
						s = "or";
						break;
					case 2:
						s = "adc";
						break;
					case 3:
						s = "sbb";
						break;
					case 4:
						s = "and";
						break;
					case 5:
						s = "sub";
						break;
					case 6:
						s = "xor";
						break;
					case 7:
						s = "cmp";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0x83:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "add";
						break;
					case 1:
						s = "or";
						break;
					case 2:
						s = "adc";
						break;
					case 3:
						s = "sbb";
						break;
					case 4:
						s = "and";
						break;
					case 5:
						s = "sub";
						break;
					case 6:
						s = "xor";
						break;
					case 7:
						s = "cmp";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0x84:
				s = "test";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x85:
				s = "test";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x86:
				s = "xchg";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x87:
				s = "xchg";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x88:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 1, 1,
						 flip_addr_sz);
				break;
			case 0x89:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 1,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x8a:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 0, 1,
						 flip_addr_sz);
				break;
			case 0x8b:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 0,
						 flip_imm_sz ? 2 : 3,
						 flip_addr_sz);
				break;
			case 0x8c:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 1, 4,
						 flip_addr_sz);
				break;
			case 0x8d:
				s = "lea";
				b += decodeModSM_memonly(show, ++b, op1, 0,
							 flip_imm_sz ? 2 :
							 3, flip_addr_sz);
				break;
			case 0x8e:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 0, 4,
						 flip_addr_sz);
				break;
			case 0x8f:
				s = "pop";
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				break;
			case 0x90:
				s = flip_imm_sz ? "xchg    ax, ax" : "nop";
				break;
			case 0x91:
				s = flip_imm_sz ? "xchg    ax, cx" :
					"xchg    eax, ecx";
				break;
			case 0x92:
				s = flip_imm_sz ? "xchg    ax, dx" :
					"xchg    eax, edx";
				break;
			case 0x93:
				s = flip_imm_sz ? "xchg    ax, bx" :
					"xchg    eax, ebx";
				break;
			case 0x94:
				s = flip_imm_sz ? "xchg    ax, sp" :
					"xchg    eax, esp";
				break;
			case 0x95:
				s = flip_imm_sz ? "xchg    ax, bp" :
					"xchg    eax, ebp";
				break;
			case 0x96:
				s = flip_imm_sz ? "xchg    ax, si" :
					"xchg    eax, esi";
				break;
			case 0x97:
				s = flip_imm_sz ? "xchg    ax, di" :
					"xchg    eax, edi";
				break;
			case 0x98:
				s = flip_imm_sz ? "cbw" : "cwde";
				break;
			case 0x99:
				s = flip_imm_sz ? "cwd" : "cdq";
				break;
			case 0x9a:
				s = "call";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1), "%x:%x",
						 *(u16 *) (b + 2),
						 *(u16 *)++ b);
					b += 3;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "far ptr %x:%x",
						 *(u16 *) (b + 4),
						 *(u32 *)++ b);
					b += 5;
				}
				break;
			case 0x9b:
				s = "wait";
				break;
			case 0x9c:
				s = flip_imm_sz ? "pushfw" : "pushf";
				break;
			case 0x9d:
				s = flip_imm_sz ? "popfw" : "popf";
				break;
			case 0x9e:
				s = "sahf";
				break;
			case 0x9f:
				s = "lahf";
				break;
			case 0xa0:
				s = "mov";
				snprintf(op1, sizeof(op1), "al, ds:%x",
					 *(u32 *)++ b);
				b += 3;
				break;
			case 0xa1:
				s = "mov";
				snprintf(op1, sizeof(op1),
					 flip_imm_sz ? "ax, ds:%x" :
					 "eax, ds:%x", *(u32 *)++ b);
				b += 3;
				break;
			case 0xa2:
				s = "mov";
				snprintf(op1, sizeof(op1), "ds:%x, al",
					 *(u32 *)++ b);
				b += 3;
				break;
			case 0xa3:
				s = "mov";
				snprintf(op1, sizeof(op1),
					 flip_imm_sz ? "ds:%x, ax" :
					 "ds:%x, eax", *(u32 *)++ b);
				b += 3;
				break;
			case 0xa4:
				s = flip_addr_sz ?
					"movs    byte ptr es:[di], byte ptr [si]"
					: "movsb";
				break;
			case 0xa5:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"movs    word ptr es:[di], word ptr [si]"
						:
						"movs    dword ptr es:[di], dword ptr [si]";
				}
				else
				{
					s = flip_imm_sz ? "movsw" :
						"movsd";
				}
				break;
			case 0xa6:
				s = flip_addr_sz ?
					"cmps    byte ptr [si], byte ptr es:[di]"
					: "cmpsb";
				break;
			case 0xa7:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"movs    word ptr [si], word ptr es:[di]"
						:
						"movs    dword ptr [si], dword ptr es:[di]";
				}
				else
				{
					s = flip_imm_sz ? "cmpsw" :
						"cmpsd";
				}
				break;
			case 0xa8:
				s = "test";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0xa9:
				s = "test";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					b += 3;
				}
				break;
			case 0xaa:
				s = flip_addr_sz ?
					"stos    byte ptr es:[di]" :
					"stosb";
				break;
			case 0xab:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"stos    word ptr es:[di]"
						:
						"stos    dword ptr es:[di]";
				}
				else
				{
					s = flip_imm_sz ? "stosw" :
						"stosd";
				}
				break;
			case 0xac:
				s = flip_addr_sz ? "lods    byte ptr [si]"
					: "lodsb";
				break;
			case 0xad:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"lods    word ptr [si]" :
						"lods    dword ptr [si]";
				}
				else
				{
					s = flip_imm_sz ? "lodsw" :
						"lodsd";
				}
				break;
			case 0xae:
				s = flip_addr_sz ?
					"scas    byte ptr es:[di]" :
					"scasb";
				break;
			case 0xaf:
				if (flip_addr_sz)
				{
					s = flip_imm_sz ?
						"scas    word ptr es:[di]"
						:
						"scas    dword ptr es:[di]";
				}
				else
				{
					s = flip_imm_sz ? "scasw" :
						"scasd";
				}
				break;
			case 0xb0:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0xb1:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "cl, %x",
					 (void *) *b);
				break;
			case 0xb2:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "dl, %x",
					 (void *) *b);
				break;
			case 0xb3:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0xb4:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "ah, %x",
					 (void *) *b);
				break;
			case 0xb5:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "ch, %x",
					 (void *) *b);
				break;
			case 0xb6:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "dh, %x",
					 (void *) *b);
				break;
			case 0xb7:
				s = "mov";
				++b;
				snprintf(op1, sizeof(op1), "bh, %x",
					 (void *) *b);
				break;
			case 0xb8:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "ax, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "eax, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xb9:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "cx, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "ecx, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xba:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "dx, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "edx, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xbb:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "bx, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "ebx, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xbc:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "sp, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "esp, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xbd:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "bp, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "ebp, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xbe:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "si, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "esi, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xbf:
				s = "mov";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "di, %x", *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "edi, %x", *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xc0:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0xc1:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0xc2:
				s = "retn";
				snprintf(op1, sizeof(op1), "%x",
					 *(u16 *)++ b);
				++b;
				break;
			case 0xc3:
				s = "retn";
				break;
			case 0xc4:
				s = "les";
				b += decodeModSM_memonly(show, ++b, op1, 0,
							 flip_imm_sz ? 2 :
							 3, flip_addr_sz);
				break;
			case 0xc5:
				s = "lds";
				b += decodeModSM_memonly(show, ++b, op1, 0,
							 flip_imm_sz ? 2 :
							 3, flip_addr_sz);
				break;
			case 0xc6:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", %x", *(u8 *)++ b);
				break;
			case 0xc7:
				s = "mov";
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				len = strlen(op1);
				if (flip_imm_sz)
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u16 *)++ b);
					++b;
				}
				else
				{
					snprintf(op1 + len,
						 sizeof(op1) - len, ", %x",
						 *(u32 *)++ b);
					b += 3;
				}
				break;
			case 0xc8:
				s = "enter";
				snprintf(op1, sizeof(op1), "%x, %x",
					 *(u16 *) (b + 1),
					 *(u8 *) (b + 3));
				b += 3;
				break;
			case 0xc9:
				s = "leave";
				break;
			case 0xca:
				s = "retf";
				snprintf(op1, sizeof(op1), "%x",
					 *(u16 *)++ b);
				++b;
				break;
			case 0xcb:
				s = "retf";
				break;
			case 0xcc:
				s = "int     3";
				break;
			case 0xcd:
				s = "int";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) *b);
				break;
			case 0xce:
				s = "into";
				break;
			case 0xcf:
				s = "iret";
				break;
			case 0xd0:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", 1");
				break;
			case 0xd1:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", 1");
				break;
			case 0xd2:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", cl");
				break;
			case 0xd3:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "rol";
						break;
					case 1:
						s = "ror";
						break;
					case 2:
						s = "rcl";
						break;
					case 3:
						s = "rcr";
						break;
					case 4:
						s = "shl";
						break;
					case 5:
						s = "shr";
						break;
					case 6:
						s = "shl";
						break;
					case 7:
						s = "sar";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				len = strlen(op1);
				snprintf(op1 + len, sizeof(op1) - len,
					 ", cl");
				break;
			case 0xd4:
				s = "aam";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) *b);
				break;
			case 0xd5:
				s = "aad";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) *b);
				break;
			case 0xd6:
				s = "salc";
				break;
			case 0xd7:
				s = "xlat";
				break;
			case 0xd8:
				if (*++b == 0xd1)
				{
					s = "fcom    st(1)";
				}
				else if (*b == 0xd9)
				{
					s = "fcomp   st(1)";
				}
				else
				{
					switch ((*b & 0x38) >> 3)
					{
						case 0:
							s = "fadd";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 1:
							s = "fmul";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 2:
							s = "fcom";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 3:
							s = "fcomp";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 4:
							s = "fsub";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 5:
							s = "fsubr";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 6:
							s = "fdiv";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						case 7:
							s = "fdivr";
							b += decodeModSM_float(show, b, op1, 1, 0, flip_addr_sz);
							break;
						default:
							if (show)
								print("Invalid Mod R/M byte.");
							return 1000;
					}
				}
				break;
			case 0xe0:
				s = "loopnz";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0xe1:
				s = "loopz";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0xe2:
				s = "loop";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0xe3:
				s = "jcxz";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0xe4:
				s = "in";
				++b;
				snprintf(op1, sizeof(op1), "al, %x",
					 (void *) *b);
				break;
			case 0xe5:
				s = "in";
				++b;
				snprintf(op1, sizeof(op1),
					 flip_imm_sz ? "ax, %x" :
					 "eax, %x", (void *) *b);
				break;
			case 0xe6:
				s = "out";
				++b;
				snprintf(op1, sizeof(op1), "%x, al",
					 (void *) *b);
				break;
			case 0xe7:
				s = "in";
				++b;
				snprintf(op1, sizeof(op1),
					 flip_imm_sz ? "%x, ax" :
					 "%x, eax", (void *) *b);
				break;
			case 0xe8:
				s = "call";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1), "%x",
						 entry + (u32) b -
						 (u32) f_entry +
						 *(u16 *)++ b + 3);
					b += 2;
				}
				else
				{
					snprintf(op1, sizeof(op1), "%x",
						 (void *) entry + (u32) b -
						 (u32) f_entry +
						 *(u32 *)++ b + 4);
					b += 3;
				}
				break;
			case 0xe9:
				s = "jmp";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1),
						 "near ptr %x",
						 entry + (u32) b -
						 (u32) f_entry +
						 *(u16 *)++ b + 3);
					++b;
				}
				else
				{
					snprintf(op1, sizeof(op1),
						 "near ptr %x",
						 (void *) entry + (u32) b -
						 (u32) f_entry +
						 *(u32 *)++ b + 4);
					b += 3;
				}
				break;
			case 0xea:
				s = "jmp";
				if (flip_imm_sz)
				{
					snprintf(op1, sizeof(op1), "%x:%x",
						 *(u16 *) (b + 2),
						 *(u16 *)++ b);
					b += 3;
				}
				else
				{
					snprintf(op1, sizeof(op1), "%x:%x",
						 *(u16 *) (b + 4),
						 *(u32 *)++ b);
					b += 5;
				}
				break;
			case 0xeb:
				s = "jmp";
				++b;
				snprintf(op1, sizeof(op1), "%x",
					 (void *) entry + (u32) b -
					 (u32) f_entry + *b + 1);
				break;
			case 0xec:
				s = "in      al, dx";
				break;
			case 0xed:
				s = flip_imm_sz ? "in      ax, dx" :
					"in      eax, dx";
				break;
			case 0xee:
				s = "out     dx, al";
				break;
			case 0xef:
				s = flip_imm_sz ? "out     dx, ax" :
					"out     dx, eax";
				break;
			case 0xf1:
				s = "int     1";
				break;
			case 0xf4:
				s = "hlt";
				break;
			case 0xf5:
				s = "cmc";
				break;
			case 0xf6:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "test";
						len = strlen(op1);
						snprintf(op1 + len,
							 sizeof(op1) - len,
							 "%x",
							 *(u8 *)++ b);
						break;
					case 1:
						s = "test";
						len = strlen(op1);
						snprintf(op1 + len,
							 sizeof(op1) - len,
							 "%x",
							 *(u8 *)++ b);
						break;
					case 2:
						s = "not";
						break;
					case 3:
						s = "neg";
						break;
					case 4:
						s = "mul     ax, al, ";
						break;
					case 5:
						s = "imul    ax, al, ";
						break;
					case 6:
						s = "div     al, ah, ax, ";
						break;
					case 7:
						s = "idiv    al, ah, ax, ";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				break;
			case 0xf7:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				switch ((*b & 0x38) / 8)
				{
					case 0:
						s = "test";
						len = strlen(op1);
						if (flip_imm_sz)
						{
							snprintf(op1 + len,
								 sizeof
								 (op1) -
								 len, "%x",
								 *(u16 *)++
								 b);
							++b;
						}
						else
						{
							snprintf(op1 + len,
								 sizeof
								 (op1) -
								 len, "%x",
								 *(u32 *)++
								 b);
							b += 3;
						}
						break;
					case 1:
						s = "test";
						len = strlen(op1);
						if (flip_imm_sz)
						{
							snprintf(op1 + len,
								 sizeof
								 (op1) -
								 len, "%x",
								 *(u16 *)++
								 b);
							++b;
						}
						else
						{
							snprintf(op1 + len,
								 sizeof
								 (op1) -
								 len, "%x",
								 *(u32 *)++
								 b);
							b += 3;
						}
						break;
					case 2:
						s = "not";
						break;
					case 3:
						s = "neg";
						break;
					case 4:
						s = "mul     rdx, rax, ";
						break;
					case 5:
						s = "imul    rdx, rax, ";
						break;
					case 6:
						s = "div     rdx, rax, ";
						break;
					case 7:
						s = "idiv    rdx, rax, ";
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				break;
			case 0xf8:
				s = "clc";
				break;
			case 0xf9:
				s = "stc";
				break;
			case 0xfa:
				s = "cli";
				break;
			case 0xfb:
				s = "sti";
				break;
			case 0xfc:
				s = "cld";
				break;
			case 0xfd:
				s = "std";
				break;
			case 0xfe:
				b += decodeModSM(show, ++b, op1, 1, 0,
						 flip_addr_sz);
				if (!((*b & 0x38) / 8))
				{
					s = "inc";
				}
				else if ((*b & 0x38) / 8 == 1)
				{
					s = "dec";
				}
				else
				{
					if (show)
						print("Invalid Mod R/M byte.");
					return 1000;
				}
				break;
			case 0xff:
				switch ((*++b & 0x38) >> 3)
				{
					case 0:
						s = "inc";
						b += decodeModSM(show, b,
								 op1, 1, 0,
								 flip_addr_sz);
						break;
					case 1:
						s = "dec";
						b += decodeModSM(show, b,
								 op1, 1, 0,
								 flip_addr_sz);
						break;
					case 2:
						s = "call";
						b += decodeModSM(show, b,
								 op1, 1, 0,
								 flip_addr_sz);
						break;
					case 3:
						s = "callf";
						b += decodeModSM_memonly
							(show, b, op1, 1,
							 0, flip_addr_sz);
						break;
					case 4:
						s = "jmp";
						b += decodeModSM(show, b,
								 op1, 1, 0,
								 flip_addr_sz);
						break;
					case 5:
						s = "jmpf";
						b += decodeModSM_memonly
							(show, b, op1, 1,
							 0, flip_addr_sz);
						break;
					case 6:
						s = "push";
						b += decodeModSM(show, b,
								 op1, 1, 0,
								 flip_addr_sz);
						break;
					default:
						if (show)
							print("Invalid Mod R/M byte.");
						return 1000;
				}
				break;
			default:
				if (show)
					print("invalid opcode\r\n");
				return 1000;
		}
		strcompressdelimiter(s, ' ');
		if (show)
			printf(" %X:  %s %s\r\n", (u32) a, s, op1);
		else if (string != NULL)
			sprintf(string, " %X:  %s %s\r\n", (u32) a, s,
				op1);

		++b;

	}

	return b - a;
}
