about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorxctan <xctan@cirno.icu>2024-08-08 14:25:05 +0800
committerGitHub <noreply@github.com>2024-08-08 08:25:05 +0200
commit18954abf54c75ab19a93cb51f79d67cd33a93d5a (patch)
tree4e0e1092b0ed81a62c24d3a2a9bb6a1f252a84df /src
parented7ee12e7ec6d965ceef6a47dca7b92e726218d5 (diff)
downloadbox64-18954abf54c75ab19a93cb51f79d67cd33a93d5a.tar.gz
box64-18954abf54c75ab19a93cb51f79d67cd33a93d5a.zip
[RV64_DYNAREC] Fixed flag generation in IMUL/MUL opcode (#1715)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c42
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c2
-rw-r--r--src/dynarec/rv64/dynarec_rv64_660f.c2
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h5
4 files changed, 39 insertions, 12 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index 60654a78..ada7e6d0 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -1028,7 +1028,6 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 case 4:
                     INST_NAME("MUL AL, Ed");
                     SETFLAGS(X_ALL, SF_PENDING);
-                    UFLAG_DF(x1, d_mul8);
                     GETEB(x1, 0);
                     ANDI(x2, xRAX, 0xff);
                     MULW(x1, x2, x1);
@@ -1037,11 +1036,11 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     AND(xRAX, xRAX, x2);
                     ZEXTH(x1, x1);
                     OR(xRAX, xRAX, x1);
+                    UFLAG_DF(x1, d_mul8);
                     break;
                 case 5:
                     INST_NAME("IMUL AL, Eb");
                     SETFLAGS(X_ALL, SF_PENDING);
-                    UFLAG_DF(x1, d_imul8);
                     GETSEB(x1, 0);
                     SLLI(x2, xRAX, 56);
                     SRAI(x2, x2, 56);
@@ -1051,6 +1050,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     AND(xRAX, xRAX, x2);
                     ZEXTH(x1, x1);
                     OR(xRAX, xRAX, x1);
+                    UFLAG_DF(x1, d_imul8);
                     break;
                 case 6:
                     INST_NAME("DIV Eb");
@@ -1097,8 +1097,9 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     break;
                 case 4:
                     INST_NAME("MUL EAX, Ed");
-                    SETFLAGS(X_ALL, SF_PENDING);
-                    UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
+                    SETFLAGS(X_ALL, SF_SET);
+                    CLEAR_FLAGS();
+                    SET_DFNONE();
                     GETED(0);
                     if(rex.w) {
                         if(ed==xRDX) gd=x3; else gd=xRDX;
@@ -1115,13 +1116,23 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                         AND(xRAX, xRDX, xMASK);
                         SRLI(xRDX, xRDX, 32);
                     }
-                    UFLAG_RES(xRAX);
-                    UFLAG_OP1(xRDX);
+                    IFX (X_CF | X_OF) {
+                        // CF = OF = RDX != 0
+                        SNEZ(x6, xRDX);
+                        IFX (X_CF) {
+                            OR(xFlags, xFlags, x6); // F_CF == 0
+                        }
+                        IFX (X_OF) {
+                            SLLI(x6, x6, F_OF2);
+                            OR(xFlags, xFlags, x6);
+                        }
+                    }
                     break;
                 case 5:
                     INST_NAME("IMUL EAX, Ed");
-                    SETFLAGS(X_ALL, SF_PENDING);
-                    UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
+                    SETFLAGS(X_ALL, SF_SET);
+                    CLEAR_FLAGS();
+                    SET_DFNONE();
                     GETSED(0);
                     if(rex.w) {
                         if(ed==xRDX) gd=x3; else gd=xRDX;
@@ -1134,8 +1145,19 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                         AND(xRAX, xRDX, xMASK);
                         SRLI(xRDX, xRDX, 32);
                     }
-                    UFLAG_RES(xRAX);
-                    UFLAG_OP1(xRDX);
+                    IFX (X_CF | X_OF) {
+                        // CF = OF = SignExtend(RAX) != RDX:RAX
+                        SRAIxw(x6, xRAX, rex.w ? 63 : 31);
+                        SUBxw(x6, xRDX, x6);
+                        SNEZ(x6, x6);
+                        IFX (X_CF) {
+                            OR(xFlags, xFlags, x6); // F_CF == 0
+                        }
+                        IFX (X_OF) {
+                            SLLI(x6, x6, F_OF2);
+                            OR(xFlags, xFlags, x6);
+                        }
+                    }
                     break;
                 case 6:
                     INST_NAME("DIV Ed");
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index 0f101d16..a90bdb77 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -426,7 +426,6 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             }
             SETFLAGS(X_ALL, SF_PENDING);
             nextop = F8;
-            UFLAG_DF(x1, d_imul16);
             GETSEW(x1, (opcode==0x69)?2:1);
             if(opcode==0x69) i32 = F16S; else i32 = F8S;
             MOV32w(x2, i32);
@@ -435,6 +434,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             UFLAG_RES(x2);
             gd=x2;
             GWBACK;
+            UFLAG_DF(x1, d_imul16);
             break;
         case 0x70:
         case 0x71:
diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c
index d2610cf4..d4f44b3c 100644
--- a/src/dynarec/rv64/dynarec_rv64_660f.c
+++ b/src/dynarec/rv64/dynarec_rv64_660f.c
@@ -2309,13 +2309,13 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             INST_NAME("IMUL Gw,Ew");
             SETFLAGS(X_ALL, SF_PENDING);
             nextop = F8;
-            UFLAG_DF(x1, d_imul16);
             GETSEW(x1, 0);
             GETSGW(x2);
             MULW(x2, x2, x1);
             UFLAG_RES(x2);
             ZEXTH(x2, x2);
             GWBACK;
+            UFLAG_DF(x1, d_imul16);
             break;
         case 0xB3:
             INST_NAME("BTR Ew, Gw");
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 9db55bf3..b45e95a4 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -854,6 +854,11 @@
     if ((N) != d_none) {                     \
         MOV_U12(S, (N));                     \
         SW(S, xEmu, offsetof(x64emu_t, df)); \
+        if(dyn->f.pending==SF_PENDING && dyn->insts[ninst].x64.need_after && !(dyn->insts[ninst].x64.need_after&X_PEND)) {  \
+            CALL_(UpdateFlags, -1, 0);       \
+            dyn->f.pending = SF_SET;         \
+            SET_NODF();                      \
+        }                                    \
         dyn->f.dfnone = 0;                   \
     } else                                   \
         SET_DFNONE()