fpu: Have opcode 0xDF use fixed_g instruction functions

This commit is contained in:
Amaan Cheval 2018-03-22 19:19:36 +05:30 committed by Fabian
parent cd17dda054
commit 1f0e7c3ce0
3 changed files with 28 additions and 150 deletions

View file

@ -163,8 +163,6 @@ const encodings = [
{ opcode: 0xD6, nonfaulting: 1, },
{ opcode: 0xD7, skip: 1, },
{ opcode: 0xDF, e: 1, skip: 1, },
{ opcode: 0xE0, imm8s: 1, skip: 1, jump: 1, },
{ opcode: 0xE1, imm8s: 1, skip: 1, jump: 1, },
{ opcode: 0xE2, imm8s: 1, skip: 1, jump: 1, },
@ -665,6 +663,7 @@ for(let i = 0; i < 8; i++)
{ opcode: 0xDC, e: 1, fixed_g: i, skip: 1, },
{ opcode: 0xDD, e: 1, fixed_g: i, skip: 1, },
{ opcode: 0xDE, e: 1, fixed_g: i, skip: 1, },
{ opcode: 0xDF, e: 1, fixed_g: i, skip: 1, },
]);
}

View file

@ -966,149 +966,3 @@ void fpu_fistp(int32_t addr)
fpu_pop();
}
void fpu_op_DF_reg(int32_t imm8)
{
dbg_log_fpu_op(0xDF, imm8);
int32_t mod = imm8 >> 3 & 7;
int32_t low = imm8 & 7;
switch(mod)
{
case 4:
if(imm8 == 0xE0)
{
// fnstsw
reg16[AX] = fpu_load_status_word();
}
else
{
dbg_log("%x", imm8);
fpu_unimpl();
}
break;
case 5:
// fucomip
fpu_fucomi(low);
fpu_pop();
break;
case 6:
// fcomip
fpu_fcomi(low);
fpu_pop();
break;
default:
dbg_log("%x", mod);
fpu_unimpl();
}
}
void fpu_op_DF_mem(int32_t mod, int32_t addr)
{
dbg_log_fpu_op(0xDF, mod);
switch(mod)
{
case 0:
{
int32_t m16 = safe_read16(addr) << 16 >> 16;
fpu_push(m16);
}
break;
case 1:
// fisttp
dbg_log("df/fisttp");
fpu_unimpl();
break;
case 2:
// fist
{
double_t st0 = fpu_integer_round(fpu_get_st0());
if(st0 <= 0x7FFF && st0 >= -0x8000)
{
safe_write16(addr, st0);
}
else
{
fpu_invalid_arithmetic();
safe_write16(addr, 0x8000);
}
}
break;
case 3:
// fistp
{
double_t st0 = fpu_integer_round(fpu_get_st0());
if(st0 <= 0x7FFF && st0 >= -0x8000)
{
safe_write16(addr, st0);
}
else
{
fpu_invalid_arithmetic();
safe_write16(addr, 0x8000);
}
fpu_pop();
}
break;
case 4:
// fbld
dbg_log("fbld");
fpu_unimpl();
break;
case 5:
// fild
// XXX: Use safe_read64s
{
uint32_t low = safe_read32s(addr);
int32_t high = safe_read32s(addr + 4);
double_t m64 = (double_t)low + 0x100000000 * (double_t)high;
fpu_push(m64);
}
break;
case 6:
// fbstp
dbg_log("fbstp");
fpu_unimpl();
break;
case 7:
{
// fistp
writable_or_pagefault(addr, 8);
double_t st0 = fpu_integer_round(fpu_get_st0());
//union f64_int v = { .f64 = st0 };
//dbg_log("fistp %x %x", v.i32[0], v.i32[1]);
int32_t st0_low;
int32_t st0_high;
if(st0 < TWO_POW_63 && st0 >= -TWO_POW_63)
{
int64_t st0_int = st0;
st0_low = st0_int;
st0_high = st0_int >> 32;
}
else
{
// write 0x8000000000000000
st0_low = 0;
st0_high = 0x80000000;
fpu_invalid_arithmetic();
}
// XXX: Use safe_write64
safe_write32(addr, st0_low);
safe_write32(addr + 4, st0_high);
fpu_pop();
}
break;
default:
dbg_assert(false);
}
}

View file

@ -1366,9 +1366,34 @@ void instr_DE_7_reg(int32_t r)
fpu_pop();
}
void instr_DF_mem(int32_t addr, int32_t r) { task_switch_test(); fpu_op_DF_mem(r, addr); }
void instr_DF_reg(int32_t r2, int32_t r) { task_switch_test(); fpu_op_DF_reg(0xC0 | r2 | r << 3); }
void instr_DF_0_mem(int32_t addr) { task_switch_test(); fpu_push((int16_t) safe_read16(addr)); }
void instr_DF_1_mem(int32_t addr) { dbg_log("df/fisttp"); trigger_ud(); }
void instr_DF_2_mem(int32_t addr) { task_switch_test(); fpu_fistm16(addr); }
void instr_DF_3_mem(int32_t addr) { task_switch_test(); fpu_fistm16p(addr); }
void instr_DF_4_mem(int32_t addr) { dbg_log("fbld"); trigger_ud(); }
void instr_DF_5_mem(int32_t addr) { task_switch_test(); fpu_fild(addr); }
void instr_DF_6_mem(int32_t addr) { dbg_log("fbstp"); trigger_ud(); }
void instr_DF_7_mem(int32_t addr) { task_switch_test(); fpu_fistp(addr); }
void instr_DF_0_reg(int32_t r) { trigger_ud(); }
void instr_DF_1_reg(int32_t r) { trigger_ud(); }
void instr_DF_2_reg(int32_t r) { trigger_ud(); }
void instr_DF_3_reg(int32_t r) { trigger_ud(); }
void instr_DF_4_reg(int32_t r)
{
task_switch_test();
if(r == 0)
{
fpu_fnstsw_reg();
}
else
{
trigger_ud();
}
}
void instr_DF_5_reg(int32_t r) { task_switch_test(); fpu_fucomip(r); }
void instr_DF_6_reg(int32_t r) { task_switch_test(); fpu_fcomip(r); }
void instr_DF_7_reg(int32_t r) { trigger_ud(); }
void instr_E0(int32_t off) { loopne(off); }
void instr_E1(int32_t off) { loope(off); }