diff options
| author | Yang Liu <numbksco@gmail.com> | 2025-10-22 02:26:50 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-21 20:26:50 +0200 |
| commit | 83a37589f27c392347f2e69a5a8e51037ccafb50 (patch) | |
| tree | 649a92cdf4981c06d28889596f1d784adaa649b4 | |
| parent | fe0e3b7a9fb6a3dd0a7b4f60b4b5c2c9d83bb796 (diff) | |
| download | box64-83a37589f27c392347f2e69a5a8e51037ccafb50.tar.gz box64-83a37589f27c392347f2e69a5a8e51037ccafb50.zip | |
[LA64_DYNAREC] Added a few more opcodes (#3081)
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 28 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_db.c | 20 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_shift.c | 119 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 4 |
4 files changed, 170 insertions, 1 deletions
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index c0609dec..5047b201 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -1422,6 +1422,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni F8; } break; + case 0xA5: + nextop = F8; + INST_NAME("SHLD Ed, Gd, CL"); + SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined + if (BOX64DRENV(dynarec_safeflags) > 1) + MAYSETFLAGS(); + GETGD; + GETED(0); + if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); } + ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f); + BEQ_NEXT(x3, xZR); + emit_shld32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6); + WBACK; + break; case 0xAB: INST_NAME("BTS Ed, Gd"); SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION); @@ -1479,6 +1493,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni F8; } break; + case 0xAD: + nextop = F8; + INST_NAME("SHRD Ed, Gd, CL"); + SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); + if (BOX64DRENV(dynarec_safeflags) > 1) + MAYSETFLAGS(); + GETGD; + GETED(0); + if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); } + ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f); + BEQ_NEXT(x3, xZR); + emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4, x6); + WBACK; + break; case 0xAE: nextop = F8; if (MODREG) diff --git a/src/dynarec/la64/dynarec_la64_db.c b/src/dynarec/la64/dynarec_la64_db.c index 7b81af4a..5318d6c0 100644 --- a/src/dynarec/la64/dynarec_la64_db.c +++ b/src/dynarec/la64/dynarec_la64_db.c @@ -177,7 +177,25 @@ uintptr_t dynarec64_DB(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni break; case 2: INST_NAME("FIST Ed, ST0"); - DEFAULT; + v1 = x87_get_st(dyn, ninst, x1, x2, 0, LSX_CACHE_ST_D); + u8 = x87_setround(dyn, ninst, x1, x5); + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x3, &fixedaddress, rex, NULL, 1, 0); + v2 = fpu_get_scratch(dyn); + if (!BOX64ENV(dynarec_fastround)) { + MOVGR2FCSR(FCSR2, xZR); // reset all bits + } + FTINT_W_D(v2, v1); + if (!BOX64ENV(dynarec_fastround)) { + MOVFCSR2GR(x5, FCSR2); // get back FPSR to check + BSTRPICK_D(x5, x5, FR_V, FR_V); + BEQZ_MARK(x5); + MOV32w(x4, 0x80000000); + MOVGR2FR_W(v2, x4); + MARK; + } + FST_S(v2, wback, fixedaddress); + x87_restoreround(dyn, ninst, u8); + break; break; case 3: INST_NAME("FISTP Ed, ST0"); diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c index 5a8cde04..6c4ba6d9 100644 --- a/src/dynarec/la64/dynarec_la64_emit_shift.c +++ b/src/dynarec/la64/dynarec_la64_emit_shift.c @@ -1387,3 +1387,122 @@ void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin SPILL_EFLAGS(); } } + +void emit_shrd32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4, int s6) +{ + if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR); + int64_t j64; + IFX (X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + SDxw(s5, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s4, rex.w ? d_shrd64 : d_shrd32); + } else IFXORNAT (X_ALL) { + SET_DFNONE(); + } + + CLEAR_FLAGS(s3); + IFX (X_CF) { + ADDI_D(s3, s5, -1); + SRA_D(s3, s1, s3); + ANDI(s3, s3, 1); // LSB == F_CF + OR(xFlags, xFlags, s3); + } + IFX (X_OF) { + // Store current sign for later use. + SRLIxw(s6, s1, rex.w ? 63 : 31); + } + ADDI_D(s4, xZR, (rex.w ? 64 : 32)); + SUB_D(s4, s4, s5); + SRLxw(s3, s1, s5); + SLLxw(s4, s2, s4); + OR(s1, s4, s3); + + IFX (X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + if (!rex.w) { + ZEROUP(s1); + } + IFX (X_OF) { + ADDI_D(s5, s5, -1); + BNEZ_MARK(s5); + SRLIxw(s3, s1, rex.w ? 63 : 31); + XOR(s3, s3, s6); + SLLI_D(s3, s3, F_OF); + OR(xFlags, xFlags, s3); + MARK; + } + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_SF) { + SRLIxw(s3, s1, rex.w ? 63 : 31); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } + IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS(); +} + +void emit_shld32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4, int s6) +{ + if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR); + int64_t j64; + IFX (X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + SDxw(s5, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s4, rex.w ? d_shld64 : d_shld32); + } else IFXORNAT (X_ALL) { + SET_DFNONE(); + } + + CLEAR_FLAGS(s3); + MOV32w(s3, (rex.w ? 64 : 32)); + SUB_D(s3, s3, s5); + + IFX (X_CF) { + SRL_D(s4, s1, s3); + ANDI(s4, s4, 1); // LSB == F_CF + OR(xFlags, xFlags, s4); + } + IFX (X_OF) { + // Store current sign for later use. + SRLIxw(s6, s1, rex.w ? 63 : 31); + } + SLLxw(s4, s1, s5); + SRLxw(s3, s2, s3); + OR(s1, s3, s4); + + IFX (X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + if (!rex.w) { + ZEROUP(s1); + } + + IFX (X_OF) { + ADDI_D(s5, s5, -1); + BNEZ_MARK(s5); + SRLIxw(s3, s1, rex.w ? 63 : 31); + XOR(s3, s3, s6); + SLLI_D(s3, s3, F_OF); + OR(xFlags, xFlags, s3); + MARK; + } + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_SF) { + SRLIxw(s3, s1, rex.w ? 63 : 31); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } + IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS(); +} diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index 440cfba5..464a1880 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -1292,6 +1292,8 @@ #define emit_sar32c STEPNAME(emit_sar32c) #define emit_shld32c STEPNAME(emit_shld32c) #define emit_shrd32c STEPNAME(emit_shrd32c) +#define emit_shld32 STEPNAME(emit_shld32) +#define emit_shrd32 STEPNAME(emit_shrd32) #define emit_ror32 STEPNAME(emit_ror32) #define emit_ror32c STEPNAME(emit_ror32c) #define emit_rol32 STEPNAME(emit_rol32) @@ -1434,6 +1436,8 @@ void emit_sar16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4); void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4); +void emit_shld32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4, int s6); +void emit_shrd32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4, int s6); void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); |