fpu: Have opcode 0xD9 use fixed_g

This commit is contained in:
Amaan Cheval 2018-03-19 17:19:28 +05:30 committed by Fabian
parent 173be47658
commit df86637cb8
4 changed files with 235 additions and 216 deletions

View file

@ -163,7 +163,6 @@ const encodings = [
{ opcode: 0xD6, nonfaulting: 1, },
{ opcode: 0xD7, skip: 1, },
{ opcode: 0xD9, e: 1, skip: 1, },
{ opcode: 0xDA, e: 1, skip: 1, },
{ opcode: 0xDB, e: 1, skip: 1, },
{ opcode: 0xDC, e: 1, skip: 1, },
@ -665,6 +664,7 @@ for(let i = 0; i < 8; i++)
{ opcode: 0xD3, nonfaulting: 1, os: 1, e: 1, fixed_g: i, mask_flags: of | af, },
{ opcode: 0xD8, e: 1, fixed_g: i, skip: 1, },
{ opcode: 0xD9, e: 1, fixed_g: i, skip: 1, },
]);
}

View file

@ -352,7 +352,7 @@ void fpu_unimpl()
}
}
void fstenv(int32_t addr)
void fpu_fstenv(int32_t addr)
{
if(is_osize_32())
{
@ -376,7 +376,7 @@ void fstenv(int32_t addr)
}
}
void fldenv(int32_t addr)
void fpu_fldenv(int32_t addr)
{
if(is_osize_32())
{
@ -402,7 +402,7 @@ void fsave(int32_t addr)
{
writable_or_pagefault(addr, 108);
fstenv(addr);
fpu_fstenv(addr);
addr += 28;
for(int32_t i = 0; i < 8; i++)
@ -418,7 +418,7 @@ void fsave(int32_t addr)
void frstor(int32_t addr)
{
fldenv(addr);
fpu_fldenv(addr);
addr += 28;
for(int32_t i = 0; i < 8; i++)
@ -627,245 +627,184 @@ void fpu_fdivr(double_t val)
fpu_st[*fpu_stack_ptr] = val / st0;
}
void fpu_op_D9_reg(int32_t imm8)
void fpu_fxch(int32_t i)
{
dbg_log_fpu_op(0xD9, imm8);
double_t sti = fpu_get_sti(i);
fpu_st[*fpu_stack_ptr + i] = fpu_get_st0();
fpu_st[*fpu_stack_ptr] = sti;
}
int32_t mod = imm8 >> 3 & 7;
int32_t low = imm8 & 7;
void fpu_fst(int32_t addr)
{
fpu_store_m32(addr, fpu_get_st0());
}
switch(mod)
void fpu_fstp(int32_t addr)
{
fpu_fst(addr);
fpu_pop();
}
void fpu_op_D9_4_reg(int32_t r)
{
double_t st0 = fpu_get_st0();
switch(r)
{
case 0:
// fld
{
double_t sti = fpu_get_sti(low);
fpu_push(sti);
}
// fchs
fpu_st[*fpu_stack_ptr] = -st0;
break;
case 1:
// fxch
{
double_t sti = fpu_get_sti(low);
fpu_st[*fpu_stack_ptr + low & 7] = fpu_get_st0();
fpu_st[*fpu_stack_ptr] = sti;
}
break;
case 2:
switch(low)
{
case 0:
// fnop
break;
default:
dbg_log("%x", low);
fpu_unimpl();
}
break;
case 3:
// fstp1
dbg_log("fstp1");
fpu_unimpl();
// fabs
fpu_st[*fpu_stack_ptr] = fabs(st0);
break;
case 4:
{
double_t st0 = fpu_get_st0();
switch(low)
{
case 0:
// fchs
fpu_st[*fpu_stack_ptr] = -st0;
break;
case 1:
// fabs
fpu_st[*fpu_stack_ptr] = fabs(st0);
break;
case 4:
ftst(st0);
break;
case 5:
fxam(st0);
break;
default:
dbg_log("%x", low);
fpu_unimpl();
}
}
ftst(st0);
break;
case 5:
// fld1/fldl2t/fldl2e/fldpi/fldlg2/fldln2/fldz
switch(low)
{
case 0: fpu_push(1); break;
case 1: fpu_push(M_LN10 / M_LN2); break;
case 2: fpu_push(M_LOG2E); break;
case 3: fpu_push(M_PI); break;
case 4: fpu_push(M_LN2 / M_LN10); break;
case 5: fpu_push(M_LN2); break;
case 6: fpu_push(0); break;
case 7: dbg_log("d9/5/7"); fpu_unimpl(); break;
}
fxam(st0);
break;
default:
dbg_log("%x", r);
fpu_unimpl();
}
}
void fpu_op_D9_5_reg(int32_t r)
{
// fld1/fldl2t/fldl2e/fldpi/fldlg2/fldln2/fldz
switch(r)
{
case 0: fpu_push(1); break;
case 1: fpu_push(M_LN10 / M_LN2); break;
case 2: fpu_push(M_LOG2E); break;
case 3: fpu_push(M_PI); break;
case 4: fpu_push(M_LN2 / M_LN10); break;
case 5: fpu_push(M_LN2); break;
case 6: fpu_push(0); break;
case 7: dbg_log("d9/5/7"); fpu_unimpl(); break;
}
}
void fpu_op_D9_6_reg(int32_t r)
{
double_t st0 = fpu_get_st0();
switch(r)
{
case 0:
// f2xm1
fpu_st[*fpu_stack_ptr] = pow(2, st0) - 1;
break;
case 1:
// fyl2x
fpu_st[*fpu_stack_ptr + 1 & 7] = fpu_get_sti(1) * log(st0) / M_LN2;
fpu_pop();
break;
case 2:
// fptan
fpu_st[*fpu_stack_ptr] = tan(st0);
fpu_push(1); // no bug: push constant 1
break;
case 3:
// fpatan
fpu_st[*fpu_stack_ptr + 1 & 7] = atan2(fpu_get_sti(1), st0);
fpu_pop();
break;
case 4:
fxtract();
break;
case 5:
// fprem1
fpu_st[*fpu_stack_ptr] = fmod(st0, fpu_get_sti(1));
break;
case 6:
{
double_t st0 = fpu_get_st0();
switch(low)
{
case 0:
// f2xm1
fpu_st[*fpu_stack_ptr] = pow(2, st0) - 1;
break;
case 1:
// fyl2x
fpu_st[*fpu_stack_ptr + 1 & 7] = fpu_get_sti(1) * log(st0) / M_LN2;
fpu_pop();
break;
case 2:
// fptan
fpu_st[*fpu_stack_ptr] = tan(st0);
fpu_push(1); // no bug: push constant 1
break;
case 3:
// fpatan
fpu_st[*fpu_stack_ptr + 1 & 7] = atan2(fpu_get_sti(1), st0);
fpu_pop();
break;
case 4:
fxtract();
break;
case 5:
// fprem1
fpu_st[*fpu_stack_ptr] = fmod(st0, fpu_get_sti(1));
break;
case 6:
// fdecstp
*fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
*fpu_status_word &= ~FPU_C1;
break;
case 7:
// fincstp
*fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
*fpu_status_word &= ~FPU_C1;
break;
default:
dbg_assert(false);
}
}
// fdecstp
*fpu_stack_ptr = *fpu_stack_ptr - 1 & 7;
*fpu_status_word &= ~FPU_C1;
break;
case 7:
{
double_t st0 = fpu_get_st0();
switch(low)
{
case 0:
// fprem
{
double_t st1 = fpu_get_sti(1);
int32_t fprem_quotient = trunc(st0 / st1);
fpu_st[*fpu_stack_ptr] = fmod(st0, st1);
*fpu_status_word &= ~(FPU_C0 | FPU_C1 | FPU_C3);
if (fprem_quotient & 1) {
*fpu_status_word |= FPU_C1;
}
if (fprem_quotient & (1 << 1)) {
*fpu_status_word |= FPU_C3;
}
if (fprem_quotient & (1 << 2)) {
*fpu_status_word |= FPU_C0;
}
*fpu_status_word &= ~FPU_C2;
}
break;
case 1:
// fyl2xp1: y * log2(x+1) and pop
fpu_st[*fpu_stack_ptr + 1 & 7] = fpu_get_sti(1) * log(st0 + 1) / M_LN2;
fpu_pop();
break;
case 2:
fpu_st[*fpu_stack_ptr] = sqrt(st0);
break;
case 3:
fpu_st[*fpu_stack_ptr] = sin(st0);
fpu_push(cos(st0));
break;
case 4:
// frndint
fpu_st[*fpu_stack_ptr] = fpu_integer_round(st0);
break;
case 5:
// fscale
fpu_st[*fpu_stack_ptr] = st0 * pow(2, fpu_truncate(fpu_get_sti(1)));
break;
case 6:
fpu_st[*fpu_stack_ptr] = sin(st0);
break;
case 7:
fpu_st[*fpu_stack_ptr] = cos(st0);
break;
default:
dbg_assert(false);
}
}
// fincstp
*fpu_stack_ptr = *fpu_stack_ptr + 1 & 7;
*fpu_status_word &= ~FPU_C1;
break;
default:
dbg_assert(false);
}
}
void fpu_op_D9_mem(int32_t mod, int32_t addr)
void fpu_op_D9_7_reg(int32_t r)
{
dbg_log_fpu_op(0xD9, mod);
switch(mod)
{
case 0:
// fld
double_t st0 = fpu_get_st0();
switch(r)
{
case 0:
// fprem
{
double_t data = fpu_load_m32(addr);
fpu_push(data);
double_t st1 = fpu_get_sti(1);
int32_t fprem_quotient = trunc(st0 / st1);
fpu_st[*fpu_stack_ptr] = fmod(st0, st1);
*fpu_status_word &= ~(FPU_C0 | FPU_C1 | FPU_C3);
if (fprem_quotient & 1) {
*fpu_status_word |= FPU_C1;
}
if (fprem_quotient & (1 << 1)) {
*fpu_status_word |= FPU_C3;
}
if (fprem_quotient & (1 << 2)) {
*fpu_status_word |= FPU_C0;
}
*fpu_status_word &= ~FPU_C2;
}
break;
case 1:
// not defined
dbg_log("d9/1");
fpu_unimpl();
break;
case 2:
// fst
fpu_store_m32(addr, fpu_get_st0());
break;
case 3:
// fstp
fpu_store_m32(addr, fpu_get_st0());
fpu_pop();
break;
case 4:
fldenv(addr);
break;
case 5:
// fldcw
{
int32_t word = safe_read16(addr);
*fpu_control_word = word;
case 1:
// fyl2xp1: y * log2(x+1) and pop
fpu_st[*fpu_stack_ptr + 1 & 7] = fpu_get_sti(1) * log(st0 + 1) / M_LN2;
fpu_pop();
break;
case 2:
fpu_st[*fpu_stack_ptr] = sqrt(st0);
break;
case 3:
fpu_st[*fpu_stack_ptr] = sin(st0);
fpu_push(cos(st0));
break;
case 4:
// frndint
fpu_st[*fpu_stack_ptr] = fpu_integer_round(st0);
break;
case 5:
// fscale
fpu_st[*fpu_stack_ptr] = st0 * pow(2, fpu_truncate(fpu_get_sti(1)));
break;
case 6:
fpu_st[*fpu_stack_ptr] = sin(st0);
break;
case 7:
fpu_st[*fpu_stack_ptr] = cos(st0);
break;
default:
dbg_assert(false);
}
break;
case 6:
fstenv(addr);
break;
case 7:
// fstcw
safe_write16(addr, *fpu_control_word);
break;
default:
dbg_assert(false);
}
}
void fpu_fldcw(int32_t addr)
{
int32_t word = safe_read16(addr);
*fpu_control_word = word;
}
void fpu_fstcw(int32_t addr)
{
safe_write16(addr, *fpu_control_word);
}
void fpu_op_DA_reg(int32_t imm8)
{
dbg_log_fpu_op(0xDA, imm8);

View file

@ -12,10 +12,14 @@ void fpu_store_m80(uint32_t addr, double_t n);
double_t fpu_load_m80(uint32_t addr);
void fwait();
void fpu_push(double_t x);
double_t fpu_get_sti(int32_t i);
double_t fpu_load_m32(int32_t addr);
double_t fpu_load_m64(int32_t addr);
void fpu_fldenv(int32_t addr);
void fpu_fstenv(int32_t addr);
void fpu_fstcw(int32_t addr);
void fpu_fadd(double_t val);
void fpu_fmul(double_t val);
void fpu_fcomp(double_t val);
@ -23,6 +27,14 @@ void fpu_fsub(double_t val);
void fpu_fsubr(double_t val);
void fpu_fdiv(double_t val);
void fpu_fdivr(double_t val);
void fpu_fst(int32_t addr);
void fpu_fstp(int32_t addr);
void fpu_fxch(int32_t i);
void fpu_op_D9_4_reg(int32_t r);
void fpu_fldcw(int32_t addr);
void fpu_op_D9_5_reg(int32_t r);
void fpu_op_D9_6_reg(int32_t r);
void fpu_op_D9_7_reg(int32_t r);
void fpu_op_D8_mem(int32_t, int32_t);
void fpu_op_D8_reg(int32_t);

View file

@ -1082,8 +1082,76 @@ DEFINE_MODRM_INSTR_FPU_READ32(instr_D8_5, fpu_fsubr(___))
DEFINE_MODRM_INSTR_FPU_READ32(instr_D8_6, fpu_fdiv(___))
DEFINE_MODRM_INSTR_FPU_READ32(instr_D8_7, fpu_fdivr(___))
void instr_D9_mem(int32_t addr, int32_t r) { task_switch_test(); fpu_op_D9_mem(r, addr); }
void instr_D9_reg(int32_t r2, int32_t r) { task_switch_test(); fpu_op_D9_reg(0xC0 | r2 | r << 3); }
DEFINE_MODRM_INSTR_FPU_READ32(instr_D9_0, fpu_push(___))
void instr_D9_1_mem(int32_t addr) {
task_switch_test();
dbg_log("d9/1");
trigger_ud();
}
void instr_D9_1_reg(int32_t r) {
task_switch_test();
fpu_fxch(r);
}
void instr_D9_2_mem(int32_t addr) {
task_switch_test();
fpu_fst(addr);
}
void instr_D9_2_reg(int32_t r) {
task_switch_test();
// r==0 -> fnop
if(r != 0)
{
trigger_ud();
}
}
void instr_D9_3_mem(int32_t addr) {
task_switch_test();
fpu_fstp(addr);
}
void instr_D9_3_reg(int32_t r) {
task_switch_test();
dbg_log("fstp1");
trigger_ud();
}
void instr_D9_4_mem(int32_t addr) {
task_switch_test();
fpu_fldenv(addr);
}
void instr_D9_4_reg(int32_t r) {
task_switch_test();
fpu_op_D9_4_reg(r);
}
void instr_D9_5_mem(int32_t addr) {
task_switch_test();
fpu_fldcw(addr);
}
void instr_D9_5_reg(int32_t r) {
task_switch_test();
fpu_op_D9_5_reg(r);
}
void instr_D9_6_mem(int32_t addr) {
task_switch_test();
fpu_fstenv(addr);
}
void instr_D9_6_reg(int32_t r) {
task_switch_test();
fpu_op_D9_6_reg(r);
}
void instr_D9_7_mem(int32_t addr) {
task_switch_test();
fpu_fstcw(addr);
}
void instr_D9_7_reg(int32_t r) {
task_switch_test();
fpu_op_D9_7_reg(r);
}
void instr_DA_mem(int32_t addr, int32_t r) { task_switch_test(); fpu_op_DA_mem(r, addr); }
void instr_DA_reg(int32_t r2, int32_t r) { task_switch_test(); fpu_op_DA_reg(0xC0 | r2 | r << 3); }
void instr_DB_mem(int32_t addr, int32_t r) { task_switch_test(); fpu_op_DB_mem(r, addr); }