about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorxctan <xctan@cirno.icu>2023-04-22 23:06:03 +0800
committerGitHub <noreply@github.com>2023-04-22 17:06:03 +0200
commit225e50a32aa9c15eb71ee8eef6bf45748074c7fa (patch)
treed17ad5ff3802d77cf090543b6d8aa65249dfba86
parentd546877e7dddba58f21b67f2595d5be3a2d3cbb7 (diff)
downloadbox64-225e50a32aa9c15eb71ee8eef6bf45748074c7fa.tar.gz
box64-225e50a32aa9c15eb71ee8eef6bf45748074c7fa.zip
[RV64_DYNAREC] Added more opcodes for SV (#726)
* [RV64_DYNAREC] Added 66 FF /0 INC opcode and fixed emit_add16

* [RV64_DYNAREC] Added 66 0F F9 PSUBW opcode

* [RV64_DYNAREC] Added 0F BA /6 BTR opcode

* [RV64_DYNAREC] Added 0F BA /5 BTS opcode

* [RV64_DYNAREC] Added 8C MOV opcode

* [RV64_DYNAREC] Added 66 8B MOV opcode
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_2.c13
-rw-r--r--src/dynarec/rv64/dynarec_rv64_0f.c54
-rw-r--r--src/dynarec/rv64/dynarec_rv64_66.c61
-rw-r--r--src/dynarec/rv64/dynarec_rv64_660f.c7
-rw-r--r--src/dynarec/rv64/dynarec_rv64_emit_math.c61
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h4
6 files changed, 182 insertions, 18 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00_2.c b/src/dynarec/rv64/dynarec_rv64_00_2.c
index f962a507..4a6e6827 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_2.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_2.c
@@ -375,7 +375,18 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 LDxw(gd, ed, fixedaddress);
             }
             break;
-
+        case 0x8C:
+            INST_NAME("MOV Ed, Seg");
+            nextop=F8;
+            if((nextop&0xC0)==0xC0) {   // reg <= seg
+                LHU(xRAX+(nextop&7)+(rex.b<<3), xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
+            } else {                    // mem <= seg
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
+                LHU(x3, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
+                SH(x3, ed, fixedaddress);
+                SMWRITE2();
+            }
+            break;
         case 0x8D:
             INST_NAME("LEA Gd, Ed");
             nextop=F8;
diff --git a/src/dynarec/rv64/dynarec_rv64_0f.c b/src/dynarec/rv64/dynarec_rv64_0f.c
index d60f7be0..c2d526cf 100644
--- a/src/dynarec/rv64/dynarec_rv64_0f.c
+++ b/src/dynarec/rv64/dynarec_rv64_0f.c
@@ -819,6 +819,60 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     ANDI(xFlags, xFlags, ~1);
                     OR(xFlags, xFlags, x3);
                     break;
+                case 5:
+                    INST_NAME("BTS Ed, Ib");
+                    SETFLAGS(X_CF, SF_SUBSET);
+                    SET_DFNONE();
+                    GETED(1);
+                    u8 = F8;
+                    u8&=(rex.w?0x3f:0x1f);
+                    ORI(xFlags, xFlags, 1<<F_CF);
+                    if (u8 <= 10) {
+                        ANDI(x6, ed, 1<<u8);
+                        BNE_MARK(x6, xZR);
+                        ANDI(xFlags, xFlags, ~(1<<F_CF));
+                        XORI(ed, ed, 1<<u8);
+                    } else {
+                        ORI(x6, xZR, 1);
+                        SLLI(x6, x6, u8);
+                        AND(x4, ed, x6);
+                        BNE_MARK(x4, xZR);
+                        ANDI(xFlags, xFlags, ~(1<<F_CF));
+                        XOR(ed, ed, x6);
+                    }
+                    if (wback) {
+                        SDxw(ed, wback, fixedaddress);
+                        SMWRITE();
+                    }
+                    MARK;
+                    break;
+                case 6:
+                    INST_NAME("BTR Ed, Ib");
+                    SETFLAGS(X_CF, SF_SUBSET);
+                    SET_DFNONE();
+                    GETED(1);
+                    u8 = F8;
+                    u8&=(rex.w?0x3f:0x1f);
+                    ANDI(xFlags, xFlags, ~(1<<F_CF));
+                    if (u8 <= 10) {
+                        ANDI(x6, ed, 1<<u8);
+                        BEQ_MARK(x6, xZR);
+                        ORI(xFlags, xFlags, 1<<F_CF);
+                        XORI(ed, ed, 1<<u8);
+                    } else {
+                        ORI(x6, xZR, 1);
+                        SLLI(x6, x6, u8);
+                        AND(x6, ed, x6);
+                        BEQ_MARK(x6, xZR);
+                        ORI(xFlags, xFlags, 1<<F_CF);
+                        XOR(ed, ed, x6);
+                    }
+                    if (wback) {
+                        SDxw(ed, wback, fixedaddress);
+                        SMWRITE();
+                    }
+                    MARK;
+                    break;
                 case 7:
                     INST_NAME("BTC Ed, Ib");
                     SETFLAGS(X_CF, SF_SUBSET);
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c
index aa2d5f7c..8b4a94f5 100644
--- a/src/dynarec/rv64/dynarec_rv64_66.c
+++ b/src/dynarec/rv64/dynarec_rv64_66.c
@@ -67,7 +67,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             nextop = F8;
             GETGW(x2);
             GETEW(x1, 0);
-            emit_add16(dyn, ninst, x1, x2, x4, x5);
+            emit_add16(dyn, ninst, x1, x2, x4, x5, x6);
             EWBACK;
             break;
         case 0x03:
@@ -76,7 +76,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             nextop = F8;
             GETGW(x1);
             GETEW(x2, 0);
-            emit_add16(dyn, ninst, x1, x2, x3, x4);
+            emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
             GWBACK;
             break;
         case 0x05:
@@ -86,7 +86,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             SLLI(x1 , xRAX, 48);
             SRLI(x1, x1, 48);
             MOV32w(x2, i32);
-            emit_add16(dyn, ninst, x1, x2, x3, x4);
+            emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
             LUI(x3, 0xffff0);
             AND(xRAX, xRAX, x3);
             OR(xRAX, xRAX, x1);
@@ -292,7 +292,7 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                     GETEW(x1, (opcode==0x81)?2:1);
                     if(opcode==0x81) i16 = F16S; else i16 = F8S;
                     MOV64x(x5, i16);
-                    emit_add16(dyn, ninst, ed, x5, x2, x4);
+                    emit_add16(dyn, ninst, ed, x5, x2, x4, x6);
                     EWBACK;
                     break;
                 case 1: // OR
@@ -384,14 +384,36 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 SMWRITELOCK(lock);
             }
             break;
-            case 0x90:
-            case 0x91:
-            case 0x92:
-            case 0x93:
-            case 0x94:
-            case 0x95:
-            case 0x96:
-            case 0x97:
+        case 0x8B:
+            INST_NAME("MOV Gw, Ew");
+            nextop = F8;
+            GETGD;  // don't need GETGW neither
+            if(MODREG) {
+                ed = xRAX+(nextop&7)+(rex.b<<3);
+                if(ed!=gd) {
+                    LUI(x1, 0xffff0);
+                    AND(gd, gd, x1);
+                    SLLI(x2, ed, 48);
+                    SRLI(x2, x2, 48);
+                    OR(gd, gd, x2);
+                }
+            } else {
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
+                SMREADLOCK(lock);
+                LHU(x1, ed, fixedaddress);
+                LUI(x4, 0xffff0);
+                AND(gd, gd, x4);
+                OR(gd, gd, x1);
+            }
+            break;
+        case 0x90:
+        case 0x91:
+        case 0x92:
+        case 0x93:
+        case 0x94:
+        case 0x95:
+        case 0x96:
+        case 0x97:
                 gd = xRAX+(opcode&0x07)+(rex.b<<3);
                 if(gd==xRAX) {
                     INST_NAME("NOP");
@@ -683,6 +705,21 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             }
             break;
 
+        case 0xFF:
+            nextop = F8;
+            switch((nextop>>3)&7) {
+                case 0:
+                    INST_NAME("INC Ew");
+                    SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
+                    GETEW(x1, 0);
+                    emit_inc16(dyn, ninst, x1, x2, x4, x5);
+                    EWBACK;
+                    break;
+                default:
+                    DEFAULT;
+            }
+            break;
+
         default:
             DEFAULT;
     }
diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c
index b42d3bea..91283c6f 100644
--- a/src/dynarec/rv64/dynarec_rv64_660f.c
+++ b/src/dynarec/rv64/dynarec_rv64_660f.c
@@ -1393,6 +1393,13 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 SB(x3, gback, i);
             }
             break;
+        case 0xF9:
+            INST_NAME("PSUBW Gx,Ex");
+            nextop = F8;
+            GETGX(x1);
+            GETEX(x2, 0);
+            SSE_LOOP_W(x3, x4, SUBW(x3, x3, x4));
+            break;
         case 0xFA:
             INST_NAME("PSUBD Gx,Ex");
             nextop = F8;
diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c
index df70eac4..90031672 100644
--- a/src/dynarec/rv64/dynarec_rv64_emit_math.c
+++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c
@@ -193,7 +193,7 @@ void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
 }
 
 // emit ADD16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
-void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
+void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
 {
     CLEAR_FLAGS();
     IFX(X_PEND) {
@@ -213,8 +213,8 @@ void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
         SW(s1, xEmu, offsetof(x64emu_t, res));
     }
     IFX(X_AF | X_OF) {
-        NOT(s2, s1);   // s2 = ~res
-        AND(s3, s2, s3);   // s3 = ~res & (op1 | op2)
+        NOT(s5, s1);   // s5 = ~res
+        AND(s3, s5, 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
@@ -778,6 +778,61 @@ void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
     }
 }
 
+// emit INC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
+void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
+{
+    IFX(X_PEND) {
+        SH(s1, xEmu, offsetof(x64emu_t, op1));
+        SET_DF(s3, d_inc16);
+    } else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
+        SET_DFNONE();
+    }
+    IFX(X_AF | X_OF) {
+        ORI(s3, s1, 1);    // s3 = op1 | op2
+        ANDI(s4, s1, 1);    // s4 = op1 & op2
+    }
+
+    ADDI(s1, s1, 1);
+
+    IFX(X_PEND) {
+        SH(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, 8);
+            ORI(xFlags, xFlags, 1 << F_AF);
+        }
+        IFX(X_OF) {
+            SRLI(s3, s3, 14);
+            SRLI(s4, s3, 1);
+            XOR(s3, s3, s4);
+            ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
+            BEQZ(s3, 8);
+            ORI(xFlags, xFlags, 1 << F_OF2);
+        }
+    }
+
+    SLLI(s1, s1, 48);
+    SRLI(s1, s1, 48);
+
+    IFX(X_ZF) {
+        BNEZ(s1, 8);
+        ORI(xFlags, xFlags, 1 << F_ZF);
+    }
+    IFX(X_SF) {
+        SRLI(s3, s1, 15);
+        BEQZ(s3, 8);
+        ORI(xFlags, xFlags, 1 << F_SF);
+    }
+    IFX(X_PF) {
+        emit_pf(dyn, ninst, s1, s3, s4);
+    }
+}
+
 // emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
 void emit_sbb8(dynarec_rv64_t* dyn, int ninst, 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 90d2598e..189fa7bc 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -933,7 +933,7 @@ void emit_xor8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_xor8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
 void emit_and8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_and8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
-void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
+void emit_add16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 //void emit_add16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
 void emit_sub16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
 //void emit_sub16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
@@ -944,7 +944,7 @@ void emit_xor16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
 void emit_and16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 //void emit_and16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
 void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
-//void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);
+void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_inc8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4);
 void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
 //void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4);