static uint32_t getUnit(bool units[5], latte::alu::Instruction &alu) { bool isTrans = false; auto elem = alu.word1.dstChan; if (isTranscendentalOnly(alu)) { isTrans = true; } else if (isVectorOnly(alu)) { isTrans = false; } else if (units[elem]) { isTrans = true; } else { isTrans = false; } if (isTrans) { assert(units[4] == false); units[4] = true; return 4; } else { units[elem] = true; return elem; } }
void disassembleAluInstruction(fmt::MemoryWriter &out, const ControlFlowInst &parent, const AluInst &inst, size_t groupPC, SQ_CHAN unit, const gsl::span<const uint32_t> &literals, int namePad) { const char *name = nullptr; SQ_ALU_FLAGS flags; auto srcCount = 0u; if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) { name = getInstructionName(inst.op2.ALU_INST()); flags = getInstructionFlags(inst.op2.ALU_INST()); srcCount = getInstructionNumSrcs(inst.op2.ALU_INST()); } else { name = getInstructionName(inst.op3.ALU_INST()); flags = getInstructionFlags(inst.op3.ALU_INST()); srcCount = getInstructionNumSrcs(inst.op3.ALU_INST()); } out << fmt::pad(name, namePad, ' ') << ' '; auto writeMask = true; if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) { writeMask = inst.op2.WRITE_MASK(); } if (!writeMask) { out << "____"; } else { disassembleAluSource(out, parent, groupPC, inst.word0.INDEX_MODE(), inst.word1.DST_GPR(), inst.word1.DST_REL(), inst.word1.DST_CHAN(), 0, false, false); } if (srcCount > 0) { auto literal = 0u; auto abs = false; if (inst.word0.SRC0_SEL() == SQ_ALU_SRC::LITERAL) { literal = literals[inst.word0.SRC0_CHAN()]; } if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) { abs = !!inst.op2.SRC0_ABS(); } out << ", "; disassembleAluSource(out, parent, groupPC, inst.word0.INDEX_MODE(), inst.word0.SRC0_SEL(), inst.word0.SRC0_REL(), inst.word0.SRC0_CHAN(), literal, inst.word0.SRC0_NEG(), abs); } if (srcCount > 1) { auto literal = 0u; auto abs = false; if (inst.word0.SRC1_SEL() == SQ_ALU_SRC::LITERAL) { literal = literals[inst.word0.SRC1_CHAN()]; } if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) { abs = !!inst.op2.SRC1_ABS(); } out << ", "; disassembleAluSource(out, parent, groupPC, inst.word0.INDEX_MODE(), inst.word0.SRC1_SEL(), inst.word0.SRC1_REL(), inst.word0.SRC1_CHAN(), literal, inst.word0.SRC1_NEG(), abs); } if (srcCount > 2) { auto literal = 0u; if (inst.op3.SRC2_SEL() == SQ_ALU_SRC::LITERAL) { literal = literals[inst.op3.SRC2_CHAN()]; } out << ", "; disassembleAluSource(out, parent, groupPC, inst.word0.INDEX_MODE(), inst.op3.SRC2_SEL(), inst.op3.SRC2_REL(), inst.op3.SRC2_CHAN(), literal, inst.op3.SRC2_NEG(), false); } if (inst.word1.CLAMP()) { out << " CLAMP"; } if (isTranscendentalOnly(flags)) { switch (static_cast<SQ_ALU_SCL_BANK_SWIZZLE>(inst.word1.BANK_SWIZZLE())) { case SQ_ALU_SCL_BANK_SWIZZLE::SCL_210: out << " SCL_210"; break; case SQ_ALU_SCL_BANK_SWIZZLE::SCL_122: out << " SCL_122"; break; case SQ_ALU_SCL_BANK_SWIZZLE::SCL_212: out << " SCL_212"; break; case SQ_ALU_SCL_BANK_SWIZZLE::SCL_221: out << " SCL_221"; break; default: decaf_abort(fmt::format("Unexpected BANK_SWIZZLE {}", inst.word1.BANK_SWIZZLE())); } } else { switch (inst.word1.BANK_SWIZZLE()) { case SQ_ALU_VEC_BANK_SWIZZLE::VEC_012: // This is default, no need to print break; case SQ_ALU_VEC_BANK_SWIZZLE::VEC_021: out << " VEC_021"; break; case SQ_ALU_VEC_BANK_SWIZZLE::VEC_120: out << " VEC_120"; break; case SQ_ALU_VEC_BANK_SWIZZLE::VEC_102: out << " VEC_102"; break; case SQ_ALU_VEC_BANK_SWIZZLE::VEC_201: out << " VEC_201"; break; case SQ_ALU_VEC_BANK_SWIZZLE::VEC_210: out << " VEC_210"; break; default: decaf_abort(fmt::format("Unexpected BANK_SWIZZLE {}", inst.word1.BANK_SWIZZLE())); } } switch (inst.word0.PRED_SEL()) { case SQ_PRED_SEL::OFF: break; case SQ_PRED_SEL::ZERO: out << " PRED_SEL_ZERO"; break; case SQ_PRED_SEL::ONE: out << " PRED_SEL_ONE"; break; default: decaf_abort(fmt::format("Unexpected PRED_SEL {}", inst.word0.PRED_SEL())); } if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) { if (inst.op2.UPDATE_EXECUTE_MASK()) { out << " UPDATE_EXECUTE_MASK"; switch (inst.op2.EXECUTE_MASK_OP()) { case SQ_ALU_EXECUTE_MASK_OP::DEACTIVATE: out << " DEACTIVATE"; break; case SQ_ALU_EXECUTE_MASK_OP::BREAK: out << " BREAK"; break; case SQ_ALU_EXECUTE_MASK_OP::CONTINUE: out << " CONTINUE"; break; case SQ_ALU_EXECUTE_MASK_OP::KILL: out << " KILL"; break; default: decaf_abort(fmt::format("Unexpected EXECUTE_MASK_OP {}", inst.op2.EXECUTE_MASK_OP())); } } else { switch (inst.op2.OMOD()) { case SQ_ALU_OMOD::OFF: break; case SQ_ALU_OMOD::D2: out << " OMOD_D2"; break; case SQ_ALU_OMOD::M2: out << " OMOD_M2"; break; case SQ_ALU_OMOD::M4: out << " OMOD_M4"; break; default: decaf_abort(fmt::format("Unexpected OMOD {}", inst.op2.OMOD())); } } if (inst.op2.UPDATE_PRED()) { out << " UPDATE_PRED"; } } }