about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorxctan <xctan@cirno.icu>2023-03-16 14:57:08 +0800
committerGitHub <noreply@github.com>2023-03-16 07:57:08 +0100
commit9ea3b34e7ea60130d5f0dec69241bc60deaf2097 (patch)
tree127ad518b5defb188f5abfd8235b74473b69ef4e /src
parent440c6d2d9a1dfd021c05a9bfc774366e6da08059 (diff)
downloadbox64-9ea3b34e7ea60130d5f0dec69241bc60deaf2097.tar.gz
box64-9ea3b34e7ea60130d5f0dec69241bc60deaf2097.zip
[RV64_DYNAREC] Added 01 ADD opcode (#573)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00.c11
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_math.c79
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h2
3 files changed, 89 insertions, 3 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index 2516507e..c437299e 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -52,6 +52,16 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
     MAYUSE(cacheupd);
 
     switch(opcode) {
+        case 0x01:
+            INST_NAME("ADD Ed, Gd");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            nextop = F8;
+            GETGD;
+            GETED(0);
+            emit_add32(dyn, ninst, rex, ed, gd, x3, x4, x5);
+            WBACK;
+            break;
+        
         case 0x0F:
             switch(rep) {
             case 2:
@@ -61,6 +71,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 DEFAULT;
             }
             break;
+
         case 0x29:
             INST_NAME("SUB Ed, Gd");
             SETFLAGS(X_ALL, SF_SET_PENDING);
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c
index c151cfab..307765ac 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_math.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c
@@ -23,6 +23,81 @@
 #include "dynarec_rv64_functions.h"
 #include "dynarec_rv64_helper.h"
 
+// emit ADD32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
+void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
+{
+    CLEAR_FLAGS();
+    IFX(X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, op1));
+        SDxw(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s3, rex.w?d_add64:d_add32b);
+    } else IFX(X_ALL) {
+        SET_DFNONE(s3);
+    }
+    IFX(X_CF) {
+        if (rex.w) {
+            AND(s5, xMASK, s1);
+            AND(s4, xMASK, s2);
+            ADD(s5, s5, s4); // lo
+            SRLI(s3, s1, 0x20);
+            SRLI(s4, s2, 0x20);
+            ADD(s4, s4, s3);
+            SRLI(s5, s5, 0x20);
+            ADD(s5, s5, s4); // hi
+            SRAI(s5, s5, 0x20);
+            BEQZ(s5, 4);
+            ORI(xFlags, xFlags, 1 << F_CF);
+        } else {
+            ADD(s5, s1, s2);
+            SRLI(s5, s5, 0x20);
+            BEQZ(s5, 4);
+            ORI(xFlags, xFlags, 1 << F_CF);
+        }
+    }
+    IFX(X_AF | X_OF) {
+        OR(s3, s1, s2);      // s3 = op1 | op2
+        AND(s4, s1, s2);      // s4 = op1 & op2
+    }
+
+    ADDxw(s1, s1, s2);
+
+    IFX(X_PEND) {
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+    }
+    IFX(X_AF | X_OF) {
+        NOT(s2, s1);   // s2 = ~res
+        AND(s3, s2, s3);   // s3 = ~res & (op1 | op2)
+        OR(s3, s3, s4);   // cc = (~res & (op1 | op2)) | (op1 & op2)
+        IFX(X_AF) {
+            ANDI(s4, s3, 0x08); // AF: cc & 0x08
+            BEQZ(s4, 4);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX(X_OF) {
+            SRLI(s3, s3, rex.w?62:30);
+            SRLI(s4, s3, 1);
+            XOR(s3, s3, s4);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 4);
+            ORI(xFlags, xFlags, 1 << F_OF2);
+        }
+    }
+    IFX(X_SF) {
+        BGE(s1, xZR, 4);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    if (!rex.w) {
+        ZEROUP(s1);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+    IFX(X_ZF) {
+        BNEZ(s1, 4);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+}
+
 // emit ADD32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
 void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
 {
@@ -38,7 +113,7 @@ void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
         }
         return;
     }
-    IFX(X_PEND | X_AF | X_CF) {
+    IFX(X_PEND | X_AF | X_CF | X_OF) {
         MOV64x(s2, c);
     }
     IFX(X_PEND) {
@@ -76,7 +151,7 @@ void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
     if(c >= -2048 && c < 2048) {
         ADDIxw(s1, s1, c);
     } else {
-        IFX(X_PEND | X_AF | X_CF) {} else {MOV64x(s2, c);}
+        IFX(X_PEND | X_AF | X_CF | X_OF) {} else {MOV64x(s2, c);}
         ADDxw(s1, s1, s2);
     }
 
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 03592e93..b9c16ca6 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -514,7 +514,7 @@ void emit_cmp8_0(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
 //void emit_test8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 //void emit_test16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 void emit_test32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
-//void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
+void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5);
 //void emit_add8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 //void emit_add8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);