diff options
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_0.c | 9 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_1.c | 3 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_2.c | 33 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_3.c | 18 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 56 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_emit_shift.c | 50 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_f0.c | 44 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.c | 34 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_helper.h | 6 |
9 files changed, 244 insertions, 9 deletions
diff --git a/src/dynarec/rv64/dynarec_rv64_00_0.c b/src/dynarec/rv64/dynarec_rv64_00_0.c index db9e7cf5..6cf6a342 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_0.c +++ b/src/dynarec/rv64/dynarec_rv64_00_0.c @@ -202,6 +202,15 @@ uintptr_t dynarec64_00_0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5); WBACK; break; + case 0x1B: + INST_NAME("SBB Gd, Ed"); + READFLAGS(X_CF); + SETFLAGS(X_ALL, SF_SET_PENDING); + nextop = F8; + GETGD; + GETED(0); + emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4, x5); + break; case 0x1C: INST_NAME("SBB AL, Ib"); READFLAGS(X_CF); diff --git a/src/dynarec/rv64/dynarec_rv64_00_1.c b/src/dynarec/rv64/dynarec_rv64_00_1.c index ee1e554f..3abb0444 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_1.c +++ b/src/dynarec/rv64/dynarec_rv64_00_1.c @@ -108,6 +108,9 @@ uintptr_t dynarec64_00_1(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int case 0x64: addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog); break; + case 0x65: + addr = dynarec64_64(dyn, addr, ip, ninst, rex, rep, _GS, ok, need_epilog); + break; case 0x66: addr = dynarec64_66(dyn, addr, ip, ninst, rex, rep, ok, need_epilog); break; diff --git a/src/dynarec/rv64/dynarec_rv64_00_2.c b/src/dynarec/rv64/dynarec_rv64_00_2.c index 4a6e6827..6f0ef03e 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_2.c +++ b/src/dynarec/rv64/dynarec_rv64_00_2.c @@ -403,7 +403,38 @@ uintptr_t dynarec64_00_2(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int } } break; - + case 0x8E: + INST_NAME("MOV Seg,Ew"); + nextop = F8; + if((nextop&0xC0)==0xC0) { + ed = xRAX+(nextop&7)+(rex.b<<3); + } else { + SMREAD(); + addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0); + LHU(x1, ed, fixedaddress); + ed = x1; + } + SW(ed, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3])); + SW(xZR, xEmu, offsetof(x64emu_t, segs_serial[(nextop&0x38)>>3])); + break; + case 0x8F: + INST_NAME("POP Ed"); + nextop = F8; + if(MODREG) { + POP1(xRAX+(nextop&7)+(rex.b<<3)); + } else { + POP1(x2); // so this can handle POP [ESP] and maybe some variant too + addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0); + if(ed==xRSP) { + SD(x2, ed, fixedaddress); + } else { + // complicated to just allow a segfault that can be recovered correctly + SUB(xRSP, xRSP, 8); + SD(x2, ed, fixedaddress); + ADD(xRSP, xRSP, 8); + } + } + break; case 0x90: case 0x91: case 0x92: diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c index a1e7421e..a19f3f68 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_3.c +++ b/src/dynarec/rv64/dynarec_rv64_00_3.c @@ -336,6 +336,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int #endif } break; + case 0xCF: + INST_NAME("IRET"); + SETFLAGS(X_ALL, SF_SET); // Not a hack, EFLAGS are restored + BARRIER(BARRIER_FLOAT); + iret_to_epilog(dyn, ninst, rex.w); + *need_epilog = 0; + *ok = 0; + break; case 0xD0: case 0xD2: // TODO: Jump if CL is 0 nextop = F8; @@ -410,7 +418,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int INST_NAME("ROR Ed, 1"); SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING); GETED(0); - emit_rol32c(dyn, ninst, rex, ed, rex.w?63:31, x3, x4); + emit_ror32c(dyn, ninst, rex, ed, 1, x3, x4); WBACK; if(!wback && !rex.w) ZEROUP(ed); break; @@ -452,6 +460,14 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int WBACK; if(!wback && !rex.w) ZEROUP(ed); break; + case 1: + INST_NAME("ROR Ed, CL"); + SETFLAGS(X_OF|X_CF, SF_SUBSET); + GETED(0); + emit_ror32(dyn, ninst, rex, ed, xRCX, x3, x4); + WBACK; + if(!wback && !rex.w) ZEROUP(ed); + break; case 4: case 6: INST_NAME("SHL Ed, CL"); diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index 8b4a94f5..320f58a0 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -445,6 +445,37 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni AND(x1, x1, x2); OR(xRAX, xRAX, x1); break; + case 0xA5: + if(rep) { + INST_NAME("REP MOVSW"); + CBZ_NEXT(xRCX); + ANDI(x1, xFlags, 1<<F_DF); + BNEZ_MARK2(x1); + MARK; // Part with DF==0 + LH(x1, xRSI, 0); + ADDI(xRSI, xRSI, 2); + SH(x1, xRDI, 0); + ADDI(xRDI, xRDI, 2); + SUBI(xRCX, xRCX, 1); + BNEZ_MARK(xRCX); + B_NEXT_nocond; + MARK2; // Part with DF==1 + LH(x1, xRSI, 0); + SUBI(xRSI, xRSI, 2); + SH(x1, xRDI, 0); + SUBI(xRDI, xRDI, 2); + SUBI(xRCX, xRCX, 1); + BNEZ_MARK2(xRCX); + // done + } else { + INST_NAME("MOVSD"); + GETDIR(x3, x1, 2); + LH(x1, xRSI, 0); + SH(x1, xRDI, 0); + ADD(xRSI, xRSI, x3); + ADD(xRDI, xRDI, x3); + } + break; case 0xA9: INST_NAME("TEST AX,Iw"); SETFLAGS(X_ALL, SF_SET_PENDING); @@ -454,6 +485,31 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SRLIW(x1, x1, 16); emit_test16(dyn, ninst, x1, x2, x3, x4, x5); break; + case 0xAB: + if(rep) { + INST_NAME("REP STOSW"); + CBZ_NEXT(xRCX); + ANDI(x1, xFlags, 1<<F_DF); + BNEZ_MARK2(x1); + MARK; // Part with DF==0 + SH(xRAX, xRDI, 0); + ADDI(xRDI, xRDI, 2); + SUBI(xRCX, xRCX, 1); + BNEZ_MARK(xRCX); + B_NEXT_nocond; + MARK2; // Part with DF==1 + SH(xRAX, xRDI, 0); + SUBI(xRDI, xRDI, 2); + SUBI(xRCX, xRCX, 1); + BNEZ_MARK2(xRCX); + // done + } else { + INST_NAME("STOSW"); + GETDIR(x3, x1, 2); + SH(xRAX, xRDI, 0); + ADD(xRDI, xRDI, x3); + } + break; case 0xB8: case 0xB9: case 0xBA: diff --git a/src/dynarec/rv64/dynarec_rv64_emit_shift.c b/src/dynarec/rv64/dynarec_rv64_emit_shift.c index be84894c..dbcc2d5f 100644 --- a/src/dynarec/rv64/dynarec_rv64_emit_shift.c +++ b/src/dynarec/rv64/dynarec_rv64_emit_shift.c @@ -307,7 +307,6 @@ void emit_sar32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, } } - // emit ROL32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) { @@ -337,8 +336,7 @@ void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s SDxw(s1, xEmu, offsetof(x64emu_t, res)); } IFX(X_CF) { - // F_CF=0 - ANDI(s4, s1, 1); + ANDI(s4, s1, 1<<F_CF); OR(xFlags, xFlags, s4); } IFX(X_OF) { @@ -352,6 +350,49 @@ void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s } } +// emit ROR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch +void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4) +{ + int64_t j64; + IFX(X_CF | X_OF) { + ANDI(xFlags, xFlags, ~(1UL<<F_CF | 1UL<<F_OF2)); + } + + IFX(X_PEND) { + SDxw(s2, xEmu, offsetof(x64emu_t, op2)); + SET_DF(s4, rex.w?d_ror64:d_ror32); + } else IFX(X_ALL) { + SET_DFNONE(); + } + + if(rex.w) { + ANDI(s4, s2, 0x3f); + } else { + ANDI(s4, s2, 0x1f); + } + SRLxw(s3, s1, s4); + NEG(s4, s4); + ADDI(s4, s4, rex.w?64:32); + SLLxw(s1, s1, s4); + OR(s1, s3, s1); + IFX(X_PEND) { + SDxw(s1, xEmu, offsetof(x64emu_t, res)); + } + IFX(X_CF) { + SRLI(s3, s1, rex.w?63:31); + AND(xFlags, xFlags, s3); + } + IFX(X_OF) { + ADDI(s3, xZR, 1); + BEQ_NEXT(s2, s3); + SRLIxw(s3, s1, rex.w?63:31); + XOR(s3, s3, s1); + ANDI(s3, s3, 1); + SLLI(s3, s3, F_OF2); + OR(xFlags, xFlags, s3); + } +} + // emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4) { @@ -379,8 +420,7 @@ void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, SDxw(s1, xEmu, offsetof(x64emu_t, res)); } IFX(X_CF) { - // F_CF=0 - ANDI(s4, s1, 1); + ANDI(s4, s1, 1<<F_CF); OR(xFlags, xFlags, s4); } IFX(X_OF) { diff --git a/src/dynarec/rv64/dynarec_rv64_f0.c b/src/dynarec/rv64/dynarec_rv64_f0.c index f5ae3950..6b230a55 100644 --- a/src/dynarec/rv64/dynarec_rv64_f0.c +++ b/src/dynarec/rv64/dynarec_rv64_f0.c @@ -323,6 +323,50 @@ uintptr_t dynarec64_F0(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni } SMDMB(); break; + case 0xFF: + nextop = F8; + switch((nextop>>3)&7) + { + case 0: // INC Ed + INST_NAME("LOCK INC Ed"); + SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING); + SMDMB(); + if(MODREG) { + ed = xRAX+(nextop&7)+(rex.b<<3); + emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6); + } else { + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + MARKLOCK; + LRxw(x1, wback, 1, 1); + ADDIxw(x4, x1, 1); + SCxw(x3, x4, wback, 1, 1); + BNEZ_MARKLOCK(x3); + IFX(X_ALL|X_PEND) + emit_inc32(dyn, ninst, rex, x1, x3, x4, x5, x6); + } + break; + case 1: // DEC Ed + INST_NAME("LOCK DEC Ed"); + SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING); + SMDMB(); + if(MODREG) { + ed = xRAX+(nextop&7)+(rex.b<<3); + emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6); + } else { + addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0); + MARKLOCK; + LRxw(x1, wback, 1, 1); + ADDIxw(x4, x1, -1); + SCxw(x3, x4, wback, 1, 1); + BNEZ_MARKLOCK(x3); + IFX(X_ALL|X_PEND) + emit_inc32(dyn, ninst, rex, x1, x3, x4, x5, x6); + } + break; + default: + DEFAULT; + } + break; default: DEFAULT; } diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c index a0f88502..37bcec29 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.c +++ b/src/dynarec/rv64/dynarec_rv64_helper.c @@ -383,6 +383,40 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n) CLEARIP(); } +void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits) +{ + //#warning TODO: is64bits + MAYUSE(ninst); + MESSAGE(LOG_DUMP, "IRet to epilog\n"); + // POP IP + NOTEST(x2); + POP1(xRIP); + // POP CS + POP1(x2); + SH(x2, xEmu, offsetof(x64emu_t, segs[_CS])); + MV(x1, xZR); + SD(x1, xEmu, offsetof(x64emu_t, segs_serial[_CS])); + SD(x1, xEmu, offsetof(x64emu_t, segs_serial[_SS])); + // POP EFLAGS + POP1(xFlags); + MOV32w(x1, 0x3F7FD7); + AND(xFlags, xFlags, x1); + ORI(xFlags, xFlags, 0x2); + SET_DFNONE(); + // POP RSP + POP1(x3); + // POP SS + POP1(x2); + SH(x2, xEmu, offsetof(x64emu_t, segs[_SS])); + // set new RSP + MV(xRSP, x3); + // Ret.... + MOV64x(x2, (uintptr_t)rv64_epilog); // epilog on purpose, CS might have changed! + SMEND(); + BR(x2); + CLEARIP(); +} + void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg) { MAYUSE(fnc); diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h index 189fa7bc..b3675745 100644 --- a/src/dynarec/rv64/dynarec_rv64_helper.h +++ b/src/dynarec/rv64/dynarec_rv64_helper.h @@ -836,7 +836,8 @@ void* rv64_next(x64emu_t* emu, uintptr_t addr); #define emit_shr32 STEPNAME(emit_shr32) #define emit_shr32c STEPNAME(emit_shr32c) #define emit_sar32c STEPNAME(emit_sar32c) -#define emit_rol32 STEPNAME(emit_rol32) +#define emit_rol32 STEPNAME(emit_rol32) +#define emit_ror32 STEPNAME(emit_ror32) #define emit_rol32c STEPNAME(emit_rol32c) #define emit_ror32c STEPNAME(emit_ror32c) #define emit_shrd32c STEPNAME(emit_shrd32c) @@ -899,7 +900,7 @@ void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst); void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst); void ret_to_epilog(dynarec_rv64_t* dyn, int ninst); void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, int n); -//void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits); +void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits); void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg); void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w); void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment); @@ -970,6 +971,7 @@ void emit_shr32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s 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); void emit_rol32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); +void emit_ror32(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4); void emit_rol32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_ror32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4); void emit_shrd32c(dynarec_rv64_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4); |