diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-04-13 03:58:05 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-12 21:58:05 +0200 |
| commit | b9ea2408c205bbcd38212dc64aa2ef6ea47dc924 (patch) | |
| tree | 0328b88c8812ddcbba1aaff00f02596ecb4476c7 /src | |
| parent | 6ce570f4a514797aafe4c02bb750106365b5a3e7 (diff) | |
| download | box64-b9ea2408c205bbcd38212dc64aa2ef6ea47dc924.tar.gz box64-b9ea2408c205bbcd38212dc64aa2ef6ea47dc924.zip | |
[LA64_DYNAREC] Added more opcodes (#1441)
* Added 66 C7 MOV opcode * Added B0..B3 MOV opcode * Added F0 87 LOCK XCHG opcode * Added 35 XOR opcode * Added F7 /7 IDIV opcode * Added BC BSF opcode * Added BD BSR opcode
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 65 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 55 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66.c | 16 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f0.c | 22 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 26 |
5 files changed, 184 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index f4987cc6..afbe2555 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -301,6 +301,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETGB(x2); emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6); break; + case 0x35: + INST_NAME("XOR EAX, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + i64 = F32S; + emit_xor32c(dyn, ninst, rex, xRAX, i64, x3, x4); + break; case 0x39: INST_NAME("CMP Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -983,6 +989,19 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ADD_D(xRDI, xRDI, x3); } break; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + INST_NAME("MOV xL, Ib"); + u8 = F8; + MOV32w(x1, u8); + if (rex.rex) + gb1 = TO_LA64((opcode & 7) + (rex.b << 3)); + else + gb1 = TO_LA64(opcode & 3); + BSTRINS_D(gb1, x1, 7, 0); + break; case 0xB8: case 0xB9: case 0xBA: @@ -1664,6 +1683,52 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni } } break; + case 7: + INST_NAME("IDIV Ed"); + SKIPTEST(x1); + SETFLAGS(X_ALL, SF_SET); + if (!rex.w) { + SET_DFNONE() + GETSED(0); + SLLI_D(x3, xRDX, 32); + AND(x2, xRAX, xMASK); + OR(x3, x3, x2); + DIV_D(x2, x3, ed); + MOD_D(xRDX, x3, ed); + AND(xRAX, x2, xMASK); + ZEROUP(xRDX); + } 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() + GETED(0); + DIV_D(x2, xRAX, ed); + MOD_D(xRDX, xRAX, ed); + MV(xRAX, x2); + } else { + GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + // need to see if RDX == 0 and RAX not signed + // or RDX == -1 and RAX signed + BNE_MARK2(xRDX, xZR); + BGE_MARK(xRAX, xZR); + MARK2; + NOR(x2, xZR, xRDX); + BNE_MARK3(x2, xZR); + BLT_MARK(xRAX, xZR); + MARK3; + if (ed != x1) MV(x1, ed); + CALL((void*)idiv64, -1); + B_NEXT_nocond; + MARK; + DIV_D(x2, xRAX, ed); + MOD_D(xRDX, xRAX, ed); + MV(xRAX, x2); + SET_DFNONE() + } + } + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index e994203d..ebb6561a 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -389,6 +389,61 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni LD_HU(gd, ed, fixedaddress); } break; + case 0xBC: + INST_NAME("BSF Gd, Ed"); + SETFLAGS(X_ZF, SF_SUBSET); + SET_DFNONE(); + nextop = F8; + GETED(0); + GETGD; + if (!rex.w && MODREG) { + AND(x4, ed, xMASK); + ed = x4; + } + BNE_MARK(ed, xZR); + if (la64_lbt) { + ADDI_D(x3, xZR, 1 << F_ZF); + X64_SET_EFLAGS(x3, X_ZF); + } else { + ORI(xFlags, xFlags, 1 << F_ZF); + } + B_NEXT_nocond; + MARK; + // gd is undefined if ed is all zeros, don't worry. + if (rex.w) + CTZ_D(gd, ed); + else + CTZ_W(gd, ed); + if (la64_lbt) { + X64_SET_EFLAGS(xZR, X_ZF); + } else { + ADDI_D(x3, xZR, ~(1 << F_ZF)); + OR(xFlags, xFlags, x3); + } + break; + case 0xBD: + INST_NAME("BSR Gd, Ed"); + SETFLAGS(X_ZF, SF_SUBSET); + SET_DFNONE(); + nextop = F8; + GETED(0); + GETGD; + if (!rex.w && MODREG) { + AND(x4, ed, xMASK); + ed = x4; + } + BNE_MARK(ed, xZR); + ORI(xFlags, xFlags, 1 << F_ZF); + B_NEXT_nocond; + MARK; + ANDI(xFlags, xFlags, ~(1 << F_ZF)); + if (rex.w) + CLZ_D(gd, ed); + else + CLZ_W(gd, ed); + ADDI_D(x1, xZR, rex.w ? 63 : 31); + SUB_D(gd, x1, gd); + break; case 0xBE: INST_NAME("MOVSX Gd, Eb"); nextop = F8; diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c index 71c73324..e7a358eb 100644 --- a/src/dynarec/la64/dynarec_la64_66.c +++ b/src/dynarec/la64/dynarec_la64_66.c @@ -153,6 +153,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0xC7: + INST_NAME("MOV Ew, Iw"); + nextop = F8; + if (MODREG) { + ed = TO_LA64((nextop & 7) + (rex.b << 3)); + u16 = F16; + MOV32w(x1, u16); + BSTRINS_D(ed, x1, 15, 0); + } else { + addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2); + u16 = F16; + MOV32w(x1, u16); + ST_H(x1, ed, fixedaddress); + SMWRITELOCK(lock); + } + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c index 931701a6..64c806f9 100644 --- a/src/dynarec/la64/dynarec_la64_f0.c +++ b/src/dynarec/la64/dynarec_la64_f0.c @@ -177,6 +177,28 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x87: + INST_NAME("LOCK XCHG Ed, Gd"); + nextop = F8; + if (MODREG) { + GETGD; + GETED(0); + MV(x1, gd); + MV(gd, ed); + MV(ed, x1); + } else { + SMDMB(); + GETGD; + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + MARKLOCK; + LLxw(x1, wback, 0); + MV(x4, gd); + SCxw(x4, wback, 0); + BEQZ_MARKLOCK(x4); + MVxw(gd, x1); + SMDMB(); + } + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index d5089d40..b44c6c88 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -151,6 +151,25 @@ ed = x1; \ } +// GETSED can use r1 for ed, and r2 for wback. ed will be sign extended! +#define GETSED(D) \ + if (MODREG) { \ + ed = TO_LA64((nextop & 7) + (rex.b << 3)); \ + wback = 0; \ + if (!rex.w) { \ + ADD_W(x1, ed, xZR); \ + ed = x1; \ + } \ + } else { \ + SMREAD(); \ + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, D); \ + if (rex.w) \ + LD_D(x1, wback, fixedaddress); \ + else \ + LD_W(x1, wback, fixedaddress); \ + ed = x1; \ + } + // FAKEED like GETED, but doesn't get anything #define FAKEED \ if (!MODREG) { \ @@ -374,6 +393,13 @@ // Branch to MARKLOCK if reg1!=0 (use j64) #define BNEZ_MARKLOCK(reg) BxxZ_gen(NE, MARKLOCK, reg) +// Branch to MARK if reg1<reg2 (use j64) +#define BLT_MARK(reg1, reg2) Bxx_gen(LT, MARK, reg1, reg2) +// Branch to MARK if reg1<reg2 (use j64) +#define BLTU_MARK(reg1, reg2) Bxx_gen(LTU, MARK, reg1, reg2) +// Branch to MARK if reg1>=reg2 (use j64) +#define BGE_MARK(reg1, reg2) Bxx_gen(GE, MARK, reg1, reg2) + // Branch to MARK1 instruction unconditionnal (use j64) #define B_MARK1_nocond Bxx_gen(__, MARK1, 0, 0) // Branch to MARK2 instruction unconditionnal (use j64) |