about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00.c8
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_math.c95
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h2
-rw-r--r--src/dynarec/rv64/rv64_emitter.h6
4 files changed, 110 insertions, 1 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index 563bdf6a..48e2ca27 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -106,6 +106,14 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0x83:
             nextop = F8;
             switch((nextop>>3)&7) {
+                case 0: //ADD
+                    if(opcode==0x81) {INST_NAME("ADD Ed, Id");} else {INST_NAME("ADD Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETED((opcode==0x81)?4:1);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
+                    WBACK;
+                    break;
                 case 5:
                     if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
                     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 ca8b4349..424b9a9c 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_math.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c
@@ -70,6 +70,101 @@
         emit_pf(dyn, ninst, s1, s3, s4);                                  \
     }                                                                     \
 
+// 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)
+{
+    CLEAR_FLAGS();
+    if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
+    {
+        // special case when doing math on ESP and only PEND is needed: ignoring it!
+        if(c >= -2048 && c < 2048) {
+            ADDIxw(s1, s1, c);
+        } else {
+            MOV64x(s2, c);
+            ADDxw(s1, s1, s2);
+        }
+        return;
+    }
+    IFX(X_PEND | X_AF | X_CF) {
+        MOV64x(s2, c);
+    }
+    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
+    }
+
+    if(c >= -2048 && c < 2048) {
+        ADDIxw(s1, s1, c);
+    } else {
+        IFX(X_PEND | X_AF | X_CF) {} else {MOV64x(s2, c);}
+        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_OF);
+        }
+    }
+    IFX(X_SF) {
+        BGE(s1, xZR, 4);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+    IFX(X_ZF) {
+        if (!rex.w) {
+            ZEROUP(s1);
+        }
+        BNEZ(s1, 4);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+}
+
+
 // 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)
 {
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index cdba7721..befeba12 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -338,7 +338,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 //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_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, 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);
 void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h
index b95f7278..6b33560e 100644
--- a/src/dynarec/rv64/rv64_emitter.h
+++ b/src/dynarec/rv64/rv64_emitter.h
@@ -152,6 +152,10 @@ f28–31  ft8–11  FP temporaries                  Caller
 
 // rd = rs1 + rs2
 #define ADD(rd, rs1, rs2)           EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, 0b0110011))
+// rd = rs1 + rs2
+#define ADDW(rd, rs1, rs2)          EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, 0b0111011))
+// rd = rs1 + rs2
+#define ADDxw(rd, rs1, rs2)         EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, rex.w?0b0110011:0b0111011))
 // rd = rs1 - rs2
 #define SUB(rd, rs1, rs2)           EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0110011))
 // rd = rs1 - rs2
@@ -240,6 +244,8 @@ f28–31  ft8–11  FP temporaries                  Caller
 
 // rd = rs1 + imm12
 #define ADDIW(rd, rs1, imm12)       EMIT(I_type((imm12)&0b111111111111, rs1, 0b000, rd, 0b0011011))
+// rd = rs1 + imm12
+#define ADDIxw(rd, rs1, imm12)      EMIT(I_type((imm12)&0b111111111111, rs1, 0b000, rd, rex.w?0b0010011:0b0011011))
 
 #define SEXT_W(rd, rs1)             ADDIW(rd, rs1, 0)