about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-03-11 19:27:52 +0800
committerGitHub <noreply@github.com>2024-03-11 12:27:52 +0100
commitac0519a046e1517508051dbb13943a056123950a (patch)
treee1cee0ec805f00c3bc8ea93ea7aced10c26bc88f /src/dynarec
parent90a6306bbe2c853221e18a9a4eb5f79e2dafc186 (diff)
downloadbox64-ac0519a046e1517508051dbb13943a056123950a.tar.gz
box64-ac0519a046e1517508051dbb13943a056123950a.zip
[LA64_DYNAREC] Added more opcodes and some fixes (#1355)
* Added F0 B1 /0 LOCK CMPXCHG opcode

* Added 0F BE MOVSX opcode

* Added 81/83 /7 CMP opcodes

* Fixed emit_shl32c

* Added missing default

* Added A0 MOV opcode
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c7
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c22
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c26
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c18
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_tests.c86
-rw-r--r--src/dynarec/la64/dynarec_la64_f0.c40
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h21
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_shift.c6
8 files changed, 210 insertions, 16 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 0cb34c96..0f506da8 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -596,6 +596,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 ZEROUP(xRAX);
             }
             break;
+        case 0xA0:
+            INST_NAME("MOV AL,Ob");
+            if(rex.is32bits) u64 = F32; else u64 = F64;
+            MOV64z(x1, u64);
+            LD_BU(x2, x1, 0);
+            BSTRINS_D(xRAX, x2, 7, 0);
+            break;
         case 0xA8:
             INST_NAME("TEST AL, Ib");
             SETFLAGS(X_ALL, SF_SET_PENDING);
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
index ccd2c368..49119328 100644
--- a/src/dynarec/la64/dynarec_la64_0f.c
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -219,6 +219,28 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 LD_HU(gd, ed, fixedaddress);
             }
             break;
