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.c7
-rw-r--r--src/dynarec/rv64/dynarec_rv64_0f.c283
-rw-r--r--src/dynarec/rv64/dynarec_rv64_functions.c16
-rw-r--r--src/dynarec/rv64/dynarec_rv64_functions.h5
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h34
-rw-r--r--src/dynarec/rv64/rv64_emitter.h5
6 files changed, 330 insertions, 20 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c
index e6bea413..99ebcb3c 100644
--- a/src/dynarec/rv64/dynarec_rv64_00.c
+++ b/src/dynarec/rv64/dynarec_rv64_00.c
@@ -64,6 +64,9 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
 
         case 0x0F:
             switch(rep) {
+            case 0:
+                addr = dynarec64_0F(dyn, addr, ip, ninst, rex, ok, need_epilog);
+                break;
             case 2:
                 addr = dynarec64_F30F(dyn, addr, ip, ninst, rex, ok, need_epilog);
                 break;
@@ -154,7 +157,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 CHECK_CACHE()) {                                        \
                 /* out of the block */                                  \
                 i32 = dyn->insts[ninst].epilog-(dyn->native_size);      \
-                NO(x1, i32);                                            \
+                B##NO(x1, i32);                                         \
                 if(dyn->insts[ninst].x64.jmp_insts==-1) {               \
                     if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))  \
                         fpu_purgecache(dyn, ninst, 1, x1, x2, x3);      \
@@ -167,7 +170,7 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             } else {                                                    \
                 /* inside the block */                                  \
                 i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);    \
-                YES(x1, i32);                                           \
+                B##YES(x1, i32);                                        \
             }
 
         GOCOND(0x70, "J", "ib");
