about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2023-03-13 17:32:29 +0800
committerGitHub <noreply@github.com>2023-03-13 10:32:29 +0100
commit170ab57f55fc6bdf9138554459fa1606d95bf153 (patch)
tree4851db4e04dfbaa1d65f468bc8adc2b12ce5d2d9 /src
parent874054f3bbf7289b858d66be0453ff1220d05382 (diff)
downloadbox64-170ab57f55fc6bdf9138554459fa1606d95bf153.tar.gz
box64-170ab57f55fc6bdf9138554459fa1606d95bf153.zip
[RV64_DYNAREC] Added (81/83) SUB opcode (#554)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00.c17
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_math.c131
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h2
3 files changed, 108 insertions, 42 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index 0094f1ff..489d870e 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -76,6 +76,23 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             SUBI(xRSP, xRSP, 8);
             break;
 
+        case 0x81:
+        case 0x83:
+            nextop = F8;
+            switch((nextop>>3)&7) {
+                case 5:
+                    if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETED((opcode==0x81)?4:1);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    emit_sub32c(dyn, ninst, rex, ed, i64, x2, x3, x4, x5);
+                    WBACK;
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
+
         case 0x89:
             INST_NAME("MOV Ed, Gd");
             nextop=F8;
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c
index 1c11a515..ca8b4349 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_math.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c
@@ -23,10 +23,57 @@
 #include "dynarec_rv64_functions.h"
 #include "dynarec_rv64_helper.h"
 
+#define CALC_SUB_FLAGS()                                                  \
+    IFX(X_PEND) {                                                         \
+        SDxw(s1, xEmu, offsetof(x64emu_t, res));                          \
+    }                                                                     \
+                                                                          \
+    IFX(X_AF | X_CF | X_OF) {                                             \
+        /* calc borrow chain */                                           \
+        /* bc = (res & (~op1 | op2)) | (~op1 & op2) */                    \
+        OR(s3, s5, s2);                                                   \
+        AND(s4, s1, s3);                                                  \
+        AND(s5, s5, s2);                                                  \
+        OR(s4, s4, s5);                                                   \
+        IFX(X_AF) {                                                       \
+            /* af = bc & 0x8 */                                           \
+            ANDI(s3, s4, 8);                                              \
+            BEQZ(s3, 4);                                                  \
+            ORI(xFlags, xFlags, 1 << F_AF);                               \
+        }                                                                 \
+        IFX(X_CF) {                                                       \
+            /* cf = bc & (rex.w?(1<<63):(1<<31)) */                       \
+            SRLI(s3, s4, rex.w?63:31);                                    \
+            BEQZ(s3, 4);                                                  \
+            ORI(xFlags, xFlags, 1 << F_CF);                               \
+        }                                                                 \
+        IFX(X_OF) {                                                       \
+            /* of = ((bc >> rex.w?62:30) ^ (bc >> rex.w?63:31)) & 0x1; */ \
+            SRLI(s3, s4, rex.w?62:30);                                    \
+            SRLI(s4, s3, 1);                                              \
+            XOR(s3, s3, s4);                                              \
+            ANDI(s3, s3, 1);                                              \
+            BEQZ(s3, 4);                                                  \
+            ORI(xFlags, xFlags, 1 << F_OF);                               \
+        }                                                                 \
+    }                                                                     \
+    IFX(X_ZF) {                                                           \
+        BEQZ(s1, 4);                                                      \
+        ORI(xFlags, xFlags, 1 << F_ZF);                                   \
+    }                                                                     \
+    IFX(X_SF) {                                                           \
+        SRLI(s3, s1, rex.w?63:31);                                        \
+        BEQZ(s3, 4);                                                      \
+        ORI(xFlags, xFlags, 1 << F_SF);                                   \
+    }                                                                     \
+    IFX(X_PF) {                                                           \
+        emit_pf(dyn, ninst, s1, s3, s4);                                  \
+    }                                                                     \
+
 // emit SUB32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
 void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
 {
-    CLEAR_FLAGS()
+    CLEAR_FLAGS();
     IFX(X_PEND) {
         SDxw(s1, xEmu, offsetof(x64emu_t, op1));
         SDxw(s2, xEmu, offsetof(x64emu_t, op2));
@@ -35,56 +82,58 @@ void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
         SET_DFNONE(s3);
     }
 
-    IFX(X_AF) {
-        // for later borrow chain calculation
+    IFX(X_AF | X_CF | X_OF) {
+        // for later flag calculation
         NOT(s5, s1);
     }
 
     SUBxw(s1, s1, s2);
+    CALC_SUB_FLAGS();
+}
+
+
+// emit SUB32 instruction, from s1, constant c, store result in s1 using s2, s3, s4 and s5 as scratch
+void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
+{
+    CLEAR_FLAGS();
+    if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
+    {
+        // special case when doing math on RSP and only PEND is needed: ignoring it!
+        if (c > -2048 && c <= 2048) {
+            ADDI(s1, s1, -c);
+        } else {
+            MOV64x(s2, c);
+            SUBxw(s1, s1, s2);
+        }
+        return;
+    }
 
     IFX(X_PEND) {
-        SDxw(s1, xEmu, offsetof(x64emu_t, res));
+        SDxw(s1, xEmu, offsetof(x64emu_t, op1));
+        MOV64x(s2, c);
+        SDxw(s2, xEmu, offsetof(x64emu_t, op2));
+        SET_DF(s3, rex.w?d_sub64:d_sub32);
+    } else IFX(X_ALL) {
+        SET_DFNONE(s3);
     }
 
     IFX(X_AF | X_CF | X_OF) {
-        // calc borrow chain
-        // bc = (res & (~op1 | op2)) | (~op1 & op2)
-        OR(s3, s5, s2);
-        AND(s4, s1, s3);
-        AND(s5, s5, s2);
-        OR(s4, s4, s5);
-        IFX(X_AF) {
-            // af = bc & 0x8
-            ANDI(s3, s4, 8);
-            BEQZ(s3, 4);
-            ORI(xFlags, xFlags, 1 << F_AF);
-        }
-        IFX(X_CF) {
-            // cf = bc & (rex.w?(1<<63):(1<<31))
-            SRLI(s3, s4, rex.w?63:31);
-            BEQZ(s3, 4);
-            ORI(xFlags, xFlags, 1 << F_CF);
-        }
-        IFX(X_OF) {
-            // of = ((bc >> rex.w?62:30) ^ (bc >> rex.w?63:31)) & 0x1;
-            SRLI(s3, s4, rex.w?62:30);
-            SRLI(s4, s3, 1);
-            XOR(s3, s3, s4);
-            ANDI(s3, s3, 1);
-            BEQZ(s3, 4);
-            ORI(xFlags, xFlags, 1 << F_OF);
-        }
-    }
-    IFX(X_ZF) {
-        BEQZ(s1, 4);
-        ORI(xFlags, xFlags, 1 << F_ZF);
+        // for later flag calculation
+        NOT(s5, s1);
     }
-    IFX(X_SF) {
-        SRLI(s3, s1, rex.w?63:31);
-        BEQZ(s3, 4);
-        ORI(xFlags, xFlags, 1 << F_SF);
+
+    if (c > -2048 && c <= 2048) {
+        ADDI(s1, s1, -c);
+    } else {
+        IFX(X_PEND) {} else {MOV64x(s2, c);}
+        SUBxw(s1, s1, s2);
     }
-    IFX(X_PF) {
-        emit_pf(dyn, ninst, s1, s3, s4);
+
+    IFX(X_AF | X_CF | X_OF) {
+        IFX(X_PEND) {}
+        else if (c > -2048 && c <= 2048) {
+            MOV64x(s2, c);
+        }
     }
+    CALC_SUB_FLAGS();
 }
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 3b347d77..53702fab 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -342,7 +342,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 //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);
 void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
-//void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
+void emit_sub32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5);
 //void emit_sub8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 //void emit_sub8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
 //void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);