about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorxctan <xctan@cirno.icu>2024-04-28 21:27:10 +0800
committerGitHub <noreply@github.com>2024-04-28 15:27:10 +0200
commit41ae74757e3b5249852551539976d507bbeeb3b6 (patch)
tree1067ea767c96e28400e57ece2a55d1872c4d3f53 /src
parent2304738336d72d0a3df1c6652cb2785751747b9a (diff)
downloadbox64-41ae74757e3b5249852551539976d507bbeeb3b6.tar.gz
box64-41ae74757e3b5249852551539976d507bbeeb3b6.zip
[RV64_DYNAREC] Fixed DIV and IDIV for zero divisor (#1476)
* [RV64_DYNAREC] Fixed DIV Ed and IDIV Ed for zero divisor

* [RV64_DYNAREC] Fixed DIV Ew and IDIV Ew for zero divisor

* [LA64_DYNAREC] Added todos for zero divisor
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c2
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c96
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c20
3 files changed, 105 insertions, 13 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 38a7abdd..64e8ba5f 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -1723,6 +1723,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 case 6:
                     INST_NAME("DIV Ed");
                     SETFLAGS(X_ALL, SF_SET);
+                    // TODO: handle zero divisor
                     if (!rex.w) {
                         SET_DFNONE();
                         GETED(0);
@@ -1765,6 +1766,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     INST_NAME("IDIV Ed");
                     SKIPTEST(x1);
                     SETFLAGS(X_ALL, SF_SET);
+                    // TODO: handle zero divisor
                     if (!rex.w) {
                         SET_DFNONE()
                         GETSED(0);
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index 93bf1690..015c2df9 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -1125,17 +1125,39 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     if(!rex.w) {
                         SET_DFNONE();
                         GETED(0);
-                        SLLI(x3, xRDX, 32);
-                        AND(x2, xRAX, xMASK);
-                        OR(x3, x3, x2);
-                        if(MODREG) {
-                            AND(x4, ed, xMASK);
-                            ed = x4;
+                        if(ninst && (nextop==0xF0)
+                           && dyn->insts[ninst-1].x64.addr
+                           && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0xB8
+                           && *(uint32_t*)(dyn->insts[ninst-1].x64.addr+1)==0) {
+                            // hack for some protection that check a divide by zero actualy trigger a divide by zero exception
+                            MESSAGE(LOG_INFO, "Divide by 0 hack\n");
+                            GETIP(ip);
+                            STORE_XEMU_CALL(x3);
+                            CALL(native_div0, -1);
+                            LOAD_XEMU_CALL();
+                        } else {
+                            if(box64_dynarec_div0) {
+                                BNE_MARK3(ed, xZR);
+                                GETIP_(ip);
+                                STORE_XEMU_CALL(x3);
+                                CALL(native_div0, -1);
+                                CLEARIP();
+                                LOAD_XEMU_CALL();
+                                jump_to_epilog(dyn, 0, xRIP, ninst);
+                                MARK3;
+                            }
+                            SLLI(x3, xRDX, 32);
+                            AND(x2, xRAX, xMASK);
+                            OR(x3, x3, x2);
+                            if(MODREG) {
+                                AND(x4, ed, xMASK);
+                                ed = x4;
+                            }
+                            DIVU(x2, x3, ed);
+                            REMU(xRDX, x3, ed);
+                            AND(xRAX, x2, xMASK);
+                            ZEROUP(xRDX);
                         }
-                        DIVU(x2, x3, ed);
-                        REMU(xRDX, x3, ed);
-                        AND(xRAX, x2, xMASK);
-                        ZEROUP(xRDX);
                     } else {
                         if(ninst
                            && dyn->insts[ninst-1].x64.addr
@@ -1143,11 +1165,31 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                            && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
                             SET_DFNONE();
                             GETED(0);
+                            if(box64_dynarec_div0) {
+                                BNE_MARK3(ed, xZR);
+                                GETIP_(ip);
+                                STORE_XEMU_CALL(x3);
+                                CALL(native_div0, -1);
+                                CLEARIP();
+                                LOAD_XEMU_CALL();
+                                jump_to_epilog(dyn, 0, xRIP, ninst);
+                                MARK3;
+                            }
                             DIVU(x2, xRAX, ed);
                             REMU(xRDX, xRAX, ed);
                             MV(xRAX, x2);
                         } else {
                             GETEDH(x1, 0);  // get edd changed addr, so cannot be called 2 times for same op...
+                            if(box64_dynarec_div0) {
+                                BNE_MARK3(ed, xZR);
+                                GETIP_(ip);
+                                STORE_XEMU_CALL(x3);
+                                CALL(native_div0, -1);
+                                CLEARIP();
+                                LOAD_XEMU_CALL();
+                                jump_to_epilog(dyn, 0, xRIP, ninst);
+                                MARK3;
+                            }
                             BEQ_MARK(xRDX, xZR);
                             if(ed!=x1) {MV(x1, ed);}
                             CALL(div64, -1);
@@ -1164,9 +1206,19 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     INST_NAME("IDIV Ed");
                     SKIPTEST(x1);
                     SETFLAGS(X_ALL, SF_SET);
+                    SET_DFNONE()
                     if(!rex.w) {
-                        SET_DFNONE()
                         GETSED(0);
+                        if(box64_dynarec_div0) {
+                            BNE_MARK3(ed, xZR);
+                            GETIP_(ip);
+                            STORE_XEMU_CALL(x3);
+                            CALL(native_div0, -1);
+                            CLEARIP();
+                            LOAD_XEMU_CALL();
+                            jump_to_epilog(dyn, 0, xRIP, ninst);
+                            MARK3;
+                        }
                         SLLI(x3, xRDX, 32);
                         AND(x2, xRAX, xMASK);
                         OR(x3, x3, x2);
@@ -1179,13 +1231,32 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                            &&  dyn->insts[ninst-1].x64.addr
                            && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48
                            && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) {
-                            SET_DFNONE()
                             GETED(0);
+                            if(box64_dynarec_div0) {
+                                BNE_MARK3(ed, xZR);
+                                GETIP_(ip);
+                                STORE_XEMU_CALL(x3);
+                                CALL(native_div0, -1);
+                                CLEARIP();
+                                LOAD_XEMU_CALL();
+                                jump_to_epilog(dyn, 0, xRIP, ninst);
+                                MARK3;
+                            }
                             DIV(x2, xRAX, ed);
                             REM(xRDX, xRAX, ed);
                             MV(xRAX, x2);
                         } else {
                             GETEDH(x1, 0);  // get edd changed addr, so cannot be called 2 times for same op...
+                            if(box64_dynarec_div0) {
+                                BNE_MARK3(ed, xZR);
+                                GETIP_(ip);
+                                STORE_XEMU_CALL(x3);
+                                CALL(native_div0, -1);
+                                CLEARIP();
+                                LOAD_XEMU_CALL();
+                                jump_to_epilog(dyn, 0, xRIP, ninst);
+                                MARK3;
+                            }
                             //Need to see if RDX==0 and RAX not signed
                             // or RDX==-1 and RAX signed
                             BNE_MARK2(xRDX, xZR);
@@ -1202,7 +1273,6 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                             DIV(x2, xRAX, ed);
                             REM(xRDX, xRAX, ed);
                             MV(xRAX, x2);
-                            SET_DFNONE()
                         }
                     }
                     break;
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index f9538fbf..c5ace2f5 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -1215,6 +1215,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     SLLI(x3, xRDX, 48);
                     SRLI(x3, x3, 32);
                     OR(x2, x2, x3);
+                    if(box64_dynarec_div0) {
+                        BNE_MARK3(ed, xZR);
+                        GETIP_(ip);
+                        STORE_XEMU_CALL(x6);
+                        CALL(native_div0, -1);
+                        CLEARIP();
+                        LOAD_XEMU_CALL();
+                        jump_to_epilog(dyn, 0, xRIP, ninst);
+                        MARK3;
+                    }
                     DIVUW(x3, x2, ed);
                     REMUW(x4, x2, ed);
                     MOV64x(x5, ~0xffff);
@@ -1231,6 +1241,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     NOTEST(x1);
                     SETFLAGS(X_ALL, SF_SET);
                     GETSEW(x1, 0);
+                    if(box64_dynarec_div0) {
+                        BNE_MARK3(ed, xZR);
+                        GETIP_(ip);
+                        STORE_XEMU_CALL(x6);
+                        CALL(native_div0, -1);
+                        CLEARIP();
+                        LOAD_XEMU_CALL();
+                        jump_to_epilog(dyn, 0, xRIP, ninst);
+                        MARK3;
+                    }
                     ZEXTH(x2, xRAX);
                     SLLI(x3, xRDX, 48);
                     SRLI(x3, x3, 32);