about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-04-14 18:47:42 +0800
committerGitHub <noreply@github.com>2024-04-14 12:47:42 +0200
commit7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab (patch)
treeb89c18dcde58ad2fdb24e3bc7206cdc039bb73bf /src/dynarec
parentd936c072eaeac7d42f5846fb5d46815a4b0f84bf (diff)
downloadbox64-7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab.tar.gz
box64-7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab.zip
[LA64_DYNAREC] Added 1 more opcode and some fixes too (#1444)
* Added D3 /0 ROL opcode

* Refined emit_sub32c

* Fixed BSF and BSR
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c8
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c16
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_math.c2
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c55
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h12
5 files changed, 89 insertions, 4 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index afbe2555..72688d4f 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -1325,6 +1325,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xD3:
             nextop = F8;
             switch((nextop>>3)&7) {
+                case 0:
+                    INST_NAME("ROL Ed, CL");
+                    SETFLAGS(X_OF | X_CF, SF_SUBSET);
+                    GETED(0);
+                    emit_rol32(dyn, ninst, rex, ed, xRCX, x3, x4);
+                    WBACK;
+                    if (!wback && !rex.w) ZEROUP(ed);
+                    break;
                 case 4:
                 case 6:
                     INST_NAME("SHL Ed, CL");
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
index ebb6561a..d7184f2c 100644
--- a/src/dynarec/la64/dynarec_la64_0f.c
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -418,7 +418,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 X64_SET_EFLAGS(xZR, X_ZF);
             } else {
                 ADDI_D(x3, xZR, ~(1 << F_ZF));
-                OR(xFlags, xFlags, x3);
+                AND(xFlags, xFlags, x3);
             }
             break;
         case 0xBD:
@@ -433,10 +433,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 ed = x4;
             }
             BNE_MARK(ed, xZR);
-            ORI(xFlags, xFlags, 1 << F_ZF);
+            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;
-            ANDI(xFlags, xFlags, ~(1 << F_ZF));
+            if (la64_lbt) {
+                X64_SET_EFLAGS(xZR, X_ZF);
+            } else {
+                ADDI_D(x3, xZR, ~(1 << F_ZF));
+                AND(xFlags, xFlags, x3);
+            }
             if (rex.w)
                 CLZ_D(gd, ed);
             else
diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c
index ca26ecc8..4c5f194f 100644
--- a/src/dynarec/la64/dynarec_la64_emit_math.c
+++ b/src/dynarec/la64/dynarec_la64_emit_math.c
@@ -531,7 +531,6 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
         SET_DFNONE();
     }
 
-    CLEAR_FLAGS(s3);
     if (la64_lbt) {
         IFX(X_PEND) {} else {MOV64xw(s2, c);}
         IFX(X_ALL) {
@@ -549,6 +548,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
         return;
     }
 
+    CLEAR_FLAGS(s3);
     IFX(X_AF | X_CF | X_OF) {
         // for later flag calculation
         NOR(s5, xZR, s1);
diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c
index 477dee08..f5a3b213 100644
--- a/src/dynarec/la64/dynarec_la64_emit_shift.c
+++ b/src/dynarec/la64/dynarec_la64_emit_shift.c
@@ -444,3 +444,58 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
         }
     }
 }
+
+// emit ROL32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
+{
+    int64_t j64;
+
+    IFX (X_PEND) {
+        SDxw(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s4, rex.w ? d_rol64 : d_rol32);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX (X_ALL) {
+            if (rex.w)
+                X64_ROTL_D(s1, s2);
+            else
+                X64_ROTL_W(s1, s2);
+        }
+    }
+
+    if (rex.w) {
+        ANDI(s4, s2, 0x3f);
+    } else {
+        ANDI(s4, s2, 0x1f);
+    }
+
+    SLLxw(s3, s1, s4);
+    NEG_D(s4, s4);
+    ADDI_D(s4, s4, rex.w ? 64 : 32);
+    SRLxw(s1, s1, s4);
+    OR(s1, s3, s1);
+
+    IFX (X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    if (la64_lbt) return;
+
+    CLEAR_FLAGS(s3);
+    IFX (X_CF | X_OF) {
+        ANDI(s4, s1, 1); // LSB == F_CF
+        IFX (X_CF) OR(xFlags, xFlags, s4);
+    }
+    IFX (X_OF) {
+        // the OF flag is set to the exclusive OR of the CF bit (after the rotate) and the most-significant bit of the result.
+        ADDI_D(s3, xZR, 1);
+        BNE_NEXT(s2, s3);
+        SRLIxw(s3, s1, rex.w ? 63 : 31);
+        XOR(s3, s3, s4); // s3: MSB, s4: CF bit
+        SLLI_D(s3, s3, F_OF);
+        OR(xFlags, xFlags, s3);
+    }
+}
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index b44c6c88..2ec42225 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -419,6 +419,16 @@
     j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \
     B(j64)
 
+// Branch to NEXT if reg1==reg2 (use j64)
+#define BEQ_NEXT(reg1, reg2)                                                  \
+    j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \
+    BEQ(reg1, reg2, j64)
+
+// Branch to NEXT if reg1!=reg2 (use j64)
+#define BNE_NEXT(reg1, reg2)                                                  \
+    j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \
+    BNE(reg1, reg2, j64)
+
 // Branch to MARKSEG if reg is 0 (use j64)
 #define CBZ_MARKSEG(reg)                   \
     j64 = GETMARKSEG - (dyn->native_size); \
@@ -708,6 +718,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_shr32c         STEPNAME(emit_shr32c)
 #define emit_sar32c         STEPNAME(emit_sar32c)
 #define emit_ror32c         STEPNAME(emit_ror32c)
+#define emit_rol32          STEPNAME(emit_rol32)
 
 #define emit_pf STEPNAME(emit_pf)
 
@@ -782,6 +793,7 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 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);
 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);
 
 void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);