diff options
| author | xctan <xctan@cirno.icu> | 2023-04-24 23:14:35 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-24 17:14:35 +0200 |
| commit | e64c542c6ad12b87c278382d17c118646ec76ae3 (patch) | |
| tree | 9a11d295197fbaf3b638b43949c556ce83e90bcc /src | |
| parent | 97ef3cccef04c4c21028fe464a0897871f694e9f (diff) | |
| download | box64-e64c542c6ad12b87c278382d17c118646ec76ae3.tar.gz box64-e64c542c6ad12b87c278382d17c118646ec76ae3.zip | |
[RV64_DYNAREC] Added more opcodes (#739)
* [RV64_DYNAREC] Added F0 0F C7 CMPXCHG8B/CMPXCHG16B opcode * [RV64_DYNAREC] Added 66 83 /3 SBB opcode * [RV64_DYNAREC] Added 66 FF /1 DEC opcode
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 17 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_math.c | 60 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_f0.c | 61 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 2 |
4 files changed, 136 insertions, 4 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index acafe265..7bc996e9 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -324,6 +324,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_adc16(dyn, ninst, x1, x5, x2, x4, x6); EWBACK; break; + case 3: // SBB + if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");} + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEW(x1, (opcode==0x81)?2:1); + if(opcode==0x81) i16 = F16S; else i16 = F8S; + MOV64x(x5, i16); + emit_sbb16(dyn, ninst, x1, x5, x2, x4, x6); + EWBACK; + break; case 4: // AND if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");} SETFLAGS(X_ALL, SF_SET_PENDING); @@ -787,6 +797,13 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_inc16(dyn, ninst, x1, x2, x4, x5); EWBACK; break; + case 1: + INST_NAME("DEC Ew"); + SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING); + GETEW(x1, 0); + emit_dec16(dyn, ninst, x1, x2, x4, x5, x6); + EWBACK; + break; default: DEFAULT; } diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c index d468e972..01579ea3 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_math.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c @@ -833,6 +833,61 @@ void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4) } } +// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch +void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) +{ + IFX(X_ALL) { + ANDI(xFlags, xFlags, ~((1UL<<F_AF) | (1UL<<F_OF2) | (1UL<<F_ZF) | (1UL<<F_SF) | (1UL<<F_PF))); + } + IFX(X_PEND) { + SH(s1, xEmu, offsetof(x64emu_t, op1)); + SET_DF(s3, d_dec16); + } else IFX(X_ALL) { + SET_DFNONE(); + } + IFX(X_AF | X_OF) { + NOT(s5, s1); + ORI(s3, s5, 1); // s3 = ~op1 | op2 + ANDI(s5, s5, 1); // s5 = ~op1 & op2 + } + + ADDIW(s1, s1, -1); + + IFX(X_PEND) { + SH(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_AF | X_OF) { + AND(s3, s1, s3); // s3 = res & (~op1 | op2) + OR(s3, s3, s5); // cc = (res & (~op1 | op2)) | (~op1 & op2) + IFX(X_AF) { + ANDI(s2, s3, 0x08); // AF: cc & 0x08 + BEQZ(s2, 8); + ORI(xFlags, xFlags, 1 << F_AF); + } + IFX(X_OF) { + SRLI(s3, s3, 14); + SRLI(s2, s3, 1); + XOR(s3, s3, s2); + ANDI(s3, s3, 1); // OF: xor of two MSB's of cc + BEQZ(s3, 8); + ORI(xFlags, xFlags, 1 << F_OF2); + } + } + SLLIW(s1, s1, 16); + IFX(X_SF) { + BGE(s1, xZR, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + SRLIW(s1, s1, 16); + IFX(X_PF) { + emit_pf(dyn, ninst, s1, s3, s2); + } + IFX(X_ZF) { + BNEZ(s1, 8); + ORI(xFlags, xFlags, 1 << F_ZF); + } +} + // emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch void emit_sbb8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5) { @@ -900,13 +955,12 @@ void emit_sbb16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, ANDI(s3, xFlags, 1 << F_CF); SUBW(s1, s1, s3); + SLLIW(s1, s1, 16); IFX(X_SF) { BGE(s1, xZR, 8); ORI(xFlags, xFlags, 1 << F_SF); } - - SLLI(s1, s1, 48); - SRLI(s1, s1, 48); + SRLIW(s1, s1, 16); IFX(X_PEND) { SH(s1, xEmu, offsetof(x64emu_t, res)); diff --git a/src/dynarec/rv64/dynarec_rv64_f0.c b/src/dynarec/rv64/dynarec_rv64_f0.c index 6b230a55..3ccaafa4 100644 --- a/src/dynarec/rv64/dynarec_rv64_f0.c +++ b/src/dynarec/rv64/dynarec_rv64_f0.c @@ -174,6 +174,67 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni DEFAULT; } break; + + case 0xC7: + switch(rep) { + case 0: + if (rex.w) { + INST_NAME("LOCK CMPXCHG16B Gq, Eq"); + } else { + INST_NAME("LOCK CMPXCHG8B Gq, Eq"); + } + SETFLAGS(X_ZF, SF_SUBSET); + nextop = F8; + addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, LOCK_LOCK, 0, 0); + ANDI(xFlags, xFlags, ~(1<<F_ZF)); + if (rex.w) { + // there is no atomic move on 16bytes, so faking it + SMDMB(); + // MARKLOCK; + LD(x2, wback, 0); + LD(x3, wback, 8); + BNE_MARK(x2, xRAX); + BNE_MARK(x3, xRDX); + SD(xRBX, wback, 0); + SD(xRCX, wback, 8); + ORI(xFlags, xFlags, 1<<F_ZF); + B_MARK3_nocond; + MARK; + MV(xRAX, x2); + MV(xRDX, x3); + MARK3; + SMDMB(); + } else { + SMDMB(); + MARKLOCK; + LR_D(x2, wback, 1, 1); + AND(x3, x2, xMASK); + AND(x4, xRAX, xMASK); + SRLI(x5, x2, 32); + AND(x6, xRDX, xMASK); + BNE_MARK(x3, x4); // EAX != Ed[0] + BNE_MARK(x5, x6); // EDX != Ed[1] + SLLI(x2, xRCX, 32); + AND(x3, xRBX, xMASK); + OR(x2, x2, x3); + SC_D(x3, x2, wback, 1, 1); + BNEZ_MARKLOCK(x3); + ORI(xFlags, xFlags, 1<<F_ZF); + B_MARK3_nocond; + MARK; + ADDI(xRAX, x3, 0); + ADDI(xRDX, x5, 0); + AND(xRAX, xRAX, xMASK); + AND(xRDX, xRDX, xMASK); + MARK3; + SMDMB(); + } + break; + default: + DEFAULT; + } + break; + default: DEFAULT; } diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 7fb1cdc9..b12ee96b 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -948,7 +948,7 @@ void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_inc8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); -//void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); +void emit_dec16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5); void emit_dec8(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_adc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); //void emit_adc32c(dynarec_rv64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4); |