| 223 | } |
| 224 | |
| 225 | bool process_instruction(size_t instr_index, const std::vector<rabbitizer::InstructionRsp>& instructions, std::ofstream& output_file, const BranchTargets& branch_targets, const std::unordered_set<uint32_t>& unsupported_instructions, const ResumeTargets& resume_targets, bool has_overlays, bool indent, bool in_delay_slot) { |
| 226 | const auto& instr = instructions[instr_index]; |
| 227 | |
| 228 | uint32_t instr_vram = instr.getVram(); |
| 229 | InstrId instr_id = instr.getUniqueId(); |
| 230 | |
| 231 | // Skip labels if we're duplicating an instruction into a delay slot |
| 232 | if (!in_delay_slot) { |
| 233 | // Print a label if one exists here |
| 234 | if (branch_targets.direct_targets.contains(instr_vram) || branch_targets.indirect_targets.contains(instr_vram)) { |
| 235 | fmt::print(output_file, "L_{:04X}:\n", instr_vram); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | uint16_t branch_target = instr.getBranchVramGeneric() & rsp_mem_mask; |
| 240 | |
| 241 | // Output a comment with the original instruction |
| 242 | if (instr.isBranch() || instr_id == InstrId::rsp_j) { |
| 243 | fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("L_{:04X}", branch_target))); |
| 244 | } else if (instr_id == InstrId::rsp_jal) { |
| 245 | fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("0x{:04X}", branch_target))); |
| 246 | } else { |
| 247 | fmt::print(output_file, " // {}\n", instr.disassemble(0)); |
| 248 | } |
| 249 | |
| 250 | auto print_indent = [&]() { |
| 251 | fmt::print(output_file, " "); |
| 252 | }; |
| 253 | |
| 254 | auto print_line = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts&& ...args) { |
| 255 | print_indent(); |
| 256 | fmt::print(output_file, fmt_str, std::forward<Ts>(args)...); |
| 257 | fmt::print(output_file, ";\n"); |
| 258 | }; |
| 259 | |
| 260 | auto print_branch_condition = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts&& ...args) { |
| 261 | fmt::print(output_file, fmt_str, std::forward<Ts>(args)...); |
| 262 | fmt::print(output_file, " "); |
| 263 | }; |
| 264 | |
| 265 | auto print_unconditional_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts&& ...args) { |
| 266 | if (instr_index < instructions.size() - 1) { |
| 267 | uint32_t next_vram = instr_vram + 4; |
| 268 | process_instruction(instr_index + 1, instructions, output_file, branch_targets, unsupported_instructions, resume_targets, has_overlays, false, true); |
| 269 | } |
| 270 | print_indent(); |
| 271 | fmt::print(output_file, fmt_str, std::forward<Ts>(args)...); |
| 272 | fmt::print(output_file, ";\n"); |
| 273 | }; |
| 274 | |
| 275 | auto print_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts&& ...args) { |
| 276 | fmt::print(output_file, "{{\n "); |
| 277 | if (instr_index < instructions.size() - 1) { |
| 278 | uint32_t next_vram = instr_vram + 4; |
| 279 | process_instruction(instr_index + 1, instructions, output_file, branch_targets, unsupported_instructions, resume_targets, has_overlays, true, true); |
| 280 | } |
| 281 | fmt::print(output_file, " "); |
| 282 | fmt::print(output_file, fmt_str, std::forward<Ts>(args)...); |
no test coverage detected