about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_0.c9
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_1.c3
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_2.c33
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c18
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c56
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_shift.c50
-rw-r--r--src/dynarec/rv64/dynarec_rv64_f0.c44
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c34
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h6
9 files changed, 244 insertions, 9 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00_0.c b/src/dynarec/rv64/dynarec_rv64_00_0.c
index db9e7cf5..6cf6a342 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_0.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_0.c
@@ -202,6 +202,15 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5);
             WBACK;
             break;
+        case 0x1B:
+            INST_NAME("SBB Gd, Ed");
+            READFLAGS(X_CF);
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGD;
+            GETED(0);
+            emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4, x5);
+            break;
         case 0x1C:
             INST_NAME("SBB AL, Ib");
             READFLAGS(X_CF);
diff --git a/src/dynarec/rv64/dynarec_rv64_00_1.c b/src/dynarec/rv64/dynarec_rv64_00_1.c
index ee1e554f..3abb0444 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_1.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_1.c
@@ -108,6 +108,9 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
         case 0x64:
             addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
             break;
+        case 0x65:
+            addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _GS, ok, need_epilog);
+            break;
         case 0x66:
             addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
             break;
diff --git a/src/dynarec/rv64/dynarec_rv64_00_2.c b/src/dynarec/rv64/dynarec_rv64_00_2.c
index 4a6e6827..6f0ef03e 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_2.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_2.c
@@ -403,7 +403,38 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 }
             }
             break;
-
+        case 0x8E:
+            INST_NAME("MOV Seg,Ew");
+            nextop = F8;
+            if((nextop&0xC0)==0xC0) {
+                ed = xRAX+(nextop&7)+(rex.b<<3);
+            } else {
+                SMREAD();
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
+                LHU(x1, ed, fixedaddress);
+                ed = x1;
+            }
+            SW(ed, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
+            SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[(nextop&0x38)>>3]));
+            break;
+        case 0x8F:
+            INST_NAME("POP Ed");
+            nextop = F8;
+            if(MODREG) {
+                POP1(xRAX+(nextop&7)+(rex.b<<3));
+            } else {
+                POP1(x2); // so this can handle POP [ESP] and maybe some variant too
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
+                if(ed==xRSP) {
+                    SD(x2, ed, fixedaddress);
+                } else {
+                    // complicated to just allow a segfault that can be recovered correctly
+                    SUB(xRSP, xRSP, 8);
+                    SD(x2, ed, fixedaddress);
+                    ADD(xRSP, xRSP, 8);
+                }
+            }
+            break;
         case 0x90:
         case 0x91:
         case 0x92:
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index a1e7421e..a19f3f68 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -336,6 +336,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 #endif
             }
             break;
+        case 0xCF:
+            INST_NAME("IRET");
+            SETFLAGS(X_ALL, SF_SET);    // Not a hack, EFLAGS are restored
+            BARRIER(BARRIER_FLOAT);
+            iret_to_epilog(dyn, ninst, rex.w);
+            *need_epilog = 0;
+            *ok = 0;
+            break;
         case 0xD0:
         case 0xD2:  // TODO: Jump if CL is 0
             nextop = F8;
@@ -410,7 +418,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     INST_NAME("ROR Ed, 1");
                     SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
                     GETED(0);
-                    emit_rol32c(dyn, ninst, rex, ed, rex.w?63:31, x3, x4);
+                    emit_ror32c(dyn, ninst, rex, ed, 1, x3, x4);
                     WBACK;
                     if(!wback && !rex.w) ZEROUP(ed);
                     break;
@@ -452,6 +460,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     WBACK;
                     if(!wback && !rex.w) ZEROUP(ed);
                     break;
