about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2025-10-22 02:26:50 +0800
committerGitHub <noreply@github.com>2025-10-21 20:26:50 +0200
commit83a37589f27c392347f2e69a5a8e51037ccafb50 (patch)
tree649a92cdf4981c06d28889596f1d784adaa649b4 /src
parentfe0e3b7a9fb6a3dd0a7b4f60b4b5c2c9d83bb796 (diff)
downloadbox64-83a37589f27c392347f2e69a5a8e51037ccafb50.tar.gz
box64-83a37589f27c392347f2e69a5a8e51037ccafb50.zip
[LA64_DYNAREC] Added a few more opcodes (#3081)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c28
-rw-r--r--src/dynarec/la64/dynarec_la64_db.c20
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c119
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h4
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);