From 4849ef020e233b4c370a878bc97df1a4cd6f792f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Oct 2026 20:07:01 +0200 Subject: [PATCH] Decode the unused bits of shifts and Allegrex bit ops as the PSP does srl/srlv rotate when the low bit of their unused field (rs or sa) is set and shift when it's clear, whatever the other bits hold (cpu/cpu_alu/shift_encodings). The interpreter treated values above 1 as invalid and the other cores shifted. The Allegrex bit ops decode only some bits of sa, so all 32 values are one of wsbh, wsbw, seb, seh and bitrev (cpu/cpu_alu/allegrex_encodings). AllegrexBitOp() gives the canonical one for every core. Special3 function 0x18 does nothing on the PSP, where it was decoded as an alias of 0x20. The interpreter dispatch is regenerated, and its generator now lists each instruction name once. CPUEquivalence no longer skips the srl/srlv encodings. Co-Authored-By: Claude Opus 5.5 --- Core/MIPS/ARM/ArmCompALU.cpp | 12 +++--- Core/MIPS/ARM64/Arm64CompALU.cpp | 12 +++--- Core/MIPS/IR/IRCompALU.cpp | 14 +++---- Core/MIPS/Interpreter.cpp | 36 +++++++---------- Core/MIPS/InterpreterDispatch.cpp | 42 +++++++++++++++++--- Core/MIPS/MIPSCodeUtils.h | 14 +++++++ Core/MIPS/MIPSDis.cpp | 6 +-- Core/MIPS/MIPSTables.cpp | 64 +++++++++++++++++++------------ Core/MIPS/x86/CompALU.cpp | 12 +++--- unittest/JitHarness.cpp | 8 ---- 10 files changed, 132 insertions(+), 88 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 19d24390cd..aa0b782732 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -519,10 +519,10 @@ namespace MIPSComp // WARNING : ROTR switch (op & 0x3f) { case 0: CompShiftImm(op, ST_LSL, sa); break; //sll - case 2: CompShiftImm(op, rs == 1 ? ST_ROR : ST_LSR, sa); break; //srl + case 2: CompShiftImm(op, (rs & 1) ? ST_ROR : ST_LSR, sa); break; //srl case 3: CompShiftImm(op, ST_ASR, sa); break; //sra case 4: CompShiftVar(op, ST_LSL); break; //sllv - case 6: CompShiftVar(op, fd == 1 ? ST_ROR : ST_LSR); break; //srlv + case 6: CompShiftVar(op, (fd & 1) ? ST_ROR : ST_LSR); break; //srlv case 7: CompShiftVar(op, ST_ASR); break; //srav default: @@ -602,7 +602,7 @@ namespace MIPSComp if (rd == 0) return; - switch ((op >> 6) & 31) { + switch (AllegrexBitOp(op)) { case 16: // seb // R(rd) = SignExtend8ToU32(R(rt)); if (gpr.IsImm(rt)) { gpr.SetImm(rd, SignExtend8ToU32(gpr.GetImm(rt))); @@ -656,8 +656,8 @@ namespace MIPSComp if (rd == 0) return; - switch (op & 0x3ff) { - case 0xA0: //wsbh + switch (AllegrexBitOp(op)) { + case 2: //wsbh if (gpr.IsImm(rt)) { gpr.SetImm(rd, ((gpr.GetImm(rt) & 0xFF00FF00) >> 8) | ((gpr.GetImm(rt) & 0x00FF00FF) << 8)); } else { @@ -665,7 +665,7 @@ namespace MIPSComp REV16(gpr.R(rd), gpr.R(rt)); } break; - case 0xE0: //wsbw + case 3: //wsbw if (gpr.IsImm(rt)) { gpr.SetImm(rd, swap32(gpr.GetImm(rt))); } else { diff --git a/Core/MIPS/ARM64/Arm64CompALU.cpp b/Core/MIPS/ARM64/Arm64CompALU.cpp index 97dcf62e0c..15d8d1fc4b 100644 --- a/Core/MIPS/ARM64/Arm64CompALU.cpp +++ b/Core/MIPS/ARM64/Arm64CompALU.cpp @@ -422,10 +422,10 @@ void Arm64Jit::Comp_ShiftType(MIPSOpcode op) { // WARNING : ROTR switch (op & 0x3f) { case 0: CompShiftImm(op, ST_LSL, sa); break; //sll - case 2: CompShiftImm(op, rs == 1 ? ST_ROR : ST_LSR, sa); break; //srl + case 2: CompShiftImm(op, (rs & 1) ? ST_ROR : ST_LSR, sa); break; //srl case 3: CompShiftImm(op, ST_ASR, sa); break; //sra case 4: CompShiftVar(op, ST_LSL); break; //sllv - case 6: CompShiftVar(op, fd == 1 ? ST_ROR : ST_LSR); break; //srlv + case 6: CompShiftVar(op, (fd & 1) ? ST_ROR : ST_LSR); break; //srlv case 7: CompShiftVar(op, ST_ASR); break; //srav default: DISABLE; @@ -493,7 +493,7 @@ void Arm64Jit::Comp_Allegrex(MIPSOpcode op) { if (rd == 0) return; - switch ((op >> 6) & 31) { + switch (AllegrexBitOp(op)) { case 16: // seb // R(rd) = SignExtend8ToU32(R(rt)); if (gpr.IsImm(rt)) { gpr.SetImm(rd, SignExtend8ToU32(gpr.GetImm(rt))); @@ -543,8 +543,8 @@ void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) { if (rd == 0) return; - switch (op & 0x3ff) { - case 0xA0: //wsbh + switch (AllegrexBitOp(op)) { + case 2: //wsbh if (gpr.IsImm(rt)) { gpr.SetImm(rd, ((gpr.GetImm(rt) & 0xFF00FF00) >> 8) | ((gpr.GetImm(rt) & 0x00FF00FF) << 8)); } else { @@ -552,7 +552,7 @@ void Arm64Jit::Comp_Allegrex2(MIPSOpcode op) { REV16(gpr.R(rd), gpr.R(rt)); } break; - case 0xE0: //wsbw + case 3: //wsbw if (gpr.IsImm(rt)) { gpr.SetImm(rd, swap32(gpr.GetImm(rt))); } else { diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index bcceaf4a33..61f96de403 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -212,13 +212,13 @@ void IRFrontend::Comp_ShiftType(MIPSOpcode op) { if (rd == MIPS_REG_ZERO) return; - // WARNING: srl/rotr and srlv/rotrv share encodings (differentiated using unused bits.) + // WARNING: srl/rotr and srlv/rotrv share encodings, told apart by the low bit of the unused field. switch (op & 0x3f) { case 0: CompShiftImm(op, IROp::ShlImm, sa); break; //sll - case 2: CompShiftImm(op, (rs == 1 ? IROp::RorImm : IROp::ShrImm), sa); break; //srl + case 2: CompShiftImm(op, ((rs & 1) ? IROp::RorImm : IROp::ShrImm), sa); break; //srl case 3: CompShiftImm(op, IROp::SarImm, sa); break; //sra case 4: CompShiftVar(op, IROp::Shl); break; //sllv - case 6: CompShiftVar(op, (sa == 1 ? IROp::Ror : IROp::Shr)); break; //srlv + case 6: CompShiftVar(op, ((sa & 1) ? IROp::Ror : IROp::Shr)); break; //srlv case 7: CompShiftVar(op, IROp::Sar); break; //srav default: @@ -292,7 +292,7 @@ void IRFrontend::Comp_Allegrex(MIPSOpcode op) { if (rd == MIPS_REG_ZERO) return; - switch ((op >> 6) & 31) { + switch (AllegrexBitOp(op)) { case 16: // seb // R(rd) = SignExtend8ToU32(R(rt)); ir.Write(IROp::Ext8to32, rd, rt); break; @@ -320,11 +320,11 @@ void IRFrontend::Comp_Allegrex2(MIPSOpcode op) { if (rd == MIPS_REG_ZERO) return; - switch (op & 0x3ff) { - case 0xA0: //wsbh + switch (AllegrexBitOp(op)) { + case 2: //wsbh ir.Write(IROp::BSwap16, rd, rt); break; - case 0xE0: //wsbw + case 3: //wsbw ir.Write(IROp::BSwap32, rd, rt); break; default: diff --git a/Core/MIPS/Interpreter.cpp b/Core/MIPS/Interpreter.cpp index 07ba2087f9..98554ebd11 100644 --- a/Core/MIPS/Interpreter.cpp +++ b/Core/MIPS/Interpreter.cpp @@ -967,34 +967,26 @@ namespace MIPSInt { { case 0: R(rd) = R(rt) << sa; break; //sll case 2: - if (_RS == 0) //srl - { - R(rd) = R(rt) >> sa; - break; - } - else if (_RS == 1) //rotr - { + // Only the low bit of the unused rs field counts (cpu/cpu_alu/shift_encodings). + if (_RS & 1) { //rotr R(rd) = __rotr(R(rt), sa); - break; + } else { //srl + R(rd) = R(rt) >> sa; } - else - goto wrong; + break; case 3: R(rd) = (u32)(((s32)R(rt)) >> sa); break; //sra case 4: R(rd) = R(rt) << (R(rs) & 0x1F); break; //sllv case 6: - if (_FD == 0) { //srlv - R(rd) = R(rt) >> (R(rs)&0x1F); - break; - } else if (_FD == 1) { // rotrv + // Same for the unused sa field. + if (_FD & 1) { // rotrv R(rd) = __rotr(R(rt), R(rs)); - break; - } else { - goto wrong; + } else { //srlv + R(rd) = R(rt) >> (R(rs) & 0x1F); } + break; case 7: R(rd) = (u32)(((s32)R(rt)) >> (R(rs) & 0x1F)); break; //srav default: - wrong: _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); break; } @@ -1011,7 +1003,7 @@ namespace MIPSInt { return; } - switch ((op >> 6) & 31) { + switch (AllegrexBitOp(op)) { case 16: // seb R(rd) = SignExtend8ToU32(R(rt)); break; @@ -1041,11 +1033,11 @@ namespace MIPSInt { return; } - switch (op & 0x3ff) { - case 0xA0: //wsbh + switch (AllegrexBitOp(op)) { + case 2: //wsbh R(rd) = ((R(rt) & 0xFF00FF00) >> 8) | ((R(rt) & 0x00FF00FF) << 8); break; - case 0xE0: //wsbw + case 3: //wsbw R(rd) = swap32(R(rt)); break; default: diff --git a/Core/MIPS/InterpreterDispatch.cpp b/Core/MIPS/InterpreterDispatch.cpp index 7902bf7ad6..6fd0f61ca9 100644 --- a/Core/MIPS/InterpreterDispatch.cpp +++ b/Core/MIPS/InterpreterDispatch.cpp @@ -399,19 +399,49 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) { case 4: MIPSInt::Int_Special3(mips, op); return 1; + // nop case 24: + MIPSInt::Int_Sync(mips, op); + return 1; case 32: { switch ((op.encoding >> 6) & 0x1f) { // wsbh, wsbw + case 0: + case 1: case 2: case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: MIPSInt::Int_Allegrex2(mips, op); return 1; // seb, bitrev, seh case 16: + case 17: + case 18: + case 19: case 20: + case 21: + case 22: + case 23: case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: MIPSInt::Int_Allegrex(mips, op); return 1; default: @@ -622,7 +652,7 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) { case 21: MIPSInt::Int_Vcmov(mips, op); return 2; - // vwbn, vwbn, vwbn, vwbn, vwbn, vwbn, vwbn, vwbn + // vwbn case 24: case 25: case 26: @@ -647,7 +677,7 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) { case 55: { switch ((op.encoding >> 23) & 0x7) { - // vpfxs, vpfxs, vpfxt, vpfxt, vpfxd, vpfxd + // vpfxs, vpfxt, vpfxd case 0: case 1: case 2: @@ -668,14 +698,14 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) { case 60: { switch ((op.encoding >> 21) & 0x1f) { - // vmmul, vmmul, vmmul, vmmul + // vmmul case 0: case 1: case 2: case 3: MIPSInt::Int_Vmmul(mips, op); return 2; - // v(h)tfm2, v(h)tfm2, v(h)tfm2, v(h)tfm2, v(h)tfm3, v(h)tfm3, v(h)tfm3, v(h)tfm3, v(h)tfm4, v(h)tfm4, v(h)tfm4, v(h)tfm4 + // v(h)tfm2, v(h)tfm3, v(h)tfm4 case 4: case 5: case 6: @@ -690,14 +720,14 @@ int ExecInstruction(MIPSState *mips, MIPSOpcode op) { case 15: MIPSInt::Int_Vtfm(mips, op); return 2; - // vmscl, vmscl, vmscl, vmscl + // vmscl case 16: case 17: case 18: case 19: MIPSInt::Int_Vmscl(mips, op); return 2; - // vcrsp.t/vqmul.q, vcrsp.t/vqmul.q, vcrsp.t/vqmul.q, vcrsp.t/vqmul.q + // vcrsp.t/vqmul.q case 20: case 21: case 22: diff --git a/Core/MIPS/MIPSCodeUtils.h b/Core/MIPS/MIPSCodeUtils.h index 79853a8020..7c55083be6 100644 --- a/Core/MIPS/MIPSCodeUtils.h +++ b/Core/MIPS/MIPSCodeUtils.h @@ -73,6 +73,20 @@ inline uint32_t SignExtend16ToU32(MIPSOpcode op) { return SignExtend16ToU32(op.encoding); } +// The Allegrex bit ops (special3, function 0x20) only decode some bits of the sa field, so every +// value is one of them (cpu/cpu_alu/allegrex_encodings). Returns the canonical sa: 2 wsbh, 3 wsbw, +// 16 seb, 20 bitrev, 24 seh. +inline int AllegrexBitOp(MIPSOpcode op) { + int sa = (op >> 6) & 31; + if (!(sa & 0x10)) { + return 2 | (sa & 1); + } + if (sa & 4) { + return 20; + } + return (sa & 8) ? 24 : 16; +} + namespace MIPSCodeUtils { u32 GetCallTarget(u32 addr); diff --git a/Core/MIPS/MIPSDis.cpp b/Core/MIPS/MIPSDis.cpp index 5fb8897ba0..68b0ff7cdb 100644 --- a/Core/MIPS/MIPSDis.cpp +++ b/Core/MIPS/MIPSDis.cpp @@ -254,9 +254,9 @@ namespace MIPSDis int rd = _RD; int sa = (op>>6) & 0x1F; const char *name = MIPSGetName(op); - if (((op & 0x3f) == 2) && rs == 1) + if (((op & 0x3f) == 2) && (rs & 1)) name = "rotr"; - if (((op & 0x3f) == 6) && sa == 1) + if (((op & 0x3f) == 6) && (sa & 1)) name = "rotrv"; snprintf(out, outSize, "%s\t%s, %s, 0x%X", name, RN(rd), RN(rt), sa); } @@ -267,7 +267,7 @@ namespace MIPSDis int rd = _RD; int sa = (op>>6) & 0x1F; const char *name = MIPSGetName(op); - if (((op & 0x3f) == 6) && sa == 1) + if (((op & 0x3f) == 6) && (sa & 1)) name = "rotrv"; snprintf(out, outSize, "%s\t%s, %s, %s", name, RN(rd), RN(rt), RN(rs)); } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index b16bed461a..b735d1082e 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -287,8 +287,8 @@ static const MIPSInstruction tableSpecial3[64] = // 011111 ..... ..... ..... ... //16 INVALID_X_8, //24 - // TODO: Is this right? Or should it only be 32? Comment above (24) was mistakenly 32 before. - ENCODING(ALLEGREX0), + // Does nothing, whatever the other fields hold (cpu/cpu_alu/allegrex_encodings). + INSTR("nop", JITFUNC(Comp_DoNothing), Dis_Generic, Int_Sync, 0), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, //32 ENCODING(ALLEGREX0), @@ -773,35 +773,46 @@ static const MIPSInstruction tableVFPU9[32] = // 110100 00010 xxxxx . ....... . INVALID, INVALID, INVALID, INVALID, }; -static const MIPSInstruction tableALLEGREX0[32] = // 011111 ..... ..... ..... xxxxx 100000 - or ending with 011000? +// Only some bits of the op are decoded, so every value is one of the five (see AllegrexBitOp). +static const MIPSInstruction tableALLEGREX0[32] = // 011111 ..... ..... ..... xxxxx 100000 { - INVALID, - INVALID, INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), - INVALID, INVALID, INVALID, INVALID, + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), //8 - INVALID_X_8, + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbh", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), + INSTR("wsbw", JITFUNC(Comp_Allegrex2), Dis_Allegrex2, Int_Allegrex2, IN_RT|OUT_RD), //16 - INSTR("seb", JITFUNC(Comp_Allegrex), Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD), - INVALID, - INVALID, - INVALID, + INSTR("seb", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seb", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seb", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seb", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), //20 - INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD), - INVALID, - INVALID, - INVALID, + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), //24 - INSTR("seh", JITFUNC(Comp_Allegrex), Dis_Allegrex,Int_Allegrex, IN_RT|OUT_RD), - INVALID, - INVALID, - INVALID, + INSTR("seh", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seh", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seh", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("seh", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), //28 - INVALID, - INVALID, - INVALID, - INVALID, + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), + INSTR("bitrev", JITFUNC(Comp_Allegrex), Dis_Allegrex, Int_Allegrex, IN_RT|OUT_RD), }; static const MIPSInstruction tableEMU[4] = { @@ -973,10 +984,15 @@ static void EmitDispatchLevel(std::string &out, MipsEncoding encoding, int inden if (instr.altEncoding == Instruc) { std::string names; + std::vector seen; for (u32 idx : group) { + std::string_view name = table[idx].name; + if (std::find(seen.begin(), seen.end(), name) != seen.end()) + continue; + seen.push_back(name); if (!names.empty()) names += ", "; - names += table[idx].name; + names += name; } out += ind + StringFromFormat("// %s\n", names.c_str()); for (u32 idx : group) diff --git a/Core/MIPS/x86/CompALU.cpp b/Core/MIPS/x86/CompALU.cpp index ae8f9a1596..3f8ecbbe95 100644 --- a/Core/MIPS/x86/CompALU.cpp +++ b/Core/MIPS/x86/CompALU.cpp @@ -706,11 +706,11 @@ namespace MIPSComp switch (op & 0x3f) { case 0: CompShiftImm(op, &XEmitter::SHL, &ShiftType_ImmLogicalLeft); break; - case 2: CompShiftImm(op, rs == 1 ? &XEmitter::ROR : &XEmitter::SHR, rs == 1 ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; // srl, rotr + case 2: CompShiftImm(op, (rs & 1) ? &XEmitter::ROR : &XEmitter::SHR, (rs & 1) ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; // srl, rotr case 3: CompShiftImm(op, &XEmitter::SAR, &ShiftType_ImmArithRight); break; // sra case 4: CompShiftVar(op, &XEmitter::SHL, &ShiftType_ImmLogicalLeft); break; //sllv - case 6: CompShiftVar(op, fd == 1 ? &XEmitter::ROR : &XEmitter::SHR, fd == 1 ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; //srlv + case 6: CompShiftVar(op, (fd & 1) ? &XEmitter::ROR : &XEmitter::SHR, (fd & 1) ? &ShiftType_ImmRotateRight : &ShiftType_ImmLogicalRight); break; //srlv case 7: CompShiftVar(op, &XEmitter::SAR, &ShiftType_ImmArithRight); break; //srav default: @@ -818,7 +818,7 @@ namespace MIPSComp if (rd == MIPS_REG_ZERO) return; - switch ((op >> 6) & 31) + switch (AllegrexBitOp(op)) { case 16: // seb // R(rd) = SignExtend8ToU32(R(rt)); if (gpr.IsImm(rt)) @@ -926,9 +926,9 @@ namespace MIPSComp if (rd == MIPS_REG_ZERO) return; - switch (op & 0x3ff) + switch (AllegrexBitOp(op)) { - case 0xA0: //wsbh + case 2: //wsbh if (gpr.IsImm(rt)) { u32 rtImm = gpr.GetImm(rt); gpr.SetImm(rd, ((rtImm & 0xFF00FF00) >> 8) | ((rtImm & 0x00FF00FF) << 8)); @@ -943,7 +943,7 @@ namespace MIPSComp ROR(32, gpr.R(rd), Imm8(16)); gpr.UnlockAll(); break; - case 0xE0: //wsbw + case 3: //wsbw if (gpr.IsImm(rt)) { gpr.SetImm(rd, swap32(gpr.GetImm(rt))); break; diff --git a/unittest/JitHarness.cpp b/unittest/JitHarness.cpp index 1acd47f431..7e58502e25 100644 --- a/unittest/JitHarness.cpp +++ b/unittest/JitHarness.cpp @@ -567,14 +567,6 @@ static u32 GenerateFuzzOp(FuzzRng &rng, const char *classes) { if (!IsFuzzableName(MIPSGetName(MIPSOpcode(op)))) { continue; } - // srl and srlv with other bits than rotr's set in the unused field: the interpreter does - // nothing, the rest shift. TODO: Test on hardware. - if (top == 0 && (op & 0x3F) == 2 && ((op >> 21) & 0x1F) > 1) { - continue; - } - if (top == 0 && (op & 0x3F) == 6 && ((op >> 6) & 0x1F) > 1) { - continue; - } // Not by MEMTYPE, which movz and movn alias with their CONDTYPE. if (std::find(std::begin(memOps), std::end(memOps), top) != std::end(memOps)) { op = FixupMemOp(op, rng);