about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-03-04 18:36:27 +0800
committerGitHub <noreply@github.com>2024-03-04 11:36:27 +0100
commit61de3532c2fe1193e13c42080f434a6230cd83bd (patch)
treef8a4f41f697ed4edfaf531d769192a55427dd168 /src
parentddfc699809e5b1300692f23aeea30b1c82007495 (diff)
downloadbox64-61de3532c2fe1193e13c42080f434a6230cd83bd.tar.gz
box64-61de3532c2fe1193e13c42080f434a6230cd83bd.zip
[LA64_DYNAREC] Added more opcodes (#1321)
* [LA64_DYNAREC] Added 0F 80..8F Jcc opcodes

* [LA64_DYNAREC] Added 31/33 XOR opcodes

* [LA64_DYNAREC] Added 0F A2 CPUID opcode

* [LA64_DYNAREC] Added 81/83 /4 AND opcode

* [LA64_DYNAREC] Added 25 AND opcode

* [LA64_DYNAREC] Added F7 /0 /1 TEST opcodes

* Fix
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c48
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c51
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_logic.c116
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_tests.c57
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h7
-rw-r--r--src/dynarec/la64/la64_emitter.h3
6 files changed, 281 insertions, 1 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index d4b79011..c7374442 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -116,6 +116,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x25:
+            INST_NAME("AND EAX, Id");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            i64 = F32S;
+            emit_and32c(dyn, ninst, rex, xRAX, i64, x3, x4);
+            break;
         case 0x28:
             INST_NAME("SUB Eb, Gb");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -167,6 +173,25 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             i64 = F32S;
             emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5);
             break;
+        case 0x31:
+            INST_NAME("XOR Ed, Gd");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGD;
+            GETED(0);
+            emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
+            if(ed!=gd) {
+                WBACK;
+            }
+            break;
+        case 0x33:
+            INST_NAME("XOR Gd, Ed");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGD;
+            GETED(0);
+            emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
+            break;
         case 0x39:
             INST_NAME("CMP Ed, Gd");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -289,6 +314,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
                     WBACK;
                     break;