+                case 1:
+                    INST_NAME("ROR Ed, CL");
+                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
+                    GETED(0);
+                    emit_ror32(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/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index 8b4a94f5..320f58a0 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -445,6 +445,37 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             AND(x1, x1, x2);
             OR(xRAX, xRAX, x1);
             break;
+        case 0xA5:
+            if(rep) {
+                INST_NAME("REP MOVSW");
+                CBZ_NEXT(xRCX);
+                ANDI(x1, xFlags, 1<<F_DF);
+                BNEZ_MARK2(x1);
+                MARK;   // Part with DF==0
+                LH(x1, xRSI, 0);
+                ADDI(xRSI, xRSI, 2);
+                SH(x1, xRDI, 0);
+                ADDI(xRDI, xRDI, 2);
+                SUBI(xRCX, xRCX, 1);
+                BNEZ_MARK(xRCX);
+                B_NEXT_nocond;
+                MARK2;  // Part with DF==1
+                LH(x1, xRSI, 0);
+                SUBI(xRSI, xRSI, 2);
+                SH(x1, xRDI, 0);
+                SUBI(xRDI, xRDI, 2);
+                SUBI(xRCX, xRCX, 1);
+                BNEZ_MARK2(xRCX);
+                // done
+            } else {
+                INST_NAME("MOVSD");
+                GETDIR(x3, x1, 2);
+                LH(x1, xRSI, 0);
+                SH(x1, xRDI, 0);
+                ADD(xRSI, xRSI, x3);
+                ADD(xRDI, xRDI, x3);
+            }
+            break;
         case 0xA9:
             INST_NAME("TEST AX,Iw");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -454,6 +485,31 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             SRLIW(x1, x1, 16);
             emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
             break;
+        case 0xAB:
+            if(rep) {
+                INST_NAME("REP STOSW");
+                CBZ_NEXT(xRCX);
+                ANDI(x1, xFlags, 1<<F_DF);
+                BNEZ_MARK2(x1);
+                MARK;   // Part with DF==0
+                SH(xRAX, xRDI, 0);
+                ADDI(xRDI, xRDI, 2);
+                SUBI(xRCX, xRCX, 1);
+                BNEZ_MARK(xRCX);
+                B_NEXT_nocond;
+                MARK2;  // Part with DF==1
+                SH(xRAX, xRDI, 0);
+                SUBI(xRDI, xRDI, 2);
+                SUBI(xRCX, xRCX, 1);
+                BNEZ_MARK2(xRCX);
+                // done
+            } else {
+                INST_NAME("STOSW");
+                GETDIR(x3, x1, 2);
+                SH(xRAX, xRDI, 0);
+                ADD(xRDI, xRDI, x3);
+            }
+            break;
         case 0xB8:
         case 0xB9:
         case 0xBA:
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_shift.c b/src/dynarec/rv64/dynarec_rv64_emit_shift.c
index be84894c..dbcc2d5f 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_shift.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_shift.c
@@ -307,7 +307,6 @@ void emit_sar32c(dynarec_rv64_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_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
 {
@@ -337,8 +336,7 @@ void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
         SDxw(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_CF) {
-        // F_CF=0
-        ANDI(s4, s1, 1);
+        ANDI(s4, s1, 1<<F_CF);
         OR(xFlags, xFlags, s4);
     }
     IFX(X_OF) {
@@ -352,6 +350,49 @@ void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
 }
 
+// emit ROR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
+{
+    int64_t j64;
+    IFX(X_CF | X_OF) {
+        ANDI(xFlags, xFlags, ~(1UL<<F_CF | 1UL<<F_OF2));
+    }
+
+    IFX(X_PEND) {
+        SDxw(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s4, rex.w?d_ror64:d_ror32);
+    } else IFX(X_ALL) {
+        SET_DFNONE();
+    }
+
+    if(rex.w) {
+        ANDI(s4, s2, 0x3f);
+    } else {
+        ANDI(s4, s2, 0x1f);
+    }
+    SRLxw(s3, s1, s4);
+    NEG(s4, s4);
+    ADDI(s4, s4, rex.w?64:32);
+    SLLxw(s1, s1, s4);
+    OR(s1, s3, s1);
+    IFX(X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_CF) {
+        SRLI(s3, s1, rex.w?63:31);
+        AND(xFlags, xFlags, s3);
+    }
+    IFX(X_OF) {
+        ADDI(s3, xZR, 1);
+        BEQ_NEXT(s2, s3);
+        SRLIxw(s3, s1, rex.w?63:31);
+        XOR(s3, s3, s1);
+        ANDI(s3, s3, 1);
+        SLLI(s3, s3, F_OF2);
+        OR(xFlags, xFlags, s3);
+    }
+}
+
 // emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
 void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
 {
@@ -379,8 +420,7 @@ void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
         SDxw(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_CF) {
-        // F_CF=0
-        ANDI(s4, s1, 1);
+        ANDI(s4, s1, 1<<F_CF);
         OR(xFlags, xFlags, s4);
     }
     IFX(X_OF) {
diff --git a/src/dynarec/rv64/dynarec_rv64_f0.c b/src/dynarec/rv64/dynarec_rv64_f0.c
index f5ae3950..6b230a55 100644
--- a/src/dynarec/rv64/dynarec_rv64_f0.c
+++ b/src/dynarec/rv64/dynarec_rv64_f0.c
@@ -323,6 +323,50 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             }
             SMDMB();
             break;
+        case 0xFF:
+            nextop = F8;
+            switch((nextop>>3)&7)
+            {
+                case 0: // INC Ed
+                    INST_NAME("LOCK INC Ed");
+                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
+                    SMDMB();
+                    if(MODREG) {
+                        ed = xRAX+(nextop&7)+(rex.b<<3);
+                        emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6);
+                    } else {
+                        addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                        MARKLOCK;
+                        LRxw(x1, wback, 1, 1);
+                        ADDIxw(x4, x1, 1);
+                        SCxw(x3, x4, wback, 1, 1);
+                        BNEZ_MARKLOCK(x3);
+                        IFX(X_ALL|X_PEND)
+                            emit_inc32(dyn, ninst, rex, x1, x3, x4, x5, x6);
+                    }
+                    break;
+                case 1: // DEC Ed
+                    INST_NAME("LOCK DEC Ed");
+                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
+                    SMDMB();
+                    if(MODREG) {
+                        ed = xRAX+(nextop&7)+(rex.b<<3);
+                        emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6);
+                    } else {
+                        addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
+                        MARKLOCK;
+                        LRxw(x1, wback, 1, 1);
+                        ADDIxw(x4, x1, -1);
+                        SCxw(x3, x4, wback, 1, 1);
+                        BNEZ_MARKLOCK(x3);
+                        IFX(X_ALL|X_PEND)
+                            emit_inc32(dyn, ninst, rex, x1, x3, x4, x5, x6);
+                    }
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index a0f88502..37bcec29 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -383,6 +383,40 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n)
     CLEARIP();
 }
 
+void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits)
+{
+    //#warning TODO: is64bits
+    MAYUSE(ninst);
+    MESSAGE(LOG_DUMP, "IRet to epilog\n");
+    // POP IP
+    NOTEST(x2);
+    POP1(xRIP);
+    // POP CS
+    POP1(x2);
+    SH(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
+    MV(x1, xZR);
+    SD(x1, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
+    SD(x1, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
+    // POP EFLAGS
+    POP1(xFlags);
+    MOV32w(x1, 0x3F7FD7);
+    AND(xFlags, xFlags, x1);
+    ORI(xFlags, xFlags, 0x2);
+    SET_DFNONE();
+    // POP RSP
+    POP1(x3);
+    // POP SS
+    POP1(x2);
+    SH(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
+    // set new RSP
+    MV(xRSP, x3);
+    // Ret....
+    MOV64x(x2, (uintptr_t)rv64_epilog);  // epilog on purpose, CS might have changed!
+    SMEND();
+    BR(x2);
+    CLEARIP();
+}
+
 void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
 {
     MAYUSE(fnc);
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 189fa7bc..b3675745 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -836,7 +836,8 @@ void* rv64_next(x64emu_t* emu, uintptr_t addr);
 #define emit_shr32      STEPNAME(emit_shr32)
 #define emit_shr32c     STEPNAME(emit_shr32c)
 #define emit_sar32c     STEPNAME(emit_sar32c)
-#define emit_rol32     STEPNAME(emit_rol32)
+#define emit_rol32      STEPNAME(emit_rol32)
+#define emit_ror32      STEPNAME(emit_ror32)
 #define emit_rol32c     STEPNAME(emit_rol32c)
 #define emit_ror32c     STEPNAME(emit_ror32c)
 #define emit_shrd32c    STEPNAME(emit_shrd32c)
@@ -899,7 +900,7 @@ void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void ret_to_epilog(dynarec_rv64_t* dyn, int ninst);
 void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n);
-//void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits);
+void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits);
 void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w);
 void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
@@ -970,6 +971,7 @@ void emit_shr32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
 void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
+void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
 void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_ror32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
 void emit_shrd32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);