x86-32 recompiler performs float->integer rounding by loading FPU control word instead of calling helper function - speedup on some stuff.
This commit is contained in:
parent
aab2c3e7cf
commit
dd2a608707
6 changed files with 88 additions and 182 deletions
|
|
@ -580,6 +580,7 @@ static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint
|
|||
|
||||
MEM_LOAD_ADDR_EA_W(target_seg);
|
||||
STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.npxc, 0);
|
||||
UPDATE_NPXC(0);
|
||||
|
||||
return op_pc + 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4556,6 +4556,10 @@ static void FP_COMPARE_IL()
|
|||
FP_COMPARE_MEM();
|
||||
}
|
||||
|
||||
static void UPDATE_NPXC(int reg)
|
||||
{
|
||||
}
|
||||
|
||||
static void SET_BITS(uintptr_t addr, uint32_t val)
|
||||
{
|
||||
if (IS_32_ADDR(addr))
|
||||
|
|
|
|||
|
|
@ -2173,82 +2173,6 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2)
|
|||
*host_reg2 = REG_ECX;
|
||||
}
|
||||
|
||||
|
||||
static double _fp_half = 0.5;
|
||||
|
||||
static void FP_LOAD_ROUNDING()
|
||||
{
|
||||
pclog("cpu_state.npxc %04x\n", cpu_state.npxc);
|
||||
addbyte(0x8b); /*MOV EDX, npxc*/
|
||||
addbyte(0x15);
|
||||
addlong((uintptr_t)&cpu_state.npxc);
|
||||
addbyte(0xd9); /*FSTCW [ESP+8]*/
|
||||
addbyte(0x7c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0x89); /*MOV [ESP+12],EDX*/
|
||||
addbyte(0x54);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
addbyte(0xd9); /*FLDCW [ESP+12]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
}
|
||||
static void FP_RESTORE_ROUNDING()
|
||||
{
|
||||
addbyte(0xd9); /*FLDCW [ESP+8]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
}
|
||||
|
||||
static int32_t x87_fround32(double b)
|
||||
{
|
||||
int64_t a, c;
|
||||
|
||||
switch ((cpu_state.npxc >> 10) & 3)
|
||||
{
|
||||
case 0: /*Nearest*/
|
||||
a = (int64_t)floor(b);
|
||||
c = (int64_t)floor(b + 1.0);
|
||||
if ((b - a) < (c - b))
|
||||
return a;
|
||||
else if ((b - a) > (c - b))
|
||||
return c;
|
||||
else
|
||||
return (a & 1) ? c : a;
|
||||
case 1: /*Down*/
|
||||
return (int32_t)floor(b);
|
||||
case 2: /*Up*/
|
||||
return (int32_t)ceil(b);
|
||||
case 3: /*Chop*/
|
||||
return (int32_t)b;
|
||||
}
|
||||
}
|
||||
static int64_t x87_fround64(double b)
|
||||
{
|
||||
int64_t a, c;
|
||||
|
||||
switch ((cpu_state.npxc >> 10) & 3)
|
||||
{
|
||||
case 0: /*Nearest*/
|
||||
a = (int64_t)floor(b);
|
||||
c = (int64_t)floor(b + 1.0);
|
||||
if ((b - a) < (c - b))
|
||||
return a;
|
||||
else if ((b - a) > (c - b))
|
||||
return c;
|
||||
else
|
||||
return (a & 1) ? c : a;
|
||||
case 1: /*Down*/
|
||||
return (int64_t)floor(b);
|
||||
case 2: /*Up*/
|
||||
return (int64_t)ceil(b);
|
||||
case 3: /*Chop*/
|
||||
return (int64_t)b;
|
||||
}
|
||||
}
|
||||
static int FP_LOAD_REG_INT_W(int reg)
|
||||
{
|
||||
addbyte(0x8b); /*MOV EBX, TOP*/
|
||||
|
|
@ -2268,25 +2192,19 @@ static int FP_LOAD_REG_INT_W(int reg)
|
|||
addbyte(0xdd);
|
||||
addbyte(cpu_state_offset(ST));
|
||||
|
||||
addbyte(0x89); /*MOV [ESP+8], EAX*/
|
||||
addbyte(0x44);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
addbyte(0xdb); /*FISTP [ESP]*/
|
||||
addbyte(0x1c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
|
||||
addbyte(0xdd); /*FSTP [ESP]*/
|
||||
addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(old_npxc));
|
||||
addbyte(0x8b); /*MOV EBX, [ESP]*/
|
||||
addbyte(0x1c);
|
||||
addbyte(0x24);
|
||||
|
||||
CALL_FUNC(x87_fround32);
|
||||
|
||||
addbyte(0x89); /*MOV EBX, EAX*/
|
||||
addbyte(0xc3);
|
||||
|
||||
addbyte(0x8b); /*MOV EAX, [ESP+8]*/
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
|
||||
return REG_EBX;
|
||||
}
|
||||
static int FP_LOAD_REG_INT(int reg)
|
||||
|
|
@ -2308,25 +2226,19 @@ static int FP_LOAD_REG_INT(int reg)
|
|||
addbyte(0xdd);
|
||||
addbyte(cpu_state_offset(ST));
|
||||
|
||||
addbyte(0x89); /*MOV [ESP+8], EAX*/
|
||||
addbyte(0x44);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
addbyte(0xdb); /*FISTP [ESP]*/
|
||||
addbyte(0x1c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
|
||||
addbyte(0xdd); /*FSTP [ESP]*/
|
||||
addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(old_npxc));
|
||||
addbyte(0x8b); /*MOV EBX, [ESP]*/
|
||||
addbyte(0x1c);
|
||||
addbyte(0x24);
|
||||
|
||||
CALL_FUNC(x87_fround32);
|
||||
|
||||
addbyte(0x89); /*MOV EBX, EAX*/
|
||||
addbyte(0xc3);
|
||||
|
||||
addbyte(0x8b); /*MOV EAX, [ESP+8]*/
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
|
||||
return REG_EBX;
|
||||
}
|
||||
static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2)
|
||||
|
|
@ -2378,34 +2290,29 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2)
|
|||
addbyte(cpu_state_offset(MM));
|
||||
|
||||
addbyte(0xeb); /*JMP done*/
|
||||
addbyte(4+4+3+5+2+2+4);
|
||||
addbyte(4+3+3+3+3+4);
|
||||
|
||||
addbyte(0xdd); /*FLD ST[EBX*8]*/
|
||||
addbyte(0x44);
|
||||
addbyte(0xdd);
|
||||
addbyte(cpu_state_offset(ST));
|
||||
|
||||
addbyte(0x89); /*MOV [ESP+8], EAX*/
|
||||
addbyte(0x44);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
addbyte(0xdf); /*FISTPQ [ESP]*/
|
||||
addbyte(0x3c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
|
||||
addbyte(0xdd); /*FSTP [ESP]*/
|
||||
addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(old_npxc));
|
||||
addbyte(0x8b); /*MOV EBX, [ESP]*/
|
||||
addbyte(0x1c);
|
||||
addbyte(0x24);
|
||||
|
||||
CALL_FUNC(x87_fround64);
|
||||
|
||||
addbyte(0x89); /*MOV EBX, EAX*/
|
||||
addbyte(0xc3);
|
||||
|
||||
addbyte(0x89); /*MOV ECX, EDX*/
|
||||
addbyte(0xd1);
|
||||
|
||||
addbyte(0x8b); /*MOV EAX, [ESP+8]*/
|
||||
addbyte(0x44);
|
||||
addbyte(0x8b); /*MOV ECX, 4[ESP]*/
|
||||
addbyte(0x4c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(4);
|
||||
|
||||
*host_reg1 = REG_EBX;
|
||||
*host_reg2 = REG_ECX;
|
||||
|
|
@ -2511,31 +2418,9 @@ static void FP_OP_D(int op)
|
|||
addbyte(0x04);
|
||||
if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD)
|
||||
{
|
||||
addbyte(0x9b); /*FSTCW [ESP+8]*/
|
||||
addbyte(0xd9);
|
||||
addbyte(0x7c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0x66); /*MOV AX, [ESP+8]*/
|
||||
addbyte(0x8b);
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0x66); /*AND AX, ~(3 << 10)*/
|
||||
addbyte(0x25);
|
||||
addword(~(3 << 10));
|
||||
addbyte(0x66); /*OR AX, npxc & (3 << 10)*/
|
||||
addbyte(0x0d);
|
||||
addword(cpu_state.npxc & (3 << 10));
|
||||
addbyte(0x66); /*MOV [ESP+12], AX*/
|
||||
addbyte(0x89);
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
addbyte(0xd9); /*FLDCW [ESP+12]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
}
|
||||
addbyte(0xdd); /*FLD ST[dst][EBP]*/
|
||||
addbyte(0x45);
|
||||
|
|
@ -2552,10 +2437,9 @@ static void FP_OP_D(int op)
|
|||
addbyte(cpu_state_offset(ST[cpu_state.TOP]));
|
||||
if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD)
|
||||
{
|
||||
addbyte(0xd9); /*FLDCW [ESP+8]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(old_npxc));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2568,31 +2452,9 @@ static void FP_OP_D(int op)
|
|||
addbyte(0x24);
|
||||
if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD)
|
||||
{
|
||||
addbyte(0x9b); /*FSTCW [ESP+8]*/
|
||||
addbyte(0xd9);
|
||||
addbyte(0x7c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0x66); /*MOV AX, [ESP+8]*/
|
||||
addbyte(0x8b);
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0x66); /*AND AX, ~(3 << 10)*/
|
||||
addbyte(0x25);
|
||||
addword(~(3 << 10));
|
||||
addbyte(0x66); /*OR AX, npxc & (3 << 10)*/
|
||||
addbyte(0x0d);
|
||||
addword(cpu_state.npxc & (3 << 10));
|
||||
addbyte(0x66); /*MOV [ESP+12], AX*/
|
||||
addbyte(0x89);
|
||||
addbyte(0x44);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
addbyte(0xd9); /*FLDCW [ESP+12]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x0c);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
}
|
||||
addbyte(0x89); /*MOV [ESP+4], EDX*/
|
||||
addbyte(0x54);
|
||||
|
|
@ -2616,10 +2478,9 @@ static void FP_OP_D(int op)
|
|||
addbyte(cpu_state_offset(ST));
|
||||
if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD)
|
||||
{
|
||||
addbyte(0xd9); /*FLDCW [ESP+8]*/
|
||||
addbyte(0x6c);
|
||||
addbyte(0x24);
|
||||
addbyte(0x08);
|
||||
addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/
|
||||
addbyte(0x6d);
|
||||
addbyte(cpu_state_offset(old_npxc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3226,6 +3087,32 @@ static void FP_COMPARE_REG(int dst, int src)
|
|||
}
|
||||
}
|
||||
|
||||
static void UPDATE_NPXC(int reg)
|
||||
{
|
||||
addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/
|
||||
addbyte(0x81);
|
||||
addbyte(0x65);
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
addword(~0xc00);
|
||||
if (reg)
|
||||
{
|
||||
addbyte(0x66); /*AND reg, 0xc00*/
|
||||
addbyte(0x81);
|
||||
addbyte(0xe0 | reg);
|
||||
addword(0xc00);
|
||||
}
|
||||
else
|
||||
{
|
||||
addbyte(0x66); /*AND AX, 0xc00*/
|
||||
addbyte(0x25);
|
||||
addword(0xc00);
|
||||
}
|
||||
addbyte(0x66); /*OR cpu_state.new_npxc, reg*/
|
||||
addbyte(0x09);
|
||||
addbyte(0x45 | (reg << 3));
|
||||
addbyte(cpu_state_offset(new_npxc));
|
||||
}
|
||||
|
||||
static int ZERO_EXTEND_W_B(int reg)
|
||||
{
|
||||
addbyte(0x0f); /*MOVZX regl, regb*/
|
||||
|
|
|
|||
|
|
@ -563,6 +563,11 @@ void codegen_init()
|
|||
mem_store_addr_ea_b = gen_MEM_STORE_ADDR_EA_B();
|
||||
block_pos = 1024;
|
||||
mem_store_addr_ea_q = gen_MEM_STORE_ADDR_EA_Q();
|
||||
|
||||
asm(
|
||||
"fstcw %0\n"
|
||||
: "=m" (cpu_state.old_npxc)
|
||||
);
|
||||
}
|
||||
|
||||
void codegen_reset()
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ struct
|
|||
uint16_t MM_w4[8];
|
||||
|
||||
MMX_REG MM[8];
|
||||
|
||||
uint16_t old_npxc, new_npxc;
|
||||
} cpu_state;
|
||||
|
||||
#define cycles cpu_state._cycles
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static int opFINIT(uint32_t fetchdat)
|
|||
FP_ENTER();
|
||||
cpu_state.pc++;
|
||||
cpu_state.npxc = 0x37F;
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00);
|
||||
cpu_state.npxs = 0;
|
||||
*(uint64_t *)cpu_state.tag = 0x0303030303030303ll;
|
||||
cpu_state.TOP = 0;
|
||||
|
|
@ -85,6 +86,7 @@ static int FSTOR()
|
|||
case 0x000: /*16-bit real mode*/
|
||||
case 0x001: /*16-bit protected mode*/
|
||||
cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2);
|
||||
x87_settag(readmemw(easeg, cpu_state.eaaddr+4));
|
||||
cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
|
||||
|
|
@ -93,6 +95,7 @@ static int FSTOR()
|
|||
case 0x100: /*32-bit real mode*/
|
||||
case 0x101: /*32-bit protected mode*/
|
||||
cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4);
|
||||
x87_settag(readmemw(easeg, cpu_state.eaaddr+8));
|
||||
cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
|
||||
|
|
@ -665,6 +668,7 @@ static int FLDENV()
|
|||
case 0x000: /*16-bit real mode*/
|
||||
case 0x001: /*16-bit protected mode*/
|
||||
cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2);
|
||||
x87_settag(readmemw(easeg, cpu_state.eaaddr+4));
|
||||
cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
|
||||
|
|
@ -672,6 +676,7 @@ static int FLDENV()
|
|||
case 0x100: /*32-bit real mode*/
|
||||
case 0x101: /*32-bit protected mode*/
|
||||
cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr);
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4);
|
||||
x87_settag(readmemw(easeg, cpu_state.eaaddr+8));
|
||||
cpu_state.TOP = (cpu_state.npxs >> 11) & 7;
|
||||
|
|
@ -705,6 +710,7 @@ static int opFLDCW_a16(uint32_t fetchdat)
|
|||
tempw = geteaw();
|
||||
if (cpu_state.abrt) return 1;
|
||||
cpu_state.npxc = tempw;
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
CLOCK_CYCLES(4);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -717,6 +723,7 @@ static int opFLDCW_a32(uint32_t fetchdat)
|
|||
tempw = geteaw();
|
||||
if (cpu_state.abrt) return 1;
|
||||
cpu_state.npxc = tempw;
|
||||
cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00);
|
||||
CLOCK_CYCLES(4);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue