diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2023-03-26 16:38:12 +0000 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2023-03-26 16:38:12 +0000 |
| commit | 9f282c2898c3597cc9198782b6782336201cd7d0 (patch) | |
| tree | 6dc5504e805403796c1e856b34cb2a7eecb2f809 /src | |
| parent | be3b95db6b1a3c0e3643ff818f33f84d176d4564 (diff) | |
| download | box64-9f282c2898c3597cc9198782b6782336201cd7d0.tar.gz box64-9f282c2898c3597cc9198782b6782336201cd7d0.zip | |
[RV64_DYNAREC] More opcodes, and a few fixes too
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00.c | 61 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_0f.c | 57 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 26 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_660f.c | 28 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_math.c | 60 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_f20f.c | 9 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 22 | ||||
| -rw-r--r-- | src/dynarec/rv64/rv64_emitter.h | 1 |
8 files changed, 259 insertions, 5 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00.c b/src/dynarec/rv64/dynarec_rv64_00.c index 3d393fdc..004707a1 100644 --- a/src/dynarec/rv64/dynarec_rv64_00.c +++ b/src/dynarec/rv64/dynarec_rv64_00.c @@ -79,6 +79,15 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5); break; + case 0x04: + INST_NAME("ADD AL, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); + u8 = F8; + ANDI(x1, xRAX, 0xff); + emit_add8c(dyn, ninst, x1, u8, x3, x4, x5); + ANDI(xRAX, xRAX, ~0xff); + OR(xRAX, xRAX, x1); + break; case 0x05: INST_NAME("ADD EAX, Id"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -217,6 +226,15 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_and32(dyn, ninst, rex, gd, ed, x3, x4); break; + case 0x24: + INST_NAME("AND AL, Ib"); + SETFLAGS(X_ALL, SF_SET_PENDING); + u8 = F8; + ANDI(x1, xRAX, 0xff); + emit_and8c(dyn, ninst, x1, u8, x3, x4); + ANDI(xRAX, xRAX, ~0xff); + OR(xRAX, xRAX, x1); + break; case 0x25: INST_NAME("AND EAX, Id"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -332,7 +350,14 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni GETED(0); emit_cmp32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6); break; - + case 0x3A: + INST_NAME("CMP Gb, Eb"); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETEB(x1, 0); + GETGB(x2); + emit_cmp8(dyn, ninst, x2, x1, x3, x4, x5, x6); + break; case 0x3B: INST_NAME("CMP Gd, Ed"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -699,6 +724,34 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni emit_test32(dyn, ninst, rex, ed, gd, x3, x4, x5); break; + case 0x87: + INST_NAME("(LOCK)XCHG Ed, Gd"); + nextop = F8; + if(MODREG) { + GETGD; + GETED(0); + MVxw(x1, gd); + MVxw(gd, ed); + MVxw(ed, x1); + } else { + GETGD; + addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + SMDMB(); + ANDI(x3, ed, (1<<(2+rex.w))-1); + BEQ_MARK(x3, xZR); + MARKLOCK; + LRxw(x1, ed, 1, 0); + SCxw(x3, gd, ed, 0, 1); + BNE_MARKLOCK(x3, xZR); + B_MARK2_nocond; + MARK; + LDxw(x1, ed, 0); + SDxw(gd, ed, 0); + MARK2; + SMDMB(); + MVxw(gd, x1); + } + break; case 0x88: INST_NAME("MOV Eb, Gb"); nextop = F8; @@ -1779,7 +1832,11 @@ uintptr_t dynarec64_00(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni WBACK; break; case 1: //DEC Ed - DEFAULT; + INST_NAME("DEC Ed"); + SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING); + GETED(0); + emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6); + WBACK; break; case 2: // CALL Ed INST_NAME("CALL Ed"); diff --git a/src/dynarec/rv64/dynarec_rv64_0f.c b/src/dynarec/rv64/dynarec_rv64_0f.c index 543ffae8..74f3379a 100644 --- a/src/dynarec/rv64/dynarec_rv64_0f.c +++ b/src/dynarec/rv64/dynarec_rv64_0f.c @@ -166,6 +166,40 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni FAKEED; break; + case 0x28: + INST_NAME("MOVAPS Gx,Ex"); + nextop = F8; + GETGX(x1); + GETEX(x2, 0); + LD(x3, wback, fixedaddress+0); + LD(x4, wback, fixedaddress+8); + SD(x3, gback, 0); + SD(x4, gback, 8); + break; + case 0x29: + INST_NAME("MOVAPS Ex,Gx"); + nextop = F8; + GETGX(x1); + GETEX(x2, 0); + LD(x3, gback, 0); + LD(x4, gback, 8); + SD(x3, wback, fixedaddress+0); + SD(x4, wback, fixedaddress+8); + if(!MODREG) + SMWRITE2(); + break; + + case 0x2B: + INST_NAME("MOVNTPS Ex,Gx"); + nextop = F8; + GETGX(x1); + GETEX(x2, 0); + LD(x3, gback, 0); + LD(x4, gback, 8); + SD(x3, wback, fixedaddress+0); + SD(x4, wback, fixedaddress+8); + break; + case 0x31: INST_NAME("RDTSC"); MESSAGE(LOG_DUMP, "Need Optimization\n"); @@ -286,6 +320,29 @@ uintptr_t dynarec64_0F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni LD(xRDX, xEmu, offsetof(x64emu_t, regs[_DX])); LD(xRBX, xEmu, offsetof(x64emu_t, regs[_BX])); break; + case 0xA3: + INST_NAME("BT Ed, Gd"); + SETFLAGS(X_CF, SF_SUBSET); + SET_DFNONE(); + nextop = F8; + GETGD; + if(MODREG) { + ed = xRAX+(nextop&7)+(rex.b<<3); + } else { + SMREAD(); + addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0); + SRAIxw(x1, gd, 5+rex.w); // r1 = (gd>>5) + SLLI(x1, x1, 2+rex.w); + ADD(x3, wback, x1); //(&ed)+=r1*4; + LDxw(x1, x3, fixedaddress); + ed = x1; + } + ANDI(x2, gd, rex.w?0x3f:0x1f); + SRL(x4, ed, x2); + ANDI(x4, x4, 1); + ANDI(xFlags, xFlags, ~1); //F_CF is 1 + OR(xFlags, xFlags, x4); + break; case 0xAE: nextop = F8; diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index c59325e2..74fdd47d 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -403,6 +403,32 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni OR(xRAX, xRAX, x1); break; + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + INST_NAME("MOV Reg, Iw"); + gd = xRAX+(opcode&7)+(rex.b<<3); + if(rex.w) { + u64 = F64; + MOV64x(gd, u64); + } else { + u16 = F16; + MOV64x(x1, ~0xffff); + AND(gd, gd, x1); + if(u16<2048) { + ORI(gd, gd, u16); + } else { + MOV32w(x1, u16); + OR(gd, gd, x1); + } + } + break; + case 0xC1: nextop = F8; switch((nextop>>3)&7) { diff --git a/src/dynarec/rv64/dynarec_rv64_660f.c b/src/dynarec/rv64/dynarec_rv64_660f.c index 5299f162..22c61359 100644 --- a/src/dynarec/rv64/dynarec_rv64_660f.c +++ b/src/dynarec/rv64/dynarec_rv64_660f.c @@ -80,6 +80,34 @@ uintptr_t dynarec64_660F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int GOCOND(0x40, "CMOV", "Gw, Ew"); #undef GO + case 0x6E: + INST_NAME("MOVD Gx, Ed"); + nextop = F8; + if(rex.w) { + GETGXSD_empty(v0); + } else { + GETGXSS_empty(v0); + } + GETED(0); + if(rex.w) { + FMVDX(v0, ed); + } else { + FMVWX(v0, ed); + SW(xZR, xEmu, offsetof(x64emu_t, xmm[gd])+4); + } + SD(xZR, xEmu, offsetof(x64emu_t, xmm[gd])+8); + break; + case 0x6F: + INST_NAME("MOVDQA Gx,Ex"); + nextop = F8; + GETGX(x1); + GETEX(x2, 0); + LD(x3, wback, fixedaddress+0); + LD(x4, wback, fixedaddress+8); + SD(x3, gback, 0); + SD(x4, gback, 8); + break; + case 0xAF: INST_NAME("IMUL Gw,Ew"); SETFLAGS(X_ALL, SF_PENDING); diff --git a/src/dynarec/rv64/dynarec_rv64_emit_math.c b/src/dynarec/rv64/dynarec_rv64_emit_math.c index e3125f31..5828fd47 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_math.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_math.c @@ -65,8 +65,8 @@ void emit_add32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s 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) + NOT(s5, s1); // s5 = ~res + AND(s3, s5, 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 @@ -612,6 +612,62 @@ void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s } } +// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch +void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, 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) { + SDxw(s1, xEmu, offsetof(x64emu_t, op1)); + SET_DF(s3, rex.w?d_dec64:d_dec32); + } 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 + } + + ADDIxw(s1, s1, -1); + + IFX(X_PEND) { + SDxw(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, rex.w?62:30); + 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); + } + } + IFX(X_SF) { + BGE(s1, xZR, 8); + ORI(xFlags, xFlags, 1 << F_SF); + } + if (!rex.w) { + ZEROUP(s1); + } + 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) { diff --git a/src/dynarec/rv64/dynarec_rv64_f20f.c b/src/dynarec/rv64/dynarec_rv64_f20f.c index 1cbe5d00..4eba1c3b 100644 --- a/src/dynarec/rv64/dynarec_rv64_f20f.c +++ b/src/dynarec/rv64/dynarec_rv64_f20f.c @@ -116,6 +116,15 @@ uintptr_t dynarec64_F20F(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int } break; + case 0x5C: + INST_NAME("SUBSD Gx, Ex"); + nextop = F8; + //TODO: fastnan handling + GETGXSD(v0); + GETEXSD(v1, 0); + FSUBD(v0, v0, v1); + break; + default: DEFAULT; diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index cb46cf2b..a21fa5c0 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -271,6 +271,11 @@ gd = ((nextop&0x38)>>3)+(rex.r<<3); \ a = sse_get_reg(dyn, ninst, x1, gd, 1) +// Get GX as a Single (might use x1), no fetching old value +#define GETGXSS_empty(a) \ + gd = ((nextop&0x38)>>3)+(rex.r<<3); \ + a = sse_get_reg_empty(dyn, ninst, x1, gd, 1) + // Get GX as a Double (might use x1) #define GETGXSD(a) \ gd = ((nextop&0x38)>>3)+(rex.r<<3); \ @@ -292,6 +297,17 @@ FLW(a, ed, fixedaddress); \ } +// Get Ex as a double, not a quad (warning, x1 get used, x2 might too) +#define GETEXSD(a, D) \ + if(MODREG) { \ + a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0); \ + } else { \ + SMREAD(); \ + a = fpu_get_scratch(dyn); \ + addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, D); \ + FLD(a, ed, fixedaddress); \ + } + // Will get pointer to GX in general register a, will purge SS or SD if loaded. can use gback as load address #define GETGX(a) \ gd = ((nextop&0x38)>>3)+(rex.r<<3); \ @@ -357,6 +373,8 @@ #define BNE_MARK(reg1, reg2) Bxx_gen(NE, MARK, reg1, reg2) // Branch to MARK if reg1!=0 (use j64) #define BNEZ_MARK(reg) BNE_MARK(reg, xZR) +// Branch to MARK instruction unconditionnal (use j64) +#define B_MARK_nocond Bxx_gen(__, MARK, 0, 0) // Branch to MARK if reg1<reg2 (use j64) #define BLT_MARK(reg1, reg2) Bxx_gen(LT, MARK, reg1, reg2) // Branch to MARK if reg1>=reg2 (use j64) @@ -369,6 +387,8 @@ #define BNEZ_MARK2(reg) BNE_MARK2(reg, xZR) // Branch to MARK2 if reg1<reg2 (use j64) #define BLT_MARK2(reg1, reg2) Bxx_gen(LT, MARK2, reg1,reg2) +// Branch to MARK instruction unconditionnal (use j64) +#define B_MARK2_nocond Bxx_gen(__, MARK2, 0, 0) // Branch to MARK3 if reg1==reg2 (use j64) #define BEQ_MARK3(reg1, reg2) Bxx_gen(EQ, MARK3, reg1, reg2) // Branch to MARK3 if reg1!=reg2 (use j64) @@ -826,7 +846,7 @@ void emit_and16(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3, int s4); void emit_inc32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5); //void emit_inc16(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); //void emit_inc8(dynarec_rv64_t* dyn, int ninst, int s1, int s3, int s4); -//void emit_dec32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, 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_dec8(dynarec_rv64_t* dyn, int ninst, int s1, 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); diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h index cda28da2..391c4a3d 100644 --- a/src/dynarec/rv64/rv64_emitter.h +++ b/src/dynarec/rv64/rv64_emitter.h @@ -132,6 +132,7 @@ f28–31 ft8–11 FP temporaries Caller #define JAL_gen(rd, imm21) J_type(imm21, rd, 0b1101111) // Unconditional branch, no return address set #define B(imm21) EMIT(JAL_gen(xZR, imm21)) +#define B__(reg1, reg2, imm21) B(imm21) // Unconditional branch, return set to xRA #define JAL(imm21) EMIT(JAL_gen(xRA, imm21)) |