+        case 0xBE:
+            INST_NAME("MOVSX Gd, Eb");
+            nextop = F8;
+            GETGD;
+            if (MODREG) {
+                if (rex.rex) {
+                    wback = TO_LA64((nextop & 7) + (rex.b << 3));
+                    wb2 = 0;
+                } else {
+                    wback = (nextop & 7);
+                    wb2 = (wback >> 2) * 8;
+                    wback = TO_LA64(wback & 3);
+                }
+                BSTRPICK_D(gd, wback, wb2 + 7, wb2);
+                EXT_W_B(gd, gd);
+            } else {
+                SMREAD();
+                addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
+                LD_B(gd, ed, fixedaddress);
+            }
+            if (!rex.w) ZEROUP(gd);
+            break;
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
index 7f3cd96c..25023eb4 100644
--- a/src/dynarec/la64/dynarec_la64_66.c
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -65,6 +65,32 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x81:
+        case 0x83:
+            nextop = F8;
+            switch ((nextop >> 3) & 7) {
+                case 7: // CMP
+                    if (opcode == 0x81) {
+                        INST_NAME("CMP Ew, Iw");
+                    } else {
+                        INST_NAME("CMP Ew, Ib");
+                    }
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEW(x1, (opcode == 0x81) ? 2 : 1);
+                    if (opcode == 0x81)
+                        i16 = F16S;
+                    else
+                        i16 = F8S;
+                    if (i16) {
+                        MOV64x(x2, i16);
+                        emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
+                    } else
+                        emit_cmp16_0(dyn, ninst, x1, x3, x4);
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0x89:
             INST_NAME("MOV Ew, Gw");
             nextop = F8;
diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c
index b4d7ccdd..dff76a5a 100644
--- a/src/dynarec/la64/dynarec_la64_emit_shift.c
+++ b/src/dynarec/la64/dynarec_la64_emit_shift.c
@@ -91,23 +91,20 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 // emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
 void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
 {
+    if (!c) return;
+
     IFX(X_PEND) {
         if (c) {
             MOV64x(s3, c);
             SDxw(s3, xEmu, offsetof(x64emu_t, op2));
-        } else 
+        } else {
             SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
+        }
         SDxw(s1, xEmu, offsetof(x64emu_t, op1));
         SET_DF(s4, rex.w?d_shl64:d_shl32);
     } else IFX(X_ALL) {
         SET_DFNONE();
     }
-    if(!c) {
-        IFX(X_PEND) {
-            SDxw(s1, xEmu, offsetof(x64emu_t, res));
-        }
-        return;
-    }
 
     if(la64_lbt) {
         IFX(X_PEND) {} else { MOV64x(s3, c); }
@@ -120,6 +117,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
 
         SLLIxw(s1, s1, c);
 
+        if (!rex.w) ZEROUP(s1);
         IFX(X_PEND) {
             SDxw(s1, xEmu, offsetof(x64emu_t, res));
         }
@@ -127,9 +125,9 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
     }
 
     CLEAR_FLAGS(s3);
-    IFX(X_CF|X_OF) {
+    IFX(X_CF | X_OF) {
         if (c > 0) {
-            SRLI_D(s3, s1, (rex.w?64:32)-c);
+            SRLI_D(s3, s1, (rex.w ? 64 : 32) - c);
             ANDI(s5, s3, 1); // LSB == F_CF
             IFX(X_CF) {
                 OR(xFlags, xFlags, s5);
@@ -156,7 +154,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
     IFX(X_OF) {
         // OF flag is affected only on 1-bit shifts
         if (c == 1) {
-            SRLIxw(s3, s1, rex.w?63:31);
+            SRLIxw(s3, s1, rex.w ? 63 : 31);
             XOR(s3, s3, s5);
             SLLI_D(s3, s3, F_OF);
             OR(xFlags, xFlags, s3);
diff --git a/src/dynarec/la64/dynarec_la64_emit_tests.c b/src/dynarec/la64/dynarec_la64_emit_tests.c
index 916fdd38..1fbf9a7e 100644
--- a/src/dynarec/la64/dynarec_la64_emit_tests.c
+++ b/src/dynarec/la64/dynarec_la64_emit_tests.c
@@ -106,6 +106,92 @@ void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
     }
 }
 
+// emit CMP16 instruction, from cmp s1, s2, using s3 and s4 as scratch
+void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6)
+{
+    IFX_PENDOR0 {
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        ST_H(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s4, d_cmp16);
+    } else {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX(X_ALL) {
+            X64_SUB_H(s1, s2);
+        }
+
+        IFX_PENDOR0 {
+            SUB_D(s6, s1, s2);
+            ST_H(s6, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    CLEAR_FLAGS(s3);
+    IFX(X_AF | X_CF | X_OF) {
+        // for later flag calculation
+        NOR(s5, s5, s1);
+    }
+
+    // It's a cmp, we can't store the result back to s1.
+    SUB_D(s6, s1, s2);
+    IFX(X_ALL) {
+        BSTRPICK_D(s6, s6, 15, 0);
+    }
+    IFX_PENDOR0 {
+        ST_H(s6, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_SF) {
+        SRLI_D(s3, s6, 15);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 16);
+    IFX(X_ZF) {
+        BNEZ(s6, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s6, s3, s4);
+    }
+}
+
+// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
+void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
+{
+    IFX_PENDOR0 {
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        ST_H(xZR, xEmu, offsetof(x64emu_t, op2));
+        ST_H(s1, xEmu, offsetof(x64emu_t, res));
+        SET_DF(s3, d_cmp16);
+    } else {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX(X_ALL) {
+            X64_SUB_H(s1, xZR);
+        }
+        return;
+    }
+
+    CLEAR_FLAGS(s3);
+    IFX(X_SF) {
+        SRLI_D(s3, s1, 15);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
 // emit CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
 void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
 {
diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c
index 9d1c19db..931701a6 100644
--- a/src/dynarec/la64/dynarec_la64_f0.c
+++ b/src/dynarec/la64/dynarec_la64_f0.c
@@ -55,6 +55,44 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0x0F:
             nextop = F8;
             switch (nextop) {
+                case 0xB1:
+                    switch (rep) {
+                        case 0:
+                            INST_NAME("LOCK CMPXCHG Ed, Gd");
+                            SETFLAGS(X_ALL, SF_SET_PENDING);
+                            nextop = F8;
+                            GETGD;
+                            if (MODREG) {
+                                ed = TO_LA64((nextop & 7) + (rex.b << 3));
+                                wback = 0;
+                                UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5, x6); }
+                                MV(x1, ed); // save value
+                                SUB_D(x2, x1, xRAX);
+                                BNE_MARK2(x2, xZR);
+                                MV(ed, gd);
+                                MARK2;
+                                MVxw(xRAX, x1);
+                            } else {
+                                SMDMB();
+                                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                                MARKLOCK;
+                                MV(x4, gd);
+                                LLxw(x1, wback, 0);
+                                SUBxw(x3, x1, xRAX);
+                                BNEZ_MARK(x3);
+                                // EAX == Ed
+                                SCxw(x4, wback, 0);
+                                BEQZ_MARKLOCK(x4);
+                                MARK;
+                                UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6); }
+                                MVxw(xRAX, x1);
+                                SMDMB();
+                            }
+                            break;
+                        default:
+                            DEFAULT;
+                    }
+                    break;
                 case 0xC1:
                     switch (rep) {
                         case 0:
@@ -135,6 +173,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                         SMDMB();
                     }
                     break;
+                default:
+                    DEFAULT;
             }
             break;
         default:
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index b1cb2fc0..db980487 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -105,6 +105,22 @@
         LDz(x1, wback, fixedaddress);                                                           \
         ed = x1;                                                                                \
     }
+// GETEWW will use i for ed, and can use w for wback.
+#define GETEWW(w, i, D)                                                                       \
+    if (MODREG) {                                                                             \
+        wback = TO_LA64((nextop & 7) + (rex.b << 3));                                         \
+        BSTRPICK_D(i, wback, 15, 0);                                                          \
+        ed = i;                                                                               \
+        wb1 = 0;                                                                              \
+    } else {                                                                                  \
+        SMREAD();                                                                             \
+        addr = geted(dyn, addr, ninst, nextop, &wback, w, i, &fixedaddress, rex, NULL, 1, D); \
+        LD_HU(i, wback, fixedaddress);                                                        \
+        ed = i;                                                                               \
+        wb1 = 1;                                                                              \
+    }
+// GETEW will use i for ed, and can use r3 for wback.
+#define GETEW(i, D) GETEWW(x3, i, D)
 
 // FAKEED like GETED, but doesn't get anything
 #define FAKEED                                   \
@@ -390,6 +406,7 @@
 #ifndef SET_HASCALLRET
 #define SET_HASCALLRET()
 #endif
+#define UFLAG_IF if (dyn->insts[ninst].x64.gen_flags)
 #ifndef DEFAULT
 #define DEFAULT \
     *ok = -1;   \
@@ -472,6 +489,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define jump_to_next        STEPNAME(jump_to_next)
 #define ret_to_epilog       STEPNAME(ret_to_epilog)
 #define call_c              STEPNAME(call_c)
+#define emit_cmp16          STEPNAME(emit_cmp16)
+#define emit_cmp16_0        STEPNAME(emit_cmp16_0)
 #define emit_cmp32          STEPNAME(emit_cmp32)
 #define emit_cmp32_0        STEPNAME(emit_cmp32_0)
 #define emit_cmp8           STEPNAME(emit_cmp8)
@@ -528,8 +547,10 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
 void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex);
 void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);
+void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);
 void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6);
 void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
+void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
 void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
 void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_shift.c b/src/dynarec/rv64/dynarec_rv64_emit_shift.c
index 1db7344f..69e6a08f 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_shift.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_shift.c
@@ -90,12 +90,6 @@ void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
         SET_DFNONE();
     }
 
-    if(!c) {
-        IFX(X_PEND) {
-            SDxw(s1, xEmu, offsetof(x64emu_t, res));
-        }
-        return;
-    }
     IFX(X_CF|X_OF) {
         if (c > 0) {
             SRLI(s3, s1, (rex.w?64:32)-c);