From a651cf33f4345dfda3a4e6071f5fcab978d5b6fb Mon Sep 17 00:00:00 2001 From: xctan Date: Tue, 14 Mar 2023 21:07:18 +0800 Subject: [RV64_DYNAREC] Added {81,83} /0 ADD opcode (#564) --- src/dynarec/rv64/dynarec_rv64_00.c | 8 +++ src/dynarec/rv64/dynarec_rv64_emit_math.c | 95 +++++++++++++++++++++++++++++++ src/dynarec/rv64/dynarec_rv64_helper.h | 2 +- src/dynarec/rv64/rv64_emitter.h | 6 ++ 4 files changed, 110 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index 563bdf6a..48e2ca27 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -106,6 +106,14 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x83: nextop = F8; switch((nextop>>3)&7) { + case 0: //ADD + if(opcode==0x81) {INST_NAME("ADD Ed, Id");} else {INST_NAME("ADD Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETED((opcode==0x81)?4:1); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); + WBACK; + break; case 5: if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");} SETFLAGS(X_ALL, SF_SET_PENDING); diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c index ca8b4349..424b9a9c 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_math.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c @@ -70,6 +70,101 @@ emit_pf(dyn, ninst, s1, s3, s4); \ } \ +// emit ADD32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch +void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5) +{ + CLEAR_FLAGS(); + if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND)) + { + // special case when doing math on ESP and only PEND is needed: ignoring it! + if(c >= -2048 && c < 2048) { + ADDIxw(s1, s1, c); + } else { + MOV64x(s2, c); + ADDxw(s1, s1, s2); + } + return; + } + IFX(X_PEND | X_AF | X_CF) { + MOV64x(s2, c); + } + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + SDxw(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s3, rex.w?d_add64:d_add32b); + } else IFX(X_ALL) { + SET_DFNONE(s3); + } + IFX(X_CF) { + if (rex.w) { + AND(s5, xMASK, s1); + AND(s4, xMASK, s2); + ADD(s5, s5, s4); // lo + SRLI(s3, s1, 0x20); + SRLI(s4, s2, 0x20); + ADD(s4, s4, s3); + SRLI(s5, s5, 0x20); + ADD(s5, s5, s4); // hi + SRAI(s5, s5, 0x20); + BEQZ(s5, 4); + ORI(xFlags, xFlags, 1 << F_CF); + } else { + ADD(s5, s1, s2); + SRLI(s5, s5, 0x20); + BEQZ(s5, 4); + ORI(xFlags, xFlags, 1 << F_CF); + } + } + IFX(X_AF | X_OF) { + OR(s3, s1, s2); // s3 = op1 | op2 + AND(s4, s1, s2); // s4 = op1 & op2 + } + + if(c >= -2048 && c < 2048) { + ADDIxw(s1, s1, c); + } else { + IFX(X_PEND | X_AF | X_CF) {} else {MOV64x(s2, c);} + ADDxw(s1, s1, s2); + } + + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_AF | X_OF) { + NOT(s2, s1); // s2 = ~res + AND(s3, s2, s3); // s3 = ~res & (op1 | op2) + OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2) + IFX(X_AF) { + ANDI(s4, s3, 0x08); // AF: cc & 0x08 + BEQZ(s4, 4); + ORI(xFlags, xFlags, 1 << F_AF); + } + IFX(X_OF) { + SRLI(s3, s3, rex.w?62:30); + SRLI(s4, s3, 1); + XOR(s3, s3, s4); + ANDI(s3, s3, 1); // OF: xor of two MSB's of cc + BEQZ(s3, 4); + ORI(xFlags, xFlags, 1 << F_OF); + } + } + IFX(X_SF) { + BGE(s1, xZR, 4); + ORI(xFlags, xFlags, 1 << F_SF); + } + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s4); + } + IFX(X_ZF) { + if (!rex.w) { + ZEROUP(s1); + } + BNEZ(s1, 4); + ORI(xFlags, xFlags, 1 << F_ZF); + } +} + + // emit SUB32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch void emit_sub32(dynarec_rv64_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_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index cdba7721..befeba12 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -338,7 +338,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst); //void emit_test16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_test32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); //void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); -//void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5); +void emit_add32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5); //void emit_add8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); //void emit_add8c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); void emit_sub32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index b95f7278..6b33560e 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -152,6 +152,10 @@ f28–31 ft8–11 FP temporaries Caller // rd = rs1 + rs2 #define ADD(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, 0b0110011)) +// rd = rs1 + rs2 +#define ADDW(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, 0b0111011)) +// rd = rs1 + rs2 +#define ADDxw(rd, rs1, rs2) EMIT(R_type(0b0000000, rs2, rs1, 0b000, rd, rex.w?0b0110011:0b0111011)) // rd = rs1 - rs2 #define SUB(rd, rs1, rs2) EMIT(R_type(0b0100000, rs2, rs1, 0b000, rd, 0b0110011)) // rd = rs1 - rs2 @@ -240,6 +244,8 @@ f28–31 ft8–11 FP temporaries Caller // rd = rs1 + imm12 #define ADDIW(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b000, rd, 0b0011011)) +// rd = rs1 + imm12 +#define ADDIxw(rd, rs1, imm12) EMIT(I_type((imm12)&0b111111111111, rs1, 0b000, rd, rex.w?0b0010011:0b0011011)) #define SEXT_W(rd, rs1) ADDIW(rd, rs1, 0) -- cgit 1.4.1