diff --git a/src/dynarec/rv64/dynarec_rv64_0f.c b/src/dynarec/rv64/dynarec_rv64_0f.c
new file mode 100644
index 00000000..bbff1f78
--- /dev/null
+++ b/src/dynarec/rv64/dynarec_rv64_0f.c
@@ -0,0 +1,283 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "debug.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "emu/x64emu_private.h"
+#include "emu/x64run_private.h"
+#include "x64run.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "emu/x64run_private.h"
+#include "x64trace.h"
+#include "dynarec_native.h"
+#include "my_cpuid.h"
+#include "emu/x87emu_private.h"
+
+#include "rv64_printer.h"
+#include "dynarec_rv64_private.h"
+#include "dynarec_rv64_functions.h"
+#include "dynarec_rv64_helper.h"
+
+uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
+{
+    (void)ip; (void)need_epilog;
+
+    uint8_t opcode = F8;
+    uint8_t nextop, u8;
+    uint8_t gd, ed;
+    uint8_t wback, wb2;
+    uint8_t eb1, eb2;
+    int32_t i32, i32_;
+    int cacheupd = 0;
+    int v0, v1;
+    int q0, q1;
+    int d0, d1;
+    int s0;
+    uint64_t tmp64u;
+    int64_t j64;
+    int64_t fixedaddress;
+    int unscaled;
+    MAYUSE(wb2);
+    MAYUSE(eb1);
+    MAYUSE(eb2);
+    MAYUSE(q0);
+    MAYUSE(q1);
+    MAYUSE(d0);
+    MAYUSE(d1);
+    MAYUSE(s0);
+    MAYUSE(j64);
+    MAYUSE(cacheupd);
+
+    switch(opcode) {
+
+        case 0x01:
+            INST_NAME("FAKE xgetbv");
+            nextop = F8;
+            addr = fakeed(dyn, addr, ninst, nextop);
+            SETFLAGS(X_ALL, SF_SET);    // Hack to set flags in "don't care" state
+            GETIP(ip);
+            STORE_XEMU_CALL();
+            CALL(rv64_ud, -1);
+            LOAD_XEMU_CALL();
+            jump_to_epilog(dyn, 0, xRIP, ninst);
+            *need_epilog = 0;
+            *ok = 0;
+            break;
+
+        case 0x05:
+            INST_NAME("SYSCALL");
+            SMEND();
+            GETIP(addr);
+            STORE_XEMU_CALL();
+            CALL_S(x64Syscall, -1);
+            LOAD_XEMU_CALL();
+            TABLE64(x3, addr); // expected return address
+            BNE_MARK(xRIP, x3);
+            LW(w1, xEmu, offsetof(x64emu_t, quit));
+            CBZ_NEXT(w1);
+            MARK;
+            LOAD_XEMU_REM();
+            jump_to_epilog(dyn, 0, xRIP, ninst);
+            break;
+
+        case 0x09:
+            INST_NAME("WBINVD");
+            SETFLAGS(X_ALL, SF_SET);    // Hack to set flags in "don't care" state
+            GETIP(ip);
+            STORE_XEMU_CALL();
+            CALL(rv64_ud, -1);
+            LOAD_XEMU_CALL();
+            jump_to_epilog(dyn, 0, xRIP, ninst);
+            *need_epilog = 0;
+            *ok = 0;
+            break;
+
+        case 0x0B:
+            INST_NAME("UD2");
+            SETFLAGS(X_ALL, SF_SET);    // Hack to set flags in "don't care" state
+            GETIP(ip);
+            STORE_XEMU_CALL();
+            CALL(rv64_ud, -1);
+            LOAD_XEMU_CALL();
+            jump_to_epilog(dyn, 0, xRIP, ninst);
+            *need_epilog = 0;
+            *ok = 0;
+            break;
+
+
+        case 0x18:
+            nextop = F8;
+            if((nextop&0xC0)==0xC0) {
+                INST_NAME("NOP (multibyte)");
+            } else
+            switch((nextop>>3)&7) {
+                case 0:
+                    DEFAULT;
+                    break;
+                case 1:
+                    DEFAULT;
+                    break;
+                case 2:
+                    DEFAULT;
+                    break;
+                case 3:
+                    DEFAULT;
+                    break;
+                default:
+                    INST_NAME("NOP (multibyte)");
+                    FAKEED;
+                }
+            break;
+
+        case 0x1F:
+            INST_NAME("NOP (multibyte)");
+            nextop = F8;
+            FAKEED;
+            break;
+
+        case 0x31:
+            INST_NAME("RDTSC");
+            MESSAGE(LOG_DUMP, "Need Optimization\n");
+            CALL(ReadTSC, xRAX);   // will return the u64 in xEAX
+            SRLI(xRDX, xRAX, 32);
+            ZEROUP(xRAX);   // wipe upper part
+            break;
+
+
+        #define GO(GETFLAGS, NO, YES, F)            \
+            READFLAGS(F);                           \
+            GETFLAGS;                               \
+            nextop=F8;                              \
+            GETGD;                                  \
+            if(MODREG) {                            \
+                ed = xRAX+(nextop&7)+(rex.b<<3);    \
+                B##NO(x1, 8);                       \
+                MV(gd, ed);                         \
+            } else {                                \
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
+                B##NO(x1, 8);                       \
+                LDxw(gd, ed, fixedaddress);         \
+                if(!rex.w) {ZEROUP(gd);}            \
+            }
+
+        GOCOND(0x40, "CMOV", "Gd, Ed");
+        #undef GO
+
+        case 0x77:
+            INST_NAME("EMMS");
+            // empty MMX, FPU now usable
+            mmx_purgecache(dyn, ninst, 0, x1);
+            /*emu->top = 0;
+            emu->fpu_stack = 0;*/ //TODO: Check if something is needed here?
+            break;
+
+        #define GO(GETFLAGS, NO, YES, F)   \
+            READFLAGS(F);                                               \
+            i32_ = F32S;                                                \
+            BARRIER(BARRIER_MAYBE);                                     \
+            JUMP(addr+i32_, 1);                                         \
+            GETFLAGS;                                                   \
+            if(dyn->insts[ninst].x64.jmp_insts==-1 ||                   \
+                CHECK_CACHE()) {                                        \
+                /* out of the block */                                  \
+                i32 = dyn->insts[ninst].epilog-(dyn->native_size);      \
+                B##NO(x1, i32);                                         \
+                if(dyn->insts[ninst].x64.jmp_insts==-1) {               \
+                    if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))  \
+                        fpu_purgecache(dyn, ninst, 1, x1, x2, x3);      \
+                    jump_to_next(dyn, addr+i32_, 0, ninst);             \
+                } else {                                                \
+                    CacheTransform(dyn, ninst, cacheupd, x1, x2, x3);   \
+                    i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);    \
+                    B(i32);                                             \
+                }                                                       \
+            } else {                                                    \
+                /* inside the block */                                  \
+                i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);    \
+                B##YES(x1, i32);                                        \
+            }
+
+        GOCOND(0x80, "J", "Id");
+        #undef GO
+
+        #define GO(GETFLAGS, NO, YES, F)                \
+            READFLAGS(F);                               \
+            GETFLAGS;                                   \
+            nextop=F8;                                  \
+            S##YES(x3, x1);                             \
+            if(MODREG) {                                \
+                if(rex.rex) {                           \
+                    eb1= xRAX+(nextop&7)+(rex.b<<3);    \
+                    eb2 = 0;                            \
+                } else {                                \
+                    ed = (nextop&7);                    \
+                    eb2 = (ed>>2)*8;                    \
+                    eb1 = xRAX+(ed&3);                  \
+                }                                       \
+                if (eb2) {                              \
+                    LUI(x1, 0xffffffffffff0);           \
+                    ORI(x1, x1, 0xff);                  \
+                    AND(eb1, eb1, x1);                  \
+                } else {                                \
+                    ANDI(eb1, eb1, 0xf00);              \
+                }                                       \
+                OR(eb1, eb1, x3);                       \
+            } else {                                    \
+                addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress,rex, NULL, 1, 0); \
+                SB(x3, ed, fixedaddress);               \
+                SMWRITE();                              \
+            }
+
+        GOCOND(0x90, "SET", "Eb");
+        #undef GO
+            
+        case 0xA2:
+            INST_NAME("CPUID");
+            MV(A1, xRAX);
+            CALL_(my_cpuid, -1, 0);
+            // BX and DX are not synchronized durring the call, so need to force the update
+            LD(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
+            LD(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
+            break;
+
+        case 0xAE:
+            nextop = F8;
+            if((nextop&0xF8)==0xE8) {
+                INST_NAME("LFENCE");
+                SMDMB();
+            } else
+            if((nextop&0xF8)==0xF0) {
+                INST_NAME("MFENCE");
+                SMDMB();
+            } else
+            if((nextop&0xF8)==0xF8) {
+                INST_NAME("SFENCE");
+                SMDMB();
+            } else {
+                switch((nextop>>3)&7) {
+                    case 7:
+                        INST_NAME("CLFLUSH Ed");
+                        MESSAGE(LOG_DUMP, "Need Optimization?\n");
+                        addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
+                        if(wback!=A1) {
+                            MV(A1, wback);
+                        }
+                        CALL_(arm_clflush, -1, 0);
+                        break;
+                    default:
+                        DEFAULT;
+                }
+            }
+            break;
+
+        default:
+            DEFAULT;
+    }
+    return addr;
+}
diff --git a/src/dynarec/rv64/dynarec_rv64_functions.c b/src/dynarec/rv64/dynarec_rv64_functions.c
index 681d20d3..f7a0af69 100644
--- a/src/dynarec/rv64/dynarec_rv64_functions.c
+++ b/src/dynarec/rv64/dynarec_rv64_functions.c
@@ -29,6 +29,22 @@
 #include "bridge.h"
 #include "rv64_lock.h"
 
