ppu disasm: Implement BCLR's, BCCTR's and BC's extended mnemonics

Also:
BCCTR cr bit is now shown as cr(bit/4)[bit % 4]
BLRL is now shown properly
BDN?Z[TF](LR?)L?A? branches are now implemented.
This commit is contained in:
Eladash 2019-10-07 19:16:34 +03:00 committed by Ani
parent 5978b1f28f
commit 1e303e9f97
2 changed files with 209 additions and 117 deletions

View File

@ -11,6 +11,136 @@ u32 PPUDisAsm::disasm(u32 pc)
return 4;
}
constexpr std::pair<const char*, char> get_BC_info(u32 bo, u32 bi)
{
std::pair<const char*, char> 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<const char> inst{""}, sign = inst;
if (!inst)
{
Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk));
return;
}
if (bo0 && !bo1 && !bo2 && bo3 && !bo4)
const auto final = std::string(inst) + (lk ? "l" : "") + (aa ? "a" : "") + sign;
// Check if need to display full BI value
if (sign == 't' || sign == 'f')
{
inst = "bdz";
}
else if (bo0 && bo1 && !bo2 && bo3 && !bo4)
if (aa)
{
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;
}
DisAsm_BI_BRANCH_A(final, bi, bd);
}
else
{
return Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk));
DisAsm_BI_BRANCH(final, bi, bd);
}
const auto msg = std::string(inst) + (lk ? "l" : "") + (aa ? "a" : "") + sign;
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)

View File

@ -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;