| 1002 | } |
| 1003 | |
| 1004 | void create_function(const std::string& function_name, std::ofstream& output_file, const std::vector<rabbitizer::InstructionRsp>& instrs, const RSPRecompilerConfig& config, const ResumeTargets& resume_targets, bool is_permutation, bool is_initial) { |
| 1005 | // Collect indirect jump targets (return addresses for linked jumps) |
| 1006 | BranchTargets branch_targets = get_branch_targets(instrs); |
| 1007 | |
| 1008 | // Add any additional indirect branch targets that may not be found directly in the code (e.g. from a jump table) |
| 1009 | for (uint32_t target : config.extra_indirect_branch_targets) { |
| 1010 | branch_targets.indirect_targets.insert(target); |
| 1011 | } |
| 1012 | |
| 1013 | // Write function |
| 1014 | if (is_permutation) { |
| 1015 | fmt::print(output_file, |
| 1016 | "RspExitReason {}(uint8_t* rdram, RspContext* ctx) {{\n" |
| 1017 | " uint32_t r1 = ctx->r1, r2 = ctx->r2, r3 = ctx->r3, r4 = ctx->r4, r5 = ctx->r5, r6 = ctx->r6, r7 = ctx->r7;\n" |
| 1018 | " uint32_t r8 = ctx->r8, r9 = ctx->r9, r10 = ctx->r10, r11 = ctx->r11, r12 = ctx->r12, r13 = ctx->r13, r14 = ctx->r14, r15 = ctx->r15;\n" |
| 1019 | " uint32_t r16 = ctx->r16, r17 = ctx->r17, r18 = ctx->r18, r19 = ctx->r19, r20 = ctx->r20, r21 = ctx->r21, r22 = ctx->r22, r23 = ctx->r23;\n" |
| 1020 | " uint32_t r24 = ctx->r24, r25 = ctx->r25, r26 = ctx->r26, r27 = ctx->r27, r28 = ctx->r28, r29 = ctx->r29, r30 = ctx->r30, r31 = ctx->r31;\n" |
| 1021 | " uint32_t dma_mem_address = ctx->dma_mem_address, dma_dram_address = ctx->dma_dram_address, jump_target = ctx->jump_target;\n" |
| 1022 | " const char * debug_file = NULL; int debug_line = 0;\n" |
| 1023 | " RSP rsp = ctx->rsp;\n", function_name); |
| 1024 | |
| 1025 | // Write jumps to resume targets |
| 1026 | if (!is_initial) { |
| 1027 | fmt::print(output_file, |
| 1028 | " if (ctx->resume_delay) {{\n" |
| 1029 | " switch (ctx->resume_address) {{\n"); |
| 1030 | |
| 1031 | for (uint32_t address : resume_targets.delay_targets) { |
| 1032 | fmt::print(output_file, " case 0x{0:04X}: goto R_{0:04X}_delay;\n", |
| 1033 | address); |
| 1034 | } |
| 1035 | |
| 1036 | fmt::print(output_file, |
| 1037 | " }}\n" |
| 1038 | " }} else {{\n" |
| 1039 | " switch (ctx->resume_address) {{\n"); |
| 1040 | |
| 1041 | for (uint32_t address : resume_targets.non_delay_targets) { |
| 1042 | fmt::print(output_file, " case 0x{0:04X}: goto R_{0:04X};\n", |
| 1043 | address); |
| 1044 | } |
| 1045 | |
| 1046 | fmt::print(output_file, |
| 1047 | " }}\n" |
| 1048 | " }}\n" |
| 1049 | " printf(\"Unhandled resume target 0x%04X (delay slot: %d) in microcode {}\\n\", ctx->resume_address, ctx->resume_delay);\n" |
| 1050 | " return RspExitReason::UnhandledResumeTarget;\n", |
| 1051 | config.output_function_name); |
| 1052 | } |
| 1053 | |
| 1054 | fmt::print(output_file, " r1 = 0xFC0;\n"); |
| 1055 | } else { |
| 1056 | fmt::print(output_file, |
| 1057 | "RspExitReason {}(uint8_t* rdram, [[maybe_unused]] uint32_t ucode_addr) {{\n" |
| 1058 | " uint32_t r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0;\n" |
| 1059 | " uint32_t r8 = 0, r9 = 0, r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0;\n" |
| 1060 | " uint32_t r16 = 0, r17 = 0, r18 = 0, r19 = 0, r20 = 0, r21 = 0, r22 = 0, r23 = 0;\n" |
| 1061 | " uint32_t r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0, r30 = 0, r31 = 0;\n" |
no test coverage detected