about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <numbksco@gmail.com>2023-05-10 19:39:45 +0800
committerGitHub <noreply@github.com>2023-05-10 13:39:45 +0200
commitfe9e5bf21db4acca9b567f7ea36b084837ae7648 (patch)
tree6d8a0dd24ab54f81a883db4dab21bdb2e699a7fe /src
parent1ca4f6acf5aee62242447e34b8a243a23144f4c2 (diff)
downloadbox64-fe9e5bf21db4acca9b567f7ea36b084837ae7648.tar.gz
box64-fe9e5bf21db4acca9b567f7ea36b084837ae7648.zip
[RV64_DYNAREC] Added more opcodes and some fixes (#775)
* Added 64 C6 MOV opcode

* Added 64 03 ADD opcode

* Added 64 81,83 opcodes

* Added D8 FDIV opcode

* Added DB FUCOMI opcode

* Fixed 66 0F 3A 09 ROUNDPD opcode

* Fixed review
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/rv64/dynarec_rv64_64.c155
-rw-r--r--src/dynarec/rv64/dynarec_rv64_660f.c65
-rw-r--r--src/dynarec/rv64/dynarec_rv64_d8.c10
-rw-r--r--src/dynarec/rv64/dynarec_rv64_db.c40
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h1
5 files changed, 242 insertions, 29 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_64.c b/src/dynarec/rv64/dynarec_rv64_64.c
index c01f0260..dde8c972 100644
--- a/src/dynarec/rv64/dynarec_rv64_64.c
+++ b/src/dynarec/rv64/dynarec_rv64_64.c
@@ -64,6 +64,15 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
     }
 
     switch(opcode) {
+        case 0x03:
+            INST_NAME("ADD Gd, Seg:Ed");
+            SETFLAGS(X_ALL, SF_SET_PENDING);
+            grab_segdata(dyn, addr, ninst, x4, seg);
+            nextop = F8;
+            GETGD;
+            GETEDO(x4, 0, x5);
+            emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
+            break;
         case 0x2B:
             INST_NAME("SUB Gd, Seg:Ed");
             SETFLAGS(X_ALL, SF_SET_PENDING);
@@ -87,7 +96,92 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0x66:
             addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog);
             break;
-
+        case 0x81:
+        case 0x83:
+            nextop = F8;
+            grab_segdata(dyn, addr, ninst, x6, seg);
+            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);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    SD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
+                    LD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    WBACKO(x6);
+                    break;
+                case 1: // OR
+                    if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
+                    WBACKO(x6);
+                    break;
+                case 2: // ADC
+                    if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    MOV64xw(x5, i64);
+                    SD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6);
+                    LD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    WBACKO(x6);
+                    break;
+                case 3: // SBB
+                    if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
+                    READFLAGS(X_CF);
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    MOV64xw(x5, i64);
+                    SD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x6);
+                    LD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    WBACKO(x6);
+                    break;
+                case 4: // AND
+                    if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
+                    WBACKO(x6);
+                    break;
+                case 5: // SUB
+                    if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    SD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
+                    LD(x6, xEmu, offsetof(x64emu_t, scratch));
+                    WBACKO(x6);
+                    break;
+                case 6: // XOR
+                    if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
+                    WBACKO(x6);
+                    break;
+                case 7: // CMP
+                    if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
+                    SETFLAGS(X_ALL, SF_SET_PENDING);
+                    GETEDO(x6, (opcode==0x81)?4:1, x5);
+                    if(opcode==0x81) i64 = F32S; else i64 = F8S;
+                    if(i64) {
+                        MOV64xw(x2, i64);
+                        emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
+                    } else
+                        emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
+                    break;
+            }
+            break;
         case 0x88:
             INST_NAME("MOV Seg:Eb, Gb");
             grab_segdata(dyn, addr, ninst, x4, seg);
@@ -160,6 +254,53 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 LDxw(gd, x4, fixedaddress);
             }
             break;