+                case 4: // AND
+                    if (opcode == 0x81) { INST_NAME("AND Ed, Id"); } else { INST_NAME("AND Ed, Ib"); }
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETED((opcode == 0x81) ? 4 : 1);
+                    if (opcode == 0x81) i64 = F32S; else i64 = F8S;
+                    emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
+                    WBACK;
+                    break;
                 case 5: // SUB
                     if (opcode == 0x81) {
                         INST_NAME("SUB Ed, Id");
@@ -714,6 +747,21 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             *need_epilog = 0;
             *ok = 0;
             break;
+        case 0xF7:
+            nextop = F8;
+            switch ((nextop >> 3) & 7) {
+                case 0:
+                case 1:
+                    INST_NAME("TEST Ed, Id");
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETED(4);
+                    i64 = F32S;
+                    emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0xFF:
             nextop = F8;
             switch ((nextop >> 3) & 7) {
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
index 92f09657..9a320619 100644
--- a/src/dynarec/la64/dynarec_la64_0f.c
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -80,6 +80,57 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             nextop = F8;
             FAKEED;
             break;
+
+        #define GO(GETFLAGS, NO, YES, F, I)                                                            \
+            READFLAGS(F);                                                                           \
+            i32_ = F32S;                                                                            \
+            BARRIER(BARRIER_MAYBE);                                                                 \
+            JUMP(addr + i32_, 1);                                                                   \
+            if (la64_lbt && (opcode - 0x70) >= 0xC) {                                               \
+                X64_SET_EFLAGS(xFlags, F);                                                          \
+                X64_SETJ(x1, I);                                                                    \
+            } else {                                                                                \
+                GETFLAGS;                                                                           \
+            }                                                                                       \
+            if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) {                           \
+                /* out of the block */                                                              \
+                i32 = dyn->insts[ninst].epilog - (dyn->native_size);                                \
+                if (la64_lbt && (opcode - 0x70) >= 0xC)                                             \
+                    BEQZ_safe(x1, i32);                                                             \
+                else                                                                                \
+                    B##NO##_safe(x1, i32);                                                          \
+                if (dyn->insts[ninst].x64.jmp_insts == -1) {                                        \
+                    if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT))                           \
+                        fpu_purgecache(dyn, ninst, 1, x1, x2, x3);                                  \
+                    jump_to_next(dyn, addr + i32_, 0, ninst, rex.is32bits);                         \
+                } else {                                                                            \
+                    CacheTransform(dyn, ninst, cacheupd, x1, x2, x3);                               \
+                    i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
+                    B(i32);                                                                         \
+                }                                                                                   \
+            } else {                                                                                \
+                /* inside the block */                                                              \
+                i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size);     \
+                if (la64_lbt && (opcode - 0x70) >= 0xC)                                             \
+                    BNEZ_safe(x1, i32);                                                             \
+                else                                                                                \
+                    B##YES##_safe(x1, i32);                                                         \
+            }
+
+            GOCOND(0x80, "J", "Id");
+
+        #undef GO
+
+        case 0xA2:
+            INST_NAME("CPUID");
+            NOTEST(x1);
+            MV(A1, xRAX);
+            CALL_(my_cpuid, -1, 0);
+            // BX and DX are not synchronized durring the call, so need to force the update
+            LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
+            LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
+            break;
+
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/la64/dynarec_la64_emit_logic.c b/src/dynarec/la64/dynarec_la64_emit_logic.c
new file mode 100644
index 00000000..e1580e97
--- /dev/null
+++ b/src/dynarec/la64/dynarec_la64_emit_logic.c
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+
+#include "la64_printer.h"
+#include "dynarec_la64_private.h"
+#include "dynarec_la64_functions.h"
+#include "dynarec_la64_helper.h"
+
+
+// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
+{
+    CLEAR_FLAGS(s3);
+    IFX(X_PEND) {
+        SET_DF(s4, rex.w ? d_xor64 : d_xor32);
+    } else IFX(X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX(X_ALL) {
+            if (rex.w) X64_XOR_D(s1, s2); else X64_XOR_W(s1, s2);
+            X64_GET_EFLAGS(s3, X_ALL);
+            OR(xFlags, xFlags, s3);
+        }
+        XOR(s1, s1, s2);
+        if (!rex.w && s1 != s2) ZEROUP(s1);
+
+        IFX(X_PEND)
+            SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        return;
+    }
+
+    XOR(s1, s1, s2);
+
+    // test sign bit before zeroup.
+    IFX(X_SF) {
+        if (!rex.w) SEXT_W(s1, s1);
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    if (!rex.w && s1 != s2) {
+        ZEROUP(s1);
+    }
+
+    IFX(X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
+// emit AND32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
+void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
+{
+    CLEAR_FLAGS(s3);
+    IFX(X_PEND) {
+        SET_DF(s3, rex.w ? d_tst64 : d_tst32);
+    } else IFX(X_ALL) {
+        SET_DFNONE();
+    }
+
+    IFXA(X_ALL, la64_lbt) {
+        MOV64xw(s3, c);
+        if (rex.w) X64_AND_D(s1, s3); else X64_AND_W(s1, s3);
+        X64_GET_EFLAGS(s4, X_ALL);
+        OR(xFlags, xFlags, s4);
+    }
+
+    if (c >= 0 && c <= 4095) {
+        ANDI(s1, s1, c);
+    } else {
+        IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c);
+        AND(s1, s1, s3); // res = s1 & s2
+    }
+
+    IFX(X_PEND)  {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    if (la64_lbt) return;
+
+    IFX(X_SF) {
+        SRLI_D(s3, s1, rex.w ? 63 : 31);
+        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);
+    }
+}
\ No newline at end of file
diff --git a/src/dynarec/la64/dynarec_la64_emit_tests.c b/src/dynarec/la64/dynarec_la64_emit_tests.c
index e6ab543e..fcb33eb2 100644
--- a/src/dynarec/la64/dynarec_la64_emit_tests.c
+++ b/src/dynarec/la64/dynarec_la64_emit_tests.c
@@ -247,4 +247,59 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
     IFX(X_PF) {
         emit_pf(dyn, ninst, s3, s4, s5);
     }
-}
\ No newline at end of file
+}
+
+// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
+void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
+{
+    CLEAR_FLAGS(s3);
+    IFX_PENDOR0 {
+        SET_DF(s3, rex.w ? d_tst64 : d_tst32);
+    } else {
+        SET_DFNONE();
+    }
+
+
+    if (la64_lbt) {
+        IFX(X_ALL) {
+            MOV64xw(s3, c);
+            if (rex.w) X64_AND_D(s1, s3); else X64_AND_W(s1, s3);
+            X64_GET_EFLAGS(s3, X_ALL);
+            OR(xFlags, xFlags, s3);
+        }
+
+        IFX_PENDOR0 {
+            if (c >= 0 && c <= 4095) {
+                ANDI(s3, s1, c);
+            } else {
+                IFX(X_ALL) { } else MOV64xw(s3, c);
+                AND(s3, s1, s3);
+            }
+            SDxw(s3, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    if (c >= 0 && c <= 4095) {
+        ANDI(s3, s1, c);
+    } else {
+        IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c);
+        AND(s3, s1, s3);
+    }
+
+    IFX_PENDOR0 {
+        SDxw(s3, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_SF) {
+        SRLI_D(s4, s3, rex.w ? 63 : 31);
+        BEQZ(s4, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX(X_ZF) {
+        BNEZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s3, s4, s5);
+    }
+}
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index c844c049..e3c0c874 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -247,6 +247,7 @@
     BEQZ(reg1, j64)
 
 #define IFX(A)      if ((dyn->insts[ninst].x64.gen_flags & (A)))
+#define IFXA(A, B)  if ((dyn->insts[ninst].x64.gen_flags & (A)) && (B))
 #define IFX_PENDOR0 if ((dyn->insts[ninst].x64.gen_flags & (X_PEND) || !dyn->insts[ninst].x64.gen_flags))
 #define IFXX(A)     if ((dyn->insts[ninst].x64.gen_flags == (A)))
 #define IFX2X(A, B) if ((dyn->insts[ninst].x64.gen_flags == (A) || dyn->insts[ninst].x64.gen_flags == (B) || dyn->insts[ninst].x64.gen_flags == ((A) | (B))))
@@ -465,6 +466,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_cmp8           STEPNAME(emit_cmp8)
 #define emit_cmp8_0         STEPNAME(emit_cmp8_0)
 #define emit_test32         STEPNAME(emit_test32)
+#define emit_test32c        STEPNAME(emit_test32c)
 #define emit_add32          STEPNAME(emit_add32)
 #define emit_add32c         STEPNAME(emit_add32c)
 #define emit_add8           STEPNAME(emit_add8)
@@ -473,6 +475,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_sub32c         STEPNAME(emit_sub32c)
 #define emit_sub8           STEPNAME(emit_sub8)
 #define emit_sub8c          STEPNAME(emit_sub8c)
+#define emit_xor32          STEPNAME(emit_xor32)
+#define emit_and32c          STEPNAME(emit_and32c)
 #define emit_shr32c         STEPNAME(emit_shr32c)
 #define emit_sar32c         STEPNAME(emit_sar32c)
 
@@ -509,6 +513,7 @@ void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_cmp8_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_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
+void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
 void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5);
 void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
@@ -517,6 +522,8 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5);
 void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_sub8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4, int s5);
+void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
+void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
 void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 
diff --git a/src/dynarec/la64/la64_emitter.h b/src/dynarec/la64/la64_emitter.h
index 35b593ba..a53ccd47 100644
--- a/src/dynarec/la64/la64_emitter.h
+++ b/src/dynarec/la64/la64_emitter.h
@@ -264,6 +264,9 @@ f24-f31  fs0-fs7   Static registers                Callee
         ADD_D(rd, rs1, scratch);           \
     }
 
+
+#define SEXT_W(rd, rs1) SLLI_W(rd, rs1, 0)
+
 // if GR[rj] == GR[rd]:
 //     PC = PC + SignExtend({imm16, 2'b0}, GRLEN)
 #define BEQ(rj, rd, imm18) EMIT(type_2RI16(0b010110, ((imm18)>>2), rj, rd))