diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-04-06 16:50:10 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-06 10:50:10 +0200 |
| commit | 24f9263fa4a9b7cf5fa6f07677bf7fa388e0ad54 (patch) | |
| tree | a8297308f658400b3518b882e8860ddd05e31d38 /src | |
| parent | 5f4f9337cdce67d7dfd437e8c8517c3b50d788f7 (diff) | |
| download | box64-24f9263fa4a9b7cf5fa6f07677bf7fa388e0ad54.tar.gz box64-24f9263fa4a9b7cf5fa6f07677bf7fa388e0ad54.zip | |
[LA64_DYNAREC] Added more opcodes (#1422)
* Added 1C SBB opcode * Added 3A CMP opcode * Added 38 CMP opcode * Added 81,83 /6 XOR opcode * Added F7 /4 MUL opcode
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 66 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_logic.c | 67 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_math.c | 67 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 6 |
4 files changed, 202 insertions, 4 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 69394021..676e8316 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -151,6 +151,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5); WBACK; break; + case 0x1C: + INST_NAME("SBB AL, Ib"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + u8 = F8; + ANDI(x1, xRAX, 0xff); + emit_sbb8c(dyn, ninst, x1, u8, x3, x4, x5, x6); + BSTRINS_D(xRAX, x1, 7, 0); + break; case 0x20: INST_NAME("AND Eb, Gb"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -268,6 +277,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_xor32(dyn, ninst, rex, gd, ed, x3, x4); break; + case 0x38: + INST_NAME("CMP Eb, Gb"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETEB(x1, 0); + GETGB(x2); + emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5, x6); + break; case 0x39: INST_NAME("CMP Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -284,6 +301,14 @@ uintptr_t dynarec64_00(dynarec_la64_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 0x3A: + INST_NAME("CMP Gb, Eb"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETEB(x1, 0); + GETGB(x2); + emit_cmp8(dyn, ninst, x2, x1, x3, x4, x5, x6); + break; case 0x3C: INST_NAME("CMP AL, Ib"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -501,6 +526,21 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); WBACK; break; + case 6: // XOR + if (opcode == 0x81) { + INST_NAME("XOR Ed, Id"); + } else { + INST_NAME("XOR Ed, Ib"); + } + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED((opcode == 0x81) ? 4 : 1); + if (opcode == 0x81) + i64 = F32S; + else + i64 = F8S; + emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4); + WBACK; + break; case 7: // CMP if (opcode == 0x81) { INST_NAME("CMP Ed, Id"); @@ -1303,6 +1343,32 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni 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); + GETED(0); + if (rex.w) { + if (ed == xRDX) + gd = x3; + else + gd = xRDX; + MULH_DU(gd, xRAX, ed); + MUL_D(xRAX, xRAX, ed); + if (gd != xRDX) { MV(xRDX, gd); } + } else { + AND(x3, xRAX, xMASK); + if (MODREG) { + AND(x4, ed, xMASK); + ed = x4; + } + MUL_D(xRDX, x3, ed); // 64 <- 32x32 + AND(xRAX, xRDX, xMASK); + SRLI_D(xRDX, xRDX, 32); + } + UFLAG_RES(xRAX); + UFLAG_OP1(xRDX); + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_emit_logic.c b/src/dynarec/la64/dynarec_la64_emit_logic.c index 34315330..9f4ce0e1 100644 --- a/src/dynarec/la64/dynarec_la64_emit_logic.c +++ b/src/dynarec/la64/dynarec_la64_emit_logic.c @@ -72,6 +72,73 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s } } + +// emit XOR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch +void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4) +{ + IFX (X_PEND) { + SET_DF(s4, rex.w ? d_xor64 : d_xor32); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX (X_ALL) { + MOV64xw(s3, c); + if (rex.w) + X64_XOR_D(s1, s3); + else + X64_XOR_W(s1, s3); + } + + if (c >= 0 && c <= 4095) { + XORI(s1, s1, c); + } else { + IFX (X_ALL) { + } else { + MOV64xw(s3, c); + } + XOR(s1, s1, s3); + } + if (!rex.w) { + ZEROUP(s1); + } + IFX (X_PEND) + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + return; + } + + if (c >= 0 && c <= 4095) { + XORI(s1, s1, c); + } else { + MOV64xw(s3, c); + XOR(s1, s1, s3); + } + + CLEAR_FLAGS(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); + } + if (!rex.w) { + ZEROUP(s1); + } + + IFX (X_PEND) { + SDxw(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 AND8 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_and8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4) { diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c index ce928edd..2e670bf4 100644 --- a/src/dynarec/la64/dynarec_la64_emit_math.c +++ b/src/dynarec/la64/dynarec_la64_emit_math.c @@ -268,8 +268,6 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4) ADD_D(s1, s1, s2); IFX(X_PEND) ST_H(s1, xEmu, offsetof(x64emu_t, res)); - - ANDI(s1, s1, 0xff); return; } @@ -338,7 +336,6 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i X64_ADD_B(s1, s4); } ADDI_D(s1, s1, c & 0xff); - ANDI(s1, s1, 0xff); IFX(X_PEND) ST_H(s1, xEmu, offsetof(x64emu_t, res)); @@ -418,7 +415,6 @@ void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i X64_SUB_B(s1, s2); } SUB_D(s1, s1, s2); - ANDI(s1, s1, 0xff); IFX(X_PEND) ST_H(s1, xEmu, offsetof(x64emu_t, res)); @@ -592,6 +588,69 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i } +// emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch +void emit_sbb8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + IFX (X_PEND) { + ST_B(s1, xEmu, offsetof(x64emu_t, op1)); + ST_B(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, d_sbb8); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + + if (la64_lbt) { + SBC_B(s3, s1, s2); + IFX (X_ALL) { + X64_SBC_B(s1, s2); + } + + MV(s1, s3); + IFX (X_PEND) + ST_B(s1, xEmu, offsetof(x64emu_t, res)); + return; + } + + + IFX (X_AF | X_CF | X_OF) { + // for later flag calculation + NOR(s5, xZR, s1); + } + + SUB_W(s1, s1, s2); + ANDI(s3, xFlags, 1 << F_CF); + SUB_W(s1, s1, s3); + ANDI(s1, s1, 0xff); + + CLEAR_FLAGS(s3); + IFX (X_PEND) { + ST_B(s1, xEmu, offsetof(x64emu_t, res)); + } + + CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 8); + IFX (X_SF) { + SRLI_D(s3, s1, 7); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX (X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX (X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + +// emit SBB8 instruction, from s1, constant c, store result in s1 using s3, s4, s5 and s6 as scratch +void emit_sbb8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s3, int s4, int s5, int s6) +{ + MOV32w(s6, c & 0xff); + emit_sbb8(dyn, ninst, s1, s6, s3, s4, s5); +} + + // emit SBB32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5) { diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index c0847af5..99c39ae5 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -616,12 +616,15 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_sub32c STEPNAME(emit_sub32c) #define emit_sub8 STEPNAME(emit_sub8) #define emit_sub8c STEPNAME(emit_sub8c) +#define emit_sbb8 STEPNAME(emit_sbb8) +#define emit_sbb8c STEPNAME(emit_sbb8c) #define emit_sbb32 STEPNAME(emit_sbb32) #define emit_neg32 STEPNAME(emit_neg32) #define emit_or32 STEPNAME(emit_or32) #define emit_or32c STEPNAME(emit_or32c) #define emit_or8 STEPNAME(emit_or8) #define emit_xor32 STEPNAME(emit_xor32) +#define emit_xor32c STEPNAME(emit_xor32c) #define emit_and8 STEPNAME(emit_and8) #define emit_and8c STEPNAME(emit_and8c) #define emit_and32 STEPNAME(emit_and32) @@ -679,11 +682,14 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_sub8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4, int s5); +void emit_sbb8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); +void emit_sbb8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6); void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3); void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4); void emit_or8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4); +void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4); void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_and8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_and8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); |