diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-10-05 23:06:58 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-10-05 23:06:58 +0200 |
| commit | 8d69c1783931384c1598421df7b1a36d3d564bde (patch) | |
| tree | 11a25597053bed0d3a476a054e4d1cb9c07dda5a /src | |
| parent | 348cb57240efe51690e420a4fdf3a012e3251d44 (diff) | |
| download | box64-8d69c1783931384c1598421df7b1a36d3d564bde.tar.gz box64-8d69c1783931384c1598421df7b1a36d3d564bde.zip | |
[DYNAREC] Added 67 89/C1/F7 opcodes
Diffstat (limited to 'src')
| -rwxr-xr-x | src/dynarec/dynarec_arm64_67.c | 232 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_arm64_helper.h | 37 |
2 files changed, 266 insertions, 3 deletions
diff --git a/src/dynarec/dynarec_arm64_67.c b/src/dynarec/dynarec_arm64_67.c index 22466181..c1e33cf8 100755 --- a/src/dynarec/dynarec_arm64_67.c +++ b/src/dynarec/dynarec_arm64_67.c @@ -32,11 +32,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin uint8_t opcode = F8; uint8_t nextop; - uint8_t gd, ed; + uint8_t gd, ed, wback, wb; int64_t fixedaddress; int8_t i8; + uint8_t u8; int32_t i32; - int64_t j64; + int64_t j64, i64; int v0, s0; MAYUSE(i32); MAYUSE(j64); @@ -88,6 +89,18 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } break; + case 0x89: + INST_NAME("MOV Ed, Gd"); + nextop=F8; + GETGD; + if(MODREG) { // reg <= reg + MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd); + } else { // mem <= reg + addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0); + STRxw_U12(gd, ed, fixedaddress); + } + break; + case 0x8D: INST_NAME("LEA Gd, Ed"); nextop=F8; @@ -103,6 +116,79 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } break; + case 0xC1: + nextop = F8; + switch((nextop>>3)&7) { + case 0: + INST_NAME("ROL Ed, Ib"); + SETFLAGS(X_OF|X_CF, SF_SUBSET); + GETED32(1); + u8 = (F8)&(rex.w?0x3f:0x1f); + emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4); + if(u8) { WBACK; } + break; + case 1: + INST_NAME("ROR Ed, Ib"); + SETFLAGS(X_OF|X_CF, SF_SUBSET); + GETED32(1); + u8 = (F8)&(rex.w?0x3f:0x1f); + emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4); + if(u8) { WBACK; } + break; + case 2: + INST_NAME("RCL Ed, Ib"); + MESSAGE(LOG_DUMP, "Need Optimization\n"); + READFLAGS(X_CF); + SETFLAGS(X_OF|X_CF, SF_SET); + GETED32W(x4, x1, 1); + u8 = F8; + MOV32w(x2, u8); + CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4); + WBACK; + break; + case 3: + INST_NAME("RCR Ed, Ib"); + MESSAGE(LOG_DUMP, "Need Optimization\n"); + READFLAGS(X_CF); + SETFLAGS(X_OF|X_CF, SF_SET); + GETED32W(x4, x1, 1); + u8 = F8; + MOV32w(x2, u8); + CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4); + WBACK; + break; + case 4: + case 6: + INST_NAME("SHL Ed, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED32(1); + u8 = (F8)&(rex.w?0x3f:0x1f); + emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4); + WBACK; + break; + case 5: + INST_NAME("SHR Ed, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED32(1); + u8 = (F8)&(rex.w?0x3f:0x1f); + emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4); + if(u8) { + WBACK; + } + break; + case 7: + INST_NAME("SAR Ed, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED32(1); + u8 = (F8)&(rex.w?0x3f:0x1f); + emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4); + if(u8) { + WBACK; + } + break; + } + break; + #define GO(NO, YES) \ BARRIER(2); \ JUMP(addr+i8);\ @@ -160,6 +246,148 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 0xE8: return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode) + case 0xF7: + nextop = F8; + switch((nextop>>3)&7) { + case 0: + case 1: + INST_NAME("TEST Ed, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED32H(x1, 4); + i64 = F32S; + MOV64xw(x2, i64); + emit_test32(dyn, ninst, rex, ed, x2, x3, x4); + break; + case 2: + INST_NAME("NOT Ed"); + GETED32(4); + MVNxw_REG(ed, ed); + WBACK; + break; + case 3: + INST_NAME("NEG Ed"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED32(0); + emit_neg32(dyn, ninst, rex, ed, x3, x4); + WBACK; + break; + case 4: + INST_NAME("MUL EAX, Ed"); + SETFLAGS(X_ALL, SF_PENDING); + UFLAG_DF(x2, rex.w?d_mul64:d_mul32); + GETED32(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); + GETED32(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); + GETED32(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); + GETED32(0); + UDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + } else { + GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + 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) + GETSED32w(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) + GETED32(0); + SDIVx(x2, xRAX, ed); + MSUBx(xRDX, x2, ed, xRAX); + MOVx_REG(xRAX, x2); + } else { + GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + 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; + default: DEFAULT; } diff --git a/src/dynarec/dynarec_arm64_helper.h b/src/dynarec/dynarec_arm64_helper.h index a005d90d..1ec25bc7 100755 --- a/src/dynarec/dynarec_arm64_helper.h +++ b/src/dynarec/dynarec_arm64_helper.h @@ -69,6 +69,24 @@ LDRSW_U12(x1, wback, fixedaddress); \ wb = ed = x1; \ } +#define GETED32(D) if(MODREG) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + wback = 0; \ + } else { \ + addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \ + LDRxw_U12(x1, wback, fixedaddress); \ + ed = x1; \ + } +#define GETSED32w(D) if((nextop&0xC0)==0xC0) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + SXTWx(x1, ed); \ + wb = x1; \ + wback = 0; \ + } else { \ + addr = geted32(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \ + 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 #define GETEDH(hint, D) if(MODREG) { \ ed = xRAX+(nextop&7)+(rex.b<<3); \ @@ -78,8 +96,16 @@ LDRxw_U12(hint, wback, fixedaddress); \ ed = hint; \ } +#define GETED32H(hint, D) if(MODREG) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + wback = 0; \ + } else { \ + addr = geted32(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \ + LDRxw_U12(hint, wback, fixedaddress); \ + ed = hint; \ + } //GETEDW can use hint for wback and ret for ed. wback is 0 if ed is xEAX..xEDI -#define GETEDW(hint, ret, D) if(MODREG) { \ +#define GETEDW(hint, ret, D) if(MODREG) { \ ed = xRAX+(nextop&7)+(rex.b<<3); \ MOVxw_REG(ret, ed); \ wback = 0; \ @@ -88,6 +114,15 @@ ed = ret; \ LDRxw_U12(ed, wback, fixedaddress); \ } +#define GETED32W(hint, ret, D) if(MODREG) { \ + ed = xRAX+(nextop&7)+(rex.b<<3); \ + MOVxw_REG(ret, ed); \ + wback = 0; \ + } else { \ + addr = geted32(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \ + ed = ret; \ + LDRxw_U12(ed, wback, fixedaddress); \ + } // Write back ed in wback (if wback not 0) #define WBACK if(wback) {STRxw_U12(ed, wback, fixedaddress);} // Write back ed in wback (if wback not 0) |