Added some x87 opcodes (D9 and DB prefixes)

This commit is contained in:
ptitSeb 2021-03-05 18:05:42 +01:00
parent 4a418d72b6
commit 5119464274
5 changed files with 498 additions and 1 deletions

View File

@ -111,6 +111,8 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/emu/x64run.c"
"${BOX64_ROOT}/src/emu/x64run0f.c"
"${BOX64_ROOT}/src/emu/x64run66.c"
"${BOX64_ROOT}/src/emu/x64rund9.c"
"${BOX64_ROOT}/src/emu/x64rundb.c"
"${BOX64_ROOT}/src/emu/x64run_private.c"
"${BOX64_ROOT}/src/emu/x64syscall.c"
"${BOX64_ROOT}/src/emu/x64tls.c"

View File

@ -458,6 +458,24 @@ x64emurun:
}
break;
case 0xD9: /* x87 opcodes */
if(RunD9(emu, rex)) {
unimp = 1;
goto fini;
}
if(emu->quit)
goto fini;
break;
case 0xDB: /* x87 opcodes */
if(RunDB(emu, rex)) {
unimp = 1;
goto fini;
}
if(emu->quit)
goto fini;
break;
case 0xE8: /* CALL Id */
tmp32s = F32S; // call is relative
Push(emu, R_RIP);

View File

@ -226,9 +226,11 @@ void UpdateFlags(x64emu_t *emu);
#define CHECK_FLAGS(emu) if(emu->df) UpdateFlags(emu)
#define RESET_FLAGS(emu) emu->df = d_none
//void Run67(x64emu_t *emu);
int Run0F(x64emu_t *emu, rex_t rex);
int Run66(x64emu_t *emu, rex_t rex);
//int Run67(x64emu_t *emu, rex_t rex);
int RunD9(x64emu_t *emu, rex_t rex);
int RunDB(x64emu_t *emu, rex_t rex);
//void Run660F(x64emu_t *emu);
//void Run66D9(x64emu_t *emu); // x87
//void Run6766(x64emu_t *emu);

289
src/emu/x64rund9.c Normal file
View File