+void arm_clflush(x64emu_t* emu, void* p)
+{
+    cleanDBFromAddressRange((uintptr_t)p, 8, 0);
+}
+
+void rv64_ud(x64emu_t* emu)
+{
+    emit_signal(emu, SIGILL, (void*)R_RIP, 0);
+}
+
+void rv64_priv(x64emu_t* emu)
+{
+    emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
+}
+
+
 void fpu_reset_scratch(dynarec_rv64_t* dyn)
 {
     //TODO
diff --git a/src/dynarec/rv64/dynarec_rv64_functions.h b/src/dynarec/rv64/dynarec_rv64_functions.h
index 2fb76659..9e0fe7ab 100644
--- a/src/dynarec/rv64/dynarec_rv64_functions.h
+++ b/src/dynarec/rv64/dynarec_rv64_functions.h
@@ -5,6 +5,11 @@
 typedef struct x64emu_s x64emu_t;
 typedef struct dynarec_rv64_s dynarec_rv64_t;
 
+void arm_clflush(x64emu_t* emu, void* p);
+
+void rv64_ud(x64emu_t* emu);
+void rv64_priv(x64emu_t* emu);
+
 // Reset scratch regs counter
 void fpu_reset_scratch(dynarec_rv64_t* dyn);
 
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 47f59fb7..803fbcf2 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -660,7 +660,7 @@ void fpu_pushcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07);
 void fpu_popcache(dynarec_rv64_t* dyn, int ninst, int s1, int not07);
 
 uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
