about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c46
-rw-r--r--src/dynarec/la64/dynarec_la64_64.c10
-rw-r--r--src/dynarec/la64/dynarec_la64_66.c47
-rw-r--r--src/dynarec/la64/dynarec_la64_emit_math.c159
-rw-r--r--src/dynarec/la64/dynarec_la64_f0.c25
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h6
6 files changed, 293 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 9f618456..c1ac8fa0 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -167,6 +167,16 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x10:
+            INST_NAME("ADC Eb, Gb");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETEB(x1, 0);
+            GETGB(x2);
+            emit_adc8(dyn, ninst, x1, x2, x4, x5, x6);
+            EBBACK();
+            break;
         case 0x11:
             INST_NAME("ADC Ed, Gd");
             READFLAGS(X_CF);
@@ -177,6 +187,16 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
             WBACK;
             break;
+        case 0x12:
+            INST_NAME("ADC Gb, Eb");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETEB(x2, 0);
+            GETGB(x1);
+            emit_adc8(dyn, ninst, x1, x2, x4, x6, x5);
+            GBBACK();
+            break;
         case 0x13:
             INST_NAME("ADC Gd, Ed");
             READFLAGS(X_CF);
@@ -186,6 +206,23 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             GETED(0);
             emit_adc32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6);
             break;
+        case 0x14:
+            INST_NAME("ADC AL, Ib");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            u8 = F8;
+            ANDI(x1, xRAX, 0xff);
+            emit_adc8c(dyn, ninst, x1, u8, x3, x4, x5, x6);
+            BSTRINS_D(xRAX, x1, 7, 0);
+            break;
+        case 0x15:
+            INST_NAME("ADC EAX, Id");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            i64 = F32S;
+            MOV64xw(x1, i64);
+            emit_adc32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6);
+            break;
         case 0x18:
             INST_NAME("SBB Eb, Gb");
             READFLAGS(X_CF);
@@ -666,6 +703,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
                     EBBACK();
                     break;
+                case 2: // ADC
+                    INST_NAME("ADC Eb, Ib");
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEB(x1, 1);
+                    u8 = F8;
+                    emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
+                    EBBACK();
+                    break;
                 case 3: // SBB
                     INST_NAME("SBB Eb, Ib");
                     READFLAGS(X_CF);
diff --git a/src/dynarec/la64/dynarec_la64_64.c b/src/dynarec/la64/dynarec_la64_64.c
index fb10e453..55f834b7 100644
--- a/src/dynarec/la64/dynarec_la64_64.c
+++ b/src/dynarec/la64/dynarec_la64_64.c
@@ -118,6 +118,16 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
                     EBBACK();
                     break;
+                case 2: // ADC
+                    INST_NAME("ADC Eb, Ib");
+                    grab_segdata(dyn, addr, ninst, x1, seg);
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEBO(x1, 1);
+                    u8 = F8;
+                    emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
+                    EBBACK();
+                    break;
                 case 3: // SBB
                     INST_NAME("SBB Eb, Ib");
                     grab_segdata(dyn, addr, ninst, x1, seg);
diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c
index bfe64ef1..d720b4cf 100644
--- a/src/dynarec/la64/dynarec_la64_66.c
+++ b/src/dynarec/la64/dynarec_la64_66.c
@@ -119,6 +119,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x11:
+            INST_NAME("ADC Ew, Gw");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGW(x2);
+            GETEW(x1, 0);
+            emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
+            EWBACK;
+            break;
+        case 0x13:
+            INST_NAME("ADC Gw, Ew");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGW(x1);
+            GETEW(x2, 0);
+            emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
+            GWBACK;
+            break;
+        case 0x15:
+            INST_NAME("ADC AX, Iw");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            u64 = F16;
+            BSTRPICK_D(x1, xRAX, 15, 0);
+            MOV64x(x2, u64);
+            emit_adc16(dyn, ninst, x1, x2, x3, x4, x5);
+            BSTRINSz(xRAX, x1, 15, 0);
+            break;
         case 0x19:
             INST_NAME("SBB Ew, Gw");
             READFLAGS(X_CF);
@@ -295,6 +325,23 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_or16(dyn, ninst, x1, x5, x2, x4);
                     EWBACK;
                     break;
+                case 2: // ADC
+                    if (opcode == 0x81) {
+                        INST_NAME("ADC Ew, Iw");
+                    } else {
+                        INST_NAME("ADC Ew, Ib");
+                    }
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEW(x1, (opcode == 0x81) ? 2 : 1);
+                    if (opcode == 0x81)
+                        u64 = F16;
+                    else
+                        u64 = (uint16_t)(int16_t)F8S;
+                    MOV64x(x5, u64);
+                    emit_adc16(dyn, ninst, x1, x5, x2, x4, x6);
+                    EWBACK;
+                    break;
                 case 4: // AND
                     if (opcode == 0x81) {
                         INST_NAME("AND Ew, Iw");
diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c
index aa8f6a13..56c38b8d 100644
--- a/src/dynarec/la64/dynarec_la64_emit_math.c
+++ b/src/dynarec/la64/dynarec_la64_emit_math.c
@@ -1029,6 +1029,165 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
 }
 
