diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-03-11 19:27:52 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-11 12:27:52 +0100 |
| commit | ac0519a046e1517508051dbb13943a056123950a (patch) | |
| tree | e1cee0ec805f00c3bc8ea93ea7aced10c26bc88f /src/dynarec | |
| parent | 90a6306bbe2c853221e18a9a4eb5f79e2dafc186 (diff) | |
| download | box64-ac0519a046e1517508051dbb13943a056123950a.tar.gz box64-ac0519a046e1517508051dbb13943a056123950a.zip | |
[LA64_DYNAREC] Added more opcodes and some fixes (#1355)
* Added F0 B1 /0 LOCK CMPXCHG opcode * Added 0F BE MOVSX opcode * Added 81/83 /7 CMP opcodes * Fixed emit_shl32c * Added missing default * Added A0 MOV opcode
Diffstat (limited to 'src/dynarec')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 7 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 22 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_66.c | 26 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_shift.c | 18 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_tests.c | 86 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_f0.c | 40 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 21 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_shift.c | 6 |
8 files changed, 210 insertions, 16 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 0cb34c96..0f506da8 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -596,6 +596,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ZEROUP(xRAX); } break; + case 0xA0: + INST_NAME("MOV AL,Ob"); + if(rex.is32bits) u64 = F32; else u64 = F64; + MOV64z(x1, u64); + LD_BU(x2, x1, 0); + BSTRINS_D(xRAX, x2, 7, 0); + break; case 0xA8: INST_NAME("TEST AL, Ib"); SETFLAGS(X_ALL, SF_SET_PENDING); diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index ccd2c368..49119328 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -219,6 +219,28 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni LD_HU(gd, ed, fixedaddress); } break; + case 0xBE: + INST_NAME("MOVSX Gd, Eb"); + nextop = F8; + GETGD; + if (MODREG) { + if (rex.rex) { + wback = TO_LA64((nextop & 7) + (rex.b << 3)); + wb2 = 0; + } else { + wback = (nextop & 7); + wb2 = (wback >> 2) * 8; + wback = TO_LA64(wback & 3); + } + BSTRPICK_D(gd, wback, wb2 + 7, wb2); + EXT_W_B(gd, gd); + } else { + SMREAD(); + addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0); + LD_B(gd, ed, fixedaddress); + } + if (!rex.w) ZEROUP(gd); + break; default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_66.c b/src/dynarec/la64/dynarec_la64_66.c index 7f3cd96c..25023eb4 100644 --- a/src/dynarec/la64/dynarec_la64_66.c +++ b/src/dynarec/la64/dynarec_la64_66.c @@ -65,6 +65,32 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x81: + case 0x83: + nextop = F8; + switch ((nextop >> 3) & 7) { + case 7: // CMP + if (opcode == 0x81) { + INST_NAME("CMP Ew, Iw"); + } else { + INST_NAME("CMP Ew, Ib"); + } + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode == 0x81) ? 2 : 1); + if (opcode == 0x81) + i16 = F16S; + else + i16 = F8S; + if (i16) { + MOV64x(x2, i16); + emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6); + } else + emit_cmp16_0(dyn, ninst, x1, x3, x4); + break; + default: + DEFAULT; + } + break; case 0x89: INST_NAME("MOV Ew, Gw"); nextop = F8; diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c index b4d7ccdd..dff76a5a 100644 --- a/src/dynarec/la64/dynarec_la64_emit_shift.c +++ b/src/dynarec/la64/dynarec_la64_emit_shift.c @@ -91,23 +91,20 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s // emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5) { + if (!c) return; + IFX(X_PEND) { if (c) { MOV64x(s3, c); SDxw(s3, xEmu, offsetof(x64emu_t, op2)); - } else + } else { SDxw(xZR, xEmu, offsetof(x64emu_t, op2)); + } SDxw(s1, xEmu, offsetof(x64emu_t, op1)); SET_DF(s4, rex.w?d_shl64:d_shl32); } else IFX(X_ALL) { SET_DFNONE(); } - if(!c) { - IFX(X_PEND) { - SDxw(s1, xEmu, offsetof(x64emu_t, res)); - } - return; - } if(la64_lbt) { IFX(X_PEND) {} else { MOV64x(s3, c); } @@ -120,6 +117,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, SLLIxw(s1, s1, c); + if (!rex.w) ZEROUP(s1); IFX(X_PEND) { SDxw(s1, xEmu, offsetof(x64emu_t, res)); } @@ -127,9 +125,9 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, } CLEAR_FLAGS(s3); - IFX(X_CF|X_OF) { + IFX(X_CF | X_OF) { if (c > 0) { - SRLI_D(s3, s1, (rex.w?64:32)-c); + SRLI_D(s3, s1, (rex.w ? 64 : 32) - c); ANDI(s5, s3, 1); // LSB == F_CF IFX(X_CF) { OR(xFlags, xFlags, s5); @@ -156,7 +154,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, IFX(X_OF) { // OF flag is affected only on 1-bit shifts if (c == 1) { - SRLIxw(s3, s1, rex.w?63:31); + SRLIxw(s3, s1, rex.w ? 63 : 31); XOR(s3, s3, s5); SLLI_D(s3, s3, F_OF); OR(xFlags, xFlags, s3); diff --git a/src/dynarec/la64/dynarec_la64_emit_tests.c b/src/dynarec/la64/dynarec_la64_emit_tests.c index 916fdd38..1fbf9a7e 100644 --- a/src/dynarec/la64/dynarec_la64_emit_tests.c +++ b/src/dynarec/la64/dynarec_la64_emit_tests.c @@ -106,6 +106,92 @@ void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4) } } +// emit CMP16 instruction, from cmp s1, s2, using s3 and s4 as scratch +void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6) +{ + IFX_PENDOR0 { + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + ST_H(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s4, d_cmp16); + } else { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX(X_ALL) { + X64_SUB_H(s1, s2); + } + + IFX_PENDOR0 { + SUB_D(s6, s1, s2); + ST_H(s6, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + CLEAR_FLAGS(s3); + IFX(X_AF | X_CF | X_OF) { + // for later flag calculation + NOR(s5, s5, s1); + } + + // It's a cmp, we can't store the result back to s1. + SUB_D(s6, s1, s2); + IFX(X_ALL) { + BSTRPICK_D(s6, s6, 15, 0); + } + IFX_PENDOR0 { + ST_H(s6, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_SF) { + SRLI_D(s3, s6, 15); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 16); + IFX(X_ZF) { + BNEZ(s6, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s6, s3, s4); + } +} + +// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch +void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4) +{ + IFX_PENDOR0 { + ST_H(s1, xEmu, offsetof(x64emu_t, op1)); + ST_H(xZR, xEmu, offsetof(x64emu_t, op2)); + ST_H(s1, xEmu, offsetof(x64emu_t, res)); + SET_DF(s3, d_cmp16); + } else { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX(X_ALL) { + X64_SUB_H(s1, xZR); + } + return; + } + + CLEAR_FLAGS(s3); + IFX(X_SF) { + SRLI_D(s3, s1, 15); + 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 CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6) { diff --git a/src/dynarec/la64/dynarec_la64_f0.c b/src/dynarec/la64/dynarec_la64_f0.c index 9d1c19db..931701a6 100644 --- a/src/dynarec/la64/dynarec_la64_f0.c +++ b/src/dynarec/la64/dynarec_la64_f0.c @@ -55,6 +55,44 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x0F: nextop = F8; switch (nextop) { + case 0xB1: + switch (rep) { + case 0: + INST_NAME("LOCK CMPXCHG Ed, Gd"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGD; + if (MODREG) { + ed = TO_LA64((nextop & 7) + (rex.b << 3)); + wback = 0; + UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5, x6); } + MV(x1, ed); // save value + SUB_D(x2, x1, xRAX); + BNE_MARK2(x2, xZR); + MV(ed, gd); + MARK2; + MVxw(xRAX, x1); + } else { + SMDMB(); + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + MARKLOCK; + MV(x4, gd); + LLxw(x1, wback, 0); + SUBxw(x3, x1, xRAX); + BNEZ_MARK(x3); + // EAX == Ed + SCxw(x4, wback, 0); + BEQZ_MARKLOCK(x4); + MARK; + UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5, x6); } + MVxw(xRAX, x1); + SMDMB(); + } + break; + default: + DEFAULT; + } + break; case 0xC1: switch (rep) { case 0: @@ -135,6 +173,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SMDMB(); } break; + default: + DEFAULT; } break; default: diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index b1cb2fc0..db980487 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -105,6 +105,22 @@ LDz(x1, wback, fixedaddress); \ ed = x1; \ } +// GETEWW will use i for ed, and can use w for wback. +#define GETEWW(w, i, D) \ + if (MODREG) { \ + wback = TO_LA64((nextop & 7) + (rex.b << 3)); \ + BSTRPICK_D(i, wback, 15, 0); \ + ed = i; \ + wb1 = 0; \ + } else { \ + SMREAD(); \ + addr = geted(dyn, addr, ninst, nextop, &wback, w, i, &fixedaddress, rex, NULL, 1, D); \ + LD_HU(i, wback, fixedaddress); \ + ed = i; \ + wb1 = 1; \ + } +// GETEW will use i for ed, and can use r3 for wback. +#define GETEW(i, D) GETEWW(x3, i, D) // FAKEED like GETED, but doesn't get anything #define FAKEED \ @@ -390,6 +406,7 @@ #ifndef SET_HASCALLRET #define SET_HASCALLRET() #endif +#define UFLAG_IF if (dyn->insts[ninst].x64.gen_flags) #ifndef DEFAULT #define DEFAULT \ *ok = -1; \ @@ -472,6 +489,8 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define jump_to_next STEPNAME(jump_to_next) #define ret_to_epilog STEPNAME(ret_to_epilog) #define call_c STEPNAME(call_c) +#define emit_cmp16 STEPNAME(emit_cmp16) +#define emit_cmp16_0 STEPNAME(emit_cmp16_0) #define emit_cmp32 STEPNAME(emit_cmp32) #define emit_cmp32_0 STEPNAME(emit_cmp32_0) #define emit_cmp8 STEPNAME(emit_cmp8) @@ -528,8 +547,10 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3 void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex); void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg); void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6); +void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6); void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6); void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4); +void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4); void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4); void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); diff --git a/src/dynarec/rv64/dynarec_rv64_emit_shift.c b/src/dynarec/rv64/dynarec_rv64_emit_shift.c index 1db7344f..69e6a08f 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_shift.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_shift.c @@ -90,12 +90,6 @@ void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, SET_DFNONE(); } - if(!c) { - IFX(X_PEND) { - SDxw(s1, xEmu, offsetof(x64emu_t, res)); - } - return; - } IFX(X_CF|X_OF) { if (c > 0) { SRLI(s3, s1, (rex.w?64:32)-c); |