-//uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
+uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
 //uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
 //uintptr_t dynarec64_65(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep,int* ok, int* need_epilog);
 //uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
@@ -703,76 +703,76 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
     case B+0x0:                                             \
         INST_NAME(T1 "O " T2);                              \
         GO( ANDI(x1, xFlags, 1<<F_OF2)                      \
-            , BEQZ, BNEZ, X_OF)                             \
+            , EQZ, NEZ, X_OF)                               \
         break;                                              \
     case B+0x1:                                             \
         INST_NAME(T1 "NO " T2);                             \
         GO( ANDI(x1, xFlags, 1<<F_OF2)                      \
-            , BNEZ, BEQZ, X_OF)                             \
+            , NEZ, EQZ, X_OF)                               \
         break;                                              \
     case B+0x2:                                             \
         INST_NAME(T1 "C " T2);                              \
         GO( ANDI(x1, xFlags, 1<<F_CF)                       \
-            , BEQZ, BNEZ, X_CF)                             \
+            , EQZ, NEZ, X_CF)                               \
         break;                                              \
     case B+0x3:                                             \
         INST_NAME(T1 "NC " T2);                             \
         GO( ANDI(x1, xFlags, 1<<F_CF)                       \
-            , BNEZ, BEQZ, X_CF)                             \
+            , NEZ, EQZ, X_CF)                               \
         break;                                              \
     case B+0x4:                                             \
         INST_NAME(T1 "Z " T2);                              \
         GO( ANDI(x1, xFlags, 1<<F_ZF)                       \
-            , BEQZ, BNEZ, X_ZF)                             \
+            , EQZ, NEZ, X_ZF)                               \
         break;                                              \
     case B+0x5:                                             \
         INST_NAME(T1 "NZ " T2);                             \
         GO( ANDI(x1, xFlags, 1<<F_ZF)                       \
-            , BNEZ, BEQZ, X_ZF)                             \
+            , NEZ, EQZ, X_ZF)                               \
         break;                                              \
     case B+0x6:                                             \
         INST_NAME(T1 "BE " T2);                             \
         GO( ANDI(x1, xFlags, (1<<F_CF)|(1<<F_ZF))           \
-            , BEQZ, BNEZ, X_CF|X_ZF)                        \
+            , EQZ, NEZ, X_CF|X_ZF)                          \
         break;                                              \
     case B+0x7:                                             \
         INST_NAME(T1 "NBE " T2);                            \
         GO( ANDI(x1, xFlags, (1<<F_CF)|(1<<F_ZF))           \
-            , BNEZ, BEQZ, X_CF|X_ZF)                        \
+            , NEZ, EQZ, X_CF|X_ZF)                          \
         break;                                              \
     case B+0x8:                                             \
         INST_NAME(T1 "S " T2);                              \
         GO( ANDI(x1, xFlags, 1<<F_SF)                       \
-            , BEQZ, BNEZ, X_SF)                             \
+            , EQZ, NEZ, X_SF)                               \
         break;                                              \
     case B+0x9:                                             \
         INST_NAME(T1 "NS " T2);                             \
         GO( ANDI(x1, xFlags, 1<<F_SF)                       \
-            , BNEZ, BEQZ, X_SF)                             \
+            , NEZ, EQZ, X_SF)                               \
         break;                                              \
     case B+0xA:                                             \
         INST_NAME(T1 "P " T2);                              \
         GO( ANDI(x1, xFlags, 1<<F_PF)                       \
-            , BEQZ, BNEZ, X_PF)                             \
+            , EQZ, NEZ, X_PF)                               \
         break;                                              \
     case B+0xB:                                             \
         INST_NAME(T1 "NP " T2);                             \
         GO( ANDI(x1, xFlags, 1<<F_PF)                       \
-            , BNEZ, BEQZ, X_PF)                             \
+            , NEZ, EQZ, X_PF)                               \
         break;                                              \
     case B+0xC:                                             \
         INST_NAME(T1 "L " T2);                              \
         GO( SRLI(x1, xFlags, F_SF-F_OF2);                   \
             XOR(x1, x1, xFlags);                            \
             ANDI(x1, x1, 1<<F_OF2)                          \
-            , BEQZ, BNEZ, X_SF|X_OF)                        \
+            , EQZ, NEZ, X_SF|X_OF)                          \
         break;                                              \
     case B+0xD:                                             \
         INST_NAME(T1 "GE " T2);                             \
         GO( SRLI(x1, xFlags, F_SF-F_OF2);                   \
             XOR(x1, x1, xFlags);                            \
             ANDI(x1, x1, 1<<F_OF2)                          \
-            , BNEZ, BEQZ, X_SF|X_OF)                        \
+            , NEZ, EQZ, X_SF|X_OF)                          \
         break;                                              \
     case B+0xE:                                             \
         INST_NAME(T1 "LE " T2);                             \
