about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-11-16 10:42:40 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-11-16 10:42:40 +0100
commitf7d75ca641ec6de4a35421fe206f8608ee531a20 (patch)
treec7b19d5320c0a5d0d0910d6902e066c8f27de5b9 /src
parent5baa0833865379799136eea5541b62fe4044ed9a (diff)
downloadbox64-f7d75ca641ec6de4a35421fe206f8608ee531a20.tar.gz
box64-f7d75ca641ec6de4a35421fe206f8608ee531a20.zip
[ARM64_DYNAREC] Fixed shrd 32/64bits opcodes
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_shift.c10
-rw-r--r--src/emu/x64run_private.c29
-rw-r--r--src/include/regs.h5
3 files changed, 37 insertions, 7 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_emit_shift.c b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
index e67961b2..7b504321 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_shift.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
@@ -1006,7 +1006,7 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
         STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
         // same flags computation as with shl64/shl32
-        SET_DF(s4, rex.w?d_shl64:d_shl32);
+        SET_DF(s4, rex.w?d_shrd64:d_shrd32);
     } else IFX(X_ALL) {
         SET_DFNONE(s4);
     }
@@ -1025,7 +1025,7 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
             BFIw(xFlags, s4, F_OF, 1);  // store sign for later use
         }
     }
-    EXTRxw(s1, s1, s2, c);
+    EXTRxw(s1, s2, s1, c);
     IFX(X_PEND) {
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
@@ -1111,7 +1111,7 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
         STRxw_U12(s5, xEmu, offsetof(x64emu_t, op2));
         // same flags computation as with shl64/shl32
-        SET_DF(s4, rex.w?d_shl64:d_shl32);
+        SET_DF(s4, rex.w?d_shrd64:d_shrd32);
     } else IFX(X_ALL) {
         SET_DFNONE(s4);
     }
@@ -1139,12 +1139,12 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
     IFX(X_SF) {
         LSRxw(s4, s1, (rex.w)?63:31);
-        BFIx(xFlags, s4, F_SF, 1);
+        BFIw(xFlags, s4, F_SF, 1);
     }
     IFX(X_OF) {
         CMPSw_U12(s5, 1);
         Bcond(cNE, 4+3*4);
-            LSRxw(s4, s1, rex.w?62:30);
+            LSRxw(s4, s1, rex.w?63:31);
             EORw_REG_LSR(s4, s4, xFlags, F_OF); // Set if sign changed
             BFIw(xFlags, s4, F_OF, 1);
     }
diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c
index 1ef14725..f50c32cc 100644
--- a/src/emu/x64run_private.c
+++ b/src/emu/x64run_private.c
@@ -687,10 +687,36 @@ void UpdateFlags(x64emu_t *emu)
                 CONDITIONAL_SET_FLAG(!emu->res.u64, F_ZF);
                 CONDITIONAL_SET_FLAG(emu->res.u64 & 0x8000000000000000LL, F_SF);
                 CONDITIONAL_SET_FLAG(PARITY(emu->res.u64 & 0xff), F_PF);
-            }
                 if (cnt == 1) {
                     CONDITIONAL_SET_FLAG(emu->op1.u64 & 0x8000000000000000LL, F_OF);
                 }
+            }
+            break;
+        case d_shrd32:
+            cnt = emu->op2.u32;
+            if (cnt > 0) {
+                cc = emu->op1.u32 & (1 << (cnt - 1));
+                CONDITIONAL_SET_FLAG(cc, F_CF);
+                CONDITIONAL_SET_FLAG(!emu->res.u32, F_ZF);
+                CONDITIONAL_SET_FLAG(emu->res.u32 & 0x80000000, F_SF);
+                CONDITIONAL_SET_FLAG(PARITY(emu->res.u32 & 0xff), F_PF);
+                if (cnt == 1) {
+                    CONDITIONAL_SET_FLAG((emu->op1.u32 ^ emu->res.u32) & 0x80000000, F_OF);
+                }
+            }
+            break;
+        case d_shrd64:
+            cnt = emu->op2.u64;
+            if (cnt > 0) {
+                cc = emu->op1.u64 & (1LL << (cnt - 1));
+                CONDITIONAL_SET_FLAG(cc, F_CF);
+                CONDITIONAL_SET_FLAG(!emu->res.u64, F_ZF);
+                CONDITIONAL_SET_FLAG(emu->res.u64 & 0x8000000000000000LL, F_SF);
+                CONDITIONAL_SET_FLAG(PARITY(emu->res.u64 & 0xff), F_PF);
+                if (cnt == 1) {
+                    CONDITIONAL_SET_FLAG((emu->op1.u64 ^ emu->res.u64) & 0x8000000000000000LL, F_OF);
+                }
+            }
             break;
         case d_sub8:
             CONDITIONAL_SET_FLAG(emu->res.u8 & 0x80, F_SF);
@@ -975,6 +1001,7 @@ void UpdateFlags(x64emu_t *emu)
         case d_rcr16:
         case d_rcr32:
         case d_rcr64:
+        case d_shrd16:
         case d_unknown:
             printf_log(LOG_NONE, "Box64: %p trying to evaluate Unknown deferred Flags\n", (void*)R_RIP);
             break;
diff --git a/src/include/regs.h b/src/include/regs.h
index 3d1a4984..433b352c 100644
--- a/src/include/regs.h
+++ b/src/include/regs.h
@@ -139,7 +139,10 @@ typedef enum {
 	d_inc16i,
 	d_inc32i,
 	d_inc64i,
-	d_unknown	//95
+	d_shrd16,
+	d_shrd32,
+	d_shrd64,
+	d_unknown	//98
 } deferred_flags_t;
 
 #pragma pack(push, 1)