+        case 0xC6:
+            INST_NAME("MOV Seg:Eb, Ib");
+            grab_segdata(dyn, addr, ninst, x4, seg);
+            nextop=F8;
+            if(MODREG) {   // reg <= u8
+                u8 = F8;
+                if(!rex.rex) {
+                    ed = (nextop&7);
+                    eb1 = xRAX+(ed&3);  // Ax, Cx, Dx or Bx
+                    eb2 = (ed&4)>>2;    // L or H
+                } else {
+                    eb1 = xRAX+(nextop&7)+(rex.b<<3);
+                    eb2 = 0;            
+                }
+
+                if (eb2) {
+                    // load a mask to x3 (ffffffffffff00ff)
+                    LUI(x3, 0xffffffffffff0);
+                    ORI(x3, x3, 0xff);
+                    // apply mask
+                    AND(eb1, eb1, x3);
+                    if(u8) {
+                        if((u8<<8)<2048) {
+                            ADDI(x4, xZR, u8<<8);
+                        } else {
+                            ADDI(x4, xZR, u8);
+                            SLLI(x4, x4, 8);
+                        }
+                        OR(eb1, eb1, x4);
+                    }
+                } else {
+                    ANDI(eb1, eb1, 0xf00);  // mask ffffffffffffff00
+                    ORI(eb1, eb1, u8);
+                }
+            } else {                    // mem <= u8
+                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
+                u8 = F8;
+                if(u8) {
+                    ADDI(x3, xZR, u8);
+                    ed = x3;
+                } else
+                    ed = xZR;
+                ADD(x4, wback, x4);
+                SB(ed, x4, fixedaddress);
+                SMWRITE2();
+            }
+            break;
         case 0xC7:
             INST_NAME("MOV Seg:Ed, Id");
             grab_segdata(dyn, addr, ninst, x4, seg);
@@ -169,11 +310,15 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 ed = xRAX+(nextop&7)+(rex.b<<3);
                 MOV64xw(ed, i64);
             } else {                    // mem <= i32
-                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 4);
+                addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 4);
                 i64 = F32S;
-                MOV64xw(x3, i64);
-                ADD(x4, ed, x4);
-                SDxw(x3, x4, fixedaddress);
+                if(i64) {
+                    MOV64xw(x3, i64);
+                    ed = x3;
+                } else
+                    ed = xZR;
+                ADD(x4, wback, x4);
+                SDxw(ed, x4, fixedaddress);
                 SMWRITE2();
             }
             break;
diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c
index bd9a4544..fec0cbd6 100644
--- a/src/dynarec/rv64/dynarec_rv64_660f.c
+++ b/src/dynarec/rv64/dynarec_rv64_660f.c
@@ -429,29 +429,50 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                     v1 = fpu_get_scratch(dyn);
                     MOV64x(x3, 1ULL << __DBL_MANT_DIG__);
                     FCVTDL(d1, x3, RD_RTZ);
