diff options
| author | Yang Liu <numbksco@gmail.com> | 2024-04-14 18:47:42 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-14 12:47:42 +0200 |
| commit | 7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab (patch) | |
| tree | b89c18dcde58ad2fdb24e3bc7206cdc039bb73bf /src | |
| parent | d936c072eaeac7d42f5846fb5d46815a4b0f84bf (diff) | |
| download | box64-7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab.tar.gz box64-7f16ddacf7707e8c8b696a62c5c4bd4b4d0695ab.zip | |
[LA64_DYNAREC] Added 1 more opcode and some fixes too (#1444)
* Added D3 /0 ROL opcode * Refined emit_sub32c * Fixed BSF and BSR
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 8 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_0f.c | 16 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_math.c | 2 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_shift.c | 55 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 12 |
5 files changed, 89 insertions, 4 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index afbe2555..72688d4f 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -1325,6 +1325,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xD3: nextop = F8; switch((nextop>>3)&7) { + case 0: + INST_NAME("ROL Ed, CL"); + SETFLAGS(X_OF | X_CF, SF_SUBSET); + GETED(0); + emit_rol32(dyn, ninst, rex, ed, xRCX, x3, x4); + WBACK; + if (!wback && !rex.w) ZEROUP(ed); + break; case 4: case 6: INST_NAME("SHL Ed, CL"); diff --git a/src/dynarec/la64/dynarec_la64_0f.c b/src/dynarec/la64/dynarec_la64_0f.c index ebb6561a..d7184f2c 100644 --- a/src/dynarec/la64/dynarec_la64_0f.c +++ b/src/dynarec/la64/dynarec_la64_0f.c @@ -418,7 +418,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni X64_SET_EFLAGS(xZR, X_ZF); } else { ADDI_D(x3, xZR, ~(1 << F_ZF)); - OR(xFlags, xFlags, x3); + AND(xFlags, xFlags, x3); } break; case 0xBD: @@ -433,10 +433,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ed = x4; } BNE_MARK(ed, xZR); - ORI(xFlags, xFlags, 1 << F_ZF); + 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; - ANDI(xFlags, xFlags, ~(1 << F_ZF)); + if (la64_lbt) { + X64_SET_EFLAGS(xZR, X_ZF); + } else { + ADDI_D(x3, xZR, ~(1 << F_ZF)); + AND(xFlags, xFlags, x3); + } if (rex.w) CLZ_D(gd, ed); else diff --git a/src/dynarec/la64/dynarec_la64_emit_math.c b/src/dynarec/la64/dynarec_la64_emit_math.c index ca26ecc8..4c5f194f 100644 --- a/src/dynarec/la64/dynarec_la64_emit_math.c +++ b/src/dynarec/la64/dynarec_la64_emit_math.c @@ -531,7 +531,6 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i SET_DFNONE(); } - CLEAR_FLAGS(s3); if (la64_lbt) { IFX(X_PEND) {} else {MOV64xw(s2, c);} IFX(X_ALL) { @@ -549,6 +548,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i return; } + CLEAR_FLAGS(s3); IFX(X_AF | X_CF | X_OF) { // for later flag calculation NOR(s5, xZR, s1); diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c index 477dee08..f5a3b213 100644 --- a/src/dynarec/la64/dynarec_la64_emit_shift.c +++ b/src/dynarec/la64/dynarec_la64_emit_shift.c @@ -444,3 +444,58 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, } } } + +// emit ROL32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) +{ + int64_t j64; + + IFX (X_PEND) { + SDxw(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s4, rex.w ? d_rol64 : d_rol32); + } else IFX (X_ALL) { + SET_DFNONE(); + } + + if (la64_lbt) { + IFX (X_ALL) { + if (rex.w) + X64_ROTL_D(s1, s2); + else + X64_ROTL_W(s1, s2); + } + } + + if (rex.w) { + ANDI(s4, s2, 0x3f); + } else { + ANDI(s4, s2, 0x1f); + } + + SLLxw(s3, s1, s4); + NEG_D(s4, s4); + ADDI_D(s4, s4, rex.w ? 64 : 32); + SRLxw(s1, s1, s4); + OR(s1, s3, s1); + + IFX (X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + + if (la64_lbt) return; + + CLEAR_FLAGS(s3); + IFX (X_CF | X_OF) { + ANDI(s4, s1, 1); // LSB == F_CF + IFX (X_CF) OR(xFlags, xFlags, s4); + } + IFX (X_OF) { + // the OF flag is set to the exclusive OR of the CF bit (after the rotate) and the most-significant bit of the result. + ADDI_D(s3, xZR, 1); + BNE_NEXT(s2, s3); + SRLIxw(s3, s1, rex.w ? 63 : 31); + XOR(s3, s3, s4); // s3: MSB, s4: CF bit + SLLI_D(s3, s3, F_OF); + OR(xFlags, xFlags, s3); + } +} diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index b44c6c88..2ec42225 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -419,6 +419,16 @@ j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \ B(j64) +// Branch to NEXT if reg1==reg2 (use j64) +#define BEQ_NEXT(reg1, reg2) \ + j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \ + BEQ(reg1, reg2, j64) + +// Branch to NEXT if reg1!=reg2 (use j64) +#define BNE_NEXT(reg1, reg2) \ + j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0; \ + BNE(reg1, reg2, j64) + // Branch to MARKSEG if reg is 0 (use j64) #define CBZ_MARKSEG(reg) \ j64 = GETMARKSEG - (dyn->native_size); \ @@ -708,6 +718,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_shr32c STEPNAME(emit_shr32c) #define emit_sar32c STEPNAME(emit_sar32c) #define emit_ror32c STEPNAME(emit_ror32c) +#define emit_rol32 STEPNAME(emit_rol32) #define emit_pf STEPNAME(emit_pf) @@ -782,6 +793,7 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s 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); 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); void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4); |