diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp index 421287d7dd..2b56b65251 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -11,6 +11,136 @@ u32 PPUDisAsm::disasm(u32 pc) return 4; } +constexpr std::pair get_BC_info(u32 bo, u32 bi) +{ + std::pair info{}; + + switch (bo) + { + case 0b00000: + case 0b00001: + { + info = {"bdnzf", 'f'}; break; + } + case 0b00010: + case 0b00011: + { + info = {"bdzf", 'f'}; break; + } + case 0b01000: + case 0b01001: + { + info = {"bdnzt", 't'}; break; + } + case 0b01010: + case 0b01011: + { + info = {"bdzt", 't'}; break; + } + case 0b10010: + { + info.first = "bdz"; break; + } + case 0b11010: + { + info = {"bdz", '-'}; break; + } + case 0b11011: + { + info = {"bdz", '+'}; break; + } + case 0b10000: + { + info.first = "bdnz"; break; + } + case 0b11000: + { + info = {"bdnz", '-'}; break; + } + case 0b11001: + { + info = {"bdnz", '+'}; break; + } + case 0b00100: + { + switch (bi % 4) + { + case 0x0: info.first = "bge"; break; + case 0x1: info.first = "ble"; break; + case 0x2: info.first = "bne"; break; + case 0x3: info.first = "bns"; break; + default: ASSUME(0); break; + } + } + case 0b00110: + { + info.second = '-'; + switch (bi % 4) + { + case 0x0: info.first = "bge"; break; + case 0x1: info.first = "ble"; break; + case 0x2: info.first = "bne"; break; + case 0x3: info.first = "bns"; break; + default: ASSUME(0); break; + } + } + case 0b00111: + { + info.second = '+'; + switch (bi % 4) + { + case 0x0: info.first = "bge"; break; + case 0x1: info.first = "ble"; break; + case 0x2: info.first = "bne"; break; + case 0x3: info.first = "bns"; break; + default: ASSUME(0); break; + } + } + case 0b01100: + { + switch (bi % 4) + { + case 0x0: info.first = "blt"; break; + case 0x1: info.first = "bgt"; break; + case 0x2: info.first = "beq"; break; + case 0x3: info.first = "bso"; break; + default: ASSUME(0); break; + } + } + case 0b01110: + { + info.second = '-'; + switch (bi % 4) + { + case 0x0: info.first = "blt"; break; + case 0x1: info.first = "bgt"; break; + case 0x2: info.first = "beq"; break; + case 0x3: info.first = "bso"; break; + default: ASSUME(0); break; + } + } + case 0b01111: + { + info.second = '+'; + switch (bi % 4) + { + case 0x0: info.first = "blt"; break; + case 0x1: info.first = "bgt"; break; + case 0x2: info.first = "beq"; break; + case 0x3: info.first = "bso"; break; + default: ASSUME(0); break; + } + } + //case 0b10100: + //{ + // info.first = "b"; break; + //} + default: break; + } + + return info; +} + void PPUDisAsm::MFVSCR(ppu_opcode_t op) { DisAsm_V1("mfvscr", op.vd); @@ -804,122 +934,38 @@ void PPUDisAsm::BC(ppu_opcode_t op) return; } - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - const u8 bo4 = (bo & 0x01) ? 1 : 0; + const auto [inst, sign] = get_BC_info(bo, bi); - std::add_pointer_t inst{""}, sign = inst; - - if (bo0 && !bo1 && !bo2 && bo3 && !bo4) + if (!inst) { - inst = "bdz"; - } - else if (bo0 && bo1 && !bo2 && bo3 && !bo4) - { - inst = "bdz", sign = "-"; - } - else if (bo0 && bo1 && !bo2 && bo3 && bo4) - { - inst = "bdz", sign = "+"; - } - else if (bo0 && !bo1 && !bo2 && !bo3 && !bo4) - { - inst = "bdnz"; - } - else if (bo0 && bo1 && !bo2 && !bo3 && !bo4) - { - inst = "bdnz", sign = "-"; - } - else if (bo0 && bo1 && !bo2 && !bo3 && bo4) - { - inst = "bdnz", sign = "+"; - } - else if (!bo0 && !bo1 && bo2 && !bo3 && !bo4) - { - switch (bi % 4) - { - case 0x0: inst = "bge"; break; - case 0x1: inst = "ble"; break; - case 0x2: inst = "bne"; break; - case 0x3: inst = "bns"; break; - default: ASSUME(0); break; - } - } - else if (!bo0 && !bo1 && bo2 && bo3 && !bo4) - { - sign = "-"; - switch (bi % 4) - { - case 0x0: inst = "bge"; break; - case 0x1: inst = "ble"; break; - case 0x2: inst = "bne"; break; - case 0x3: inst = "bns"; break; - default: ASSUME(0); break; - } - } - else if (!bo0 && !bo1 && bo2 && bo3 && bo4) - { - sign = "+"; - switch (bi % 4) - { - case 0x0: inst = "bge"; break; - case 0x1: inst = "ble"; break; - case 0x2: inst = "bne"; break; - case 0x3: inst = "bns"; break; - default: ASSUME(0); break; - } - } - else if (!bo0 && bo1 && bo2 && !bo3 && !bo4) - { - switch (bi % 4) - { - case 0x0: inst = "blt"; break; - case 0x1: inst = "bgt"; break; - case 0x2: inst = "beq"; break; - case 0x3: inst = "bso"; break; - default: ASSUME(0); break; - } - } - else if (!bo0 && bo1 && bo2 && bo3 && !bo4) - { - sign = "-"; - switch (bi % 4) - { - case 0x0: inst = "blt"; break; - case 0x1: inst = "bgt"; break; - case 0x2: inst = "beq"; break; - case 0x3: inst = "bso"; break; - default: ASSUME(0); break; - } - } - else if (!bo0 && bo1 && bo2 && bo3 && bo4) - { - sign = "+"; - switch (bi % 4) - { - case 0x0: inst = "blt"; break; - case 0x1: inst = "bgt"; break; - case 0x2: inst = "beq"; break; - case 0x3: inst = "bso"; break; - default: ASSUME(0); break; - } - } - else - { - return Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); + Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); + return; } - const auto msg = std::string(inst) + (lk ? "l" : "") + (aa ? "a" : "") + sign; + const auto final = std::string(inst) + (lk ? "l" : "") + (aa ? "a" : "") + sign; + + // Check if need to display full BI value + if (sign == 't' || sign == 'f') + { + if (aa) + { + DisAsm_BI_BRANCH_A(final, bi, bd); + } + else + { + DisAsm_BI_BRANCH(final, bi, bd); + } + + return; + } if (aa) { - DisAsm_CR_BRANCH_A(msg, bi / 4, bd); + DisAsm_CR_BRANCH_A(final, bi / 4, bd); } else { - DisAsm_CR_BRANCH(msg, bi / 4, bd); + DisAsm_CR_BRANCH(final, bi / 4, bd); } } @@ -974,14 +1020,33 @@ void PPUDisAsm::BCLR(ppu_opcode_t op) { const u32 bo = op.bo; const u32 bi = op.bi; + const u32 bh = op.bh; + const u32 lk = op.lk; - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; + if (bo == 0b10100) + { + Write(lk ? "blrl" : "blr"); + return; + } - if (bo0 && !bo1 && bo2 && !bo3) { Write("blr"); return; } - Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi / 4, bi % 4, op.bh, op.lk)); + const auto [inst, sign] = get_BC_info(bo, bi); + + if (!inst) + { + Write(fmt::format("bclr %d, cr%d[%x], %d, %d", bo, bi / 4, get_partial_BI_field(bi), bh, lk)); + return; + } + + const auto final = std::string(inst) + (lk ? "lrl" : "lr") + sign; + + // Check if need to display full BI value + if (sign == 't' || sign == 'f') + { + DisAsm_BI_BRANCH(final, bi, bh); + return; + } + + DisAsm_CR_BRANCH(final, bi / 4, bh); } void PPUDisAsm::CRNOR(ppu_opcode_t op) @@ -1034,17 +1099,24 @@ void PPUDisAsm::BCCTR(ppu_opcode_t op) const u32 bo = op.bo; const u32 bi = op.bi; const u32 bh = op.bh; + const u32 lk = op.lk; - if (bo == 20) + if (bo == 0b10100) { - return Write(op.lk ? "bctrl" : "bctr"); + Write(lk ? "bctrl" : "bctr"); + return; } - switch (op.lk) + const auto [inst, sign] = get_BC_info(bo, bi); + + if (!inst || inst[1] == 'd') { - case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; - case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; + // Invalid or unknown bcctr form + Write(fmt::format("bcctr %d, cr%d[%x], %d, %d", bo, bi / 4, bi % 4, bh, lk)); + return; } + + DisAsm_CR_BRANCH(std::string(inst) + (lk ? "ctrl" : "clr") + sign, bi / 4, bh); } void PPUDisAsm::RLWIMI(ppu_opcode_t op) diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 079e406edb..06619f923e 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -16,6 +16,18 @@ private: return dump_pc + (imm & ~3); } + constexpr const char* get_partial_BI_field(u32 bi) + { + switch (bi % 4) + { + case 0x0: return "lt"; + case 0x1: return "gt"; + case 0x2: return "eq"; + case 0x3: return "so"; + default: ASSUME(0); return {}; + } + } + private: void DisAsm_V4(const std::string& op, u32 v0, u32 v1, u32 v2, u32 v3) { @@ -243,6 +255,14 @@ private: { Write(fmt::format("%s cr%d,0x%x ", FixOp(op).c_str(), cr, pc)); } + void DisAsm_BI_BRANCH(const std::string& op, u32 bi, const int pc) + { + Write(fmt::format("%s cr%d[%s],0x%x ", FixOp(op).c_str(), bi / 4, get_partial_BI_field(bi), DisAsmBranchTarget(pc))); + } + void DisAsm_BI_BRANCH_A(const std::string& op, u32 bi, const int pc) + { + Write(fmt::format("%s cr%d[%s],0x%x ", FixOp(op).c_str(), bi / 4, get_partial_BI_field(bi), pc)); + } public: u32 disasm(u32 pc) override;