about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-12-02 15:16:51 +0100
committerptitSeb <sebastien.chev@gmail.com>2023-12-02 15:16:51 +0100
commit76eb623de6d6db256c38aab066560991c45bdfcf (patch)
treec17133bb23efce5546e28a9e80aa20d93c7cee63
parent9e45c053838ae15a9fadb6ed413867465cb54ef8 (diff)
downloadbox64-76eb623de6d6db256c38aab066560991c45bdfcf.tar.gz
box64-76eb623de6d6db256c38aab066560991c45bdfcf.zip
[ARM64_DYNAREC] Generalized the use of Flag Manipulation Extension (if present)
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_logic.c60
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_math.c175
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_shift.c176
-rw-r--r--src/dynarec/arm64/dynarec_arm64_emit_tests.c50
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h26
5 files changed, 84 insertions, 403 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_emit_logic.c b/src/dynarec/arm64/dynarec_arm64_emit_logic.c
index e8af51f5..fb3f4545 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_logic.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_logic.c
@@ -230,15 +230,7 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        TSTw_REG(s1, s1);
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -261,15 +253,7 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        TSTw_REG(s1, s1);
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -292,15 +276,7 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        TSTw_REG(s1, s1);
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -323,15 +299,7 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        TSTw_REG(s1, s1);
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -423,15 +391,7 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -500,15 +460,7 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
diff --git a/src/dynarec/arm64/dynarec_arm64_emit_math.c b/src/dynarec/arm64/dynarec_arm64_emit_math.c
index b8215ef2..1248ef63 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_math.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_math.c
@@ -278,38 +278,22 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     } else IFX(X_ALL) {
         SET_DFNONE(s3);
     }
-    if(arm64_flagm && 0) {
-        IFX(X_AF) {
-            ORRw_REG(s3, s1, s2);    // s3 = op1 | op2
-            ANDw_REG(s4, s1, s2);    // s4 = op1 & op2
-        }
-    } else {
-        IFX(X_AF | X_OF) {
-            ORRw_REG(s3, s1, s2);    // s3 = op1 | op2
-            ANDw_REG(s4, s1, s2);    // s4 = op1 & op2
-        }
+    IFX(X_AF | X_OF) {
+        ORRw_REG(s3, s1, s2);    // s3 = op1 | op2
+        ANDw_REG(s4, s1, s2);    // s4 = op1 & op2
     }
     ADDw_REG(s1, s1, s2);
-    if(arm64_flagm && 0) { // disable O flag there, it needs singned 8bits values
+    IFX(X_AF|X_OF) {
+        BICw_REG(s3, s3, s1);   // s3 = (op1 | op2) & ~ res
+        ORRw_REG(s3, s3, s4);   // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
         IFX(X_AF) {
-            BICw_REG(s3, s3, s1);   // s3 = (op1 | op2) & ~ res
-            ORRw_REG(s3, s3, s4);   // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
             LSRw(s4, s3, 3);
             BFIw(xFlags, s4, F_AF, 1);    // AF: bc & 0x08
         }
-    } else {
-        IFX(X_AF|X_OF) {
-            BICw_REG(s3, s3, s1);   // s3 = (op1 | op2) & ~ res
-            ORRw_REG(s3, s3, s4);   // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
-            IFX(X_AF) {
-                LSRw(s4, s3, 3);
-                BFIw(xFlags, s4, F_AF, 1);    // AF: bc & 0x08
-            }
-            IFX(X_OF) {
-                LSRw(s4, s3, 6);
-                EORw_REG_LSR(s4, s4, s4, 1);
-                BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
-            }
+        IFX(X_OF) {
+            LSRw(s4, s3, 6);
+            EORw_REG_LSR(s4, s4, s4, 1);
+            BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
         }
     }
     IFX(X_CF) {
@@ -319,33 +303,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    if(arm64_flagm) {
-        IFX(X_ZF|X_SF/*|X_OF*/) {
-            SETF8(s1);
-        }
-        IFX(X_ZF) {
-            CSETw(s3, cEQ);
-            BFIw(xFlags, s3, F_ZF, 1);
-        }
-        IFX(X_SF) {
-            CSETw(s3, cMI);
-            BFIw(xFlags, s3, F_SF, 1);
-        }
-        /*IFX(X_OF) {
-            CSETw(s3, cVS);
-            BFIw(xFlags, s3, F_OF, 1);
-        }*/
-    } else {
-        IFX(X_ZF) {
-            ANDSw_mask(s1, s1, 0, 7);   //mask=0xff
-            CSETw(s3, cEQ);
-            BFIw(xFlags, s3, F_ZF, 1);
-        }
-        IFX(X_SF) {
-            LSRw(s3, s1, 7);
-            BFIw(xFlags, s3, F_SF, 1);
-        }
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -389,15 +347,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 0b000111);    //mask=000000ff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -441,15 +391,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 7);   //mask=0xff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -499,15 +441,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 0b000111);    //mask=000000ff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -550,15 +484,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -668,15 +594,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -826,16 +744,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
         }
     }
-
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 7);   //mask=0xff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -872,15 +781,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 0b001111); // mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -1196,15 +1097,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         LSRw(s3, s1, 8);
         BFIw(xFlags, s3, F_CF, 1);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 7);   //mask=0xff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -1258,15 +1151,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         LSRw(s3, s1, 16);
         BFIw(xFlags, s3, F_CF, 1);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);   //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -1508,15 +1393,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 7);   //mask=0xff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -1571,15 +1448,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
             BFIw(xFlags, s4, F_OF, 1);    // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
         }
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 15);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
diff --git a/src/dynarec/arm64/dynarec_arm64_emit_shift.c b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
index cc583c45..778583b4 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_shift.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_shift.c
@@ -286,19 +286,11 @@ void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 7);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 7);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_OF) {
         CMPSw_U12(s2, 1);   // if s2==1
-            IFX(X_SF) {} else {LSRw(s4, s1, 7);}
-            EORw_REG(s4, s4, xFlags);  // CF is set if OF is asked
+            IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
+            EORw_REG(s4, s3, xFlags);  // CF is set if OF is asked
             CSELw(s4, s4, wZR, cEQ);
             BFIw(xFlags, s4, F_OF, 1);
     }
