From 986476b9db31de92b6a3fe473b2b62526db6fda5 Mon Sep 17 00:00:00 2001 From: TomW Date: Mon, 21 Sep 2015 21:54:43 +0100 Subject: [PATCH] FPU rounding modes now have effect in FADD double precision. Fixes rendering in Interstate '76. --- src/codegen_ops_x86-64.h | 33 +++++++++++++++++++++++++++++++++ src/codegen_ops_x86.h | 35 +++++++++++++++++++++++++++++++++++ src/x87_ops.h | 3 +++ src/x87_ops_arith.h | 4 ++++ 4 files changed, 75 insertions(+) diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h index 1efb279..7b52213 100644 --- a/src/codegen_ops_x86-64.h +++ b/src/codegen_ops_x86-64.h @@ -4080,7 +4080,40 @@ static void FP_OP_D(int op) addbyte(0x0f); addbyte(0x6e); addbyte(0xc8); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*STMXCSR [ESP+8]*/ + addbyte(0xae); + addbyte(0x5c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x25); /*AND EAX, ~(3 << 13)*/ + addlong(~(3 << 10)); + addbyte(0x0d); /*OR EAX, (npxc & (3 << 10)) << 3*/ + addlong((npxc & (3 << 10)) << 3); + addbyte(0x89); /*MOV [RSP+12], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x0f); /*LDMXCSR [RSP+12]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + } FP_OP_MEM(op); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*LDMXCSR [RSP+8]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x08); + } } static void FP_OP_IW(int op) { diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h index 1097eed..e8695ff 100644 --- a/src/codegen_ops_x86.h +++ b/src/codegen_ops_x86.h @@ -2496,6 +2496,34 @@ static void FP_OP_D(int op) addbyte(0x89); /*MOV [ESP], EAX*/ addbyte(0x04); addbyte(0x24); + if (((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(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(0x89); /*MOV [ESP+4], EDX*/ addbyte(0x54); addbyte(0x24); @@ -2515,6 +2543,13 @@ static void FP_OP_D(int op) addbyte(0x1c); addbyte(0xdd); addlong((uintptr_t)ST); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW [ESP+8]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x08); + } } static void FP_OP_IW(int op) { diff --git a/src/x87_ops.h b/src/x87_ops.h index e17998f..188b9cc 100644 --- a/src/x87_ops.h +++ b/src/x87_ops.h @@ -1,7 +1,10 @@ #include +#include #define fplog 0 +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + #define ST(x) ST[((TOP+(x))&7)] #define C0 (1<<8) diff --git a/src/x87_ops_arith.h b/src/x87_ops_arith.h index 7536040..c198289 100644 --- a/src/x87_ops_arith.h +++ b/src/x87_ops_arith.h @@ -5,7 +5,11 @@ static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ load_var = get(); if (abrt) return 1; \ + if ((npxc >> 10) & 3) \ + fesetround(rounding_modes[(npxc >> 10) & 3]); \ ST(0) += use_var; \ + if ((npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ tag[TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \