about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-03-20 10:20:51 +0100
committerptitSeb <sebastien.chev@gmail.com>2021-03-20 10:20:51 +0100
commita68be9117b1d8cc78e9e6ceea5f8236f074983c9 (patch)
tree551bf8753513ced2f153ed5de0e143eaef38d63b /src
parentf4fceb53bc3def59d34baec0453d313382c2a58d (diff)
downloadbox64-a68be9117b1d8cc78e9e6ceea5f8236f074983c9.tar.gz
box64-a68be9117b1d8cc78e9e6ceea5f8236f074983c9.zip
[DYNAREC] Added D3 opcodes, and fixed sl32/shl32c/shr32/shr32c emitter
Diffstat (limited to 'src')
-rwxr-xr-xsrc/dynarec/dynarec_arm64_00.c132
-rwxr-xr-xsrc/dynarec/dynarec_arm64_emit_math.c2
-rwxr-xr-xsrc/dynarec/dynarec_arm64_emit_shift.c36
-rwxr-xr-xsrc/dynarec/dynarec_arm64_helper.h8
-rwxr-xr-xsrc/include/regs.h18
5 files changed, 164 insertions, 32 deletions
diff --git a/src/dynarec/dynarec_arm64_00.c b/src/dynarec/dynarec_arm64_00.c
index 0e6613a9..d0bb204c 100755
--- a/src/dynarec/dynarec_arm64_00.c
+++ b/src/dynarec/dynarec_arm64_00.c
@@ -766,6 +766,138 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     break;
             }
             break;
+        case 0xD3:
+            nextop = F8;
+            switch((nextop>>3)&7) {
+                case 0:
+                    INST_NAME("ROL Ed, CL");
+                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
+                    if(rex.w) {
+                        ANDSx_mask(x3, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x3, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    MOV64xw(x4, (rex.w?64:32));
+                    SUBx_REG(x3, x4, x3);
+                    GETEDW(x4, x2, 0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    RORxw_REG(ed, ed, x3);
+                    WBACK;
+                    UFLAG_IF {  // calculate flags directly
+                        CMPSw_U12(x3, rex.w?63:31);
+                        B_MARK(cNE);
+                            LSRxw(x1, ed, rex.w?63:31);
+                            ADDxw_REG(x1, x1, ed);
+                            BFIw(xFlags, x1, F_OF, 1);
+                        MARK;
+                        BFIw(xFlags, ed, F_CF, 1);
+                        UFLAG_DF(x2, d_none);
+                    }
+                    break;
+                case 1:
+                    INST_NAME("ROR Ed, CL");
+                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
+                    if(rex.w) {
+                        ANDSx_mask(x3, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x3, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETEDW(x4, x2, 0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    RORxw_REG(ed, ed, x3);
+                    WBACK;
+                    UFLAG_IF {  // calculate flags directly
+                        CMPSw_U12(x3, 1);
+                        B_MARK(cNE);
+                            LSRxw(x2, ed, rex.w?62:30); // x2 = d>>30
+                            EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
+                            BFIw(xFlags, x2, F_OF, 1);
+                        MARK;
+                        LSRxw(x2, ed, rex.w?63:31);
+                        BFIw(xFlags, x2, F_CF, 1);
+                        UFLAG_DF(x2, d_none);
+                    }
+                    break;
+                case 2:
+                    INST_NAME("RCL Ed, CL");
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
+                    if(rex.w) {
+                        ANDSx_mask(x2, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETEDW(x4, x1, 0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
+                    WBACK;
+                    break;
+                case 3:
+                    INST_NAME("RCR Ed, CL");
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_OF|X_CF, SF_SUBSET);
+                    if(rex.w) {
+                        ANDSx_mask(x2, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x2, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETEDW(x4, x1, 0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
+                    WBACK;
+                    break;
+                case 4:
+                case 6:
+                    INST_NAME("SHL Ed, CL");
+                    SETFLAGS(X_ALL, SF_SET);    // some flags are left undefined
+                    if(rex.w) {
+                        ANDSx_mask(x3, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x3, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETED(0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    emit_shl32(dyn, ninst, rex, ed, x3, x5, x4);
+                    WBACK;
+                    break;
+                case 5:
+                    INST_NAME("SHR Ed, CL");
+                    SETFLAGS(X_ALL, SF_SET);    // some flags are left undefined
+                    if(rex.w) {
+                        ANDSx_mask(x3, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x3, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETED(0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    emit_shr32(dyn, ninst, rex, ed, x3, x5, x4);
+                    WBACK;
+                    break;
+                case 7:
+                    INST_NAME("SAR Ed, CL");
+                    SETFLAGS(X_ALL, SF_PENDING);
+                    if(rex.w) {
+                        ANDSx_mask(x3, xRCX, 1, 0, 0b00101);  //mask=0x000000000000003f
+                    } else {
+                        ANDSw_mask(x3, xRCX, 0, 0b00100);  //mask=0x00000001f
+                    }
+                    GETED(0);
+                    if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
+                    B_NEXT(cEQ);
+                    UFLAG_OP12(ed, x3);
+                    ASRxw_REG(ed, ed, x3);
+                    WBACK;
+                    UFLAG_RES(ed);
+                    UFLAG_DF(x3, rex.w?d_sar64:d_sar32);
+                    break;
+            }
+            break;
         
         case 0xE8:
             INST_NAME("CALL Id");
diff --git a/src/dynarec/dynarec_arm64_emit_math.c b/src/dynarec/dynarec_arm64_emit_math.c
index 34232aba..d3931ccc 100755
--- a/src/dynarec/dynarec_arm64_emit_math.c
+++ b/src/dynarec/dynarec_arm64_emit_math.c
@@ -1567,7 +1567,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
     }
     EORw_mask(s4, xFlags, 0, 0);            // invert CC because it's reverted for SUB on ARM
     MRS_nzvc(s3);
-    BFIx(s3, s4, 0, 1); // set C
+    BFIx(s3, s4, 29, 1); // set C, bit 29
     MSR_nzvc(s3);      // load CC into ARM CF
     IFX(X_AF|X_OF|X_CF) {
         MVNw_REG(s4, s1);
diff --git a/src/dynarec/dynarec_arm64_emit_shift.c b/src/dynarec/dynarec_arm64_emit_shift.c
index fef4b4e5..98ed81f5 100755
--- a/src/dynarec/dynarec_arm64_emit_shift.c
+++ b/src/dynarec/dynarec_arm64_emit_shift.c
@@ -59,7 +59,7 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_ZF) {
-        TSTw_REG(s1, s1);
+        TSTxw_REG(s1, s1);
         BFCx(xFlags, F_ZF, 1);
         Bcond(cNE, +8);
         ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
@@ -69,10 +69,10 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
         BFIx(xFlags, s4, F_SF, 1);
     }
     IFX(X_OF) {
-        CMPSxw_U12(s2, 1);   // if s3==1
+        CMPSxw_U12(s2, 1);   // if s2==1
             IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
+            Bcond(cNE, 4+3*4);
             BFCw(xFlags, F_OF, 1);
-            Bcond(cNE, +12);
             EORxw_REG(s4, s4, xFlags);  // CF is set if OF is asked
             BFIw(xFlags, s4, F_OF, 1);
     }
@@ -111,7 +111,7 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_ZF) {
-        TSTw_REG(s1, s1);
+        TSTxw_REG(s1, s1);
         BFCx(xFlags, F_ZF, 1);
         Bcond(cNE, +8);
         ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
@@ -156,34 +156,34 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
             }
             B_NEXT(cEQ);
     }
+    IFX(X_CF) {
+        SUBxw_U12(s3, s2, 1);
+        LSRxw_REG(s3, s1, s3);
+        BFIw(xFlags, s3, 0, 1);
+    }
     LSRxw_REG(s1, s1, s2);
     IFX(X_PEND) {
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_ZF) {
-        TSTw_REG(s1, s1);
+        TSTxw_REG(s1, s1);
         BFCx(xFlags, F_ZF, 1);
         Bcond(cNE, +8);
         ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
     }
-    IFX(X_CF) {
-        SUBxw_U12(s3, s2, 1);
-        LSRxw_REG(s3, s1, s3);
-        BFIw(xFlags, s3, 0, 1);
-    }
     IFX(X_SF) {
         LSRxw(s4, s1, (rex.w)?63:31);
         BFIx(xFlags, s4, F_SF, 1);
     }
     IFX(X_OF) {
-        CMPSxw_U12(s2, 1);   // if s3==1
+        CMPSxw_U12(s2, 1);   // if s2==1
             Bcond(cNE, 4+3*4);
             if(rex.w) {
                 LSRx(s4, s1, 62);
             } else {
                 LSRw(s4, s1, 30);
             }
-            EORw_mask(s4, s4, 0, 0);  // CF is set if OF is asked
+            EORw_REG_LSR(s4, s4, s4, 1);
             BFIw(xFlags, s4, F_OF, 1);
     }
     IFX(X_PF) {
@@ -208,20 +208,20 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
         }
         return;
     }
+    IFX(X_CF) {
+        LSRxw_REG(s3, s1, c-1);
+        BFIw(xFlags, s3, 0, 1);
+    }
     LSRxw(s1, s1, c);
     IFX(X_PEND) {
         STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_ZF) {
-        TSTw_REG(s1, s1);
+        TSTxw_REG(s1, s1);
         BFCx(xFlags, F_ZF, 1);
         Bcond(cNE, +8);
         ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
     }
-    IFX(X_CF) {
-        LSRxw_REG(s3, s1, c-1);
-        BFIw(xFlags, s3, 0, 1);
-    }
     IFX(X_SF) {
         LSRxw(s4, s1, (rex.w)?63:31);
         BFIx(xFlags, s4, F_SF, 1);
@@ -229,7 +229,7 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, in
     IFX(X_OF) {
         if(c==1) {
             LSRxw(s4, s1, rex.w?62:30);
-            EORw_mask(s4, s4, 0, 0);
+            EORw_REG_LSR(s4, s4, s4, 1);
             BFIw(xFlags, s4, F_OF, 1);
         }
     }
diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h
index 2da9e799..0c08e5c4 100755
--- a/src/dynarec/dynarec_arm64_helper.h
+++ b/src/dynarec/dynarec_arm64_helper.h
@@ -430,10 +430,10 @@
 #ifndef BARRIER_NEXT
 #define BARRIER_NEXT(A)
 #endif
-#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STR_IMM9(A, xEmu, offsetof(x64emu_t, op1));}
-#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STR_IMM9(A, xEmu, offsetof(x64emu_t, op2));}
-#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STR_IMM9(A1, xEmu, offsetof(x64emu_t, op1));STR_IMM9(A2, 0, offsetof(x64emu_t, op2));}
-#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STR_IMM9(A, xEmu, offsetof(x64emu_t, res));}
+#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
+#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
+#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
+#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
 #define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {SET_DF(r, A)}
 #define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x64.need_flags)
 #ifndef DEFAULT
diff --git a/src/include/regs.h b/src/include/regs.h
index 008b61bc..44cc21b8 100755
--- a/src/include/regs.h
+++ b/src/include/regs.h
@@ -159,18 +159,18 @@ typedef struct {
 
 typedef union {
     struct __attribute__ ((__packed__)) {
-        unsigned int _F_CF:1;
+        unsigned int _F_CF:1;		//0x0001
 		unsigned int _F_res1:1;
-        unsigned int _F_PF:1;
+        unsigned int _F_PF:1;		//0x0004
 		unsigned int _F_res2:1;
-        unsigned int _F_AF:1;
+        unsigned int _F_AF:1;		//0x0010
 		unsigned int _F_res3:1;
-        unsigned int _F_ZF:1;
-        unsigned int _F_SF:1;
-        unsigned int _F_TF:1;
-        unsigned int _F_IF:1;
-        unsigned int _F_DF:1;
-        unsigned int _F_OF:1;
+        unsigned int _F_ZF:1;		//0x0040
+        unsigned int _F_SF:1;		//0x0080
+        unsigned int _F_TF:1;		//0x0100
+        unsigned int _F_IF:1;		//0x0200
+        unsigned int _F_DF:1;		//0x0400
+        unsigned int _F_OF:1;		//0x0800
         unsigned int _F_IOPL:2;
         unsigned int _F_NT:1;
         unsigned int _F_dummy:1;