diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/dynarec/arm64_emitter.h | 17 | ||||
| -rw-r--r-- | src/dynarec/dynarec_arm64_64.c | 144 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_arm64_helper.h | 12 | ||||
| -rw-r--r-- | src/emu/x64run64.c | 71 |
4 files changed, 235 insertions, 9 deletions
diff --git a/src/dynarec/arm64_emitter.h b/src/dynarec/arm64_emitter.h index e6fe2fd6..13ad556b 100755 --- a/src/dynarec/arm64_emitter.h +++ b/src/dynarec/arm64_emitter.h @@ -230,13 +230,16 @@ #define LDRB_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt)) #define LDRH_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt)) -#define LDRSH_gen(size, op1, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt)) -#define LDRSHx_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) -#define LDRSHw_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b01, 0b01, 0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) -#define LDRSHxw_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b01, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) -#define LDRSBx_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b00, 0b01, 0b10, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) -#define LDRSBw_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b00, 0b01, 0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) -#define LDRSBxw_U12(Rt, Rn, imm12) EMIT(LDRSH_gen(0b00, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) +#define LDRS_U12_gen(size, op1, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt)) +#define LDRSHx_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) +#define LDRSHw_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b01, 0b01, 0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) +#define LDRSHxw_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b01, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt)) +#define LDRSBx_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b00, 0b01, 0b10, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) +#define LDRSBw_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b00, 0b01, 0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) +#define LDRSBxw_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b00, 0b01, rex.w?0b10:0b11, ((uint32_t)(imm12>>0))&0xfff, Rn, Rt)) + +#define LDRS_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b10<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt)) +#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt)) #define LDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt)) #define LDRx_literal(Rt, imm19) EMIT(LDR_PC_gen(0b01, ((imm19)>>2)&0x7FFFF, Rt)) diff --git a/src/dynarec/dynarec_arm64_64.c b/src/dynarec/dynarec_arm64_64.c index 9ef1b272..18bb65de 100644 --- a/src/dynarec/dynarec_arm64_64.c +++ b/src/dynarec/dynarec_arm64_64.c @@ -32,7 +32,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin uint8_t nextop; uint8_t u8; uint8_t gd, ed, eb1, eb2; - uint8_t wback, wb1, wb2; + uint8_t wback, wb1, wb2, wb; int64_t i64, j64; int v0; int q0; @@ -625,6 +625,148 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } break; + case 0xF7: + nextop = F8; + switch((nextop>>3)&7) { + case 0: + case 1: + INST_NAME("TEST Ed, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, 4); + i64 = F32S; + MOV64xw(x2, i64); + emit_test32(dyn, ninst, rex, ed, x2, x3, x4); + break; + case 2: + INST_NAME("NOT Ed"); + GETEDO(x6, 4); + MVNxw_REG(ed, ed); + WBACKO(x6); + break; + case 3: + INST_NAME("NEG Ed"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, 0); + emit_neg32(dyn, ninst, rex, ed, x3, x4); + WBACKO(x6); + break; + case 4: + INST_NAME("MUL EAX, Ed"); + SETFLAGS(X_ALL, SF_PENDING); + UFLAG_DF(x2, rex.w?d_mul64:d_mul32); + GETEDO(x6, 0); + if(rex.w) { + if(ed==xRDX) gd=x3; else gd=xRDX; + UMULH(gd, xRAX, ed); + MULx(xRAX, xRAX, ed); + if(gd!=xRDX) {MOVx_REG(xRDX, gd);} + } else { + UMULL(xRDX, xRAX, ed); //64 <- 32x32 + MOVw_REG(xRAX, xRDX); + LSRx(xRDX, xRDX, 32); + } + UFLAG_RES(xRAX); + UFLAG_OP1(xRDX); + break; + case 5: + INST_NAME("IMUL EAX, Ed"); + SETFLAGS(X_ALL, SF_PENDING); + UFLAG_DF(x2, rex.w?d_imul64:d_imul32); + GETEDO(x6, 0); + if(rex.w) { + if(ed==xRDX) gd=x3; else gd=xRDX; + SMULH(gd, xRAX, ed); + MULx(xRAX, xRAX, ed); + if(gd!=xRDX) {MOVx_REG(xRDX, gd);} + } else { + SMULL(xRDX, xRAX, ed); //64 <- 32x32 + MOVw_REG(xRAX, xRDX); + LSRx(xRDX, xRDX, 32); + } + UFLAG_RES(xRAX); + UFLAG_OP1(xRDX); + break; + case 6: + INST_NAME("DIV Ed"); + SETFLAGS(X_ALL, SF_SET); + if(!rex.w) { + SET_DFNONE(x2); + GETEDO(x6, 0); + MOVw_REG(x3, xRAX); + ORRx_REG_LSL(x3, x3, xRDX, 32); + if(MODREG) { + MOVw_REG(x4, ed); + ed = x4; + } + UDIVx(x2, x3, ed); + MSUBx(x4, x2, ed, xRAX); + MOVw_REG(xRAX, x2); + MOVw_REG(xRDX, x4); + } else { + if(ninst && dyn->insts + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31 + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) { + SET_DFNONE(x2); + GETEDO(x6, 0); + UDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + } else { + GETEDO(x6, 0); + CBZxw_MARK(xRDX); + if(ed!=x1) {MOVx_REG(x1, ed);} + CALL(div64, -1); + B_NEXT_nocond; + MARK; + UDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + SET_DFNONE(x2); + } + } + break; + case 7: + INST_NAME("IDIV Ed"); + SETFLAGS(X_ALL, SF_SET); + if(!rex.w) { + SET_DFNONE(x2) + GETSEDOw(x6, 0); + MOVw_REG(x3, xRAX); + ORRx_REG_LSL(x3, x3, xRDX, 32); + SDIVx(x2, x3, wb); + MSUBx(x4, x2, wb, x3); + MOVw_REG(xRAX, x2); + MOVw_REG(xRDX, x4); + } else { + if(ninst && dyn->insts + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48 + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) { + SET_DFNONE(x2) + GETEDO(x6, 0); + SDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + } else { + GETEDO(x6, 0); + CBZxw_MARK(xRDX); + MVNx_REG(x2, xRDX); + CBZxw_MARK(x2); + if(ed!=x1) {MOVx_REG(x1, ed);} + CALL((void*)idiv64, -1); + B_NEXT_nocond; + MARK; + SDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + SET_DFNONE(x2) + } + } + break; + } + break; + case 0xFF: nextop = F8; grab_segdata(dyn, addr, ninst, x6, seg); diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h index e2905874..27c1e9a7 100755 --- a/src/dynarec/dynarec_arm64_helper.h +++ b/src/dynarec/dynarec_arm64_helper.h @@ -66,7 +66,7 @@ wback = 0; \ } else { \ addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \ - LDRw_U12(x1, wback, fixedaddress); \ + LDRSW_U12(x1, wback, fixedaddress); \ wb = ed = x1; \ } //GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI @@ -115,6 +115,16 @@ LDRx_REG(x1, wback, O); \ ed = x1; \ } +#define GETSEDOw(O, D) if((nextop&0xC0)==0xC0) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + SXTWx(x1, ed); \ + wb = x1; \ + wback = 0; \ + } else { \ + addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \ + LDRSW_REG(x1, wback, O); \ + wb = ed = x1; \ + } //FAKEELike GETED, but doesn't get anything #define FAKEED if(!MODREG) { \ addr = fakeed(dyn, addr, ninst, nextop); \ diff --git a/src/emu/x64run64.c b/src/emu/x64run64.c index e6039c2b..c7cbbc4b 100644 --- a/src/emu/x64run64.c +++ b/src/emu/x64run64.c @@ -413,6 +413,77 @@ int Run64(x64emu_t *emu, rex_t rex, int seg) } break; + case 0xF7: /* GRP3 Ed(,Id) */ + nextop = F8; + tmp8u = (nextop>>3)&7; + GETED_OFFS((tmp8u<2)?4:0, tlsdata); + if(rex.w) { + switch(tmp8u) { + case 0: + case 1: /* TEST Ed,Id */ + tmp64u = F32S64; + test64(emu, ED->q[0], tmp64u); + break; + case 2: /* NOT Ed */ + ED->q[0] = not64(emu, ED->q[0]); + break; + case 3: /* NEG Ed */ + ED->q[0] = neg64(emu, ED->q[0]); + break; + case 4: /* MUL RAX,Ed */ + mul64_rax(emu, ED->q[0]); + break; + case 5: /* IMUL RAX,Ed */ + imul64_rax(emu, ED->q[0]); + break; + case 6: /* DIV Ed */ + div64(emu, ED->q[0]); + break; + case 7: /* IDIV Ed */ + idiv64(emu, ED->q[0]); + break; + } + } else { + switch(tmp8u) { + case 0: + case 1: /* TEST Ed,Id */ + tmp32u = F32; + test32(emu, ED->dword[0], tmp32u); + break; + case 2: /* NOT Ed */ + if(MODREG) + ED->q[0] = not32(emu, ED->dword[0]); + else + ED->dword[0] = not32(emu, ED->dword[0]); + break; + case 3: /* NEG Ed */ + if(MODREG) + ED->q[0] = neg32(emu, ED->dword[0]); + else + ED->dword[0] = neg32(emu, ED->dword[0]); + break; + case 4: /* MUL EAX,Ed */ + mul32_eax(emu, ED->dword[0]); + emu->regs[_AX].dword[1] = 0; + break; + case 5: /* IMUL EAX,Ed */ + imul32_eax(emu, ED->dword[0]); + emu->regs[_AX].dword[1] = 0; + break; + case 6: /* DIV Ed */ + div32(emu, ED->dword[0]); + //emu->regs[_AX].dword[1] = 0; // already put high regs to 0 + //emu->regs[_DX].dword[1] = 0; + break; + case 7: /* IDIV Ed */ + idiv32(emu, ED->dword[0]); + //emu->regs[_AX].dword[1] = 0; + //emu->regs[_DX].dword[1] = 0; + break; + } + } + break; + case 0xFF: /* GRP 5 Ed */ nextop = F8; GETED_OFFS(0, tlsdata); |