about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-05-23 16:51:07 +0800
committerGitHub <noreply@github.com>2024-05-23 10:51:07 +0200
commit080cc772083be446132557e3b2e6aad1b59c0e3f (patch)
tree43ba80b09892ce59c8d4143f99248146132eb25e /src/dynarec
parent7ebd92be7dab9f3959c8c25f73d3637ddcd72149 (diff)
downloadbox64-080cc772083be446132557e3b2e6aad1b59c0e3f.tar.gz
box64-080cc772083be446132557e3b2e6aad1b59c0e3f.zip
[LA64_DYNAREC] Added more opcodes (#1525)
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c14
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_math.c139
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h4
3 files changed, 157 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 570db990..4ed4e271 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -2055,6 +2055,20 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xFF:
             nextop = F8;
             switch ((nextop >> 3) & 7) {
+                case 0: // INC Ed
+                    INST_NAME("INC Ed");
+                    SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
+                    GETED(0);
+                    emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6);
+                    WBACK;
+                    break;
+                case 1: // DEC Ed
+                    INST_NAME("DEC Ed");
+                    SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
+                    GETED(0);
+                    emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6);
+                    WBACK;
+                    break;
                 case 2:
                     INST_NAME("CALL Ed");
                     PASS2IF((box64_dynarec_safeflags > 1) || ((ninst && dyn->insts[ninst - 1].x64.set_flags) || ((ninst > 1) && dyn->insts[ninst - 2].x64.set_flags)), 1)
diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c
index 50a8b103..cd94673e 100644
--- a/src/dynarec/la64/dynarec_la64_emit_math.c
+++ b/src/dynarec/la64/dynarec_la64_emit_math.c
@@ -1126,3 +1126,142 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
         ORI(xFlags, xFlags, 1 << F_ZF);
     }
 }
+
+// emit INC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
+void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
+{
+    IFX (X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s3, rex.w ? d_inc64 : d_inc32);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    IFXA (X_AF | X_OF, !la64_lbt) {
+        ORI(s3, s1, 1);  // s3 = op1 | op2
+        ANDI(s5, s1, 1); // s5 = op1 & op2
+    }
+
+    IFXA (X_ALL, la64_lbt) {
+        if (rex.w) {
+            X64_INC_D(s1);
+        } else {
+            X64_INC_W(s1);
+        }
+    }
+
+    ADDIxw(s1, s1, 1);
+
+    IFX (X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    if (la64_lbt) return;
+
+    IFX (X_ALL) {
+        // preserving CF
+        MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
+        ANDN(xFlags, xFlags, s4);
+    }
+    IFX (X_AF | X_OF) {
+        ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
+        OR(s3, s3, s5);   // cc = (~res & (op1 | op2)) | (op1 & op2)
+        IFX (X_AF) {
+            ANDI(s2, s3, 0x08); // AF: cc & 0x08
+            BEQZ(s2, 8);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX (X_OF) {
+            SRLI_D(s3, s3, rex.w ? 62 : 30);
+            SRLI_D(s2, s3, 1);
+            XOR(s3, s3, s2);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 8);
+            ORI(xFlags, xFlags, 1 << F_OF);
+        }
+    }
+    IFX (X_SF) {
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    if (!rex.w) {
+        ZEROUP(s1);
+    }
+    IFX (X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s2);
+    }
+    IFX (X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+}
+
+// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
+void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
+{
+    IFX (X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s3, rex.w ? d_dec64 : d_dec32);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+    IFXA (X_AF | X_OF, !la64_lbt) {
+        NOR(s5, xZR, s1);
+        ORI(s3, s5, 1);  // s3 = ~op1 | op2
+        ANDI(s5, s5, 1); // s5 = ~op1 & op2
+    }
+
+    IFXA (X_ALL, la64_lbt) {
+        if (rex.w) {
+            X64_DEC_D(s1);
+        } else {
+            X64_DEC_W(s1);
+        }
+    }
+
+
+    ADDIxw(s1, s1, -1);
+
+    IFX (X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+
+    if (la64_lbt) return;
+
+    IFX (X_ALL) {
+        // preserving CF
+        MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
+        ANDN(xFlags, xFlags, s4);
+    }
+    IFX (X_AF | X_OF) {
+        AND(s3, s1, s3); // s3 = res & (~op1 | op2)
+        OR(s3, s3, s5);  // cc = (res & (~op1 | op2)) | (~op1 & op2)
+        IFX (X_AF) {
+            ANDI(s2, s3, 0x08); // AF: cc & 0x08
+            BEQZ(s2, 8);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX (X_OF) {
+            SRLI_D(s3, s3, rex.w ? 62 : 30);
+            SRLI_D(s2, s3, 1);
+            XOR(s3, s3, s2);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 8);
+            ORI(xFlags, xFlags, 1 << F_OF);
+        }
+    }
+    IFX (X_SF) {
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    if (!rex.w) {
+        ZEROUP(s1);
+    }
+    IFX (X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s2);
+    }
+    IFX (X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+}
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index a8bd4018..cb74bcdf 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -764,6 +764,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_sbb32          STEPNAME(emit_sbb32)
 #define emit_neg8           STEPNAME(emit_neg8)
 #define emit_neg32          STEPNAME(emit_neg32)
+#define emit_inc32          STEPNAME(emit_inc32)
+#define emit_dec32          STEPNAME(emit_dec32)
 #define emit_or32           STEPNAME(emit_or32)
 #define emit_or32c          STEPNAME(emit_or32c)
 #define emit_or8            STEPNAME(emit_or8)
@@ -853,6 +855,8 @@ void emit_sbb16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
 void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 void emit_neg8(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4);
 void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3);
+void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
+void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
 void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
 void emit_or8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);