diff options
| author | Yang Liu <liuyang22@iscas.ac.cn> | 2023-03-19 17:28:33 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-19 10:28:33 +0100 |
| commit | e1ca614f1c777ce332253945dabc9a043057976b (patch) | |
| tree | 4c832549c32324ab0a28c2ae34d17165833a1a50 /src | |
| parent | 01d1ea0b90ed171c33ff18b27966fabf652f4eba (diff) | |
| download | box64-e1ca614f1c777ce332253945dabc9a043057976b.tar.gz box64-e1ca614f1c777ce332253945dabc9a043057976b.zip | |
[RV64_DYNAREC] Added more opcode (#591)
* [RV64_DYNAREC] Added 84 TEST opcode
* [RV64_DYNAREC] Added 64 8B MOV opcode
* [RV64_DYNAREC] Added {B4,B5,B6,B7} MOV opcode
* [RV64_DYNAREC] Added 3C CMP opcode
* [RV64_DYNAREC] Added {81,83} /1 OR opcode
* [RV64_DYNAREC] Fixed MOV opcodeDiffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 45 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_64.c | 85 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 17 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_logic.c | 32 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.c | 25 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 29 | ||||
| -rw-r--r-- | src/dynarec/rv64/rv64_emitter.h | 2 |
7 files changed, 229 insertions, 6 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index 926f3d6a..6f6be07a 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -149,7 +149,18 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5, x6); break; - + case 0x3C: + INST_NAME("CMP AL, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); + u8 = F8; + ANDI(x1, xRAX, 0xff); + if(u8) { + MOV32w(x2, u8); + emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6); + } else { + emit_cmp8_0(dyn, ninst, x1, x3, x4); + } + break; case 0x50: case 0x51: case 0x52: @@ -201,7 +212,9 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni } } break; - + case 0x64: + addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog); + break; case 0x66: addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break; @@ -361,7 +374,14 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; - + case 0x84: + INST_NAME("TEST Eb, Gb"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop=F8; + GETEB(x1, 0); + GETGB(x2); + emit_test8(dyn, ninst, x1, x2, x3, x4, x5); + break; case 0x85: INST_NAME("TEST Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -499,6 +519,25 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni MOV32w(x2, u8); emit_test8(dyn, ninst, x1, x2, x3, x4, x5); break; + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + INST_NAME("MOV xH, Ib"); + u8 = F8; + MOV32w(x1, u8); + if(rex.rex) { + gb1 = xRAX+(opcode&7)+(rex.b<<3); + ANDI(gb1, gb1, ~0xff); + OR(gb1, gb1, x1); + } else { + gb1 = xRAX+(opcode&3); + MOV64x(x2, 0xffffffffffff00ffLL); + AND(gb1, gb1, x2); + SLLI(x1, x1, 8); + OR(gb1, gb1, x1); + } + break; case 0xB8: case 0xB9: case 0xBA: diff --git a/src/dynarec/rv64/dynarec_rv64_64.c b/src/dynarec/rv64/dynarec_rv64_64.c new file mode 100644 index 00000000..bbcdc681 --- /dev/null +++ b/src/dynarec/rv64/dynarec_rv64_64.c @@ -0,0 +1,85 @@ +#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 "custommem.h" + +#include "rv64_printer.h" +#include "dynarec_rv64_private.h" +#include "dynarec_rv64_helper.h" +#include "dynarec_rv64_functions.h" + +#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3) + +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) +{ + (void)ip; (void)rep; (void)need_epilog; + + uint8_t opcode = F8; + uint8_t nextop; + uint8_t u8; + uint8_t gd, ed, eb1, eb2, gb1, gb2; + uint8_t wback, wb1, wb2, wb; + int64_t i64, j64; + int v0, v1; + int q0; + int d0; + int64_t fixedaddress; + int unscaled; + MAYUSE(eb1); + MAYUSE(eb2); + MAYUSE(wb1); + MAYUSE(wb2); + MAYUSE(gb1); + MAYUSE(gb2); + MAYUSE(j64); + MAYUSE(d0); + MAYUSE(q0); + MAYUSE(v0); + MAYUSE(v1); + + while((opcode==0xF2) || (opcode==0xF3)) { + rep = opcode-0xF1; + opcode = F8; + } + // REX prefix before the F0 are ignored + rex.rex = 0; + while(opcode>=0x40 && opcode<=0x4f) { + rex.rex = opcode; + opcode = F8; + } + + switch(opcode) { + case 0x8B: + INST_NAME("MOV Gd, Seg:Ed"); + grab_segdata(dyn, addr, ninst, x4, seg); + nextop=F8; + GETGD; + if(MODREG) { // reg <= reg + MVxw(gd, xRAX+(nextop&7)+(rex.b<<3)); + } else { // mem <= reg + SMREAD(); + addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0); + ADD(x4, ed, x4); + LDxw(gd, x4, 0); + } + break; + default: + DEFAULT; + } + return addr; +} diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index 6348728c..86446b7a 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -85,6 +85,23 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni // just use regular conditional jump return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); + case 0x81: + case 0x83: + nextop = F8; + switch((nextop>>3)&7) { + case 1: // OR + if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode==0x81)?2:1); + if(opcode==0x81) i16 = F16S; else i16 = F8S; + MOV64x(x5, i16); + emit_or16(dyn, ninst, x1, x5, x2, x4); + EWBACK; + break; + default: + DEFAULT; + } + break; case 0xC1: nextop = F8; switch((nextop>>3)&7) { diff --git a/src/dynarec/rv64/dynarec_rv64_emit_logic.c b/src/dynarec/rv64/dynarec_rv64_emit_logic.c index 4d399fd8..6076a159 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_logic.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_logic.c @@ -96,6 +96,37 @@ void emit_xor32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i } } +// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed) +void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) { + CLEAR_FLAGS(); + IFX(X_PEND) { + SET_DF(s3, d_or16); + } else IFX(X_ALL) { + SET_DFNONE(s3); + } + + OR(s1, s1, s2); + SLLI(s1, s1, 48); + SRLI(s1, s1, 48); + IFX(X_PEND) { + SD(s1, xEmu, offsetof(x64emu_t, res)); + } + + IFX(X_SF) { + SRLI(s3, s1, 15); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + + IFX(X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, F_ZF); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + // emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) { @@ -110,6 +141,7 @@ void emit_or32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3 // test sign bit before zeroup. IFX(X_SF) { + if (!rex.w) SEXT_W(s1, s1); BGE(s1, xZR, 8); ORI(xFlags, xFlags, 1 << F_SF); } diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c index 41343cf2..a57c27dd 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.c +++ b/src/dynarec/rv64/dynarec_rv64_helper.c @@ -481,6 +481,31 @@ void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w) SET_NODF(); } +void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment) +{ + (void)addr; + int64_t j64; + MAYUSE(j64); + MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS"); + int t1 = x1, t2 = x4; + if(reg==t1) ++t1; + if(reg==t2) ++t2; + LWU(t2, xEmu, offsetof(x64emu_t, segs_serial[segment])); + LD(reg, xEmu, offsetof(x64emu_t, segs_offs[segment])); + if(segment==_GS) { + CBNZ_MARKSEG(t2); // fast check + } else { + LD(t1, xEmu, offsetof(x64emu_t, context)); + LWU(t1, t1, offsetof(box64context_t, sel_serial)); + SUBW(t1, t1, t2); + CBZ_MARKSEG(t1); + } + MOV64x(x1, segment); + call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0); + MARKSEG; + MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS"); +} + void fpu_reset(dynarec_rv64_t* dyn) { //TODO diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index dca0f1da..82a0fbab 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -176,6 +176,20 @@ wb1 = 1; \ ed = i; \ } +//GETGB will use i for gd +#define GETGB(i) if(rex.rex) { \ + gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \ + gb2 = 0; \ + } else { \ + gd = (nextop&0x38)>>3; \ + gb2 = ((gd&4)>>2); \ + gb1 = xRAX+(gd&3); \ + } \ + gd = i; \ + MV(gd, gb1); \ + if (gb2) SRLI(gd, gd, gb2*8); \ + ANDI(gd, gd, 0xff); + // CALL will use x6 for the call address. Return value can be put in ret (unless ret is -1) // R0 will not be pushed/popd if ret is -2 #define CALL(F, ret) call_c(dyn, ninst, F, x6, ret, 1, 0) @@ -233,6 +247,15 @@ j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;\ B(j64) +// Branch to MARKSEG if reg is 0 (use j64) +#define CBZ_MARKSEG(reg) \ + j64 = GETMARKSEG-(dyn->native_size); \ + BEQZ(reg, j64); +// Branch to MARKSEG if reg is not 0 (use j64) +#define CBNZ_MARKSEG(reg) \ + j64 = GETMARKSEG-(dyn->native_size); \ + BNEZ(reg, j64); + #define IFX(A) if((dyn->insts[ninst].x64.gen_flags&(A))) #define IFX_PENDOR0 if((dyn->insts[ninst].x64.gen_flags&(X_PEND) || !dyn->insts[ninst].x64.gen_flags)) #define IFXX(A) if((dyn->insts[ninst].x64.gen_flags==(A))) @@ -605,7 +628,7 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n); //void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits); void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg); void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w); -//void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment); +void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment); void emit_cmp8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6); //void emit_cmp16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_cmp32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6); @@ -640,7 +663,7 @@ void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i //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); //void emit_sub16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); -//void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); +void emit_or16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_or16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); //void emit_xor16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_xor16c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); @@ -745,7 +768,7 @@ 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* 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_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); //uintptr_t dynarec64_67(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog); diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index 4a87ecba..484deb36 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -174,6 +174,8 @@ f28–31 ft8–11 FP temporaries Caller // rd = rs1 - rs2 #define SUB(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0110011)) // rd = rs1 - rs2 +#define SUBW(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0111011)) +// rd = rs1 - rs2 #define SUBxw(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, rex.w?0b0110011:0b0111011)) // rd = rs1<<rs2 #define SLL(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b001, rd, 0b0110011)) |