@@ -329,19 +321,11 @@ void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
         IFX(X_PEND) {
             STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
         }
-        IFX(X_ZF) {
-            TSTw_mask(s1, 0, 7);
-            CSETw(s4, cEQ);
-            BFIw(xFlags, s4, F_ZF, 1);
-        }
-        IFX(X_SF) {
-            LSRw(s4, s1, 7);
-            BFIw(xFlags, s4, F_SF, 1);
-        }
+        COMP_ZFSF(s1, 8)
         IFX(X_OF) {
             if(c==1) {
-                IFX(X_SF) {} else {LSRw(s4, s1, 7);}
-                EORw_REG(s4, s4, xFlags);  // CF is set if OF is asked
+                IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
+                EORw_REG(s4, s3, xFlags);  // CF is set if OF is asked
                 BFIw(xFlags, s4, F_OF, 1);
             } else {
                 BFCw(xFlags, F_OF, 1);
@@ -403,15 +387,7 @@ void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 7);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 7);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -448,15 +424,7 @@ void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
     IFX(X_PEND) {
         STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 7);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 7);
-        BFIx(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -481,15 +449,7 @@ void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 7);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 7);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_OF) {
         CMPSw_U12(s2, 1);
         Bcond(cNE, 4+4);
@@ -521,15 +481,7 @@ void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
     IFX(X_PEND) {
         STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 7);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 7);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_OF)
         if(c==1) {
             BFCw(xFlags, F_OF, 1);
@@ -559,19 +511,11 @@ void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         CMPSw_U12(s2, 1);   // if s2==1
-            IFX(X_SF) {} else {LSRw(s4, s1, 15);}
-            EORw_REG(s4, s4, xFlags);  // CF is set if OF is asked
+            IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
+            EORw_REG(s4, s3, xFlags);  // CF is set if OF is asked
             CSELw(s4, s4, wZR, cEQ);
             BFIw(xFlags, s4, F_OF, 1);
     }
@@ -603,19 +547,11 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
         IFX(X_PEND) {
             STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
         }
