text: #include "cpu/instr.h"
  
  // reference: http://www.felixcloutier.com/x86/
  
  static uint32_t f2u(float val)
  {
  	uint32_t *temp = (uint32_t *)&val;
  	return *temp;
  }
  
  static float u2f(uint32_t val)
  {
  	float *temp = (float *)&val;
  	return *temp;
  }
  
  typedef union {
  	double dval;
  	uint32_t uval[2];
  } DOUBLE;
  
  make_instr_func(x87_fldl)
  {
  	int len = 1;
  	DOUBLE temp;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	temp.uval[0] = opr_src.val;
  	opr_src.addr += 4;
  	operand_read(&opr_src);
  	temp.uval[1] = opr_src.val;
  	print_asm_0("fldl", "", len);
  	fpu_load(f2u((float)temp.dval));
  	return len;
  }
  
  make_instr_func(x87_flds)
  {
  	int len = 1;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	print_asm_0("flds", "", len);
  	fpu_load(opr_src.val);
  	return len;
  }
  
  make_instr_func(x87_fildl)
  {
  	int len = 1;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	fpu_load(f2u((float)((int)opr_src.val)));
  	print_asm_0("fildl", "", len);
  	return len;
  }
  
  make_instr_func(x87_fldx)
  {
  	int len = 2;
  	fflush(stdout);
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xE8:
  		fpu_load(f2u(1.0));
  		break;
  	case 0xE9:
  		assert(0);
  		break;
  	case 0xEA:
  		assert(0);
  		break;
  	case 0xEB:
  		assert(0);
  		break;
  	case 0xEC:
  		assert(0);
  		break;
  	case 0xED:
  		assert(0);
  		break;
  	case 0xEE:
  		fpu_load(f2u(0.0));
  		break;
  	default: // fldcw
  		len = 1;
  		opr_dest.data_size = 16;
  		len += modrm_rm(eip + 1, &opr_dest);
  		operand_read(&opr_dest);
  		fpu.control.val = opr_dest.val;
  		print_asm_0("fldcw", "", len);
  		break;
  	}
  	return len;
  }
  
  make_instr_func(x87_fadds)
  {
  	int len = 1;
  	uint32_t idx;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xC0:
  	case 0xC1:
  	case 0xC2:
  	case 0xC3:
  	case 0xC4:
  	case 0xC5:
  	case 0xC6:
  	case 0xC7:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_add_idx(idx, 0);
  		len++;
  		break;
  	default: //fadds m32fp
  		opr_src.data_size = 32;
  		len += modrm_rm(eip + 1, &opr_src);
  		operand_read(&opr_src);
  		fpu_add(opr_src.val);
  	}
  	print_asm_0("fadds", "", len);
  	return len;
  }
  
  make_instr_func(x87_faddx)
  {
  	int len = 1;
  	uint32_t idx;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xC0:
  	case 0xC1:
  	case 0xC2:
  	case 0xC3:
  	case 0xC4:
  	case 0xC5:
  	case 0xC6:
  	case 0xC7:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_add_idx(idx, idx);
  		fpu_store();
  		len++;
  		break;
  	default: //fiadd m16int
  		opr_src.data_size = 16;
  		len += modrm_rm(eip + 1, &opr_src);
  		operand_read(&opr_src);
  		fpu_add(f2u((float)((int)opr_src.val)));
  	}
  	print_asm_0("fadd", "", len);
  	return len;
  }
  
  make_instr_func(x87_faddlx)
  {
  	int len = 1;
  	uint32_t idx;
  	DOUBLE temp;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xC0:
  	case 0xC1:
  	case 0xC2:
  	case 0xC3:
  	case 0xC4:
  	case 0xC5:
  	case 0xC6:
  	case 0xC7:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_add_idx(idx, idx);
  		len++;
  		break;
  	default: //faddl
  		opr_src.data_size = 32;
  		len += modrm_rm(eip + 1, &opr_src);
  		operand_read(&opr_src);
  		temp.uval[0] = opr_src.val;
  		opr_src.addr += 4;
  		operand_read(&opr_src);
  		temp.uval[1] = opr_src.val;
  		fpu_add(f2u((float)(temp.dval)));
  	}
  	print_asm_0("faddl", "", len);
  	return len;
  }
  
  make_instr_func(x87_fsubs)
  {
  	int len = 1;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	fpu_sub(opr_src.val);
  	print_asm_0("fsubs", "", len);
  	return len;
  }
  
  make_instr_func(x87_fmuls)
  {
  	int len = 1;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	fpu_mul(opr_src.val);
  	print_asm_0("fmuls", "", len);
  	return len;
  }
  
  make_instr_func(x87_fmullx)
  {
  	int len = 1;
  	uint32_t idx;
  	DOUBLE temp;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xC8:
  	case 0xC9:
  	case 0xCA:
  	case 0xCB:
  	case 0xCC:
  	case 0xCD:
  	case 0xCE:
  	case 0xCF:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_mul_idx(idx, idx);
  		len++;
  		break;
  	default: //fmul m64fp
  		opr_src.data_size = 32;
  		len += modrm_rm(eip + 1, &opr_src);
  		operand_read(&opr_src);
  		temp.uval[0] = opr_src.val;
  		opr_src.addr += 4;
  		operand_read(&opr_src);
  		temp.uval[1] = opr_src.val;
  		fpu_mul(f2u((float)(temp.dval)));
  	}
  	print_asm_0("fmull", "", len);
  	return len;
  }
  
  make_instr_func(x87_fdivs)
  {
  	int len = 1;
  	opr_src.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_src);
  	operand_read(&opr_src);
  	fpu_div(opr_src.val);
  	print_asm_0("fdivs", "", len);
  	return len;
  }
  
  make_instr_func(x87_fstps)
  {
  	int len = 1;
  	opr_dest.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_dest);
  	opr_dest.val = fpu_store();
  	operand_write(&opr_dest);
  	print_asm_0("fstps", "", len);
  	return len;
  }
  
  make_instr_func(x87_fxch)
  {
  	uint32_t idx = instr_fetch(eip + 1, 1) & 0x7;
  	fpu_xch(idx);
  	print_asm_0("fxch", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fucompp)
  {
  	fpu_cmp(1);
  	fpu_store();
  	fpu_store();
  	print_asm_0("fucompp", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fnstsw)
  {
  	cpu.gpr[0]._16 = fpu.status.val;
  	print_asm_0("fnstsw", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fstpx)
  {
  	int len = 1;
  	uint32_t idx;
  	DOUBLE temp;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xD8:
  	case 0xD9:
  	case 0xDA:
  	case 0xDB:
  	case 0xDC:
  	case 0xDD:
  	case 0xDE:
  	case 0xDF:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_copy(idx);
  		fpu_store();
  		len++;
  		break;
  	default: // fstpl
  		opr_dest.data_size = 32;
  		len += modrm_rm(eip + 1, &opr_dest);
  		temp.dval = (double)u2f(fpu_store());
  		opr_dest.val = temp.uval[0];
  		operand_write(&opr_dest);
  		opr_dest.addr += 4;
  		opr_dest.val = temp.uval[1];
  		operand_write(&opr_dest);
  	}
  	print_asm_0("fstp", "", len);
  	return len;
  }
  
  make_instr_func(x87_fstx)
  {
  	int len = 1;
  	uint32_t idx;
  	DOUBLE temp;
  	switch (instr_fetch(eip + 1, 1))
  	{
  	case 0xD0:
  	case 0xD1:
  	case 0xD2:
  	case 0xD3:
  	case 0xD4:
  	case 0xD5:
  	case 0xD6:
  	case 0xD7:
  		idx = instr_fetch(eip + 1, 1) & 0x7;
  		fpu_copy(idx);
  		len++;
  		break;
  	default: // fstl
  		opr_dest.data_size = 32;
  		len += modrm_rm(eip + 1, &opr_dest);
  		temp.dval = (double)u2f(fpu_peek());
  		opr_dest.val = temp.uval[0];
  		operand_write(&opr_dest);
  		opr_dest.addr += 4;
  		opr_dest.val = temp.uval[1];
  		operand_write(&opr_dest);
  	}
  	print_asm_0("fst", "", len);
  	return len;
  }
  
  make_instr_func(x87_fsts)
  {
  	int len = 1;
  	opr_dest.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_dest);
  	opr_dest.val = fpu_peek();
  	operand_write(&opr_dest);
  	print_asm_0("fsts", "", len);
  	return len;
  }
  
  make_instr_func(x87_fucom)
  {
  	uint32_t idx = instr_fetch(eip + 1, 1) & 0x7;
  	fpu_cmp(idx);
  	print_asm_0("fucom", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fucomi)
  {
  	uint32_t idx = instr_fetch(eip + 1, 1) & 0x7;
  	fpu_cmpi(idx);
  	print_asm_0("fucomi", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fcomi)
  {
  	return x87_fucomi(eip, opcode);
  }
  
  make_instr_func(x87_fucomip)
  {
  	uint32_t idx = instr_fetch(eip + 1, 1) & 0x7;
  	fpu_cmpi(idx);
  	fpu_store();
  	print_asm_0("fucomip", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fcomip)
  {
  	return x87_fucomip(eip, opcode);
  }
  
  make_instr_func(x87_fucomp)
  {
  	uint32_t idx = instr_fetch(eip + 1, 1) & 0x7;
  	fpu_cmp(idx);
  	fpu_store();
  	print_asm_0("fucomp", "", 2);
  	return 2;
  }
  
  make_instr_func(x87_fnstcw)
  {
  	int len = 1;
  	opr_dest.data_size = 16;
  	len += modrm_rm(eip + 1, &opr_dest);
  	opr_dest.val = fpu.control.val;
  	operand_write(&opr_dest);
  	print_asm_0("fnstcw", "", len);
  	return len;
  }
  
  make_instr_func(x87_fistpl)
  {
  	int len = 1;
  	float f;
  	uint32_t u;
  	int i;
  	opr_dest.data_size = 32;
  	len += modrm_rm(eip + 1, &opr_dest);
  	u = fpu_store();
  	f = u2f(u);
  	i = (int)f;
  	opr_dest.val = i;
  	operand_write(&opr_dest);
  	print_asm_0("fistpl", "", len);
  	return len;
  }
  