about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-04-13 03:58:05 +0800
committerGitHub <noreply@github.com>2024-04-12 21:58:05 +0200
commitb9ea2408c205bbcd38212dc64aa2ef6ea47dc924 (patch)
tree0328b88c8812ddcbba1aaff00f02596ecb4476c7 /src
parent6ce570f4a514797aafe4c02bb750106365b5a3e7 (diff)
downloadbox64-b9ea2408c205bbcd38212dc64aa2ef6ea47dc924.tar.gz
box64-b9ea2408c205bbcd38212dc64aa2ef6ea47dc924.zip
[LA64_DYNAREC] Added more opcodes (#1441)
* Added 66 C7 MOV opcode

* Added B0..B3 MOV opcode

* Added F0 87 LOCK XCHG opcode

* Added 35 XOR opcode

* Added F7 /7 IDIV opcode

* Added BC BSF opcode

* Added BD BSR opcode
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c65
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c55
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c16
-rw-r--r--src/dynarec/la64/dynarec_la64_f0.c22
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h26
5 files changed, 184 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index f4987cc6..afbe2555 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -301,6 +301,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             GETGB(x2);
             emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6);
             break;
+        case 0x35:
+            INST_NAME("XOR EAX, Id");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            i64 = F32S;
+            emit_xor32c(dyn, ninst, rex, xRAX, i64, x3, x4);
+            break;
         case 0x39:
             INST_NAME("CMP Ed, Gd");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -983,6 +989,19 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 ADD_D(xRDI, xRDI, x3);
             }
             break;
+        case 0xB0:
+        case 0xB1:
+        case 0xB2:
+        case 0xB3:
+            INST_NAME("MOV xL, Ib");
+            u8 = F8;
+            MOV32w(x1, u8);
+            if (rex.rex)
+                gb1 = TO_LA64((opcode & 7) + (rex.b << 3));
+            else
+                gb1 = TO_LA64(opcode & 3);
+            BSTRINS_D(gb1, x1, 7, 0);
+            break;
         case 0xB8:
         case 0xB9:
         case 0xBA:
@@ -1664,6 +1683,52 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                         }
                     }
                     break;
+                case 7:
+                    INST_NAME("IDIV Ed");
+                    SKIPTEST(x1);
+                    SETFLAGS(X_ALL, SF_SET);
+                    if (!rex.w) {
+                        SET_DFNONE()
+                        GETSED(0);
+                        SLLI_D(x3, xRDX, 32);
+                        AND(x2, xRAX, xMASK);
+                        OR(x3, x3, x2);
+                        DIV_D(x2, x3, ed);
+                        MOD_D(xRDX, x3, ed);
+                        AND(xRAX, x2, xMASK);
+                        ZEROUP(xRDX);
+                    } else {
+                        if (ninst && dyn->insts
+                            && dyn->insts[ninst - 1].x64.addr
+                            && *(uint8_t*)(dyn->insts[ninst - 1].x64.addr) == 0x48
+                            && *(uint8_t*)(dyn->insts[ninst - 1].x64.addr + 1) == 0x99) {
+                            SET_DFNONE()
+                            GETED(0);
+                            DIV_D(x2, xRAX, ed);
+                            MOD_D(xRDX, xRAX, ed);
+                            MV(xRAX, x2);
+                        } else {
+                            GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
+                            // need to see if RDX == 0 and RAX not signed
+                            // or RDX == -1 and RAX signed
+                            BNE_MARK2(xRDX, xZR);
+                            BGE_MARK(xRAX, xZR);
+                            MARK2;
+                            NOR(x2, xZR, xRDX);
+                            BNE_MARK3(x2, xZR);
+                            BLT_MARK(xRAX, xZR);
+                            MARK3;
+                            if (ed != x1) MV(x1, ed);
+                            CALL((void*)idiv64, -1);
+                            B_NEXT_nocond;
+                            MARK;
+                            DIV_D(x2, xRAX, ed);
+                            MOD_D(xRDX, xRAX, ed);
+                            MV(xRAX, x2);
+                            SET_DFNONE()
+                        }
+                    }
+                    break;
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
index e994203d..ebb6561a 100644
--- a/src/dynarec/la64/dynarec_la64_0f.c
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -389,6 +389,61 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 LD_HU(gd, ed, fixedaddress);
             }
             break;
