about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorxctan <xctan@cirno.icu>2023-04-24 23:14:35 +0800
committerGitHub <noreply@github.com>2023-04-24 17:14:35 +0200
commite64c542c6ad12b87c278382d17c118646ec76ae3 (patch)
tree9a11d295197fbaf3b638b43949c556ce83e90bcc /src
parent97ef3cccef04c4c21028fe464a0897871f694e9f (diff)
downloadbox64-e64c542c6ad12b87c278382d17c118646ec76ae3.tar.gz
box64-e64c542c6ad12b87c278382d17c118646ec76ae3.zip
[RV64_DYNAREC] Added more opcodes (#739)
* [RV64_DYNAREC] Added F0 0F C7 CMPXCHG8B/CMPXCHG16B opcode

* [RV64_DYNAREC] Added 66 83 /3 SBB opcode

* [RV64_DYNAREC] Added 66 FF /1 DEC opcode
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c17
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_math.c60
-rw-r--r--src/dynarec/rv64/dynarec_rv64_f0.c61
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h2
4 files changed, 136 insertions, 4 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index acafe265..7bc996e9 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -324,6 +324,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_adc16(dyn, ninst, x1, x5, x2, x4, x6);
                     EWBACK;
                     break;
+                case 3: // SBB
+                    if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEW(x1, (opcode==0x81)?2:1);
+                    if(opcode==0x81) i16 = F16S; else i16 = F8S;
+                    MOV64x(x5, i16);
+                    emit_sbb16(dyn, ninst, x1, x5, x2, x4, x6);
+                    EWBACK;
+                    break;
                 case 4: // AND
                     if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
                     SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -787,6 +797,13 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     emit_inc16(dyn, ninst, x1, x2, x4, x5);
                     EWBACK;
                     break;
+                case 1:
+                    INST_NAME("DEC Ew");
+                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
+                    GETEW(x1, 0);
+                    emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
+                    EWBACK;
+                    break;
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c
index d468e972..01579ea3 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_math.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c
@@ -833,6 +833,61 @@ void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     }
 }
 
+// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
+void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
+{
+    IFX(X_ALL) {
+        ANDI(xFlags, xFlags, ~((1UL<<F_AF) | (1UL<<F_OF2) | (1UL<<F_ZF) | (1UL<<F_SF) | (1UL<<F_PF)));
+    }
+    IFX(X_PEND) {
+        SH(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s3, d_dec16);
+    } else IFX(X_ALL) {
+        SET_DFNONE();
+    }
+    IFX(X_AF | X_OF) {
+        NOT(s5, s1);
+        ORI(s3, s5, 1);      // s3 = ~op1 | op2
+        ANDI(s5, s5, 1);      // s5 = ~op1 & op2
+    }
+
+    ADDIW(s1, s1, -1);
+
+    IFX(X_PEND) {
+        SH(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    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(s3, s3, 14);
+            SRLI(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_OF2);
+        }
+    }
+    SLLIW(s1, s1, 16);
+    IFX(X_SF) {
+        BGE(s1, xZR, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    SRLIW(s1, s1, 16);
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s2);
+    }
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+}
+
 // emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
 void emit_sbb8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
 {
@@ -900,13 +955,12 @@ void emit_sbb16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
     ANDI(s3, xFlags, 1 << F_CF);
     SUBW(s1, s1, s3);
 
+    SLLIW(s1, s1, 16);
     IFX(X_SF) {
         BGE(s1, xZR, 8);
         ORI(xFlags, xFlags, 1 << F_SF);
     }
-
-    SLLI(s1, s1, 48);
-    SRLI(s1, s1, 48);
+    SRLIW(s1, s1, 16);
 
     IFX(X_PEND) {
         SH(s1, xEmu, offsetof(x64emu_t, res));
diff --git a/src/dynarec/rv64/dynarec_rv64_f0.c b/src/dynarec/rv64/dynarec_rv64_f0.c
index 6b230a55..3ccaafa4 100644
--- a/src/dynarec/rv64/dynarec_rv64_f0.c
+++ b/src/dynarec/rv64/dynarec_rv64_f0.c
@@ -174,6 +174,67 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                             DEFAULT;
                     }
                     break;
+
+                case 0xC7:
+                    switch(rep) {
+                        case 0:
+                            if (rex.w) {
+                                INST_NAME("LOCK CMPXCHG16B Gq, Eq");
+                            } else {
+                                INST_NAME("LOCK CMPXCHG8B Gq, Eq");
+                            }
+                            SETFLAGS(X_ZF, SF_SUBSET);
+                            nextop = F8;
+                            addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                            ANDI(xFlags, xFlags, ~(1<<F_ZF));
+                            if (rex.w) {
+                                // there is no atomic move on 16bytes, so faking it
+                                SMDMB();
+                                // MARKLOCK;
+                                LD(x2, wback, 0);
+                                LD(x3, wback, 8);
+                                BNE_MARK(x2, xRAX);
+                                BNE_MARK(x3, xRDX);
+                                SD(xRBX, wback, 0);
+                                SD(xRCX, wback, 8);
+                                ORI(xFlags, xFlags, 1<<F_ZF);
+                                B_MARK3_nocond;
+                                MARK;
+                                MV(xRAX, x2);
+                                MV(xRDX, x3);
+                                MARK3;
+                                SMDMB();
+                            } else {
+                                SMDMB();
+                                MARKLOCK;
+                                LR_D(x2, wback, 1, 1);
+                                AND(x3, x2, xMASK);
+                                AND(x4, xRAX, xMASK);
+                                SRLI(x5, x2, 32);
+                                AND(x6, xRDX, xMASK);
+                                BNE_MARK(x3, x4); // EAX != Ed[0]
+                                BNE_MARK(x5, x6); // EDX != Ed[1]
+                                SLLI(x2, xRCX, 32);
+                                AND(x3, xRBX, xMASK);
+                                OR(x2, x2, x3);
+                                SC_D(x3, x2, wback, 1, 1);
+                                BNEZ_MARKLOCK(x3);
+                                ORI(xFlags, xFlags, 1<<F_ZF);
+                                B_MARK3_nocond;
+                                MARK;
+                                ADDI(xRAX, x3, 0);
+                                ADDI(xRDX, x5, 0);
+                                AND(xRAX, xRAX, xMASK);
+                                AND(xRDX, xRDX, xMASK);
+                                MARK3;
+                                SMDMB();
+                            }
+                            break;
+                        default:
+                            DEFAULT;
+                    }
+                    break;
+
                 default:
                     DEFAULT;
             }
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 7fb1cdc9..b12ee96b 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -948,7 +948,7 @@ void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_inc8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
-//void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
+void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_dec8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_adc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 //void emit_adc32c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);