diff options
| author | Yang Liu <numbksco@gmail.com> | 2023-05-10 19:39:45 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-10 13:39:45 +0200 |
| commit | fe9e5bf21db4acca9b567f7ea36b084837ae7648 (patch) | |
| tree | 6d8a0dd24ab54f81a883db4dab21bdb2e699a7fe /src | |
| parent | 1ca4f6acf5aee62242447e34b8a243a23144f4c2 (diff) | |
| download | box64-fe9e5bf21db4acca9b567f7ea36b084837ae7648.tar.gz box64-fe9e5bf21db4acca9b567f7ea36b084837ae7648.zip | |
[RV64_DYNAREC] Added more opcodes and some fixes (#775)
* Added 64 C6 MOV opcode * Added 64 03 ADD opcode * Added 64 81,83 opcodes * Added D8 FDIV opcode * Added DB FUCOMI opcode * Fixed 66 0F 3A 09 ROUNDPD opcode * Fixed review
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_64.c | 155 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_660f.c | 65 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_d8.c | 10 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_db.c | 40 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 1 |
5 files changed, 242 insertions, 29 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_64.c b/src/dynarec/rv64/dynarec_rv64_64.c index c01f0260..dde8c972 100644 --- a/src/dynarec/rv64/dynarec_rv64_64.c +++ b/src/dynarec/rv64/dynarec_rv64_64.c @@ -64,6 +64,15 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni } switch(opcode) { + case 0x03: + INST_NAME("ADD Gd, Seg:Ed"); + SETFLAGS(X_ALL, SF_SET_PENDING); + grab_segdata(dyn, addr, ninst, x4, seg); + nextop = F8; + GETGD; + GETEDO(x4, 0, x5); + emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5); + break; case 0x2B: INST_NAME("SUB Gd, Seg:Ed"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -87,7 +96,92 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0x66: addr = dynarec64_6664(dyn, addr, ip, ninst, rex, seg, ok, need_epilog); break; - + case 0x81: + case 0x83: + nextop = F8; + grab_segdata(dyn, addr, ninst, x6, seg); + 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); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + SD(x6, xEmu, offsetof(x64emu_t, scratch)); + emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); + LD(x6, xEmu, offsetof(x64emu_t, scratch)); + WBACKO(x6); + break; + case 1: // OR + if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + emit_or32c(dyn, ninst, rex, ed, i64, x3, x4); + WBACKO(x6); + break; + case 2: // ADC + if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");} + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + MOV64xw(x5, i64); + SD(x6, xEmu, offsetof(x64emu_t, scratch)); + emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6); + LD(x6, xEmu, offsetof(x64emu_t, scratch)); + WBACKO(x6); + break; + case 3: // SBB + if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");} + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + MOV64xw(x5, i64); + SD(x6, xEmu, offsetof(x64emu_t, scratch)); + emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x6); + LD(x6, xEmu, offsetof(x64emu_t, scratch)); + WBACKO(x6); + break; + case 4: // AND + if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + emit_and32c(dyn, ninst, rex, ed, i64, x3, x4); + WBACKO(x6); + break; + case 5: // SUB + if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + SD(x6, xEmu, offsetof(x64emu_t, scratch)); + emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6); + LD(x6, xEmu, offsetof(x64emu_t, scratch)); + WBACKO(x6); + break; + case 6: // XOR + if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4); + WBACKO(x6); + break; + case 7: // CMP + if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");} + SETFLAGS(X_ALL, SF_SET_PENDING); + GETEDO(x6, (opcode==0x81)?4:1, x5); + if(opcode==0x81) i64 = F32S; else i64 = F8S; + if(i64) { + MOV64xw(x2, i64); + emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6); + } else + emit_cmp32_0(dyn, ninst, rex, ed, x3, x4); + break; + } + break; case 0x88: INST_NAME("MOV Seg:Eb, Gb"); grab_segdata(dyn, addr, ninst, x4, seg); @@ -160,6 +254,53 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni LDxw(gd, x4, fixedaddress); } break; + case 0xC6: + INST_NAME("MOV Seg:Eb, Ib"); + grab_segdata(dyn, addr, ninst, x4, seg); + nextop=F8; + if(MODREG) { // reg <= u8 + u8 = F8; + if(!rex.rex) { + ed = (nextop&7); + eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx + eb2 = (ed&4)>>2; // L or H + } else { + eb1 = xRAX+(nextop&7)+(rex.b<<3); + eb2 = 0; + } + + if (eb2) { + // load a mask to x3 (ffffffffffff00ff) + LUI(x3, 0xffffffffffff0); + ORI(x3, x3, 0xff); + // apply mask + AND(eb1, eb1, x3); + if(u8) { + if((u8<<8)<2048) { + ADDI(x4, xZR, u8<<8); + } else { + ADDI(x4, xZR, u8); + SLLI(x4, x4, 8); + } + OR(eb1, eb1, x4); + } + } else { + ANDI(eb1, eb1, 0xf00); // mask ffffffffffffff00 + ORI(eb1, eb1, u8); + } + } else { // mem <= u8 + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1); + u8 = F8; + if(u8) { + ADDI(x3, xZR, u8); + ed = x3; + } else + ed = xZR; + ADD(x4, wback, x4); + SB(ed, x4, fixedaddress); + SMWRITE2(); + } + break; case 0xC7: INST_NAME("MOV Seg:Ed, Id"); grab_segdata(dyn, addr, ninst, x4, seg); @@ -169,11 +310,15 @@ uintptr_t dynarec64_64(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni ed = xRAX+(nextop&7)+(rex.b<<3); MOV64xw(ed, i64); } else { // mem <= i32 - addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 4); + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 4); i64 = F32S; - MOV64xw(x3, i64); - ADD(x4, ed, x4); - SDxw(x3, x4, fixedaddress); + if(i64) { + MOV64xw(x3, i64); + ed = x3; + } else + ed = xZR; + ADD(x4, wback, x4); + SDxw(ed, x4, fixedaddress); SMWRITE2(); } break; diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c index bd9a4544..fec0cbd6 100644 --- a/src/dynarec/rv64/dynarec_rv64_660f.c +++ b/src/dynarec/rv64/dynarec_rv64_660f.c @@ -429,29 +429,50 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int v1 = fpu_get_scratch(dyn); MOV64x(x3, 1ULL << __DBL_MANT_DIG__); FCVTDL(d1, x3, RD_RTZ); - for (int i=0; i<2; ++i) { - FLD(d0, wback, fixedaddress+8*i); - FEQD(x4, d0, d0); - BNEZ_MARK(x4); - B_MARK3_nocond; - MARK; // d0 is not nan - FABSD(v1, d0); - FLTD(x4, v1, d1); - BNEZ_MARK2(x4); - B_MARK3_nocond; - MARK2; - if(u8&4) { - u8 = sse_setround(dyn, ninst, x4, x5); - FCVTLD(x5, d0, RD_DYN); - FCVTDL(d0, x5, RD_RTZ); - x87_restoreround(dyn, ninst, u8); - } else { - FCVTLD(x5, d0, round_round[u8&3]); - FCVTDL(d0, x5, RD_RTZ); - } - MARK3; - FSD(d0, gback, 8*i); + + // i = 0 + FLD(d0, wback, fixedaddress); + FEQD(x4, d0, d0); + BNEZ(x4, 8); + B_MARK_nocond; + // d0 is not nan + FABSD(v1, d0); + FLTD(x4, v1, d1); + BNEZ(x4, 8); + B_MARK_nocond; + if(u8&4) { + u8 = sse_setround(dyn, ninst, x4, x5); + FCVTLD(x5, d0, RD_DYN); + FCVTDL(d0, x5, RD_RTZ); + x87_restoreround(dyn, ninst, u8); + } else { + FCVTLD(x5, d0, round_round[u8&3]); + FCVTDL(d0, x5, RD_RTZ); } + MARK; + FSD(d0, gback, 0); + + // i = 1 + FLD(d0, wback, fixedaddress+8); + FEQD(x4, d0, d0); + BNEZ(x4, 8); + B_MARK2_nocond; + // d0 is not nan + FABSD(v1, d0); + FLTD(x4, v1, d1); + BNEZ(x4, 8); + B_MARK2_nocond; + if(u8&4) { + u8 = sse_setround(dyn, ninst, x4, x5); + FCVTLD(x5, d0, RD_DYN); + FCVTDL(d0, x5, RD_RTZ); + x87_restoreround(dyn, ninst, u8); + } else { + FCVTLD(x5, d0, round_round[u8&3]); + FCVTDL(d0, x5, RD_RTZ); + } + MARK2; + FSD(d0, gback, 8); break; case 0x0E: INST_NAME("PBLENDW Gx, Ex, Ib"); diff --git a/src/dynarec/rv64/dynarec_rv64_d8.c b/src/dynarec/rv64/dynarec_rv64_d8.c index c3c10166..246221ce 100644 --- a/src/dynarec/rv64/dynarec_rv64_d8.c +++ b/src/dynarec/rv64/dynarec_rv64_d8.c @@ -108,7 +108,15 @@ uintptr_t dynarec64_D8(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xE8 ... 0xEF: case 0xF0 ... 0xF7: - + INST_NAME("FDIV ST0, STx"); + v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7)); + v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7)); + if(ST_IS_F(0)) { + FDIVS(v1, v1, v2); + } else { + FDIVD(v1, v1, v2); + } + break; case 0xF8 ... 0xFF: DEFAULT; break; diff --git a/src/dynarec/rv64/dynarec_rv64_db.c b/src/dynarec/rv64/dynarec_rv64_db.c index 08abacfd..cc3eac61 100644 --- a/src/dynarec/rv64/dynarec_rv64_db.c +++ b/src/dynarec/rv64/dynarec_rv64_db.c @@ -150,7 +150,45 @@ uintptr_t dynarec64_DB(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 0xEE: case 0xEF: INST_NAME("FUCOMI ST0, STx"); - DEFAULT; + SETFLAGS(X_ALL, SF_SET); + SET_DFNONE(); + v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7)); + v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7)); + IFX(F_ZF | F_PF | F_CF) { + if(ST_IS_F(0)) { + FEQS(x5, v1, v1); + FEQS(x4, v2, v2); + AND(x5, x5, x4); + BEQZ(x5, 24); // undefined/NaN + FEQS(x5, v1, v2); + BNEZ(x5, 24); // equal + FLTS(x3, v1, v2); // x3 = (v1<v2)?1:0 + OR(xFlags, xFlags, x3); // CF is the least significant bit + J(16); // end + // NaN + ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF)); + J(8); // end + // equal + ORI(xFlags, xFlags, 1<<F_ZF); + // end + } else { + FEQD(x5, v1, v1); + FEQD(x4, v2, v2); + AND(x5, x5, x4); + BEQZ(x5, 24); // undefined/NaN + FEQD(x5, v1, v2); + BNEZ(x5, 24); // equal + FLTD(x3, v1, v2); // x3 = (v1<v2)?1:0 + OR(xFlags, xFlags, x3); // CF is the least significant bit + J(16); // end + // NaN + ORI(xFlags, xFlags, (1<<F_ZF) | (1<<F_PF) | (1<<F_CF)); + J(8); // end + // equal + ORI(xFlags, xFlags, 1<<F_ZF); + // end + } + } break; case 0xF0: case 0xF1: diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index fd9db950..fa0e0808 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -179,6 +179,7 @@ LDxw(x1, S, fixedaddress); \ ed = x1; \ } +#define WBACKO(O) if(wback) {ADD(O, wback, O); SDxw(ed, O, 0); SMWRITE2();} // FAKEED like GETED, but doesn't get anything #define FAKEED if(!MODREG) { \ |