+        case 0xBC:
+            INST_NAME("BSF Gd, Ed");
+            SETFLAGS(X_ZF, SF_SUBSET);
+            SET_DFNONE();
+            nextop = F8;
+            GETED(0);
+            GETGD;
+            if (!rex.w && MODREG) {
+                AND(x4, ed, xMASK);
+                ed = x4;
+            }
+            BNE_MARK(ed, xZR);
+            if (la64_lbt) {
+                ADDI_D(x3, xZR, 1 << F_ZF);
+                X64_SET_EFLAGS(x3, X_ZF);
+            } else {
+                ORI(xFlags, xFlags, 1 << F_ZF);
+            }
+            B_NEXT_nocond;
+            MARK;
+            // gd is undefined if ed is all zeros, don't worry.
+            if (rex.w)
+                CTZ_D(gd, ed);
+            else
+                CTZ_W(gd, ed);
+            if (la64_lbt) {
+                X64_SET_EFLAGS(xZR, X_ZF);
+            } else {
+                ADDI_D(x3, xZR, ~(1 << F_ZF));
+                OR(xFlags, xFlags, x3);
+            }
+            break;
+        case 0xBD:
+            INST_NAME("BSR Gd, Ed");
+            SETFLAGS(X_ZF, SF_SUBSET);
+            SET_DFNONE();
+            nextop = F8;
+            GETED(0);
+            GETGD;
+            if (!rex.w && MODREG) {
+                AND(x4, ed, xMASK);
+                ed = x4;
+            }
+            BNE_MARK(ed, xZR);
+            ORI(xFlags, xFlags, 1 << F_ZF);
+            B_NEXT_nocond;
+            MARK;
+            ANDI(xFlags, xFlags, ~(1 << F_ZF));
+            if (rex.w)
+                CLZ_D(gd, ed);
+            else
+                CLZ_W(gd, ed);
+            ADDI_D(x1, xZR, rex.w ? 63 : 31);
+            SUB_D(gd, x1, gd);
+            break;
         case 0xBE:
             INST_NAME("MOVSX Gd, Eb");
             nextop = F8;
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
index 71c73324..e7a358eb 100644
--- a/src/dynarec/la64/dynarec_la64_66.c
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -153,6 +153,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0xC7:
+            INST_NAME("MOV Ew, Iw");
+            nextop = F8;
+            if (MODREG) {
+                ed = TO_LA64((nextop & 7) + (rex.b << 3));
+                u16 = F16;
+                MOV32w(x1, u16);
+                BSTRINS_D(ed, x1, 15, 0);
+            } else {
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2);
+                u16 = F16;
+                MOV32w(x1, u16);
+                ST_H(x1, ed, fixedaddress);
+                SMWRITELOCK(lock);
+            }
+            break;
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c
index 931701a6..64c806f9 100644
--- a/src/dynarec/la64/dynarec_la64_f0.c
+++ b/src/dynarec/la64/dynarec_la64_f0.c
@@ -177,6 +177,28 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x87:
+            INST_NAME("LOCK XCHG Ed, Gd");
+            nextop = F8;
+            if (MODREG) {
+                GETGD;
+                GETED(0);
+                MV(x1, gd);
+                MV(gd, ed);
+                MV(ed, x1);
+            } else {
+                SMDMB();
+                GETGD;
+                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                MARKLOCK;
+                LLxw(x1, wback, 0);
+                MV(x4, gd);
+                SCxw(x4, wback, 0);
+                BEQZ_MARKLOCK(x4);
+                MVxw(gd, x1);
+                SMDMB();
+            }
+            break;
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index d5089d40..b44c6c88 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -151,6 +151,25 @@
         ed = x1;                                                                                \
     }
 
+// GETSED can use r1 for ed, and r2 for wback. ed will be sign extended!
+#define GETSED(D)                                                                               \
+    if (MODREG) {                                                                               \
+        ed = TO_LA64((nextop & 7) + (rex.b << 3));                                              \
+        wback = 0;                                                                              \
+        if (!rex.w) {                                                                           \
+            ADD_W(x1, ed, xZR);                                                                 \
+            ed = x1;                                                                            \
+        }                                                                                       \
+    } else {                                                                                    \
+        SMREAD();                                                                               \
+        addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, D); \
+        if (rex.w)                                                                              \
+            LD_D(x1, wback, fixedaddress);                                                      \
+        else                                                                                    \
+            LD_W(x1, wback, fixedaddress);                                                      \
+        ed = x1;                                                                                \
+    }
+
 // FAKEED like GETED, but doesn't get anything
 #define FAKEED                                   \
     if (!MODREG) {                               \
@@ -374,6 +393,13 @@
 // Branch to MARKLOCK if reg1!=0 (use j64)
 #define BNEZ_MARKLOCK(reg) BxxZ_gen(NE, MARKLOCK, reg)
 
+// Branch to MARK if reg1<reg2 (use j64)
+#define BLT_MARK(reg1, reg2) Bxx_gen(LT, MARK, reg1, reg2)
+// Branch to MARK if reg1<reg2 (use j64)
+#define BLTU_MARK(reg1, reg2) Bxx_gen(LTU, MARK, reg1, reg2)
+// Branch to MARK if reg1>=reg2 (use j64)
+#define BGE_MARK(reg1, reg2) Bxx_gen(GE, MARK, reg1, reg2)
+
 // Branch to MARK1 instruction unconditionnal (use j64)
 #define B_MARK1_nocond Bxx_gen(__, MARK1, 0, 0)
 // Branch to MARK2 instruction unconditionnal (use j64)