-        IFX(X_ZF) {
-            TSTw_mask(s1, 0, 15);
-            CSETw(s4, cEQ);
-            BFIw(xFlags, s4, F_ZF, 1);
-        }
-        IFX(X_SF) {
-            LSRw(s4, s1, 15);
-            BFIw(xFlags, s4, F_SF, 1);
-        }
+        COMP_ZFSF(s1, 16)
         IFX(X_OF) {
             if(c==1) {
-                IFX(X_SF) {} else {LSRw(s4, s1, 15);}
-                EORw_REG(s4, s4, xFlags);  // CF is set if OF is asked
+                IFX(X_SF && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
+                EORw_REG(s4, s3, xFlags);  // CF is set if OF is asked
                 BFIw(xFlags, s4, F_OF, 1);
             } else {
                 BFCw(xFlags, F_OF, 1);
@@ -673,15 +609,7 @@ void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -718,15 +646,7 @@ void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIx(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -751,15 +671,7 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         CMPSw_U12(s2, 1);
         Bcond(cNE, 4+4);
@@ -791,15 +703,7 @@ void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF)
         if(c==1) {
             BFCw(xFlags, F_OF, 1);
@@ -1233,15 +1137,7 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15); // 0xffff
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         if(c==1) {
             LSRw(s4, s1, 15);
@@ -1279,15 +1175,7 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);   // 0xffff
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         CMPSw_U12(s5, 1);
         Bcond(cNE, 4+3*4);
@@ -1334,15 +1222,7 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);   // 0xffff
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         if(c==1) {
             LSRw(s3, s1, 15);
@@ -1384,15 +1264,7 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
     IFX(X_PEND) {
         STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        TSTw_mask(s1, 0, 15);   // 0xffff
-        CSETw(s4, cEQ);
-        BFIw(xFlags, s4, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_OF) {
         CMPSw_U12(s5, 1);
         Bcond(cNE, 4+3*4);
diff --git a/src/dynarec/arm64/dynarec_arm64_emit_tests.c b/src/dynarec/arm64/dynarec_arm64_emit_tests.c
index bf190586..5c6c602f 100644
--- a/src/dynarec/arm64/dynarec_arm64_emit_tests.c
+++ b/src/dynarec/arm64/dynarec_arm64_emit_tests.c
@@ -111,22 +111,11 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
     } else {
         SET_DFNONE(s3);
     }
-    IFX(X_ZF) {
-        SUBSw_REG(s5, s1, s2);   // res = s1 - s2
-    } else {
-        SUBw_REG(s5, s1, s2);   // res = s1 - s2
-    }
+    SUBw_REG(s5, s1, s2);   // res = s1 - s2
     IFX_PENDOR0 {
         STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s5, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s5, 16)
     // bc = (res & (~d | s)) | (~d & s)
     IFX(X_CF|X_AF|X_OF) {
         MVNw_REG(s4, s1);        // s4 = ~d
@@ -170,15 +159,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 15);  //mask=0xffff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s4, s1, 15);
-        BFIw(xFlags, s4, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 16)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
@@ -194,22 +175,11 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
     } else {
         SET_DFNONE(s4);
     }
-    IFX(X_ZF) {
-        SUBSw_REG(s5, s1, s2);   // res = s1 - s2
-    } else {
-        SUBw_REG(s5, s1, s2);   // res = s1 - s2
-    }
+    SUBw_REG(s5, s1, s2);   // res = s1 - s2
     IFX_PENDOR0 {
         STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
     }
-    IFX(X_ZF) {
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s5, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s5, 8)
     // bc = (res & (~d | s)) | (~d & s)
     IFX(X_CF|X_AF|X_OF) {
         ORNw_REG(s4, s2, s1);   // s4 = ~d | s
@@ -251,15 +221,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
         MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
         BICw(xFlags, xFlags, s3);
     }
-    IFX(X_ZF) {
-        ANDSw_mask(s1, s1, 0, 0b000111);    //mask=000000ff
-        CSETw(s3, cEQ);
-        BFIw(xFlags, s3, F_ZF, 1);
-    }
-    IFX(X_SF) {
-        LSRw(s3, s1, 7);
-        BFIw(xFlags, s3, F_SF, 1);
-    }
+    COMP_ZFSF(s1, 8)
     IFX(X_PF) {
         emit_pf(dyn, ninst, s1, s3, s4);
     }
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index c8320b57..b511457d 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1465,4 +1465,30 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
             opcode = F8;                        \
         }
 
+#define COMP_ZFSF(s1, A)                        \
+    IFX(X_ZF|X_SF) {                            \
+        if(arm64_flagm) {                       \
+            SETF##A(s1);                        \
+            IFX(X_ZF) {                         \
+                CSETw(s3, cEQ);                 \
+                BFIw(xFlags, s3, F_ZF, 1);      \
+            }                                   \
+            IFX(X_SF) {                         \
+                CSETw(s3, cMI);                 \
+                BFIw(xFlags, s3, F_SF, 1);      \
+            }                                   \
+        } else {                                \
+            IFX(X_ZF) {                         \
+                ANDSw_mask(s1, s1, 0, (A)-1);   \
+                CSETw(s3, cEQ);                 \
+                BFIw(xFlags, s3, F_ZF, 1);      \
+            }                                   \
+            IFX(X_SF) {                         \
+                LSRw(s3, s1, (A)-1);            \
+                BFIw(xFlags, s3, F_SF, 1);      \
+            }                                   \
+        }                                       \
+    }
+
+
 #endif //__DYNAREC_ARM64_HELPER_H__