Moved remaining instruction processing text generation into Generator class

This commit is contained in:
Mr-Wiseguy 2024-09-28 23:58:25 -04:00
parent d33d381617
commit 053242263f
5 changed files with 332 additions and 151 deletions

View file

@ -365,6 +365,46 @@ void N64Recomp::CGenerator::get_binary_expr_string(BinaryOpType type, const Bina
}
}
void N64Recomp::CGenerator::emit_function_start(std::ostream& output_file, const std::string& function_name) const {
fmt::print(output_file,
"RECOMP_FUNC void {}(uint8_t* rdram, recomp_context* ctx) {{\n"
// these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output
" uint64_t hi = 0, lo = 0, result = 0;\n"
" unsigned int rounding_mode = DEFAULT_ROUNDING_MODE;\n"
" int c1cs = 0;\n", // cop1 conditional signal
function_name);
}
void N64Recomp::CGenerator::emit_function_end(std::ostream& output_file) const {
fmt::print(output_file, ";}}\n");
}
void N64Recomp::CGenerator::emit_function_call_lookup(std::ostream& output_file, uint32_t addr) const {
fmt::print(output_file, "LOOKUP_FUNC(0x{:08X})(rdram, ctx);\n", addr);
}
void N64Recomp::CGenerator::emit_function_call_by_register(std::ostream& output_file, int reg) const {
fmt::print(output_file, "LOOKUP_FUNC({})(rdram, ctx);\n", gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_function_call_by_name(std::ostream& output_file, const std::string& func_name) const {
fmt::print(output_file, "{}(rdram, ctx);\n", func_name);
}
void N64Recomp::CGenerator::emit_goto(std::ostream& output_file, const std::string& target) const {
fmt::print(output_file,
" goto {};\n", target);
}
void N64Recomp::CGenerator::emit_label(std::ostream& output_file, const std::string& label_name) const {
fmt::print(output_file,
"{}:\n", label_name);
}
void N64Recomp::CGenerator::emit_variable_declaration(std::ostream& output_file, const std::string& var_name, int reg) const {
fmt::print(output_file, "gpr {} = {};\n", var_name, gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx) const {
// Thread local variables to prevent allocations when possible.
// TODO these thread locals probably don't actually help right now, so figure out a better way to prevent allocations.
@ -374,7 +414,27 @@ void N64Recomp::CGenerator::emit_branch_condition(std::ostream& output_file, con
}
void N64Recomp::CGenerator::emit_branch_close(std::ostream& output_file) const {
fmt::print(output_file, " }}\n");
fmt::print(output_file, "}}\n");
}
void N64Recomp::CGenerator::emit_switch_close(std::ostream& output_file) const {
fmt::print(output_file, "}}\n");
}
void N64Recomp::CGenerator::emit_switch(std::ostream& output_file, const std::string& jump_variable, int shift_amount) const {
fmt::print(output_file, "switch ({} >> {}) {{\n", jump_variable, shift_amount);
}
void N64Recomp::CGenerator::emit_case(std::ostream& output_file, int case_index, const std::string& target_label) const {
fmt::print(output_file, "case {}: goto {}; break;\n", case_index, target_label);
}
void N64Recomp::CGenerator::emit_switch_error(std::ostream& output_file, uint32_t instr_vram, uint32_t jtbl_vram) const {
fmt::print(output_file, "default: switch_error(__func__, 0x{:08X}, 0x{:08X});\n", instr_vram, jtbl_vram);
}
void N64Recomp::CGenerator::emit_return(std::ostream& output_file) const {
fmt::print(output_file, "return;\n");
}
void N64Recomp::CGenerator::emit_check_fr(std::ostream& output_file, int fpr) const {
@ -385,6 +445,72 @@ void N64Recomp::CGenerator::emit_check_nan(std::ostream& output_file, int fpr, b
fmt::print(output_file, "NAN_CHECK(ctx->f{}.{}); ", fpr, is_double ? "d" : "fl");
}
void N64Recomp::CGenerator::emit_cop0_status_read(std::ostream& output_file, int reg) const {
fmt::print(output_file, "{} = cop0_status_read(ctx);\n", gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_cop0_status_write(std::ostream& output_file, int reg) const {
fmt::print(output_file, "cop0_status_write(ctx, {})", gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_cop1_cs_read(std::ostream& output_file, int reg) const {
fmt::print(output_file, "{} = rounding_mode;\n", gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_cop1_cs_write(std::ostream& output_file, int reg) const {
fmt::print(output_file, "rounding_mode = ({}) & 0x3;\n", gpr_to_string(reg));
}
void N64Recomp::CGenerator::emit_muldiv(std::ostream& output_file, InstrId instr_id, int reg1, int reg2) const {
switch (instr_id) {
case InstrId::cpu_mult:
fmt::print(output_file, "result = S64(S32({})) * S64(S32({})); lo = S32(result >> 0); hi = S32(result >> 32);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_dmult:
fmt::print(output_file, "DMULT(S64({}), S64({}), &lo, &hi);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_multu:
fmt::print(output_file, "result = U64(U32({})) * U64(U32({})); lo = S32(result >> 0); hi = S32(result >> 32);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_dmultu:
fmt::print(output_file, "DMULTU(U64({}), U64({}), &lo, &hi);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_div:
// Cast to 64-bits before division to prevent artihmetic exception for s32(0x80000000) / -1
fmt::print(output_file, "lo = S32(S64(S32({0})) / S64(S32({1}))); hi = S32(S64(S32({0})) % S64(S32({1})));\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_ddiv:
fmt::print(output_file, "DDIV(S64({}), S64({}), &lo, &hi);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_divu:
fmt::print(output_file, "lo = S32(U32({0}) / U32({1})); hi = S32(U32({0}) % U32({1}));\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
case InstrId::cpu_ddivu:
fmt::print(output_file, "DDIVU(U64({}), U64({}), &lo, &hi);\n", gpr_to_string(reg1), gpr_to_string(reg2));
break;
}
}
void N64Recomp::CGenerator::emit_syscall(std::ostream& output_file, uint32_t instr_vram) const {
fmt::print(output_file, "recomp_syscall_handler(rdram, ctx, 0x{:08X});\n", instr_vram);
}
void N64Recomp::CGenerator::emit_do_break(std::ostream& output_file, uint32_t instr_vram) const {
fmt::print(output_file, "do_break({});\n", instr_vram);
}
void N64Recomp::CGenerator::emit_pause_self(std::ostream& output_file) const {
fmt::print(output_file, "pause_self(rdram);\n");
}
void N64Recomp::CGenerator::emit_trigger_event(std::ostream& output_file, size_t event_index) const {
fmt::print(output_file, "recomp_trigger_event(rdram, ctx, base_event_index + {});\n", event_index);
}
void N64Recomp::CGenerator::emit_comment(std::ostream& output_file, const std::string& comment) const {
fmt::print(output_file, "// {}\n", comment);
}
void N64Recomp::CGenerator::process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx) const {
// Thread local variables to prevent allocations when possible.
// TODO these thread locals probably don't actually help right now, so figure out a better way to prevent allocations.