diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_0f.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_660f.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_6664.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_67.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_avx_0f.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_avx_66_0f.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_d8.c | 8 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_d9.c | 24 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_da.c | 6 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_db.c | 4 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_dc.c | 8 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_dd.c | 4 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_de.c | 8 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_df.c | 4 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.h | 48 | ||||
| -rw-r--r-- | src/dynarec/dynarec_native_functions.c | 18 |
16 files changed, 99 insertions, 45 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_0f.c b/src/dynarec/arm64/dynarec_arm64_0f.c index beb6a34b..894c8320 100644 --- a/src/dynarec/arm64/dynarec_arm64_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_0f.c @@ -499,7 +499,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin GETGX(v0, 0); GETEXSS(s0, 0, 0); FCMPS(v0, s0); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, s0, 1); // disabled precise cmp break; case 0x30: INST_NAME("WRMSR"); diff --git a/src/dynarec/arm64/dynarec_arm64_660f.c b/src/dynarec/arm64/dynarec_arm64_660f.c index 34bd16cc..458b24ba 100644 --- a/src/dynarec/arm64/dynarec_arm64_660f.c +++ b/src/dynarec/arm64/dynarec_arm64_660f.c @@ -312,7 +312,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n GETGX(v0, 0); GETEXSD(q0, 0, 0); FCMPD(v0, q0); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp break; case 0x38: // SSSE3 opcodes diff --git a/src/dynarec/arm64/dynarec_arm64_6664.c b/src/dynarec/arm64/dynarec_arm64_6664.c index dfc1bef1..7685d1b8 100644 --- a/src/dynarec/arm64/dynarec_arm64_6664.c +++ b/src/dynarec/arm64/dynarec_arm64_6664.c @@ -68,7 +68,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n VLDR64_REG(v1, ed, x4); } FCMPD(v0, v1); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, v1, 0); //disable precise cmp break; case 0x6F: diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c index 5dc4043a..5316866e 100644 --- a/src/dynarec/arm64/dynarec_arm64_67.c +++ b/src/dynarec/arm64/dynarec_arm64_67.c @@ -215,7 +215,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin VLD32(s0, ed, fixedaddress); } FCMPS(v0, s0); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, s0, 1); //disabled precise cmp break; default: DEFAULT; diff --git a/src/dynarec/arm64/dynarec_arm64_avx_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_0f.c index 2cdc6e51..439a0997 100644 --- a/src/dynarec/arm64/dynarec_arm64_avx_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_avx_0f.c @@ -290,7 +290,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int GETGX(v0, 0); GETEXSS(s0, 0, 0); FCMPS(v0, s0); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, s0, 1); //disable precise cmp break; case 0x50: diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c index 4acb4d31..bcd9ed8a 100644 --- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c @@ -273,7 +273,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, GETGX(v0, 0); GETEXSD(q0, 0, 0); FCMPD(v0, q0); - FCOMI(x1, x2); + FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp break; case 0x50: diff --git a/src/dynarec/arm64/dynarec_arm64_d8.c b/src/dynarec/arm64/dynarec_arm64_d8.c index e8f002a4..668694c0 100644 --- a/src/dynarec/arm64/dynarec_arm64_d8.c +++ b/src/dynarec/arm64/dynarec_arm64_d8.c @@ -90,7 +90,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 0xD8: case 0xD9: @@ -108,7 +108,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 0xE0: @@ -222,7 +222,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin FCVT_D_S(s0, s0); FCMPD(v1, s0); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 3: INST_NAME("FCOMP ST0, float[ED]"); @@ -236,7 +236,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin FCVT_D_S(s0, s0); FCMPD(v1, s0); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, s0, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 4: diff --git a/src/dynarec/arm64/dynarec_arm64_d9.c b/src/dynarec/arm64/dynarec_arm64_d9.c index 9a002202..557b3673 100644 --- a/src/dynarec/arm64/dynarec_arm64_d9.c +++ b/src/dynarec/arm64/dynarec_arm64_d9.c @@ -128,7 +128,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD_0(v1); } - FCOM(x1, x2, x3); // same flags... + FCOM(x1, x2, x3, x4, 0, 0, ST_IS_F(0)); // same flags... break; case 0xE5: INST_NAME("FXAM"); @@ -161,21 +161,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { ADDw_U12(x5, x5, i2); } - ANDw_mask(x5, x5, 0, 3); // (emu->top + i)&7 + ANDw_mask(x5, x5, 0, 2); // (emu->top + i)&7 } - // load tag - LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags)); - if(i2<0) { - LSLw_IMM(x3, x3, -i2*2); - } else if(i2>0) { - ORRw_mask(x3, x3, 0b010000, 0b001111); // 0xffff0000 - LSRw_IMM(x3, x3, i2*2); - } - TSTw_mask(x3, 0, 1); // 0b11 - B_MARK3(cNE); // empty: C3,C2,C0 = 101 // load x2 with ST0 anyway, for sign extraction ADDx_REG_LSL(x1, xEmu, x5, 3); LDRx_U12(x2, x1, offsetof(x64emu_t, x87)); + // load tag + if(i2>=0) { + LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags)); + if(i2>0) { + ORRw_mask(x3, x3, 0b010000, 0b001111); // 0xffff0000 + LSRw_IMM(x3, x3, i2*2); + } + TSTw_mask(x3, 0, 1); // 0b11 + B_MARK3(cNE); // empty: C3,C2,C0 = 101 + } } } else { // simply move from cache reg to x2 diff --git a/src/dynarec/arm64/dynarec_arm64_da.c b/src/dynarec/arm64/dynarec_arm64_da.c index 52965b3f..1c87f3c7 100644 --- a/src/dynarec/arm64/dynarec_arm64_da.c +++ b/src/dynarec/arm64/dynarec_arm64_da.c @@ -130,7 +130,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); X87_POP_OR_FAIL(dyn, ninst, x3); break; @@ -169,7 +169,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SXTL_32(v2, v2); // i32 -> i64 SCVTFDD(v2, v2); // i64 -> double FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 3: INST_NAME("FICOMP ST0, Ed"); @@ -180,7 +180,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SXTL_32(v2, v2); // i32 -> i64 SCVTFDD(v2, v2); // i64 -> double FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 4: diff --git a/src/dynarec/arm64/dynarec_arm64_db.c b/src/dynarec/arm64/dynarec_arm64_db.c index 68e36ef4..feba2072 100644 --- a/src/dynarec/arm64/dynarec_arm64_db.c +++ b/src/dynarec/arm64/dynarec_arm64_db.c @@ -155,7 +155,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOMI(x1, x2); + FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0)); break; case 0xF0: case 0xF1: @@ -174,7 +174,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOMI(x1, x2); + FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0)); break; default: diff --git a/src/dynarec/arm64/dynarec_arm64_dc.c b/src/dynarec/arm64/dynarec_arm64_dc.c index ee5b2c62..8834de6c 100644 --- a/src/dynarec/arm64/dynarec_arm64_dc.c +++ b/src/dynarec/arm64/dynarec_arm64_dc.c @@ -88,7 +88,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 0xD8: case 0xD9: @@ -106,7 +106,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 0xE0: @@ -205,7 +205,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0); VLD64(v2, wback, fixedaddress); FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 3: INST_NAME("FCOMP ST0, double[ED]"); @@ -214,7 +214,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0); VLD64(v2, wback, fixedaddress); FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 4: diff --git a/src/dynarec/arm64/dynarec_arm64_dd.c b/src/dynarec/arm64/dynarec_arm64_dd.c index 6ce37042..33282abd 100644 --- a/src/dynarec/arm64/dynarec_arm64_dd.c +++ b/src/dynarec/arm64/dynarec_arm64_dd.c @@ -118,7 +118,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 0xE8: case 0xE9: @@ -136,7 +136,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; diff --git a/src/dynarec/arm64/dynarec_arm64_de.c b/src/dynarec/arm64/dynarec_arm64_de.c index 7dbbb210..6da8f029 100644 --- a/src/dynarec/arm64/dynarec_arm64_de.c +++ b/src/dynarec/arm64/dynarec_arm64_de.c @@ -90,7 +90,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 0xD9: @@ -102,7 +102,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); X87_POP_OR_FAIL(dyn, ninst, x3); break; @@ -215,7 +215,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SXTL_32(v2, v2); SCVTFDD(v2, v2); FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); break; case 3: INST_NAME("FICOMP ST0, word[ED]"); @@ -227,7 +227,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SXTL_32(v2, v2); SCVTFDD(v2, v2); FCMPD(v1, v2); - FCOM(x1, x2, x3); + FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 4: diff --git a/src/dynarec/arm64/dynarec_arm64_df.c b/src/dynarec/arm64/dynarec_arm64_df.c index cef734bf..bbcf3758 100644 --- a/src/dynarec/arm64/dynarec_arm64_df.c +++ b/src/dynarec/arm64/dynarec_arm64_df.c @@ -109,7 +109,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOMI(x1, x2); + FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; case 0xF0: @@ -130,7 +130,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } else { FCMPD(v1, v2); } - FCOMI(x1, x2); + FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0)); X87_POP_OR_FAIL(dyn, ninst, x3); break; diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h index 267d873b..77cedbf1 100644 --- a/src/dynarec/arm64/dynarec_arm64_helper.h +++ b/src/dynarec/arm64/dynarec_arm64_helper.h @@ -880,7 +880,7 @@ #endif // Generate FCOM with s1 and s2 scratch regs (the VCMP is already done) -#define FCOM(s1, s2, s3) \ +#define FCOM(s1, s2, s3, s4, v1, v2, is_f) \ LDRH_U12(s3, xEmu, offsetof(x64emu_t, sw)); /*offset is 8bits right?*/\ MOV32w(s1, 0b0100011100000000); \ BICw_REG(s3, s3, s1); \ @@ -890,11 +890,33 @@ CSELw(s1, s2, s1, cEQ); \ MOV32w(s2, 0b01000101); /* unordered */ \ CSELw(s1, s2, s1, cVS); \ + if(v1||v2) { \ + Bcond(cVS, 10*4); \ + if(is_f) { \ + ORRw_mask(s4, xZR, 12, 10); /*+inf*/ \ + FMOVwS(s2, v1); \ + CMPSw_REG(s2, s4); \ + Bcond(cEQ, 5*4); /* same */ \ + FMOVwS(s2, v2); \ + ORRw_mask(s4, s4, 1, 0); /*-inf*/ \ + CMPSw_REG(s2, s4); \ + } else { \ + ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/ \ + FMOVxD(s2, v1); \ + CMPSx_REG(s2, s4); \ + Bcond(cEQ, 5*4); /* same */ \ + FMOVxD(s2, v2); \ + ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/ \ + CMPSx_REG(s2, s4); \ + } \ + Bcond(cNE, 4+4); /* same */ \ + MOVZw(s2, 0); \ + } \ ORRw_REG_LSL(s3, s3, s1, 8); \ STRH_U12(s3, xEmu, offsetof(x64emu_t, sw)) // Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done) -#define FCOMI(s1, s2) \ +#define FCOMI(s1, s2, s4, v1, v2, is_f) \ IFX(X_OF|X_AF|X_SF|X_PEND) { \ MOV32w(s2, 0b100011010101); \ BICw_REG(xFlags, xFlags, s2); \ @@ -914,6 +936,28 @@ MOV32w(s2, 0b01000000); /* zero */ \ CSELw(s1, s2, s1, cEQ); \ /* greater than leave 0 */ \ + if(s4) { \ + Bcond(cVS, 10*4); \ + if(is_f) { \ + ORRw_mask(s4, xZR, 12, 10); /*+inf*/ \ + FMOVwS(s2, v1); \ + CMPSw_REG(s2, s4); \ + Bcond(cEQ, 5*4); /* same */ \ + FMOVwS(s2, v2); \ + ORRw_mask(s4, s4, 1, 0); /*-inf*/ \ + CMPSw_REG(s2, s4); \ + } else { \ + ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/ \ + FMOVxD(s2, v1); \ + CMPSx_REG(s2, s4); \ + Bcond(cEQ, 5*4); /* same */ \ + FMOVxD(s2, v2); \ + ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/ \ + CMPSx_REG(s2, s4); \ + } \ + Bcond(cNE, 4+4); /* same */ \ + MOVZw(s1, 0); \ + } \ ORRw_REG(xFlags, xFlags, s1); \ } \ SET_DFNONE(s1); \ diff --git a/src/dynarec/dynarec_native_functions.c b/src/dynarec/dynarec_native_functions.c index e2e149f2..4b72ea01 100644 --- a/src/dynarec/dynarec_native_functions.c +++ b/src/dynarec/dynarec_native_functions.c @@ -59,10 +59,20 @@ void native_fpatan(x64emu_t* emu) } void native_fxtract(x64emu_t* emu) { - int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52; - tmp32s -= 1023; - ST1.d /= exp2(tmp32s); - ST0.d = tmp32s; + int tmp32s; + if(isnan(ST1.d)) { + ST0.d = ST1.d; + } else if(isinf(ST1.d)) { + ST0.d = ST1.d; + ST1.d = INFINITY; + } else if(ST1.d==0.0) { + ST0.d = ST1.d; + ST1.d = -INFINITY; + } else { + // LD80bits doesn't have implicit "1" bit, so need to adjust for that + ST0.d = frexp(ST1.d, &tmp32s)*2; + ST1.d = tmp32s-1; + } } void native_fprem(x64emu_t* emu) { |