diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-03-04 18:36:27 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-04 11:36:27 +0100 |
| commit | 61de3532c2fe1193e13c42080f434a6230cd83bd (patch) | |
| tree | f8a4f41f697ed4edfaf531d769192a55427dd168 /src | |
| parent | ddfc699809e5b1300692f23aeea30b1c82007495 (diff) | |
| download | box64-61de3532c2fe1193e13c42080f434a6230cd83bd.tar.gz box64-61de3532c2fe1193e13c42080f434a6230cd83bd.zip | |
[LA64_DYNAREC] Added more opcodes (#1321)
* [LA64_DYNAREC] Added 0F 80..8F Jcc opcodes * [LA64_DYNAREC] Added 31/33 XOR opcodes * [LA64_DYNAREC] Added 0F A2 CPUID opcode * [LA64_DYNAREC] Added 81/83 /4 AND opcode * [LA64_DYNAREC] Added 25 AND opcode * [LA64_DYNAREC] Added F7 /0 /1 TEST opcodes * Fix
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 48 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 51 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_logic.c | 116 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_tests.c | 57 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 7 | ||||
| -rw-r--r-- | src/dynarec/la64/la64_emitter.h | 3 |
6 files changed, 281 insertions, 1 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index d4b79011..c7374442 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -116,6 +116,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + case 0x25: + INST_NAME("AND EAX, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + i64 = F32S; + emit_and32c(dyn, ninst, rex, xRAX, i64, x3, x4); + break; case 0x28: INST_NAME("SUB Eb, Gb"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -167,6 +173,25 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni i64 = F32S; emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5); break; + case 0x31: + INST_NAME("XOR Ed, Gd"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGD; + GETED(0); + emit_xor32(dyn, ninst, rex, ed, gd, x3, x4); + if(ed!=gd) { + WBACK; + } + break; + case 0x33: + INST_NAME("XOR Gd, Ed"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGD; + GETED(0); + emit_xor32(dyn, ninst, rex, gd, ed, x3, x4); + break; case 0x39: INST_NAME("CMP Ed, Gd"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -289,6 +314,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); WBACK; break; + case 4: // AND + if (opcode == 0x81) { INST_NAME("AND Ed, Id"); } else { INST_NAME("AND Ed, Ib"); } + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED((opcode == 0x81) ? 4 : 1); + if (opcode == 0x81) i64 = F32S; else i64 = F8S; + emit_and32c(dyn, ninst, rex, ed, i64, x3, x4); + WBACK; + break; case 5: // SUB if (opcode == 0x81) { INST_NAME("SUB Ed, Id"); @@ -714,6 +747,21 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni *need_epilog = 0; *ok = 0; break; + case 0xF7: + nextop = F8; + switch ((nextop >> 3) & 7) { + case 0: + case 1: + INST_NAME("TEST Ed, Id"); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED(4); + i64 = F32S; + emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5); + break; + default: + DEFAULT; + } + break; case 0xFF: nextop = F8; switch ((nextop >> 3) & 7) { diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index 92f09657..9a320619 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -80,6 +80,57 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni nextop = F8; FAKEED; break; + + #define GO(GETFLAGS, NO, YES, F, I) \ + READFLAGS(F); \ + i32_ = F32S; \ + BARRIER(BARRIER_MAYBE); \ + JUMP(addr + i32_, 1); \ + if (la64_lbt && (opcode - 0x70) >= 0xC) { \ + X64_SET_EFLAGS(xFlags, F); \ + X64_SETJ(x1, I); \ + } else { \ + GETFLAGS; \ + } \ + if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \ + /* out of the block */ \ + i32 = dyn->insts[ninst].epilog - (dyn->native_size); \ + if (la64_lbt && (opcode - 0x70) >= 0xC) \ + BEQZ_safe(x1, i32); \ + else \ + B##NO##_safe(x1, i32); \ + if (dyn->insts[ninst].x64.jmp_insts == -1) { \ + if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \ + fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \ + jump_to_next(dyn, addr + i32_, 0, ninst, rex.is32bits); \ + } else { \ + CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \ + i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \ + B(i32); \ + } \ + } else { \ + /* inside the block */ \ + i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \ + if (la64_lbt && (opcode - 0x70) >= 0xC) \ + BNEZ_safe(x1, i32); \ + else \ + B##YES##_safe(x1, i32); \ + } + + GOCOND(0x80, "J", "Id"); + + #undef GO + + case 0xA2: + INST_NAME("CPUID"); + NOTEST(x1); + MV(A1, xRAX); + CALL_(my_cpuid, -1, 0); + // BX and DX are not synchronized durring the call, so need to force the update + LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX])); + LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX])); + break; + default: DEFAULT; } diff --git a/src/dynarec/la64/dynarec_la64_emit_logic.c b/src/dynarec/la64/dynarec_la64_emit_logic.c new file mode 100644 index 00000000..e1580e97 --- /dev/null +++ b/src/dynarec/la64/dynarec_la64_emit_logic.c @@ -0,0 +1,116 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <errno.h> + +#include "debug.h" +#include "box64context.h" +#include "dynarec.h" +#include "emu/x64emu_private.h" +#include "emu/x64run_private.h" +#include "x64run.h" +#include "x64emu.h" +#include "box64stack.h" +#include "callback.h" +#include "emu/x64run_private.h" +#include "x64trace.h" +#include "dynarec_native.h" + +#include "la64_printer.h" +#include "dynarec_la64_private.h" +#include "dynarec_la64_functions.h" +#include "dynarec_la64_helper.h" + + +// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) +{ + CLEAR_FLAGS(s3); + IFX(X_PEND) { + SET_DF(s4, rex.w ? d_xor64 : d_xor32); + } else IFX(X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX(X_ALL) { + if (rex.w) X64_XOR_D(s1, s2); else X64_XOR_W(s1, s2); + X64_GET_EFLAGS(s3, X_ALL); + OR(xFlags, xFlags, s3); + } + XOR(s1, s1, s2); + if (!rex.w && s1 != s2) ZEROUP(s1); + + IFX(X_PEND) + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + return; + } + + XOR(s1, s1, s2); + + // 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 && s1 != s2) { + 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 AND32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch +void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4) +{ + CLEAR_FLAGS(s3); + IFX(X_PEND) { + SET_DF(s3, rex.w ? d_tst64 : d_tst32); + } else IFX(X_ALL) { + SET_DFNONE(); + } + + IFXA(X_ALL, la64_lbt) { + MOV64xw(s3, c); + if (rex.w) X64_AND_D(s1, s3); else X64_AND_W(s1, s3); + X64_GET_EFLAGS(s4, X_ALL); + OR(xFlags, xFlags, s4); + } + + if (c >= 0 && c <= 4095) { + ANDI(s1, s1, c); + } else { + IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c); + AND(s1, s1, s3); // res = s1 & s2 + } + + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + + if (la64_lbt) return; + + IFX(X_SF) { + SRLI_D(s3, s1, rex.w ? 63 : 31); + 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); + } +} \ No newline at end of file diff --git a/src/dynarec/la64/dynarec_la64_emit_tests.c b/src/dynarec/la64/dynarec_la64_emit_tests.c index e6ab543e..fcb33eb2 100644 --- a/src/dynarec/la64/dynarec_la64_emit_tests.c +++ b/src/dynarec/la64/dynarec_la64_emit_tests.c @@ -247,4 +247,59 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int IFX(X_PF) { emit_pf(dyn, ninst, s3, s4, s5); } -} \ No newline at end of file +} + +// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch +void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5) +{ + CLEAR_FLAGS(s3); + IFX_PENDOR0 { + SET_DF(s3, rex.w ? d_tst64 : d_tst32); + } else { + SET_DFNONE(); + } + + + if (la64_lbt) { + IFX(X_ALL) { + MOV64xw(s3, c); + if (rex.w) X64_AND_D(s1, s3); else X64_AND_W(s1, s3); + X64_GET_EFLAGS(s3, X_ALL); + OR(xFlags, xFlags, s3); + } + + IFX_PENDOR0 { + if (c >= 0 && c <= 4095) { + ANDI(s3, s1, c); + } else { + IFX(X_ALL) { } else MOV64xw(s3, c); + AND(s3, s1, s3); + } + SDxw(s3, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + if (c >= 0 && c <= 4095) { + ANDI(s3, s1, c); + } else { + IFXA(X_ALL, la64_lbt) { } else MOV64xw(s3, c); + AND(s3, s1, s3); + } + + IFX_PENDOR0 { + SDxw(s3, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_SF) { + SRLI_D(s4, s3, rex.w ? 63 : 31); + BEQZ(s4, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX(X_ZF) { + BNEZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s3, s4, s5); + } +} diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index c844c049..e3c0c874 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -247,6 +247,7 @@ BEQZ(reg1, j64) #define IFX(A) if ((dyn->insts[ninst].x64.gen_flags & (A))) +#define IFXA(A, B) if ((dyn->insts[ninst].x64.gen_flags & (A)) && (B)) #define IFX_PENDOR0 if ((dyn->insts[ninst].x64.gen_flags & (X_PEND) || !dyn->insts[ninst].x64.gen_flags)) #define IFXX(A) if ((dyn->insts[ninst].x64.gen_flags == (A))) #define IFX2X(A, B) if ((dyn->insts[ninst].x64.gen_flags == (A) || dyn->insts[ninst].x64.gen_flags == (B) || dyn->insts[ninst].x64.gen_flags == ((A) | (B)))) @@ -465,6 +466,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_cmp8 STEPNAME(emit_cmp8) #define emit_cmp8_0 STEPNAME(emit_cmp8_0) #define emit_test32 STEPNAME(emit_test32) +#define emit_test32c STEPNAME(emit_test32c) #define emit_add32 STEPNAME(emit_add32) #define emit_add32c STEPNAME(emit_add32c) #define emit_add8 STEPNAME(emit_add8) @@ -473,6 +475,8 @@ 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_xor32 STEPNAME(emit_xor32) +#define emit_and32c STEPNAME(emit_and32c) #define emit_shr32c STEPNAME(emit_shr32c) #define emit_sar32c STEPNAME(emit_sar32c) @@ -509,6 +513,7 @@ void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s void emit_cmp8_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_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); +void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5); void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4); @@ -517,6 +522,8 @@ 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_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); +void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, 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_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/la64_emitter.h b/src/dynarec/la64/la64_emitter.h index 35b593ba..a53ccd47 100644 --- a/src/dynarec/la64/la64_emitter.h +++ b/src/dynarec/la64/la64_emitter.h @@ -264,6 +264,9 @@ f24-f31 fs0-fs7 Static registers Callee ADD_D(rd, rs1, scratch); \ } + +#define SEXT_W(rd, rs1) SLLI_W(rd, rs1, 0) + // if GR[rj] == GR[rd]: // PC = PC + SignExtend({imm16, 2'b0}, GRLEN) #define BEQ(rj, rd, imm18) EMIT(type_2RI16(0b010110, ((imm18)>>2), rj, rd)) |