-                    for (int i=0; i<2; ++i) {
-                        FLD(d0, wback, fixedaddress+8*i);
-                        FEQD(x4, d0, d0);
-                        BNEZ_MARK(x4);
-                        B_MARK3_nocond;
-                        MARK; // d0 is not nan
-                        FABSD(v1, d0);
-                        FLTD(x4, v1, d1);
-                        BNEZ_MARK2(x4);
-                        B_MARK3_nocond;
-                        MARK2;
-                        if(u8&4) {
-                            u8 = sse_setround(dyn, ninst, x4, x5);
-                            FCVTLD(x5, d0, RD_DYN);
-                            FCVTDL(d0, x5, RD_RTZ);
-                            x87_restoreround(dyn, ninst, u8);
-                        } else {
-                            FCVTLD(x5, d0, round_round[u8&3]);
-                            FCVTDL(d0, x5, RD_RTZ);
-                        }
-                        MARK3;
-                        FSD(d0, gback, 8*i);
+
+                    // i = 0
+                    FLD(d0, wback, fixedaddress);
+                    FEQD(x4, d0, d0);
+                    BNEZ(x4, 8);
+                    B_MARK_nocond;
+                    // d0 is not nan
+                    FABSD(v1, d0);
+                    FLTD(x4, v1, d1);
+                    BNEZ(x4, 8);
+                    B_MARK_nocond;
+                    if(u8&4) {
+                        u8 = sse_setround(dyn, ninst, x4, x5);
+                        FCVTLD(x5, d0, RD_DYN);
+                        FCVTDL(d0, x5, RD_RTZ);
+                        x87_restoreround(dyn, ninst, u8);
+                    } else {
+                        FCVTLD(x5, d0, round_round[u8&3]);
+                        FCVTDL(d0, x5, RD_RTZ);
                     }
+                    MARK;
+                    FSD(d0, gback, 0);
+
+                    // i = 1
+                    FLD(d0, wback, fixedaddress+8);
+                    FEQD(x4, d0, d0);
+                    BNEZ(x4, 8);
+                    B_MARK2_nocond;
+                    // d0 is not nan
+                    FABSD(v1, d0);
+                    FLTD(x4, v1, d1);
+                    BNEZ(x4, 8);
+                    B_MARK2_nocond;
+                    if(u8&4) {
+                        u8 = sse_setround(dyn, ninst, x4, x5);
+                        FCVTLD(x5, d0, RD_DYN);
+                        FCVTDL(d0, x5, RD_RTZ);
+                        x87_restoreround(dyn, ninst, u8);
+                    } else {
+                        FCVTLD(x5, d0, round_round[u8&3]);
+                        FCVTDL(d0, x5, RD_RTZ);
+                    }
+                    MARK2;
+                    FSD(d0, gback, 8);
                     break;
                 case 0x0E:
                     INST_NAME("PBLENDW Gx, Ex, Ib");
diff --git a/src/dynarec/rv64/dynarec_rv64_d8.c b/src/dynarec/rv64/dynarec_rv64_d8.c
index c3c10166..246221ce 100644
--- a/src/dynarec/rv64/dynarec_rv64_d8.c
+++ b/src/dynarec/rv64/dynarec_rv64_d8.c
@@ -108,7 +108,15 @@ uintptr_t dynarec64_D8(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xE8 ... 0xEF:
 
         case 0xF0 ... 0xF7:
-
+            INST_NAME("FDIV ST0, STx");
+            v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
+            v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
+            if(ST_IS_F(0)) {
+                FDIVS(v1, v1, v2);
+            } else {
+                FDIVD(v1, v1, v2);
+            }
+            break;
         case 0xF8 ... 0xFF:
             DEFAULT;
             break;
diff --git a/src/dynarec/rv64/dynarec_rv64_db.c b/src/dynarec/rv64/dynarec_rv64_db.c
index 08abacfd..cc3eac61 100644
--- a/src/dynarec/rv64/dynarec_rv64_db.c
+++ b/src/dynarec/rv64/dynarec_rv64_db.c
@@ -150,7 +150,45 @@ uintptr_t dynarec64_DB(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
         case 0xEE:
         case 0xEF:
             INST_NAME("FUCOMI ST0, STx");
-            DEFAULT;
+            SETFLAGS(X_ALL, SF_SET);
+            SET_DFNONE();
+            v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
+            v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
+            IFX(F_ZF | F_PF | F_CF) {
+                if(ST_IS_F(0)) {
+                    FEQS(x5, v1, v1);
+                    FEQS(x4, v2, v2);
+                    AND(x5, x5, x4);
+                    BEQZ(x5, 24); // undefined/NaN
+                    FEQS(x5, v1, v2);
+                    BNEZ(x5, 24); // equal
+                    FLTS(x3, v1, v2); // x3 = (v1<v2)?1:0
+                    OR(xFlags, xFlags, x3); // CF is the least significant bit
+                    J(16); // end
+                    // NaN
+                    ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
+                    J(8); // end
+                    // equal
+                    ORI(xFlags, xFlags, 1<<F_ZF);
+                    // end
+                } else {
+                    FEQD(x5, v1, v1);
+                    FEQD(x4, v2, v2);
+                    AND(x5, x5, x4);
+                    BEQZ(x5, 24); // undefined/NaN
+                    FEQD(x5, v1, v2);
+                    BNEZ(x5, 24); // equal
+                    FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0
+                    OR(xFlags, xFlags, x3); // CF is the least significant bit
+                    J(16); // end
+                    // NaN
+                    ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF));
+                    J(8); // end
+                    // equal
+                    ORI(xFlags, xFlags, 1<<F_ZF);
+                    // end
+                }
+            }
             break;
         case 0xF0:  
         case 0xF1:
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index fd9db950..fa0e0808 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -179,6 +179,7 @@
                     LDxw(x1, S, fixedaddress);          \
                     ed = x1;                            \
                 }
+#define WBACKO(O)   if(wback) {ADD(O, wback, O); SDxw(ed, O, 0); SMWRITE2();}
 
 // FAKEED like GETED, but doesn't get anything
 #define FAKEED  if(!MODREG) {   \