diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 7 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_0f.c | 283 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_functions.c | 16 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_functions.h | 5 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 34 | ||||
| -rw-r--r-- | src/dynarec/rv64/rv64_emitter.h | 5 |
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)) |