From 9e05a02bbf182f7f9554d00e2aa6c0cc6810f0d0 Mon Sep 17 00:00:00 2001 From: Yang Liu Date: Fri, 17 Mar 2023 14:55:14 +0800 Subject: [RV64_DYNAREC] Added C1 /(4/6) SHL opcode (#577) --- src/dynarec/rv64/dynarec_rv64_00.c | 9 ++++ src/dynarec/rv64/dynarec_rv64_emit_shift.c | 73 ++++++++++++++++++++++++++++-- src/dynarec/rv64/dynarec_rv64_helper.h | 2 +- src/dynarec/rv64/rv64_emitter.h | 2 + 4 files changed, 80 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index 90025fb4..a7d776aa 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -355,6 +355,15 @@ uintptr_t dynarec64_00(dynarec_rv64_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"); + 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); + if(u8) WBACK; + break; case 5: INST_NAME("SHR Ed, Ib"); SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined diff --git a/src/dynarec/rv64/dynarec_rv64_emit_shift.c b/src/dynarec/rv64/dynarec_rv64_emit_shift.c index db038011..eccf668b 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_shift.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_shift.c @@ -23,15 +23,76 @@ #include "dynarec_rv64_functions.h" #include "dynarec_rv64_helper.h" +// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch +void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5) +{ + CLEAR_FLAGS(); + 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(s4); + } + + if(!c) { + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + return; + } + IFX(X_CF) { + if (c > 0) { + SRLI(s3, s1, (rex.w?64:32)-c); + ANDI(s5, s3, 1); // LSB + BEQZ(s5, 8); + ORI(xFlags, xFlags, 1 << F_CF); + } else { + IFX(X_OF) MOV64x(s5, 0); + } + } + + 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) { + SRLIxw(s3, s1, rex.w?63:31); + XOR(s3, s3, s5); + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_OF2); + } + 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_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4) { CLEAR_FLAGS(); IFX(X_PEND) { - MOV64x(s3, c); + 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)); - SDxw(s3, xEmu, offsetof(x64emu_t, op2)); SET_DF(s4, rex.w?d_shr64:d_shr32); } else IFX(X_ALL) { SET_DFNONE(s4); @@ -92,9 +153,11 @@ void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, CLEAR_FLAGS(); IFX(X_PEND) { - MOV64x(s3, c); + 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)); - SDxw(s3, xEmu, offsetof(x64emu_t, op2)); SET_DF(s4, rex.w?d_sar64:d_sar32); } else IFX(X_ALL) { SET_DFNONE(s4); @@ -138,4 +201,4 @@ void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, IFX(X_PF) { emit_pf(dyn, ninst, s1, s3, s4); } -} \ No newline at end of file +} diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 741577d0..c917fda0 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -584,7 +584,7 @@ void emit_and32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i //void emit_neg16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); //void emit_neg8(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); //void emit_shl32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); -//void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); +void emit_shl32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5); //void emit_shr32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_shr32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index e920a9f9..4601bee6 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -279,6 +279,8 @@ f28–31 ft8–11 FP temporaries Caller // Shift Left Immediate, 32-bit, sign-extended #define SLLIW(rd, rs1, imm5) EMIT(I_type(imm5, rs1, 0b001, rd, 0b0011011)) +// Shift Left Immediate +#define SLLIxw(rd, rs1, imm) if (rex.w) { SLLI(rd, rs1, imm); } else { SLLIW(rd, rs1, imm); } // Shift Right Logical Immediate, 32-bit, sign-extended #define SRLIW(rd, rs1, imm5) EMIT(I_type(imm5, rs1, 0b101, rd, 0b0011011)) // Shift Right Logical Immediate -- cgit 1.4.1