diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-05-11 16:49:16 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-11 10:49:16 +0200 |
| commit | 46dfaab639b7d2a5af79c288160bfe92b1fd6961 (patch) | |
| tree | 40700e5ae357f63641c96c698a89eed0450470b9 /src | |
| parent | ff755facc0c0ec502b4476d1144b61055abb3e7b (diff) | |
| download | box64-46dfaab639b7d2a5af79c288160bfe92b1fd6961.tar.gz box64-46dfaab639b7d2a5af79c288160bfe92b1fd6961.zip | |
[DYNAREC_LA64] Added more opcodes (#1496)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 59 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66.c | 40 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_660f.c | 14 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_shift.c | 116 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f0.c | 34 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f20f.c | 24 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 4 |
7 files changed, 290 insertions, 1 deletions
diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index 8ddae253..b63bdca4 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -607,6 +607,65 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni LD_HU(gd, ed, fixedaddress); } break; + case 0xBA: + nextop = F8; + switch ((nextop >> 3) & 7) { + case 4: + INST_NAME("BT Ed, Ib"); + SETFLAGS(X_CF, SF_SUBSET); + SET_DFNONE(); + GETED(1); + u8 = F8; + u8 &= rex.w ? 0x3f : 0x1f; + BSTRPICK_D(x4, ed, u8, u8); + if (la64_lbt) + X64_SET_EFLAGS(x4, X_CF); + else + BSTRINS_D(xFlags, x4, 0, 0); + break; + case 5: + INST_NAME("BTS Ed, Ib"); + SETFLAGS(X_CF, SF_SUBSET); + SET_DFNONE(); + GETED(1); + u8 = F8; + u8 &= (rex.w ? 0x3f : 0x1f); + BSTRPICK_D(x4, ed, u8, u8); + if (la64_lbt) + X64_SET_EFLAGS(x4, X_CF); + else + BSTRINS_D(xFlags, x4, 0, 0); + ADDI_D(x4, xZR, -1); + BSTRINS_D(ed, x4, u8, u8); + if (wback) { + SDxw(ed, wback, fixedaddress); + SMWRITE(); + } + MARK; + break; + case 6: + INST_NAME("BTR Ed, Ib"); + SETFLAGS(X_CF, SF_SUBSET); + SET_DFNONE(); + GETED(1); + u8 = F8; + u8 &= (rex.w ? 0x3f : 0x1f); + BSTRPICK_D(x4, ed, u8, u8); + if (la64_lbt) + X64_SET_EFLAGS(x4, X_CF); + else + BSTRINS_D(xFlags, x4, 0, 0); + BSTRINS_D(ed, xZR, u8, u8); + if (wback) { + SDxw(ed, wback, fixedaddress); + SMWRITE(); + } + MARK; + break; + default: + DEFAULT; + } + break; case 0xBC: INST_NAME("BSF Gd, Ed"); SETFLAGS(X_ZF, SF_SUBSET); diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c index 3dd04ede..9f23ed8c 100644 --- a/src/dynarec/la64/dynarec_la64_66.c +++ b/src/dynarec/la64/dynarec_la64_66.c @@ -94,6 +94,15 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_or16(dyn, ninst, x1, x2, x4, x2); EWBACK; break; + case 0x0B: + INST_NAME("OR Gw, Ew"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGW(x1); + GETEW(x2, 0); + emit_or16(dyn, ninst, x1, x2, x4, x5); + GWBACK; + break; case 0x0F: switch (rep) { case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break; @@ -451,6 +460,21 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xD3: nextop = F8; switch ((nextop >> 3) & 7) { + case 5: + if (opcode == 0xD1) { + INST_NAME("SHR Ew, 1"); + MOV32w(x2, 1); + } else { + INST_NAME("SHR Ew, CL"); + ANDI(x2, xRCX, 0x1f); + BEQ_NEXT(x2, xZR); + } + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + if (box64_dynarec_safeflags > 1) MAYSETFLAGS(); + GETEW(x1, 0); + emit_shr16(dyn, ninst, x1, x2, x5, x4, x6); + EWBACK; + break; case 4: case 6: if (opcode == 0xD1) { @@ -468,6 +492,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_shl16(dyn, ninst, x1, x2, x5, x4, x6); EWBACK; break; + case 7: + if (opcode == 0xD1) { + INST_NAME("SAR Ew, 1"); + MOV32w(x2, 1); + } else { + INST_NAME("SAR Ew, CL"); + ANDI(x2, xRCX, 0x1f); + BEQ_NEXT(x2, xZR); + } + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + if (box64_dynarec_safeflags > 1) + MAYSETFLAGS(); + GETSEW(x1, 0); + emit_sar16(dyn, ninst, x1, x2, x5, x4, x6); + EWBACK; + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_660f.c b/src/dynarec/la64/dynarec_la64_660f.c index 2929118a..c9a55984 100644 --- a/src/dynarec/la64/dynarec_la64_660f.c +++ b/src/dynarec/la64/dynarec_la64_660f.c @@ -255,6 +255,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int GETGX(v0, 1); VAND_V(v0, v0, q0); break; + case 0x55: + INST_NAME("ANDNPD Gx, Ex"); + nextop = F8; + GETEX(q0, 0, 0); + GETGX(v0, 1); + VANDN_V(v0, v0, q0); + break; + case 0x56: + INST_NAME("ORPD Gx, Ex"); + nextop = F8; + GETEX(q0, 0, 0); + GETGX(v0, 1); + VOR_V(v0, v0, q0); + break; case 0x57: INST_NAME("XORPD Gx, Ex"); nextop = F8; diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c index 9820a754..28f8b849 100644 --- a/src/dynarec/la64/dynarec_la64_emit_shift.c +++ b/src/dynarec/la64/dynarec_la64_emit_shift.c @@ -294,6 +294,65 @@ void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i } } +// emit SHR16 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch +void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + int64_t j64; + + IFX (X_PEND) { + ST_H(s2, xEmu, offsetof(x64emu_t, op2)); + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + SET_DF(s4, d_shr16); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX (X_ALL) { + X64_SRL_H(s1, s2); + } + + SRL_D(s1, s1, s2); + BSTRPICK_D(s1, s1, 15, 0); + + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + CLEAR_FLAGS(s3); + IFX (X_CF) { + ADDI_D(s3, s2, -1); + SRA_D(s3, s1, s3); + ANDI(s3, s3, 1); // LSB == F_CF + OR(xFlags, xFlags, s3); + } + IFX (X_OF) { + // OF flag is affected only on 1-bit shifts + // OF flag is set to the most-significant bit of the original operand + ADDI_D(s3, xZR, 1); + BNE(s2, s3, 4 + 3 * 4); + SRLI_D(s3, s1, 15); + SLLI_D(s3, s3, F_OF); + OR(xFlags, xFlags, s3); + } + + SRL_D(s1, s1, s2); + BSTRPICK_D(s1, s1, 15, 0); + + // SF should be unset + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} // emit SHR32 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) @@ -447,6 +506,63 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, } +// emit SAR16 instruction, from s1, shift s2 (!0 and and'd already), store result in s1 using s3, s4 and s5 as scratch +void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + int64_t j64; + + IFX (X_PEND) { + ST_H(s2, xEmu, offsetof(x64emu_t, op2)); + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + SET_DF(s4, d_sar8); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX (X_ALL) { + X64_SRA_H(s1, s2); + } + + SRL_D(s1, s1, s2); + BSTRPICK_D(s1, s1, 15, 0); + + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + CLEAR_FLAGS(s3); + IFX (X_CF) { + ADDI_D(s3, s2, -1); + SRA_D(s3, s1, s3); + ANDI(s3, s3, 1); // LSB == F_CF + OR(xFlags, xFlags, s3); + } + // For the SAR instruction, the OF flag is cleared for all 1-bit shifts. + // OF nop + IFX (X_SF) { + // SF is the same as the original operand + BGE(s1, xZR, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + + SRL_D(s1, s1, s2); + BSTRPICK_D(s1, s1, 15, 0); + + IFX (X_PEND) { + ST_H(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + // emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4) { diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c index 03e16a8b..545f4287 100644 --- a/src/dynarec/la64/dynarec_la64_f0.c +++ b/src/dynarec/la64/dynarec_la64_f0.c @@ -217,6 +217,40 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SMDMB(); } break; + case 5: // SUB + if (opcode == 0x81) { + INST_NAME("LOCK SUB Ed, Id"); + } else { + INST_NAME("LOCK SUB Ed, Ib"); + } + SETFLAGS(X_ALL, SF_SET_PENDING); + if (MODREG) { + if (opcode == 0x81) + i64 = F32S; + else + i64 = F8S; + ed = xRAX + (nextop & 7) + (rex.b << 3); + emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); + } else { + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1); + if (opcode == 0x81) + i64 = F32S; + else + i64 = F8S; + MARKLOCK; + LLxw(x1, wback, 0); + if (i64 > -2048 && i64 <= 2048) { + ADDIxw(x4, x1, -i64); + } else { + MOV64xw(x4, i64); + SUBxw(x4, x1, x4); + } + SCxw(x4, wback, 0); + BEQZ_MARKLOCK(x4); + IFX (X_ALL | X_PEND) + emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5, x6); + } + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_f20f.c b/src/dynarec/la64/dynarec_la64_f20f.c index e065c569..d9d474e6 100644 --- a/src/dynarec/la64/dynarec_la64_f20f.c +++ b/src/dynarec/la64/dynarec_la64_f20f.c @@ -33,7 +33,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int uint8_t u8; uint64_t u64, j64; int v0, v1; - int q0; + int q0, q1; int d0, d1; int64_t fixedaddress; int unscaled; @@ -229,6 +229,28 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int MARK; VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0] break; + case 0xC2: + INST_NAME("CMPSD Gx, Ex, Ib"); + nextop = F8; + GETGX(v0, 1); + GETEXSS(v1, 0, 1); + u8 = F8; + switch (u8 & 7) { + case 0: FCMP_D(fcc0, v0, v1, cEQ); break; // Equal + case 1: FCMP_D(fcc0, v0, v1, cLT); break; // Less than + case 2: FCMP_D(fcc0, v0, v1, cLE); break; // Less or equal + case 3: FCMP_D(fcc0, v0, v1, cUN); break; // NaN + case 4: FCMP_D(fcc0, v0, v1, cUNE); break; // Not Equal or unordered + case 5: FCMP_D(fcc0, v1, v0, cULE); break; // Greater or equal or unordered + case 6: FCMP_D(fcc0, v1, v0, cULT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted) + case 7: FCMP_D(fcc0, v0, v1, cOR); break; // not NaN + } + MOVCF2GR(x2, fcc0); + NEG_D(x2, x2); + q1 = fpu_get_scratch(dyn); + MOVGR2FR_D(q1, x2); + VEXTRINS_D(v0, q1, 0); + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index bebc24c6..a8bd4018 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -783,8 +783,10 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_shl32 STEPNAME(emit_shl32) #define emit_shl32c STEPNAME(emit_shl32c) #define emit_shr8 STEPNAME(emit_shr8) +#define emit_shr16 STEPNAME(emit_shr16) #define emit_shr32 STEPNAME(emit_shr32) #define emit_shr32c STEPNAME(emit_shr32c) +#define emit_sar16 STEPNAME(emit_sar16) #define emit_sar32c STEPNAME(emit_sar32c) #define emit_ror32c STEPNAME(emit_ror32c) #define emit_rol32 STEPNAME(emit_rol32) @@ -870,8 +872,10 @@ void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5); void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); +void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); +void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); |