diff options
| author | Haichen Wu <www.wxmqq@gmail.com> | 2024-03-08 00:49:24 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-07 17:49:24 +0100 |
| commit | 08e93a0fe9e89614b79dcb9ffda93916de0a20bf (patch) | |
| tree | dc7bc96a62665fd3d79e9cf6a09967da8482014c | |
| parent | 4096869c50722c69854a36016265fa86e7836089 (diff) | |
| download | box64-08e93a0fe9e89614b79dcb9ffda93916de0a20bf.tar.gz box64-08e93a0fe9e89614b79dcb9ffda93916de0a20bf.zip | |
[LA64_DYNAREC] Added C1 /4 and /6 opcodes and some fix (#1341)
* [LA64_DYNAREC] Added C1 /4 and /6 opcodes * [LA64_DYNAREC] Some fix of C1 opcodes
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 62 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_emit_shift.c | 79 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 2 | ||||
| -rw-r--r-- | src/dynarec/la64/la64_emitter.h | 7 |
4 files changed, 140 insertions, 10 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 8ad4a9d4..c0583e16 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -649,21 +649,63 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xC1: nextop = F8; switch ((nextop >> 3) & 7) { + case 4: + case 6: + INST_NAME("SHL Ed, Ib"); + u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20)); + if(u8) { + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED(1); + u8 = (F8) & (rex.w ? 0x3f : 0x1f); + emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4, x5); + WBACK; + } else { + if(MODREG && ! rex.w && !rex.is32bits) { + GETED(1); + AND(ed, ed, xMASK); + } else { + FAKEED; + } + F8; + } + break; case 5: INST_NAME("SHR Ed, Ib"); - SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined - GETED(1); - u8 = (F8) & (rex.w ? 0x3f : 0x1f); - emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4); - if (u8) { WBACK; } + u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20)); + if(u8) { + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED(1); + u8 = (F8) & (rex.w ? 0x3f : 0x1f); + emit_shr32c(dyn, ninst, rex, ed, u8, x3, x4); + WBACK; + } else { + if(MODREG && ! rex.w && !rex.is32bits) { + GETED(1); + AND(ed, ed, xMASK); + } else { + FAKEED; + } + F8; + } break; case 7: INST_NAME("SAR Ed, Ib"); - SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined - GETED(1); - u8 = (F8) & (rex.w ? 0x3f : 0x1f); - emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4); - if (u8) { WBACK; } + u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20)); + if(u8) { + SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined + GETED(1); + u8 = (F8) & (rex.w ? 0x3f : 0x1f); + emit_sar32c(dyn, ninst, rex, ed, u8, x3, x4); + WBACK; + } else { + if(MODREG && ! rex.w && !rex.is32bits) { + GETED(1); + AND(ed, ed, xMASK); + } else { + FAKEED; + } + F8; + } break; default: DEFAULT; diff --git a/src/dynarec/la64/dynarec_la64_emit_shift.c b/src/dynarec/la64/dynarec_la64_emit_shift.c index b2534c60..b4d7ccdd 100644 --- a/src/dynarec/la64/dynarec_la64_emit_shift.c +++ b/src/dynarec/la64/dynarec_la64_emit_shift.c @@ -88,6 +88,85 @@ 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) +{ + IFX(X_PEND) { + if (c) { + MOV64x(s3, c); + SDxw(s3, xEmu, offsetof(x64emu_t, op2)); + } 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); } + IFX(X_ALL) { + if (rex.w) + X64_SLL_D(s1, s3); + else + X64_SLL_W(s1, s3); + } + + SLLIxw(s1, s1, c); + + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + + CLEAR_FLAGS(s3); + IFX(X_CF|X_OF) { + if (c > 0) { + SRLI_D(s3, s1, (rex.w?64:32)-c); + ANDI(s5, s3, 1); // LSB == F_CF + IFX(X_CF) { + OR(xFlags, xFlags, s5); + } + } + } + + SLLIxw(s1, s1, c); + + IFX(X_SF) { + 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_OF) { + // OF flag is affected only on 1-bit shifts + if (c == 1) { + SRLIxw(s3, s1, rex.w?63:31); + XOR(s3, s3, s5); + SLLI_D(s3, s3, F_OF); + OR(xFlags, xFlags, s3); + } + } + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } +} + // emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch void emit_shr32c(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_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index fd07111b..a2503932 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -495,6 +495,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define emit_and32 STEPNAME(emit_and32) #define emit_and32c STEPNAME(emit_and32c) #define emit_shl32 STEPNAME(emit_shl32) +#define emit_shl32c STEPNAME(emit_shl32c) #define emit_shr32c STEPNAME(emit_shr32c) #define emit_sar32c STEPNAME(emit_sar32c) @@ -549,6 +550,7 @@ void emit_and8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s void emit_and32(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_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_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 b8c72ee7..51fbbf68 100644 --- a/src/dynarec/la64/la64_emitter.h +++ b/src/dynarec/la64/la64_emitter.h @@ -269,6 +269,13 @@ f24-f31 fs0-fs7 Static registers Callee // GR[rd] = ROTR(GR[rj][31:0], imm5) (Rotate To Right) #define ROTRI_W(rd, rj, imm5) EMIT(type_2RI5(0b00000000010011001, imm5, rj, rd)) +// Shift Left Immediate +#define SLLIxw(rd, rs1, imm) \ + if (rex.w) { \ + SLLI_D(rd, rs1, imm); \ + } else { \ + SLLI_W(rd, rs1, imm); \ + } // Shift Right Logical Immediate #define SRLIxw(rd, rs1, imm) \ if (rex.w) { \ |