@@ -781,7 +781,7 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             ANDI(x3, xFlags, 1<<F_ZF);                      \
             OR(x1, x1, x3);                                 \
             ANDI(x1, x1, (1<<F_OF2) | (1<<F_ZF))            \
-            , BEQZ, BNEZ, X_SF|X_OF|X_ZF)                   \
+            , EQZ, NEZ, X_SF|X_OF|X_ZF)                     \
         break;                                              \
     case B+0xF:                                             \
         INST_NAME(T1 "G " T2);                              \
@@ -790,7 +790,7 @@ uintptr_t dynarec64_F30F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             ANDI(x3, xFlags, 1<<F_ZF);                      \
             OR(x1, x1, x3);                                 \
             ANDI(x1, x1, (1<<F_OF2) | (1<<F_ZF))            \
-            , BNEZ, BEQZ, X_SF|X_OF|X_ZF)                   \
+            , NEZ, EQZ, X_SF|X_OF|X_ZF)                     \
         break
 
 #endif //__DYNAREC_RV64_HELPER_H__
diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h
index 5f5cfe0c..e920a9f9 100644
--- a/src/dynarec/rv64/rv64_emitter.h
+++ b/src/dynarec/rv64/rv64_emitter.h
@@ -203,7 +203,10 @@ f28–31  ft8–11  FP temporaries                  Caller
 // rd = -rs1
 #define NEG(rd, rs1)                SUB(rd, xZR, rs1)
 // rd = rs1 == 0
-#define SEQZ(rd, rs1)               SLTIU(rd, rs1, 0)
+#define SEQZ(rd, rs1)               SLTIU(rd, rs1, 1)
+// rd = rs1 != 0
+#define SNEZ(rd, rs1)               SLTU(rd, xZR, rs1)
+
 
 #define BEQ(rs1, rs2, imm13)       EMIT(B_type(imm13, rs2, rs1, 0b000, 0b1100011))
 #define BNE(rs1, rs2, imm13)       EMIT(B_type(imm13, rs2, rs1, 0b001, 0b1100011))