about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2024-05-11 16:49:16 +0800
committerGitHub <noreply@github.com>2024-05-11 10:49:16 +0200
commit46dfaab639b7d2a5af79c288160bfe92b1fd6961 (patch)
tree40700e5ae357f63641c96c698a89eed0450470b9 /src
parentff755facc0c0ec502b4476d1144b61055abb3e7b (diff)
downloadbox64-46dfaab639b7d2a5af79c288160bfe92b1fd6961.tar.gz
box64-46dfaab639b7d2a5af79c288160bfe92b1fd6961.zip
[DYNAREC_LA64] Added more opcodes (#1496)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_0f.c59
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c40
-rw-r--r--src/dynarec/la64/dynarec_la64_660f.c14
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_shift.c116
-rw-r--r--src/dynarec/la64/dynarec_la64_f0.c34
-rw-r--r--src/dynarec/la64/dynarec_la64_f20f.c24
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h4
7 files changed, 290 insertions, 1 deletions
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c
index 8ddae253..b63bdca4 100644
--- a/src/dynarec/la64/dynarec_la64_0f.c
+++ b/src/dynarec/la64/dynarec_la64_0f.c
@@ -607,6 +607,65 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 LD_HU(gd, ed, fixedaddress);
             }
             break;
+        case 0xBA:
+            nextop = F8;
+            switch ((nextop >> 3) & 7) {
+                case 4:
+                    INST_NAME("BT Ed, Ib");
+                    SETFLAGS(X_CF, SF_SUBSET);
+                    SET_DFNONE();
+                    GETED(1);
+                    u8 = F8;
+                    u8 &= rex.w ? 0x3f : 0x1f;
+                    BSTRPICK_D(x4, ed, u8, u8);
+                    if (la64_lbt)
+                        X64_SET_EFLAGS(x4, X_CF);
+                    else
+                        BSTRINS_D(xFlags, x4, 0, 0);
+                    break;
+                case 5:
+                    INST_NAME("BTS Ed, Ib");
+                    SETFLAGS(X_CF, SF_SUBSET);
+                    SET_DFNONE();
+                    GETED(1);
+                    u8 = F8;
+                    u8 &= (rex.w ? 0x3f : 0x1f);
+                    BSTRPICK_D(x4, ed, u8, u8);
+                    if (la64_lbt)
+                        X64_SET_EFLAGS(x4, X_CF);
+                    else
+                        BSTRINS_D(xFlags, x4, 0, 0);
+                    ADDI_D(x4, xZR, -1);
+                    BSTRINS_D(ed, x4, u8, u8);
+                    if (wback) {
+                        SDxw(ed, wback, fixedaddress);
+                        SMWRITE();
+                    }
+                    MARK;
+                    break;
+                case 6:
+                    INST_NAME("BTR Ed, Ib");
+                    SETFLAGS(X_CF, SF_SUBSET);
+                    SET_DFNONE();
+                    GETED(1);
+                    u8 = F8;
+                    u8 &= (rex.w ? 0x3f : 0x1f);
+                    BSTRPICK_D(x4, ed, u8, u8);
+                    if (la64_lbt)
+                        X64_SET_EFLAGS(x4, X_CF);
+                    else
+                        BSTRINS_D(xFlags, x4, 0, 0);
+                    BSTRINS_D(ed, xZR, u8, u8);
+                    if (wback) {
+                        SDxw(ed, wback, fixedaddress);
+                        SMWRITE();
+                    }
+                    MARK;
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         case 0xBC:
             INST_NAME("BSF Gd, Ed");
             SETFLAGS(X_ZF, SF_SUBSET);
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
index 3dd04ede..9f23ed8c 100644
--- a/src/dynarec/la64/dynarec_la64_66.c
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -94,6 +94,15 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             emit_or16(dyn, ninst, x1, x2, x4, x2);
             EWBACK;
             break;
+        case 0x0B:
+            INST_NAME("OR Gw, Ew");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGW(x1);
+            GETEW(x2, 0);
+            emit_or16(dyn, ninst, x1, x2, x4, x5);
+            GWBACK;
+            break;
         case 0x0F:
             switch (rep) {
                 case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
@@ -451,6 +460,21 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xD3:
             nextop = F8;
             switch ((nextop >> 3) & 7) {
+                case 5:
+                    if (opcode == 0xD1) {
+                        INST_NAME("SHR Ew, 1");
+                        MOV32w(x2, 1);
+                    } else {
+                        INST_NAME("SHR Ew, CL");
+                        ANDI(x2, xRCX, 0x1f);
+                        BEQ_NEXT(x2, xZR);
+                    }
+                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                    if (box64_dynarec_safeflags > 1) MAYSETFLAGS();
+                    GETEW(x1, 0);
+                    emit_shr16(dyn, ninst, x1, x2, x5, x4, x6);
+                    EWBACK;
+                    break;
                 case 4:
                 case 6:
                     if (opcode == 0xD1) {
@@ -468,6 +492,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_shl16(dyn, ninst, x1, x2, x5, x4, x6);
                     EWBACK;
                     break;
+                case 7:
+                    if (opcode == 0xD1) {
+                        INST_NAME("SAR Ew, 1");
+                        MOV32w(x2, 1);
+                    } else {
+                        INST_NAME("SAR Ew, CL");
+                        ANDI(x2, xRCX, 0x1f);
+                        BEQ_NEXT(x2, xZR);
+                    }
+                    SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
+                    if (box64_dynarec_safeflags > 1)
+                        MAYSETFLAGS();
+                    GETSEW(x1, 0);
+                    emit_sar16(dyn, ninst, x1, x2, x5, x4, x6);
+                    EWBACK;
+                    break;
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/la64/dynarec_la64_660f.c b/src/dynarec/la64/dynarec_la64_660f.c
index 2929118a..c9a55984 100644
--- a/src/dynarec/la64/dynarec_la64_660f.c
+++ b/src/dynarec/la64/dynarec_la64_660f.c
@@ -255,6 +255,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
             GETGX(v0, 1);
             VAND_V(v0, v0, q0);
             break;
+        case 0x55:
+            INST_NAME("ANDNPD Gx, Ex");
+            nextop = F8;
+            GETEX(q0, 0, 0);
+            GETGX(v0, 1);
+            VANDN_V(v0, v0, q0);
+            break;
+        case 0x56:
+            INST_NAME("ORPD Gx, Ex");
+            nextop = F8;
+            GETEX(q0, 0, 0);
+            GETGX(v0, 1);
+            VOR_V(v0, v0, q0);
+            break;
         case 0x57:
             INST_NAME("XORPD Gx, Ex");
             nextop = F8;
diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c
index 9820a754..28f8b849 100644
--- a/src/dynarec/la64/dynarec_la64_emit_shift.c
+++ b/src/dynarec/la64/dynarec_la64_emit_shift.c
@@ -294,6 +294,65 @@ void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
     }
 }
 
+// emit SHR16 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
+void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    int64_t j64;
+
+    IFX (X_PEND) {
+        ST_H(s2, xEmu, offsetof(x64emu_t, op2));
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s4, d_shr16);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX (X_ALL) {
+            X64_SRL_H(s1, s2);
+        }
+
+        SRL_D(s1, s1, s2);
+        BSTRPICK_D(s1, s1, 15, 0);
+
+        IFX (X_PEND) {
+            ST_H(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    CLEAR_FLAGS(s3);
+    IFX (X_CF) {
+        ADDI_D(s3, s2, -1);
+        SRA_D(s3, s1, s3);
+        ANDI(s3, s3, 1); // LSB == F_CF
+        OR(xFlags, xFlags, s3);
+    }
+    IFX (X_OF) {
+        // OF flag is affected only on 1-bit shifts
+        // OF flag is set to the most-significant bit of the original operand
+        ADDI_D(s3, xZR, 1);
+        BNE(s2, s3, 4 + 3 * 4);
+        SRLI_D(s3, s1, 15);
+        SLLI_D(s3, s3, F_OF);
+        OR(xFlags, xFlags, s3);
+    }
+
+    SRL_D(s1, s1, s2);
+    BSTRPICK_D(s1, s1, 15, 0);
+
+    // SF should be unset
+    IFX (X_PEND) {
+        ST_H(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 SHR32 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
 void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
@@ -447,6 +506,63 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
 }
 
 
+// emit SAR16 instruction, from s1, shift s2 (!0 and and'd already), store result in s1 using s3, s4 and s5 as scratch
+void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    int64_t j64;
+
+    IFX (X_PEND) {
+        ST_H(s2, xEmu, offsetof(x64emu_t, op2));
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s4, d_sar8);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        IFX (X_ALL) {
+            X64_SRA_H(s1, s2);
+        }
+
+        SRL_D(s1, s1, s2);
+        BSTRPICK_D(s1, s1, 15, 0);
+
+        IFX (X_PEND) {
+            ST_H(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    CLEAR_FLAGS(s3);
+    IFX (X_CF) {
+        ADDI_D(s3, s2, -1);
+        SRA_D(s3, s1, s3);
+        ANDI(s3, s3, 1); // LSB == F_CF
+        OR(xFlags, xFlags, s3);
+    }
+    // For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
+    // OF nop
+    IFX (X_SF) {
+        // SF is the same as the original operand
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+
+    SRL_D(s1, s1, s2);
+    BSTRPICK_D(s1, s1, 15, 0);
+
+    IFX (X_PEND) {
+        ST_H(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 SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
 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/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c
index 03e16a8b..545f4287 100644
--- a/src/dynarec/la64/dynarec_la64_f0.c
+++ b/src/dynarec/la64/dynarec_la64_f0.c
@@ -217,6 +217,40 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                         SMDMB();
                     }
                     break;
+                case 5: // SUB
+                    if (opcode == 0x81) {
+                        INST_NAME("LOCK SUB Ed, Id");
+                    } else {
+                        INST_NAME("LOCK SUB Ed, Ib");
+                    }
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    if (MODREG) {
+                        if (opcode == 0x81)
+                            i64 = F32S;
+                        else
+                            i64 = F8S;
+                        ed = xRAX + (nextop & 7) + (rex.b << 3);
+                        emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
+                    } else {
+                        addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
+                        if (opcode == 0x81)
+                            i64 = F32S;
+                        else
+                            i64 = F8S;
+                        MARKLOCK;
+                        LLxw(x1, wback, 0);
+                        if (i64 > -2048 && i64 <= 2048) {
+                            ADDIxw(x4, x1, -i64);
+                        } else {
+                            MOV64xw(x4, i64);
+                            SUBxw(x4, x1, x4);
+                        }
+                        SCxw(x4, wback, 0);
+                        BEQZ_MARKLOCK(x4);
+                        IFX (X_ALL | X_PEND)
+                            emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5, x6);
+                    }
+                    break;
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/la64/dynarec_la64_f20f.c b/src/dynarec/la64/dynarec_la64_f20f.c
index e065c569..d9d474e6 100644
--- a/src/dynarec/la64/dynarec_la64_f20f.c
+++ b/src/dynarec/la64/dynarec_la64_f20f.c
@@ -33,7 +33,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
     uint8_t u8;
     uint64_t u64, j64;
     int v0, v1;
-    int q0;
+    int q0, q1;
     int d0, d1;
     int64_t fixedaddress;
     int unscaled;
@@ -229,6 +229,28 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
             MARK;
             VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
             break;
+        case 0xC2:
+            INST_NAME("CMPSD Gx, Ex, Ib");
+            nextop = F8;
+            GETGX(v0, 1);
+            GETEXSS(v1, 0, 1);
+            u8 = F8;
+            switch (u8 & 7) {
+                case 0: FCMP_D(fcc0, v0, v1, cEQ); break;  // Equal
+                case 1: FCMP_D(fcc0, v0, v1, cLT); break;  // Less than
+                case 2: FCMP_D(fcc0, v0, v1, cLE); break;  // Less or equal
+                case 3: FCMP_D(fcc0, v0, v1, cUN); break;  // NaN
+                case 4: FCMP_D(fcc0, v0, v1, cUNE); break; // Not Equal or unordered
+                case 5: FCMP_D(fcc0, v1, v0, cULE); break; // Greater or equal or unordered
+                case 6: FCMP_D(fcc0, v1, v0, cULT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
+                case 7: FCMP_D(fcc0, v0, v1, cOR); break;  // not NaN
+            }
+            MOVCF2GR(x2, fcc0);
+            NEG_D(x2, x2);
+            q1 = fpu_get_scratch(dyn);
+            MOVGR2FR_D(q1, x2);
+            VEXTRINS_D(v0, q1, 0);
+            break;
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index bebc24c6..a8bd4018 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -783,8 +783,10 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_shl32          STEPNAME(emit_shl32)
 #define emit_shl32c         STEPNAME(emit_shl32c)
 #define emit_shr8           STEPNAME(emit_shr8)
+#define emit_shr16          STEPNAME(emit_shr16)
 #define emit_shr32          STEPNAME(emit_shr32)
 #define emit_shr32c         STEPNAME(emit_shr32c)
+#define emit_sar16          STEPNAME(emit_sar16)
 #define emit_sar32c         STEPNAME(emit_sar32c)
 #define emit_ror32c         STEPNAME(emit_ror32c)
 #define emit_rol32          STEPNAME(emit_rol32)
@@ -870,8 +872,10 @@ void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
 void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5);
 void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
+void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, 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_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 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);