@ -0,0 +1,289 @@
#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box64stack.h"
#include "x64emu.h"
#include "x64run.h"
#include "x64emu_private.h"
#include "x64run_private.h"
#include "x64primop.h"
#include "x64trace.h"
#include "x87emu_private.h"
#include "box64context.h"
//#include "my_cpuid.h"
#include "bridge.h"
//#include "signals.h"
#ifdef DYNAREC
#include "../dynarec/arm_lock_helper.h"
#endif
#include "modrm.h"
int RunD9(x64emu_t *emu, rex_t rex)
{
uint8_t nextop;
int32_t tmp32s;
uint64_t ll;
float f;
reg64_t *oped;
nextop = F8;
switch (nextop) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7: /* FLD STx */
ll = ST(nextop&7).ll;
fpu_do_push(emu);
ST0.ll = ll;
break;
case 0xC8:
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF: /* FXCH STx */
ll = ST(nextop&7).ll;
ST(nextop&7).ll = ST0.ll;
ST0.ll = ll;
break;
case 0xD0: /* FNOP */
break;
case 0xE0: /* FCHS */
ST0.d = -ST0.d;
break;
case 0xE1: /* FABS */
ST0.d = fabs(ST0.d);
break;
case 0xE4: /* FTST */
fpu_ftst(emu);
break;
case 0xE5: /* FXAM */
fpu_fxam(emu);
break;
case 0xE8: /* FLD1 */
fpu_do_push(emu);
ST0.d = 1.0;
break;
case 0xE9: /* FLDL2T */
fpu_do_push(emu);
ST0.d = L2T;
break;
case 0xEA: /* FLDL2E */
fpu_do_push(emu);
ST0.d = L2E;
break;
case 0xEB: /* FLDPI */
fpu_do_push(emu);
ST0.d = PI;
break;
case 0xEC: /* FLDLG2 */
fpu_do_push(emu);
ST0.d = LG2;
break;
case 0xED: /* FLDLN2 */
fpu_do_push(emu);
ST0.d = LN2;
break;
case 0xEE: /* FLDZ */
fpu_do_push(emu);
ST0.d = 0.0;
break;
case 0xF0: /* F2XM1 */
ST0.d = exp2(ST0.d) - 1.0;
break;
case 0xF1: /* FYL2X */
ST(1).d *= log2(ST0.d);
fpu_do_pop(emu);
break;
case 0xF2: /* FPTAN */
ST0.d = tan(ST0.d);
fpu_do_push(emu);
ST0.d = 1.0;
emu->sw.f.F87_C2 = 0;
break;
case 0xF3: /* FPATAN */
ST1.d = atan2(ST1.d, ST0.d);
fpu_do_pop(emu);
break;
case 0xF4: /* FXTRACT */
ST0.d = frexp(ST0.d, &tmp32s);
fpu_do_push(emu);
ST0.d = tmp32s;
break;
case 0xF8: /* FPREM */
{
int e0, e1;
frexp(ST0.d, &e0);
frexp(ST1.d, &e1);
tmp32s = e0 - e1;
}
if(tmp32s<64)
{
ll = (int64_t)floor(ST0.d/ST1.d);
ST0.d = ST0.d - (ST1.d*ll);
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = (ll&1)?1:0;
emu->sw.f.F87_C3 = (ll&2)?1:0;
emu->sw.f.F87_C0 = (ll&4)?1:0;
} else {
ll = (int64_t)(floor((ST0.d/ST1.d))/exp2(tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
emu->sw.f.F87_C2 = 1;
}
break;
case 0xF5: /* FPREM1 */
// get exponant(ST(0))-exponant(ST(1)) in temp32s
{
int e0, e1;
frexp(ST0.d, &e0);
frexp(ST1.d, &e1);
tmp32s = e0 - e1;
}
if(tmp32s<64)
{
ll = (int64_t)round(ST0.d/ST1.d);
ST0.d = ST0.d - (ST1.d*ll);
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = (ll&1)?1:0;
emu->sw.f.F87_C3 = (ll&2)?1:0;
emu->sw.f.F87_C0 = (ll&4)?1:0;
} else {
ll = (int64_t)(trunc((ST0.d/ST1.d))/exp2(tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
emu->sw.f.F87_C2 = 1;
}
break;
case 0xF6: /* FDECSTP */
emu->top=(emu->top-1)&7; // this will probably break a few things
break;
case 0xF7: /* FINCSTP */
emu->top=(emu->top+1)&7; // this will probably break a few things
break;
case 0xF9: /* FYL2XP1 */
ST(1).d *= log2(ST0.d + 1.0);
fpu_do_pop(emu);
break;
case 0xFA: /* FSQRT */
ST0.d = sqrt(ST0.d);
break;
case 0xFB: /* FSINCOS */
fpu_do_push(emu);
sincos(ST1.d, &ST1.d, &ST0.d);
break;
case 0xFC: /* FRNDINT */
ST0.d = fpu_round(emu, ST0.d);
break;
case 0xFD: /* FSCALE */
// this could probably be done by just altering the exponant part of the float...
ST0.d *= exp2(trunc(ST1.d));
break;
case 0xFE: /* FSIN */
ST0.d = sin(ST0.d);
break;
case 0xFF: /* FCOS */
ST0.d = cos(ST0.d);
break;
case 0xD1:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
case 0xD8:
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
case 0xE2:
case 0xE3:
case 0xE6:
case 0xE7:
case 0xEF:
return 1;
default:
switch((nextop>>3)&7) {
case 0: /* FLD ST0, Ed float */
GETED;
fpu_do_push(emu);
if(!(((uintptr_t)ED)&3))
ST0.d = *(float*)ED;
else {
memcpy(&f, ED, sizeof(float));
ST0.d = f;
}
break;
case 2: /* FST Ed, ST0 */
GETED;
if(!(((uintptr_t)ED)&3))
*(float*)ED = ST0.d;
else {
f = ST0.d;
memcpy(ED, &f, sizeof(float));
}
break;
case 3: /* FSTP Ed, ST0 */
GETED;
if(!(((uintptr_t)ED)&3))
*(float*)ED = ST0.d;
else {
f = ST0.d;
memcpy(ED, &f, sizeof(float));
}
fpu_do_pop(emu);
break;
case 4: /* FLDENV m */
// warning, incomplete
GETED;
fpu_loadenv(emu, (char*)ED, 0);
break;
case 5: /* FLDCW Ew */
GETEW;
emu->cw = EW->word[0];
// do something with cw?
emu->round = (fpu_round_t)((emu->cw >> 10) & 3);
break;
#if 0
case 6: /* FNSTENV m */
// warning, incomplete
GETED;
fpu_savenv(emu, (char*)ED, 0);
// intruction pointer: 48bits
// data (operand) pointer: 48bits
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
break;
#endif
case 7: /* FNSTCW Ew */
GETEW;
EW->word[0] = emu->cw;
break;
default:
return 1;
}
}
return 0;
}

186
src/emu/x64rundb.c Normal file
View File

@ -0,0 +1,186 @@
#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box64stack.h"
#include "x64emu.h"
#include "x64run.h"
#include "x64emu_private.h"
#include "x64run_private.h"
#include "x64primop.h"
#include "x64trace.h"
#include "x87emu_private.h"
#include "box64context.h"
//#include "my_cpuid.h"
#include "bridge.h"
//#include "signals.h"
#ifdef DYNAREC
#include "../dynarec/arm_lock_helper.h"
#endif
#include "modrm.h"
int RunDB(x64emu_t *emu, rex_t rex)
{
uint8_t nextop;
int32_t tmp32s;
reg64_t *oped;
nextop = F8;
switch(nextop) {
case 0xC0: /* FCMOVNB ST(0), ST(i) */
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_CF))
ST0.ll = ST(nextop&7).ll;
break;
case 0xC8: /* FCMOVNE ST(0), ST(i) */
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
break;
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
CHECK_FLAGS(emu);
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
ST0.ll = ST(nextop&7).ll;
break;
case 0xD8: /* FCMOVNU ST(0), ST(i) */
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_PF))
ST0.ll = ST(nextop&7).ll;
break;
case 0xE1: /* FDISI8087_NOP */
break;
case 0xE2: /* FNCLEX */
//Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE),
// the exception summary status flag (ES), the stack fault flag (SF), and the busy flag (B) in the FPU status word
emu->sw.f.F87_PE = 0;
emu->sw.f.F87_UE = 0;
emu->sw.f.F87_OE = 0;
emu->sw.f.F87_ZE = 0;
emu->sw.f.F87_DE = 0;
emu->sw.f.F87_IE = 0;
emu->sw.f.F87_ES = 0;
emu->sw.f.F87_SF = 0;
emu->sw.f.F87_B = 0;
break;
case 0xE3: /* FNINIT */
reset_fpu(emu);
break;
case 0xE8: /* FUCOMI ST0, STx */
case 0xE9:
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
break;
case 0xF0: /* FCOMI ST0, STx */
case 0xF1:
case 0xF2:
case 0xF3:
case 0xF4:
case 0xF5:
case 0xF6:
case 0xF7:
fpu_fcomi(emu, ST(nextop&7).d);
break;
case 0xE0:
case 0xE4:
case 0xE5:
case 0xE6:
case 0xE7:
return 1;
default:
switch((nextop>>3)&7) {
case 0: /* FILD ST0, Ed */
GETED;
fpu_do_push(emu);
ST0.d = ED->sdword[0];
break;
case 1: /* FISTTP Ed, ST0 */
GETED;
tmp32s = ST0.d; // TODO: Handling of FPU Exception
if(tmp32s==0x7fffffff && isgreater(ST0.d, (double)(int32_t)0x7fffffff))
tmp32s = 0x80000000;
fpu_do_pop(emu);
ED->sdword[0] = tmp32s;
break;
case 2: /* FIST Ed, ST0 */
GETED;
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
ED->sdword[0] = 0x80000000;
else {
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
ED->sdword[0] = tmp;
}
break;
case 3: /* FISTP Ed, ST0 */
GETED;
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
ED->sdword[0] = 0x80000000;
else {
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
ED->sdword[0] = tmp;
}
fpu_do_pop(emu);
break;
case 5: /* FLD ST0, Et */
GETED;
fpu_do_push(emu);
memcpy(&STld(0).ld, ED, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).ref = ST0.ll;
break;
case 7: /* FSTP tbyte */
GETED;
if(ST0.ll!=STld(0).ref)
D2LD(&ST0.d, ED);
else
memcpy(ED, &STld(0).ld, 10);
fpu_do_pop(emu);
break;
default:
return 1;
}
}
return 0;
}