+// emit ADC8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    IFX (X_PEND) {
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        ST_H(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s3, d_adc8);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        ADC_B(s3, s1, s2);
+
+        IFX (X_ALL) {
+            X64_ADC_B(s1, s2);
+        }
+        MV(s1, s3);
+        IFX (X_PEND) {
+            ST_W(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    IFX (X_AF | X_OF) {
+        OR(s4, s1, s2);  // s4 = op1 | op2
+        AND(s5, s1, s2); // s5 = op1 & op2
+    }
+
+    ADD_D(s1, s1, s2);
+    ANDI(s3, xFlags, 1 << F_CF);
+    ADD_D(s1, s1, s3);
+
+    CLEAR_FLAGS(s3);
+    IFX (X_PEND) {
+        ST_W(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX (X_AF | X_OF) {
+        ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
+        OR(s3, s3, s5);   // cc = (~res & (op1 | op2)) | (op1 & op2)
+        IFX (X_AF) {
+            ANDI(s4, s3, 0x08); // AF: cc & 0x08
+            BEQZ(s4, 8);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX (X_OF) {
+            SRLI_D(s3, s3, 6);
+            SRLI_D(s4, s3, 1);
+            XOR(s3, s3, s4);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 8);
+            ORI(xFlags, xFlags, 1 << F_OF);
+        }
+    }
+    IFX (X_CF) {
+        SRLI_D(s3, s1, 8);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_CF);
+    }
+
+    ANDI(s1, s1, 0xff);
+
+    IFX (X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX (X_SF) {
+        SRLI_D(s3, s1, 7);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX (X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
+// emit ADC8 instruction, from s1, const c, store result in s1 using s3, s4, s5 and s6 as scratch
+void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6)
+{
+    MOV32w(s5, c & 0xff);
+    emit_adc8(dyn, ninst, s1, s5, s3, s4, s6);
+}
+
+// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    IFX (X_PEND) {
+        ST_H(s1, xEmu, offsetof(x64emu_t, op1));
+        ST_H(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s3, d_adc16);
+    } else IFX (X_ALL) {
+        SET_DFNONE();
+    }
+
+    if (la64_lbt) {
+        ADC_H(s3, s1, s2);
+
+        IFX (X_ALL) {
+            X64_ADC_H(s1, s2);
+        }
+        MV(s1, s3);
+        IFX (X_PEND) {
+            ST_W(s1, xEmu, offsetof(x64emu_t, res));
+        }
+        return;
+    }
+
+    IFX (X_AF | X_OF) {
+        OR(s4, s1, s2);  // s4 = op1 | op2
+        AND(s5, s1, s2); // s5 = op1 & op2
+    }
+
+    ADD_D(s1, s1, s2);
+    ANDI(s3, xFlags, 1 << F_CF);
+    ADD_D(s1, s1, s3);
+
+    CLEAR_FLAGS(s3);
+    IFX (X_PEND) {
+        ST_W(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX (X_AF | X_OF) {
+        ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
+        OR(s3, s3, s5);   // cc = (~res & (op1 | op2)) | (op1 & op2)
+        IFX (X_AF) {
+            ANDI(s4, s3, 0x08); // AF: cc & 0x08
+            BEQZ(s4, 8);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX (X_OF) {
+            SRLI_D(s3, s3, 14);
+            SRLI_D(s4, s3, 1);
+            XOR(s3, s3, s4);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 8);
+            ORI(xFlags, xFlags, 1 << F_OF);
+        }
+    }
+    IFX (X_CF) {
+        SRLI_D(s3, s1, 16);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_CF);
+    }
+
+    BSTRPICK_D(s1, s1, 15, 0);
+
+    IFX (X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX (X_SF) {
+        SRLI_D(s3, s1, 15);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX (X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
 // emit ADC32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
 void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
 {
diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c
index 22457c0d..c92e9406 100644
--- a/src/dynarec/la64/dynarec_la64_f0.c
+++ b/src/dynarec/la64/dynarec_la64_f0.c
@@ -402,6 +402,31 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     DEFAULT;
             }
             break;
+        case 0x11:
+            INST_NAME("LOCK ADC Ed, Gd");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGD;
+            SMDMB();
+            if (MODREG) {
+                ed = xRAX + (nextop & 7) + (rex.b << 3);
+                emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
+            } else {
+                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                MARKLOCK;
+                LLxw(x1, wback, 0);
+                ADDxw(x3, x1, gd);
+                ANDI(x4, xFlags, 1 << F_CF);
+                ADDxw(x3, x3, x4);
+                SCxw(x3, wback, 0);
+                BEQZ_MARKLOCK(x3);
+                IFX (X_ALL | X_PEND) {
+                    emit_adc32(dyn, ninst, rex, x1, gd, x3, x4, x5, x6);
+                }
+            }
+            SMDMB();
+            break;
         case 0x29:
             INST_NAME("LOCK SUB Ed, Gd");
             SETFLAGS(X_ALL, SF_SET_PENDING);
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index b6069c61..12ebe679 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -801,6 +801,9 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_add8c          STEPNAME(emit_add8c)
 #define emit_add16          STEPNAME(emit_add16)
 #define emit_adc32          STEPNAME(emit_adc32)
+#define emit_adc8           STEPNAME(emit_adc8)
+#define emit_adc8c          STEPNAME(emit_adc8c)
+#define emit_adc16          STEPNAME(emit_adc16)
 #define emit_sub16          STEPNAME(emit_sub16)
 #define emit_sub32          STEPNAME(emit_sub32)
 #define emit_sub32c         STEPNAME(emit_sub32c)
@@ -903,6 +906,9 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4);
 void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6);
+void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
+void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6);
+void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_sub16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 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);